Compare commits
7
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7fbdd9ad2f | ||
|
|
24539968fd | ||
|
|
f13b356531 | ||
|
|
477594d7bc | ||
|
|
e955a18126 | ||
|
|
adec1c4507 | ||
|
|
172b8a032c |
+15
-13
@@ -100,6 +100,7 @@ set(SYSTEM_EXPAT OFF)
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
option(SIMGEAR_HEADLESS "Set to ON to build SimGear without GUI/graphics support" OFF)
|
option(SIMGEAR_HEADLESS "Set to ON to build SimGear without GUI/graphics support" OFF)
|
||||||
|
option(JPEG_FACTORY "Enable JPEG-factory support" OFF)
|
||||||
option(ENABLE_RTI "Set to ON to build SimGear with RTI support" OFF)
|
option(ENABLE_RTI "Set to ON to build SimGear with RTI support" OFF)
|
||||||
option(ENABLE_TESTS "Set to OFF to disable building SimGear's test applications" ON)
|
option(ENABLE_TESTS "Set to OFF to disable building SimGear's test applications" ON)
|
||||||
option(ENABLE_SOUND "Set to OFF to disable building SimGear's sound support" ON)
|
option(ENABLE_SOUND "Set to OFF to disable building SimGear's sound support" ON)
|
||||||
@@ -160,12 +161,9 @@ if (MSVC AND MSVC_3RDPARTY_ROOT)
|
|||||||
endif (MSVC AND MSVC_3RDPARTY_ROOT)
|
endif (MSVC AND MSVC_3RDPARTY_ROOT)
|
||||||
|
|
||||||
if(APPLE)
|
if(APPLE)
|
||||||
find_library(COCOA_LIBRARY Cocoa)
|
find_library(CORE_SERVICES_LIBRARY CoreServices)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Somehow this only works if included before searching for Boost...
|
|
||||||
include(BoostTestTargets)
|
|
||||||
|
|
||||||
find_package(Boost REQUIRED)
|
find_package(Boost REQUIRED)
|
||||||
set (BOOST_CXX_FLAGS "-DBOOST_MULTI_INDEX_DISABLE_SERIALIZATION -DBOOST_BIMAP_DISABLE_SERIALIZATION")
|
set (BOOST_CXX_FLAGS "-DBOOST_MULTI_INDEX_DISABLE_SERIALIZATION -DBOOST_BIMAP_DISABLE_SERIALIZATION")
|
||||||
|
|
||||||
@@ -181,9 +179,17 @@ else()
|
|||||||
message(STATUS "Sound support: ENABLED")
|
message(STATUS "Sound support: ENABLED")
|
||||||
endif(ENABLE_SOUND)
|
endif(ENABLE_SOUND)
|
||||||
|
|
||||||
find_package(OpenSceneGraph 3.2.0 REQUIRED osgText osgSim osgDB osgParticle osgGA osgUtil)
|
find_package(OpenSceneGraph 3.0.0 REQUIRED osgText osgSim osgDB osgParticle osgGA osgUtil)
|
||||||
endif(SIMGEAR_HEADLESS)
|
endif(SIMGEAR_HEADLESS)
|
||||||
|
|
||||||
|
if(JPEG_FACTORY)
|
||||||
|
message(STATUS "JPEG-factory: ENABLED")
|
||||||
|
find_package(JPEG REQUIRED)
|
||||||
|
include_directories(${JPEG_INCLUDE_DIR})
|
||||||
|
else()
|
||||||
|
message(STATUS "JPEG-factory: DISABLED")
|
||||||
|
endif(JPEG_FACTORY)
|
||||||
|
|
||||||
find_package(ZLIB REQUIRED)
|
find_package(ZLIB REQUIRED)
|
||||||
find_package(Threads REQUIRED)
|
find_package(Threads REQUIRED)
|
||||||
|
|
||||||
@@ -263,9 +269,7 @@ check_cxx_source_compiles(
|
|||||||
|
|
||||||
if(HAVE_DLFCN_H)
|
if(HAVE_DLFCN_H)
|
||||||
check_library_exists(dl dlerror "" HAVE_DL)
|
check_library_exists(dl dlerror "" HAVE_DL)
|
||||||
if(HAVE_DL)
|
|
||||||
set(DL_LIBRARY "dl")
|
set(DL_LIBRARY "dl")
|
||||||
endif()
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
SET(CMAKE_DEBUG_POSTFIX "d" CACHE STRING "add a postfix, usually 'd' on windows")
|
SET(CMAKE_DEBUG_POSTFIX "d" CACHE STRING "add a postfix, usually 'd' on windows")
|
||||||
@@ -338,11 +342,9 @@ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${WARNING_FLAGS_C} ${MSVC_FLAGS}")
|
|||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${WARNING_FLAGS_CXX} ${MSVC_FLAGS} ${BOOST_CXX_FLAGS}")
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${WARNING_FLAGS_CXX} ${MSVC_FLAGS} ${BOOST_CXX_FLAGS}")
|
||||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${MSVC_LD_FLAGS}")
|
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${MSVC_LD_FLAGS}")
|
||||||
|
|
||||||
# use BEFORE to ensure local directories are used first,
|
include_directories(${PROJECT_SOURCE_DIR})
|
||||||
# ahead of system-installed libs
|
include_directories(${PROJECT_SOURCE_DIR}/simgear/canvas/ShivaVG/include)
|
||||||
include_directories(BEFORE ${PROJECT_SOURCE_DIR})
|
include_directories(${PROJECT_BINARY_DIR}/simgear)
|
||||||
include_directories(BEFORE ${PROJECT_SOURCE_DIR}/simgear/canvas/ShivaVG/include)
|
|
||||||
include_directories(BEFORE ${PROJECT_BINARY_DIR}/simgear)
|
|
||||||
|
|
||||||
include_directories(${OPENSCENEGRAPH_INCLUDE_DIRS}
|
include_directories(${OPENSCENEGRAPH_INCLUDE_DIRS}
|
||||||
${Boost_INCLUDE_DIRS}
|
${Boost_INCLUDE_DIRS}
|
||||||
@@ -376,7 +378,7 @@ set(TEST_LIBS_INTERNAL_CORE
|
|||||||
${WINSOCK_LIBRARY}
|
${WINSOCK_LIBRARY}
|
||||||
${RT_LIBRARY}
|
${RT_LIBRARY}
|
||||||
${DL_LIBRARY}
|
${DL_LIBRARY}
|
||||||
${COCOA_LIBRARY})
|
${CORE_SERVICES_LIBRARY})
|
||||||
set(TEST_LIBS SimGearCore ${TEST_LIBS_INTERNAL_CORE})
|
set(TEST_LIBS SimGearCore ${TEST_LIBS_INTERNAL_CORE})
|
||||||
|
|
||||||
if(NOT SIMGEAR_HEADLESS)
|
if(NOT SIMGEAR_HEADLESS)
|
||||||
|
|||||||
@@ -1,256 +0,0 @@
|
|||||||
# - Add tests using boost::test
|
|
||||||
#
|
|
||||||
# Add this line to your test files in place of including a basic boost test header:
|
|
||||||
# #include <BoostTestTargetConfig.h>
|
|
||||||
#
|
|
||||||
# If you cannot do that and must use the included form for a given test,
|
|
||||||
# include the line
|
|
||||||
# // OVERRIDE_BOOST_TEST_INCLUDED_WARNING
|
|
||||||
# in the same file with the boost test include.
|
|
||||||
#
|
|
||||||
# include(BoostTestTargets)
|
|
||||||
# add_boost_test(<testdriver_name> SOURCES <source1> [<more sources...>]
|
|
||||||
# [FAIL_REGULAR_EXPRESSION <additional fail regex>]
|
|
||||||
# [LAUNCHER <generic launcher script>]
|
|
||||||
# [LIBRARIES <library> [<library>...]]
|
|
||||||
# [RESOURCES <resource> [<resource>...]]
|
|
||||||
# [TESTS <testcasename> [<testcasename>...]])
|
|
||||||
#
|
|
||||||
# If for some reason you need access to the executable target created,
|
|
||||||
# it can be found in ${${testdriver_name}_TARGET_NAME} as specified when
|
|
||||||
# you called add_boost_test
|
|
||||||
#
|
|
||||||
# Requires CMake 2.6 or newer (uses the 'function' command)
|
|
||||||
#
|
|
||||||
# Requires:
|
|
||||||
# GetForceIncludeDefinitions
|
|
||||||
# CopyResourcesToBuildTree
|
|
||||||
#
|
|
||||||
# Original Author:
|
|
||||||
# 2009-2010 Ryan Pavlik <rpavlik@iastate.edu> <abiryan@ryand.net>
|
|
||||||
# http://academic.cleardefinition.com
|
|
||||||
# Iowa State University HCI Graduate Program/VRAC
|
|
||||||
#
|
|
||||||
# Copyright Iowa State University 2009-2010.
|
|
||||||
# Distributed under the Boost Software License, Version 1.0.
|
|
||||||
# (See accompanying file LICENSE_1_0.txt or copy at
|
|
||||||
# http://www.boost.org/LICENSE_1_0.txt)
|
|
||||||
|
|
||||||
if(__add_boost_test)
|
|
||||||
return()
|
|
||||||
endif()
|
|
||||||
set(__add_boost_test YES)
|
|
||||||
|
|
||||||
set(BOOST_TEST_TARGET_PREFIX "test")
|
|
||||||
|
|
||||||
if(NOT Boost_FOUND)
|
|
||||||
find_package(Boost 1.34.0 QUIET)
|
|
||||||
endif()
|
|
||||||
if("${Boost_VERSION}0" LESS "1034000")
|
|
||||||
set(_shared_msg
|
|
||||||
"NOTE: boost::test-based targets and tests cannot "
|
|
||||||
"be added: boost >= 1.34.0 required but not found. "
|
|
||||||
"(found: '${Boost_VERSION}'; want >=103400) ")
|
|
||||||
if(BUILD_TESTING)
|
|
||||||
message(FATAL_ERROR
|
|
||||||
${_shared_msg}
|
|
||||||
"You may disable BUILD_TESTING to continue without the "
|
|
||||||
"tests.")
|
|
||||||
else()
|
|
||||||
message(STATUS
|
|
||||||
${_shared_msg}
|
|
||||||
"BUILD_TESTING disabled, so continuing anyway.")
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
include(GetForceIncludeDefinitions)
|
|
||||||
include(CopyResourcesToBuildTree)
|
|
||||||
|
|
||||||
if(Boost_FOUND AND NOT "${Boost_VERSION}0" LESS "1034000")
|
|
||||||
set(_boosttesttargets_libs)
|
|
||||||
set(_boostConfig "BoostTestTargetsIncluded.h")
|
|
||||||
if(NOT Boost_UNIT_TEST_FRAMEWORK_LIBRARY)
|
|
||||||
find_package(Boost 1.34.0 QUIET COMPONENTS unit_test_framework)
|
|
||||||
endif()
|
|
||||||
if(Boost_UNIT_TEST_FRAMEWORK_LIBRARY)
|
|
||||||
set(_boosttesttargets_libs "${Boost_UNIT_TEST_FRAMEWORK_LIBRARY}")
|
|
||||||
if(Boost_USE_STATIC_LIBS)
|
|
||||||
set(_boostConfig "BoostTestTargetsStatic.h")
|
|
||||||
else()
|
|
||||||
set(_boostConfig "BoostTestTargetsDynamic.h")
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
get_filename_component(_moddir ${CMAKE_CURRENT_LIST_FILE} PATH)
|
|
||||||
configure_file("${_moddir}/${_boostConfig}"
|
|
||||||
"${CMAKE_CURRENT_BINARY_DIR}/BoostTestTargetConfig.h"
|
|
||||||
COPYONLY)
|
|
||||||
include_directories("${CMAKE_CURRENT_BINARY_DIR}")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
function(add_boost_test _name)
|
|
||||||
if(NOT BUILD_TESTING)
|
|
||||||
return()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# parse arguments
|
|
||||||
set(_nowhere)
|
|
||||||
set(_curdest _nowhere)
|
|
||||||
set(_val_args
|
|
||||||
SOURCES
|
|
||||||
FAIL_REGULAR_EXPRESSION
|
|
||||||
LAUNCHER
|
|
||||||
LIBRARIES
|
|
||||||
RESOURCES
|
|
||||||
TESTS)
|
|
||||||
set(_bool_args
|
|
||||||
USE_COMPILED_LIBRARY)
|
|
||||||
foreach(_arg ${_val_args} ${_bool_args})
|
|
||||||
set(${_arg})
|
|
||||||
endforeach()
|
|
||||||
foreach(_element ${ARGN})
|
|
||||||
list(FIND _val_args "${_element}" _val_arg_find)
|
|
||||||
list(FIND _bool_args "${_element}" _bool_arg_find)
|
|
||||||
if("${_val_arg_find}" GREATER "-1")
|
|
||||||
set(_curdest "${_element}")
|
|
||||||
elseif("${_bool_arg_find}" GREATER "-1")
|
|
||||||
set("${_element}" ON)
|
|
||||||
set(_curdest _nowhere)
|
|
||||||
else()
|
|
||||||
list(APPEND ${_curdest} "${_element}")
|
|
||||||
endif()
|
|
||||||
endforeach()
|
|
||||||
|
|
||||||
if(_nowhere)
|
|
||||||
message(FATAL_ERROR "Syntax error in use of add_boost_test!")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(NOT SOURCES)
|
|
||||||
message(FATAL_ERROR
|
|
||||||
"Syntax error in use of add_boost_test: at least one source file required!")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(Boost_FOUND AND NOT "${Boost_VERSION}0" LESS "1034000")
|
|
||||||
|
|
||||||
include_directories(${Boost_INCLUDE_DIRS})
|
|
||||||
|
|
||||||
set(includeType)
|
|
||||||
foreach(src ${SOURCES})
|
|
||||||
file(READ ${src} thefile)
|
|
||||||
if("${thefile}" MATCHES ".*BoostTestTargetConfig.h.*")
|
|
||||||
set(includeType CONFIGURED)
|
|
||||||
set(includeFileLoc ${src})
|
|
||||||
break()
|
|
||||||
elseif("${thefile}" MATCHES ".*boost/test/included/unit_test.hpp.*")
|
|
||||||
set(includeType INCLUDED)
|
|
||||||
set(includeFileLoc ${src})
|
|
||||||
set(_boosttesttargets_libs) # clear this out - linking would be a bad idea
|
|
||||||
if(NOT
|
|
||||||
"${thefile}"
|
|
||||||
MATCHES
|
|
||||||
".*OVERRIDE_BOOST_TEST_INCLUDED_WARNING.*")
|
|
||||||
message("Please replace the include line in ${src} with this alternate include line instead:")
|
|
||||||
message(" \#include <BoostTestTargetConfig.h>")
|
|
||||||
message("Once you've saved your changes, re-run CMake. (See BoostTestTargets.cmake for more info)")
|
|
||||||
endif()
|
|
||||||
break()
|
|
||||||
endif()
|
|
||||||
endforeach()
|
|
||||||
|
|
||||||
if(NOT _boostTestTargetsNagged${_name} STREQUAL "${includeType}")
|
|
||||||
if("includeType" STREQUAL "CONFIGURED")
|
|
||||||
message(STATUS
|
|
||||||
"Test '${_name}' uses the CMake-configurable form of the boost test framework - congrats! (Including File: ${includeFileLoc})")
|
|
||||||
elseif("${includeType}" STREQUAL "INCLUDED")
|
|
||||||
message("In test '${_name}': ${includeFileLoc} uses the 'included' form of the boost unit test framework.")
|
|
||||||
else()
|
|
||||||
message("In test '${_name}': Didn't detect the CMake-configurable boost test include.")
|
|
||||||
message("Please replace your existing boost test include in that test with the following:")
|
|
||||||
message(" \#include <BoostTestTargetConfig.h>")
|
|
||||||
message("Once you've saved your changes, re-run CMake. (See BoostTestTargets.cmake for more info)")
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
set(_boostTestTargetsNagged${_name}
|
|
||||||
"${includeType}"
|
|
||||||
CACHE
|
|
||||||
INTERNAL
|
|
||||||
""
|
|
||||||
FORCE)
|
|
||||||
|
|
||||||
|
|
||||||
if(RESOURCES)
|
|
||||||
list(APPEND SOURCES ${RESOURCES})
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Generate a unique target name, using the relative binary dir
|
|
||||||
# and provided name. (transform all / into _ and remove all other
|
|
||||||
# non-alphabet characters)
|
|
||||||
file(RELATIVE_PATH
|
|
||||||
targetpath
|
|
||||||
"${CMAKE_BINARY_DIR}"
|
|
||||||
"${CMAKE_CURRENT_BINARY_DIR}")
|
|
||||||
string(REGEX REPLACE "[^A-Za-z/_]" "" targetpath "${targetpath}")
|
|
||||||
string(REPLACE "/" "_" targetpath "${targetpath}")
|
|
||||||
|
|
||||||
set(_target_name ${BOOST_TEST_TARGET_PREFIX}-${targetpath}-${_name})
|
|
||||||
set(${_name}_TARGET_NAME "${_target_name}" PARENT_SCOPE)
|
|
||||||
|
|
||||||
# Build the test.
|
|
||||||
add_executable(${_target_name} ${SOURCES})
|
|
||||||
|
|
||||||
list(APPEND LIBRARIES ${_boosttesttargets_libs})
|
|
||||||
|
|
||||||
if(LIBRARIES)
|
|
||||||
target_link_libraries(${_target_name} ${LIBRARIES})
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(RESOURCES)
|
|
||||||
set_property(TARGET ${_target_name} PROPERTY RESOURCE ${RESOURCES})
|
|
||||||
copy_resources_to_build_tree(${_target_name})
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(NOT Boost_TEST_FLAGS)
|
|
||||||
# set(Boost_TEST_FLAGS --catch_system_error=yes --output_format=XML)
|
|
||||||
set(Boost_TEST_FLAGS --catch_system_error=yes)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# TODO: Figure out why only recent boost handles individual test running properly
|
|
||||||
|
|
||||||
if(LAUNCHER)
|
|
||||||
set(_test_command ${LAUNCHER} "\$<TARGET_FILE:${_target_name}>")
|
|
||||||
else()
|
|
||||||
set(_test_command ${_target_name})
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(TESTS AND ( "${Boost_VERSION}" VERSION_GREATER "103799" ))
|
|
||||||
foreach(_test ${TESTS})
|
|
||||||
add_test(
|
|
||||||
${_name}-${_test}
|
|
||||||
${_test_command} --run_test=${_test} ${Boost_TEST_FLAGS}
|
|
||||||
)
|
|
||||||
if(FAIL_REGULAR_EXPRESSION)
|
|
||||||
set_tests_properties(${_name}-${_test}
|
|
||||||
PROPERTIES
|
|
||||||
FAIL_REGULAR_EXPRESSION
|
|
||||||
"${FAIL_REGULAR_EXPRESSION}")
|
|
||||||
endif()
|
|
||||||
endforeach()
|
|
||||||
else()
|
|
||||||
add_test(
|
|
||||||
${_name}-boost_test
|
|
||||||
${_test_command} ${Boost_TEST_FLAGS}
|
|
||||||
)
|
|
||||||
if(FAIL_REGULAR_EXPRESSION)
|
|
||||||
set_tests_properties(${_name}-boost_test
|
|
||||||
PROPERTIES
|
|
||||||
FAIL_REGULAR_EXPRESSION
|
|
||||||
"${FAIL_REGULAR_EXPRESSION}")
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# CppCheck the test if we can.
|
|
||||||
if(COMMAND add_cppcheck)
|
|
||||||
add_cppcheck(${_target_name} STYLE UNUSED_FUNCTIONS)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
endif()
|
|
||||||
endfunction()
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
// Small header computed by CMake to set up boost test.
|
|
||||||
// include AFTER #define BOOST_TEST_MODULE whatever
|
|
||||||
// but before any other boost test includes.
|
|
||||||
|
|
||||||
// Using the Boost UTF dynamic library
|
|
||||||
|
|
||||||
#define BOOST_TEST_DYN_LINK
|
|
||||||
#include <boost/test/unit_test.hpp>
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
// Small header computed by CMake to set up boost test.
|
|
||||||
// include AFTER #define BOOST_TEST_MODULE whatever
|
|
||||||
// but before any other boost test includes.
|
|
||||||
|
|
||||||
// Using the Boost UTF included framework
|
|
||||||
|
|
||||||
#include <boost/test/included/unit_test.hpp>
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
// Small header computed by CMake to set up boost test.
|
|
||||||
// include AFTER #define BOOST_TEST_MODULE whatever
|
|
||||||
// but before any other boost test includes.
|
|
||||||
|
|
||||||
// Using the Boost UTF static library
|
|
||||||
|
|
||||||
#include <boost/test/unit_test.hpp>
|
|
||||||
@@ -1,83 +0,0 @@
|
|||||||
# - Copy the resources your app needs to the build tree.
|
|
||||||
#
|
|
||||||
# copy_resources_to_build_tree(<target_name>)
|
|
||||||
#
|
|
||||||
# Requires CMake 2.6 or newer (uses the 'function' command)
|
|
||||||
#
|
|
||||||
# Original Author:
|
|
||||||
# 2009-2010 Ryan Pavlik <rpavlik@iastate.edu> <abiryan@ryand.net>
|
|
||||||
# http://academic.cleardefinition.com
|
|
||||||
# Iowa State University HCI Graduate Program/VRAC
|
|
||||||
#
|
|
||||||
# Copyright Iowa State University 2009-2010.
|
|
||||||
# Distributed under the Boost Software License, Version 1.0.
|
|
||||||
# (See accompanying file LICENSE_1_0.txt or copy at
|
|
||||||
# http://www.boost.org/LICENSE_1_0.txt)
|
|
||||||
|
|
||||||
if(__copy_resources_to_build_tree)
|
|
||||||
return()
|
|
||||||
endif()
|
|
||||||
set(__copy_resources_to_build_tree YES)
|
|
||||||
|
|
||||||
function(copy_resources_to_build_tree _target)
|
|
||||||
get_target_property(_resources ${_target} RESOURCE)
|
|
||||||
if(NOT _resources)
|
|
||||||
# Bail if no resources
|
|
||||||
message(STATUS
|
|
||||||
"Told to copy resources for target ${_target}, but "
|
|
||||||
"no resources are set!")
|
|
||||||
return()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
get_target_property(_path ${_target} LOCATION)
|
|
||||||
get_filename_component(_path "${_path}" PATH)
|
|
||||||
|
|
||||||
if(NOT MSVC AND NOT "${CMAKE_GENERATOR}" MATCHES "Makefiles")
|
|
||||||
foreach(_config ${CMAKE_CONFIGURATION_TYPES})
|
|
||||||
get_target_property(_path${_config} ${_target} LOCATION_${_config})
|
|
||||||
get_filename_component(_path${_config} "${_path${_config}}" PATH)
|
|
||||||
add_custom_command(TARGET ${_target}
|
|
||||||
POST_BUILD
|
|
||||||
COMMAND
|
|
||||||
${CMAKE_COMMAND}
|
|
||||||
ARGS -E make_directory "${_path${_config}}/"
|
|
||||||
COMMENT "Creating directory ${_path${_config}}/")
|
|
||||||
endforeach()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
foreach(_res ${_resources})
|
|
||||||
if(NOT IS_ABSOLUTE "${_res}")
|
|
||||||
get_filename_component(_res "${_res}" ABSOLUTE)
|
|
||||||
endif()
|
|
||||||
get_filename_component(_name "${_res}" NAME)
|
|
||||||
|
|
||||||
if(MSVC)
|
|
||||||
# Working dir is solution file dir, not exe file dir.
|
|
||||||
add_custom_command(TARGET ${_target}
|
|
||||||
POST_BUILD
|
|
||||||
COMMAND
|
|
||||||
${CMAKE_COMMAND}
|
|
||||||
ARGS -E copy "${_res}" "${CMAKE_BINARY_DIR}/"
|
|
||||||
COMMENT "Copying ${_name} to ${CMAKE_BINARY_DIR}/ for MSVC")
|
|
||||||
else()
|
|
||||||
if("${CMAKE_GENERATOR}" MATCHES "Makefiles")
|
|
||||||
add_custom_command(TARGET ${_target}
|
|
||||||
POST_BUILD
|
|
||||||
COMMAND
|
|
||||||
${CMAKE_COMMAND}
|
|
||||||
ARGS -E copy "${_res}" "${_path}/"
|
|
||||||
COMMENT "Copying ${_name} to ${_path}/")
|
|
||||||
else()
|
|
||||||
foreach(_config ${CMAKE_CONFIGURATION_TYPES})
|
|
||||||
add_custom_command(TARGET ${_target}
|
|
||||||
POST_BUILD
|
|
||||||
COMMAND
|
|
||||||
${CMAKE_COMMAND}
|
|
||||||
ARGS -E copy "${_res}" "${_path${_config}}"
|
|
||||||
COMMENT "Copying ${_name} to ${_path${_config}}")
|
|
||||||
endforeach()
|
|
||||||
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
endforeach()
|
|
||||||
endfunction()
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
# - Get the platform-appropriate flags to add to force inclusion of a file
|
|
||||||
#
|
|
||||||
# The most common use of this is to use a generated config.h-type file
|
|
||||||
# placed out of the source tree in all files.
|
|
||||||
#
|
|
||||||
# get_force_include_definitions(var forcedincludefiles...) -
|
|
||||||
# where var is the name of your desired output variable, and everything
|
|
||||||
# else is a source file to forcibly include.
|
|
||||||
# a list item to be filtered.
|
|
||||||
#
|
|
||||||
# Original Author:
|
|
||||||
# 2009-2010 Ryan Pavlik <rpavlik@iastate.edu> <abiryan@ryand.net>
|
|
||||||
# http://academic.cleardefinition.com
|
|
||||||
# Iowa State University HCI Graduate Program/VRAC
|
|
||||||
#
|
|
||||||
# Copyright Iowa State University 2009-2010.
|
|
||||||
# Distributed under the Boost Software License, Version 1.0.
|
|
||||||
# (See accompanying file LICENSE_1_0.txt or copy at
|
|
||||||
# http://www.boost.org/LICENSE_1_0.txt)
|
|
||||||
|
|
||||||
if(__get_force_include_definitions)
|
|
||||||
return()
|
|
||||||
endif()
|
|
||||||
set(__get_force_include_definitions YES)
|
|
||||||
|
|
||||||
function(get_force_include_definitions var)
|
|
||||||
set(_flagprefix)
|
|
||||||
if(CMAKE_COMPILER_IS_GNUCXX)
|
|
||||||
set(_flag "-include")
|
|
||||||
elseif(MSVC)
|
|
||||||
set(_flag "/FI")
|
|
||||||
else()
|
|
||||||
message(SEND_ERROR "You don't seem to be using MSVC or GCC, but")
|
|
||||||
message(SEND_ERROR "the project called get_force_include_definitions.")
|
|
||||||
message(SEND_ERROR "Contact this project with the name of your")
|
|
||||||
message(FATAL_ERROR "compiler and preferably the flag to force includes")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
set(_out)
|
|
||||||
foreach(_item ${ARGN})
|
|
||||||
list(APPEND _out "${_flag} \"${_item}\"")
|
|
||||||
endforeach()
|
|
||||||
set(${var} "${_out}" PARENT_SCOPE)
|
|
||||||
endfunction()
|
|
||||||
@@ -122,7 +122,7 @@ target_link_libraries(SimGearCore
|
|||||||
${DL_LIBRARY}
|
${DL_LIBRARY}
|
||||||
${EXPAT_LIBRARIES}
|
${EXPAT_LIBRARIES}
|
||||||
${CMAKE_THREAD_LIBS_INIT}
|
${CMAKE_THREAD_LIBS_INIT}
|
||||||
${COCOA_LIBRARY})
|
${CORE_SERVICES_LIBRARY})
|
||||||
|
|
||||||
if(NOT SIMGEAR_HEADLESS)
|
if(NOT SIMGEAR_HEADLESS)
|
||||||
target_link_libraries(SimGearScene
|
target_link_libraries(SimGearScene
|
||||||
|
|||||||
@@ -5,12 +5,3 @@ set(HEADERS newbucket.hxx)
|
|||||||
set(SOURCES newbucket.cxx)
|
set(SOURCES newbucket.cxx)
|
||||||
|
|
||||||
simgear_component(bucket bucket "${SOURCES}" "${HEADERS}")
|
simgear_component(bucket bucket "${SOURCES}" "${HEADERS}")
|
||||||
|
|
||||||
|
|
||||||
if(ENABLE_TESTS)
|
|
||||||
|
|
||||||
add_executable(test_bucket test_bucket.cxx)
|
|
||||||
add_test(test_bucket ${EXECUTABLE_OUTPUT_PATH}/test_bucket)
|
|
||||||
target_link_libraries(test_bucket ${TEST_LIBS})
|
|
||||||
|
|
||||||
endif(ENABLE_TESTS)
|
|
||||||
+86
-158
@@ -27,56 +27,36 @@
|
|||||||
# include <simgear_config.h>
|
# include <simgear_config.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <cmath>
|
#include <math.h>
|
||||||
#include <cstdio> // some platforms need this for ::snprintf
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
#include <simgear/misc/sg_path.hxx>
|
#include <simgear/misc/sg_path.hxx>
|
||||||
#include <simgear/debug/logstream.hxx>
|
|
||||||
|
|
||||||
#include "newbucket.hxx"
|
#include "newbucket.hxx"
|
||||||
|
|
||||||
|
|
||||||
// default constructor
|
// default constructor
|
||||||
SGBucket::SGBucket() :
|
SGBucket::SGBucket() {
|
||||||
lon(-1000),
|
|
||||||
lat(-1000),
|
|
||||||
x(0),
|
|
||||||
y(0)
|
|
||||||
{
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SGBucket::isValid() const
|
|
||||||
{
|
|
||||||
// The most northerly valid latitude is 89, not 90. There is no tile
|
|
||||||
// whose *bottom* latitude is 90. Similar there is no tile whose left egde
|
|
||||||
// is 180 longitude.
|
|
||||||
return (lon >= -180) &&
|
|
||||||
(lon < 180) &&
|
|
||||||
(lat >= -90) &&
|
|
||||||
(lat < 90) &&
|
|
||||||
(x < 8) && (y < 8);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SGBucket::make_bad()
|
|
||||||
{
|
|
||||||
lon = -1000;
|
|
||||||
lat = -1000;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef NO_DEPRECATED_API
|
|
||||||
|
|
||||||
// constructor for specified location
|
// constructor for specified location
|
||||||
SGBucket::SGBucket(const double dlon, const double dlat) {
|
SGBucket::SGBucket(const double dlon, const double dlat) {
|
||||||
set_bucket(dlon, dlat);
|
set_bucket(dlon, dlat);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
SGBucket::SGBucket(const SGGeod& geod) {
|
SGBucket::SGBucket(const SGGeod& geod) {
|
||||||
innerSet(geod.getLongitudeDeg(),
|
set_bucket(geod);
|
||||||
geod.getLatitudeDeg());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// create an impossible bucket if false
|
||||||
|
SGBucket::SGBucket(const bool is_good) {
|
||||||
|
set_bucket(0.0, 0.0);
|
||||||
|
if ( !is_good ) {
|
||||||
|
lon = -1000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Parse a unique scenery tile index and find the lon, lat, x, and y
|
// Parse a unique scenery tile index and find the lon, lat, x, and y
|
||||||
SGBucket::SGBucket(const long int bindex) {
|
SGBucket::SGBucket(const long int bindex) {
|
||||||
long int index = bindex;
|
long int index = bindex;
|
||||||
@@ -95,59 +75,48 @@ SGBucket::SGBucket(const long int bindex) {
|
|||||||
x = index;
|
x = index;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Calculate the greatest integral value less than
|
|
||||||
* or equal to the given value (floor(x)),
|
|
||||||
* but attribute coordinates close to the boundary to the next
|
|
||||||
* (increasing) integral
|
|
||||||
*/
|
|
||||||
static int floorWithEpsilon(double x)
|
|
||||||
{
|
|
||||||
return static_cast<int>(floor(x + SG_EPSILON));
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef NO_DEPRECATED_API
|
|
||||||
|
|
||||||
void SGBucket::set_bucket(double dlon, double dlat)
|
|
||||||
{
|
|
||||||
innerSet(dlon, dlat);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void SGBucket::set_bucket(const SGGeod& geod)
|
|
||||||
{
|
|
||||||
innerSet(geod.getLongitudeDeg(), geod.getLatitudeDeg());
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Set the bucket params for the specified lat and lon
|
// Set the bucket params for the specified lat and lon
|
||||||
void SGBucket::innerSet( double dlon, double dlat )
|
void SGBucket::set_bucket( double *lonlat ) {
|
||||||
{
|
set_bucket( lonlat[0], lonlat[1] );
|
||||||
if ((dlon < -180.0) || (dlon >= 180.0)) {
|
}
|
||||||
SG_LOG(SG_TERRAIN, SG_WARN, "SGBucket::set_bucket: passed longitude:" << dlon);
|
|
||||||
dlon = SGMiscd::normalizePeriodic(-180.0, 180.0, dlon);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((dlat < -90.0) || (dlat > 90.0)) {
|
|
||||||
SG_LOG(SG_TERRAIN, SG_WARN, "SGBucket::set_bucket: passed latitude" << dlat);
|
|
||||||
dlat = SGMiscd::clip(dlat, -90.0, 90.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// Set the bucket params for the specified lat and lon
|
||||||
|
void SGBucket::set_bucket( double dlon, double dlat ) {
|
||||||
//
|
//
|
||||||
// longitude first
|
// latitude first
|
||||||
//
|
//
|
||||||
double span = sg_bucket_span( dlat );
|
double span = sg_bucket_span( dlat );
|
||||||
// we do NOT need to special case lon=180 here, since
|
double diff = dlon - (double)(int)dlon;
|
||||||
// normalizePeriodic will never return 180; it will
|
|
||||||
// return -180, which is what we want.
|
// cout << "diff = " << diff << " span = " << span << endl;
|
||||||
lon = floorWithEpsilon(dlon);
|
|
||||||
|
/* Calculate the greatest integral longitude less than
|
||||||
|
* or equal to the given longitude (floor(dlon)),
|
||||||
|
* but attribute coordinates near the east border
|
||||||
|
* to the next tile.
|
||||||
|
*/
|
||||||
|
if ( (dlon >= 0) || (fabs(diff) < SG_EPSILON) ) {
|
||||||
|
lon = (int)dlon;
|
||||||
|
} else {
|
||||||
|
lon = (int)dlon - 1;
|
||||||
|
}
|
||||||
|
|
||||||
// find subdivision or super lon if needed
|
// find subdivision or super lon if needed
|
||||||
if ( span <= 1.0 ) {
|
if ( span < SG_EPSILON ) {
|
||||||
|
/* sg_bucket_span() never returns 0.0
|
||||||
|
* or anything near it, so this really
|
||||||
|
* should not occur at any time.
|
||||||
|
*/
|
||||||
|
// polar cap
|
||||||
|
lon = 0;
|
||||||
|
x = 0;
|
||||||
|
} else if ( span <= 1.0 ) {
|
||||||
/* We have more than one tile per degree of
|
/* We have more than one tile per degree of
|
||||||
* longitude, so we need an x offset.
|
* longitude, so we need an x offset.
|
||||||
*/
|
*/
|
||||||
x = floorWithEpsilon((dlon - lon) / span);
|
x = (int)((dlon - lon) / span);
|
||||||
} else {
|
} else {
|
||||||
/* We have one or more degrees per tile,
|
/* We have one or more degrees per tile,
|
||||||
* so we need to find the base longitude
|
* so we need to find the base longitude
|
||||||
@@ -160,28 +129,48 @@ void SGBucket::innerSet( double dlon, double dlat )
|
|||||||
*
|
*
|
||||||
* That way, the Greenwich Meridian is always
|
* That way, the Greenwich Meridian is always
|
||||||
* a tile border.
|
* a tile border.
|
||||||
|
*
|
||||||
|
* This gets us into trouble with the polar caps,
|
||||||
|
* which have width 360 and thus either span
|
||||||
|
* the range from 0 to 360 or from -360 to 0
|
||||||
|
* degrees, depending on whether lon is positive
|
||||||
|
* or negative!
|
||||||
|
*
|
||||||
|
* We also get into trouble with the 8 degree tiles
|
||||||
|
* north of 88N and south of 88S, because the west-
|
||||||
|
* and east-most tiles in that range will cover 184W
|
||||||
|
* to 176W and 176E to 184E respectively, with their
|
||||||
|
* center at 180E/W!
|
||||||
*/
|
*/
|
||||||
lon=static_cast<int>(floor(lon / span) * span);
|
lon=(int)floor(floor((lon+SG_EPSILON)/span)*span);
|
||||||
|
/* Correct the polar cap issue */
|
||||||
|
if ( lon < -180 ) {
|
||||||
|
lon = -180;
|
||||||
|
}
|
||||||
x = 0;
|
x = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// then latitude
|
// then latitude
|
||||||
//
|
//
|
||||||
lat = floorWithEpsilon(dlat);
|
diff = dlat - (double)(int)dlat;
|
||||||
|
|
||||||
// special case when passing in the north pole point (possibly due to
|
/* Again, a modified floor() function (see longitude) */
|
||||||
// clipping latitude above). Ensures we generate a valid bucket in this
|
if ( (dlat >= 0) || (fabs(diff) < SG_EPSILON) ) {
|
||||||
// scenario
|
lat = (int)dlat;
|
||||||
if (lat == 90) {
|
|
||||||
lat = 89;
|
|
||||||
y = 7;
|
|
||||||
} else {
|
} else {
|
||||||
|
lat = (int)dlat - 1;
|
||||||
|
}
|
||||||
/* Latitude base and offset are easier, as
|
/* Latitude base and offset are easier, as
|
||||||
* tiles always are 1/8 degree of latitude wide.
|
* tiles always are 1/8 degree of latitude wide.
|
||||||
*/
|
*/
|
||||||
y = floorWithEpsilon((dlat - lat) * 8);
|
y = (int)((dlat - lat) * 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void SGBucket::set_bucket(const SGGeod& geod)
|
||||||
|
{
|
||||||
|
set_bucket(geod.getLongitudeDeg(), geod.getLatitudeDeg());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build the path name for this bucket
|
// Build the path name for this bucket
|
||||||
@@ -223,7 +212,7 @@ std::string SGBucket::gen_base_path() const {
|
|||||||
main_lat *= -1;
|
main_lat *= -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
::snprintf(raw_path, 256, "%c%03d%c%02d/%c%03d%c%02d",
|
snprintf(raw_path, 256, "%c%03d%c%02d/%c%03d%c%02d",
|
||||||
hem, top_lon, pole, top_lat,
|
hem, top_lon, pole, top_lat,
|
||||||
hem, main_lon, pole, main_lat);
|
hem, main_lon, pole, main_lat);
|
||||||
|
|
||||||
@@ -244,32 +233,17 @@ double SGBucket::get_height() const {
|
|||||||
return SG_BUCKET_SPAN;
|
return SG_BUCKET_SPAN;
|
||||||
}
|
}
|
||||||
|
|
||||||
double SGBucket::get_highest_lat() const
|
|
||||||
{
|
// return width of the tile in meters
|
||||||
unsigned char adjustedY = y;
|
double SGBucket::get_width_m() const {
|
||||||
if (lat >= 0) {
|
double clat = (int)get_center_lat();
|
||||||
// tile is north of the equator, so we want the top edge. Add one
|
if ( clat > 0 ) {
|
||||||
// to y to achieve this.
|
clat = (int)clat + 0.5;
|
||||||
++adjustedY;
|
} else {
|
||||||
|
clat = (int)clat - 0.5;
|
||||||
}
|
}
|
||||||
|
double clat_rad = clat * SGD_DEGREES_TO_RADIANS;
|
||||||
return lat + (adjustedY / 8.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// return width of the tile in meters. This function is used by the
|
|
||||||
// tile-manager to estimate how many tiles are in the view distance, so
|
|
||||||
// we care about the smallest width, which occurs at the highest latitude.
|
|
||||||
double SGBucket::get_width_m() const
|
|
||||||
{
|
|
||||||
double clat_rad = get_highest_lat() * SGD_DEGREES_TO_RADIANS;
|
|
||||||
double cos_lat = cos( clat_rad );
|
double cos_lat = cos( clat_rad );
|
||||||
if (fabs(cos_lat) < SG_EPSILON) {
|
|
||||||
// happens for polar tiles, since we pass in a latitude of 90
|
|
||||||
// return an arbitrary small value so all tiles are loaded
|
|
||||||
return 10.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
double local_radius = cos_lat * SG_EQUATORIAL_RADIUS_M;
|
double local_radius = cos_lat * SG_EQUATORIAL_RADIUS_M;
|
||||||
double local_perimeter = local_radius * SGD_2PI;
|
double local_perimeter = local_radius * SGD_2PI;
|
||||||
double degree_width = local_perimeter / 360.0;
|
double degree_width = local_perimeter / 360.0;
|
||||||
@@ -286,41 +260,7 @@ double SGBucket::get_height_m() const {
|
|||||||
return SG_BUCKET_SPAN * degree_height;
|
return SG_BUCKET_SPAN * degree_height;
|
||||||
}
|
}
|
||||||
|
|
||||||
SGBucket SGBucket::sibling(int dx, int dy) const
|
|
||||||
{
|
|
||||||
if (!isValid()) {
|
|
||||||
SG_LOG(SG_TERRAIN, SG_WARN, "SGBucket::sibling: requesting sibling of invalid bucket");
|
|
||||||
return SGBucket();
|
|
||||||
}
|
|
||||||
|
|
||||||
double clat = get_center_lat() + dy * SG_BUCKET_SPAN;
|
|
||||||
// return invalid here instead of clipping, so callers can discard
|
|
||||||
// invalid buckets without having to check if it's an existing one
|
|
||||||
if ((clat < -90.0) || (clat > 90.0)) {
|
|
||||||
return SGBucket();
|
|
||||||
}
|
|
||||||
|
|
||||||
// find the lon span for the new latitude
|
|
||||||
double span = sg_bucket_span( clat );
|
|
||||||
|
|
||||||
double tmp = get_center_lon() + dx * span;
|
|
||||||
tmp = SGMiscd::normalizePeriodic(-180.0, 180.0, tmp);
|
|
||||||
|
|
||||||
SGBucket b;
|
|
||||||
b.innerSet(tmp, clat);
|
|
||||||
return b;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string SGBucket::gen_index_str() const
|
|
||||||
{
|
|
||||||
char tmp[20];
|
|
||||||
::snprintf(tmp, 20, "%ld",
|
|
||||||
(((long)lon + 180) << 14) + ((lat + 90) << 6)
|
|
||||||
+ (y << 3) + x);
|
|
||||||
return (std::string)tmp;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef NO_DEPRECATED_API
|
|
||||||
// find the bucket which is offset by the specified tile units in the
|
// find the bucket which is offset by the specified tile units in the
|
||||||
// X & Y direction. We need the current lon and lat to resolve
|
// X & Y direction. We need the current lon and lat to resolve
|
||||||
// ambiguities when going from a wider tile to a narrower one above or
|
// ambiguities when going from a wider tile to a narrower one above or
|
||||||
@@ -347,7 +287,7 @@ SGBucket sgBucketOffset( double dlon, double dlat, int dx, int dy ) {
|
|||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
// calculate the offset between two buckets
|
// calculate the offset between two buckets
|
||||||
void sgBucketDiff( const SGBucket& b1, const SGBucket& b2, int *dx, int *dy ) {
|
void sgBucketDiff( const SGBucket& b1, const SGBucket& b2, int *dx, int *dy ) {
|
||||||
@@ -408,22 +348,10 @@ void sgBucketDiff( const SGBucket& b1, const SGBucket& b2, int *dx, int *dy ) {
|
|||||||
void sgGetBuckets( const SGGeod& min, const SGGeod& max, std::vector<SGBucket>& list ) {
|
void sgGetBuckets( const SGGeod& min, const SGGeod& max, std::vector<SGBucket>& list ) {
|
||||||
double lon, lat, span;
|
double lon, lat, span;
|
||||||
|
|
||||||
for (lat = min.getLatitudeDeg(); lat < max.getLatitudeDeg()+SG_BUCKET_SPAN; lat += SG_BUCKET_SPAN) {
|
for (lat = min.getLatitudeDeg(); lat <= max.getLatitudeDeg(); lat += SG_BUCKET_SPAN) {
|
||||||
span = sg_bucket_span( lat );
|
span = sg_bucket_span( lat );
|
||||||
for (lon = min.getLongitudeDeg(); lon <= max.getLongitudeDeg(); lon += span)
|
for (lon = min.getLongitudeDeg(); lon <= max.getLongitudeDeg(); lon += span) {
|
||||||
{
|
list.push_back( SGBucket(lon , lat) );
|
||||||
SGBucket b(SGGeod::fromDeg(lon, lat));
|
|
||||||
if (!b.isValid()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
list.push_back(b);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::ostream& operator<< ( std::ostream& out, const SGBucket& b )
|
|
||||||
{
|
|
||||||
return out << b.lon << ":" << (int)b.x << ", " << b.lat << ":" << (int)b.y;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|||||||
@@ -39,12 +39,11 @@
|
|||||||
#include <simgear/math/SGMath.hxx>
|
#include <simgear/math/SGMath.hxx>
|
||||||
|
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
#include <cstdio> // sprintf()
|
||||||
|
#include <ostream>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <iosfwd>
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
// #define NO_DEPRECATED_API
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* standard size of a bucket in degrees (1/8 of a degree)
|
* standard size of a bucket in degrees (1/8 of a degree)
|
||||||
*/
|
*/
|
||||||
@@ -100,30 +99,22 @@ class SGBucket {
|
|||||||
private:
|
private:
|
||||||
short lon; // longitude index (-180 to 179)
|
short lon; // longitude index (-180 to 179)
|
||||||
short lat; // latitude index (-90 to 89)
|
short lat; // latitude index (-90 to 89)
|
||||||
unsigned char x; // x subdivision (0 to 7)
|
char x; // x subdivision (0 to 7)
|
||||||
unsigned char y; // y subdivision (0 to 7)
|
char y; // y subdivision (0 to 7)
|
||||||
|
|
||||||
void innerSet( double dlon, double dlat );
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default constructor, creates an invalid SGBucket
|
* Default constructor.
|
||||||
*/
|
*/
|
||||||
SGBucket();
|
SGBucket();
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if this bucket refers to a valid tile, or not.
|
|
||||||
*/
|
|
||||||
bool isValid() const;
|
|
||||||
|
|
||||||
#ifndef NO_DEPRECATED_API
|
|
||||||
/**
|
/**
|
||||||
* Construct a bucket given a specific location.
|
* Construct a bucket given a specific location.
|
||||||
* @param dlon longitude specified in degrees
|
* @param dlon longitude specified in degrees
|
||||||
* @param dlat latitude specified in degrees
|
* @param dlat latitude specified in degrees
|
||||||
*/
|
*/
|
||||||
SGBucket(const double dlon, const double dlat);
|
SGBucket(const double dlon, const double dlat);
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a bucket given a specific location.
|
* Construct a bucket given a specific location.
|
||||||
@@ -132,27 +123,39 @@ public:
|
|||||||
*/
|
*/
|
||||||
SGBucket(const SGGeod& geod);
|
SGBucket(const SGGeod& geod);
|
||||||
|
|
||||||
|
/** Construct a bucket.
|
||||||
|
* @param is_good if false, create an invalid bucket. This is
|
||||||
|
* useful * if you are comparing cur_bucket to last_bucket and
|
||||||
|
* you want to * make sure last_bucket starts out as something
|
||||||
|
* impossible.
|
||||||
|
*/
|
||||||
|
SGBucket(const bool is_good);
|
||||||
|
|
||||||
/** Construct a bucket given a unique bucket index number.
|
/** Construct a bucket given a unique bucket index number.
|
||||||
* @param bindex unique bucket index
|
* @param bindex unique bucket index
|
||||||
*/
|
*/
|
||||||
SGBucket(const long int bindex);
|
SGBucket(const long int bindex);
|
||||||
|
|
||||||
#ifndef NO_DEPRECATED_API
|
|
||||||
/**
|
|
||||||
* Reset a bucket to represent a new lat and lon
|
|
||||||
* @param dlon longitude specified in degrees
|
|
||||||
* @param dlat latitude specified in degrees
|
|
||||||
*/
|
|
||||||
void set_bucket(const SGGeod& geod);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reset a bucket to represent a new lat and lon
|
* Reset a bucket to represent a new lat and lon
|
||||||
* @param dlon longitude specified in degrees
|
* @param dlon longitude specified in degrees
|
||||||
* @param dlat latitude specified in degrees
|
* @param dlat latitude specified in degrees
|
||||||
*/
|
*/
|
||||||
void set_bucket( double dlon, double dlat );
|
void set_bucket( double dlon, double dlat );
|
||||||
#endif
|
|
||||||
|
/**
|
||||||
|
* Reset a bucket to represent a new lat and lon
|
||||||
|
* @param lonlat an array of double[2] holding lon and lat
|
||||||
|
* (specified) in degrees
|
||||||
|
*/
|
||||||
|
void set_bucket( double *lonlat );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reset a bucket to represent a new lat and lon
|
||||||
|
* @param dlon longitude specified in degrees
|
||||||
|
* @param dlat latitude specified in degrees
|
||||||
|
*/
|
||||||
|
void set_bucket(const SGGeod& geod);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create an impossible bucket.
|
* Create an impossible bucket.
|
||||||
@@ -160,7 +163,10 @@ public:
|
|||||||
* and you want to make sure last_bucket starts out as something
|
* and you want to make sure last_bucket starts out as something
|
||||||
* impossible.
|
* impossible.
|
||||||
*/
|
*/
|
||||||
void make_bad();
|
inline void make_bad() {
|
||||||
|
set_bucket(0.0, 0.0);
|
||||||
|
lon = -1000;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate the unique scenery tile index for this bucket
|
* Generate the unique scenery tile index for this bucket
|
||||||
@@ -186,7 +192,13 @@ public:
|
|||||||
* string form.
|
* string form.
|
||||||
* @return tile index in string form
|
* @return tile index in string form
|
||||||
*/
|
*/
|
||||||
std::string gen_index_str() const;
|
inline std::string gen_index_str() const {
|
||||||
|
char tmp[20];
|
||||||
|
std::sprintf(tmp, "%ld",
|
||||||
|
(((long)lon + 180) << 14) + ((lat + 90) << 6)
|
||||||
|
+ (y << 3) + x);
|
||||||
|
return (std::string)tmp;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Build the base path name for this bucket.
|
* Build the base path name for this bucket.
|
||||||
@@ -214,13 +226,6 @@ public:
|
|||||||
return lat + y / 8.0 + SG_HALF_BUCKET_SPAN;
|
return lat + y / 8.0 + SG_HALF_BUCKET_SPAN;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the highest (furthest from the equator) latitude of this
|
|
||||||
* tile. This is the top edge for tiles north of the equator, and
|
|
||||||
* the bottom edge for tiles south
|
|
||||||
*/
|
|
||||||
double get_highest_lat() const;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the width of the tile in degrees.
|
* @return the width of the tile in degrees.
|
||||||
*/
|
*/
|
||||||
@@ -282,11 +287,6 @@ public:
|
|||||||
*/
|
*/
|
||||||
inline int get_y() const { return y; }
|
inline int get_y() const { return y; }
|
||||||
|
|
||||||
/**
|
|
||||||
* @return bucket offset from this by dx,dy
|
|
||||||
*/
|
|
||||||
SGBucket sibling(int dx, int dy) const;
|
|
||||||
|
|
||||||
// friends
|
// friends
|
||||||
|
|
||||||
friend std::ostream& operator<< ( std::ostream&, const SGBucket& );
|
friend std::ostream& operator<< ( std::ostream&, const SGBucket& );
|
||||||
@@ -298,7 +298,7 @@ inline bool operator!= (const SGBucket& lhs, const SGBucket& rhs)
|
|||||||
return !(lhs == rhs);
|
return !(lhs == rhs);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef NO_DEPRECATED_API
|
|
||||||
/**
|
/**
|
||||||
* \relates SGBucket
|
* \relates SGBucket
|
||||||
* Return the bucket which is offset from the specified dlon, dlat by
|
* Return the bucket which is offset from the specified dlon, dlat by
|
||||||
@@ -310,7 +310,6 @@ inline bool operator!= (const SGBucket& lhs, const SGBucket& rhs)
|
|||||||
* @return offset bucket
|
* @return offset bucket
|
||||||
*/
|
*/
|
||||||
SGBucket sgBucketOffset( double dlon, double dlat, int x, int y );
|
SGBucket sgBucketOffset( double dlon, double dlat, int x, int y );
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -338,7 +337,12 @@ void sgGetBuckets( const SGGeod& min, const SGGeod& max, std::vector<SGBucket>&
|
|||||||
* @param out output stream
|
* @param out output stream
|
||||||
* @param b bucket
|
* @param b bucket
|
||||||
*/
|
*/
|
||||||
std::ostream& operator<< ( std::ostream& out, const SGBucket& b );
|
inline std::ostream&
|
||||||
|
operator<< ( std::ostream& out, const SGBucket& b )
|
||||||
|
{
|
||||||
|
return out << b.lon << ":" << (int)b.x << ", " << b.lat << ":" << (int)b.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compare two bucket structures for equality.
|
* Compare two bucket structures for equality.
|
||||||
|
|||||||
@@ -1,283 +0,0 @@
|
|||||||
/**************************************************************************
|
|
||||||
* test_bucket.cxx -- unit-tests for SGBucket class
|
|
||||||
*
|
|
||||||
* Copyright (C) 2014 James Turner - <zakalawe@mac.com>
|
|
||||||
*
|
|
||||||
* This library is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU Library General Public
|
|
||||||
* License as published by the Free Software Foundation; either
|
|
||||||
* version 2 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This library is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
* Library General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
||||||
*
|
|
||||||
* $Id$
|
|
||||||
**************************************************************************/
|
|
||||||
|
|
||||||
#include <simgear/compiler.h>
|
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
#include <cstdlib>
|
|
||||||
#include <cstring>
|
|
||||||
|
|
||||||
using std::cout;
|
|
||||||
using std::cerr;
|
|
||||||
using std::endl;
|
|
||||||
|
|
||||||
#include <simgear/bucket/newbucket.hxx>
|
|
||||||
#include <simgear/misc/test_macros.hxx>
|
|
||||||
|
|
||||||
void testBucketSpans()
|
|
||||||
{
|
|
||||||
COMPARE(sg_bucket_span(0.0), 0.125);
|
|
||||||
COMPARE(sg_bucket_span(-20), 0.125);
|
|
||||||
COMPARE(sg_bucket_span(-40), 0.25);
|
|
||||||
COMPARE(sg_bucket_span(89.9), 12.0);
|
|
||||||
COMPARE(sg_bucket_span(88.1), 4.0);
|
|
||||||
COMPARE(sg_bucket_span(-89.9), 12.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void testBasic()
|
|
||||||
{
|
|
||||||
SGBucket b1(5.1, 55.05);
|
|
||||||
COMPARE(b1.get_chunk_lon(), 5);
|
|
||||||
COMPARE(b1.get_chunk_lat(), 55);
|
|
||||||
COMPARE(b1.get_x(), 0);
|
|
||||||
COMPARE(b1.get_y(), 0);
|
|
||||||
COMPARE(b1.gen_index(), 3040320);
|
|
||||||
COMPARE(b1.gen_base_path(), "e000n50/e005n55");
|
|
||||||
VERIFY(b1.isValid());
|
|
||||||
|
|
||||||
SGBucket b2(-10.1, -43.8);
|
|
||||||
COMPARE(b2.get_chunk_lon(), -11);
|
|
||||||
COMPARE(b2.get_chunk_lat(), -44);
|
|
||||||
COMPARE(b2.get_x(), 3);
|
|
||||||
COMPARE(b2.get_y(), 1); // latitude chunks numbered bottom to top, it seems
|
|
||||||
COMPARE(b2.gen_base_path(), "w020s50/w011s44");
|
|
||||||
VERIFY(b2.isValid());
|
|
||||||
|
|
||||||
SGBucket b3(123.48, 9.01);
|
|
||||||
COMPARE(b3.get_chunk_lon(), 123);
|
|
||||||
COMPARE(b3.get_chunk_lat(), 9);
|
|
||||||
COMPARE(b3.get_x(), 3);
|
|
||||||
COMPARE(b3.get_y(), 0);
|
|
||||||
COMPARE(b3.gen_base_path(), "e120n00/e123n09");
|
|
||||||
VERIFY(b3.isValid());
|
|
||||||
|
|
||||||
SGBucket defBuck;
|
|
||||||
VERIFY(!defBuck.isValid());
|
|
||||||
|
|
||||||
b3.make_bad();
|
|
||||||
VERIFY(!b3.isValid());
|
|
||||||
|
|
||||||
SGBucket atAntiMeridian(180.0, 12.3);
|
|
||||||
VERIFY(atAntiMeridian.isValid());
|
|
||||||
COMPARE(atAntiMeridian.get_chunk_lon(), -180);
|
|
||||||
COMPARE(atAntiMeridian.get_x(), 0);
|
|
||||||
|
|
||||||
SGBucket atAntiMeridian2(-180.0, -78.1);
|
|
||||||
VERIFY(atAntiMeridian2.isValid());
|
|
||||||
COMPARE(atAntiMeridian2.get_chunk_lon(), -180);
|
|
||||||
COMPARE(atAntiMeridian2.get_x(), 0);
|
|
||||||
|
|
||||||
// check comparisom operator overload
|
|
||||||
SGBucket b4(5.11, 55.1);
|
|
||||||
VERIFY(b1 == b4); // should be equal
|
|
||||||
VERIFY(b1 == b1);
|
|
||||||
VERIFY(b1 != defBuck);
|
|
||||||
VERIFY(b1 != b2);
|
|
||||||
|
|
||||||
// check wrapping/clipping of inputs
|
|
||||||
SGBucket wrapMeridian(-200.0, 45.0);
|
|
||||||
COMPARE(wrapMeridian.get_chunk_lon(), 160);
|
|
||||||
|
|
||||||
SGBucket clipPole(48.9, 91);
|
|
||||||
COMPARE(clipPole.get_chunk_lat(), 89);
|
|
||||||
}
|
|
||||||
|
|
||||||
void testPolar()
|
|
||||||
{
|
|
||||||
SGBucket b1(0.0, 89.92);
|
|
||||||
SGBucket b2(10.0, 89.96);
|
|
||||||
COMPARE(b1.get_chunk_lat(), 89);
|
|
||||||
COMPARE(b1.get_chunk_lon(), 0);
|
|
||||||
COMPARE(b1.get_x(), 0);
|
|
||||||
COMPARE(b1.get_y(), 7);
|
|
||||||
|
|
||||||
COMPARE_EP(b1.get_highest_lat(), 90.0);
|
|
||||||
COMPARE_EP(b1.get_width_m(), 10.0);
|
|
||||||
|
|
||||||
COMPARE(b2.get_chunk_lat(), 89);
|
|
||||||
COMPARE(b2.get_chunk_lon(), 0);
|
|
||||||
COMPARE(b2.get_x(), 0);
|
|
||||||
COMPARE(b2.get_y(), 7);
|
|
||||||
|
|
||||||
COMPARE(b1.gen_index(), b2.gen_index());
|
|
||||||
|
|
||||||
SGGeod actualNorthPole1 = b1.get_corner(2);
|
|
||||||
SGGeod actualNorthPole2 = b1.get_corner(3);
|
|
||||||
COMPARE_EP(actualNorthPole1.getLatitudeDeg(), 90.0);
|
|
||||||
COMPARE_EP(actualNorthPole1.getLongitudeDeg(), 12.0);
|
|
||||||
COMPARE_EP(actualNorthPole2.getLatitudeDeg(), 90.0);
|
|
||||||
COMPARE_EP(actualNorthPole2.getLongitudeDeg(), 0.0);
|
|
||||||
|
|
||||||
SGBucket b3(-2, 89.88);
|
|
||||||
SGBucket b4(-7, 89.88);
|
|
||||||
COMPARE(b3.gen_index(), b4.gen_index());
|
|
||||||
|
|
||||||
// south pole
|
|
||||||
SGBucket b5(-170, -89.88);
|
|
||||||
SGBucket b6(-179, -89.88);
|
|
||||||
|
|
||||||
COMPARE(b5.get_chunk_lat(), -90);
|
|
||||||
COMPARE(b5.get_chunk_lon(), -180);
|
|
||||||
COMPARE(b5.get_x(), 0);
|
|
||||||
COMPARE(b5.get_y(), 0);
|
|
||||||
COMPARE(b5.gen_index(), b6.gen_index());
|
|
||||||
COMPARE_EP(b5.get_highest_lat(), -90.0);
|
|
||||||
COMPARE_EP(b5.get_width_m(), 10.0);
|
|
||||||
|
|
||||||
SGGeod actualSouthPole1 = b5.get_corner(0);
|
|
||||||
SGGeod actualSouthPole2 = b5.get_corner(1);
|
|
||||||
COMPARE_EP(actualSouthPole1.getLatitudeDeg(), -90.0);
|
|
||||||
COMPARE_EP(actualSouthPole1.getLongitudeDeg(), -180);
|
|
||||||
COMPARE_EP(actualSouthPole2.getLatitudeDeg(), -90.0);
|
|
||||||
COMPARE_EP(actualSouthPole2.getLongitudeDeg(), -168);
|
|
||||||
|
|
||||||
SGBucket b7(200, 89.88);
|
|
||||||
COMPARE(b7.get_chunk_lon(), -168);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// test the tiles just below the pole (between 86 & 89 degrees N/S)
|
|
||||||
void testNearPolar()
|
|
||||||
{
|
|
||||||
SGBucket b1(1, 88.5);
|
|
||||||
SGBucket b2(-1, 88.8);
|
|
||||||
COMPARE(b1.get_chunk_lon(), 0);
|
|
||||||
COMPARE(b1.get_chunk_lat(), 88);
|
|
||||||
VERIFY(b1.gen_index() != b2.gen_index());
|
|
||||||
|
|
||||||
SGBucket b3(176.1, 88.5);
|
|
||||||
COMPARE(b3.get_chunk_lon(), 176);
|
|
||||||
|
|
||||||
SGBucket b4(-178, 88.5);
|
|
||||||
COMPARE(b4.get_chunk_lon(), -180);
|
|
||||||
}
|
|
||||||
|
|
||||||
void testOffset()
|
|
||||||
{
|
|
||||||
// bucket just below the 22 degree cutoff, so the next tile north
|
|
||||||
// is twice the width
|
|
||||||
SGBucket b1(-59.8, 21.9);
|
|
||||||
COMPARE(b1.get_chunk_lat(), 21);
|
|
||||||
COMPARE(b1.get_chunk_lon(), -60);
|
|
||||||
COMPARE(b1.get_x(), 1);
|
|
||||||
COMPARE(b1.get_y(), 7);
|
|
||||||
|
|
||||||
// offset vertically
|
|
||||||
SGBucket b2(b1.sibling(0, 1));
|
|
||||||
COMPARE(b2.get_chunk_lat(), 22);
|
|
||||||
COMPARE(b2.get_chunk_lon(), -60);
|
|
||||||
COMPARE(b2.get_x(), 0);
|
|
||||||
COMPARE(b2.get_y(), 0);
|
|
||||||
|
|
||||||
COMPARE(b2.gen_index(), sgBucketOffset(-59.8, 21.9, 0, 1));
|
|
||||||
|
|
||||||
// offset vertically and horizontally. We compute horizontal (x)
|
|
||||||
// movement at the target latitude, so this should move 0.25 * -3 degrees,
|
|
||||||
// NOT 0.125 * -3 degrees.
|
|
||||||
SGBucket b3(b1.sibling(-3, 1));
|
|
||||||
COMPARE(b3.get_chunk_lat(), 22);
|
|
||||||
COMPARE(b3.get_chunk_lon(), -61);
|
|
||||||
COMPARE(b3.get_x(), 1);
|
|
||||||
COMPARE(b3.get_y(), 0);
|
|
||||||
|
|
||||||
COMPARE(b3.gen_index(), sgBucketOffset(-59.8, 21.9, -3, 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
void testPolarOffset()
|
|
||||||
{
|
|
||||||
SGBucket b1(-11.7, -89.6);
|
|
||||||
COMPARE(b1.get_chunk_lat(), -90);
|
|
||||||
COMPARE(b1.get_chunk_lon(), -12);
|
|
||||||
COMPARE(b1.get_x(), 0);
|
|
||||||
COMPARE(b1.get_y(), 3);
|
|
||||||
|
|
||||||
// offset horizontally
|
|
||||||
SGBucket b2(b1.sibling(-2, 0));
|
|
||||||
COMPARE(b2.get_chunk_lat(), -90);
|
|
||||||
COMPARE(b2.get_chunk_lon(), -36);
|
|
||||||
COMPARE(b2.get_x(), 0);
|
|
||||||
COMPARE(b2.get_y(), 3);
|
|
||||||
|
|
||||||
COMPARE(b2.gen_index(), sgBucketOffset(-11.7, -89.6, -2, 0));
|
|
||||||
|
|
||||||
// offset and wrap
|
|
||||||
SGBucket b3(-170, 89.1);
|
|
||||||
SGBucket b4(b3.sibling(-1, 0));
|
|
||||||
COMPARE(b4.get_chunk_lat(), 89);
|
|
||||||
COMPARE(b4.get_chunk_lon(), 168);
|
|
||||||
COMPARE(b4.get_x(), 0);
|
|
||||||
COMPARE(b4.get_y(), 0);
|
|
||||||
|
|
||||||
COMPARE(b4.gen_index(), sgBucketOffset(-170, 89.1, -1, 0));
|
|
||||||
|
|
||||||
|
|
||||||
SGBucket b5(177, 87.3);
|
|
||||||
SGBucket b6(b5.sibling(1, 1));
|
|
||||||
COMPARE(b6.get_chunk_lat(), 87);
|
|
||||||
COMPARE(b6.get_chunk_lon(), -180);
|
|
||||||
COMPARE(b6.get_x(), 0);
|
|
||||||
COMPARE(b6.get_y(), 3);
|
|
||||||
|
|
||||||
COMPARE(b6.gen_index(), sgBucketOffset(177, 87.3, 1, 1));
|
|
||||||
|
|
||||||
// offset vertically towards the pole
|
|
||||||
SGBucket b7(b1.sibling(0, -5));
|
|
||||||
VERIFY(!b7.isValid());
|
|
||||||
|
|
||||||
VERIFY(!SGBucket(0, 90).sibling(0, 1).isValid());
|
|
||||||
}
|
|
||||||
|
|
||||||
// test behaviour of bucket-offset near the anti-meridian (180-meridian)
|
|
||||||
void testOffsetWrap()
|
|
||||||
{
|
|
||||||
// near the equator
|
|
||||||
SGBucket b1(-179.8, 16.8);
|
|
||||||
COMPARE(b1.get_chunk_lat(), 16);
|
|
||||||
COMPARE(b1.get_chunk_lon(), -180);
|
|
||||||
COMPARE(b1.get_x(), 1);
|
|
||||||
COMPARE(b1.get_y(), 6);
|
|
||||||
|
|
||||||
SGBucket b2(b1.sibling(-2, 0));
|
|
||||||
COMPARE(b2.get_chunk_lat(), 16);
|
|
||||||
COMPARE(b2.get_chunk_lon(), 179);
|
|
||||||
COMPARE(b2.get_x(), 7);
|
|
||||||
COMPARE(b2.get_y(), 6);
|
|
||||||
COMPARE(b2.gen_index(), sgBucketOffset(-179.8, 16.8, -2, 0));
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char* argv[])
|
|
||||||
{
|
|
||||||
testBucketSpans();
|
|
||||||
|
|
||||||
testBasic();
|
|
||||||
testPolar();
|
|
||||||
testNearPolar();
|
|
||||||
testOffset();
|
|
||||||
testOffsetWrap();
|
|
||||||
testPolarOffset();
|
|
||||||
|
|
||||||
cout << "all tests passed OK" << endl;
|
|
||||||
return 0; // passed
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -11,7 +11,7 @@ set(HEADERS
|
|||||||
CanvasObjectPlacement.hxx
|
CanvasObjectPlacement.hxx
|
||||||
CanvasPlacement.hxx
|
CanvasPlacement.hxx
|
||||||
CanvasSystemAdapter.hxx
|
CanvasSystemAdapter.hxx
|
||||||
CanvasWindow.hxx
|
MouseEvent.hxx
|
||||||
ODGauge.hxx
|
ODGauge.hxx
|
||||||
VGInitOperation.hxx
|
VGInitOperation.hxx
|
||||||
)
|
)
|
||||||
@@ -24,14 +24,11 @@ set(SOURCES
|
|||||||
CanvasMgr.cxx
|
CanvasMgr.cxx
|
||||||
CanvasObjectPlacement.cxx
|
CanvasObjectPlacement.cxx
|
||||||
CanvasPlacement.cxx
|
CanvasPlacement.cxx
|
||||||
CanvasWindow.cxx
|
|
||||||
ODGauge.cxx
|
ODGauge.cxx
|
||||||
VGInitOperation.cxx
|
VGInitOperation.cxx
|
||||||
)
|
)
|
||||||
|
|
||||||
add_subdirectory(ShivaVG/src)
|
add_subdirectory(ShivaVG/src)
|
||||||
add_subdirectory(elements)
|
add_subdirectory(elements)
|
||||||
add_subdirectory(events)
|
|
||||||
add_subdirectory(layout)
|
|
||||||
|
|
||||||
simgear_scene_component(canvas canvas "${SOURCES}" "${HEADERS}")
|
simgear_scene_component(canvas canvas "${SOURCES}" "${HEADERS}")
|
||||||
|
|||||||
+50
-85
@@ -19,8 +19,8 @@
|
|||||||
#include "Canvas.hxx"
|
#include "Canvas.hxx"
|
||||||
#include "CanvasEventManager.hxx"
|
#include "CanvasEventManager.hxx"
|
||||||
#include "CanvasEventVisitor.hxx"
|
#include "CanvasEventVisitor.hxx"
|
||||||
#include "CanvasPlacement.hxx"
|
#include <simgear/canvas/MouseEvent.hxx>
|
||||||
#include <simgear/canvas/events/MouseEvent.hxx>
|
#include <simgear/canvas/CanvasPlacement.hxx>
|
||||||
#include <simgear/scene/util/parse_color.hxx>
|
#include <simgear/scene/util/parse_color.hxx>
|
||||||
#include <simgear/scene/util/RenderConstants.hxx>
|
#include <simgear/scene/util/RenderConstants.hxx>
|
||||||
|
|
||||||
@@ -48,12 +48,8 @@ namespace canvas
|
|||||||
void Canvas::CullCallback::operator()( osg::Node* node,
|
void Canvas::CullCallback::operator()( osg::Node* node,
|
||||||
osg::NodeVisitor* nv )
|
osg::NodeVisitor* nv )
|
||||||
{
|
{
|
||||||
if( (nv->getTraversalMask() & simgear::MODEL_BIT) )
|
if( (nv->getTraversalMask() & simgear::MODEL_BIT) && !_canvas.expired() )
|
||||||
{
|
_canvas.lock()->enableRendering();
|
||||||
CanvasPtr canvas = _canvas.lock();
|
|
||||||
if( canvas )
|
|
||||||
canvas->enableRendering();
|
|
||||||
}
|
|
||||||
|
|
||||||
traverse(node, nv);
|
traverse(node, nv);
|
||||||
}
|
}
|
||||||
@@ -76,13 +72,6 @@ namespace canvas
|
|||||||
{
|
{
|
||||||
_status = 0;
|
_status = 0;
|
||||||
setStatusFlags(MISSING_SIZE_X | MISSING_SIZE_Y);
|
setStatusFlags(MISSING_SIZE_X | MISSING_SIZE_Y);
|
||||||
|
|
||||||
_root_group.reset( new Group(this, _node) );
|
|
||||||
|
|
||||||
// Remove automatically created property listener as we forward them on our
|
|
||||||
// own
|
|
||||||
_root_group->removeListener();
|
|
||||||
_cull_callback = new CullCallback(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
@@ -191,14 +180,6 @@ namespace canvas
|
|||||||
return _root_group;
|
return _root_group;
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
void Canvas::setLayout(const LayoutRef& layout)
|
|
||||||
{
|
|
||||||
_layout = layout;
|
|
||||||
_layout->setCanvas(this);
|
|
||||||
_status |= LAYOUT_DIRTY;
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
void Canvas::enableRendering(bool force)
|
void Canvas::enableRendering(bool force)
|
||||||
{
|
{
|
||||||
@@ -210,10 +191,11 @@ namespace canvas
|
|||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
void Canvas::update(double delta_time_sec)
|
void Canvas::update(double delta_time_sec)
|
||||||
{
|
{
|
||||||
if( _status & (CREATE_FAILED | MISSING_SIZE) )
|
if( (!_texture.serviceable() && _status != STATUS_DIRTY)
|
||||||
|
|| (_status & CREATE_FAILED) )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if( _status & STATUS_DIRTY )
|
if( _status == STATUS_DIRTY )
|
||||||
{
|
{
|
||||||
_texture.setSize(_size_x, _size_y);
|
_texture.setSize(_size_x, _size_y);
|
||||||
|
|
||||||
@@ -255,36 +237,23 @@ namespace canvas
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if( _layout )
|
|
||||||
{
|
|
||||||
if( (_status & LAYOUT_DIRTY) )
|
|
||||||
{
|
|
||||||
_layout->setGeometry(SGRecti(0, 0, _view_width, _view_height));
|
|
||||||
_status &= ~LAYOUT_DIRTY;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
_layout->update();
|
|
||||||
}
|
|
||||||
|
|
||||||
if( _visible || _render_always )
|
if( _visible || _render_always )
|
||||||
{
|
{
|
||||||
BOOST_FOREACH(CanvasWeakPtr canvas_weak, _child_canvases)
|
BOOST_FOREACH(CanvasWeakPtr canvas, _child_canvases)
|
||||||
{
|
{
|
||||||
// TODO should we check if the image the child canvas is displayed
|
// TODO should we check if the image the child canvas is displayed
|
||||||
// within is really visible?
|
// within is really visible?
|
||||||
CanvasPtr canvas = canvas_weak.lock();
|
if( !canvas.expired() )
|
||||||
if( canvas )
|
canvas.lock()->_visible = true;
|
||||||
canvas->_visible = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if( _render_dirty )
|
if( _render_dirty )
|
||||||
{
|
{
|
||||||
// Also mark all canvases this canvas is displayed within as dirty
|
// Also mark all canvases this canvas is displayed within as dirty
|
||||||
BOOST_FOREACH(CanvasWeakPtr canvas_weak, _parent_canvases)
|
BOOST_FOREACH(CanvasWeakPtr canvas, _parent_canvases)
|
||||||
{
|
{
|
||||||
CanvasPtr canvas = canvas_weak.lock();
|
if( !canvas.expired() )
|
||||||
if( canvas )
|
canvas.lock()->_render_dirty = true;
|
||||||
canvas->_render_dirty = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -327,7 +296,11 @@ namespace canvas
|
|||||||
if( placement_factory != _placement_factories.end() )
|
if( placement_factory != _placement_factories.end() )
|
||||||
{
|
{
|
||||||
Placements& placements = _placements[ node->getIndex() ] =
|
Placements& placements = _placements[ node->getIndex() ] =
|
||||||
placement_factory->second(node, this);
|
placement_factory->second
|
||||||
|
(
|
||||||
|
node,
|
||||||
|
boost::static_pointer_cast<Canvas>(_self.lock())
|
||||||
|
);
|
||||||
node->setStringValue
|
node->setStringValue
|
||||||
(
|
(
|
||||||
"status-msg",
|
"status-msg",
|
||||||
@@ -344,20 +317,11 @@ namespace canvas
|
|||||||
const EventListener& cb )
|
const EventListener& cb )
|
||||||
{
|
{
|
||||||
if( !_root_group.get() )
|
if( !_root_group.get() )
|
||||||
throw std::runtime_error("Canvas::addEventListener: no root group!");
|
throw std::runtime_error("Canvas::AddEventListener: no root group!");
|
||||||
|
|
||||||
return _root_group->addEventListener(type, cb);
|
return _root_group->addEventListener(type, cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
bool Canvas::dispatchEvent(const EventPtr& event)
|
|
||||||
{
|
|
||||||
if( !_root_group.get() )
|
|
||||||
throw std::runtime_error("Canvas::dispatchEvent: no root group!");
|
|
||||||
|
|
||||||
return _root_group->dispatchEvent(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
void Canvas::setSizeX(int sx)
|
void Canvas::setSizeX(int sx)
|
||||||
{
|
{
|
||||||
@@ -410,7 +374,6 @@ namespace canvas
|
|||||||
if( _view_width == w )
|
if( _view_width == w )
|
||||||
return;
|
return;
|
||||||
_view_width = w;
|
_view_width = w;
|
||||||
_status |= LAYOUT_DIRTY;
|
|
||||||
|
|
||||||
_texture.setViewSize(_view_width, _view_height);
|
_texture.setViewSize(_view_width, _view_height);
|
||||||
}
|
}
|
||||||
@@ -421,7 +384,6 @@ namespace canvas
|
|||||||
if( _view_height == h )
|
if( _view_height == h )
|
||||||
return;
|
return;
|
||||||
_view_height = h;
|
_view_height = h;
|
||||||
_status |= LAYOUT_DIRTY;
|
|
||||||
|
|
||||||
_texture.setViewSize(_view_width, _view_height);
|
_texture.setViewSize(_view_width, _view_height);
|
||||||
}
|
}
|
||||||
@@ -447,11 +409,12 @@ namespace canvas
|
|||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
bool Canvas::handleMouseEvent(const MouseEventPtr& event)
|
bool Canvas::handleMouseEvent(const MouseEventPtr& event)
|
||||||
{
|
{
|
||||||
if( !_root_group )
|
if( !_root_group.get() )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
EventVisitor visitor( EventVisitor::TRAVERSE_DOWN,
|
EventVisitor visitor( EventVisitor::TRAVERSE_DOWN,
|
||||||
event->getClientPos(),
|
event->getClientPos(),
|
||||||
|
event->getDelta(),
|
||||||
_root_group );
|
_root_group );
|
||||||
if( !_root_group->accept(visitor) )
|
if( !_root_group->accept(visitor) )
|
||||||
return false;
|
return false;
|
||||||
@@ -459,13 +422,6 @@ namespace canvas
|
|||||||
return _event_manager->handleEvent(event, visitor.getPropagationPath());
|
return _event_manager->handleEvent(event, visitor.getPropagationPath());
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
bool Canvas::propagateEvent( EventPtr const& event,
|
|
||||||
EventPropagationPath const& path )
|
|
||||||
{
|
|
||||||
return _event_manager->propagateEvent(event, path);
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
void Canvas::childAdded( SGPropertyNode * parent,
|
void Canvas::childAdded( SGPropertyNode * parent,
|
||||||
SGPropertyNode * child )
|
SGPropertyNode * child )
|
||||||
@@ -497,10 +453,8 @@ namespace canvas
|
|||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
void Canvas::valueChanged(SGPropertyNode* node)
|
void Canvas::valueChanged(SGPropertyNode* node)
|
||||||
{
|
{
|
||||||
const std::string& name = node->getNameString();
|
if( boost::starts_with(node->getNameString(), "status")
|
||||||
|
|| node->getParent()->getNameString() == "bounding-box" )
|
||||||
if( boost::starts_with(name, "status")
|
|
||||||
|| boost::starts_with(name, "data-") )
|
|
||||||
return;
|
return;
|
||||||
_render_dirty = true;
|
_render_dirty = true;
|
||||||
|
|
||||||
@@ -539,7 +493,7 @@ namespace canvas
|
|||||||
}
|
}
|
||||||
else if( node->getParent() == _node )
|
else if( node->getParent() == _node )
|
||||||
{
|
{
|
||||||
if( name == "background" )
|
if( node->getNameString() == "background" )
|
||||||
{
|
{
|
||||||
osg::Vec4 color;
|
osg::Vec4 color;
|
||||||
if( _texture.getCamera() && parseColor(node->getStringValue(), color) )
|
if( _texture.getCamera() && parseColor(node->getStringValue(), color) )
|
||||||
@@ -548,41 +502,35 @@ namespace canvas
|
|||||||
_render_dirty = true;
|
_render_dirty = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if( name == "mipmapping"
|
else if( node->getNameString() == "mipmapping"
|
||||||
|| name == "coverage-samples"
|
|| node->getNameString() == "coverage-samples"
|
||||||
|| name == "color-samples" )
|
|| node->getNameString() == "color-samples" )
|
||||||
{
|
{
|
||||||
_sampling_dirty = true;
|
_sampling_dirty = true;
|
||||||
}
|
}
|
||||||
else if( name == "additive-blend" )
|
else if( node->getNameString() == "additive-blend" )
|
||||||
{
|
{
|
||||||
_texture.useAdditiveBlend( node->getBoolValue() );
|
_texture.useAdditiveBlend( node->getBoolValue() );
|
||||||
}
|
}
|
||||||
else if( name == "render-always" )
|
else if( node->getNameString() == "render-always" )
|
||||||
{
|
{
|
||||||
_render_always = node->getBoolValue();
|
_render_always = node->getBoolValue();
|
||||||
}
|
}
|
||||||
else if( name == "size" )
|
else if( node->getNameString() == "size" )
|
||||||
{
|
{
|
||||||
if( node->getIndex() == 0 )
|
if( node->getIndex() == 0 )
|
||||||
setSizeX( node->getIntValue() );
|
setSizeX( node->getIntValue() );
|
||||||
else if( node->getIndex() == 1 )
|
else if( node->getIndex() == 1 )
|
||||||
setSizeY( node->getIntValue() );
|
setSizeY( node->getIntValue() );
|
||||||
}
|
}
|
||||||
else if( name == "update" )
|
else if( node->getNameString() == "view" )
|
||||||
{
|
|
||||||
if( _root_group )
|
|
||||||
_root_group->update(0);
|
|
||||||
return update(0);
|
|
||||||
}
|
|
||||||
else if( name == "view" )
|
|
||||||
{
|
{
|
||||||
if( node->getIndex() == 0 )
|
if( node->getIndex() == 0 )
|
||||||
setViewWidth( node->getIntValue() );
|
setViewWidth( node->getIntValue() );
|
||||||
else if( node->getIndex() == 1 )
|
else if( node->getIndex() == 1 )
|
||||||
setViewHeight( node->getIntValue() );
|
setViewHeight( node->getIntValue() );
|
||||||
}
|
}
|
||||||
else if( name == "freeze" )
|
else if( node->getNameString() == "freeze" )
|
||||||
_texture.setRender( node->getBoolValue() );
|
_texture.setRender( node->getBoolValue() );
|
||||||
else
|
else
|
||||||
handled = false;
|
handled = false;
|
||||||
@@ -667,6 +615,23 @@ namespace canvas
|
|||||||
return _system_adapter;
|
return _system_adapter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void Canvas::setSelf(const PropertyBasedElementPtr& self)
|
||||||
|
{
|
||||||
|
PropertyBasedElement::setSelf(self);
|
||||||
|
|
||||||
|
CanvasPtr canvas = boost::static_pointer_cast<Canvas>(self);
|
||||||
|
|
||||||
|
_root_group.reset( new Group(canvas, _node) );
|
||||||
|
_root_group->setSelf(_root_group);
|
||||||
|
|
||||||
|
// Remove automatically created property listener as we forward them on our
|
||||||
|
// own
|
||||||
|
_root_group->removeListener();
|
||||||
|
|
||||||
|
_cull_callback = new CullCallback(canvas);
|
||||||
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
void Canvas::setStatusFlags(unsigned int flags, bool set)
|
void Canvas::setStatusFlags(unsigned int flags, bool set)
|
||||||
{
|
{
|
||||||
@@ -683,7 +648,7 @@ namespace canvas
|
|||||||
_status_msg = "Missing size-y";
|
_status_msg = "Missing size-y";
|
||||||
else if( _status & CREATE_FAILED )
|
else if( _status & CREATE_FAILED )
|
||||||
_status_msg = "Creating render target failed";
|
_status_msg = "Creating render target failed";
|
||||||
else if( _status & STATUS_DIRTY )
|
else if( _status == STATUS_DIRTY )
|
||||||
_status_msg = "Creation pending...";
|
_status_msg = "Creation pending...";
|
||||||
else
|
else
|
||||||
_status_msg = "Ok";
|
_status_msg = "Ok";
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
///@file The canvas for rendering with the 2d API
|
// The canvas for rendering with the 2d API
|
||||||
//
|
//
|
||||||
// Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com>
|
// Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com>
|
||||||
//
|
//
|
||||||
@@ -23,12 +23,9 @@
|
|||||||
#include "ODGauge.hxx"
|
#include "ODGauge.hxx"
|
||||||
|
|
||||||
#include <simgear/canvas/elements/CanvasGroup.hxx>
|
#include <simgear/canvas/elements/CanvasGroup.hxx>
|
||||||
#include <simgear/canvas/layout/Layout.hxx>
|
|
||||||
#include <simgear/math/SGRect.hxx>
|
#include <simgear/math/SGRect.hxx>
|
||||||
#include <simgear/nasal/cppbind/NasalObject.hxx>
|
|
||||||
#include <simgear/props/PropertyBasedElement.hxx>
|
#include <simgear/props/PropertyBasedElement.hxx>
|
||||||
#include <simgear/props/propertyObject.hxx>
|
#include <simgear/props/propertyObject.hxx>
|
||||||
|
|
||||||
#include <osg/NodeCallback>
|
#include <osg/NodeCallback>
|
||||||
#include <osg/observer_ptr>
|
#include <osg/observer_ptr>
|
||||||
|
|
||||||
@@ -37,15 +34,13 @@
|
|||||||
|
|
||||||
namespace simgear
|
namespace simgear
|
||||||
{
|
{
|
||||||
/// Canvas 2D drawing API
|
|
||||||
namespace canvas
|
namespace canvas
|
||||||
{
|
{
|
||||||
class CanvasMgr;
|
class CanvasMgr;
|
||||||
class MouseEvent;
|
class MouseEvent;
|
||||||
|
|
||||||
class Canvas:
|
class Canvas:
|
||||||
public PropertyBasedElement,
|
public PropertyBasedElement
|
||||||
public nasal::Object
|
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
@@ -53,10 +48,8 @@ namespace canvas
|
|||||||
{
|
{
|
||||||
STATUS_OK,
|
STATUS_OK,
|
||||||
STATUS_DIRTY = 1,
|
STATUS_DIRTY = 1,
|
||||||
LAYOUT_DIRTY = STATUS_DIRTY << 1,
|
MISSING_SIZE_X = STATUS_DIRTY << 1,
|
||||||
MISSING_SIZE_X = LAYOUT_DIRTY << 1,
|
|
||||||
MISSING_SIZE_Y = MISSING_SIZE_X << 1,
|
MISSING_SIZE_Y = MISSING_SIZE_X << 1,
|
||||||
MISSING_SIZE = MISSING_SIZE_X | MISSING_SIZE_Y,
|
|
||||||
CREATE_FAILED = MISSING_SIZE_Y << 1
|
CREATE_FAILED = MISSING_SIZE_Y << 1
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -127,12 +120,6 @@ namespace canvas
|
|||||||
*/
|
*/
|
||||||
GroupPtr getRootGroup();
|
GroupPtr getRootGroup();
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the layout of the canvas (the layout will automatically update with
|
|
||||||
* the viewport size of the canvas)
|
|
||||||
*/
|
|
||||||
void setLayout(const LayoutRef& layout);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enable rendering for the next frame
|
* Enable rendering for the next frame
|
||||||
*
|
*
|
||||||
@@ -144,7 +131,6 @@ namespace canvas
|
|||||||
void update(double delta_time_sec);
|
void update(double delta_time_sec);
|
||||||
|
|
||||||
bool addEventListener(const std::string& type, const EventListener& cb);
|
bool addEventListener(const std::string& type, const EventListener& cb);
|
||||||
bool dispatchEvent(const EventPtr& event);
|
|
||||||
|
|
||||||
void setSizeX(int sx);
|
void setSizeX(int sx);
|
||||||
void setSizeY(int sy);
|
void setSizeY(int sy);
|
||||||
@@ -160,8 +146,6 @@ namespace canvas
|
|||||||
SGRect<int> getViewport() const;
|
SGRect<int> getViewport() const;
|
||||||
|
|
||||||
bool handleMouseEvent(const MouseEventPtr& event);
|
bool handleMouseEvent(const MouseEventPtr& event);
|
||||||
bool propagateEvent( EventPtr const& event,
|
|
||||||
EventPropagationPath const& path );
|
|
||||||
|
|
||||||
virtual void childAdded( SGPropertyNode * parent,
|
virtual void childAdded( SGPropertyNode * parent,
|
||||||
SGPropertyNode * child );
|
SGPropertyNode * child );
|
||||||
@@ -207,9 +191,7 @@ namespace canvas
|
|||||||
_visible;
|
_visible;
|
||||||
|
|
||||||
ODGauge _texture;
|
ODGauge _texture;
|
||||||
|
|
||||||
GroupPtr _root_group;
|
GroupPtr _root_group;
|
||||||
LayoutRef _layout;
|
|
||||||
|
|
||||||
CullCallbackPtr _cull_callback;
|
CullCallbackPtr _cull_callback;
|
||||||
bool _render_always; //<! Used to disable automatic lazy rendering (culling)
|
bool _render_always; //<! Used to disable automatic lazy rendering (culling)
|
||||||
@@ -223,6 +205,7 @@ namespace canvas
|
|||||||
typedef std::map<std::string, PlacementFactory> PlacementFactoryMap;
|
typedef std::map<std::string, PlacementFactory> PlacementFactoryMap;
|
||||||
static PlacementFactoryMap _placement_factories;
|
static PlacementFactoryMap _placement_factories;
|
||||||
|
|
||||||
|
virtual void setSelf(const PropertyBasedElementPtr& self);
|
||||||
void setStatusFlags(unsigned int flags, bool set = true);
|
void setStatusFlags(unsigned int flags, bool set = true);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@@ -26,7 +26,6 @@ namespace canvas
|
|||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
Event::Event():
|
Event::Event():
|
||||||
type(UNKNOWN),
|
type(UNKNOWN),
|
||||||
time(-1),
|
|
||||||
propagation_stopped(false)
|
propagation_stopped(false)
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -39,13 +38,7 @@ namespace canvas
|
|||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
bool Event::canBubble() const
|
Event::Type Event::getType() const
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
int Event::getType() const
|
|
||||||
{
|
{
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
@@ -53,7 +46,14 @@ namespace canvas
|
|||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
std::string Event::getTypeString() const
|
std::string Event::getTypeString() const
|
||||||
{
|
{
|
||||||
return typeToStr(type);
|
switch( type )
|
||||||
|
{
|
||||||
|
# define ENUM_MAPPING(name, str) case name: return str;
|
||||||
|
# include "CanvasEventTypes.hxx"
|
||||||
|
# undef ENUM_MAPPING
|
||||||
|
default:
|
||||||
|
return "unknown";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
@@ -81,57 +81,23 @@ namespace canvas
|
|||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
int Event::getOrRegisterType(const std::string& type_str)
|
Event::Type Event::strToType(const std::string& str)
|
||||||
{
|
|
||||||
int type = strToType(type_str);
|
|
||||||
|
|
||||||
if( type == UNKNOWN )
|
|
||||||
{
|
|
||||||
// Register new type
|
|
||||||
TypeMap& type_map = getTypeMap();
|
|
||||||
type = type_map.size() + 1; // ids start with 1 (after UNKNOWN)
|
|
||||||
type_map.insert(TypeMap::value_type(type_str, type));
|
|
||||||
}
|
|
||||||
|
|
||||||
return type;
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
int Event::strToType(const std::string& str)
|
|
||||||
{
|
|
||||||
TypeMap const& type_map = getTypeMap();
|
|
||||||
|
|
||||||
TypeMap::map_by<name>::const_iterator it = type_map.by<name>().find(str);
|
|
||||||
if( it == type_map.by<name>().end() )
|
|
||||||
return UNKNOWN;
|
|
||||||
return it->second;
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
std::string Event::typeToStr(int type)
|
|
||||||
{
|
|
||||||
TypeMap const& type_map = getTypeMap();
|
|
||||||
|
|
||||||
TypeMap::map_by<id>::const_iterator it = type_map.by<id>().find(type);
|
|
||||||
if( it == type_map.by<id>().end() )
|
|
||||||
return "unknown";
|
|
||||||
return it->second;
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
Event::TypeMap& Event::getTypeMap()
|
|
||||||
{
|
{
|
||||||
|
typedef std::map<std::string, Type> TypeMap;
|
||||||
static TypeMap type_map;
|
static TypeMap type_map;
|
||||||
|
|
||||||
if( type_map.empty() )
|
if( type_map.empty() )
|
||||||
{
|
{
|
||||||
# define ENUM_MAPPING(type, str)\
|
# define ENUM_MAPPING(type, str) type_map[ str ] = type;
|
||||||
type_map.insert(TypeMap::value_type(str, type));
|
|
||||||
# include "CanvasEventTypes.hxx"
|
# include "CanvasEventTypes.hxx"
|
||||||
# undef ENUM_MAPPING
|
# undef ENUM_MAPPING
|
||||||
}
|
}
|
||||||
|
|
||||||
return type_map;
|
TypeMap::const_iterator it = type_map.find(str);
|
||||||
|
if( it == type_map.end() )
|
||||||
|
return UNKNOWN;
|
||||||
|
|
||||||
|
return it->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace canvas
|
} // namespace canvas
|
||||||
|
|||||||
@@ -20,15 +20,13 @@
|
|||||||
#define CANVAS_EVENT_HXX_
|
#define CANVAS_EVENT_HXX_
|
||||||
|
|
||||||
#include "canvas_fwd.hxx"
|
#include "canvas_fwd.hxx"
|
||||||
#include <boost/bimap.hpp>
|
|
||||||
|
|
||||||
namespace simgear
|
namespace simgear
|
||||||
{
|
{
|
||||||
namespace canvas
|
namespace canvas
|
||||||
{
|
{
|
||||||
|
|
||||||
class Event:
|
class Event
|
||||||
public SGReferenced
|
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
@@ -38,11 +36,11 @@ namespace canvas
|
|||||||
# define ENUM_MAPPING(name, str) name,
|
# define ENUM_MAPPING(name, str) name,
|
||||||
# include "CanvasEventTypes.hxx"
|
# include "CanvasEventTypes.hxx"
|
||||||
# undef ENUM_MAPPING
|
# undef ENUM_MAPPING
|
||||||
CUSTOM_EVENT ///< all user defined event types share the same id. They
|
USER_TYPE ///<! first unused id to be used for user defined types (not
|
||||||
/// are just differentiated by using the type string.
|
/// implemented yet)
|
||||||
};
|
};
|
||||||
|
|
||||||
int type;
|
Type type;
|
||||||
ElementWeakPtr target,
|
ElementWeakPtr target,
|
||||||
current_target;
|
current_target;
|
||||||
double time;
|
double time;
|
||||||
@@ -54,19 +52,7 @@ namespace canvas
|
|||||||
// of the actual event instances.
|
// of the actual event instances.
|
||||||
virtual ~Event();
|
virtual ~Event();
|
||||||
|
|
||||||
/**
|
Type getType() const;
|
||||||
* Get whether this events support bubbling
|
|
||||||
*/
|
|
||||||
virtual bool canBubble() const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set type of event.
|
|
||||||
*
|
|
||||||
* If no such type exists it is registered.
|
|
||||||
*/
|
|
||||||
void setType(const std::string& type);
|
|
||||||
|
|
||||||
int getType() const;
|
|
||||||
std::string getTypeString() const;
|
std::string getTypeString() const;
|
||||||
|
|
||||||
ElementWeakPtr getTarget() const;
|
ElementWeakPtr getTarget() const;
|
||||||
@@ -76,19 +62,7 @@ namespace canvas
|
|||||||
|
|
||||||
void stopPropagation();
|
void stopPropagation();
|
||||||
|
|
||||||
static int getOrRegisterType(const std::string& type);
|
static Type strToType(const std::string& str);
|
||||||
static int strToType(const std::string& type);
|
|
||||||
static std::string typeToStr(int type);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
struct name {};
|
|
||||||
struct id {};
|
|
||||||
typedef boost::bimaps::bimap<
|
|
||||||
boost::bimaps::tagged<std::string, name>,
|
|
||||||
boost::bimaps::tagged<int, id>
|
|
||||||
> TypeMap;
|
|
||||||
|
|
||||||
static TypeMap& getTypeMap();
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||||
|
|
||||||
#include "CanvasEventManager.hxx"
|
#include "CanvasEventManager.hxx"
|
||||||
#include <simgear/canvas/events/MouseEvent.hxx>
|
#include "MouseEvent.hxx"
|
||||||
#include <simgear/canvas/elements/CanvasElement.hxx>
|
#include <simgear/canvas/elements/CanvasElement.hxx>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|
||||||
@@ -61,16 +61,6 @@ namespace canvas
|
|||||||
return !path.empty() && time > 0;
|
return !path.empty() && time > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
void EventManager::MouseEventInfo::set( const MouseEventPtr& event,
|
|
||||||
const EventPropagationPath& p )
|
|
||||||
{
|
|
||||||
path = p;
|
|
||||||
time = event->time;
|
|
||||||
button = event->button;
|
|
||||||
pos = event->screen_pos;
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
EventManager::EventManager():
|
EventManager::EventManager():
|
||||||
_current_click_count(0)
|
_current_click_count(0)
|
||||||
@@ -86,7 +76,7 @@ namespace canvas
|
|||||||
switch( event->type )
|
switch( event->type )
|
||||||
{
|
{
|
||||||
case Event::MOUSE_DOWN:
|
case Event::MOUSE_DOWN:
|
||||||
_last_mouse_down.set(event, path);
|
_last_mouse_down = StampedPropagationPath(path, event->getTime());
|
||||||
break;
|
break;
|
||||||
case Event::MOUSE_UP:
|
case Event::MOUSE_UP:
|
||||||
{
|
{
|
||||||
@@ -99,12 +89,12 @@ namespace canvas
|
|||||||
// normal mouseup
|
// normal mouseup
|
||||||
handled |= propagateEvent(event, path);
|
handled |= propagateEvent(event, path);
|
||||||
|
|
||||||
if( !_last_mouse_down.valid() )
|
if( _last_mouse_down.path.empty() )
|
||||||
// Ignore mouse up without any previous mouse down
|
// Ignore mouse up without any previous mouse down
|
||||||
return handled;
|
return handled;
|
||||||
|
|
||||||
// now handle click/dblclick
|
// now handle click/dblclick
|
||||||
if( checkClickDistance(event->screen_pos, _last_mouse_down.pos) )
|
if( checkClickDistance(path, _last_mouse_down.path) )
|
||||||
handled |=
|
handled |=
|
||||||
handleClick(event, getCommonAncestor(_last_mouse_down.path, path));
|
handleClick(event, getCommonAncestor(_last_mouse_down.path, path));
|
||||||
|
|
||||||
@@ -116,11 +106,7 @@ namespace canvas
|
|||||||
if( !_last_mouse_down.valid() )
|
if( !_last_mouse_down.valid() )
|
||||||
return false;
|
return false;
|
||||||
else
|
else
|
||||||
{
|
|
||||||
// OSG does not set button for drag events.
|
|
||||||
event->button = _last_mouse_down.button;
|
|
||||||
return propagateEvent(event, _last_mouse_down.path);
|
return propagateEvent(event, _last_mouse_down.path);
|
||||||
}
|
|
||||||
case Event::MOUSE_MOVE:
|
case Event::MOUSE_MOVE:
|
||||||
handled |= handleMove(event, path);
|
handled |= handleMove(event, path);
|
||||||
break;
|
break;
|
||||||
@@ -144,71 +130,6 @@ namespace canvas
|
|||||||
return handled | propagateEvent(event, path);
|
return handled | propagateEvent(event, path);
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
bool EventManager::propagateEvent( const EventPtr& event,
|
|
||||||
const EventPropagationPath& path )
|
|
||||||
{
|
|
||||||
event->target = path.back().element;
|
|
||||||
MouseEventPtr mouse_event = dynamic_cast<MouseEvent*>(event.get());
|
|
||||||
|
|
||||||
// Event propagation similar to DOM Level 3 event flow:
|
|
||||||
// http://www.w3.org/TR/DOM-Level-3-Events/#event-flow
|
|
||||||
|
|
||||||
// Position update only needed for drag event (as event needs to be
|
|
||||||
// delivered to element of initial mousedown, but with update positions)
|
|
||||||
if( mouse_event && mouse_event->type == MouseEvent::DRAG )
|
|
||||||
{
|
|
||||||
osg::Vec2f local_pos = mouse_event->client_pos;
|
|
||||||
|
|
||||||
// Capturing phase (currently just update position)
|
|
||||||
for( EventPropagationPath::const_iterator it = path.begin();
|
|
||||||
it != path.end();
|
|
||||||
++it )
|
|
||||||
{
|
|
||||||
ElementPtr el = it->element.lock();
|
|
||||||
if( !el )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
it->local_pos = local_pos = el->posToLocal(local_pos);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool const do_bubble = event->canBubble();
|
|
||||||
|
|
||||||
// Bubbling phase
|
|
||||||
for( EventPropagationPath::const_reverse_iterator
|
|
||||||
it = path.rbegin();
|
|
||||||
it != path.rend();
|
|
||||||
++it )
|
|
||||||
{
|
|
||||||
ElementPtr el = it->element.lock();
|
|
||||||
|
|
||||||
if( !el )
|
|
||||||
{
|
|
||||||
// Ignore element if it has been destroyed while traversing the event
|
|
||||||
// (eg. removed by another event handler)
|
|
||||||
if( do_bubble )
|
|
||||||
continue;
|
|
||||||
else
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO provide functions to convert delta to local coordinates on demand.
|
|
||||||
// Maybe also provide a clone method for events as local coordinates
|
|
||||||
// might differ between different elements receiving the same event.
|
|
||||||
if( mouse_event )
|
|
||||||
mouse_event->local_pos = it->local_pos;
|
|
||||||
|
|
||||||
event->current_target = el;
|
|
||||||
el->handleEvent(event);
|
|
||||||
|
|
||||||
if( event->propagation_stopped || !do_bubble )
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
bool EventManager::handleClick( const MouseEventPtr& event,
|
bool EventManager::handleClick( const MouseEventPtr& event,
|
||||||
const EventPropagationPath& path )
|
const EventPropagationPath& path )
|
||||||
@@ -225,10 +146,8 @@ namespace canvas
|
|||||||
|
|
||||||
if( _current_click_count > 1 )
|
if( _current_click_count > 1 )
|
||||||
{
|
{
|
||||||
// Reset current click count if moved too far or different button has
|
// Reset current click count if moved too far
|
||||||
// been clicked
|
if( !checkClickDistance(path, _last_click.path) )
|
||||||
if( !checkClickDistance(event->screen_pos, _last_click.pos)
|
|
||||||
|| _last_click.button != event->button )
|
|
||||||
_current_click_count = 1;
|
_current_click_count = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -248,7 +167,7 @@ namespace canvas
|
|||||||
handled |= propagateEvent( dbl_click,
|
handled |= propagateEvent( dbl_click,
|
||||||
getCommonAncestor(_last_click.path, path) );
|
getCommonAncestor(_last_click.path, path) );
|
||||||
|
|
||||||
_last_click.set(event, path);
|
_last_click = StampedPropagationPath(path, event->getTime());
|
||||||
|
|
||||||
return handled;
|
return handled;
|
||||||
}
|
}
|
||||||
@@ -315,11 +234,88 @@ namespace canvas
|
|||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
bool
|
bool EventManager::propagateEvent( const EventPtr& event,
|
||||||
EventManager::checkClickDistance( const osg::Vec2f& pos1,
|
const EventPropagationPath& path )
|
||||||
const osg::Vec2f& pos2 ) const
|
|
||||||
{
|
{
|
||||||
osg::Vec2 delta = pos1 - pos2;
|
event->target = path.back().element;
|
||||||
|
MouseEventPtr mouse_event = boost::dynamic_pointer_cast<MouseEvent>(event);
|
||||||
|
|
||||||
|
// Event propagation similar to DOM Level 3 event flow:
|
||||||
|
// http://www.w3.org/TR/DOM-Level-3-Events/#event-flow
|
||||||
|
|
||||||
|
// Capturing phase
|
||||||
|
// for( EventPropagationPath::const_iterator it = path.begin();
|
||||||
|
// it != path.end();
|
||||||
|
// ++it )
|
||||||
|
// {
|
||||||
|
// if( !it->element.expired() )
|
||||||
|
// std::cout << it->element.lock()->getProps()->getPath() << std::endl;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// Check if event supports bubbling
|
||||||
|
const Event::Type types_no_bubbling[] = {
|
||||||
|
Event::MOUSE_ENTER,
|
||||||
|
Event::MOUSE_LEAVE,
|
||||||
|
};
|
||||||
|
const size_t num_types_no_bubbling = sizeof(types_no_bubbling)
|
||||||
|
/ sizeof(types_no_bubbling[0]);
|
||||||
|
bool do_bubble = true;
|
||||||
|
for( size_t i = 0; i < num_types_no_bubbling; ++i )
|
||||||
|
if( event->type == types_no_bubbling[i] )
|
||||||
|
{
|
||||||
|
do_bubble = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bubbling phase
|
||||||
|
for( EventPropagationPath::const_reverse_iterator
|
||||||
|
it = path.rbegin();
|
||||||
|
it != path.rend();
|
||||||
|
++it )
|
||||||
|
{
|
||||||
|
ElementPtr el = it->element.lock();
|
||||||
|
|
||||||
|
if( !el )
|
||||||
|
{
|
||||||
|
// Ignore element if it has been destroyed while traversing the event
|
||||||
|
// (eg. removed by another event handler)
|
||||||
|
if( do_bubble )
|
||||||
|
continue;
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO provide functions to convert delta to local coordinates on demand.
|
||||||
|
// Maybe also provide a clone method for events as local coordinates
|
||||||
|
// might differ between different elements receiving the same event.
|
||||||
|
if( mouse_event ) //&& event->type != Event::DRAG )
|
||||||
|
{
|
||||||
|
// TODO transform pos and delta for drag events. Maybe we should just
|
||||||
|
// store the global coordinates and convert to local coordinates
|
||||||
|
// on demand.
|
||||||
|
|
||||||
|
// Position and delta are specified in local coordinate system of
|
||||||
|
// current element
|
||||||
|
mouse_event->local_pos = it->local_pos;
|
||||||
|
//mouse_event->delta = it->local_delta;
|
||||||
|
}
|
||||||
|
|
||||||
|
event->current_target = el;
|
||||||
|
el->handleEvent(event);
|
||||||
|
|
||||||
|
if( event->propagation_stopped || !do_bubble )
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
bool
|
||||||
|
EventManager::checkClickDistance( const EventPropagationPath& path1,
|
||||||
|
const EventPropagationPath& path2 ) const
|
||||||
|
{
|
||||||
|
osg::Vec2 delta = path1.front().local_pos - path2.front().local_pos;
|
||||||
return std::fabs(delta.x()) < drag_threshold
|
return std::fabs(delta.x()) < drag_threshold
|
||||||
&& std::fabs(delta.y()) < drag_threshold;
|
&& std::fabs(delta.y()) < drag_threshold;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,17 +30,10 @@ namespace canvas
|
|||||||
struct EventTarget
|
struct EventTarget
|
||||||
{
|
{
|
||||||
ElementWeakPtr element;
|
ElementWeakPtr element;
|
||||||
|
osg::Vec2f local_pos,
|
||||||
// Used as storage by EventManager during event propagation
|
local_delta;
|
||||||
mutable osg::Vec2f local_pos;
|
|
||||||
|
|
||||||
EventTarget( Element* el,
|
|
||||||
const osg::Vec2f pos = osg::Vec2f() ):
|
|
||||||
element(el),
|
|
||||||
local_pos(pos)
|
|
||||||
{}
|
|
||||||
};
|
};
|
||||||
|
typedef std::deque<EventTarget> EventPropagationPath;
|
||||||
inline bool operator==(const EventTarget& t1, const EventTarget& t2)
|
inline bool operator==(const EventTarget& t1, const EventTarget& t2)
|
||||||
{
|
{
|
||||||
return t1.element.lock() == t2.element.lock();
|
return t1.element.lock() == t2.element.lock();
|
||||||
@@ -54,9 +47,6 @@ namespace canvas
|
|||||||
bool handleEvent( const MouseEventPtr& event,
|
bool handleEvent( const MouseEventPtr& event,
|
||||||
const EventPropagationPath& path );
|
const EventPropagationPath& path );
|
||||||
|
|
||||||
bool propagateEvent( const EventPtr& event,
|
|
||||||
const EventPropagationPath& path );
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
struct StampedPropagationPath
|
struct StampedPropagationPath
|
||||||
{
|
{
|
||||||
@@ -72,20 +62,11 @@ namespace canvas
|
|||||||
|
|
||||||
// TODO if we really need the paths modify to not copy around the paths
|
// TODO if we really need the paths modify to not copy around the paths
|
||||||
// that much.
|
// that much.
|
||||||
StampedPropagationPath _last_mouse_over;
|
StampedPropagationPath _last_mouse_down,
|
||||||
|
_last_click,
|
||||||
|
_last_mouse_over;
|
||||||
size_t _current_click_count;
|
size_t _current_click_count;
|
||||||
|
|
||||||
struct MouseEventInfo:
|
|
||||||
public StampedPropagationPath
|
|
||||||
{
|
|
||||||
int button;
|
|
||||||
osg::Vec2f pos;
|
|
||||||
|
|
||||||
void set( const MouseEventPtr& event,
|
|
||||||
const EventPropagationPath& path );
|
|
||||||
} _last_mouse_down,
|
|
||||||
_last_click;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Propagate click event and handle multi-click (eg. create dblclick)
|
* Propagate click event and handle multi-click (eg. create dblclick)
|
||||||
*/
|
*/
|
||||||
@@ -98,13 +79,16 @@ namespace canvas
|
|||||||
bool handleMove( const MouseEventPtr& event,
|
bool handleMove( const MouseEventPtr& event,
|
||||||
const EventPropagationPath& path );
|
const EventPropagationPath& path );
|
||||||
|
|
||||||
|
bool propagateEvent( const EventPtr& event,
|
||||||
|
const EventPropagationPath& path );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if two click events (either mousedown/up or two consecutive
|
* Check if two click events (either mousedown/up or two consecutive
|
||||||
* clicks) are inside a maximum distance to still create a click or
|
* clicks) are inside a maximum distance to still create a click or
|
||||||
* dblclick event respectively.
|
* dblclick event respectively.
|
||||||
*/
|
*/
|
||||||
bool checkClickDistance( const osg::Vec2f& pos1,
|
bool checkClickDistance( const EventPropagationPath& path1,
|
||||||
const osg::Vec2f& pos2 ) const;
|
const EventPropagationPath& path2 ) const;
|
||||||
EventPropagationPath
|
EventPropagationPath
|
||||||
getCommonAncestor( const EventPropagationPath& path1,
|
getCommonAncestor( const EventPropagationPath& path1,
|
||||||
const EventPropagationPath& path2 ) const;
|
const EventPropagationPath& path2 ) const;
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
#include "CanvasEvent.hxx"
|
#include "CanvasEvent.hxx"
|
||||||
#include "CanvasEventVisitor.hxx"
|
#include "CanvasEventVisitor.hxx"
|
||||||
#include <simgear/canvas/elements/CanvasElement.hxx>
|
#include <simgear/canvas/elements/CanvasElement.hxx>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
namespace simgear
|
namespace simgear
|
||||||
{
|
{
|
||||||
@@ -29,12 +30,16 @@ namespace canvas
|
|||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
EventVisitor::EventVisitor( TraverseMode mode,
|
EventVisitor::EventVisitor( TraverseMode mode,
|
||||||
const osg::Vec2f& pos,
|
const osg::Vec2f& pos,
|
||||||
|
const osg::Vec2f& delta,
|
||||||
const ElementPtr& root ):
|
const ElementPtr& root ):
|
||||||
_traverse_mode( mode ),
|
_traverse_mode( mode ),
|
||||||
_root(root)
|
_root(root)
|
||||||
{
|
{
|
||||||
if( mode == TRAVERSE_DOWN )
|
if( mode == TRAVERSE_DOWN )
|
||||||
_target_path.push_back( EventTarget(NULL, pos) );
|
{
|
||||||
|
EventTarget target = {ElementWeakPtr(), pos, delta};
|
||||||
|
_target_path.push_back(target);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
@@ -58,18 +63,31 @@ namespace canvas
|
|||||||
// We only need to check for hits while traversing down
|
// We only need to check for hits while traversing down
|
||||||
if( _traverse_mode == TRAVERSE_DOWN )
|
if( _traverse_mode == TRAVERSE_DOWN )
|
||||||
{
|
{
|
||||||
|
// Transform event to local coordinates
|
||||||
|
const osg::Matrix& m = el.getMatrixTransform()->getInverseMatrix();
|
||||||
const osg::Vec2f& pos = _target_path.back().local_pos;
|
const osg::Vec2f& pos = _target_path.back().local_pos;
|
||||||
const osg::Vec2f local_pos = el.posToLocal(pos);
|
const osg::Vec2f local_pos
|
||||||
|
(
|
||||||
|
m(0, 0) * pos[0] + m(1, 0) * pos[1] + m(3, 0),
|
||||||
|
m(0, 1) * pos[0] + m(1, 1) * pos[1] + m(3, 1)
|
||||||
|
);
|
||||||
|
|
||||||
// Don't check specified root element for collision, as its purpose is to
|
// Don't check specified root element for collision, as its purpose is to
|
||||||
// catch all events which have no target. This allows for example calling
|
// catch all events which have no target. This allows for example calling
|
||||||
// event listeners attached to the canvas itself (its root group) even if
|
// event listeners attached to the canvas itself (its root group) even if
|
||||||
// no element has been hit.
|
// no element has been hit.
|
||||||
if( _root.get() != &el
|
if( _root.get() != &el && !el.hitBound(pos, local_pos) )
|
||||||
&& !el.hitBound(_target_path.front().local_pos, pos, local_pos) )
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
_target_path.push_back( EventTarget(&el, local_pos) );
|
const osg::Vec2f& delta = _target_path.back().local_delta;
|
||||||
|
const osg::Vec2f local_delta
|
||||||
|
(
|
||||||
|
m(0, 0) * delta[0] + m(1, 0) * delta[1],
|
||||||
|
m(0, 1) * delta[0] + m(1, 1) * delta[1]
|
||||||
|
);
|
||||||
|
|
||||||
|
EventTarget target = {el.getWeakPtr(), local_pos, local_delta};
|
||||||
|
_target_path.push_back(target);
|
||||||
|
|
||||||
if( el.traverse(*this) || &el == _root.get() )
|
if( el.traverse(*this) || &el == _root.get() )
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -42,10 +42,12 @@ namespace canvas
|
|||||||
*
|
*
|
||||||
* @param mode
|
* @param mode
|
||||||
* @param pos Mouse position
|
* @param pos Mouse position
|
||||||
|
* @param delta Mouse movement since last mouse move event
|
||||||
* @param root Element to dispatch events to if no element is hit
|
* @param root Element to dispatch events to if no element is hit
|
||||||
*/
|
*/
|
||||||
EventVisitor( TraverseMode mode,
|
EventVisitor( TraverseMode mode,
|
||||||
const osg::Vec2f& pos,
|
const osg::Vec2f& pos,
|
||||||
|
const osg::Vec2f& delta,
|
||||||
const ElementPtr& root = ElementPtr() );
|
const ElementPtr& root = ElementPtr() );
|
||||||
virtual ~EventVisitor();
|
virtual ~EventVisitor();
|
||||||
virtual bool traverse(Element& el);
|
virtual bool traverse(Element& el);
|
||||||
|
|||||||
@@ -45,25 +45,25 @@ namespace canvas
|
|||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
CanvasPtr CanvasMgr::createCanvas(const std::string& name)
|
CanvasPtr CanvasMgr::createCanvas(const std::string& name)
|
||||||
{
|
{
|
||||||
return static_cast<Canvas*>( createElement(name).get() );
|
return boost::static_pointer_cast<Canvas>( createElement(name) );
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
CanvasPtr CanvasMgr::getCanvas(size_t index) const
|
CanvasPtr CanvasMgr::getCanvas(size_t index) const
|
||||||
{
|
{
|
||||||
return static_cast<Canvas*>( getElement(index).get() );
|
return boost::static_pointer_cast<Canvas>( getElement(index) );
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
CanvasPtr CanvasMgr::getCanvas(const std::string& name) const
|
CanvasPtr CanvasMgr::getCanvas(const std::string& name) const
|
||||||
{
|
{
|
||||||
return static_cast<Canvas*>( getElement(name).get() );
|
return boost::static_pointer_cast<Canvas>( getElement(name) );
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
void CanvasMgr::elementCreated(PropertyBasedElementPtr element)
|
void CanvasMgr::elementCreated(PropertyBasedElementPtr element)
|
||||||
{
|
{
|
||||||
CanvasPtr canvas = static_cast<Canvas*>(element.get());
|
CanvasPtr canvas = boost::static_pointer_cast<Canvas>(element);
|
||||||
canvas->setCanvasMgr(this);
|
canvas->setCanvasMgr(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
|
|
||||||
#include "Canvas.hxx"
|
#include "Canvas.hxx"
|
||||||
#include "CanvasObjectPlacement.hxx"
|
#include "CanvasObjectPlacement.hxx"
|
||||||
#include <simgear/canvas/events/MouseEvent.hxx>
|
#include "MouseEvent.hxx"
|
||||||
|
|
||||||
#include <simgear/props/props.hxx>
|
#include <simgear/props/props.hxx>
|
||||||
#include <simgear/scene/util/SGPickCallback.hxx>
|
#include <simgear/scene/util/SGPickCallback.hxx>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
///@file Placement for putting a canvas texture onto OpenSceneGraph objects.
|
// Canvas placement for placing a canvas texture onto osg objects.
|
||||||
//
|
//
|
||||||
// It also provides a SGPickCallback for passing mouse events to the canvas and
|
// It also provides a SGPickCallback for passing mouse events to the canvas and
|
||||||
// manages emissive lighting of the placed canvas.
|
// manages emissive lighting of the placed canvas.
|
||||||
@@ -19,7 +19,7 @@
|
|||||||
// License along with this library; if not, write to the Free Software
|
// License along with this library; if not, write to the Free Software
|
||||||
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||||
|
|
||||||
#ifndef CANVAS_OBJECT_PLACEMENT_HXX_
|
#ifndef CANVAS_PICK_PLACEMENT_HXX_
|
||||||
#define CANVAS_OBJECT_PLACEMENT_HXX_
|
#define CANVAS_OBJECT_PLACEMENT_HXX_
|
||||||
|
|
||||||
#include "CanvasPlacement.hxx"
|
#include "CanvasPlacement.hxx"
|
||||||
@@ -33,9 +33,6 @@ namespace simgear
|
|||||||
namespace canvas
|
namespace canvas
|
||||||
{
|
{
|
||||||
|
|
||||||
/**
|
|
||||||
* Place a Canvas onto an osg object (as texture).
|
|
||||||
*/
|
|
||||||
class ObjectPlacement:
|
class ObjectPlacement:
|
||||||
public Placement
|
public Placement
|
||||||
{
|
{
|
||||||
@@ -75,4 +72,4 @@ namespace canvas
|
|||||||
} // namespace canvas
|
} // namespace canvas
|
||||||
} // namespace simgear
|
} // namespace simgear
|
||||||
|
|
||||||
#endif /* CANVAS_OBJECT_PLACEMENT_HXX_ */
|
#endif /* CANVAS_PICK_PLACEMENT_HXX_ */
|
||||||
|
|||||||
@@ -21,11 +21,8 @@
|
|||||||
|
|
||||||
#include "canvas_fwd.hxx"
|
#include "canvas_fwd.hxx"
|
||||||
|
|
||||||
class SGSubsystem;
|
|
||||||
|
|
||||||
namespace simgear
|
namespace simgear
|
||||||
{
|
{
|
||||||
namespace HTTP { class Client; }
|
|
||||||
namespace canvas
|
namespace canvas
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -38,8 +35,6 @@ namespace canvas
|
|||||||
virtual void addCamera(osg::Camera* camera) const = 0;
|
virtual void addCamera(osg::Camera* camera) const = 0;
|
||||||
virtual void removeCamera(osg::Camera* camera) const = 0;
|
virtual void removeCamera(osg::Camera* camera) const = 0;
|
||||||
virtual osg::Image* getImage(const std::string& path) const = 0;
|
virtual osg::Image* getImage(const std::string& path) const = 0;
|
||||||
virtual SGSubsystem* getSubsystem(const std::string& name) const = 0;
|
|
||||||
virtual HTTP::Client* getHTTPClient() const = 0;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace canvas
|
} // namespace canvas
|
||||||
|
|||||||
@@ -1,330 +0,0 @@
|
|||||||
// Window for placing a Canvas onto it (for dialogs, menus, etc.)
|
|
||||||
//
|
|
||||||
// Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com>
|
|
||||||
//
|
|
||||||
// This library is free software; you can redistribute it and/or
|
|
||||||
// modify it under the terms of the GNU Library General Public
|
|
||||||
// License as published by the Free Software Foundation; either
|
|
||||||
// version 2 of the License, or (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
// Library General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Library General Public
|
|
||||||
// License along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
|
||||||
|
|
||||||
#include "CanvasMgr.hxx"
|
|
||||||
#include "CanvasSystemAdapter.hxx"
|
|
||||||
#include "CanvasWindow.hxx"
|
|
||||||
|
|
||||||
#include <simgear/canvas/Canvas.hxx>
|
|
||||||
#include <simgear/scene/util/OsgMath.hxx>
|
|
||||||
|
|
||||||
#include <osgGA/GUIEventHandler>
|
|
||||||
|
|
||||||
#include <boost/algorithm/string/predicate.hpp>
|
|
||||||
#include <boost/foreach.hpp>
|
|
||||||
|
|
||||||
namespace simgear
|
|
||||||
{
|
|
||||||
namespace canvas
|
|
||||||
{
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
const std::string Window::TYPE_NAME = "window";
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
Window::Window( const CanvasWeakPtr& canvas,
|
|
||||||
const SGPropertyNode_ptr& node,
|
|
||||||
const Style& parent_style,
|
|
||||||
Element* parent ):
|
|
||||||
Image(canvas, node, parent_style, parent),
|
|
||||||
_attributes_dirty(0),
|
|
||||||
_resizable(false),
|
|
||||||
_capture_events(true),
|
|
||||||
_resize_top(node, "resize-top"),
|
|
||||||
_resize_right(node, "resize-right"),
|
|
||||||
_resize_bottom(node, "resize-bottom"),
|
|
||||||
_resize_left(node, "resize-left"),
|
|
||||||
_resize_status(node, "resize-status")
|
|
||||||
{
|
|
||||||
node->setFloatValue("source/right", 1);
|
|
||||||
node->setFloatValue("source/bottom", 1);
|
|
||||||
node->setBoolValue("source/normalized", true);
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
Window::~Window()
|
|
||||||
{
|
|
||||||
if( _canvas_decoration )
|
|
||||||
_canvas_decoration->destroy();
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
void Window::update(double delta_time_sec)
|
|
||||||
{
|
|
||||||
if( _attributes_dirty & DECORATION )
|
|
||||||
{
|
|
||||||
updateDecoration();
|
|
||||||
_attributes_dirty &= ~DECORATION;
|
|
||||||
}
|
|
||||||
|
|
||||||
Image::update(delta_time_sec);
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
void Window::valueChanged(SGPropertyNode * node)
|
|
||||||
{
|
|
||||||
bool handled = false;
|
|
||||||
if( node->getParent() == _node )
|
|
||||||
{
|
|
||||||
handled = true;
|
|
||||||
const std::string& name = node->getNameString();
|
|
||||||
if( name == "resize" )
|
|
||||||
_resizable = node->getBoolValue();
|
|
||||||
else if( name == "update" )
|
|
||||||
update(0);
|
|
||||||
else if( name == "capture-events" )
|
|
||||||
_capture_events = node->getBoolValue();
|
|
||||||
else if( name == "decoration-border" )
|
|
||||||
parseDecorationBorder(node->getStringValue());
|
|
||||||
else if( boost::starts_with(name, "shadow-")
|
|
||||||
|| name == "content-size" )
|
|
||||||
_attributes_dirty |= DECORATION;
|
|
||||||
else
|
|
||||||
handled = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( !handled )
|
|
||||||
Image::valueChanged(node);
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
osg::Group* Window::getGroup()
|
|
||||||
{
|
|
||||||
return getMatrixTransform();
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
const SGVec2<float> Window::getPosition() const
|
|
||||||
{
|
|
||||||
const osg::Matrix& m = getMatrixTransform()->getMatrix();
|
|
||||||
return SGVec2<float>( m(3, 0), m(3, 1) );
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
const SGRect<float> Window::getScreenRegion() const
|
|
||||||
{
|
|
||||||
return getPosition() + getRegion();
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
void Window::setCanvasContent(CanvasPtr canvas)
|
|
||||||
{
|
|
||||||
_canvas_content = canvas;
|
|
||||||
if( _layout )
|
|
||||||
{
|
|
||||||
canvas->setLayout(_layout);
|
|
||||||
_layout.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
if( _image_content )
|
|
||||||
// Placement within decoration canvas
|
|
||||||
_image_content->setSrcCanvas(canvas);
|
|
||||||
else
|
|
||||||
setSrcCanvas(canvas);
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
CanvasWeakPtr Window::getCanvasContent() const
|
|
||||||
{
|
|
||||||
return _canvas_content;
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
void Window::setLayout(const LayoutRef& layout)
|
|
||||||
{
|
|
||||||
CanvasPtr canvas = _canvas_content.lock();
|
|
||||||
if( canvas )
|
|
||||||
canvas->setLayout(layout);
|
|
||||||
else
|
|
||||||
_layout = layout; // keep layout until content canvas is set
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
CanvasPtr Window::getCanvasDecoration() const
|
|
||||||
{
|
|
||||||
return _canvas_decoration;
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
bool Window::isResizable() const
|
|
||||||
{
|
|
||||||
return _resizable;
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
bool Window::isCapturingEvents() const
|
|
||||||
{
|
|
||||||
return _capture_events;
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
void Window::raise()
|
|
||||||
{
|
|
||||||
// on writing the z-index the window always is moved to the top of all other
|
|
||||||
// windows with the same z-index.
|
|
||||||
set<int>("z-index", get<int>("z-index", 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
void Window::handleResize( uint8_t mode,
|
|
||||||
const osg::Vec2f& offset )
|
|
||||||
{
|
|
||||||
if( mode == NONE )
|
|
||||||
{
|
|
||||||
_resize_status = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else if( mode & INIT )
|
|
||||||
{
|
|
||||||
_resize_top = getRegion().t();
|
|
||||||
_resize_right = getRegion().r();
|
|
||||||
_resize_bottom = getRegion().b();
|
|
||||||
_resize_left = getRegion().l();
|
|
||||||
_resize_status = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( mode & BOTTOM )
|
|
||||||
_resize_bottom = getRegion().b() + offset.y();
|
|
||||||
else if( mode & TOP )
|
|
||||||
_resize_top = getRegion().t() + offset.y();
|
|
||||||
|
|
||||||
if( mode & canvas::Window::RIGHT )
|
|
||||||
_resize_right = getRegion().r() + offset.x();
|
|
||||||
else if( mode & canvas::Window::LEFT )
|
|
||||||
_resize_left = getRegion().l() + offset.x();
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
void Window::parseDecorationBorder(const std::string& str)
|
|
||||||
{
|
|
||||||
_decoration_border = simgear::CSSBorder::parse(str);
|
|
||||||
_attributes_dirty |= DECORATION;
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
void Window::updateDecoration()
|
|
||||||
{
|
|
||||||
int shadow_radius = get<float>("shadow-radius") + 0.5;
|
|
||||||
if( shadow_radius < 2 )
|
|
||||||
shadow_radius = 0;
|
|
||||||
|
|
||||||
CanvasPtr content = _canvas_content.lock();
|
|
||||||
SGRect<int> content_view
|
|
||||||
(
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
get<int>("content-size[0]", content ? content->getViewWidth() : 400),
|
|
||||||
get<int>("content-size[1]", content ? content->getViewHeight() : 300)
|
|
||||||
);
|
|
||||||
|
|
||||||
if( _decoration_border.isNone() && !shadow_radius )
|
|
||||||
{
|
|
||||||
setSrcCanvas(content);
|
|
||||||
set<int>("size[0]", content_view.width());
|
|
||||||
set<int>("size[1]", content_view.height());
|
|
||||||
|
|
||||||
_image_content.reset();
|
|
||||||
_image_shadow.reset();
|
|
||||||
if( _canvas_decoration )
|
|
||||||
_canvas_decoration->destroy();
|
|
||||||
_canvas_decoration.reset();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( !_canvas_decoration )
|
|
||||||
{
|
|
||||||
CanvasMgr* mgr = dynamic_cast<CanvasMgr*>(
|
|
||||||
Canvas::getSystemAdapter()->getSubsystem("Canvas")
|
|
||||||
);
|
|
||||||
|
|
||||||
if( !mgr )
|
|
||||||
{
|
|
||||||
SG_LOG(SG_GENERAL, SG_WARN, "canvas::Window: no canvas manager!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_canvas_decoration = mgr->createCanvas("window-decoration");
|
|
||||||
_canvas_decoration->getProps()
|
|
||||||
->setStringValue("background", "rgba(0,0,0,0)");
|
|
||||||
setSrcCanvas(_canvas_decoration);
|
|
||||||
|
|
||||||
_image_content = _canvas_decoration->getRootGroup()
|
|
||||||
->createChild<Image>("content");
|
|
||||||
_image_content->setSrcCanvas(content);
|
|
||||||
|
|
||||||
// Draw content on top of decoration
|
|
||||||
_image_content->set<int>("z-index", 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
GroupPtr group_decoration =
|
|
||||||
_canvas_decoration->getOrCreateGroup("decoration");
|
|
||||||
group_decoration->set<int>("tf/t[0]", shadow_radius);
|
|
||||||
group_decoration->set<int>("tf/t[1]", shadow_radius);
|
|
||||||
// TODO do we need clipping or shall we trust the decorator not to draw over
|
|
||||||
// the shadow?
|
|
||||||
|
|
||||||
CSSBorder::Offsets const border =
|
|
||||||
_decoration_border.getAbsOffsets(content_view);
|
|
||||||
|
|
||||||
int shad2 = 2 * shadow_radius,
|
|
||||||
outer_width = border.l + content_view.width() + border.r + shad2,
|
|
||||||
outer_height = border.t + content_view.height() + border.b + shad2;
|
|
||||||
|
|
||||||
_canvas_decoration->setSizeX( outer_width );
|
|
||||||
_canvas_decoration->setSizeY( outer_height );
|
|
||||||
_canvas_decoration->setViewWidth( outer_width );
|
|
||||||
_canvas_decoration->setViewHeight( outer_height );
|
|
||||||
|
|
||||||
set<int>("size[0]", outer_width - shad2);
|
|
||||||
set<int>("size[1]", outer_height - shad2);
|
|
||||||
set<int>("outset", shadow_radius);
|
|
||||||
|
|
||||||
assert(_image_content);
|
|
||||||
_image_content->set<int>("x", shadow_radius + border.l);
|
|
||||||
_image_content->set<int>("y", shadow_radius + border.t);
|
|
||||||
_image_content->set<int>("size[0]", content_view.width());
|
|
||||||
_image_content->set<int>("size[1]", content_view.height());
|
|
||||||
|
|
||||||
if( !shadow_radius )
|
|
||||||
{
|
|
||||||
if( _image_shadow )
|
|
||||||
{
|
|
||||||
_image_shadow->destroy();
|
|
||||||
_image_shadow.reset();
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int shadow_inset = std::max<int>(get<float>("shadow-inset") + 0.5, 0),
|
|
||||||
slice_width = shadow_radius + shadow_inset;
|
|
||||||
|
|
||||||
_image_shadow = _canvas_decoration->getRootGroup()
|
|
||||||
->getOrCreateChild<Image>("shadow");
|
|
||||||
_image_shadow->set<std::string>("src", "gui/images/shadow.png");
|
|
||||||
_image_shadow->set<float>("slice", 7);
|
|
||||||
_image_shadow->set<std::string>("fill", "#000000");
|
|
||||||
_image_shadow->set<float>("slice-width", slice_width);
|
|
||||||
_image_shadow->set<int>("size[0]", outer_width);
|
|
||||||
_image_shadow->set<int>("size[1]", outer_height);
|
|
||||||
|
|
||||||
// Draw shadow below decoration
|
|
||||||
_image_shadow->set<int>("z-index", -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace canvas
|
|
||||||
} // namespace simgear
|
|
||||||
@@ -1,131 +0,0 @@
|
|||||||
// Window for placing a Canvas onto it (for dialogs, menus, etc.)
|
|
||||||
//
|
|
||||||
// Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com>
|
|
||||||
//
|
|
||||||
// This library is free software; you can redistribute it and/or
|
|
||||||
// modify it under the terms of the GNU Library General Public
|
|
||||||
// License as published by the Free Software Foundation; either
|
|
||||||
// version 2 of the License, or (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
// Library General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Library General Public
|
|
||||||
// License along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
|
||||||
|
|
||||||
#ifndef CANVAS_WINDOW_HXX_
|
|
||||||
#define CANVAS_WINDOW_HXX_
|
|
||||||
|
|
||||||
#include <simgear/canvas/elements/CanvasImage.hxx>
|
|
||||||
#include <simgear/canvas/layout/Layout.hxx>
|
|
||||||
#include <simgear/canvas/events/MouseEvent.hxx>
|
|
||||||
#include <simgear/props/PropertyBasedElement.hxx>
|
|
||||||
#include <simgear/props/propertyObject.hxx>
|
|
||||||
#include <simgear/misc/CSSBorder.hxx>
|
|
||||||
|
|
||||||
#include <osg/Geode>
|
|
||||||
#include <osg/Geometry>
|
|
||||||
|
|
||||||
namespace simgear
|
|
||||||
{
|
|
||||||
namespace canvas
|
|
||||||
{
|
|
||||||
|
|
||||||
class Window:
|
|
||||||
public Image,
|
|
||||||
public LayoutItem
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
static const std::string TYPE_NAME;
|
|
||||||
|
|
||||||
enum Resize
|
|
||||||
{
|
|
||||||
NONE = 0,
|
|
||||||
LEFT = 1,
|
|
||||||
RIGHT = LEFT << 1,
|
|
||||||
TOP = RIGHT << 1,
|
|
||||||
BOTTOM = TOP << 1,
|
|
||||||
INIT = BOTTOM << 1
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param node Property node containing settings for this window:
|
|
||||||
* capture-events Disable/Enable event capturing
|
|
||||||
* content-size[0-1] Size of content area (excluding
|
|
||||||
* decoration border)
|
|
||||||
* decoration-border Size of decoration border
|
|
||||||
* resize Enable resize cursor and properties
|
|
||||||
* shadow-inset Inset of shadow image
|
|
||||||
* shadow-radius Radius/outset of shadow image
|
|
||||||
*/
|
|
||||||
Window( const CanvasWeakPtr& canvas,
|
|
||||||
const SGPropertyNode_ptr& node,
|
|
||||||
const Style& parent_style = Style(),
|
|
||||||
Element* parent = 0 );
|
|
||||||
virtual ~Window();
|
|
||||||
|
|
||||||
virtual void update(double delta_time_sec);
|
|
||||||
virtual void valueChanged(SGPropertyNode* node);
|
|
||||||
|
|
||||||
osg::Group* getGroup();
|
|
||||||
const SGVec2<float> getPosition() const;
|
|
||||||
const SGRect<float> getScreenRegion() const;
|
|
||||||
|
|
||||||
void setCanvasContent(CanvasPtr canvas);
|
|
||||||
simgear::canvas::CanvasWeakPtr getCanvasContent() const;
|
|
||||||
|
|
||||||
void setLayout(const LayoutRef& layout);
|
|
||||||
|
|
||||||
CanvasPtr getCanvasDecoration() const;
|
|
||||||
|
|
||||||
bool isResizable() const;
|
|
||||||
bool isCapturingEvents() const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Moves window on top of all other windows with the same z-index.
|
|
||||||
*
|
|
||||||
* @note If no z-index is set it defaults to 0.
|
|
||||||
*/
|
|
||||||
void raise();
|
|
||||||
|
|
||||||
void handleResize( uint8_t mode,
|
|
||||||
const osg::Vec2f& offset = osg::Vec2f() );
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
enum Attributes
|
|
||||||
{
|
|
||||||
DECORATION = 1
|
|
||||||
};
|
|
||||||
|
|
||||||
uint32_t _attributes_dirty;
|
|
||||||
|
|
||||||
CanvasPtr _canvas_decoration;
|
|
||||||
CanvasWeakPtr _canvas_content;
|
|
||||||
LayoutRef _layout;
|
|
||||||
|
|
||||||
ImagePtr _image_content,
|
|
||||||
_image_shadow;
|
|
||||||
|
|
||||||
bool _resizable,
|
|
||||||
_capture_events;
|
|
||||||
|
|
||||||
PropertyObject<int> _resize_top,
|
|
||||||
_resize_right,
|
|
||||||
_resize_bottom,
|
|
||||||
_resize_left,
|
|
||||||
_resize_status;
|
|
||||||
|
|
||||||
CSSBorder _decoration_border;
|
|
||||||
|
|
||||||
void parseDecorationBorder(const std::string& str);
|
|
||||||
void updateDecoration();
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace canvas
|
|
||||||
} // namespace simgear
|
|
||||||
|
|
||||||
#endif /* CANVAS_WINDOW_HXX_ */
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
///@file Mouse event
|
// Mouse event
|
||||||
//
|
//
|
||||||
// Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com>
|
// Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com>
|
||||||
//
|
//
|
||||||
@@ -19,7 +19,7 @@
|
|||||||
#ifndef CANVAS_MOUSE_EVENT_HXX_
|
#ifndef CANVAS_MOUSE_EVENT_HXX_
|
||||||
#define CANVAS_MOUSE_EVENT_HXX_
|
#define CANVAS_MOUSE_EVENT_HXX_
|
||||||
|
|
||||||
#include <simgear/canvas/CanvasEvent.hxx>
|
#include "CanvasEvent.hxx"
|
||||||
#include <osgGA/GUIEventAdapter>
|
#include <osgGA/GUIEventAdapter>
|
||||||
|
|
||||||
namespace simgear
|
namespace simgear
|
||||||
@@ -31,10 +31,21 @@ namespace canvas
|
|||||||
public Event
|
public Event
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
MouseEvent();
|
MouseEvent():
|
||||||
MouseEvent(const osgGA::GUIEventAdapter& ea);
|
button(-1),
|
||||||
|
state(-1),
|
||||||
|
mod(-1),
|
||||||
|
click_count(0)
|
||||||
|
{}
|
||||||
|
|
||||||
virtual bool canBubble() const;
|
MouseEvent(const osgGA::GUIEventAdapter& ea):
|
||||||
|
button(ea.getButton()),
|
||||||
|
state(ea.getButtonMask()),
|
||||||
|
mod(ea.getModKeyMask()),
|
||||||
|
click_count(0)
|
||||||
|
{
|
||||||
|
time = ea.getTime();
|
||||||
|
}
|
||||||
|
|
||||||
osg::Vec2f getScreenPos() const { return screen_pos; }
|
osg::Vec2f getScreenPos() const { return screen_pos; }
|
||||||
osg::Vec2f getClientPos() const { return client_pos; }
|
osg::Vec2f getClientPos() const { return client_pos; }
|
||||||
@@ -53,10 +64,6 @@ namespace canvas
|
|||||||
float getDeltaX() const { return delta.x(); }
|
float getDeltaX() const { return delta.x(); }
|
||||||
float getDeltaY() const { return delta.y(); }
|
float getDeltaY() const { return delta.y(); }
|
||||||
|
|
||||||
int getButton() const { return button; }
|
|
||||||
int getButtonMask() const { return buttons; }
|
|
||||||
int getModifiers() const { return modifiers; }
|
|
||||||
|
|
||||||
int getCurrentClickCount() const { return click_count; }
|
int getCurrentClickCount() const { return click_count; }
|
||||||
|
|
||||||
osg::Vec2f screen_pos, //<! Position in screen coordinates
|
osg::Vec2f screen_pos, //<! Position in screen coordinates
|
||||||
@@ -64,8 +71,8 @@ namespace canvas
|
|||||||
local_pos, //<! Position in local/element coordinates
|
local_pos, //<! Position in local/element coordinates
|
||||||
delta;
|
delta;
|
||||||
int button, //<! Button for this event
|
int button, //<! Button for this event
|
||||||
buttons, //<! Current button state
|
state, //<! Current button state
|
||||||
modifiers, //<! Keyboard modifier state
|
mod, //<! Keyboard modifier state
|
||||||
click_count; //<! Current click count
|
click_count; //<! Current click count
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -38,9 +38,4 @@
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// We currently do not support using images (inside paths). If we were going to
|
|
||||||
// use it loading and unloading needs to happen within OpenSceneGraph to handle
|
|
||||||
// synchronization correctly in multithreading mode.
|
|
||||||
#define SH_NO_IMAGE
|
|
||||||
|
|
||||||
#endif // __SHCONFIG_H
|
#endif // __SHCONFIG_H
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ VG_API_CALL VGboolean vgCreateContextSH(VGint width, VGint height)
|
|||||||
|
|
||||||
glMatrixMode(GL_PROJECTION);
|
glMatrixMode(GL_PROJECTION);
|
||||||
glLoadIdentity();
|
glLoadIdentity();
|
||||||
glOrtho(0, width, 0, height, -1, 1);
|
gluOrtho2D(0,width,0,height);
|
||||||
|
|
||||||
glMatrixMode(GL_MODELVIEW);
|
glMatrixMode(GL_MODELVIEW);
|
||||||
glLoadIdentity();*/
|
glLoadIdentity();*/
|
||||||
@@ -79,7 +79,7 @@ VG_API_CALL void vgResizeSurfaceSH(VGint width, VGint height)
|
|||||||
|
|
||||||
glMatrixMode(GL_PROJECTION);
|
glMatrixMode(GL_PROJECTION);
|
||||||
glLoadIdentity();
|
glLoadIdentity();
|
||||||
glOrtho(0, width, 0, height, -1, 1);
|
gluOrtho2D(0,width,0,height);
|
||||||
|
|
||||||
glMatrixMode(GL_MODELVIEW);
|
glMatrixMode(GL_MODELVIEW);
|
||||||
glLoadIdentity();
|
glLoadIdentity();
|
||||||
|
|||||||
@@ -34,7 +34,7 @@
|
|||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <float.h>
|
#include <float.h>
|
||||||
|
|
||||||
#if !defined(VG_API_MACOSX) && !defined(__FreeBSD__)
|
#ifndef VG_API_MACOSX
|
||||||
# include <malloc.h>
|
# include <malloc.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -158,14 +158,18 @@ SHfloat getMaxFloat();
|
|||||||
|
|
||||||
#if defined(VG_API_LINUX)
|
#if defined(VG_API_LINUX)
|
||||||
#include <GL/gl.h>
|
#include <GL/gl.h>
|
||||||
|
#include <GL/glu.h>
|
||||||
#include <GL/glx.h>
|
#include <GL/glx.h>
|
||||||
#elif defined(VG_API_MACOSX)
|
#elif defined(VG_API_MACOSX)
|
||||||
#include <OpenGL/gl.h>
|
#include <OpenGL/gl.h>
|
||||||
|
#include <OpenGL/glu.h>
|
||||||
#elif defined(VG_API_WINDOWS)
|
#elif defined(VG_API_WINDOWS)
|
||||||
#include <GL/gl.h>
|
#include <GL/gl.h>
|
||||||
|
#include <GL/glu.h>
|
||||||
#else
|
#else
|
||||||
#define GL_GLEXT_LEGACY /* don't include glext.h */
|
#define GL_GLEXT_LEGACY /* don't include glext.h */
|
||||||
#include <GL/gl.h>
|
#include <GL/gl.h>
|
||||||
|
#include <GL/glu.h>
|
||||||
#include <GL/glx.h>
|
#include <GL/glx.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -37,7 +37,6 @@
|
|||||||
#define _ARRAY_DEFINE
|
#define _ARRAY_DEFINE
|
||||||
#include "shArrayBase.h"
|
#include "shArrayBase.h"
|
||||||
|
|
||||||
#ifndef SH_NO_IMAGE
|
|
||||||
|
|
||||||
/*-----------------------------------------------------------
|
/*-----------------------------------------------------------
|
||||||
* Prepares the proper pixel pack/unpack info for the given
|
* Prepares the proper pixel pack/unpack info for the given
|
||||||
@@ -441,7 +440,6 @@ void shLoadColor(SHColor *c, const void *data, SHImageFormatDesc *f)
|
|||||||
if (f->rmask == 0x0) { c->r = 1.0f; c->g = 1.0f; c->b = 1.0f; }
|
if (f->rmask == 0x0) { c->r = 1.0f; c->g = 1.0f; c->b = 1.0f; }
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // SH_NO_IMAGE
|
|
||||||
|
|
||||||
/*----------------------------------------------
|
/*----------------------------------------------
|
||||||
* Color and Image constructors and destructors
|
* Color and Image constructors and destructors
|
||||||
@@ -463,12 +461,7 @@ void SHImage_ctor(SHImage *i)
|
|||||||
i->data = NULL;
|
i->data = NULL;
|
||||||
i->width = 0;
|
i->width = 0;
|
||||||
i->height = 0;
|
i->height = 0;
|
||||||
|
|
||||||
#ifdef SH_NO_IMAGE
|
|
||||||
printf("ShivaVG: images not supported!");
|
|
||||||
#else
|
|
||||||
glGenTextures(1, &i->texture);
|
glGenTextures(1, &i->texture);
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SHImage_dtor(SHImage *i)
|
void SHImage_dtor(SHImage *i)
|
||||||
@@ -476,15 +469,10 @@ void SHImage_dtor(SHImage *i)
|
|||||||
if (i->data != NULL)
|
if (i->data != NULL)
|
||||||
free(i->data);
|
free(i->data);
|
||||||
|
|
||||||
#ifdef SH_NO_IMAGE
|
|
||||||
printf("ShivaVG: images not supported!");
|
|
||||||
#else
|
|
||||||
if (glIsTexture(i->texture))
|
if (glIsTexture(i->texture))
|
||||||
glDeleteTextures(1, &i->texture);
|
glDeleteTextures(1, &i->texture);
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef SH_NO_IMAGE
|
|
||||||
/*--------------------------------------------------------
|
/*--------------------------------------------------------
|
||||||
* Finds appropriate OpenGL texture size for the size of
|
* Finds appropriate OpenGL texture size for the size of
|
||||||
* the given image
|
* the given image
|
||||||
@@ -565,7 +553,6 @@ void shUpdateImageTexture(SHImage *i, VGContext *c)
|
|||||||
i->texwidth, i->texheight, 0,
|
i->texwidth, i->texheight, 0,
|
||||||
i->fd.glformat, i->fd.gltype, i->data);
|
i->fd.glformat, i->fd.gltype, i->data);
|
||||||
}
|
}
|
||||||
#endif // SH_NO_IMAGE
|
|
||||||
|
|
||||||
/*----------------------------------------------------------
|
/*----------------------------------------------------------
|
||||||
* Creates a new image object and returns the handle to it
|
* Creates a new image object and returns the handle to it
|
||||||
@@ -575,10 +562,6 @@ VG_API_CALL VGImage vgCreateImage(VGImageFormat format,
|
|||||||
VGint width, VGint height,
|
VGint width, VGint height,
|
||||||
VGbitfield allowedQuality)
|
VGbitfield allowedQuality)
|
||||||
{
|
{
|
||||||
#ifdef SH_NO_IMAGE
|
|
||||||
printf("ShivaVG: images not supported!");
|
|
||||||
return VG_INVALID_HANDLE;
|
|
||||||
#else
|
|
||||||
SHImage *i = NULL;
|
SHImage *i = NULL;
|
||||||
SHImageFormatDesc fd;
|
SHImageFormatDesc fd;
|
||||||
VG_GETCONTEXT(VG_INVALID_HANDLE);
|
VG_GETCONTEXT(VG_INVALID_HANDLE);
|
||||||
@@ -633,14 +616,10 @@ VG_API_CALL VGImage vgCreateImage(VGImageFormat format,
|
|||||||
shImageArrayPushBack(&context->images, i);
|
shImageArrayPushBack(&context->images, i);
|
||||||
|
|
||||||
VG_RETURN((VGImage)i);
|
VG_RETURN((VGImage)i);
|
||||||
#endif // SH_NO_IMAGE
|
|
||||||
}
|
}
|
||||||
|
|
||||||
VG_API_CALL void vgDestroyImage(VGImage image)
|
VG_API_CALL void vgDestroyImage(VGImage image)
|
||||||
{
|
{
|
||||||
#ifdef SH_NO_IMAGE
|
|
||||||
printf("ShivaVG: images not supported!");
|
|
||||||
#else
|
|
||||||
SHint index;
|
SHint index;
|
||||||
VG_GETCONTEXT(VG_NO_RETVAL);
|
VG_GETCONTEXT(VG_NO_RETVAL);
|
||||||
|
|
||||||
@@ -653,7 +632,6 @@ VG_API_CALL void vgDestroyImage(VGImage image)
|
|||||||
shImageArrayRemoveAt(&context->images, index);
|
shImageArrayRemoveAt(&context->images, index);
|
||||||
|
|
||||||
VG_RETURN(VG_NO_RETVAL);
|
VG_RETURN(VG_NO_RETVAL);
|
||||||
#endif // SH_NO_IMAGE
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*---------------------------------------------------
|
/*---------------------------------------------------
|
||||||
@@ -664,9 +642,6 @@ VG_API_CALL void vgDestroyImage(VGImage image)
|
|||||||
VG_API_CALL void vgClearImage(VGImage image,
|
VG_API_CALL void vgClearImage(VGImage image,
|
||||||
VGint x, VGint y, VGint width, VGint height)
|
VGint x, VGint y, VGint width, VGint height)
|
||||||
{
|
{
|
||||||
#ifdef SH_NO_IMAGE
|
|
||||||
printf("ShivaVG: images not supported!");
|
|
||||||
#else
|
|
||||||
SHImage *i;
|
SHImage *i;
|
||||||
SHColor clear;
|
SHColor clear;
|
||||||
SHuint8 *data;
|
SHuint8 *data;
|
||||||
@@ -707,13 +682,9 @@ VG_API_CALL void vgClearImage(VGImage image,
|
|||||||
}}
|
}}
|
||||||
|
|
||||||
shUpdateImageTexture(i, context);
|
shUpdateImageTexture(i, context);
|
||||||
|
|
||||||
VG_RETURN(VG_NO_RETVAL);
|
VG_RETURN(VG_NO_RETVAL);
|
||||||
#endif // SH_NO_IMAGE
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef SH_NO_IMAGE
|
|
||||||
|
|
||||||
/*------------------------------------------------------------
|
/*------------------------------------------------------------
|
||||||
* Generic function for copying a rectangle area of pixels
|
* Generic function for copying a rectangle area of pixels
|
||||||
* of size (width,height) among two data buffers. The size of
|
* of size (width,height) among two data buffers. The size of
|
||||||
@@ -824,8 +795,6 @@ void shCopyPixels(SHuint8 *dst, VGImageFormat dstFormat, SHint dstStride,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // SH_NO_IMAGE
|
|
||||||
|
|
||||||
/*---------------------------------------------------------
|
/*---------------------------------------------------------
|
||||||
* Copies a rectangle area of pixels of size (width,height)
|
* Copies a rectangle area of pixels of size (width,height)
|
||||||
* from given data buffer to image surface at destination
|
* from given data buffer to image surface at destination
|
||||||
@@ -837,9 +806,6 @@ VG_API_CALL void vgImageSubData(VGImage image,
|
|||||||
VGImageFormat dataFormat,
|
VGImageFormat dataFormat,
|
||||||
VGint x, VGint y, VGint width, VGint height)
|
VGint x, VGint y, VGint width, VGint height)
|
||||||
{
|
{
|
||||||
#ifdef SH_NO_IMAGE
|
|
||||||
printf("ShivaVG: images not supported!");
|
|
||||||
#else
|
|
||||||
SHImage *i;
|
SHImage *i;
|
||||||
VG_GETCONTEXT(VG_NO_RETVAL);
|
VG_GETCONTEXT(VG_NO_RETVAL);
|
||||||
|
|
||||||
@@ -870,9 +836,7 @@ VG_API_CALL void vgImageSubData(VGImage image,
|
|||||||
x, y, 0, 0, width, height);
|
x, y, 0, 0, width, height);
|
||||||
|
|
||||||
shUpdateImageTexture(i, context);
|
shUpdateImageTexture(i, context);
|
||||||
|
|
||||||
VG_RETURN(VG_NO_RETVAL);
|
VG_RETURN(VG_NO_RETVAL);
|
||||||
#endif // SH_NO_IMAGE
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*---------------------------------------------------------
|
/*---------------------------------------------------------
|
||||||
@@ -887,9 +851,6 @@ VG_API_CALL void vgGetImageSubData(VGImage image,
|
|||||||
VGint x, VGint y,
|
VGint x, VGint y,
|
||||||
VGint width, VGint height)
|
VGint width, VGint height)
|
||||||
{
|
{
|
||||||
#ifdef SH_NO_IMAGE
|
|
||||||
printf("ShivaVG: images not supported!");
|
|
||||||
#else
|
|
||||||
SHImage *i;
|
SHImage *i;
|
||||||
VG_GETCONTEXT(VG_NO_RETVAL);
|
VG_GETCONTEXT(VG_NO_RETVAL);
|
||||||
|
|
||||||
@@ -917,10 +878,9 @@ VG_API_CALL void vgGetImageSubData(VGImage image,
|
|||||||
shCopyPixels(data, dataFormat, dataStride,
|
shCopyPixels(data, dataFormat, dataStride,
|
||||||
i->data, i->fd.vgformat, i->texwidth * i->fd.bytes,
|
i->data, i->fd.vgformat, i->texwidth * i->fd.bytes,
|
||||||
width, height, i->width, i->height,
|
width, height, i->width, i->height,
|
||||||
0,0,x,y,width,height);
|
0,0,x,x,width,height);
|
||||||
|
|
||||||
VG_RETURN(VG_NO_RETVAL);
|
VG_RETURN(VG_NO_RETVAL);
|
||||||
#endif // SH_NO_IMAGE
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*----------------------------------------------------------
|
/*----------------------------------------------------------
|
||||||
@@ -934,9 +894,6 @@ VG_API_CALL void vgCopyImage(VGImage dst, VGint dx, VGint dy,
|
|||||||
VGint width, VGint height,
|
VGint width, VGint height,
|
||||||
VGboolean dither)
|
VGboolean dither)
|
||||||
{
|
{
|
||||||
#ifdef SH_NO_IMAGE
|
|
||||||
printf("ShivaVG: images not supported!");
|
|
||||||
#else
|
|
||||||
SHImage *s, *d;
|
SHImage *s, *d;
|
||||||
SHuint8 *pixels;
|
SHuint8 *pixels;
|
||||||
|
|
||||||
@@ -976,9 +933,7 @@ VG_API_CALL void vgCopyImage(VGImage dst, VGint dx, VGint dy,
|
|||||||
free(pixels);
|
free(pixels);
|
||||||
|
|
||||||
shUpdateImageTexture(d, context);
|
shUpdateImageTexture(d, context);
|
||||||
|
|
||||||
VG_RETURN(VG_NO_RETVAL);
|
VG_RETURN(VG_NO_RETVAL);
|
||||||
#endif // SH_NO_IMAGE
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*---------------------------------------------------------
|
/*---------------------------------------------------------
|
||||||
@@ -991,9 +946,6 @@ VG_API_CALL void vgSetPixels(VGint dx, VGint dy,
|
|||||||
VGImage src, VGint sx, VGint sy,
|
VGImage src, VGint sx, VGint sy,
|
||||||
VGint width, VGint height)
|
VGint width, VGint height)
|
||||||
{
|
{
|
||||||
#ifdef SH_NO_IMAGE
|
|
||||||
printf("ShivaVG: images not supported!");
|
|
||||||
#else
|
|
||||||
SHImage *i;
|
SHImage *i;
|
||||||
SHuint8 *pixels;
|
SHuint8 *pixels;
|
||||||
SHImageFormatDesc winfd;
|
SHImageFormatDesc winfd;
|
||||||
@@ -1034,7 +986,6 @@ VG_API_CALL void vgSetPixels(VGint dx, VGint dy,
|
|||||||
free(pixels);
|
free(pixels);
|
||||||
|
|
||||||
VG_RETURN(VG_NO_RETVAL);
|
VG_RETURN(VG_NO_RETVAL);
|
||||||
#endif // SH_NO_IMAGE
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*---------------------------------------------------------
|
/*---------------------------------------------------------
|
||||||
@@ -1048,9 +999,6 @@ VG_API_CALL void vgWritePixels(const void * data, VGint dataStride,
|
|||||||
VGint dx, VGint dy,
|
VGint dx, VGint dy,
|
||||||
VGint width, VGint height)
|
VGint width, VGint height)
|
||||||
{
|
{
|
||||||
#ifdef SH_NO_IMAGE
|
|
||||||
printf("ShivaVG: images not supported!");
|
|
||||||
#else
|
|
||||||
SHuint8 *pixels;
|
SHuint8 *pixels;
|
||||||
SHImageFormatDesc winfd;
|
SHImageFormatDesc winfd;
|
||||||
|
|
||||||
@@ -1096,7 +1044,6 @@ VG_API_CALL void vgWritePixels(const void * data, VGint dataStride,
|
|||||||
free(pixels);
|
free(pixels);
|
||||||
|
|
||||||
VG_RETURN(VG_NO_RETVAL);
|
VG_RETURN(VG_NO_RETVAL);
|
||||||
#endif // SH_NO_IMAGE
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*-----------------------------------------------------------
|
/*-----------------------------------------------------------
|
||||||
@@ -1109,9 +1056,6 @@ VG_API_CALL void vgGetPixels(VGImage dst, VGint dx, VGint dy,
|
|||||||
VGint sx, VGint sy,
|
VGint sx, VGint sy,
|
||||||
VGint width, VGint height)
|
VGint width, VGint height)
|
||||||
{
|
{
|
||||||
#ifdef SH_NO_IMAGE
|
|
||||||
printf("ShivaVG: images not supported!");
|
|
||||||
#else
|
|
||||||
SHImage *i;
|
SHImage *i;
|
||||||
SHuint8 *pixels;
|
SHuint8 *pixels;
|
||||||
SHImageFormatDesc winfd;
|
SHImageFormatDesc winfd;
|
||||||
@@ -1149,9 +1093,7 @@ VG_API_CALL void vgGetPixels(VGImage dst, VGint dx, VGint dy,
|
|||||||
free(pixels);
|
free(pixels);
|
||||||
|
|
||||||
shUpdateImageTexture(i, context);
|
shUpdateImageTexture(i, context);
|
||||||
|
|
||||||
VG_RETURN(VG_NO_RETVAL);
|
VG_RETURN(VG_NO_RETVAL);
|
||||||
#endif // SH_NO_IMAGE
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*-----------------------------------------------------------
|
/*-----------------------------------------------------------
|
||||||
@@ -1165,9 +1107,6 @@ VG_API_CALL void vgReadPixels(void * data, VGint dataStride,
|
|||||||
VGint sx, VGint sy,
|
VGint sx, VGint sy,
|
||||||
VGint width, VGint height)
|
VGint width, VGint height)
|
||||||
{
|
{
|
||||||
#ifdef SH_NO_IMAGE
|
|
||||||
printf("ShivaVG: images not supported!");
|
|
||||||
#else
|
|
||||||
SHuint8 *pixels;
|
SHuint8 *pixels;
|
||||||
SHImageFormatDesc winfd;
|
SHImageFormatDesc winfd;
|
||||||
VG_GETCONTEXT(VG_NO_RETVAL);
|
VG_GETCONTEXT(VG_NO_RETVAL);
|
||||||
@@ -1209,7 +1148,6 @@ VG_API_CALL void vgReadPixels(void * data, VGint dataStride,
|
|||||||
free(pixels);
|
free(pixels);
|
||||||
|
|
||||||
VG_RETURN(VG_NO_RETVAL);
|
VG_RETURN(VG_NO_RETVAL);
|
||||||
#endif // SH_NO_IMAGE
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*----------------------------------------------------------
|
/*----------------------------------------------------------
|
||||||
@@ -1222,9 +1160,6 @@ VG_API_CALL void vgCopyPixels(VGint dx, VGint dy,
|
|||||||
VGint sx, VGint sy,
|
VGint sx, VGint sy,
|
||||||
VGint width, VGint height)
|
VGint width, VGint height)
|
||||||
{
|
{
|
||||||
#ifdef SH_NO_IMAGE
|
|
||||||
printf("ShivaVG: images not supported!");
|
|
||||||
#else
|
|
||||||
VG_GETCONTEXT(VG_NO_RETVAL);
|
VG_GETCONTEXT(VG_NO_RETVAL);
|
||||||
|
|
||||||
VG_RETURN_ERR_IF(width <= 0 || height <= 0,
|
VG_RETURN_ERR_IF(width <= 0 || height <= 0,
|
||||||
@@ -1237,7 +1172,6 @@ VG_API_CALL void vgCopyPixels(VGint dx, VGint dy,
|
|||||||
glRasterPos2i(0, 0);
|
glRasterPos2i(0, 0);
|
||||||
|
|
||||||
VG_RETURN(VG_NO_RETVAL);
|
VG_RETURN(VG_NO_RETVAL);
|
||||||
#endif // SH_NO_IMAGE
|
|
||||||
}
|
}
|
||||||
|
|
||||||
VG_API_CALL VGImage vgChildImage(VGImage parent,
|
VG_API_CALL VGImage vgChildImage(VGImage parent,
|
||||||
|
|||||||
@@ -36,9 +36,6 @@
|
|||||||
#define _ARRAY_DEFINE
|
#define _ARRAY_DEFINE
|
||||||
#include "shArrayBase.h"
|
#include "shArrayBase.h"
|
||||||
|
|
||||||
// We currently do not use gradients which need textures, so disable them to
|
|
||||||
// prevent freeing resources outside the correct OpenGL thread/context.
|
|
||||||
#define SH_NO_PAINT_TEXTURE
|
|
||||||
|
|
||||||
void SHPaint_ctor(SHPaint *p)
|
void SHPaint_ctor(SHPaint *p)
|
||||||
{
|
{
|
||||||
@@ -55,14 +52,10 @@ void SHPaint_ctor(SHPaint *p)
|
|||||||
for (i=0; i<5; ++i) p->radialGradient[i] = 0.0f;
|
for (i=0; i<5; ++i) p->radialGradient[i] = 0.0f;
|
||||||
p->pattern = VG_INVALID_HANDLE;
|
p->pattern = VG_INVALID_HANDLE;
|
||||||
|
|
||||||
#ifndef SH_NO_PAINT_TEXTURE
|
|
||||||
glGenTextures(1, &p->texture);
|
glGenTextures(1, &p->texture);
|
||||||
glBindTexture(GL_TEXTURE_1D, p->texture);
|
glBindTexture(GL_TEXTURE_1D, p->texture);
|
||||||
glTexImage1D(GL_TEXTURE_1D, 0, GL_RGBA, SH_GRADIENT_TEX_SIZE, 0,
|
glTexImage1D(GL_TEXTURE_1D, 0, GL_RGBA, SH_GRADIENT_TEX_SIZE, 0,
|
||||||
GL_RGBA, GL_FLOAT, NULL);
|
GL_RGBA, GL_FLOAT, NULL);
|
||||||
#else
|
|
||||||
p->texture = 0;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SHPaint_dtor(SHPaint *p)
|
void SHPaint_dtor(SHPaint *p)
|
||||||
@@ -70,10 +63,8 @@ void SHPaint_dtor(SHPaint *p)
|
|||||||
SH_DEINITOBJ(SHStopArray, p->instops);
|
SH_DEINITOBJ(SHStopArray, p->instops);
|
||||||
SH_DEINITOBJ(SHStopArray, p->stops);
|
SH_DEINITOBJ(SHStopArray, p->stops);
|
||||||
|
|
||||||
#ifndef SH_NO_PAINT_TEXTURE
|
|
||||||
if (glIsTexture(p->texture))
|
if (glIsTexture(p->texture))
|
||||||
glDeleteTextures(1, &p->texture);
|
glDeleteTextures(1, &p->texture);
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
VG_API_CALL VGPaint vgCreatePaint(void)
|
VG_API_CALL VGPaint vgCreatePaint(void)
|
||||||
@@ -152,7 +143,6 @@ VG_API_CALL void vgPaintPattern(VGPaint paint, VGImage pattern)
|
|||||||
|
|
||||||
void shUpdateColorRampTexture(SHPaint *p)
|
void shUpdateColorRampTexture(SHPaint *p)
|
||||||
{
|
{
|
||||||
#ifndef SH_NO_PAINT_TEXTURE
|
|
||||||
SHint s=0;
|
SHint s=0;
|
||||||
SHStop *stop1, *stop2;
|
SHStop *stop1, *stop2;
|
||||||
SHfloat rgba[SH_GRADIENT_TEX_COORDSIZE];
|
SHfloat rgba[SH_GRADIENT_TEX_COORDSIZE];
|
||||||
@@ -193,9 +183,6 @@ void shUpdateColorRampTexture(SHPaint *p)
|
|||||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||||
glTexSubImage1D(GL_TEXTURE_1D, 0, 0, SH_GRADIENT_TEX_SIZE,
|
glTexSubImage1D(GL_TEXTURE_1D, 0, 0, SH_GRADIENT_TEX_SIZE,
|
||||||
GL_RGBA, GL_FLOAT, rgba);
|
GL_RGBA, GL_FLOAT, rgba);
|
||||||
#else
|
|
||||||
printf("ShivaVG: gradients not supported!");
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void shValidateInputStops(SHPaint *p)
|
void shValidateInputStops(SHPaint *p)
|
||||||
@@ -357,7 +344,6 @@ void shGenerateStops(SHPaint *p, SHfloat minOffset, SHfloat maxOffset,
|
|||||||
|
|
||||||
void shSetGradientTexGLState(SHPaint *p)
|
void shSetGradientTexGLState(SHPaint *p)
|
||||||
{
|
{
|
||||||
#ifndef SH_NO_PAINT_TEXTURE
|
|
||||||
glBindTexture(GL_TEXTURE_1D, p->texture);
|
glBindTexture(GL_TEXTURE_1D, p->texture);
|
||||||
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||||
@@ -373,9 +359,6 @@ void shSetGradientTexGLState(SHPaint *p)
|
|||||||
|
|
||||||
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
||||||
glColor4f(1,1,1,1);
|
glColor4f(1,1,1,1);
|
||||||
#else
|
|
||||||
printf("ShivaVG: gradients not supported!");
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void shSetPatternTexGLState(SHPaint *p, VGContext *c)
|
void shSetPatternTexGLState(SHPaint *p, VGContext *c)
|
||||||
|
|||||||
@@ -314,9 +314,9 @@ VG_API_CALL void vgDrawPath(VGPath path, VGbitfield paintModes)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* TODO: Turn antialiasing on/off */
|
/* TODO: Turn antialiasing on/off */
|
||||||
// glDisable(GL_LINE_SMOOTH);
|
glDisable(GL_LINE_SMOOTH);
|
||||||
// glDisable(GL_POLYGON_SMOOTH);
|
glDisable(GL_POLYGON_SMOOTH);
|
||||||
// glEnable(GL_MULTISAMPLE);
|
glEnable(GL_MULTISAMPLE);
|
||||||
|
|
||||||
/* Pick paint if available or default*/
|
/* Pick paint if available or default*/
|
||||||
fill = (context->fillPaint ? context->fillPaint : &context->defaultPaint);
|
fill = (context->fillPaint ? context->fillPaint : &context->defaultPaint);
|
||||||
@@ -364,27 +364,26 @@ VG_API_CALL void vgDrawPath(VGPath path, VGbitfield paintModes)
|
|||||||
/* TODO: Is there any way to do this safely along
|
/* TODO: Is there any way to do this safely along
|
||||||
with the paint generation pass?? */
|
with the paint generation pass?? */
|
||||||
glDisable(GL_BLEND);
|
glDisable(GL_BLEND);
|
||||||
// glDisable(GL_MULTISAMPLE);
|
glDisable(GL_MULTISAMPLE);
|
||||||
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
|
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
|
||||||
shDrawBoundBox(context, p, VG_FILL_PATH);
|
shDrawBoundBox(context, p, VG_FILL_PATH);
|
||||||
|
|
||||||
/* Reset state */
|
/* Reset state */
|
||||||
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
|
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
|
||||||
glDisable(GL_STENCIL_TEST);
|
glDisable(GL_STENCIL_TEST);
|
||||||
// glDisable(GL_BLEND);
|
glDisable(GL_BLEND);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO: Turn antialiasing on/off */
|
/* TODO: Turn antialiasing on/off */
|
||||||
// glDisable(GL_LINE_SMOOTH);
|
glDisable(GL_LINE_SMOOTH);
|
||||||
// glDisable(GL_POLYGON_SMOOTH);
|
glDisable(GL_POLYGON_SMOOTH);
|
||||||
// glEnable(GL_MULTISAMPLE);
|
glEnable(GL_MULTISAMPLE);
|
||||||
|
|
||||||
if ((paintModes & VG_STROKE_PATH) &&
|
if ((paintModes & VG_STROKE_PATH) &&
|
||||||
context->strokeLineWidth > 0.0f) {
|
context->strokeLineWidth > 0.0f) {
|
||||||
|
|
||||||
#if 0
|
|
||||||
if (1) {/*context->strokeLineWidth > 1.0f) {*/
|
if (1) {/*context->strokeLineWidth > 1.0f) {*/
|
||||||
#endif
|
|
||||||
if (shIsStrokeCacheValid( context, p ) == VG_FALSE)
|
if (shIsStrokeCacheValid( context, p ) == VG_FALSE)
|
||||||
{
|
{
|
||||||
/* Generate stroke triangles in user space */
|
/* Generate stroke triangles in user space */
|
||||||
@@ -412,15 +411,15 @@ VG_API_CALL void vgDrawPath(VGPath path, VGbitfield paintModes)
|
|||||||
|
|
||||||
/* Clear stencil for sure */
|
/* Clear stencil for sure */
|
||||||
glDisable(GL_BLEND);
|
glDisable(GL_BLEND);
|
||||||
// glDisable(GL_MULTISAMPLE);
|
glDisable(GL_MULTISAMPLE);
|
||||||
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
|
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
|
||||||
shDrawBoundBox(context, p, VG_STROKE_PATH);
|
shDrawBoundBox(context, p, VG_STROKE_PATH);
|
||||||
|
|
||||||
/* Reset state */
|
/* Reset state */
|
||||||
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
|
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
|
||||||
glDisable(GL_STENCIL_TEST);
|
glDisable(GL_STENCIL_TEST);
|
||||||
// glDisable(GL_BLEND);
|
glDisable(GL_BLEND);
|
||||||
#if 0
|
|
||||||
}else{
|
}else{
|
||||||
|
|
||||||
/* Simulate thin stroke by alpha */
|
/* Simulate thin stroke by alpha */
|
||||||
@@ -439,7 +438,6 @@ VG_API_CALL void vgDrawPath(VGPath path, VGbitfield paintModes)
|
|||||||
glDisable(GL_BLEND);
|
glDisable(GL_BLEND);
|
||||||
glDisable(GL_LINE_SMOOTH);
|
glDisable(GL_LINE_SMOOTH);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -124,13 +124,11 @@ int shLineLineXsection(SHVector2 *o1, SHVector2 *v1,
|
|||||||
SHfloat DX = rightU * (-v2->y) - rightD * (-v2->x);
|
SHfloat DX = rightU * (-v2->y) - rightD * (-v2->x);
|
||||||
/*SHfloat DY = v1.x * rightD - v1.y * rightU;*/
|
/*SHfloat DY = v1.x * rightD - v1.y * rightU;*/
|
||||||
|
|
||||||
SHfloat t1;
|
SHfloat t1 = DX / D;
|
||||||
|
|
||||||
if (D == 0.0f)
|
if (D == 0.0f)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
t1 = DX / D;
|
|
||||||
|
|
||||||
xsection->x = o1->x + t1*v1->x;
|
xsection->x = o1->x + t1*v1->x;
|
||||||
xsection->y = o1->y + t1*v1->y;
|
xsection->y = o1->y + t1*v1->y;
|
||||||
return 1;
|
return 1;
|
||||||
|
|||||||
@@ -39,8 +39,8 @@ namespace canvas
|
|||||||
|
|
||||||
#define SG_FWD_DECL(name)\
|
#define SG_FWD_DECL(name)\
|
||||||
class name;\
|
class name;\
|
||||||
typedef SGSharedPtr<name> name##Ptr;\
|
typedef boost::shared_ptr<name> name##Ptr;\
|
||||||
typedef SGWeakPtr<name> name##WeakPtr;
|
typedef boost::weak_ptr<name> name##WeakPtr;
|
||||||
|
|
||||||
SG_FWD_DECL(Canvas)
|
SG_FWD_DECL(Canvas)
|
||||||
SG_FWD_DECL(Element)
|
SG_FWD_DECL(Element)
|
||||||
@@ -49,19 +49,9 @@ namespace canvas
|
|||||||
SG_FWD_DECL(Map)
|
SG_FWD_DECL(Map)
|
||||||
SG_FWD_DECL(Path)
|
SG_FWD_DECL(Path)
|
||||||
SG_FWD_DECL(Text)
|
SG_FWD_DECL(Text)
|
||||||
SG_FWD_DECL(Window)
|
|
||||||
|
|
||||||
SG_FWD_DECL(Event)
|
SG_FWD_DECL(Event)
|
||||||
SG_FWD_DECL(CustomEvent)
|
|
||||||
SG_FWD_DECL(MouseEvent)
|
SG_FWD_DECL(MouseEvent)
|
||||||
|
|
||||||
#undef SG_FWD_DECL
|
|
||||||
|
|
||||||
#define SG_FWD_DECL(name)\
|
|
||||||
class name;\
|
|
||||||
typedef boost::shared_ptr<name> name##Ptr;\
|
|
||||||
typedef boost::weak_ptr<name> name##WeakPtr;
|
|
||||||
|
|
||||||
SG_FWD_DECL(Placement)
|
SG_FWD_DECL(Placement)
|
||||||
SG_FWD_DECL(SystemAdapter)
|
SG_FWD_DECL(SystemAdapter)
|
||||||
|
|
||||||
@@ -70,9 +60,6 @@ namespace canvas
|
|||||||
class EventManager;
|
class EventManager;
|
||||||
class EventVisitor;
|
class EventVisitor;
|
||||||
|
|
||||||
struct EventTarget;
|
|
||||||
typedef std::deque<EventTarget> EventPropagationPath;
|
|
||||||
|
|
||||||
typedef std::map<std::string, const SGPropertyNode*> Style;
|
typedef std::map<std::string, const SGPropertyNode*> Style;
|
||||||
typedef ElementPtr (*ElementFactory)( const CanvasWeakPtr&,
|
typedef ElementPtr (*ElementFactory)( const CanvasWeakPtr&,
|
||||||
const SGPropertyNode_ptr&,
|
const SGPropertyNode_ptr&,
|
||||||
|
|||||||
@@ -24,8 +24,3 @@ set(SOURCES
|
|||||||
|
|
||||||
simgear_scene_component(canvas-elements canvas/elements "${SOURCES}" "${HEADERS}")
|
simgear_scene_component(canvas-elements canvas/elements "${SOURCES}" "${HEADERS}")
|
||||||
simgear_component(canvas-elements/detail canvas/elements/detail "" "${DETAIL_HEADERS}")
|
simgear_component(canvas-elements/detail canvas/elements/detail "" "${DETAIL_HEADERS}")
|
||||||
|
|
||||||
add_boost_test(canvas_element
|
|
||||||
SOURCES canvas_element_test.cpp
|
|
||||||
LIBRARIES ${TEST_LIBS}
|
|
||||||
)
|
|
||||||
@@ -17,9 +17,8 @@
|
|||||||
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||||
|
|
||||||
#include "CanvasElement.hxx"
|
#include "CanvasElement.hxx"
|
||||||
#include <simgear/canvas/Canvas.hxx>
|
|
||||||
#include <simgear/canvas/CanvasEventVisitor.hxx>
|
#include <simgear/canvas/CanvasEventVisitor.hxx>
|
||||||
#include <simgear/canvas/events/MouseEvent.hxx>
|
#include <simgear/canvas/MouseEvent.hxx>
|
||||||
#include <simgear/math/SGMisc.hxx>
|
#include <simgear/math/SGMisc.hxx>
|
||||||
#include <simgear/misc/strutils.hxx>
|
#include <simgear/misc/strutils.hxx>
|
||||||
#include <simgear/scene/material/parseBlendFunc.hxx>
|
#include <simgear/scene/material/parseBlendFunc.hxx>
|
||||||
@@ -51,49 +50,14 @@ namespace canvas
|
|||||||
public:
|
public:
|
||||||
|
|
||||||
ReferenceFrame _coord_reference;
|
ReferenceFrame _coord_reference;
|
||||||
osg::observer_ptr<osg::Node> _node;
|
osg::Matrix _parent_inverse;
|
||||||
|
|
||||||
RelativeScissor(osg::Node* node = NULL):
|
RelativeScissor():
|
||||||
_coord_reference(GLOBAL),
|
_coord_reference(GLOBAL)
|
||||||
_node(node)
|
|
||||||
{
|
|
||||||
_width = 0;
|
|
||||||
_height = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Copy constructor using CopyOp to manage deep vs shallow copy. */
|
|
||||||
RelativeScissor( const RelativeScissor& vp,
|
|
||||||
const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY ):
|
|
||||||
Scissor(vp, copyop),
|
|
||||||
_coord_reference(vp._coord_reference),
|
|
||||||
_node(vp._node)
|
|
||||||
{}
|
{}
|
||||||
|
|
||||||
META_StateAttribute(simgear, RelativeScissor, SCISSOR);
|
|
||||||
|
|
||||||
/** Return -1 if *this < *rhs, 0 if *this==*rhs, 1 if *this>*rhs. */
|
|
||||||
virtual int compare(const StateAttribute& sa) const
|
|
||||||
{
|
|
||||||
// check the types are equal and then create the rhs variable
|
|
||||||
// used by the COMPARE_StateAttribute_Parameter macros below.
|
|
||||||
COMPARE_StateAttribute_Types(RelativeScissor,sa)
|
|
||||||
|
|
||||||
// compare each parameter in turn against the rhs.
|
|
||||||
COMPARE_StateAttribute_Parameter(_x)
|
|
||||||
COMPARE_StateAttribute_Parameter(_y)
|
|
||||||
COMPARE_StateAttribute_Parameter(_width)
|
|
||||||
COMPARE_StateAttribute_Parameter(_height)
|
|
||||||
COMPARE_StateAttribute_Parameter(_coord_reference)
|
|
||||||
COMPARE_StateAttribute_Parameter(_node)
|
|
||||||
|
|
||||||
return 0; // passed all the above comparison macros, must be equal.
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void apply(osg::State& state) const
|
virtual void apply(osg::State& state) const
|
||||||
{
|
{
|
||||||
if( _width <= 0 || _height <= 0 )
|
|
||||||
return;
|
|
||||||
|
|
||||||
const osg::Viewport* vp = state.getCurrentViewport();
|
const osg::Viewport* vp = state.getCurrentViewport();
|
||||||
float w2 = 0.5 * vp->width(),
|
float w2 = 0.5 * vp->width(),
|
||||||
h2 = 0.5 * vp->height();
|
h2 = 0.5 * vp->height();
|
||||||
@@ -109,28 +73,17 @@ namespace canvas
|
|||||||
|
|
||||||
if( _coord_reference != GLOBAL )
|
if( _coord_reference != GLOBAL )
|
||||||
{
|
{
|
||||||
osg::Node* ref_obj = _node.get();
|
model_view.preMult(state.getModelViewMatrix());
|
||||||
|
|
||||||
if( _coord_reference == PARENT )
|
if( _coord_reference == PARENT )
|
||||||
{
|
model_view.preMult(_parent_inverse);
|
||||||
if( _node->getNumParents() < 1 )
|
|
||||||
{
|
|
||||||
SG_LOG(SG_GL, SG_WARN, "RelativeScissor: missing parent.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ref_obj = _node->getParent(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
osg::MatrixList const& parent_matrices = ref_obj->getWorldMatrices();
|
|
||||||
assert( !parent_matrices.empty() );
|
|
||||||
model_view.preMult(parent_matrices.front());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const osg::Vec2 scale( model_view(0,0), model_view(1,1)),
|
const osg::Vec2 scale( model_view(0,0), model_view(1,1)),
|
||||||
offset(model_view(3,0), model_view(3,1));
|
offset(model_view(3,0), model_view(3,1));
|
||||||
|
|
||||||
// TODO check/warn for rotation?
|
// TODO check/warn for rotation?
|
||||||
|
|
||||||
GLint x = SGMiscf::roundToInt(scale.x() * _x + offset.x()),
|
GLint x = SGMiscf::roundToInt(scale.x() * _x + offset.x()),
|
||||||
y = SGMiscf::roundToInt(scale.y() * _y + offset.y()),
|
y = SGMiscf::roundToInt(scale.y() * _y + offset.y()),
|
||||||
w = SGMiscf::roundToInt(std::fabs(scale.x()) * _width),
|
w = SGMiscf::roundToInt(std::fabs(scale.x()) * _width),
|
||||||
@@ -143,26 +96,6 @@ namespace canvas
|
|||||||
|
|
||||||
glScissor(x, y, w, h);
|
glScissor(x, y, w, h);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool contains(const osg::Vec2f& pos) const
|
|
||||||
{
|
|
||||||
return _x <= pos.x() && pos.x() <= _x + _width
|
|
||||||
&& _y <= pos.y() && pos.y() <= _y + _height;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool contains( const osg::Vec2f& global_pos,
|
|
||||||
const osg::Vec2f& parent_pos,
|
|
||||||
const osg::Vec2f& local_pos ) const
|
|
||||||
{
|
|
||||||
switch( _coord_reference )
|
|
||||||
{
|
|
||||||
case GLOBAL: return contains(global_pos);
|
|
||||||
case PARENT: return contains(parent_pos);
|
|
||||||
case LOCAL: return contains(local_pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
@@ -190,6 +123,17 @@ namespace canvas
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void Element::setSelf(const PropertyBasedElementPtr& self)
|
||||||
|
{
|
||||||
|
PropertyBasedElement::setSelf(self);
|
||||||
|
|
||||||
|
_transform->setUserData
|
||||||
|
(
|
||||||
|
new OSGUserData(boost::static_pointer_cast<Element>(self))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
void Element::onDestroy()
|
void Element::onDestroy()
|
||||||
{
|
{
|
||||||
@@ -202,41 +146,43 @@ namespace canvas
|
|||||||
{
|
{
|
||||||
parent->removeChild(_transform.get());
|
parent->removeChild(_transform.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hide in case someone still holds a reference
|
|
||||||
setVisible(false);
|
|
||||||
removeListener();
|
|
||||||
|
|
||||||
_parent = 0;
|
|
||||||
_transform = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
ElementPtr Element::getParent() const
|
ElementWeakPtr Element::getWeakPtr() const
|
||||||
{
|
{
|
||||||
return _parent;
|
return boost::static_pointer_cast<Element>(_self.lock());
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
CanvasWeakPtr Element::getCanvas() const
|
ElementPtr Element::getParent()
|
||||||
{
|
{
|
||||||
return _canvas;
|
return _parent ? _parent->getWeakPtr().lock() : ElementPtr();
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
void Element::update(double dt)
|
void Element::update(double dt)
|
||||||
{
|
{
|
||||||
if( !isVisible() )
|
if( !_transform->getNodeMask() )
|
||||||
|
// Don't do anything if element is hidden
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Trigger matrix update
|
// Trigger matrix update
|
||||||
getMatrix();
|
getMatrix();
|
||||||
|
|
||||||
|
if( _attributes_dirty & SCISSOR_COORDS )
|
||||||
|
{
|
||||||
|
if( _scissor && _scissor->_coord_reference != GLOBAL )
|
||||||
|
_scissor->_parent_inverse = _transform->getInverseMatrix();
|
||||||
|
|
||||||
|
_attributes_dirty &= ~SCISSOR_COORDS;
|
||||||
|
}
|
||||||
|
|
||||||
// Update bounding box on manual update (manual updates pass zero dt)
|
// Update bounding box on manual update (manual updates pass zero dt)
|
||||||
if( dt == 0 && _drawable )
|
if( dt == 0 && _drawable )
|
||||||
_drawable->getBound();
|
_drawable->getBound();
|
||||||
|
|
||||||
if( (_attributes_dirty & BLEND_FUNC) && _transform.valid() )
|
if( _attributes_dirty & BLEND_FUNC )
|
||||||
{
|
{
|
||||||
parseBlendFunc(
|
parseBlendFunc(
|
||||||
_transform->getOrCreateStateSet(),
|
_transform->getOrCreateStateSet(),
|
||||||
@@ -262,7 +208,17 @@ namespace canvas
|
|||||||
"addEventListener(" << _node->getPath() << ", " << type_str << ")"
|
"addEventListener(" << _node->getPath() << ", " << type_str << ")"
|
||||||
);
|
);
|
||||||
|
|
||||||
_listener[ Event::getOrRegisterType(type_str) ].push_back(cb);
|
Event::Type type = Event::strToType(type_str);
|
||||||
|
if( type == Event::UNKNOWN )
|
||||||
|
{
|
||||||
|
SG_LOG( SG_GENERAL,
|
||||||
|
SG_WARN,
|
||||||
|
"addEventListener: Unknown event type " << type_str );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
_listener[ type ].push_back(cb);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -296,74 +252,30 @@ namespace canvas
|
|||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
bool Element::handleEvent(const EventPtr& event)
|
bool Element::handleEvent(canvas::EventPtr event)
|
||||||
{
|
{
|
||||||
ListenerMap::iterator listeners = _listener.find(event->getType());
|
ListenerMap::iterator listeners = _listener.find(event->getType());
|
||||||
if( listeners == _listener.end() )
|
if( listeners == _listener.end() )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
BOOST_FOREACH(EventListener const& listener, listeners->second)
|
BOOST_FOREACH(EventListener const& listener, listeners->second)
|
||||||
try
|
|
||||||
{
|
|
||||||
listener(event);
|
listener(event);
|
||||||
}
|
|
||||||
catch( std::exception const& ex )
|
|
||||||
{
|
|
||||||
SG_LOG(
|
|
||||||
SG_GENERAL,
|
|
||||||
SG_WARN,
|
|
||||||
"canvas::Element: event handler error: '" << ex.what() << "'"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
bool Element::dispatchEvent(const EventPtr& event)
|
bool Element::hitBound( const osg::Vec2f& pos,
|
||||||
{
|
|
||||||
EventPropagationPath path;
|
|
||||||
path.push_back( EventTarget(this) );
|
|
||||||
|
|
||||||
for( Element* parent = _parent;
|
|
||||||
parent != NULL;
|
|
||||||
parent = parent->_parent )
|
|
||||||
path.push_front( EventTarget(parent) );
|
|
||||||
|
|
||||||
CanvasPtr canvas = _canvas.lock();
|
|
||||||
if( !canvas )
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return canvas->propagateEvent(event, path);
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
bool Element::hitBound( const osg::Vec2f& global_pos,
|
|
||||||
const osg::Vec2f& parent_pos,
|
|
||||||
const osg::Vec2f& local_pos ) const
|
const osg::Vec2f& local_pos ) const
|
||||||
{
|
{
|
||||||
if( _scissor && !_scissor->contains(global_pos, parent_pos, local_pos) )
|
const osg::Vec3f pos3(pos, 0);
|
||||||
return false;
|
|
||||||
|
|
||||||
const osg::Vec3f pos3(parent_pos, 0);
|
|
||||||
|
|
||||||
// Drawables have a bounding box...
|
// Drawables have a bounding box...
|
||||||
if( _drawable )
|
if( _drawable )
|
||||||
return _drawable->getBound().contains(osg::Vec3f(local_pos, 0));
|
return _drawable->getBound().contains(osg::Vec3f(local_pos, 0));
|
||||||
else if( _transform.valid() )
|
|
||||||
// ... for other elements, i.e. groups only a bounding sphere is available
|
// ... for other elements, i.e. groups only a bounding sphere is available
|
||||||
return _transform->getBound().contains(osg::Vec3f(parent_pos, 0));
|
|
||||||
else
|
else
|
||||||
return false;
|
return _transform->getBound().contains(osg::Vec3f(pos, 0));
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
void Element::setVisible(bool visible)
|
|
||||||
{
|
|
||||||
if( _transform.valid() )
|
|
||||||
// TODO check if we need another nodemask
|
|
||||||
_transform->setNodeMask(visible ? 0xffffffff : 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
@@ -384,18 +296,6 @@ namespace canvas
|
|||||||
return _transform.get();
|
return _transform.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
osg::Vec2f Element::posToLocal(const osg::Vec2f& pos) const
|
|
||||||
{
|
|
||||||
getMatrix();
|
|
||||||
const osg::Matrix& m = _transform->getInverseMatrix();
|
|
||||||
return osg::Vec2f
|
|
||||||
(
|
|
||||||
m(0, 0) * pos[0] + m(1, 0) * pos[1] + m(3, 0),
|
|
||||||
m(0, 1) * pos[0] + m(1, 1) * pos[1] + m(3, 1)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
void Element::childAdded(SGPropertyNode* parent, SGPropertyNode* child)
|
void Element::childAdded(SGPropertyNode* parent, SGPropertyNode* child)
|
||||||
{
|
{
|
||||||
@@ -480,9 +380,7 @@ namespace canvas
|
|||||||
if( parent == _node )
|
if( parent == _node )
|
||||||
{
|
{
|
||||||
const std::string& name = child->getNameString();
|
const std::string& name = child->getNameString();
|
||||||
if( boost::starts_with(name, "data-") )
|
if( StyleInfo const* style_info = getStyleInfo(name) )
|
||||||
return;
|
|
||||||
else if( StyleInfo const* style_info = getStyleInfo(name) )
|
|
||||||
{
|
{
|
||||||
SGPropertyNode const* style = child;
|
SGPropertyNode const* style = child;
|
||||||
if( isStyleEmpty(child) )
|
if( isStyleEmpty(child) )
|
||||||
@@ -495,11 +393,13 @@ namespace canvas
|
|||||||
}
|
}
|
||||||
else if( name == "update" )
|
else if( name == "update" )
|
||||||
return update(0);
|
return update(0);
|
||||||
|
else if( name == "visible" )
|
||||||
|
// TODO check if we need another nodemask
|
||||||
|
return _transform->setNodeMask( child->getBoolValue() ? 0xffffffff : 0 );
|
||||||
else if( boost::starts_with(name, "blend-") )
|
else if( boost::starts_with(name, "blend-") )
|
||||||
return (void)(_attributes_dirty |= BLEND_FUNC);
|
return (void)(_attributes_dirty |= BLEND_FUNC);
|
||||||
}
|
}
|
||||||
else if( parent
|
else if( parent->getParent() == _node
|
||||||
&& parent->getParent() == _node
|
|
||||||
&& parent->getNameString() == NAME_TRANSFORM )
|
&& parent->getNameString() == NAME_TRANSFORM )
|
||||||
{
|
{
|
||||||
_attributes_dirty |= TRANSFORM;
|
_attributes_dirty |= TRANSFORM;
|
||||||
@@ -519,13 +419,9 @@ namespace canvas
|
|||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
void Element::setClip(const std::string& clip)
|
void Element::setClip(const std::string& clip)
|
||||||
{
|
{
|
||||||
osg::StateSet* ss = getOrCreateStateSet();
|
|
||||||
if( !ss )
|
|
||||||
return;
|
|
||||||
|
|
||||||
if( clip.empty() || clip == "auto" )
|
if( clip.empty() || clip == "auto" )
|
||||||
{
|
{
|
||||||
ss->removeAttribute(osg::StateAttribute::SCISSOR);
|
getOrCreateStateSet()->removeAttribute(osg::StateAttribute::SCISSOR);
|
||||||
_scissor = 0;
|
_scissor = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -572,49 +468,47 @@ namespace canvas
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( !_scissor )
|
_scissor = new RelativeScissor();
|
||||||
_scissor = new RelativeScissor(_transform.get());
|
|
||||||
|
|
||||||
// <top>, <right>, <bottom>, <left>
|
// <top>, <right>, <bottom>, <left>
|
||||||
_scissor->x() = SGMiscf::roundToInt(values[3]);
|
_scissor->x() = SGMiscf::roundToInt(values[3]);
|
||||||
_scissor->y() = SGMiscf::roundToInt(values[0]);
|
_scissor->y() = SGMiscf::roundToInt(values[0]);
|
||||||
_scissor->width() = SGMiscf::roundToInt(width);
|
_scissor->width() = SGMiscf::roundToInt(width);
|
||||||
_scissor->height() = SGMiscf::roundToInt(height);
|
_scissor->height() = SGMiscf::roundToInt(height);
|
||||||
|
|
||||||
|
getOrCreateStateSet()->setAttributeAndModes(_scissor);
|
||||||
|
|
||||||
SGPropertyNode* clip_frame = _node->getChild("clip-frame", 0);
|
SGPropertyNode* clip_frame = _node->getChild("clip-frame", 0);
|
||||||
if( clip_frame )
|
if( clip_frame )
|
||||||
valueChanged(clip_frame);
|
valueChanged(clip_frame);
|
||||||
else
|
|
||||||
_scissor->_coord_reference = GLOBAL;
|
|
||||||
|
|
||||||
ss->setAttributeAndModes(_scissor);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
void Element::setClipFrame(ReferenceFrame rf)
|
void Element::setClipFrame(ReferenceFrame rf)
|
||||||
{
|
{
|
||||||
if( _scissor )
|
if( _scissor )
|
||||||
|
{
|
||||||
_scissor->_coord_reference = rf;
|
_scissor->_coord_reference = rf;
|
||||||
|
_attributes_dirty |= SCISSOR_COORDS;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
osg::BoundingBox Element::getBoundingBox() const
|
void Element::setBoundingBox(const osg::BoundingBox& bb)
|
||||||
{
|
{
|
||||||
if( _drawable )
|
if( _bounding_box.empty() )
|
||||||
return _drawable->getBound();
|
{
|
||||||
|
SGPropertyNode* bb_node = _node->getChild("bounding-box", 0, true);
|
||||||
osg::BoundingBox bb;
|
_bounding_box.resize(4);
|
||||||
|
_bounding_box[0] = bb_node->getChild("min-x", 0, true);
|
||||||
if( _transform.valid() )
|
_bounding_box[1] = bb_node->getChild("min-y", 0, true);
|
||||||
bb.expandBy(_transform->getBound());
|
_bounding_box[2] = bb_node->getChild("max-x", 0, true);
|
||||||
|
_bounding_box[3] = bb_node->getChild("max-y", 0, true);
|
||||||
return bb;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
_bounding_box[0]->setFloatValue(bb._min.x());
|
||||||
osg::BoundingBox Element::getTightBoundingBox() const
|
_bounding_box[1]->setFloatValue(bb._min.y());
|
||||||
{
|
_bounding_box[2]->setFloatValue(bb._max.x());
|
||||||
return getTransformedBounds(getMatrix());
|
_bounding_box[3]->setFloatValue(bb._max.y());
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
@@ -634,9 +528,6 @@ namespace canvas
|
|||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
osg::Matrix Element::getMatrix() const
|
osg::Matrix Element::getMatrix() const
|
||||||
{
|
{
|
||||||
if( !_transform )
|
|
||||||
return osg::Matrix::identity();
|
|
||||||
|
|
||||||
if( !(_attributes_dirty & TRANSFORM) )
|
if( !(_attributes_dirty & TRANSFORM) )
|
||||||
return _transform->getMatrix();
|
return _transform->getMatrix();
|
||||||
|
|
||||||
@@ -696,6 +587,7 @@ namespace canvas
|
|||||||
}
|
}
|
||||||
_transform->setMatrix(m);
|
_transform->setMatrix(m);
|
||||||
_attributes_dirty &= ~TRANSFORM;
|
_attributes_dirty &= ~TRANSFORM;
|
||||||
|
_attributes_dirty |= SCISSOR_COORDS;
|
||||||
|
|
||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
@@ -734,8 +626,6 @@ namespace canvas
|
|||||||
"PreOrderBin",
|
"PreOrderBin",
|
||||||
osg::StateSet::OVERRIDE_RENDERBIN_DETAILS
|
osg::StateSet::OVERRIDE_RENDERBIN_DETAILS
|
||||||
);
|
);
|
||||||
|
|
||||||
_transform->setUserData( new OSGUserData(this) );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
@@ -746,7 +636,6 @@ namespace canvas
|
|||||||
|
|
||||||
addStyle("clip", "", &Element::setClip, false);
|
addStyle("clip", "", &Element::setClip, false);
|
||||||
addStyle("clip-frame", "", &Element::setClipFrame, false);
|
addStyle("clip-frame", "", &Element::setClipFrame, false);
|
||||||
addStyle("visible", "", &Element::setVisible, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
@@ -832,12 +721,8 @@ namespace canvas
|
|||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
osg::StateSet* Element::getOrCreateStateSet()
|
osg::StateSet* Element::getOrCreateStateSet()
|
||||||
{
|
{
|
||||||
if( _drawable.valid() )
|
return _drawable ? _drawable->getOrCreateStateSet()
|
||||||
return _drawable->getOrCreateStateSet();
|
: _transform->getOrCreateStateSet();
|
||||||
if( _transform.valid() )
|
|
||||||
return _transform->getOrCreateStateSet();
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
///@file Interface for 2D Canvas elements
|
// Interface for 2D Canvas elements
|
||||||
//
|
//
|
||||||
// Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com>
|
// Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com>
|
||||||
//
|
//
|
||||||
@@ -41,9 +41,6 @@ namespace simgear
|
|||||||
namespace canvas
|
namespace canvas
|
||||||
{
|
{
|
||||||
|
|
||||||
/**
|
|
||||||
* Baseclass for Elements displayed inside a Canvas.
|
|
||||||
*/
|
|
||||||
class Element:
|
class Element:
|
||||||
public PropertyBasedElement
|
public PropertyBasedElement
|
||||||
{
|
{
|
||||||
@@ -72,9 +69,9 @@ namespace canvas
|
|||||||
};
|
};
|
||||||
struct StyleInfo
|
struct StyleInfo
|
||||||
{
|
{
|
||||||
StyleSetter setter; ///< Function(s) for setting this style
|
StyleSetter setter; ///!< Function(s) for setting this style
|
||||||
std::string type; ///< Interpolation type
|
std::string type; ///!< Interpolation type
|
||||||
bool inheritable; ///< Whether children can inherit this style from
|
bool inheritable; ///!< Whether children can inherit this style from
|
||||||
/// their parents
|
/// their parents
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -83,9 +80,9 @@ namespace canvas
|
|||||||
*/
|
*/
|
||||||
enum ReferenceFrame
|
enum ReferenceFrame
|
||||||
{
|
{
|
||||||
GLOBAL, ///< Global coordinates
|
GLOBAL, ///!< Global coordinates
|
||||||
PARENT, ///< Coordinates relative to parent coordinate frame
|
PARENT, ///!< Coordinates relative to parent coordinate frame
|
||||||
LOCAL ///< Coordinates relative to local coordinates (parent
|
LOCAL ///!< Coordinates relative to local coordinates (parent
|
||||||
/// coordinates with local transformations applied)
|
/// coordinates with local transformations applied)
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -93,10 +90,12 @@ namespace canvas
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
virtual ~Element() = 0;
|
virtual ~Element() = 0;
|
||||||
|
|
||||||
|
virtual void setSelf(const PropertyBasedElementPtr& self);
|
||||||
virtual void onDestroy();
|
virtual void onDestroy();
|
||||||
|
|
||||||
ElementPtr getParent() const;
|
ElementWeakPtr getWeakPtr() const;
|
||||||
CanvasWeakPtr getCanvas() const;
|
ElementPtr getParent();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called every frame to update internal state
|
* Called every frame to update internal state
|
||||||
@@ -112,37 +111,20 @@ namespace canvas
|
|||||||
virtual bool ascend(EventVisitor& visitor);
|
virtual bool ascend(EventVisitor& visitor);
|
||||||
virtual bool traverse(EventVisitor& visitor);
|
virtual bool traverse(EventVisitor& visitor);
|
||||||
|
|
||||||
virtual bool handleEvent(const EventPtr& event);
|
virtual bool handleEvent(canvas::EventPtr event);
|
||||||
bool dispatchEvent(const EventPtr& event);
|
|
||||||
|
|
||||||
/**
|
virtual bool hitBound( const osg::Vec2f& pos,
|
||||||
*
|
|
||||||
* @param global_pos Position in global (canvas) coordinate frame
|
|
||||||
* @param parent_pos Position in parent coordinate frame
|
|
||||||
* @param local_pos Position in local (element) coordinate frame
|
|
||||||
*/
|
|
||||||
virtual bool hitBound( const osg::Vec2f& global_pos,
|
|
||||||
const osg::Vec2f& parent_pos,
|
|
||||||
const osg::Vec2f& local_pos ) const;
|
const osg::Vec2f& local_pos ) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set visibility of the element.
|
* Get whether the element is visible or hidden (Can be changed with
|
||||||
*/
|
* setting property "visible" accordingly).
|
||||||
void setVisible(bool visible);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get whether the element is visible or hidden.
|
|
||||||
*/
|
*/
|
||||||
bool isVisible() const;
|
bool isVisible() const;
|
||||||
|
|
||||||
osg::MatrixTransform* getMatrixTransform();
|
osg::MatrixTransform* getMatrixTransform();
|
||||||
osg::MatrixTransform const* getMatrixTransform() const;
|
osg::MatrixTransform const* getMatrixTransform() const;
|
||||||
|
|
||||||
/**
|
|
||||||
* Transform position to local coordinages.
|
|
||||||
*/
|
|
||||||
osg::Vec2f posToLocal(const osg::Vec2f& pos) const;
|
|
||||||
|
|
||||||
virtual void childAdded( SGPropertyNode * parent,
|
virtual void childAdded( SGPropertyNode * parent,
|
||||||
SGPropertyNode * child );
|
SGPropertyNode * child );
|
||||||
virtual void childRemoved( SGPropertyNode * parent,
|
virtual void childRemoved( SGPropertyNode * parent,
|
||||||
@@ -166,16 +148,9 @@ namespace canvas
|
|||||||
void setClipFrame(ReferenceFrame rf);
|
void setClipFrame(ReferenceFrame rf);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get bounding box (may not be as tight as bounding box returned by
|
* Write the given bounding box to the property tree
|
||||||
* #getTightBoundingBox)
|
|
||||||
*/
|
*/
|
||||||
osg::BoundingBox getBoundingBox() const;
|
void setBoundingBox(const osg::BoundingBox& bb);
|
||||||
|
|
||||||
/**
|
|
||||||
* Get tight bounding box (child points are transformed to elements
|
|
||||||
* coordinate space before calculating the bounding box).
|
|
||||||
*/
|
|
||||||
osg::BoundingBox getTightBoundingBox() const;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get bounding box with children/drawables transformed by passed matrix
|
* Get bounding box with children/drawables transformed by passed matrix
|
||||||
@@ -199,10 +174,12 @@ namespace canvas
|
|||||||
ElementPtr
|
ElementPtr
|
||||||
>::type create( const CanvasWeakPtr& canvas,
|
>::type create( const CanvasWeakPtr& canvas,
|
||||||
const SGPropertyNode_ptr& node,
|
const SGPropertyNode_ptr& node,
|
||||||
const Style& style = Style(),
|
const Style& style,
|
||||||
Element* parent = NULL )
|
Element* parent )
|
||||||
{
|
{
|
||||||
return ElementPtr( new Derived(canvas, node, style, parent) );
|
ElementPtr el( new Derived(canvas, node, style, parent) );
|
||||||
|
el->setSelf(el);
|
||||||
|
return el;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@@ -211,7 +188,8 @@ namespace canvas
|
|||||||
{
|
{
|
||||||
TRANSFORM = 1,
|
TRANSFORM = 1,
|
||||||
BLEND_FUNC = TRANSFORM << 1,
|
BLEND_FUNC = TRANSFORM << 1,
|
||||||
LAST_ATTRIBUTE = BLEND_FUNC << 1
|
SCISSOR_COORDS = BLEND_FUNC << 1,
|
||||||
|
LAST_ATTRIBUTE = SCISSOR_COORDS << 1
|
||||||
};
|
};
|
||||||
|
|
||||||
enum TransformType
|
enum TransformType
|
||||||
@@ -234,10 +212,11 @@ namespace canvas
|
|||||||
std::vector<TransformType> _transform_types;
|
std::vector<TransformType> _transform_types;
|
||||||
|
|
||||||
Style _style;
|
Style _style;
|
||||||
|
std::vector<SGPropertyNode_ptr> _bounding_box;
|
||||||
RelativeScissor *_scissor;
|
RelativeScissor *_scissor;
|
||||||
|
|
||||||
typedef std::vector<EventListener> Listener;
|
typedef std::vector<EventListener> Listener;
|
||||||
typedef std::map<int, Listener> ListenerMap;
|
typedef std::map<Event::Type, Listener> ListenerMap;
|
||||||
|
|
||||||
ListenerMap _listener;
|
ListenerMap _listener;
|
||||||
|
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
#include "CanvasPath.hxx"
|
#include "CanvasPath.hxx"
|
||||||
#include "CanvasText.hxx"
|
#include "CanvasText.hxx"
|
||||||
#include <simgear/canvas/CanvasEventVisitor.hxx>
|
#include <simgear/canvas/CanvasEventVisitor.hxx>
|
||||||
#include <simgear/canvas/events/MouseEvent.hxx>
|
#include <simgear/canvas/MouseEvent.hxx>
|
||||||
|
|
||||||
#include <boost/bind.hpp>
|
#include <boost/bind.hpp>
|
||||||
#include <boost/foreach.hpp>
|
#include <boost/foreach.hpp>
|
||||||
@@ -146,7 +146,7 @@ namespace canvas
|
|||||||
if( el->get<std::string>("id") == id )
|
if( el->get<std::string>("id") == id )
|
||||||
return el;
|
return el;
|
||||||
|
|
||||||
Group* group = dynamic_cast<Group*>(el.get());
|
GroupPtr group = boost::dynamic_pointer_cast<Group>(el);
|
||||||
if( group )
|
if( group )
|
||||||
groups.push_back(group);
|
groups.push_back(group);
|
||||||
}
|
}
|
||||||
@@ -320,12 +320,10 @@ namespace canvas
|
|||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
void Group::childChanged(SGPropertyNode* node)
|
void Group::childChanged(SGPropertyNode* node)
|
||||||
{
|
{
|
||||||
SGPropertyNode* parent = node->getParent();
|
if( node->getParent()->getParent() == _node
|
||||||
SGPropertyNode* grand_parent = parent ? parent->getParent() : NULL;
|
|
||||||
|
|
||||||
if( grand_parent == _node
|
|
||||||
&& node->getNameString() == "z-index" )
|
&& node->getNameString() == "z-index" )
|
||||||
return handleZIndexChanged(getChild(parent), node->getIntValue());
|
return handleZIndexChanged( getChild(node->getParent()),
|
||||||
|
node->getIntValue() );
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -56,27 +56,28 @@ namespace canvas
|
|||||||
const std::string& id );
|
const std::string& id );
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
SGSharedPtr<T> createChild(const std::string& id = "")
|
boost::shared_ptr<T> createChild(const std::string& id = "")
|
||||||
{
|
{
|
||||||
return dynamic_cast<T*>( createChild(T::TYPE_NAME, id).get() );
|
return boost::dynamic_pointer_cast<T>( createChild(T::TYPE_NAME, id) );
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
SGSharedPtr<T> getChild(const SGPropertyNode* node)
|
boost::shared_ptr<T> getChild(const SGPropertyNode* node)
|
||||||
{
|
{
|
||||||
return dynamic_cast<T*>( getChild(node).get() );
|
return boost::dynamic_pointer_cast<T>( getChild(node) );
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
SGSharedPtr<T> getChild(const std::string& id)
|
boost::shared_ptr<T> getChild(const std::string& id)
|
||||||
{
|
{
|
||||||
return dynamic_cast<T*>( getChild(id).get() );
|
return boost::dynamic_pointer_cast<T>( getChild(id) );
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
SGSharedPtr<T> getOrCreateChild(const std::string& id)
|
boost::shared_ptr<T> getOrCreateChild(const std::string& id)
|
||||||
{
|
{
|
||||||
return dynamic_cast<T*>( getOrCreateChild(T::TYPE_NAME, id).get() );
|
return
|
||||||
|
boost::dynamic_pointer_cast<T>( getOrCreateChild(T::TYPE_NAME, id) );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
#include <simgear/canvas/Canvas.hxx>
|
#include <simgear/canvas/Canvas.hxx>
|
||||||
#include <simgear/canvas/CanvasMgr.hxx>
|
#include <simgear/canvas/CanvasMgr.hxx>
|
||||||
#include <simgear/canvas/CanvasSystemAdapter.hxx>
|
#include <simgear/canvas/CanvasSystemAdapter.hxx>
|
||||||
#include <simgear/canvas/events/MouseEvent.hxx>
|
#include <simgear/canvas/MouseEvent.hxx>
|
||||||
#include <simgear/scene/util/OsgMath.hxx>
|
#include <simgear/scene/util/OsgMath.hxx>
|
||||||
#include <simgear/scene/util/parse_color.hxx>
|
#include <simgear/scene/util/parse_color.hxx>
|
||||||
#include <simgear/misc/sg_path.hxx>
|
#include <simgear/misc/sg_path.hxx>
|
||||||
@@ -29,7 +29,8 @@
|
|||||||
#include <osg/Array>
|
#include <osg/Array>
|
||||||
#include <osg/Geometry>
|
#include <osg/Geometry>
|
||||||
#include <osg/PrimitiveSet>
|
#include <osg/PrimitiveSet>
|
||||||
#include <osgDB/Registry>
|
|
||||||
|
#include <boost/algorithm/string/predicate.hpp>
|
||||||
|
|
||||||
namespace simgear
|
namespace simgear
|
||||||
{
|
{
|
||||||
@@ -74,9 +75,8 @@ namespace canvas
|
|||||||
osg::Drawable* drawable,
|
osg::Drawable* drawable,
|
||||||
osg::RenderInfo* renderInfo ) const
|
osg::RenderInfo* renderInfo ) const
|
||||||
{
|
{
|
||||||
CanvasPtr canvas = _canvas.lock();
|
if( !_canvas.expired() )
|
||||||
if( canvas )
|
_canvas.lock()->enableRendering();
|
||||||
canvas->enableRendering();
|
|
||||||
|
|
||||||
if( !_cull_next_frame )
|
if( !_cull_next_frame )
|
||||||
// TODO check if window/image should be culled
|
// TODO check if window/image should be culled
|
||||||
@@ -96,10 +96,9 @@ namespace canvas
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
addStyle("fill", "color", &Image::setFill);
|
addStyle("fill", "color", &Image::setFill);
|
||||||
addStyle("outset", "", &Image::setOutset);
|
|
||||||
addStyle("preserveAspectRatio", "", &Image::setPreserveAspectRatio);
|
|
||||||
addStyle("slice", "", &Image::setSlice);
|
addStyle("slice", "", &Image::setSlice);
|
||||||
addStyle("slice-width", "", &Image::setSliceWidth);
|
addStyle("slice-width", "", &Image::setSliceWidth);
|
||||||
|
addStyle("outset", "", &Image::setOutset);
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
@@ -129,11 +128,12 @@ namespace canvas
|
|||||||
|
|
||||||
_texCoords = new osg::Vec2Array(4);
|
_texCoords = new osg::Vec2Array(4);
|
||||||
_texCoords->setDataVariance(osg::Object::DYNAMIC);
|
_texCoords->setDataVariance(osg::Object::DYNAMIC);
|
||||||
_geom->setTexCoordArray(0, _texCoords, osg::Array::BIND_PER_VERTEX);
|
_geom->setTexCoordArray(0, _texCoords);
|
||||||
|
|
||||||
_colors = new osg::Vec4Array(1);
|
_colors = new osg::Vec4Array(1);
|
||||||
_colors->setDataVariance(osg::Object::DYNAMIC);
|
_colors->setDataVariance(osg::Object::DYNAMIC);
|
||||||
_geom->setColorArray(_colors, osg::Array::BIND_OVERALL);
|
_geom->setColorArray(_colors);
|
||||||
|
_geom->setColorBinding(osg::Geometry::BIND_OVERALL);
|
||||||
|
|
||||||
_prim = new osg::DrawArrays(osg::PrimitiveSet::QUADS);
|
_prim = new osg::DrawArrays(osg::PrimitiveSet::QUADS);
|
||||||
_prim->set(osg::PrimitiveSet::QUADS, 0, 4);
|
_prim->set(osg::PrimitiveSet::QUADS, 0, 4);
|
||||||
@@ -149,8 +149,7 @@ namespace canvas
|
|||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
Image::~Image()
|
Image::~Image()
|
||||||
{
|
{
|
||||||
if( _http_request )
|
|
||||||
_http_request->abort("image destroyed");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
@@ -215,10 +214,6 @@ namespace canvas
|
|||||||
if( !_slice.isValid() )
|
if( !_slice.isValid() )
|
||||||
{
|
{
|
||||||
setQuad(0, region.getMin(), region.getMax());
|
setQuad(0, region.getMin(), region.getMax());
|
||||||
|
|
||||||
if( !_preserve_aspect_ratio.scaleToFill() )
|
|
||||||
// We need to update texture coordinates to keep the aspect ratio
|
|
||||||
_attributes_dirty |= SRC_RECT;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -277,6 +272,7 @@ namespace canvas
|
|||||||
_vertices->dirty();
|
_vertices->dirty();
|
||||||
_attributes_dirty &= ~DEST_SIZE;
|
_attributes_dirty &= ~DEST_SIZE;
|
||||||
_geom->dirtyBound();
|
_geom->dirtyBound();
|
||||||
|
setBoundingBox(_geom->getBound());
|
||||||
}
|
}
|
||||||
|
|
||||||
if( _attributes_dirty & SRC_RECT )
|
if( _attributes_dirty & SRC_RECT )
|
||||||
@@ -295,66 +291,6 @@ namespace canvas
|
|||||||
|
|
||||||
if( !_slice.isValid() )
|
if( !_slice.isValid() )
|
||||||
{
|
{
|
||||||
// Image scaling preserving aspect ratio. Change texture coordinates to
|
|
||||||
// scale image accordingly.
|
|
||||||
//
|
|
||||||
// TODO allow to specify what happens to not filled space (eg. color,
|
|
||||||
// or texture repeat/mirror)
|
|
||||||
//
|
|
||||||
// http://www.w3.org/TR/SVG11/coords.html#PreserveAspectRatioAttribute
|
|
||||||
if( !_preserve_aspect_ratio.scaleToFill() )
|
|
||||||
{
|
|
||||||
osg::BoundingBox const& bb = getBoundingBox();
|
|
||||||
float dst_width = bb._max.x() - bb._min.x(),
|
|
||||||
dst_height = bb._max.y() - bb._min.y();
|
|
||||||
float scale_x = dst_width / tex_dim.width(),
|
|
||||||
scale_y = dst_height / tex_dim.height();
|
|
||||||
|
|
||||||
float scale = _preserve_aspect_ratio.scaleToFit()
|
|
||||||
? std::min(scale_x, scale_y)
|
|
||||||
: std::max(scale_x, scale_y);
|
|
||||||
|
|
||||||
if( scale_x != scale )
|
|
||||||
{
|
|
||||||
float d = scale_x / scale - 1;
|
|
||||||
if( _preserve_aspect_ratio.alignX()
|
|
||||||
== SVGpreserveAspectRatio::ALIGN_MIN )
|
|
||||||
{
|
|
||||||
src_rect.r() += d;
|
|
||||||
}
|
|
||||||
else if( _preserve_aspect_ratio.alignX()
|
|
||||||
== SVGpreserveAspectRatio::ALIGN_MAX )
|
|
||||||
{
|
|
||||||
src_rect.l() -= d;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
src_rect.l() -= d / 2;
|
|
||||||
src_rect.r() += d / 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if( scale_y != scale )
|
|
||||||
{
|
|
||||||
float d = scale_y / scale - 1;
|
|
||||||
if( _preserve_aspect_ratio.alignY()
|
|
||||||
== SVGpreserveAspectRatio::ALIGN_MIN )
|
|
||||||
{
|
|
||||||
src_rect.b() -= d;
|
|
||||||
}
|
|
||||||
else if( _preserve_aspect_ratio.alignY()
|
|
||||||
== SVGpreserveAspectRatio::ALIGN_MAX )
|
|
||||||
{
|
|
||||||
src_rect.t() += d;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
src_rect.t() += d / 2;
|
|
||||||
src_rect.b() -= d / 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setQuadUV(0, src_rect.getMin(), src_rect.getMax());
|
setQuadUV(0, src_rect.getMin(), src_rect.getMax());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -478,20 +414,6 @@ namespace canvas
|
|||||||
_colors->dirty();
|
_colors->dirty();
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
void Image::setOutset(const std::string& outset)
|
|
||||||
{
|
|
||||||
_outset = CSSBorder::parse(outset);
|
|
||||||
_attributes_dirty |= DEST_SIZE;
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
void Image::setPreserveAspectRatio(const std::string& scale)
|
|
||||||
{
|
|
||||||
_preserve_aspect_ratio = SVGpreserveAspectRatio::parse(scale);
|
|
||||||
_attributes_dirty |= SRC_RECT;
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
void Image::setSlice(const std::string& slice)
|
void Image::setSlice(const std::string& slice)
|
||||||
{
|
{
|
||||||
@@ -506,6 +428,13 @@ namespace canvas
|
|||||||
_attributes_dirty |= DEST_SIZE;
|
_attributes_dirty |= DEST_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void Image::setOutset(const std::string& outset)
|
||||||
|
{
|
||||||
|
_outset = CSSBorder::parse(outset);
|
||||||
|
_attributes_dirty |= DEST_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
const SGRect<float>& Image::getRegion() const
|
const SGRect<float>& Image::getRegion() const
|
||||||
{
|
{
|
||||||
@@ -513,7 +442,7 @@ namespace canvas
|
|||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
bool Image::handleEvent(const EventPtr& event)
|
bool Image::handleEvent(EventPtr event)
|
||||||
{
|
{
|
||||||
bool handled = Element::handleEvent(event);
|
bool handled = Element::handleEvent(event);
|
||||||
|
|
||||||
@@ -521,10 +450,11 @@ namespace canvas
|
|||||||
if( !src_canvas )
|
if( !src_canvas )
|
||||||
return handled;
|
return handled;
|
||||||
|
|
||||||
MouseEventPtr mouse_event = dynamic_cast<MouseEvent*>(event.get());
|
MouseEventPtr mouse_event = boost::dynamic_pointer_cast<MouseEvent>(event);
|
||||||
if( mouse_event )
|
if( mouse_event )
|
||||||
{
|
{
|
||||||
mouse_event.reset( new MouseEvent(*mouse_event) );
|
mouse_event.reset( new MouseEvent(*mouse_event) );
|
||||||
|
event = mouse_event;
|
||||||
|
|
||||||
mouse_event->client_pos = mouse_event->local_pos
|
mouse_event->client_pos = mouse_event->local_pos
|
||||||
- toOsg(_region.getMin());
|
- toOsg(_region.getMin());
|
||||||
@@ -544,11 +474,9 @@ namespace canvas
|
|||||||
mouse_event->client_pos.x() *= src_canvas->getViewWidth() / size.x();
|
mouse_event->client_pos.x() *= src_canvas->getViewWidth() / size.x();
|
||||||
mouse_event->client_pos.y() *= src_canvas->getViewHeight()/ size.y();
|
mouse_event->client_pos.y() *= src_canvas->getViewHeight()/ size.y();
|
||||||
mouse_event->local_pos = mouse_event->client_pos;
|
mouse_event->local_pos = mouse_event->client_pos;
|
||||||
|
|
||||||
handled |= src_canvas->handleMouseEvent(mouse_event);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return handled;
|
return handled | src_canvas->handleMouseEvent(mouse_event);
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
@@ -593,34 +521,11 @@ namespace canvas
|
|||||||
|
|
||||||
_attributes_dirty |= DEST_SIZE;
|
_attributes_dirty |= DEST_SIZE;
|
||||||
}
|
}
|
||||||
else if( name == "src" || name == "file" )
|
else if( name == "file" )
|
||||||
{
|
{
|
||||||
if( name == "file" )
|
static const std::string CANVAS_PROTOCOL = "canvas://";
|
||||||
SG_LOG(SG_GL, SG_WARN, "'file' is deprecated. Use 'src' instead");
|
const std::string& path = child->getStringValue();
|
||||||
|
|
||||||
// Abort pending request
|
|
||||||
if( _http_request )
|
|
||||||
{
|
|
||||||
_http_request->abort("setting new image");
|
|
||||||
_http_request.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
static const std::string PROTOCOL_SEP = "://";
|
|
||||||
|
|
||||||
std::string url = child->getStringValue(),
|
|
||||||
protocol, path;
|
|
||||||
|
|
||||||
size_t sep_pos = url.find(PROTOCOL_SEP);
|
|
||||||
if( sep_pos != std::string::npos )
|
|
||||||
{
|
|
||||||
protocol = url.substr(0, sep_pos);
|
|
||||||
path = url.substr(sep_pos + PROTOCOL_SEP.length());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
path = url;
|
|
||||||
|
|
||||||
if( protocol == "canvas" )
|
|
||||||
{
|
|
||||||
CanvasPtr canvas = _canvas.lock();
|
CanvasPtr canvas = _canvas.lock();
|
||||||
if( !canvas )
|
if( !canvas )
|
||||||
{
|
{
|
||||||
@@ -628,6 +533,8 @@ namespace canvas
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if( boost::starts_with(path, CANVAS_PROTOCOL) )
|
||||||
|
{
|
||||||
CanvasMgr* canvas_mgr = canvas->getCanvasMgr();
|
CanvasMgr* canvas_mgr = canvas->getCanvasMgr();
|
||||||
if( !canvas_mgr )
|
if( !canvas_mgr )
|
||||||
{
|
{
|
||||||
@@ -638,7 +545,7 @@ namespace canvas
|
|||||||
const SGPropertyNode* canvas_node =
|
const SGPropertyNode* canvas_node =
|
||||||
canvas_mgr->getPropertyRoot()
|
canvas_mgr->getPropertyRoot()
|
||||||
->getParent()
|
->getParent()
|
||||||
->getNode( path );
|
->getNode( path.substr(CANVAS_PROTOCOL.size()) );
|
||||||
if( !canvas_node )
|
if( !canvas_node )
|
||||||
{
|
{
|
||||||
SG_LOG(SG_GL, SG_ALERT, "canvas::Image: No such canvas: " << path);
|
SG_LOG(SG_GL, SG_ALERT, "canvas::Image: No such canvas: " << path);
|
||||||
@@ -656,16 +563,6 @@ namespace canvas
|
|||||||
|
|
||||||
setSrcCanvas(src_canvas);
|
setSrcCanvas(src_canvas);
|
||||||
}
|
}
|
||||||
else if( protocol == "http" || protocol == "https" )
|
|
||||||
// TODO check https
|
|
||||||
{
|
|
||||||
_http_request =
|
|
||||||
Canvas::getSystemAdapter()
|
|
||||||
->getHTTPClient()
|
|
||||||
->load(url)
|
|
||||||
// TODO handle capture of 'this'
|
|
||||||
->done(this, &Image::handleImageLoadDone);
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
setImage( Canvas::getSystemAdapter()->getImage(path) );
|
setImage( Canvas::getSystemAdapter()->getImage(path) );
|
||||||
@@ -741,65 +638,5 @@ namespace canvas
|
|||||||
(*_texCoords)[i + 3].set(tl.x(), br.y());
|
(*_texCoords)[i + 3].set(tl.x(), br.y());
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
void Image::handleImageLoadDone(HTTP::Request* req)
|
|
||||||
{
|
|
||||||
// Ignore stale/expired requests
|
|
||||||
if( _http_request != req )
|
|
||||||
return;
|
|
||||||
_http_request.reset();
|
|
||||||
|
|
||||||
if( req->responseCode() != 200 )
|
|
||||||
{
|
|
||||||
SG_LOG(SG_IO, SG_WARN, "failed to download '" << req->url() << "': "
|
|
||||||
<< req->responseReason());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::string ext = SGPath(req->path()).extension(),
|
|
||||||
mime = req->responseMime();
|
|
||||||
|
|
||||||
SG_LOG(SG_IO, SG_INFO, "received " << req->url() <<
|
|
||||||
" (ext=" << ext << ", MIME=" << mime << ")");
|
|
||||||
|
|
||||||
const std::string& img_data =
|
|
||||||
static_cast<HTTP::MemoryRequest*>(req)->responseBody();
|
|
||||||
osgDB::Registry* reg = osgDB::Registry::instance();
|
|
||||||
|
|
||||||
// First try to detect image type by extension
|
|
||||||
osgDB::ReaderWriter* rw = reg->getReaderWriterForExtension(ext);
|
|
||||||
if( rw && loadImage(*rw, img_data, *req, "extension") )
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Now try with MIME type
|
|
||||||
rw = reg->getReaderWriterForMimeType(mime);
|
|
||||||
if( rw && loadImage(*rw, img_data, *req, "MIME type") )
|
|
||||||
return;
|
|
||||||
|
|
||||||
SG_LOG(SG_IO, SG_WARN, "unable to read image '" << req->url() << "'");
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
bool Image::loadImage( osgDB::ReaderWriter& reader,
|
|
||||||
const std::string& data,
|
|
||||||
HTTP::Request& request,
|
|
||||||
const std::string& type )
|
|
||||||
{
|
|
||||||
SG_LOG(SG_IO, SG_DEBUG, "use image reader detected by " << type);
|
|
||||||
|
|
||||||
std::istringstream data_strm(data);
|
|
||||||
osgDB::ReaderWriter::ReadResult result = reader.readImage(data_strm);
|
|
||||||
if( result.success() )
|
|
||||||
{
|
|
||||||
setImage( result.takeImage() );
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
SG_LOG(SG_IO, SG_WARN, "failed to read image '" << request.url() << "': "
|
|
||||||
<< result.message());
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace canvas
|
} // namespace canvas
|
||||||
} // namespace simgear
|
} // namespace simgear
|
||||||
|
|||||||
@@ -22,14 +22,11 @@
|
|||||||
#include "CanvasElement.hxx"
|
#include "CanvasElement.hxx"
|
||||||
|
|
||||||
#include <simgear/canvas/canvas_fwd.hxx>
|
#include <simgear/canvas/canvas_fwd.hxx>
|
||||||
#include <simgear/io/HTTPClient.hxx>
|
|
||||||
#include <simgear/misc/CSSBorder.hxx>
|
#include <simgear/misc/CSSBorder.hxx>
|
||||||
#include <simgear/misc/SVGpreserveAspectRatio.hxx>
|
|
||||||
#include <osg/Texture2D>
|
#include <osg/Texture2D>
|
||||||
|
|
||||||
namespace simgear
|
namespace simgear
|
||||||
{
|
{
|
||||||
namespace HTTP { class Request; }
|
|
||||||
namespace canvas
|
namespace canvas
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -62,17 +59,6 @@ namespace canvas
|
|||||||
void setImage(osg::Image *img);
|
void setImage(osg::Image *img);
|
||||||
void setFill(const std::string& fill);
|
void setFill(const std::string& fill);
|
||||||
|
|
||||||
/**
|
|
||||||
* @see http://www.w3.org/TR/css3-background/#border-image-outset
|
|
||||||
*/
|
|
||||||
void setOutset(const std::string& outset);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @see
|
|
||||||
* http://www.w3.org/TR/SVG11/coords.html#PreserveAspectRatioAttribute
|
|
||||||
*/
|
|
||||||
void setPreserveAspectRatio(const std::string& scale);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set image slice (aka. 9-scale)
|
* Set image slice (aka. 9-scale)
|
||||||
*
|
*
|
||||||
@@ -91,9 +77,14 @@ namespace canvas
|
|||||||
*/
|
*/
|
||||||
void setSliceWidth(const std::string& width);
|
void setSliceWidth(const std::string& width);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* http://www.w3.org/TR/css3-background/#border-image-outset
|
||||||
|
*/
|
||||||
|
void setOutset(const std::string& outset);
|
||||||
|
|
||||||
const SGRect<float>& getRegion() const;
|
const SGRect<float>& getRegion() const;
|
||||||
|
|
||||||
bool handleEvent(const EventPtr& event);
|
bool handleEvent(EventPtr event);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
@@ -112,16 +103,9 @@ namespace canvas
|
|||||||
void setQuad(size_t index, const SGVec2f& tl, const SGVec2f& br);
|
void setQuad(size_t index, const SGVec2f& tl, const SGVec2f& br);
|
||||||
void setQuadUV(size_t index, const SGVec2f& tl, const SGVec2f& br);
|
void setQuadUV(size_t index, const SGVec2f& tl, const SGVec2f& br);
|
||||||
|
|
||||||
void handleImageLoadDone(HTTP::Request*);
|
|
||||||
bool loadImage( osgDB::ReaderWriter& reader,
|
|
||||||
const std::string& data,
|
|
||||||
HTTP::Request& request,
|
|
||||||
const std::string& type );
|
|
||||||
|
|
||||||
osg::ref_ptr<osg::Texture2D> _texture;
|
osg::ref_ptr<osg::Texture2D> _texture;
|
||||||
// TODO optionally forward events to canvas
|
// TODO optionally forward events to canvas
|
||||||
CanvasWeakPtr _src_canvas;
|
CanvasWeakPtr _src_canvas;
|
||||||
HTTP::Request_ptr _http_request;
|
|
||||||
|
|
||||||
osg::ref_ptr<osg::Geometry> _geom;
|
osg::ref_ptr<osg::Geometry> _geom;
|
||||||
osg::ref_ptr<osg::DrawArrays>_prim;
|
osg::ref_ptr<osg::DrawArrays>_prim;
|
||||||
@@ -133,11 +117,9 @@ namespace canvas
|
|||||||
SGRect<float> _src_rect,
|
SGRect<float> _src_rect,
|
||||||
_region;
|
_region;
|
||||||
|
|
||||||
SVGpreserveAspectRatio _preserve_aspect_ratio;
|
CSSBorder _slice,
|
||||||
|
_slice_width,
|
||||||
CSSBorder _outset,
|
_outset;
|
||||||
_slice,
|
|
||||||
_slice_width;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace canvas
|
} // namespace canvas
|
||||||
|
|||||||
@@ -217,10 +217,9 @@ namespace canvas
|
|||||||
state->setClientActiveTextureUnit(0);
|
state->setClientActiveTextureUnit(0);
|
||||||
state->disableAllVertexArrays();
|
state->disableAllVertexArrays();
|
||||||
|
|
||||||
bool was_blend_enabled = state->getLastAppliedMode(GL_BLEND);
|
glPushAttrib(~0u); // Don't use GL_ALL_ATTRIB_BITS as on my machine it
|
||||||
bool was_stencil_enabled = state->getLastAppliedMode(GL_STENCIL_TEST);
|
// eg. doesn't include GL_MULTISAMPLE_BIT
|
||||||
osg::StateAttribute const* blend_func =
|
glPushClientAttrib(~0u);
|
||||||
state->getLastAppliedAttribute(osg::StateAttribute::BLENDFUNC);
|
|
||||||
|
|
||||||
// Initialize/Update the paint
|
// Initialize/Update the paint
|
||||||
if( _attributes_dirty & STROKE_COLOR )
|
if( _attributes_dirty & STROKE_COLOR )
|
||||||
@@ -270,11 +269,8 @@ namespace canvas
|
|||||||
if( err != VG_NO_ERROR )
|
if( err != VG_NO_ERROR )
|
||||||
SG_LOG(SG_GL, SG_ALERT, "vgError: " << err);
|
SG_LOG(SG_GL, SG_ALERT, "vgError: " << err);
|
||||||
|
|
||||||
// Restore OpenGL state (TODO check if more is needed or integrate
|
glPopAttrib();
|
||||||
// better with OpenSceneGraph)
|
glPopClientAttrib();
|
||||||
if( was_blend_enabled ) glEnable(GL_BLEND);
|
|
||||||
if( was_stencil_enabled ) glEnable(GL_STENCIL_TEST);
|
|
||||||
if( blend_func ) blend_func->apply(*state);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
osg::BoundingBox getTransformedBounds(const osg::Matrix& mat) const
|
osg::BoundingBox getTransformedBounds(const osg::Matrix& mat) const
|
||||||
@@ -385,11 +381,14 @@ namespace canvas
|
|||||||
// vgPathBounds doesn't take stroke width into account
|
// vgPathBounds doesn't take stroke width into account
|
||||||
float ext = 0.5 * _stroke_width;
|
float ext = 0.5 * _stroke_width;
|
||||||
|
|
||||||
return osg::BoundingBox
|
osg::BoundingBox bb
|
||||||
(
|
(
|
||||||
min[0] - ext, min[1] - ext, -0.1,
|
min[0] - ext, min[1] - ext, -0.1,
|
||||||
min[0] + size[0] + ext, min[1] + size[1] + ext, 0.1
|
min[0] + size[0] + ext, min[1] + size[1] + ext, 0.1
|
||||||
);
|
);
|
||||||
|
_path_element->setBoundingBox(bb);
|
||||||
|
|
||||||
|
return bb;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -464,12 +463,7 @@ namespace canvas
|
|||||||
}
|
}
|
||||||
|
|
||||||
if( _attributes_dirty & BOUNDING_BOX )
|
if( _attributes_dirty & BOUNDING_BOX )
|
||||||
{
|
|
||||||
dirtyBound();
|
dirtyBound();
|
||||||
|
|
||||||
// Recalculate bounding box now (prevent race condition)
|
|
||||||
getBound();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct PathUpdateCallback:
|
struct PathUpdateCallback:
|
||||||
|
|||||||
@@ -40,7 +40,6 @@ namespace canvas
|
|||||||
void setFill(const std::string& fill);
|
void setFill(const std::string& fill);
|
||||||
void setBackgroundColor(const std::string& fill);
|
void setBackgroundColor(const std::string& fill);
|
||||||
|
|
||||||
SGVec2i sizeForWidth(int w) const;
|
|
||||||
osg::Vec2 handleHit(const osg::Vec2f& pos);
|
osg::Vec2 handleHit(const osg::Vec2f& pos);
|
||||||
|
|
||||||
virtual osg::BoundingBox computeBound() const;
|
virtual osg::BoundingBox computeBound() const;
|
||||||
@@ -96,281 +95,6 @@ namespace canvas
|
|||||||
setBoundingBoxColor( color );
|
setBoundingBoxColor( color );
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
// simplified version of osgText::Text::computeGlyphRepresentation() to
|
|
||||||
// just calculate the size for a given weight. Glpyh calculations/creating
|
|
||||||
// is not necessary for this...
|
|
||||||
SGVec2i Text::TextOSG::sizeForWidth(int w) const
|
|
||||||
{
|
|
||||||
if( _text.empty() )
|
|
||||||
return SGVec2i(0, 0);
|
|
||||||
|
|
||||||
osgText::Font* activefont = const_cast<osgText::Font*>(getActiveFont());
|
|
||||||
if( !activefont )
|
|
||||||
return SGVec2i(-1, -1);
|
|
||||||
|
|
||||||
float max_width_safe = _maximumWidth;
|
|
||||||
const_cast<TextOSG*>(this)->_maximumWidth = w;
|
|
||||||
|
|
||||||
SGRecti bb;
|
|
||||||
|
|
||||||
osg::Vec2 startOfLine_coords(0.0f,0.0f);
|
|
||||||
osg::Vec2 cursor(startOfLine_coords);
|
|
||||||
osg::Vec2 local(0.0f,0.0f);
|
|
||||||
|
|
||||||
unsigned int previous_charcode = 0;
|
|
||||||
unsigned int line_length = 0;
|
|
||||||
bool horizontal = _layout != VERTICAL;
|
|
||||||
bool kerning = true;
|
|
||||||
|
|
||||||
float hr = _characterHeight;
|
|
||||||
float wr = hr / getCharacterAspectRatio();
|
|
||||||
|
|
||||||
// osg should really care more about const :-/
|
|
||||||
osgText::String& text = const_cast<osgText::String&>(_text);
|
|
||||||
typedef osgText::String::iterator TextIterator;
|
|
||||||
|
|
||||||
for( TextIterator itr = text.begin(); itr != text.end(); )
|
|
||||||
{
|
|
||||||
// record the start of the current line
|
|
||||||
TextIterator startOfLine_itr = itr;
|
|
||||||
|
|
||||||
// find the end of the current line.
|
|
||||||
osg::Vec2 endOfLine_coords(cursor);
|
|
||||||
TextIterator endOfLine_itr =
|
|
||||||
const_cast<TextOSG*>(this)->computeLastCharacterOnLine(
|
|
||||||
endOfLine_coords, itr, text.end()
|
|
||||||
);
|
|
||||||
|
|
||||||
line_length = endOfLine_itr - startOfLine_itr;
|
|
||||||
|
|
||||||
// Set line position to correct alignment.
|
|
||||||
switch( _layout )
|
|
||||||
{
|
|
||||||
case LEFT_TO_RIGHT:
|
|
||||||
{
|
|
||||||
switch( _alignment )
|
|
||||||
{
|
|
||||||
// nothing to be done for these
|
|
||||||
//case LEFT_TOP:
|
|
||||||
//case LEFT_CENTER:
|
|
||||||
//case LEFT_BOTTOM:
|
|
||||||
//case LEFT_BASE_LINE:
|
|
||||||
//case LEFT_BOTTOM_BASE_LINE:
|
|
||||||
// break;
|
|
||||||
case CENTER_TOP:
|
|
||||||
case CENTER_CENTER:
|
|
||||||
case CENTER_BOTTOM:
|
|
||||||
case CENTER_BASE_LINE:
|
|
||||||
case CENTER_BOTTOM_BASE_LINE:
|
|
||||||
cursor.x() = (cursor.x() - endOfLine_coords.x()) * 0.5f;
|
|
||||||
break;
|
|
||||||
case RIGHT_TOP:
|
|
||||||
case RIGHT_CENTER:
|
|
||||||
case RIGHT_BOTTOM:
|
|
||||||
case RIGHT_BASE_LINE:
|
|
||||||
case RIGHT_BOTTOM_BASE_LINE:
|
|
||||||
cursor.x() = cursor.x() - endOfLine_coords.x();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case RIGHT_TO_LEFT:
|
|
||||||
{
|
|
||||||
switch( _alignment )
|
|
||||||
{
|
|
||||||
case LEFT_TOP:
|
|
||||||
case LEFT_CENTER:
|
|
||||||
case LEFT_BOTTOM:
|
|
||||||
case LEFT_BASE_LINE:
|
|
||||||
case LEFT_BOTTOM_BASE_LINE:
|
|
||||||
cursor.x() = 2 * cursor.x() - endOfLine_coords.x();
|
|
||||||
break;
|
|
||||||
case CENTER_TOP:
|
|
||||||
case CENTER_CENTER:
|
|
||||||
case CENTER_BOTTOM:
|
|
||||||
case CENTER_BASE_LINE:
|
|
||||||
case CENTER_BOTTOM_BASE_LINE:
|
|
||||||
cursor.x() = cursor.x()
|
|
||||||
+ (cursor.x() - endOfLine_coords.x()) * 0.5f;
|
|
||||||
break;
|
|
||||||
// nothing to be done for these
|
|
||||||
//case RIGHT_TOP:
|
|
||||||
//case RIGHT_CENTER:
|
|
||||||
//case RIGHT_BOTTOM:
|
|
||||||
//case RIGHT_BASE_LINE:
|
|
||||||
//case RIGHT_BOTTOM_BASE_LINE:
|
|
||||||
// break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case VERTICAL:
|
|
||||||
{
|
|
||||||
switch( _alignment )
|
|
||||||
{
|
|
||||||
// TODO: current behaviour top baselines lined up in both cases - need to implement
|
|
||||||
// top of characters alignment - Question is this necessary?
|
|
||||||
// ... otherwise, nothing to be done for these 6 cases
|
|
||||||
//case LEFT_TOP:
|
|
||||||
//case CENTER_TOP:
|
|
||||||
//case RIGHT_TOP:
|
|
||||||
// break;
|
|
||||||
//case LEFT_BASE_LINE:
|
|
||||||
//case CENTER_BASE_LINE:
|
|
||||||
//case RIGHT_BASE_LINE:
|
|
||||||
// break;
|
|
||||||
case LEFT_CENTER:
|
|
||||||
case CENTER_CENTER:
|
|
||||||
case RIGHT_CENTER:
|
|
||||||
cursor.y() = cursor.y()
|
|
||||||
+ (cursor.y() - endOfLine_coords.y()) * 0.5f;
|
|
||||||
break;
|
|
||||||
case LEFT_BOTTOM_BASE_LINE:
|
|
||||||
case CENTER_BOTTOM_BASE_LINE:
|
|
||||||
case RIGHT_BOTTOM_BASE_LINE:
|
|
||||||
cursor.y() = cursor.y() - (line_length * _characterHeight);
|
|
||||||
break;
|
|
||||||
case LEFT_BOTTOM:
|
|
||||||
case CENTER_BOTTOM:
|
|
||||||
case RIGHT_BOTTOM:
|
|
||||||
cursor.y() = 2 * cursor.y() - endOfLine_coords.y();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if( itr != endOfLine_itr )
|
|
||||||
{
|
|
||||||
|
|
||||||
for(;itr != endOfLine_itr;++itr)
|
|
||||||
{
|
|
||||||
unsigned int charcode = *itr;
|
|
||||||
|
|
||||||
osgText::Glyph* glyph = activefont->getGlyph(_fontSize, charcode);
|
|
||||||
if( glyph )
|
|
||||||
{
|
|
||||||
float width = (float) (glyph->getWidth()) * wr;
|
|
||||||
float height = (float) (glyph->getHeight()) * hr;
|
|
||||||
|
|
||||||
if( _layout == RIGHT_TO_LEFT )
|
|
||||||
{
|
|
||||||
cursor.x() -= glyph->getHorizontalAdvance() * wr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// adjust cursor position w.r.t any kerning.
|
|
||||||
if( kerning && previous_charcode )
|
|
||||||
{
|
|
||||||
switch( _layout )
|
|
||||||
{
|
|
||||||
case LEFT_TO_RIGHT:
|
|
||||||
{
|
|
||||||
osg::Vec2 delta( activefont->getKerning( previous_charcode,
|
|
||||||
charcode,
|
|
||||||
_kerningType ) );
|
|
||||||
cursor.x() += delta.x() * wr;
|
|
||||||
cursor.y() += delta.y() * hr;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case RIGHT_TO_LEFT:
|
|
||||||
{
|
|
||||||
osg::Vec2 delta( activefont->getKerning( charcode,
|
|
||||||
previous_charcode,
|
|
||||||
_kerningType ) );
|
|
||||||
cursor.x() -= delta.x() * wr;
|
|
||||||
cursor.y() -= delta.y() * hr;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case VERTICAL:
|
|
||||||
break; // no kerning when vertical.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
local = cursor;
|
|
||||||
osg::Vec2 bearing( horizontal ? glyph->getHorizontalBearing()
|
|
||||||
: glyph->getVerticalBearing() );
|
|
||||||
local.x() += bearing.x() * wr;
|
|
||||||
local.y() += bearing.y() * hr;
|
|
||||||
|
|
||||||
// set up the coords of the quad
|
|
||||||
osg::Vec2 upLeft = local + osg::Vec2(0.f, height);
|
|
||||||
osg::Vec2 lowLeft = local;
|
|
||||||
osg::Vec2 lowRight = local + osg::Vec2(width, 0.f);
|
|
||||||
osg::Vec2 upRight = local + osg::Vec2(width, height);
|
|
||||||
|
|
||||||
// move the cursor onto the next character.
|
|
||||||
// also expand bounding box
|
|
||||||
switch( _layout )
|
|
||||||
{
|
|
||||||
case LEFT_TO_RIGHT:
|
|
||||||
cursor.x() += glyph->getHorizontalAdvance() * wr;
|
|
||||||
bb.expandBy(lowLeft.x(), lowLeft.y());
|
|
||||||
bb.expandBy(upRight.x(), upRight.y());
|
|
||||||
break;
|
|
||||||
case VERTICAL:
|
|
||||||
cursor.y() -= glyph->getVerticalAdvance() * hr;
|
|
||||||
bb.expandBy(upLeft.x(), upLeft.y());
|
|
||||||
bb.expandBy(lowRight.x(), lowRight.y());
|
|
||||||
break;
|
|
||||||
case RIGHT_TO_LEFT:
|
|
||||||
bb.expandBy(lowRight.x(), lowRight.y());
|
|
||||||
bb.expandBy(upLeft.x(), upLeft.y());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
previous_charcode = charcode;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// skip over spaces and return.
|
|
||||||
while( itr != text.end() && *itr == ' ' )
|
|
||||||
++itr;
|
|
||||||
if( itr != text.end() && *itr == '\n' )
|
|
||||||
++itr;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
++itr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// move to new line.
|
|
||||||
switch( _layout )
|
|
||||||
{
|
|
||||||
case LEFT_TO_RIGHT:
|
|
||||||
{
|
|
||||||
startOfLine_coords.y() -= _characterHeight * (1.0 + _lineSpacing);
|
|
||||||
cursor = startOfLine_coords;
|
|
||||||
previous_charcode = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case RIGHT_TO_LEFT:
|
|
||||||
{
|
|
||||||
startOfLine_coords.y() -= _characterHeight * (1.0 + _lineSpacing);
|
|
||||||
cursor = startOfLine_coords;
|
|
||||||
previous_charcode = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case VERTICAL:
|
|
||||||
{
|
|
||||||
startOfLine_coords.x() += _characterHeight * (1.0 + _lineSpacing)
|
|
||||||
/ getCharacterAspectRatio();
|
|
||||||
cursor = startOfLine_coords;
|
|
||||||
previous_charcode = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const_cast<TextOSG*>(this)->_maximumWidth = max_width_safe;
|
|
||||||
|
|
||||||
return bb.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
osg::Vec2 Text::TextOSG::handleHit(const osg::Vec2f& pos)
|
osg::Vec2 Text::TextOSG::handleHit(const osg::Vec2f& pos)
|
||||||
{
|
{
|
||||||
@@ -455,17 +179,18 @@ namespace canvas
|
|||||||
osg::BoundingBox Text::TextOSG::computeBound() const
|
osg::BoundingBox Text::TextOSG::computeBound() const
|
||||||
{
|
{
|
||||||
osg::BoundingBox bb = osgText::Text::computeBound();
|
osg::BoundingBox bb = osgText::Text::computeBound();
|
||||||
|
if( !bb.valid() )
|
||||||
|
return bb;
|
||||||
|
|
||||||
#if OSG_VERSION_LESS_THAN(3,1,0)
|
#if OSG_VERSION_LESS_THAN(3,1,0)
|
||||||
if( bb.valid() )
|
|
||||||
{
|
|
||||||
// TODO bounding box still doesn't seem always right (eg. with center
|
// TODO bounding box still doesn't seem always right (eg. with center
|
||||||
// horizontal alignment not completely accurate)
|
// horizontal alignment not completely accurate)
|
||||||
bb._min.y() += _offset.y();
|
bb._min.y() += _offset.y();
|
||||||
bb._max.y() += _offset.y();
|
bb._max.y() += _offset.y();
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
_text_element->setBoundingBox(bb);
|
||||||
|
|
||||||
return bb;
|
return bb;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -645,18 +370,6 @@ namespace canvas
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
int Text::heightForWidth(int w) const
|
|
||||||
{
|
|
||||||
return _text->sizeForWidth(w).y();
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
int Text::maxWidth() const
|
|
||||||
{
|
|
||||||
return _text->sizeForWidth(INT_MAX).x();
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
osg::Vec2 Text::getNearestCursor(const osg::Vec2& pos) const
|
osg::Vec2 Text::getNearestCursor(const osg::Vec2& pos) const
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -46,8 +46,6 @@ namespace canvas
|
|||||||
void setFont(const char* name);
|
void setFont(const char* name);
|
||||||
void setAlignment(const char* align);
|
void setAlignment(const char* align);
|
||||||
|
|
||||||
int heightForWidth(int w) const;
|
|
||||||
int maxWidth() const;
|
|
||||||
osg::Vec2 getNearestCursor(const osg::Vec2& pos) const;
|
osg::Vec2 getNearestCursor(const osg::Vec2& pos) const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|||||||
@@ -1,66 +0,0 @@
|
|||||||
/// Unit tests for canvas::Element
|
|
||||||
#define BOOST_TEST_MODULE canvas
|
|
||||||
#include <BoostTestTargetConfig.h>
|
|
||||||
|
|
||||||
#include "CanvasElement.hxx"
|
|
||||||
#include "CanvasGroup.hxx"
|
|
||||||
|
|
||||||
namespace sc = simgear::canvas;
|
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE( attr_data )
|
|
||||||
{
|
|
||||||
// http://www.w3.org/TR/html5/dom.html#attr-data-*
|
|
||||||
|
|
||||||
#define SG_CHECK_ATTR2PROP(attr, prop)\
|
|
||||||
BOOST_CHECK_EQUAL(sc::Element::attrToDataPropName(attr), prop)
|
|
||||||
|
|
||||||
// If name starts with "data-", for each "-" (U+002D) character in the name
|
|
||||||
// that is followed by a lowercase ASCII letter, remove the "-" (U+002D)
|
|
||||||
// character and replace the character that followed it by the same character
|
|
||||||
// converted to ASCII uppercase.
|
|
||||||
|
|
||||||
SG_CHECK_ATTR2PROP("no-data", "");
|
|
||||||
SG_CHECK_ATTR2PROP("data-blub", "blub");
|
|
||||||
SG_CHECK_ATTR2PROP("data-blub-x-y", "blubXY");
|
|
||||||
SG_CHECK_ATTR2PROP("data-blub-x-y-", "blubXY-");
|
|
||||||
|
|
||||||
#undef SG_CHECK_ATTR2PROP
|
|
||||||
|
|
||||||
#define SG_CHECK_PROP2ATTR(prop, attr)\
|
|
||||||
BOOST_CHECK_EQUAL(sc::Element::dataPropToAttrName(prop), attr)
|
|
||||||
|
|
||||||
// If name contains a "-" (U+002D) character followed by a lowercase ASCII
|
|
||||||
// letter, throw a SyntaxError exception (empty string) and abort these steps.
|
|
||||||
// For each uppercase ASCII letter in name, insert a "-" (U+002D) character
|
|
||||||
// before the character and replace the character with the same character
|
|
||||||
// converted to ASCII lowercase.
|
|
||||||
// Insert the string "data-" at the front of name.
|
|
||||||
|
|
||||||
SG_CHECK_PROP2ATTR("test", "data-test");
|
|
||||||
SG_CHECK_PROP2ATTR("testIt", "data-test-it");
|
|
||||||
SG_CHECK_PROP2ATTR("testIt-Hyphen", "data-test-it--hyphen");
|
|
||||||
SG_CHECK_PROP2ATTR("-test", "");
|
|
||||||
SG_CHECK_PROP2ATTR("test-", "data-test-");
|
|
||||||
|
|
||||||
#undef SG_CHECK_PROP2ATTR
|
|
||||||
|
|
||||||
SGPropertyNode_ptr node = new SGPropertyNode;
|
|
||||||
sc::ElementPtr el =
|
|
||||||
sc::Element::create<sc::Group>(sc::CanvasWeakPtr(), node);
|
|
||||||
|
|
||||||
el->setDataProp("myData", 3);
|
|
||||||
BOOST_CHECK_EQUAL( el->getDataProp<int>("myData"), 3 );
|
|
||||||
BOOST_CHECK_EQUAL( node->getIntValue("data-my-data"), 3 );
|
|
||||||
|
|
||||||
SGPropertyNode* prop = el->getDataProp<SGPropertyNode*>("notExistingProp");
|
|
||||||
BOOST_CHECK( !prop );
|
|
||||||
prop = el->getDataProp<SGPropertyNode*>("myData");
|
|
||||||
BOOST_CHECK( prop );
|
|
||||||
BOOST_CHECK_EQUAL( prop->getParent(), node );
|
|
||||||
BOOST_CHECK_EQUAL( prop->getIntValue(), 3 );
|
|
||||||
|
|
||||||
BOOST_CHECK( el->hasDataProp("myData") );
|
|
||||||
el->removeDataProp("myData");
|
|
||||||
BOOST_CHECK( !el->hasDataProp("myData") );
|
|
||||||
BOOST_CHECK_EQUAL( el->getDataProp("myData", 5), 5 );
|
|
||||||
}
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
include (SimGearComponent)
|
|
||||||
|
|
||||||
set(HEADERS
|
|
||||||
CustomEvent.hxx
|
|
||||||
MouseEvent.hxx
|
|
||||||
)
|
|
||||||
|
|
||||||
set(SOURCES
|
|
||||||
CustomEvent.cxx
|
|
||||||
MouseEvent.cxx
|
|
||||||
)
|
|
||||||
|
|
||||||
simgear_scene_component(canvas-events canvas/events "${SOURCES}" "${HEADERS}")
|
|
||||||
|
|
||||||
add_boost_test(canvas_event
|
|
||||||
SOURCES event_test.cpp
|
|
||||||
LIBRARIES ${TEST_LIBS}
|
|
||||||
)
|
|
||||||
@@ -1,73 +0,0 @@
|
|||||||
///@file Canvas user defined event
|
|
||||||
//
|
|
||||||
// Copyright (C) 2014 Thomas Geymayer <tomgey@gmail.com>
|
|
||||||
//
|
|
||||||
// This library is free software; you can redistribute it and/or
|
|
||||||
// modify it under the terms of the GNU Library General Public
|
|
||||||
// License as published by the Free Software Foundation; either
|
|
||||||
// version 2 of the License, or (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
// Library General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Library General Public
|
|
||||||
// License along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
|
||||||
|
|
||||||
#ifndef CANVAS_CUSTOM_EVENT_HXX_
|
|
||||||
#define CANVAS_CUSTOM_EVENT_HXX_
|
|
||||||
|
|
||||||
#include <simgear/canvas/CanvasEvent.hxx>
|
|
||||||
#include <simgear/structure/map.hxx>
|
|
||||||
|
|
||||||
namespace simgear
|
|
||||||
{
|
|
||||||
namespace canvas
|
|
||||||
{
|
|
||||||
|
|
||||||
class CustomEvent:
|
|
||||||
public Event
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param type_str Event type name (if name does not exist yet it will
|
|
||||||
* be registered as new event type)
|
|
||||||
* @param data Optional user data stored in event
|
|
||||||
*/
|
|
||||||
CustomEvent( std::string const& type_str,
|
|
||||||
bool bubbles = false,
|
|
||||||
StringMap const& data = StringMap() );
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param type_id Event type id
|
|
||||||
* @param data Optional user data stored in event
|
|
||||||
*/
|
|
||||||
CustomEvent( int type_id,
|
|
||||||
bool bubbles = false,
|
|
||||||
StringMap const& data = StringMap() );
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set user data
|
|
||||||
*/
|
|
||||||
void setDetail(StringMap const& data);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get user data
|
|
||||||
*/
|
|
||||||
StringMap const& getDetail() const { return detail; }
|
|
||||||
|
|
||||||
virtual bool canBubble() const { return bubbles; }
|
|
||||||
|
|
||||||
StringMap detail; //<! user data map
|
|
||||||
bool bubbles;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace canvas
|
|
||||||
} // namespace simgear
|
|
||||||
|
|
||||||
#endif /* CANVAS_CUSTOM_EVENT_HXX_ */
|
|
||||||
@@ -1,70 +0,0 @@
|
|||||||
// Mouse event
|
|
||||||
//
|
|
||||||
// Copyright (C) 2014 Thomas Geymayer <tomgey@gmail.com>
|
|
||||||
//
|
|
||||||
// This library is free software; you can redistribute it and/or
|
|
||||||
// modify it under the terms of the GNU Library General Public
|
|
||||||
// License as published by the Free Software Foundation; either
|
|
||||||
// version 2 of the License, or (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
// Library General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Library General Public
|
|
||||||
// License along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
|
||||||
|
|
||||||
#include "MouseEvent.hxx"
|
|
||||||
|
|
||||||
namespace simgear
|
|
||||||
{
|
|
||||||
namespace canvas
|
|
||||||
{
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
MouseEvent::MouseEvent():
|
|
||||||
button(0),
|
|
||||||
buttons(0),
|
|
||||||
modifiers(0),
|
|
||||||
click_count(0)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
MouseEvent::MouseEvent(const osgGA::GUIEventAdapter& ea):
|
|
||||||
button(0),
|
|
||||||
buttons(ea.getButtonMask()),
|
|
||||||
modifiers(ea.getModKeyMask()),
|
|
||||||
click_count(0)
|
|
||||||
{
|
|
||||||
time = ea.getTime();
|
|
||||||
|
|
||||||
// Convert button mask to index
|
|
||||||
int button_mask = ea.getButton();
|
|
||||||
while( (button_mask >>= 1) > 0 )
|
|
||||||
button += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
bool MouseEvent::canBubble() const
|
|
||||||
{
|
|
||||||
// Check if event supports bubbling
|
|
||||||
const Event::Type types_no_bubbling[] = {
|
|
||||||
Event::MOUSE_ENTER,
|
|
||||||
Event::MOUSE_LEAVE,
|
|
||||||
};
|
|
||||||
const size_t num_types_no_bubbling = sizeof(types_no_bubbling)
|
|
||||||
/ sizeof(types_no_bubbling[0]);
|
|
||||||
|
|
||||||
for( size_t i = 0; i < num_types_no_bubbling; ++i )
|
|
||||||
if( type == types_no_bubbling[i] )
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace canvas
|
|
||||||
} // namespace simgear
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
/// Unit tests for reference counting and smart pointer classes
|
|
||||||
#define BOOST_TEST_MODULE structure
|
|
||||||
#include <BoostTestTargetConfig.h>
|
|
||||||
|
|
||||||
#include "MouseEvent.hxx"
|
|
||||||
#include "CustomEvent.hxx"
|
|
||||||
|
|
||||||
namespace sc = simgear::canvas;
|
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE( canvas_event_types )
|
|
||||||
{
|
|
||||||
// Register type
|
|
||||||
BOOST_REQUIRE_EQUAL( sc::Event::strToType("test"),
|
|
||||||
sc::Event::UNKNOWN );
|
|
||||||
BOOST_REQUIRE_EQUAL( sc::Event::getOrRegisterType("test"),
|
|
||||||
sc::Event::CUSTOM_EVENT );
|
|
||||||
BOOST_REQUIRE_EQUAL( sc::Event::strToType("test"),
|
|
||||||
sc::Event::CUSTOM_EVENT );
|
|
||||||
BOOST_REQUIRE_EQUAL( sc::Event::typeToStr(sc::Event::CUSTOM_EVENT),
|
|
||||||
"test" );
|
|
||||||
|
|
||||||
// Basic internal type
|
|
||||||
BOOST_REQUIRE_EQUAL( sc::Event::typeToStr(sc::Event::MOUSE_DOWN),
|
|
||||||
"mousedown" );
|
|
||||||
BOOST_REQUIRE_EQUAL( sc::Event::strToType("mousedown"),
|
|
||||||
sc::Event::MOUSE_DOWN );
|
|
||||||
|
|
||||||
// Unknown type
|
|
||||||
BOOST_REQUIRE_EQUAL( sc::Event::typeToStr(123),
|
|
||||||
"unknown" );
|
|
||||||
|
|
||||||
// Register type through custom event instance
|
|
||||||
sc::CustomEvent e("blub");
|
|
||||||
BOOST_REQUIRE_EQUAL( e.getTypeString(), "blub" );
|
|
||||||
BOOST_REQUIRE_NE( e.getType(), sc::Event::UNKNOWN );
|
|
||||||
}
|
|
||||||
@@ -1,488 +0,0 @@
|
|||||||
// Align items horizontally or vertically in a box
|
|
||||||
//
|
|
||||||
// Copyright (C) 2014 Thomas Geymayer <tomgey@gmail.com>
|
|
||||||
//
|
|
||||||
// This library is free software; you can redistribute it and/or
|
|
||||||
// modify it under the terms of the GNU Library General Public
|
|
||||||
// License as published by the Free Software Foundation; either
|
|
||||||
// version 2 of the License, or (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
// Library General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Library General Public
|
|
||||||
// License along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
|
||||||
|
|
||||||
#include "BoxLayout.hxx"
|
|
||||||
#include "SpacerItem.hxx"
|
|
||||||
#include <simgear/canvas/Canvas.hxx>
|
|
||||||
|
|
||||||
namespace simgear
|
|
||||||
{
|
|
||||||
namespace canvas
|
|
||||||
{
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
BoxLayout::BoxLayout(Direction dir):
|
|
||||||
_padding(5)
|
|
||||||
{
|
|
||||||
setDirection(dir);
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
BoxLayout::~BoxLayout()
|
|
||||||
{
|
|
||||||
_parent.reset(); // No need to invalidate parent again...
|
|
||||||
clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
void BoxLayout::addItem(const LayoutItemRef& item)
|
|
||||||
{
|
|
||||||
return addItem(item, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
void BoxLayout::addItem(const LayoutItemRef& item, int stretch)
|
|
||||||
{
|
|
||||||
insertItem(-1, item, stretch);
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
void BoxLayout::addStretch(int stretch)
|
|
||||||
{
|
|
||||||
insertStretch(-1, stretch);
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
void BoxLayout::addSpacing(int size)
|
|
||||||
{
|
|
||||||
insertSpacing(-1, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
void BoxLayout::insertItem(int index, const LayoutItemRef& item, int stretch)
|
|
||||||
{
|
|
||||||
ItemData item_data = {0};
|
|
||||||
item_data.layout_item = item;
|
|
||||||
item_data.stretch = std::max(0, stretch);
|
|
||||||
|
|
||||||
item->setCanvas(_canvas);
|
|
||||||
item->setParent(this);
|
|
||||||
|
|
||||||
if( index < 0 )
|
|
||||||
_layout_items.push_back(item_data);
|
|
||||||
else
|
|
||||||
_layout_items.insert(_layout_items.begin() + index, item_data);
|
|
||||||
|
|
||||||
invalidate();
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
void BoxLayout::insertStretch(int index, int stretch)
|
|
||||||
{
|
|
||||||
insertItem(index, LayoutItemRef(new SpacerItem()), stretch);
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
void BoxLayout::insertSpacing(int index, int size)
|
|
||||||
{
|
|
||||||
SGVec2i size_hint = horiz()
|
|
||||||
? SGVec2i(size, 0)
|
|
||||||
: SGVec2i(0, size),
|
|
||||||
max_size = size_hint;
|
|
||||||
|
|
||||||
insertItem(index, LayoutItemRef(new SpacerItem(size_hint, max_size)));
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
size_t BoxLayout::count() const
|
|
||||||
{
|
|
||||||
return _layout_items.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
LayoutItemRef BoxLayout::itemAt(size_t index)
|
|
||||||
{
|
|
||||||
if( index >= _layout_items.size() )
|
|
||||||
return LayoutItemRef();
|
|
||||||
|
|
||||||
return _layout_items[index].layout_item;
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
LayoutItemRef BoxLayout::takeAt(size_t index)
|
|
||||||
{
|
|
||||||
if( index >= _layout_items.size() )
|
|
||||||
return LayoutItemRef();
|
|
||||||
|
|
||||||
LayoutItems::iterator it = _layout_items.begin() + index;
|
|
||||||
LayoutItemRef item = it->layout_item;
|
|
||||||
item->onRemove();
|
|
||||||
_layout_items.erase(it);
|
|
||||||
|
|
||||||
invalidate();
|
|
||||||
|
|
||||||
return item;
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
void BoxLayout::clear()
|
|
||||||
{
|
|
||||||
for( LayoutItems::iterator it = _layout_items.begin();
|
|
||||||
it != _layout_items.end();
|
|
||||||
++it )
|
|
||||||
{
|
|
||||||
it->layout_item->onRemove();
|
|
||||||
}
|
|
||||||
_layout_items.clear();
|
|
||||||
invalidate();
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
void BoxLayout::setStretch(size_t index, int stretch)
|
|
||||||
{
|
|
||||||
if( index >= _layout_items.size() )
|
|
||||||
return;
|
|
||||||
|
|
||||||
_layout_items.at(index).stretch = std::max(0, stretch);
|
|
||||||
invalidate();
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
bool BoxLayout::setStretchFactor(const LayoutItemRef& item, int stretch)
|
|
||||||
{
|
|
||||||
for( LayoutItems::iterator it = _layout_items.begin();
|
|
||||||
it != _layout_items.end();
|
|
||||||
++it )
|
|
||||||
{
|
|
||||||
if( item == it->layout_item )
|
|
||||||
{
|
|
||||||
it->stretch = std::max(0, stretch);
|
|
||||||
invalidate();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
int BoxLayout::stretch(size_t index) const
|
|
||||||
{
|
|
||||||
if( index >= _layout_items.size() )
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return _layout_items.at(index).stretch;
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
void BoxLayout::setSpacing(int spacing)
|
|
||||||
{
|
|
||||||
if( spacing == _padding )
|
|
||||||
return;
|
|
||||||
|
|
||||||
_padding = spacing;
|
|
||||||
invalidate();
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
int BoxLayout::spacing() const
|
|
||||||
{
|
|
||||||
return _padding;
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
void BoxLayout::setDirection(Direction dir)
|
|
||||||
{
|
|
||||||
_direction = dir;
|
|
||||||
_get_layout_coord = &SGVec2i::x;
|
|
||||||
_get_fixed_coord = &SGVec2i::y;
|
|
||||||
|
|
||||||
if( !horiz() )
|
|
||||||
std::swap(_get_layout_coord, _get_fixed_coord);
|
|
||||||
|
|
||||||
invalidate();
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
BoxLayout::Direction BoxLayout::direction() const
|
|
||||||
{
|
|
||||||
return _direction;
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
bool BoxLayout::hasHeightForWidth() const
|
|
||||||
{
|
|
||||||
if( _flags & SIZE_INFO_DIRTY )
|
|
||||||
updateSizeHints();
|
|
||||||
|
|
||||||
return _layout_data.has_hfw;
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
int BoxLayout::heightForWidth(int w) const
|
|
||||||
{
|
|
||||||
if( !hasHeightForWidth() )
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
updateWFHCache(w);
|
|
||||||
return _hfw_height;
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
int BoxLayout::minimumHeightForWidth(int w) const
|
|
||||||
{
|
|
||||||
if( !hasHeightForWidth() )
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
updateWFHCache(w);
|
|
||||||
return _hfw_min_height;
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
void BoxLayout::setCanvas(const CanvasWeakPtr& canvas)
|
|
||||||
{
|
|
||||||
_canvas = canvas;
|
|
||||||
|
|
||||||
for(size_t i = 0; i < _layout_items.size(); ++i)
|
|
||||||
_layout_items[i].layout_item->setCanvas(canvas);
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
bool BoxLayout::horiz() const
|
|
||||||
{
|
|
||||||
return (_direction == LeftToRight) || (_direction == RightToLeft);
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
void BoxLayout::updateSizeHints() const
|
|
||||||
{
|
|
||||||
SGVec2i min_size(0, 0),
|
|
||||||
max_size(0, 0),
|
|
||||||
size_hint(0, 0);
|
|
||||||
|
|
||||||
_layout_data.reset();
|
|
||||||
_hfw_width = _hfw_height = _hfw_min_height = -1;
|
|
||||||
|
|
||||||
bool is_first = true;
|
|
||||||
|
|
||||||
for(size_t i = 0; i < _layout_items.size(); ++i)
|
|
||||||
{
|
|
||||||
// TODO check visible
|
|
||||||
|
|
||||||
ItemData& item_data = _layout_items[i];
|
|
||||||
LayoutItem const& item = *item_data.layout_item;
|
|
||||||
|
|
||||||
item_data.min_size = (item.minimumSize().*_get_layout_coord)();
|
|
||||||
item_data.max_size = (item.maximumSize().*_get_layout_coord)();
|
|
||||||
item_data.size_hint = (item.sizeHint().*_get_layout_coord)();
|
|
||||||
item_data.has_hfw = item.hasHeightForWidth();
|
|
||||||
|
|
||||||
if( !dynamic_cast<SpacerItem*>(item_data.layout_item.get()) )
|
|
||||||
{
|
|
||||||
if( is_first )
|
|
||||||
{
|
|
||||||
item_data.padding_orig = 0;
|
|
||||||
is_first = false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
item_data.padding_orig = _padding;
|
|
||||||
_layout_data.padding += item_data.padding_orig;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add sizes of all children in layout direction
|
|
||||||
safeAdd(min_size.x(), item_data.min_size);
|
|
||||||
safeAdd(max_size.x(), item_data.max_size);
|
|
||||||
safeAdd(size_hint.x(), item_data.size_hint);
|
|
||||||
|
|
||||||
// Take maximum in fixed (non-layouted) direction
|
|
||||||
min_size.y() = std::max( min_size.y(),
|
|
||||||
(item.minimumSize().*_get_fixed_coord)() );
|
|
||||||
max_size.y() = std::max( max_size.y(),
|
|
||||||
(item.maximumSize().*_get_fixed_coord)() );
|
|
||||||
size_hint.y() = std::max( size_hint.y(),
|
|
||||||
(item.sizeHint().*_get_fixed_coord)() );
|
|
||||||
|
|
||||||
_layout_data.has_hfw = _layout_data.has_hfw || item.hasHeightForWidth();
|
|
||||||
}
|
|
||||||
|
|
||||||
safeAdd(min_size.x(), _layout_data.padding);
|
|
||||||
safeAdd(max_size.x(), _layout_data.padding);
|
|
||||||
safeAdd(size_hint.x(), _layout_data.padding);
|
|
||||||
|
|
||||||
_layout_data.min_size = min_size.x();
|
|
||||||
_layout_data.max_size = max_size.x();
|
|
||||||
_layout_data.size_hint = size_hint.x();
|
|
||||||
|
|
||||||
_min_size.x() = (min_size.*_get_layout_coord)();
|
|
||||||
_max_size.x() = (max_size.*_get_layout_coord)();
|
|
||||||
_size_hint.x() = (size_hint.*_get_layout_coord)();
|
|
||||||
|
|
||||||
_min_size.y() = (min_size.*_get_fixed_coord)();
|
|
||||||
_max_size.y() = (max_size.*_get_fixed_coord)();
|
|
||||||
_size_hint.y() = (size_hint.*_get_fixed_coord)();
|
|
||||||
|
|
||||||
_flags &= ~SIZE_INFO_DIRTY;
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
void BoxLayout::updateWFHCache(int w) const
|
|
||||||
{
|
|
||||||
if( w == _hfw_width )
|
|
||||||
return;
|
|
||||||
|
|
||||||
_hfw_height = 0;
|
|
||||||
_hfw_min_height = 0;
|
|
||||||
|
|
||||||
if( horiz() )
|
|
||||||
{
|
|
||||||
_layout_data.size = w;
|
|
||||||
const_cast<BoxLayout*>(this)->distribute(_layout_items, _layout_data);
|
|
||||||
|
|
||||||
for(size_t i = 0; i < _layout_items.size(); ++i)
|
|
||||||
{
|
|
||||||
ItemData const& data = _layout_items[i];
|
|
||||||
_hfw_height = std::max(_hfw_height, data.hfw(data.size));
|
|
||||||
_hfw_min_height = std::max(_hfw_min_height, data.mhfw(data.size));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for(size_t i = 0; i < _layout_items.size(); ++i)
|
|
||||||
{
|
|
||||||
ItemData const& data = _layout_items[i];
|
|
||||||
_hfw_height += data.hfw(w) + data.padding_orig;
|
|
||||||
_hfw_min_height += data.mhfw(w) + data.padding_orig;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_hfw_width = w;
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
SGVec2i BoxLayout::sizeHintImpl() const
|
|
||||||
{
|
|
||||||
updateSizeHints();
|
|
||||||
return _size_hint;
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
SGVec2i BoxLayout::minimumSizeImpl() const
|
|
||||||
{
|
|
||||||
updateSizeHints();
|
|
||||||
return _min_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
SGVec2i BoxLayout::maximumSizeImpl() const
|
|
||||||
{
|
|
||||||
updateSizeHints();
|
|
||||||
return _max_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
void BoxLayout::doLayout(const SGRecti& geom)
|
|
||||||
{
|
|
||||||
if( _flags & SIZE_INFO_DIRTY )
|
|
||||||
updateSizeHints();
|
|
||||||
|
|
||||||
// Store current size hints because vertical layouts containing
|
|
||||||
// height-for-width items the size hints are update for the actual width of
|
|
||||||
// the layout
|
|
||||||
int min_size_save = _layout_data.min_size,
|
|
||||||
size_hint_save = _layout_data.size_hint;
|
|
||||||
|
|
||||||
_layout_data.size = (geom.size().*_get_layout_coord)();
|
|
||||||
|
|
||||||
// update width dependent data for layouting of vertical layouts
|
|
||||||
if( _layout_data.has_hfw && !horiz() )
|
|
||||||
{
|
|
||||||
for(size_t i = 0; i < _layout_items.size(); ++i)
|
|
||||||
{
|
|
||||||
ItemData& data = _layout_items[i];
|
|
||||||
if( data.has_hfw )
|
|
||||||
{
|
|
||||||
int w = SGMisc<int>::clip( geom.width(),
|
|
||||||
data.layout_item->minimumSize().x(),
|
|
||||||
data.layout_item->maximumSize().x() );
|
|
||||||
|
|
||||||
data.min_size = data.mhfw(w);
|
|
||||||
data.size_hint = data.hfw(w);
|
|
||||||
|
|
||||||
// Update size hints for layouting with difference to size hints
|
|
||||||
// calculated by using the size hints provided (without trading
|
|
||||||
// height for width)
|
|
||||||
_layout_data.min_size += data.min_size
|
|
||||||
- data.layout_item->minimumSize().y();
|
|
||||||
_layout_data.size_hint += data.size_hint
|
|
||||||
- data.layout_item->sizeHint().y();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// now do the actual layouting
|
|
||||||
distribute(_layout_items, _layout_data);
|
|
||||||
|
|
||||||
// Restore size hints possibly changed by vertical layouting
|
|
||||||
_layout_data.min_size = min_size_save;
|
|
||||||
_layout_data.size_hint = size_hint_save;
|
|
||||||
|
|
||||||
// and finally set the layouted geometry for each item
|
|
||||||
int fixed_size = (geom.size().*_get_fixed_coord)();
|
|
||||||
SGVec2i cur_pos( (geom.pos().*_get_layout_coord)(),
|
|
||||||
(geom.pos().*_get_fixed_coord)() );
|
|
||||||
|
|
||||||
bool reverse = (_direction == RightToLeft) || (_direction == BottomToTop);
|
|
||||||
if( reverse )
|
|
||||||
cur_pos.x() += (geom.size().*_get_layout_coord)();
|
|
||||||
|
|
||||||
for(size_t i = 0; i < _layout_items.size(); ++i)
|
|
||||||
{
|
|
||||||
ItemData const& data = _layout_items[i];
|
|
||||||
cur_pos.x() += reverse ? -data.padding - data.size : data.padding;
|
|
||||||
|
|
||||||
SGVec2i size(
|
|
||||||
data.size,
|
|
||||||
std::min( (data.layout_item->maximumSize().*_get_fixed_coord)(),
|
|
||||||
fixed_size )
|
|
||||||
);
|
|
||||||
|
|
||||||
// Center in fixed direction (TODO allow specifying alignment)
|
|
||||||
int offset_fixed = (fixed_size - size.y()) / 2;
|
|
||||||
cur_pos.y() += offset_fixed;
|
|
||||||
|
|
||||||
data.layout_item->setGeometry(SGRecti(
|
|
||||||
(cur_pos.*_get_layout_coord)(),
|
|
||||||
(cur_pos.*_get_fixed_coord)(),
|
|
||||||
(size.*_get_layout_coord)(),
|
|
||||||
(size.*_get_fixed_coord)()
|
|
||||||
));
|
|
||||||
|
|
||||||
if( !reverse )
|
|
||||||
cur_pos.x() += data.size;
|
|
||||||
cur_pos.y() -= offset_fixed;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
HBoxLayout::HBoxLayout():
|
|
||||||
BoxLayout(LeftToRight)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
VBoxLayout::VBoxLayout():
|
|
||||||
BoxLayout(TopToBottom)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace canvas
|
|
||||||
} // namespace simgear
|
|
||||||
@@ -1,154 +0,0 @@
|
|||||||
// Align items horizontally or vertically in a box
|
|
||||||
//
|
|
||||||
// Copyright (C) 2014 Thomas Geymayer <tomgey@gmail.com>
|
|
||||||
//
|
|
||||||
// This library is free software; you can redistribute it and/or
|
|
||||||
// modify it under the terms of the GNU Library General Public
|
|
||||||
// License as published by the Free Software Foundation; either
|
|
||||||
// version 2 of the License, or (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
// Library General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Library General Public
|
|
||||||
// License along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
|
||||||
|
|
||||||
#ifndef SG_CANVAS_BOX_LAYOUT_HXX_
|
|
||||||
#define SG_CANVAS_BOX_LAYOUT_HXX_
|
|
||||||
|
|
||||||
#include "Layout.hxx"
|
|
||||||
|
|
||||||
namespace simgear
|
|
||||||
{
|
|
||||||
namespace canvas
|
|
||||||
{
|
|
||||||
|
|
||||||
class BoxLayout:
|
|
||||||
public Layout
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
enum Direction
|
|
||||||
{
|
|
||||||
LeftToRight,
|
|
||||||
RightToLeft,
|
|
||||||
TopToBottom,
|
|
||||||
BottomToTop
|
|
||||||
};
|
|
||||||
|
|
||||||
BoxLayout(Direction dir);
|
|
||||||
~BoxLayout();
|
|
||||||
|
|
||||||
virtual void addItem(const LayoutItemRef& item);
|
|
||||||
|
|
||||||
void addItem(const LayoutItemRef& item, int stretch);
|
|
||||||
|
|
||||||
void addStretch(int stretch = 0);
|
|
||||||
|
|
||||||
void addSpacing(int size);
|
|
||||||
|
|
||||||
void insertItem(int index, const LayoutItemRef& item, int stretch = 0);
|
|
||||||
|
|
||||||
void insertStretch(int index, int stretch = 0);
|
|
||||||
|
|
||||||
void insertSpacing(int index, int size);
|
|
||||||
|
|
||||||
virtual size_t count() const;
|
|
||||||
virtual LayoutItemRef itemAt(size_t index);
|
|
||||||
virtual LayoutItemRef takeAt(size_t index);
|
|
||||||
virtual void clear();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the stretch factor of the item at position @a index to @a stretch.
|
|
||||||
*/
|
|
||||||
void setStretch(size_t index, int stretch);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the stretch factor of the given @a item to @a stretch, if it exists
|
|
||||||
* in this layout.
|
|
||||||
*
|
|
||||||
* @return true, if the @a item was found in the layout
|
|
||||||
*/
|
|
||||||
bool setStretchFactor(const LayoutItemRef& item, int stretch);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the stretch factor of the item at position @a index
|
|
||||||
*/
|
|
||||||
int stretch(size_t index) const;
|
|
||||||
|
|
||||||
virtual void setSpacing(int spacing);
|
|
||||||
virtual int spacing() const;
|
|
||||||
|
|
||||||
void setDirection(Direction dir);
|
|
||||||
Direction direction() const;
|
|
||||||
|
|
||||||
virtual bool hasHeightForWidth() const;
|
|
||||||
virtual int heightForWidth(int w) const;
|
|
||||||
virtual int minimumHeightForWidth(int w) const;
|
|
||||||
|
|
||||||
virtual void setCanvas(const CanvasWeakPtr& canvas);
|
|
||||||
|
|
||||||
bool horiz() const;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
typedef const int& (SGVec2i::*CoordGetter)() const;
|
|
||||||
CoordGetter _get_layout_coord, //<! getter for coordinate in layout
|
|
||||||
// direction
|
|
||||||
_get_fixed_coord; //<! getter for coordinate in secondary
|
|
||||||
// (fixed) direction
|
|
||||||
|
|
||||||
int _padding;
|
|
||||||
Direction _direction;
|
|
||||||
|
|
||||||
typedef std::vector<ItemData> LayoutItems;
|
|
||||||
|
|
||||||
mutable LayoutItems _layout_items;
|
|
||||||
mutable ItemData _layout_data;
|
|
||||||
|
|
||||||
// Cache for last height-for-width query
|
|
||||||
mutable int _hfw_width,
|
|
||||||
_hfw_height,
|
|
||||||
_hfw_min_height;
|
|
||||||
|
|
||||||
void updateSizeHints() const;
|
|
||||||
void updateWFHCache(int w) const;
|
|
||||||
|
|
||||||
virtual SGVec2i sizeHintImpl() const;
|
|
||||||
virtual SGVec2i minimumSizeImpl() const;
|
|
||||||
virtual SGVec2i maximumSizeImpl() const;
|
|
||||||
|
|
||||||
virtual void doLayout(const SGRecti& geom);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Shortcut for creating a horizontal box layout
|
|
||||||
*/
|
|
||||||
class HBoxLayout:
|
|
||||||
public BoxLayout
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
HBoxLayout();
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Shortcut for creating a vertical box layout
|
|
||||||
*/
|
|
||||||
class VBoxLayout:
|
|
||||||
public BoxLayout
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
VBoxLayout();
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef SGSharedPtr<BoxLayout> BoxLayoutRef;
|
|
||||||
|
|
||||||
} // namespace canvas
|
|
||||||
} // namespace simgear
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* SG_CANVAS_BOX_LAYOUT_HXX_ */
|
|
||||||
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
include (SimGearComponent)
|
|
||||||
|
|
||||||
set(HEADERS
|
|
||||||
BoxLayout.hxx
|
|
||||||
Layout.hxx
|
|
||||||
LayoutItem.hxx
|
|
||||||
NasalWidget.hxx
|
|
||||||
SpacerItem.hxx
|
|
||||||
)
|
|
||||||
|
|
||||||
set(SOURCES
|
|
||||||
BoxLayout.cxx
|
|
||||||
Layout.cxx
|
|
||||||
LayoutItem.cxx
|
|
||||||
NasalWidget.cxx
|
|
||||||
SpacerItem.cxx
|
|
||||||
)
|
|
||||||
|
|
||||||
simgear_scene_component(canvas-layout canvas/layout "${SOURCES}" "${HEADERS}")
|
|
||||||
|
|
||||||
add_boost_test(canvas_layout
|
|
||||||
SOURCES canvas_layout_test.cxx
|
|
||||||
LIBRARIES ${TEST_LIBS}
|
|
||||||
)
|
|
||||||
@@ -1,295 +0,0 @@
|
|||||||
// Basic class for canvas layouts
|
|
||||||
//
|
|
||||||
// Copyright (C) 2014 Thomas Geymayer <tomgey@gmail.com>
|
|
||||||
//
|
|
||||||
// This library is free software; you can redistribute it and/or
|
|
||||||
// modify it under the terms of the GNU Library General Public
|
|
||||||
// License as published by the Free Software Foundation; either
|
|
||||||
// version 2 of the License, or (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
// Library General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Library General Public
|
|
||||||
// License along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
|
||||||
|
|
||||||
#include "Layout.hxx"
|
|
||||||
#include <simgear/debug/logstream.hxx>
|
|
||||||
|
|
||||||
namespace simgear
|
|
||||||
{
|
|
||||||
namespace canvas
|
|
||||||
{
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
void Layout::update()
|
|
||||||
{
|
|
||||||
if( !(_flags & (LAYOUT_DIRTY | SIZE_INFO_DIRTY)) )
|
|
||||||
return;
|
|
||||||
|
|
||||||
doLayout(_geometry);
|
|
||||||
|
|
||||||
_flags &= ~LAYOUT_DIRTY;
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
void Layout::invalidate()
|
|
||||||
{
|
|
||||||
LayoutItem::invalidate();
|
|
||||||
_flags |= LAYOUT_DIRTY;
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
void Layout::setGeometry(const SGRecti& geom)
|
|
||||||
{
|
|
||||||
if( geom != _geometry )
|
|
||||||
{
|
|
||||||
_geometry = geom;
|
|
||||||
_flags |= LAYOUT_DIRTY;
|
|
||||||
}
|
|
||||||
|
|
||||||
update();
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
void Layout::removeItem(const LayoutItemRef& item)
|
|
||||||
{
|
|
||||||
size_t i = 0;
|
|
||||||
while( LayoutItemRef child = itemAt(i) )
|
|
||||||
{
|
|
||||||
if( item == child )
|
|
||||||
return (void)takeAt(i);
|
|
||||||
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
void Layout::clear()
|
|
||||||
{
|
|
||||||
while( itemAt(0) )
|
|
||||||
takeAt(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
void Layout::ItemData::reset()
|
|
||||||
{
|
|
||||||
layout_item = 0;
|
|
||||||
size_hint = 0;
|
|
||||||
min_size = 0;
|
|
||||||
max_size = 0;
|
|
||||||
padding_orig= 0;
|
|
||||||
padding = 0;
|
|
||||||
size = 0;
|
|
||||||
stretch = 0;
|
|
||||||
has_hfw = false;
|
|
||||||
done = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
int Layout::ItemData::hfw(int w) const
|
|
||||||
{
|
|
||||||
if( has_hfw )
|
|
||||||
return layout_item->heightForWidth(w);
|
|
||||||
else
|
|
||||||
return layout_item->sizeHint().y();
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
int Layout::ItemData::mhfw(int w) const
|
|
||||||
{
|
|
||||||
if( has_hfw )
|
|
||||||
return layout_item->minimumHeightForWidth(w);
|
|
||||||
else
|
|
||||||
return layout_item->minimumSize().y();
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
void Layout::safeAdd(int& a, int b)
|
|
||||||
{
|
|
||||||
if( SGLimits<int>::max() - b < a )
|
|
||||||
a = SGLimits<int>::max();
|
|
||||||
else
|
|
||||||
a += b;
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
void Layout::distribute(std::vector<ItemData>& items, const ItemData& space)
|
|
||||||
{
|
|
||||||
const int num_children = static_cast<int>(items.size());
|
|
||||||
_num_not_done = num_children;
|
|
||||||
|
|
||||||
SG_LOG( SG_GUI,
|
|
||||||
SG_DEBUG,
|
|
||||||
"Layout::distribute(" << space.size << "px for "
|
|
||||||
<< num_children << " items, s.t."
|
|
||||||
<< " min=" << space.min_size
|
|
||||||
<< ", hint=" << space.size_hint
|
|
||||||
<< ", max=" << space.max_size << ")" );
|
|
||||||
|
|
||||||
if( space.size < space.min_size )
|
|
||||||
{
|
|
||||||
// TODO
|
|
||||||
SG_LOG( SG_GUI, SG_WARN, "Layout: not enough size (not implemented)");
|
|
||||||
}
|
|
||||||
else if( space.size < space.max_size )
|
|
||||||
{
|
|
||||||
_sum_stretch = 0;
|
|
||||||
_space_stretch = 0;
|
|
||||||
|
|
||||||
bool less_then_hint = space.size < space.size_hint;
|
|
||||||
|
|
||||||
// Give min_size/size_hint to all items
|
|
||||||
_space_left = space.size
|
|
||||||
- (less_then_hint ? space.min_size : space.size_hint);
|
|
||||||
for(int i = 0; i < num_children; ++i)
|
|
||||||
{
|
|
||||||
ItemData& d = items[i];
|
|
||||||
d.size = less_then_hint ? d.min_size : d.size_hint;
|
|
||||||
d.padding = d.padding_orig;
|
|
||||||
d.done = d.size >= (less_then_hint ? d.size_hint : d.max_size);
|
|
||||||
|
|
||||||
SG_LOG(
|
|
||||||
SG_GUI,
|
|
||||||
SG_DEBUG,
|
|
||||||
i << ") initial=" << d.size
|
|
||||||
<< ", min=" << d.min_size
|
|
||||||
<< ", hint=" << d.size_hint
|
|
||||||
<< ", max=" << d.max_size
|
|
||||||
);
|
|
||||||
|
|
||||||
if( d.done )
|
|
||||||
{
|
|
||||||
_num_not_done -= 1;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( d.stretch > 0 )
|
|
||||||
{
|
|
||||||
_sum_stretch += d.stretch;
|
|
||||||
_space_stretch += d.size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Distribute remaining space to increase the size of each item up to its
|
|
||||||
// size_hint/max_size
|
|
||||||
while( _space_left > 0 )
|
|
||||||
{
|
|
||||||
if( _num_not_done <= 0 )
|
|
||||||
{
|
|
||||||
SG_LOG(SG_GUI, SG_WARN, "space left, but no more items?");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
int space_per_element = std::max(1, _space_left / _num_not_done);
|
|
||||||
|
|
||||||
SG_LOG(SG_GUI, SG_DEBUG, "space/element=" << space_per_element);
|
|
||||||
|
|
||||||
for(int i = 0; i < num_children; ++i)
|
|
||||||
{
|
|
||||||
ItemData& d = items[i];
|
|
||||||
|
|
||||||
SG_LOG(
|
|
||||||
SG_GUI,
|
|
||||||
SG_DEBUG,
|
|
||||||
i << ") left=" << _space_left
|
|
||||||
<< ", not_done=" << _num_not_done
|
|
||||||
<< ", sum=" << _sum_stretch
|
|
||||||
<< ", stretch=" << _space_stretch
|
|
||||||
<< ", stretch/unit=" << _space_stretch / std::max(1, _sum_stretch)
|
|
||||||
);
|
|
||||||
|
|
||||||
if( d.done )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if( _sum_stretch > 0 && d.stretch <= 0 )
|
|
||||||
d.done = true;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
int target_size = 0;
|
|
||||||
int max_size = less_then_hint ? d.size_hint : d.max_size;
|
|
||||||
|
|
||||||
if( _sum_stretch > 0 )
|
|
||||||
{
|
|
||||||
target_size = (d.stretch * (_space_left + _space_stretch))
|
|
||||||
/ _sum_stretch;
|
|
||||||
|
|
||||||
// Item would be smaller than minimum size or larger than maximum
|
|
||||||
// size, so just keep bounded size and ignore stretch factor
|
|
||||||
if( target_size <= d.size || target_size >= max_size )
|
|
||||||
{
|
|
||||||
d.done = true;
|
|
||||||
_sum_stretch -= d.stretch;
|
|
||||||
_space_stretch -= d.size;
|
|
||||||
|
|
||||||
if( target_size >= max_size )
|
|
||||||
target_size = max_size;
|
|
||||||
else
|
|
||||||
target_size = d.size;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
_space_stretch += target_size - d.size;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Give space evenly to all remaining elements in this round
|
|
||||||
target_size = d.size + std::min(_space_left, space_per_element);
|
|
||||||
|
|
||||||
if( target_size >= max_size )
|
|
||||||
{
|
|
||||||
d.done = true;
|
|
||||||
target_size = max_size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int old_size = d.size;
|
|
||||||
d.size = target_size;
|
|
||||||
_space_left -= d.size - old_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( d.done )
|
|
||||||
{
|
|
||||||
_num_not_done -= 1;
|
|
||||||
|
|
||||||
if( _sum_stretch <= 0 && d.stretch > 0 )
|
|
||||||
// Distribute remaining space evenly to all non-stretchable items
|
|
||||||
// in a new round
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_space_left = space.size - space.max_size;
|
|
||||||
for(int i = 0; i < num_children; ++i)
|
|
||||||
{
|
|
||||||
ItemData& d = items[i];
|
|
||||||
d.size = d.max_size;
|
|
||||||
|
|
||||||
// Add superfluous space as padding
|
|
||||||
d.padding = d.padding_orig + _space_left
|
|
||||||
// Padding after last child...
|
|
||||||
/ (_num_not_done + 1);
|
|
||||||
|
|
||||||
_space_left -= d.padding - d.padding_orig;
|
|
||||||
_num_not_done -= 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SG_LOG(SG_GUI, SG_DEBUG, "distribute:");
|
|
||||||
for(int i = 0; i < num_children; ++i)
|
|
||||||
{
|
|
||||||
ItemData const& d = items[i];
|
|
||||||
SG_LOG( SG_GUI,
|
|
||||||
SG_DEBUG,
|
|
||||||
i << ") pad=" << d.padding
|
|
||||||
<< ", size = " << d.size );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace canvas
|
|
||||||
} // namespace simgear
|
|
||||||
@@ -1,133 +0,0 @@
|
|||||||
// Basic class for canvas layouts
|
|
||||||
//
|
|
||||||
// Copyright (C) 2014 Thomas Geymayer <tomgey@gmail.com>
|
|
||||||
//
|
|
||||||
// This library is free software; you can redistribute it and/or
|
|
||||||
// modify it under the terms of the GNU Library General Public
|
|
||||||
// License as published by the Free Software Foundation; either
|
|
||||||
// version 2 of the License, or (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
// Library General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Library General Public
|
|
||||||
// License along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
|
||||||
|
|
||||||
#ifndef SG_CANVAS_LAYOUT_HXX_
|
|
||||||
#define SG_CANVAS_LAYOUT_HXX_
|
|
||||||
|
|
||||||
#include "LayoutItem.hxx"
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
namespace simgear
|
|
||||||
{
|
|
||||||
namespace canvas
|
|
||||||
{
|
|
||||||
|
|
||||||
class Layout:
|
|
||||||
public LayoutItem
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
void update();
|
|
||||||
|
|
||||||
virtual void invalidate();
|
|
||||||
virtual void setGeometry(const SGRecti& geom);
|
|
||||||
|
|
||||||
virtual void addItem(const LayoutItemRef& item) = 0;
|
|
||||||
virtual void setSpacing(int spacing) = 0;
|
|
||||||
virtual int spacing() const = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the number of items.
|
|
||||||
*/
|
|
||||||
virtual size_t count() const = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the item at position @a index.
|
|
||||||
*
|
|
||||||
* If there is no such item the function must do nothing and return an
|
|
||||||
* empty reference.
|
|
||||||
*/
|
|
||||||
virtual LayoutItemRef itemAt(size_t index) = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove and get the item at position @a index.
|
|
||||||
*
|
|
||||||
* If there is no such item the function must do nothing and return an
|
|
||||||
* empty reference.
|
|
||||||
*/
|
|
||||||
virtual LayoutItemRef takeAt(size_t index) = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove the given @a item from the layout.
|
|
||||||
*/
|
|
||||||
void removeItem(const LayoutItemRef& item);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove all items.
|
|
||||||
*/
|
|
||||||
virtual void clear();
|
|
||||||
|
|
||||||
protected:
|
|
||||||
enum LayoutFlags
|
|
||||||
{
|
|
||||||
LAYOUT_DIRTY = LayoutItem::LAST_FLAG << 1,
|
|
||||||
LAST_FLAG = LAYOUT_DIRTY
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ItemData
|
|
||||||
{
|
|
||||||
LayoutItemRef layout_item;
|
|
||||||
int size_hint,
|
|
||||||
min_size,
|
|
||||||
max_size,
|
|
||||||
padding_orig, //<! original padding as specified by the user
|
|
||||||
padding, //<! padding before element (layouted)
|
|
||||||
size, //<! layouted size
|
|
||||||
stretch; //<! stretch factor
|
|
||||||
bool has_hfw : 1, //<! height for width
|
|
||||||
done : 1; //<! layouting done
|
|
||||||
|
|
||||||
/** Clear values (reset to default/empty state) */
|
|
||||||
void reset();
|
|
||||||
|
|
||||||
int hfw(int w) const;
|
|
||||||
int mhfw(int w) const;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Override to implement the actual layouting
|
|
||||||
*/
|
|
||||||
virtual void doLayout(const SGRecti& geom) = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add two integers taking care of overflow (limit to INT_MAX)
|
|
||||||
*/
|
|
||||||
static void safeAdd(int& a, int b);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Distribute the available @a space to all @a items
|
|
||||||
*/
|
|
||||||
void distribute(std::vector<ItemData>& items, const ItemData& space);
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
int _num_not_done, //<! number of children not layouted yet
|
|
||||||
_sum_stretch, //<! sum of stretch factors of all not yet layouted
|
|
||||||
// children
|
|
||||||
_space_stretch,//<! space currently assigned to all not yet layouted
|
|
||||||
// stretchable children
|
|
||||||
_space_left; //<! remaining space not used by any child yet
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef SGSharedPtr<Layout> LayoutRef;
|
|
||||||
|
|
||||||
} // namespace canvas
|
|
||||||
} // namespace simgear
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* SG_CANVAS_LAYOUT_HXX_ */
|
|
||||||
@@ -1,171 +0,0 @@
|
|||||||
// Basic element for layouting canvas elements
|
|
||||||
//
|
|
||||||
// Copyright (C) 2014 Thomas Geymayer <tomgey@gmail.com>
|
|
||||||
//
|
|
||||||
// This library is free software; you can redistribute it and/or
|
|
||||||
// modify it under the terms of the GNU Library General Public
|
|
||||||
// License as published by the Free Software Foundation; either
|
|
||||||
// version 2 of the License, or (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
// Library General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Library General Public
|
|
||||||
// License along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
|
||||||
|
|
||||||
#include "LayoutItem.hxx"
|
|
||||||
#include <simgear/canvas/Canvas.hxx>
|
|
||||||
|
|
||||||
namespace simgear
|
|
||||||
{
|
|
||||||
namespace canvas
|
|
||||||
{
|
|
||||||
const SGVec2i LayoutItem::MAX_SIZE( SGLimits<int>::max(),
|
|
||||||
SGLimits<int>::max() );
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
LayoutItem::LayoutItem():
|
|
||||||
_flags(0),
|
|
||||||
_size_hint(0, 0),
|
|
||||||
_min_size(0, 0),
|
|
||||||
_max_size(MAX_SIZE)
|
|
||||||
{
|
|
||||||
invalidate();
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
LayoutItem::~LayoutItem()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
SGVec2i LayoutItem::sizeHint() const
|
|
||||||
{
|
|
||||||
if( _flags & SIZE_HINT_DIRTY )
|
|
||||||
{
|
|
||||||
_size_hint = sizeHintImpl();
|
|
||||||
_flags &= ~SIZE_HINT_DIRTY;
|
|
||||||
}
|
|
||||||
|
|
||||||
return _size_hint;
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
SGVec2i LayoutItem::minimumSize() const
|
|
||||||
{
|
|
||||||
if( _flags & MINIMUM_SIZE_DIRTY )
|
|
||||||
{
|
|
||||||
_min_size = minimumSizeImpl();
|
|
||||||
_flags &= ~MINIMUM_SIZE_DIRTY;
|
|
||||||
}
|
|
||||||
|
|
||||||
return _min_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
SGVec2i LayoutItem::maximumSize() const
|
|
||||||
{
|
|
||||||
if( _flags & MAXIMUM_SIZE_DIRTY )
|
|
||||||
{
|
|
||||||
_max_size = maximumSizeImpl();
|
|
||||||
_flags &= ~MAXIMUM_SIZE_DIRTY;
|
|
||||||
}
|
|
||||||
|
|
||||||
return _max_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
bool LayoutItem::hasHeightForWidth() const
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
int LayoutItem::heightForWidth(int w) const
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
int LayoutItem::minimumHeightForWidth(int w) const
|
|
||||||
{
|
|
||||||
return heightForWidth(w);
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
void LayoutItem::invalidate()
|
|
||||||
{
|
|
||||||
_flags |= SIZE_INFO_DIRTY;
|
|
||||||
invalidateParent();
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
void LayoutItem::invalidateParent()
|
|
||||||
{
|
|
||||||
LayoutItemRef parent = _parent.lock();
|
|
||||||
if( parent )
|
|
||||||
parent->invalidate();
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
void LayoutItem::setGeometry(const SGRecti& geom)
|
|
||||||
{
|
|
||||||
_geometry = geom;
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
SGRecti LayoutItem::geometry() const
|
|
||||||
{
|
|
||||||
return _geometry;
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
void LayoutItem::setCanvas(const CanvasWeakPtr& canvas)
|
|
||||||
{
|
|
||||||
_canvas = canvas;
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
CanvasPtr LayoutItem::getCanvas() const
|
|
||||||
{
|
|
||||||
return _canvas.lock();
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
void LayoutItem::setParent(const LayoutItemWeakRef& parent)
|
|
||||||
{
|
|
||||||
_parent = parent;
|
|
||||||
LayoutItemRef parent_ref = parent.lock();
|
|
||||||
setCanvas(parent_ref ? parent_ref->_canvas : CanvasWeakPtr());
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
LayoutItemRef LayoutItem::getParent() const
|
|
||||||
{
|
|
||||||
return _parent.lock();
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
SGVec2i LayoutItem::sizeHintImpl() const
|
|
||||||
{
|
|
||||||
return _size_hint;
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
SGVec2i LayoutItem::minimumSizeImpl() const
|
|
||||||
{
|
|
||||||
return _min_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
SGVec2i LayoutItem::maximumSizeImpl() const
|
|
||||||
{
|
|
||||||
return _max_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace canvas
|
|
||||||
} // namespace simgear
|
|
||||||
@@ -1,149 +0,0 @@
|
|||||||
///@file Basic element for layouting canvas elements
|
|
||||||
//
|
|
||||||
// Copyright (C) 2014 Thomas Geymayer <tomgey@gmail.com>
|
|
||||||
//
|
|
||||||
// This library is free software; you can redistribute it and/or
|
|
||||||
// modify it under the terms of the GNU Library General Public
|
|
||||||
// License as published by the Free Software Foundation; either
|
|
||||||
// version 2 of the License, or (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
// Library General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Library General Public
|
|
||||||
// License along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
|
||||||
|
|
||||||
#ifndef SG_CANVAS_LAYOUT_ITEM_HXX_
|
|
||||||
#define SG_CANVAS_LAYOUT_ITEM_HXX_
|
|
||||||
|
|
||||||
#include <simgear/canvas/canvas_fwd.hxx>
|
|
||||||
#include <simgear/math/SGMath.hxx>
|
|
||||||
#include <simgear/math/SGRect.hxx>
|
|
||||||
#include <simgear/misc/stdint.hxx>
|
|
||||||
#include <simgear/structure/SGWeakReferenced.hxx>
|
|
||||||
#include <simgear/structure/SGSharedPtr.hxx>
|
|
||||||
|
|
||||||
namespace simgear
|
|
||||||
{
|
|
||||||
namespace canvas
|
|
||||||
{
|
|
||||||
class LayoutItem;
|
|
||||||
typedef SGSharedPtr<LayoutItem> LayoutItemRef;
|
|
||||||
typedef SGWeakPtr<LayoutItem> LayoutItemWeakRef;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Base class for all layouting elements. Specializations either implement a
|
|
||||||
* layouting algorithm or a widget.
|
|
||||||
*/
|
|
||||||
class LayoutItem:
|
|
||||||
public virtual SGVirtualWeakReferenced
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
/** Maximum item size (indicating no limit) */
|
|
||||||
static const SGVec2i MAX_SIZE;
|
|
||||||
|
|
||||||
LayoutItem();
|
|
||||||
virtual ~LayoutItem();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the preferred size of this item.
|
|
||||||
*/
|
|
||||||
SGVec2i sizeHint() const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the minimum amount of the space this item requires.
|
|
||||||
*/
|
|
||||||
SGVec2i minimumSize() const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the maximum amount of space this item can use.
|
|
||||||
*/
|
|
||||||
SGVec2i maximumSize() const;
|
|
||||||
|
|
||||||
virtual bool hasHeightForWidth() const;
|
|
||||||
virtual int heightForWidth(int w) const;
|
|
||||||
virtual int minimumHeightForWidth(int w) const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Mark all cached data as invalid and require it to be recalculated.
|
|
||||||
*/
|
|
||||||
virtual void invalidate();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Mark all cached data of parent item as invalid (if it is known)
|
|
||||||
*/
|
|
||||||
void invalidateParent();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set position and size of this element. For layouts this triggers a
|
|
||||||
* recalculation of the layout.
|
|
||||||
*/
|
|
||||||
virtual void setGeometry(const SGRecti& geom);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get position and size of this element.
|
|
||||||
*/
|
|
||||||
virtual SGRecti geometry() const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the canvas this item is attached to.
|
|
||||||
*/
|
|
||||||
virtual void setCanvas(const CanvasWeakPtr& canvas);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the canvas this item is attached to.
|
|
||||||
*/
|
|
||||||
CanvasPtr getCanvas() const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the parent layout item (usually this is a layout).
|
|
||||||
*/
|
|
||||||
void setParent(const LayoutItemWeakRef& parent);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the parent layout.
|
|
||||||
*/
|
|
||||||
LayoutItemRef getParent() const;
|
|
||||||
|
|
||||||
/// Called before item is removed from a layout
|
|
||||||
virtual void onRemove() {}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
friend class Canvas;
|
|
||||||
|
|
||||||
enum Flags
|
|
||||||
{
|
|
||||||
SIZE_HINT_DIRTY = 1,
|
|
||||||
MINIMUM_SIZE_DIRTY = SIZE_HINT_DIRTY << 1,
|
|
||||||
MAXIMUM_SIZE_DIRTY = MINIMUM_SIZE_DIRTY << 1,
|
|
||||||
SIZE_INFO_DIRTY = SIZE_HINT_DIRTY
|
|
||||||
| MINIMUM_SIZE_DIRTY
|
|
||||||
| MAXIMUM_SIZE_DIRTY,
|
|
||||||
LAST_FLAG = MAXIMUM_SIZE_DIRTY
|
|
||||||
};
|
|
||||||
|
|
||||||
CanvasWeakPtr _canvas;
|
|
||||||
LayoutItemWeakRef _parent;
|
|
||||||
|
|
||||||
SGRecti _geometry;
|
|
||||||
|
|
||||||
mutable uint32_t _flags;
|
|
||||||
mutable SGVec2i _size_hint,
|
|
||||||
_min_size,
|
|
||||||
_max_size;
|
|
||||||
|
|
||||||
virtual SGVec2i sizeHintImpl() const;
|
|
||||||
virtual SGVec2i minimumSizeImpl() const;
|
|
||||||
virtual SGVec2i maximumSizeImpl() const;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace canvas
|
|
||||||
} // namespace simgear
|
|
||||||
|
|
||||||
#endif /* SG_CANVAS_LAYOUT_ITEM_HXX_ */
|
|
||||||
@@ -1,295 +0,0 @@
|
|||||||
// Glue for GUI layout items implemented in Nasal space
|
|
||||||
//
|
|
||||||
// Copyright (C) 2014 Thomas Geymayer <tomgey@gmail.com>
|
|
||||||
//
|
|
||||||
// This library is free software; you can redistribute it and/or
|
|
||||||
// modify it under the terms of the GNU Library General Public
|
|
||||||
// License as published by the Free Software Foundation; either
|
|
||||||
// version 2 of the License, or (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
// Library General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Library General Public
|
|
||||||
// License along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
|
||||||
|
|
||||||
#include "NasalWidget.hxx"
|
|
||||||
|
|
||||||
#include <simgear/canvas/Canvas.hxx>
|
|
||||||
#include <simgear/nasal/cppbind/Ghost.hxx>
|
|
||||||
|
|
||||||
namespace simgear
|
|
||||||
{
|
|
||||||
namespace canvas
|
|
||||||
{
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
NasalWidget::NasalWidget(naRef impl):
|
|
||||||
Object(impl),
|
|
||||||
_layout_size_hint(32, 32),
|
|
||||||
_layout_min_size(16, 16),
|
|
||||||
_layout_max_size(MAX_SIZE),
|
|
||||||
_user_size_hint(0, 0),
|
|
||||||
_user_min_size(0, 0),
|
|
||||||
_user_max_size(MAX_SIZE)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
NasalWidget::~NasalWidget()
|
|
||||||
{
|
|
||||||
onRemove();
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
void NasalWidget::invalidate()
|
|
||||||
{
|
|
||||||
LayoutItem::invalidate();
|
|
||||||
_flags |= LAYOUT_DIRTY;
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
void NasalWidget::setGeometry(const SGRect<int>& geom)
|
|
||||||
{
|
|
||||||
if( _geometry != geom )
|
|
||||||
_geometry = geom;
|
|
||||||
else if( !(_flags & LAYOUT_DIRTY) || !_set_geometry )
|
|
||||||
return;
|
|
||||||
|
|
||||||
naContext c = naNewContext();
|
|
||||||
try
|
|
||||||
{
|
|
||||||
_set_geometry(nasal::to_nasal(c, this), geom);
|
|
||||||
_flags &= ~LAYOUT_DIRTY;
|
|
||||||
}
|
|
||||||
catch( std::exception const& ex )
|
|
||||||
{
|
|
||||||
SG_LOG(
|
|
||||||
SG_GUI,
|
|
||||||
SG_WARN,
|
|
||||||
"NasalWidget::setGeometry: callback error: '" << ex.what() << "'"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
naFreeContext(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
void NasalWidget::onRemove()
|
|
||||||
{
|
|
||||||
if( !_nasal_impl.valid() )
|
|
||||||
return;
|
|
||||||
|
|
||||||
typedef boost::function<void(nasal::Me)> Deleter;
|
|
||||||
|
|
||||||
naContext c = naNewContext();
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Deleter del =
|
|
||||||
nasal::get_member<Deleter>(c, _nasal_impl.get_naRef(), "onRemove");
|
|
||||||
if( del )
|
|
||||||
del(nasal::to_nasal(c, this));
|
|
||||||
}
|
|
||||||
catch( std::exception const& ex )
|
|
||||||
{
|
|
||||||
SG_LOG(
|
|
||||||
SG_GUI,
|
|
||||||
SG_WARN,
|
|
||||||
"NasalWidget::onRemove: callback error: '" << ex.what() << "'"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
naFreeContext(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
void NasalWidget::setSetGeometryFunc(const SetGeometryFunc& func)
|
|
||||||
{
|
|
||||||
_set_geometry = func;
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
void NasalWidget::setHeightForWidthFunc(const HeightForWidthFunc& func)
|
|
||||||
{
|
|
||||||
_height_for_width = func;
|
|
||||||
invalidate();
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
void NasalWidget::setMinimumHeightForWidthFunc(const HeightForWidthFunc& func)
|
|
||||||
{
|
|
||||||
_min_height_for_width = func;
|
|
||||||
invalidate();
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
void NasalWidget::setSizeHint(const SGVec2i& s)
|
|
||||||
{
|
|
||||||
if( _user_size_hint == s )
|
|
||||||
return;
|
|
||||||
|
|
||||||
_user_size_hint = s;
|
|
||||||
|
|
||||||
// TODO just invalidate size_hint? Probably not a performance issue...
|
|
||||||
invalidate();
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
void NasalWidget::setMinimumSize(const SGVec2i& s)
|
|
||||||
{
|
|
||||||
if( _user_min_size == s )
|
|
||||||
return;
|
|
||||||
|
|
||||||
_user_min_size = s;
|
|
||||||
invalidate();
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
void NasalWidget::setMaximumSize(const SGVec2i& s)
|
|
||||||
{
|
|
||||||
if( _user_max_size == s )
|
|
||||||
return;
|
|
||||||
|
|
||||||
_user_max_size = s;
|
|
||||||
invalidate();
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
void NasalWidget::setLayoutSizeHint(const SGVec2i& s)
|
|
||||||
{
|
|
||||||
if( _layout_size_hint == s )
|
|
||||||
return;
|
|
||||||
|
|
||||||
_layout_size_hint = s;
|
|
||||||
invalidate();
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
void NasalWidget::setLayoutMinimumSize(const SGVec2i& s)
|
|
||||||
{
|
|
||||||
if( _layout_min_size == s )
|
|
||||||
return;
|
|
||||||
|
|
||||||
_layout_min_size = s;
|
|
||||||
invalidate();
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
void NasalWidget::setLayoutMaximumSize(const SGVec2i& s)
|
|
||||||
{
|
|
||||||
if( _layout_max_size == s )
|
|
||||||
return;
|
|
||||||
|
|
||||||
_layout_max_size = s;
|
|
||||||
invalidate();
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
bool NasalWidget::hasHeightForWidth() const
|
|
||||||
{
|
|
||||||
return !_height_for_width.empty() || !_min_height_for_width.empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
int NasalWidget::heightForWidth(int w) const
|
|
||||||
{
|
|
||||||
return callHeightForWidthFunc( _height_for_width.empty()
|
|
||||||
? _min_height_for_width
|
|
||||||
: _height_for_width, w );
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
int NasalWidget::minimumHeightForWidth(int w) const
|
|
||||||
{
|
|
||||||
return callHeightForWidthFunc( _min_height_for_width.empty()
|
|
||||||
? _height_for_width
|
|
||||||
: _min_height_for_width, w );
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
static naRef f_makeNasalWidget(const nasal::CallContext& ctx)
|
|
||||||
{
|
|
||||||
return ctx.to_nasal(NasalWidgetRef(
|
|
||||||
new NasalWidget( ctx.requireArg<naRef>(0) )
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
void NasalWidget::setupGhost(nasal::Hash& ns)
|
|
||||||
{
|
|
||||||
nasal::Ghost<NasalWidgetRef>::init("canvas.Widget")
|
|
||||||
.bases<LayoutItemRef>()
|
|
||||||
.bases<nasal::ObjectRef>()
|
|
||||||
.method("setSetGeometryFunc", &NasalWidget::setSetGeometryFunc)
|
|
||||||
.method("setMinimumHeightForWidthFunc",
|
|
||||||
&NasalWidget::setMinimumHeightForWidthFunc)
|
|
||||||
.method("setHeightForWidthFunc", &NasalWidget::setHeightForWidthFunc)
|
|
||||||
.method("setSizeHint", &NasalWidget::setSizeHint)
|
|
||||||
.method("setMinimumSize", &NasalWidget::setMinimumSize)
|
|
||||||
.method("setMaximumSize", &NasalWidget::setMaximumSize)
|
|
||||||
.method("setLayoutSizeHint", &NasalWidget::setLayoutSizeHint)
|
|
||||||
.method("setLayoutMinimumSize", &NasalWidget::setLayoutMinimumSize)
|
|
||||||
.method("setLayoutMaximumSize", &NasalWidget::setLayoutMaximumSize);
|
|
||||||
|
|
||||||
nasal::Hash widget_hash = ns.createHash("Widget");
|
|
||||||
widget_hash.set("new", &f_makeNasalWidget);
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
int NasalWidget::callHeightForWidthFunc( const HeightForWidthFunc& hfw,
|
|
||||||
int w ) const
|
|
||||||
{
|
|
||||||
if( hfw.empty() )
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
naContext c = naNewContext();
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return hfw(nasal::to_nasal(c, const_cast<NasalWidget*>(this)), w);
|
|
||||||
}
|
|
||||||
catch( std::exception const& ex )
|
|
||||||
{
|
|
||||||
SG_LOG(
|
|
||||||
SG_GUI,
|
|
||||||
SG_WARN,
|
|
||||||
"NasalWidget.heightForWidth: callback error: '" << ex.what() << "'"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
naFreeContext(c);
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
SGVec2i NasalWidget::sizeHintImpl() const
|
|
||||||
{
|
|
||||||
return SGVec2i(
|
|
||||||
_user_size_hint.x() > 0 ? _user_size_hint.x() : _layout_size_hint.x(),
|
|
||||||
_user_size_hint.y() > 0 ? _user_size_hint.y() : _layout_size_hint.y()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
SGVec2i NasalWidget::minimumSizeImpl() const
|
|
||||||
{
|
|
||||||
return SGVec2i(
|
|
||||||
_user_min_size.x() > 0 ? _user_min_size.x() : _layout_min_size.x(),
|
|
||||||
_user_min_size.y() > 0 ? _user_min_size.y() : _layout_min_size.y()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
SGVec2i NasalWidget::maximumSizeImpl() const
|
|
||||||
{
|
|
||||||
return SGVec2i(
|
|
||||||
_user_max_size.x() < MAX_SIZE.x() ? _user_max_size.x()
|
|
||||||
: _layout_max_size.x(),
|
|
||||||
_user_max_size.y() < MAX_SIZE.y() ? _user_max_size.y()
|
|
||||||
: _layout_max_size.y()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace canvas
|
|
||||||
} // namespace simgear
|
|
||||||
@@ -1,129 +0,0 @@
|
|||||||
///@file Glue for GUI widgets implemented in Nasal space
|
|
||||||
//
|
|
||||||
// Copyright (C) 2014 Thomas Geymayer <tomgey@gmail.com>
|
|
||||||
//
|
|
||||||
// This library is free software; you can redistribute it and/or
|
|
||||||
// modify it under the terms of the GNU Library General Public
|
|
||||||
// License as published by the Free Software Foundation; either
|
|
||||||
// version 2 of the License, or (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
// Library General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Library General Public
|
|
||||||
// License along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
|
||||||
|
|
||||||
#ifndef SG_CANVAS_NASAL_WIDGET_HXX_
|
|
||||||
#define SG_CANVAS_NASAL_WIDGET_HXX_
|
|
||||||
|
|
||||||
#include "LayoutItem.hxx"
|
|
||||||
|
|
||||||
#include <simgear/nasal/cppbind/from_nasal.hxx>
|
|
||||||
#include <simgear/nasal/cppbind/NasalHash.hxx>
|
|
||||||
#include <simgear/nasal/cppbind/NasalObject.hxx>
|
|
||||||
|
|
||||||
namespace simgear
|
|
||||||
{
|
|
||||||
namespace canvas
|
|
||||||
{
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Baseclass/ghost to create widgets with Nasal.
|
|
||||||
*/
|
|
||||||
class NasalWidget:
|
|
||||||
public LayoutItem,
|
|
||||||
public nasal::Object
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
typedef boost::function<void (nasal::Me, const SGRecti&)> SetGeometryFunc;
|
|
||||||
typedef boost::function<int (nasal::Me, int)> HeightForWidthFunc;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param impl Initial implementation hash (nasal part of
|
|
||||||
* implementation)
|
|
||||||
*/
|
|
||||||
NasalWidget(naRef impl);
|
|
||||||
|
|
||||||
~NasalWidget();
|
|
||||||
|
|
||||||
virtual void invalidate();
|
|
||||||
virtual void setGeometry(const SGRecti& geom);
|
|
||||||
virtual void onRemove();
|
|
||||||
|
|
||||||
void setSetGeometryFunc(const SetGeometryFunc& func);
|
|
||||||
void setHeightForWidthFunc(const HeightForWidthFunc& func);
|
|
||||||
void setMinimumHeightForWidthFunc(const HeightForWidthFunc& func);
|
|
||||||
|
|
||||||
/** Set size hint.
|
|
||||||
*
|
|
||||||
* Overrides default size hint. Set to (0, 0) to fall back to default size
|
|
||||||
* hint.
|
|
||||||
*/
|
|
||||||
void setSizeHint(const SGVec2i& s);
|
|
||||||
|
|
||||||
/** Set minimum size.
|
|
||||||
*
|
|
||||||
* Overrides default minimum size. Set to (0, 0) to fall back to default
|
|
||||||
* minimum size.
|
|
||||||
*/
|
|
||||||
void setMinimumSize(const SGVec2i& s);
|
|
||||||
|
|
||||||
/** Set maximum size.
|
|
||||||
*
|
|
||||||
* Overrides default maximum size hint. Set to LayoutItem::MAX_SIZE to
|
|
||||||
* fall back to default maximum size.
|
|
||||||
*/
|
|
||||||
void setMaximumSize(const SGVec2i& s);
|
|
||||||
|
|
||||||
void setLayoutSizeHint(const SGVec2i& s);
|
|
||||||
void setLayoutMinimumSize(const SGVec2i& s);
|
|
||||||
void setLayoutMaximumSize(const SGVec2i& s);
|
|
||||||
|
|
||||||
virtual bool hasHeightForWidth() const;
|
|
||||||
virtual int heightForWidth(int w) const;
|
|
||||||
virtual int minimumHeightForWidth(int w) const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param ns Namespace to register the class interface
|
|
||||||
*/
|
|
||||||
static void setupGhost(nasal::Hash& ns);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
enum WidgetFlags
|
|
||||||
{
|
|
||||||
LAYOUT_DIRTY = LayoutItem::LAST_FLAG << 1,
|
|
||||||
LAST_FLAG = LAYOUT_DIRTY
|
|
||||||
};
|
|
||||||
|
|
||||||
SetGeometryFunc _set_geometry;
|
|
||||||
HeightForWidthFunc _height_for_width,
|
|
||||||
_min_height_for_width;
|
|
||||||
|
|
||||||
SGVec2i _layout_size_hint,
|
|
||||||
_layout_min_size,
|
|
||||||
_layout_max_size,
|
|
||||||
_user_size_hint,
|
|
||||||
_user_min_size,
|
|
||||||
_user_max_size;
|
|
||||||
|
|
||||||
int callHeightForWidthFunc( const HeightForWidthFunc& hfw,
|
|
||||||
int w ) const;
|
|
||||||
|
|
||||||
virtual SGVec2i sizeHintImpl() const;
|
|
||||||
virtual SGVec2i minimumSizeImpl() const;
|
|
||||||
virtual SGVec2i maximumSizeImpl() const;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef SGSharedPtr<NasalWidget> NasalWidgetRef;
|
|
||||||
|
|
||||||
} // namespace canvas
|
|
||||||
} // namespace simgear
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* SG_CANVAS_NASAL_WIDGET_HXX_ */
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
// Element providing blank space in a layout.
|
|
||||||
//
|
|
||||||
// Copyright (C) 2014 Thomas Geymayer <tomgey@gmail.com>
|
|
||||||
//
|
|
||||||
// This library is free software; you can redistribute it and/or
|
|
||||||
// modify it under the terms of the GNU Library General Public
|
|
||||||
// License as published by the Free Software Foundation; either
|
|
||||||
// version 2 of the License, or (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
// Library General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Library General Public
|
|
||||||
// License along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
|
||||||
|
|
||||||
#include "SpacerItem.hxx"
|
|
||||||
|
|
||||||
namespace simgear
|
|
||||||
{
|
|
||||||
namespace canvas
|
|
||||||
{
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
SpacerItem::SpacerItem( const SGVec2i& size,
|
|
||||||
const SGVec2i& max_size )
|
|
||||||
{
|
|
||||||
_size_hint = size;
|
|
||||||
_min_size = size;
|
|
||||||
_max_size = max_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace canvas
|
|
||||||
} // namespace simgear
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
///@file Element providing blank space in a layout.
|
|
||||||
//
|
|
||||||
// Copyright (C) 2014 Thomas Geymayer <tomgey@gmail.com>
|
|
||||||
//
|
|
||||||
// This library is free software; you can redistribute it and/or
|
|
||||||
// modify it under the terms of the GNU Library General Public
|
|
||||||
// License as published by the Free Software Foundation; either
|
|
||||||
// version 2 of the License, or (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
// Library General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Library General Public
|
|
||||||
// License along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
|
||||||
|
|
||||||
#ifndef SG_CANVAS_SPACER_ITEM_HXX_
|
|
||||||
#define SG_CANVAS_SPACER_ITEM_HXX_
|
|
||||||
|
|
||||||
#include "LayoutItem.hxx"
|
|
||||||
|
|
||||||
namespace simgear
|
|
||||||
{
|
|
||||||
namespace canvas
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Element for providing blank space in a layout.
|
|
||||||
*/
|
|
||||||
class SpacerItem:
|
|
||||||
public LayoutItem
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
SpacerItem( const SGVec2i& size = SGVec2i(0, 0),
|
|
||||||
const SGVec2i& max_size = MAX_SIZE );
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace canvas
|
|
||||||
} // namespace simgear
|
|
||||||
|
|
||||||
#endif /* SG_CANVAS_SPACER_ITEM_HXX_ */
|
|
||||||
@@ -1,461 +0,0 @@
|
|||||||
// Testing canvas layouting system
|
|
||||||
//
|
|
||||||
// Copyright (C) 2014 Thomas Geymayer <tomgey@gmail.com>
|
|
||||||
//
|
|
||||||
// This library is free software; you can redistribute it and/or
|
|
||||||
// modify it under the terms of the GNU Library General Public
|
|
||||||
// License as published by the Free Software Foundation; either
|
|
||||||
// version 2 of the License, or (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
// Library General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Library General Public
|
|
||||||
// License along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
|
||||||
|
|
||||||
#define BOOST_TEST_MODULE canvas_layout
|
|
||||||
#include <BoostTestTargetConfig.h>
|
|
||||||
|
|
||||||
#include "BoxLayout.hxx"
|
|
||||||
#include "NasalWidget.hxx"
|
|
||||||
|
|
||||||
#include <simgear/debug/logstream.hxx>
|
|
||||||
#include <cstdlib>
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
struct SetLogLevelFixture
|
|
||||||
{
|
|
||||||
SetLogLevelFixture()
|
|
||||||
{
|
|
||||||
sglog().set_log_priority(SG_DEBUG);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
BOOST_GLOBAL_FIXTURE(SetLogLevelFixture);
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
namespace sc = simgear::canvas;
|
|
||||||
|
|
||||||
class TestWidget:
|
|
||||||
public sc::LayoutItem
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
TestWidget( const SGVec2i& min_size,
|
|
||||||
const SGVec2i& size_hint,
|
|
||||||
const SGVec2i& max_size = MAX_SIZE )
|
|
||||||
{
|
|
||||||
_size_hint = size_hint;
|
|
||||||
_min_size = min_size;
|
|
||||||
_max_size = max_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
TestWidget(const TestWidget& rhs)
|
|
||||||
{
|
|
||||||
_size_hint = rhs._size_hint;
|
|
||||||
_min_size = rhs._min_size;
|
|
||||||
_max_size = rhs._max_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setMinSize(const SGVec2i& size) { _min_size = size; }
|
|
||||||
void setMaxSize(const SGVec2i& size) { _max_size = size; }
|
|
||||||
void setSizeHint(const SGVec2i& size) { _size_hint = size; }
|
|
||||||
|
|
||||||
virtual void setGeometry(const SGRecti& geom) { _geom = geom; }
|
|
||||||
virtual SGRecti geometry() const { return _geom; }
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
SGRecti _geom;
|
|
||||||
|
|
||||||
virtual SGVec2i sizeHintImpl() const { return _size_hint; }
|
|
||||||
virtual SGVec2i minimumSizeImpl() const { return _min_size; }
|
|
||||||
virtual SGVec2i maximumSizeImpl() const { return _max_size; }
|
|
||||||
};
|
|
||||||
|
|
||||||
class TestWidgetHFW:
|
|
||||||
public TestWidget
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
TestWidgetHFW( const SGVec2i& min_size,
|
|
||||||
const SGVec2i& size_hint,
|
|
||||||
const SGVec2i& max_size = MAX_SIZE ):
|
|
||||||
TestWidget(min_size, size_hint, max_size)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual bool hasHeightForWidth() const
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual int heightForWidth(int w) const
|
|
||||||
{
|
|
||||||
return _size_hint.x() * _size_hint.y() / w;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual int minimumHeightForWidth(int w) const
|
|
||||||
{
|
|
||||||
return _min_size.x() * _min_size.y() / w;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef SGSharedPtr<TestWidget> TestWidgetRef;
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
BOOST_AUTO_TEST_CASE( horizontal_layout )
|
|
||||||
{
|
|
||||||
sc::BoxLayout box_layout(sc::BoxLayout::BottomToTop);
|
|
||||||
box_layout.setSpacing(5);
|
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(box_layout.direction(), sc::BoxLayout::BottomToTop);
|
|
||||||
BOOST_CHECK_EQUAL(box_layout.spacing(), 5);
|
|
||||||
|
|
||||||
box_layout.setDirection(sc::BoxLayout::LeftToRight);
|
|
||||||
box_layout.setSpacing(9);
|
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(box_layout.direction(), sc::BoxLayout::LeftToRight);
|
|
||||||
BOOST_CHECK_EQUAL(box_layout.spacing(), 9);
|
|
||||||
|
|
||||||
TestWidgetRef fixed_size_widget( new TestWidget( SGVec2i(16, 16),
|
|
||||||
SGVec2i(16, 16),
|
|
||||||
SGVec2i(16, 16) ) );
|
|
||||||
box_layout.addItem(fixed_size_widget);
|
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(box_layout.minimumSize(), SGVec2i(16, 16));
|
|
||||||
BOOST_CHECK_EQUAL(box_layout.sizeHint(), SGVec2i(16, 16));
|
|
||||||
BOOST_CHECK_EQUAL(box_layout.maximumSize(), SGVec2i(16, 16));
|
|
||||||
|
|
||||||
TestWidgetRef limited_resize_widget( new TestWidget( SGVec2i(16, 16),
|
|
||||||
SGVec2i(32, 32),
|
|
||||||
SGVec2i(256, 64) ) );
|
|
||||||
box_layout.addItem(limited_resize_widget);
|
|
||||||
|
|
||||||
// Combined sizes of both widget plus the padding between them
|
|
||||||
BOOST_CHECK_EQUAL(box_layout.minimumSize(), SGVec2i(41, 16));
|
|
||||||
BOOST_CHECK_EQUAL(box_layout.sizeHint(), SGVec2i(57, 32));
|
|
||||||
BOOST_CHECK_EQUAL(box_layout.maximumSize(), SGVec2i(281, 64));
|
|
||||||
|
|
||||||
// Test with different spacing/padding
|
|
||||||
box_layout.setSpacing(5);
|
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(box_layout.minimumSize(), SGVec2i(37, 16));
|
|
||||||
BOOST_CHECK_EQUAL(box_layout.sizeHint(), SGVec2i(53, 32));
|
|
||||||
BOOST_CHECK_EQUAL(box_layout.maximumSize(), SGVec2i(277, 64));
|
|
||||||
|
|
||||||
box_layout.setGeometry(SGRecti(0, 0, 128, 32));
|
|
||||||
|
|
||||||
// Fixed size for first widget and remaining space goes to second widget
|
|
||||||
BOOST_CHECK_EQUAL(fixed_size_widget->geometry(), SGRecti(0, 8, 16, 16));
|
|
||||||
BOOST_CHECK_EQUAL(limited_resize_widget->geometry(), SGRecti(21, 0, 107, 32));
|
|
||||||
|
|
||||||
TestWidgetRef stretch_widget( new TestWidget( SGVec2i(16, 16),
|
|
||||||
SGVec2i(32, 32),
|
|
||||||
SGVec2i(128, 32) ) );
|
|
||||||
box_layout.addItem(stretch_widget, 1);
|
|
||||||
box_layout.update();
|
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(box_layout.minimumSize(), SGVec2i(58, 16));
|
|
||||||
BOOST_CHECK_EQUAL(box_layout.sizeHint(), SGVec2i(90, 32));
|
|
||||||
BOOST_CHECK_EQUAL(box_layout.maximumSize(), SGVec2i(410, 64));
|
|
||||||
|
|
||||||
// Due to the stretch factor only the last widget gets additional space. All
|
|
||||||
// other widgets get the preferred size.
|
|
||||||
BOOST_CHECK_EQUAL(fixed_size_widget->geometry(), SGRecti(0, 8, 16, 16));
|
|
||||||
BOOST_CHECK_EQUAL(limited_resize_widget->geometry(), SGRecti(21, 0, 32, 32));
|
|
||||||
BOOST_CHECK_EQUAL(stretch_widget->geometry(), SGRecti(58, 0, 70, 32));
|
|
||||||
|
|
||||||
// Test stretch factor
|
|
||||||
TestWidgetRef fast_stretch( new TestWidget(*stretch_widget) );
|
|
||||||
sc::BoxLayout box_layout_stretch(sc::BoxLayout::LeftToRight);
|
|
||||||
|
|
||||||
box_layout_stretch.addItem(stretch_widget, 1);
|
|
||||||
box_layout_stretch.addItem(fast_stretch, 2);
|
|
||||||
|
|
||||||
box_layout_stretch.setGeometry(SGRecti(0,0,128,32));
|
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(stretch_widget->geometry(), SGRecti(0, 0, 41, 32));
|
|
||||||
BOOST_CHECK_EQUAL(fast_stretch->geometry(), SGRecti(46, 0, 82, 32));
|
|
||||||
|
|
||||||
box_layout_stretch.setGeometry(SGRecti(0,0,256,32));
|
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(stretch_widget->geometry(), SGRecti(0, 0, 123, 32));
|
|
||||||
BOOST_CHECK_EQUAL(fast_stretch->geometry(), SGRecti(128, 0, 128, 32));
|
|
||||||
|
|
||||||
// Test superflous space to padding
|
|
||||||
box_layout_stretch.setGeometry(SGRecti(0,0,512,32));
|
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(stretch_widget->geometry(), SGRecti(83, 0, 128, 32));
|
|
||||||
BOOST_CHECK_EQUAL(fast_stretch->geometry(), SGRecti(300, 0, 128, 32));
|
|
||||||
|
|
||||||
// Test more space then preferred, but less than maximum
|
|
||||||
{
|
|
||||||
sc::HBoxLayout hbox;
|
|
||||||
TestWidgetRef w1( new TestWidget( SGVec2i(16, 16),
|
|
||||||
SGVec2i(32, 32),
|
|
||||||
SGVec2i(9999, 32) ) ),
|
|
||||||
w2( new TestWidget(*w1) );
|
|
||||||
|
|
||||||
hbox.addItem(w1);
|
|
||||||
hbox.addItem(w2);
|
|
||||||
|
|
||||||
hbox.setGeometry( SGRecti(0, 0, 256, 32) );
|
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(w1->geometry(), SGRecti(0, 0, 126, 32));
|
|
||||||
BOOST_CHECK_EQUAL(w2->geometry(), SGRecti(131, 0, 125, 32));
|
|
||||||
|
|
||||||
hbox.setStretch(0, 1);
|
|
||||||
hbox.setStretch(1, 1);
|
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(hbox.stretch(0), 1);
|
|
||||||
BOOST_CHECK_EQUAL(hbox.stretch(1), 1);
|
|
||||||
|
|
||||||
hbox.update();
|
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(w1->geometry(), SGRecti(0, 0, 125, 32));
|
|
||||||
BOOST_CHECK_EQUAL(w2->geometry(), SGRecti(130, 0, 126, 32));
|
|
||||||
|
|
||||||
BOOST_REQUIRE( hbox.setStretchFactor(w1, 2) );
|
|
||||||
BOOST_REQUIRE( hbox.setStretchFactor(w2, 3) );
|
|
||||||
BOOST_CHECK_EQUAL(hbox.stretch(0), 2);
|
|
||||||
BOOST_CHECK_EQUAL(hbox.stretch(1), 3);
|
|
||||||
|
|
||||||
hbox.removeItem(w1);
|
|
||||||
|
|
||||||
BOOST_CHECK( !hbox.setStretchFactor(w1, 0) );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
BOOST_AUTO_TEST_CASE( spacer_layouting )
|
|
||||||
{
|
|
||||||
sc::HBoxLayout hbox;
|
|
||||||
TestWidgetRef w1( new TestWidget( SGVec2i(16, 16),
|
|
||||||
SGVec2i(32, 32),
|
|
||||||
SGVec2i(9999, 9999) ) ),
|
|
||||||
w2( new TestWidget(*w1) );
|
|
||||||
|
|
||||||
hbox.addItem(w1);
|
|
||||||
hbox.addItem(w2);
|
|
||||||
hbox.addStretch(1);
|
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(hbox.minimumSize(), SGVec2i(37, 16));
|
|
||||||
BOOST_CHECK_EQUAL(hbox.sizeHint(), SGVec2i(69, 32));
|
|
||||||
BOOST_CHECK_EQUAL(hbox.maximumSize(), sc::LayoutItem::MAX_SIZE);
|
|
||||||
|
|
||||||
hbox.setGeometry(SGRecti(0, 0, 256, 40));
|
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(w1->geometry(), SGRecti(0, 0, 32, 40));
|
|
||||||
BOOST_CHECK_EQUAL(w2->geometry(), SGRecti(37, 0, 32, 40));
|
|
||||||
|
|
||||||
// now center with increased spacing between both widgets
|
|
||||||
hbox.insertStretch(0, 1);
|
|
||||||
hbox.insertSpacing(2, 10);
|
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(hbox.minimumSize(), SGVec2i(47, 16));
|
|
||||||
BOOST_CHECK_EQUAL(hbox.sizeHint(), SGVec2i(79, 32));
|
|
||||||
BOOST_CHECK_EQUAL(hbox.maximumSize(), sc::LayoutItem::MAX_SIZE);
|
|
||||||
|
|
||||||
hbox.update();
|
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(w1->geometry(), SGRecti(88, 0, 32, 40));
|
|
||||||
BOOST_CHECK_EQUAL(w2->geometry(), SGRecti(135, 0, 32, 40));
|
|
||||||
}
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
BOOST_AUTO_TEST_CASE( vertical_layout)
|
|
||||||
{
|
|
||||||
sc::BoxLayout vbox(sc::BoxLayout::TopToBottom);
|
|
||||||
vbox.setSpacing(7);
|
|
||||||
|
|
||||||
TestWidgetRef fixed_size_widget( new TestWidget( SGVec2i(16, 16),
|
|
||||||
SGVec2i(16, 16),
|
|
||||||
SGVec2i(16, 16) ) );
|
|
||||||
TestWidgetRef limited_resize_widget( new TestWidget( SGVec2i(16, 16),
|
|
||||||
SGVec2i(32, 32),
|
|
||||||
SGVec2i(256, 64) ) );
|
|
||||||
|
|
||||||
vbox.addItem(fixed_size_widget);
|
|
||||||
vbox.addItem(limited_resize_widget);
|
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(vbox.minimumSize(), SGVec2i(16, 39));
|
|
||||||
BOOST_CHECK_EQUAL(vbox.sizeHint(), SGVec2i(32, 55));
|
|
||||||
BOOST_CHECK_EQUAL(vbox.maximumSize(), SGVec2i(256, 87));
|
|
||||||
|
|
||||||
vbox.setGeometry(SGRecti(10, 20, 16, 55));
|
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(fixed_size_widget->geometry(), SGRecti(10, 20, 16, 16));
|
|
||||||
BOOST_CHECK_EQUAL(limited_resize_widget->geometry(), SGRecti(10, 43, 16, 32));
|
|
||||||
|
|
||||||
vbox.setDirection(sc::BoxLayout::BottomToTop);
|
|
||||||
}
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
BOOST_AUTO_TEST_CASE( boxlayout_insert_remove )
|
|
||||||
{
|
|
||||||
sc::HBoxLayout hbox;
|
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(hbox.count(), 0);
|
|
||||||
BOOST_CHECK(!hbox.itemAt(0));
|
|
||||||
BOOST_CHECK(!hbox.takeAt(0));
|
|
||||||
|
|
||||||
TestWidgetRef w1( new TestWidget( SGVec2i(16, 16),
|
|
||||||
SGVec2i(32, 32),
|
|
||||||
SGVec2i(9999, 32) ) ),
|
|
||||||
w2( new TestWidget(*w1) );
|
|
||||||
|
|
||||||
hbox.addItem(w1);
|
|
||||||
BOOST_CHECK_EQUAL(hbox.count(), 1);
|
|
||||||
BOOST_CHECK_EQUAL(hbox.itemAt(0), w1);
|
|
||||||
|
|
||||||
hbox.insertItem(0, w2);
|
|
||||||
BOOST_CHECK_EQUAL(hbox.count(), 2);
|
|
||||||
BOOST_CHECK_EQUAL(hbox.itemAt(0), w2);
|
|
||||||
BOOST_CHECK_EQUAL(hbox.itemAt(1), w1);
|
|
||||||
|
|
||||||
hbox.removeItem(w2);
|
|
||||||
BOOST_CHECK_EQUAL(hbox.count(), 1);
|
|
||||||
BOOST_CHECK_EQUAL(hbox.itemAt(0), w1);
|
|
||||||
|
|
||||||
hbox.addItem(w2);
|
|
||||||
BOOST_CHECK_EQUAL(hbox.count(), 2);
|
|
||||||
|
|
||||||
hbox.clear();
|
|
||||||
BOOST_CHECK_EQUAL(hbox.count(), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
BOOST_AUTO_TEST_CASE( boxlayout_hfw )
|
|
||||||
{
|
|
||||||
TestWidgetRef w1( new TestWidgetHFW( SGVec2i(16, 16),
|
|
||||||
SGVec2i(32, 32) ) ),
|
|
||||||
w2( new TestWidgetHFW( SGVec2i(24, 24),
|
|
||||||
SGVec2i(48, 48) ) );
|
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(w1->heightForWidth(16), 64);
|
|
||||||
BOOST_CHECK_EQUAL(w1->minimumHeightForWidth(16), 16);
|
|
||||||
BOOST_CHECK_EQUAL(w2->heightForWidth(24), 96);
|
|
||||||
BOOST_CHECK_EQUAL(w2->minimumHeightForWidth(24), 24);
|
|
||||||
|
|
||||||
TestWidgetRef w_no_hfw( new TestWidget( SGVec2i(16, 16),
|
|
||||||
SGVec2i(32, 32) ) );
|
|
||||||
BOOST_CHECK(!w_no_hfw->hasHeightForWidth());
|
|
||||||
BOOST_CHECK_EQUAL(w_no_hfw->heightForWidth(16), -1);
|
|
||||||
BOOST_CHECK_EQUAL(w_no_hfw->minimumHeightForWidth(16), -1);
|
|
||||||
|
|
||||||
// horizontal
|
|
||||||
sc::HBoxLayout hbox;
|
|
||||||
hbox.setSpacing(5);
|
|
||||||
hbox.addItem(w1);
|
|
||||||
hbox.addItem(w2);
|
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(hbox.heightForWidth(45), w2->heightForWidth(24));
|
|
||||||
BOOST_CHECK_EQUAL(hbox.heightForWidth(85), w2->heightForWidth(48));
|
|
||||||
|
|
||||||
hbox.addItem(w_no_hfw);
|
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(hbox.heightForWidth(66), 96);
|
|
||||||
BOOST_CHECK_EQUAL(hbox.heightForWidth(122), 48);
|
|
||||||
BOOST_CHECK_EQUAL(hbox.minimumHeightForWidth(66), 24);
|
|
||||||
BOOST_CHECK_EQUAL(hbox.minimumHeightForWidth(122), 16);
|
|
||||||
|
|
||||||
hbox.setGeometry(SGRecti(0, 0, 66, 24));
|
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(w1->geometry(), SGRecti(0, 0, 16, 24));
|
|
||||||
BOOST_CHECK_EQUAL(w2->geometry(), SGRecti(21, 0, 24, 24));
|
|
||||||
BOOST_CHECK_EQUAL(w_no_hfw->geometry(), SGRecti(50, 0, 16, 24));
|
|
||||||
|
|
||||||
// vertical
|
|
||||||
sc::VBoxLayout vbox;
|
|
||||||
vbox.setSpacing(5);
|
|
||||||
vbox.addItem(w1);
|
|
||||||
vbox.addItem(w2);
|
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(vbox.heightForWidth(24), 143);
|
|
||||||
BOOST_CHECK_EQUAL(vbox.heightForWidth(48), 74);
|
|
||||||
BOOST_CHECK_EQUAL(vbox.minimumHeightForWidth(24), 39);
|
|
||||||
BOOST_CHECK_EQUAL(vbox.minimumHeightForWidth(48), 22);
|
|
||||||
|
|
||||||
vbox.addItem(w_no_hfw);
|
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(vbox.heightForWidth(24), 180);
|
|
||||||
BOOST_CHECK_EQUAL(vbox.heightForWidth(48), 111);
|
|
||||||
BOOST_CHECK_EQUAL(vbox.minimumHeightForWidth(24), 60);
|
|
||||||
BOOST_CHECK_EQUAL(vbox.minimumHeightForWidth(48), 43);
|
|
||||||
|
|
||||||
SGVec2i min_size = vbox.minimumSize(),
|
|
||||||
size_hint = vbox.sizeHint();
|
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(min_size, SGVec2i(24, 66));
|
|
||||||
BOOST_CHECK_EQUAL(size_hint, SGVec2i(48, 122));
|
|
||||||
|
|
||||||
vbox.setGeometry(SGRecti(0, 0, 24, 122));
|
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(w1->geometry(), SGRecti(0, 0, 24, 33));
|
|
||||||
BOOST_CHECK_EQUAL(w2->geometry(), SGRecti(0, 38, 24, 47));
|
|
||||||
BOOST_CHECK_EQUAL(w_no_hfw->geometry(), SGRecti(0, 90, 24, 32));
|
|
||||||
|
|
||||||
// Vertical layouting modifies size hints, so check if they are correctly
|
|
||||||
// restored
|
|
||||||
BOOST_CHECK_EQUAL(min_size, vbox.minimumSize());
|
|
||||||
BOOST_CHECK_EQUAL(size_hint, vbox.sizeHint());
|
|
||||||
|
|
||||||
vbox.setGeometry(SGRecti(0, 0, 50, 122));
|
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(w1->geometry(), SGRecti(0, 0, 50, 25));
|
|
||||||
BOOST_CHECK_EQUAL(w2->geometry(), SGRecti(0, 30, 50, 51));
|
|
||||||
BOOST_CHECK_EQUAL(w_no_hfw->geometry(), SGRecti(0, 86, 50, 36));
|
|
||||||
|
|
||||||
// Same geometry as before -> should get same widget geometry
|
|
||||||
// (check internal size hint cache updates correctly)
|
|
||||||
vbox.setGeometry(SGRecti(0, 0, 24, 122));
|
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(w1->geometry(), SGRecti(0, 0, 24, 33));
|
|
||||||
BOOST_CHECK_EQUAL(w2->geometry(), SGRecti(0, 38, 24, 47));
|
|
||||||
BOOST_CHECK_EQUAL(w_no_hfw->geometry(), SGRecti(0, 90, 24, 32));
|
|
||||||
}
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
BOOST_AUTO_TEST_CASE( nasal_widget )
|
|
||||||
{
|
|
||||||
naContext c = naNewContext();
|
|
||||||
naRef me = naNewHash(c);
|
|
||||||
|
|
||||||
sc::NasalWidgetRef w( new sc::NasalWidget(me) );
|
|
||||||
|
|
||||||
// Default layout sizes (no user set values)
|
|
||||||
BOOST_CHECK_EQUAL(w->minimumSize(), SGVec2i(16, 16));
|
|
||||||
BOOST_CHECK_EQUAL(w->sizeHint(), SGVec2i(32, 32));
|
|
||||||
BOOST_CHECK_EQUAL(w->maximumSize(), sc::LayoutItem::MAX_SIZE);
|
|
||||||
|
|
||||||
// Changed layout sizes
|
|
||||||
w->setLayoutMinimumSize( SGVec2i(2, 12) );
|
|
||||||
w->setLayoutSizeHint( SGVec2i(3, 13) );
|
|
||||||
w->setLayoutMaximumSize( SGVec2i(4, 14) );
|
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(w->minimumSize(), SGVec2i(2, 12));
|
|
||||||
BOOST_CHECK_EQUAL(w->sizeHint(), SGVec2i(3, 13));
|
|
||||||
BOOST_CHECK_EQUAL(w->maximumSize(), SGVec2i(4, 14));
|
|
||||||
|
|
||||||
// User set values (overwrite layout sizes)
|
|
||||||
w->setMinimumSize( SGVec2i(15, 16) );
|
|
||||||
w->setSizeHint( SGVec2i(17, 18) );
|
|
||||||
w->setMaximumSize( SGVec2i(19, 20) );
|
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(w->minimumSize(), SGVec2i(15, 16));
|
|
||||||
BOOST_CHECK_EQUAL(w->sizeHint(), SGVec2i(17, 18));
|
|
||||||
BOOST_CHECK_EQUAL(w->maximumSize(), SGVec2i(19, 20));
|
|
||||||
|
|
||||||
// Only vertical user set values (layout/default for horizontal hints)
|
|
||||||
w->setMinimumSize( SGVec2i(0, 21) );
|
|
||||||
w->setSizeHint( SGVec2i(0, 22) );
|
|
||||||
w->setMaximumSize( SGVec2i(SGLimits<int>::max(), 23) );
|
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(w->minimumSize(), SGVec2i(2, 21));
|
|
||||||
BOOST_CHECK_EQUAL(w->sizeHint(), SGVec2i(3, 22));
|
|
||||||
BOOST_CHECK_EQUAL(w->maximumSize(), SGVec2i(4, 23));
|
|
||||||
|
|
||||||
naFreeContext(c);
|
|
||||||
}
|
|
||||||
@@ -31,8 +31,7 @@ typedef enum {
|
|||||||
SG_ENVIRONMENT = 0x00100000,
|
SG_ENVIRONMENT = 0x00100000,
|
||||||
SG_SOUND = 0x00200000,
|
SG_SOUND = 0x00200000,
|
||||||
SG_NAVAID = 0x00400000,
|
SG_NAVAID = 0x00400000,
|
||||||
SG_GUI = 0x00800000,
|
SG_UNDEFD = 0x00800000, // For range checking
|
||||||
SG_UNDEFD = 0x01000000, // For range checking
|
|
||||||
|
|
||||||
SG_ALL = 0xFFFFFFFF
|
SG_ALL = 0xFFFFFFFF
|
||||||
} sgDebugClass;
|
} sgDebugClass;
|
||||||
|
|||||||
@@ -70,7 +70,6 @@ const char* debugClassToString(sgDebugClass c)
|
|||||||
case SG_ENVIRONMENT:return "environment";
|
case SG_ENVIRONMENT:return "environment";
|
||||||
case SG_SOUND: return "sound";
|
case SG_SOUND: return "sound";
|
||||||
case SG_NAVAID: return "navaid";
|
case SG_NAVAID: return "navaid";
|
||||||
case SG_GUI: return "gui";
|
|
||||||
default: return "unknown";
|
default: return "unknown";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -122,28 +122,27 @@ public:
|
|||||||
// socket-level errors
|
// socket-level errors
|
||||||
virtual void handleError(int error)
|
virtual void handleError(int error)
|
||||||
{
|
{
|
||||||
const char* errStr = strerror(error);
|
if (error == ENOENT) {
|
||||||
if (!activeRequest)
|
// name lookup failure
|
||||||
{
|
// we won't have an active request yet, so the logic below won't
|
||||||
// connection level failure, eg name lookup or routing
|
// fire to actually call setFailure. Let's fail all of the requests
|
||||||
// we won't have an active request yet, so let's fail all of the
|
|
||||||
// requests since we presume it's a systematic failure for
|
|
||||||
// the host in question
|
|
||||||
BOOST_FOREACH(Request_ptr req, sentRequests) {
|
BOOST_FOREACH(Request_ptr req, sentRequests) {
|
||||||
req->setFailure(error, errStr);
|
req->setFailure(error, "hostname lookup failure");
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_FOREACH(Request_ptr req, queuedRequests) {
|
BOOST_FOREACH(Request_ptr req, queuedRequests) {
|
||||||
req->setFailure(error, errStr);
|
req->setFailure(error, "hostname lookup failure");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// name lookup failure, abandon all requests on this connection
|
||||||
sentRequests.clear();
|
sentRequests.clear();
|
||||||
queuedRequests.clear();
|
queuedRequests.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
NetChat::handleError(error);
|
NetChat::handleError(error);
|
||||||
if (activeRequest) {
|
if (activeRequest) {
|
||||||
activeRequest->setFailure(error, errStr);
|
SG_LOG(SG_IO, SG_INFO, "HTTP socket error");
|
||||||
|
activeRequest->setFailure(error, "socket error");
|
||||||
activeRequest = NULL;
|
activeRequest = NULL;
|
||||||
_contentDecoder.reset();
|
_contentDecoder.reset();
|
||||||
}
|
}
|
||||||
@@ -253,7 +252,6 @@ public:
|
|||||||
|
|
||||||
if (state == STATE_CLOSED) {
|
if (state == STATE_CLOSED) {
|
||||||
if (!connectToHost()) {
|
if (!connectToHost()) {
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ Request* Request::done(const Callback& cb)
|
|||||||
if( _ready_state == DONE )
|
if( _ready_state == DONE )
|
||||||
cb(this);
|
cb(this);
|
||||||
else
|
else
|
||||||
_cb_done.push_back(cb);
|
_cb_done = cb;
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@@ -50,7 +50,7 @@ Request* Request::fail(const Callback& cb)
|
|||||||
if( _ready_state == FAILED )
|
if( _ready_state == FAILED )
|
||||||
cb(this);
|
cb(this);
|
||||||
else
|
else
|
||||||
_cb_fail.push_back(cb);
|
_cb_fail = cb;
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@@ -61,7 +61,7 @@ Request* Request::always(const Callback& cb)
|
|||||||
if( isComplete() )
|
if( isComplete() )
|
||||||
cb(this);
|
cb(this);
|
||||||
else
|
else
|
||||||
_cb_always.push_back(cb);
|
_cb_always = cb;
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@@ -272,16 +272,6 @@ std::string Request::hostAndPort() const
|
|||||||
return u.substr(schemeEnd + 3, hostEnd - (schemeEnd + 3));
|
return u.substr(schemeEnd + 3, hostEnd - (schemeEnd + 3));
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
std::string Request::responseMime() const
|
|
||||||
{
|
|
||||||
std::string content_type = _responseHeaders.get("content-type");
|
|
||||||
if( content_type.empty() )
|
|
||||||
return "application/octet-stream";
|
|
||||||
|
|
||||||
return content_type.substr(0, content_type.find(';'));
|
|
||||||
}
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
void Request::setResponseLength(unsigned int l)
|
void Request::setResponseLength(unsigned int l)
|
||||||
{
|
{
|
||||||
@@ -304,8 +294,6 @@ void Request::setFailure(int code, const std::string& reason)
|
|||||||
{
|
{
|
||||||
_responseStatus = code;
|
_responseStatus = code;
|
||||||
_responseReason = reason;
|
_responseReason = reason;
|
||||||
|
|
||||||
if( !isComplete() )
|
|
||||||
setReadyState(FAILED);
|
setReadyState(FAILED);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -321,6 +309,7 @@ void Request::setReadyState(ReadyState state)
|
|||||||
onDone();
|
onDone();
|
||||||
onAlways();
|
onAlways();
|
||||||
|
|
||||||
|
if( _cb_done )
|
||||||
_cb_done(this);
|
_cb_done(this);
|
||||||
}
|
}
|
||||||
else if( state == FAILED )
|
else if( state == FAILED )
|
||||||
@@ -328,11 +317,13 @@ void Request::setReadyState(ReadyState state)
|
|||||||
onFail();
|
onFail();
|
||||||
onAlways();
|
onAlways();
|
||||||
|
|
||||||
|
if( _cb_fail )
|
||||||
_cb_fail(this);
|
_cb_fail(this);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if( _cb_always )
|
||||||
_cb_always(this);
|
_cb_always(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -345,6 +336,9 @@ void Request::abort()
|
|||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
void Request::abort(const std::string& reason)
|
void Request::abort(const std::string& reason)
|
||||||
{
|
{
|
||||||
|
if( isComplete() )
|
||||||
|
return;
|
||||||
|
|
||||||
setFailure(-1, reason);
|
setFailure(-1, reason);
|
||||||
_willClose = true;
|
_willClose = true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,13 +3,12 @@
|
|||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
#include <simgear/structure/function_list.hxx>
|
|
||||||
#include <simgear/structure/map.hxx>
|
#include <simgear/structure/map.hxx>
|
||||||
#include <simgear/structure/SGReferenced.hxx>
|
#include <simgear/structure/SGReferenced.hxx>
|
||||||
#include <simgear/structure/SGSharedPtr.hxx>
|
#include <simgear/structure/SGSharedPtr.hxx>
|
||||||
#include <simgear/math/sg_types.hxx>
|
#include <simgear/math/sg_types.hxx>
|
||||||
|
|
||||||
#include <boost/bind.hpp>
|
#include <boost/function.hpp>
|
||||||
|
|
||||||
class SGPropertyNode;
|
class SGPropertyNode;
|
||||||
|
|
||||||
@@ -47,21 +46,15 @@ public:
|
|||||||
{ return _request_headers.get(key); }
|
{ return _request_headers.get(key); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a handler to be called when the request successfully completes.
|
* Set the handler to be called when the request successfully completes.
|
||||||
*
|
*
|
||||||
* @note If the request is already complete, the handler is called
|
* @note If the request is already complete, the handler is called
|
||||||
* immediately.
|
* immediately.
|
||||||
*/
|
*/
|
||||||
Request* done(const Callback& cb);
|
Request* done(const Callback& cb);
|
||||||
|
|
||||||
template<class C>
|
|
||||||
Request* done(C* instance, void (C::*mem_func)(Request*))
|
|
||||||
{
|
|
||||||
return done(boost::bind(mem_func, instance, _1));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a handler to be called when the request completes or aborts with an
|
* Set the handler to be called when the request completes or aborts with an
|
||||||
* error.
|
* error.
|
||||||
*
|
*
|
||||||
* @note If the request has already failed, the handler is called
|
* @note If the request has already failed, the handler is called
|
||||||
@@ -69,27 +62,15 @@ public:
|
|||||||
*/
|
*/
|
||||||
Request* fail(const Callback& cb);
|
Request* fail(const Callback& cb);
|
||||||
|
|
||||||
template<class C>
|
|
||||||
Request* fail(C* instance, void (C::*mem_func)(Request*))
|
|
||||||
{
|
|
||||||
return fail(boost::bind(mem_func, instance, _1));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a handler to be called when the request either successfully completes
|
* Set the handler to be called when the request either successfully
|
||||||
* or fails.
|
* completes or fails.
|
||||||
*
|
*
|
||||||
* @note If the request is already complete or has already failed, the
|
* @note If the request is already complete or has already failed, the
|
||||||
* handler is called immediately.
|
* handler is called immediately.
|
||||||
*/
|
*/
|
||||||
Request* always(const Callback& cb);
|
Request* always(const Callback& cb);
|
||||||
|
|
||||||
template<class C>
|
|
||||||
Request* always(C* instance, void (C::*mem_func)(Request*))
|
|
||||||
{
|
|
||||||
return always(boost::bind(mem_func, instance, _1));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the data for the body of the request. The request is automatically
|
* Set the data for the body of the request. The request is automatically
|
||||||
* send using the POST method.
|
* send using the POST method.
|
||||||
@@ -118,8 +99,6 @@ public:
|
|||||||
StringMap const& responseHeaders() const
|
StringMap const& responseHeaders() const
|
||||||
{ return _responseHeaders; }
|
{ return _responseHeaders; }
|
||||||
|
|
||||||
std::string responseMime() const;
|
|
||||||
|
|
||||||
virtual int responseCode() const
|
virtual int responseCode() const
|
||||||
{ return _responseStatus; }
|
{ return _responseStatus; }
|
||||||
|
|
||||||
@@ -224,7 +203,7 @@ private:
|
|||||||
unsigned int _responseLength;
|
unsigned int _responseLength;
|
||||||
unsigned int _receivedBodyBytes;
|
unsigned int _receivedBodyBytes;
|
||||||
|
|
||||||
function_list<Callback> _cb_done,
|
Callback _cb_done,
|
||||||
_cb_fail,
|
_cb_fail,
|
||||||
_cb_always;
|
_cb_always;
|
||||||
|
|
||||||
|
|||||||
@@ -97,12 +97,12 @@ int main( int argc, char **argv ) {
|
|||||||
string_list tri_materials = obj.get_tri_materials();
|
string_list tri_materials = obj.get_tri_materials();
|
||||||
group_list tris_v = obj.get_tris_v();
|
group_list tris_v = obj.get_tris_v();
|
||||||
group_list tris_n = obj.get_tris_n();
|
group_list tris_n = obj.get_tris_n();
|
||||||
group_tci_list tris_tc = obj.get_tris_tcs();
|
group_list tris_tc = obj.get_tris_tc();
|
||||||
for ( i = 0; i < (int)tris_v.size(); ++i ) {
|
for ( i = 0; i < (int)tris_v.size(); ++i ) {
|
||||||
material = tri_materials[i];
|
material = tri_materials[i];
|
||||||
vertex_index = tris_v[i];
|
vertex_index = tris_v[i];
|
||||||
normal_index = tris_n[i];
|
normal_index = tris_n[i];
|
||||||
tex_index = tris_tc[0][i];
|
tex_index = tris_tc[i];
|
||||||
cout << "# usemtl " << material << endl;
|
cout << "# usemtl " << material << endl;
|
||||||
cout << "f ";
|
cout << "f ";
|
||||||
for ( j = 0; j < (int)vertex_index.size(); ++j ) {
|
for ( j = 0; j < (int)vertex_index.size(); ++j ) {
|
||||||
@@ -120,12 +120,12 @@ int main( int argc, char **argv ) {
|
|||||||
string_list strip_materials = obj.get_strip_materials();
|
string_list strip_materials = obj.get_strip_materials();
|
||||||
group_list strips_v = obj.get_strips_v();
|
group_list strips_v = obj.get_strips_v();
|
||||||
group_list strips_n = obj.get_strips_n();
|
group_list strips_n = obj.get_strips_n();
|
||||||
group_tci_list strips_tc = obj.get_strips_tcs();
|
group_list strips_tc = obj.get_strips_tc();
|
||||||
for ( i = 0; i < (int)strips_v.size(); ++i ) {
|
for ( i = 0; i < (int)strips_v.size(); ++i ) {
|
||||||
material = strip_materials[i];
|
material = strip_materials[i];
|
||||||
vertex_index = strips_v[i];
|
vertex_index = strips_v[i];
|
||||||
normal_index = strips_n[i];
|
normal_index = strips_n[i];
|
||||||
tex_index = strips_tc[0][i];
|
tex_index = strips_tc[i];
|
||||||
cout << "# usemtl " << material << endl;
|
cout << "# usemtl " << material << endl;
|
||||||
cout << "ts ";
|
cout << "ts ";
|
||||||
for ( j = 0; j < (int)vertex_index.size(); ++j ) {
|
for ( j = 0; j < (int)vertex_index.size(); ++j ) {
|
||||||
@@ -142,12 +142,12 @@ int main( int argc, char **argv ) {
|
|||||||
string_list fan_materials = obj.get_fan_materials();
|
string_list fan_materials = obj.get_fan_materials();
|
||||||
group_list fans_v = obj.get_fans_v();
|
group_list fans_v = obj.get_fans_v();
|
||||||
group_list fans_n = obj.get_fans_n();
|
group_list fans_n = obj.get_fans_n();
|
||||||
group_tci_list fans_tc = obj.get_fans_tcs();
|
group_list fans_tc = obj.get_fans_tc();
|
||||||
for ( i = 0; i < (int)fans_v.size(); ++i ) {
|
for ( i = 0; i < (int)fans_v.size(); ++i ) {
|
||||||
material = fan_materials[i];
|
material = fan_materials[i];
|
||||||
vertex_index = fans_v[i];
|
vertex_index = fans_v[i];
|
||||||
normal_index = fans_n[i];
|
normal_index = fans_n[i];
|
||||||
tex_index = fans_tc[0][i];
|
tex_index = fans_tc[i];
|
||||||
cout << "# usemtl " << material << endl;
|
cout << "# usemtl " << material << endl;
|
||||||
cout << "tf ";
|
cout << "tf ";
|
||||||
for ( j = 0; j < (int)vertex_index.size(); ++j ) {
|
for ( j = 0; j < (int)vertex_index.size(); ++j ) {
|
||||||
|
|||||||
+73
-291
@@ -58,11 +58,9 @@ enum sgObjectTypes {
|
|||||||
SG_BOUNDING_SPHERE = 0,
|
SG_BOUNDING_SPHERE = 0,
|
||||||
|
|
||||||
SG_VERTEX_LIST = 1,
|
SG_VERTEX_LIST = 1,
|
||||||
|
SG_COLOR_LIST = 4,
|
||||||
SG_NORMAL_LIST = 2,
|
SG_NORMAL_LIST = 2,
|
||||||
SG_TEXCOORD_LIST = 3,
|
SG_TEXCOORD_LIST = 3,
|
||||||
SG_COLOR_LIST = 4,
|
|
||||||
SG_VA_FLOAT_LIST = 5,
|
|
||||||
SG_VA_INTEGER_LIST = 6,
|
|
||||||
|
|
||||||
SG_POINTS = 9,
|
SG_POINTS = 9,
|
||||||
|
|
||||||
@@ -75,29 +73,12 @@ enum sgIndexTypes {
|
|||||||
SG_IDX_VERTICES = 0x01,
|
SG_IDX_VERTICES = 0x01,
|
||||||
SG_IDX_NORMALS = 0x02,
|
SG_IDX_NORMALS = 0x02,
|
||||||
SG_IDX_COLORS = 0x04,
|
SG_IDX_COLORS = 0x04,
|
||||||
SG_IDX_TEXCOORDS_0 = 0x08,
|
SG_IDX_TEXCOORDS = 0x08
|
||||||
SG_IDX_TEXCOORDS_1 = 0x10,
|
|
||||||
SG_IDX_TEXCOORDS_2 = 0x20,
|
|
||||||
SG_IDX_TEXCOORDS_3 = 0x40,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum sgVertexAttributeTypes {
|
|
||||||
// vertex attributes
|
|
||||||
SG_VA_INTEGER_0 = 0x00000001,
|
|
||||||
SG_VA_INTEGER_1 = 0x00000002,
|
|
||||||
SG_VA_INTEGER_2 = 0x00000004,
|
|
||||||
SG_VA_INTEGER_3 = 0x00000008,
|
|
||||||
|
|
||||||
SG_VA_FLOAT_0 = 0x00000100,
|
|
||||||
SG_VA_FLOAT_1 = 0x00000200,
|
|
||||||
SG_VA_FLOAT_2 = 0x00000400,
|
|
||||||
SG_VA_FLOAT_3 = 0x00000800,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum sgPropertyTypes {
|
enum sgPropertyTypes {
|
||||||
SG_MATERIAL = 0,
|
SG_MATERIAL = 0,
|
||||||
SG_INDEX_TYPES = 1,
|
SG_INDEX_TYPES = 1
|
||||||
SG_VERT_ATTRIBS = 2
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -149,17 +130,6 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
float readInt()
|
|
||||||
{
|
|
||||||
unsigned int* p = reinterpret_cast<unsigned int*>(ptr + offset);
|
|
||||||
if ( sgIsBigEndian() ) {
|
|
||||||
sgEndianSwap((uint32_t *) p);
|
|
||||||
}
|
|
||||||
|
|
||||||
offset += sizeof(unsigned int);
|
|
||||||
return *p;
|
|
||||||
}
|
|
||||||
|
|
||||||
SGVec3d readVec3d()
|
SGVec3d readVec3d()
|
||||||
{
|
{
|
||||||
double* p = reinterpret_cast<double*>(ptr + offset);
|
double* p = reinterpret_cast<double*>(ptr + offset);
|
||||||
@@ -232,19 +202,15 @@ template <class T>
|
|||||||
static void read_indices(char* buffer,
|
static void read_indices(char* buffer,
|
||||||
size_t bytes,
|
size_t bytes,
|
||||||
int indexMask,
|
int indexMask,
|
||||||
int vaMask,
|
|
||||||
int_list& vertices,
|
int_list& vertices,
|
||||||
int_list& normals,
|
int_list& normals,
|
||||||
int_list& colors,
|
int_list& colors,
|
||||||
tci_list& texCoords,
|
int_list& texCoords)
|
||||||
vai_list& vas
|
|
||||||
)
|
|
||||||
{
|
{
|
||||||
const int indexSize = sizeof(T) * std::bitset<32>((int)indexMask).count();
|
const int indexSize = sizeof(T) * std::bitset<32>(indexMask).count();
|
||||||
const int vaSize = sizeof(T) * std::bitset<32>((int)vaMask).count();
|
const int count = bytes / indexSize;
|
||||||
const int count = bytes / (indexSize + vaSize);
|
|
||||||
|
|
||||||
// fix endian-ness of the whole lot, if required
|
// fix endian-ness of the whole lot, if required
|
||||||
if (sgIsBigEndian()) {
|
if (sgIsBigEndian()) {
|
||||||
int indices = bytes / sizeof(T);
|
int indices = bytes / sizeof(T);
|
||||||
T* src = reinterpret_cast<T*>(buffer);
|
T* src = reinterpret_cast<T*>(buffer);
|
||||||
@@ -258,21 +224,7 @@ static void read_indices(char* buffer,
|
|||||||
if (indexMask & SG_IDX_VERTICES) vertices.push_back(*src++);
|
if (indexMask & SG_IDX_VERTICES) vertices.push_back(*src++);
|
||||||
if (indexMask & SG_IDX_NORMALS) normals.push_back(*src++);
|
if (indexMask & SG_IDX_NORMALS) normals.push_back(*src++);
|
||||||
if (indexMask & SG_IDX_COLORS) colors.push_back(*src++);
|
if (indexMask & SG_IDX_COLORS) colors.push_back(*src++);
|
||||||
if (indexMask & SG_IDX_TEXCOORDS_0) texCoords[0].push_back(*src++);
|
if (indexMask & SG_IDX_TEXCOORDS) texCoords.push_back(*src++);
|
||||||
if (indexMask & SG_IDX_TEXCOORDS_1) texCoords[1].push_back(*src++);
|
|
||||||
if (indexMask & SG_IDX_TEXCOORDS_2) texCoords[2].push_back(*src++);
|
|
||||||
if (indexMask & SG_IDX_TEXCOORDS_3) texCoords[3].push_back(*src++);
|
|
||||||
|
|
||||||
if ( vaMask ) {
|
|
||||||
if (vaMask & SG_VA_INTEGER_0) vas[0].push_back(*src++);
|
|
||||||
if (vaMask & SG_VA_INTEGER_1) vas[1].push_back(*src++);
|
|
||||||
if (vaMask & SG_VA_INTEGER_2) vas[2].push_back(*src++);
|
|
||||||
if (vaMask & SG_VA_INTEGER_3) vas[3].push_back(*src++);
|
|
||||||
if (vaMask & SG_VA_FLOAT_0) vas[4].push_back(*src++);
|
|
||||||
if (vaMask & SG_VA_FLOAT_1) vas[5].push_back(*src++);
|
|
||||||
if (vaMask & SG_VA_FLOAT_2) vas[6].push_back(*src++);
|
|
||||||
if (vaMask & SG_VA_FLOAT_3) vas[7].push_back(*src++);
|
|
||||||
}
|
|
||||||
} // of elements in the index
|
} // of elements in the index
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -297,19 +249,15 @@ void write_indice(gzFile fp, uint32_t value)
|
|||||||
|
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
void write_indices(gzFile fp,
|
void write_indices(gzFile fp, unsigned char indexMask,
|
||||||
unsigned char indexMask,
|
|
||||||
unsigned int vaMask,
|
|
||||||
const int_list& vertices,
|
const int_list& vertices,
|
||||||
const int_list& normals,
|
const int_list& normals,
|
||||||
const int_list& colors,
|
const int_list& colors,
|
||||||
const tci_list& texCoords,
|
const int_list& texCoords)
|
||||||
const vai_list& vas )
|
|
||||||
{
|
{
|
||||||
unsigned int count = vertices.size();
|
unsigned int count = vertices.size();
|
||||||
const int indexSize = sizeof(T) * std::bitset<32>((int)indexMask).count();
|
const int indexSize = sizeof(T) * std::bitset<32>(indexMask).count();
|
||||||
const int vaSize = sizeof(T) * std::bitset<32>((int)vaMask).count();
|
sgWriteUInt(fp, indexSize * count);
|
||||||
sgWriteUInt(fp, (indexSize + vaSize) * count);
|
|
||||||
|
|
||||||
for (unsigned int i=0; i < count; ++i) {
|
for (unsigned int i=0; i < count; ++i) {
|
||||||
write_indice(fp, static_cast<T>(vertices[i]));
|
write_indice(fp, static_cast<T>(vertices[i]));
|
||||||
@@ -320,45 +268,8 @@ void write_indices(gzFile fp,
|
|||||||
if (indexMask & SG_IDX_COLORS) {
|
if (indexMask & SG_IDX_COLORS) {
|
||||||
write_indice(fp, static_cast<T>(colors[i]));
|
write_indice(fp, static_cast<T>(colors[i]));
|
||||||
}
|
}
|
||||||
if (indexMask & SG_IDX_TEXCOORDS_0) {
|
if (indexMask & SG_IDX_TEXCOORDS) {
|
||||||
write_indice(fp, static_cast<T>(texCoords[0][i]));
|
write_indice(fp, static_cast<T>(texCoords[i]));
|
||||||
}
|
|
||||||
if (indexMask & SG_IDX_TEXCOORDS_1) {
|
|
||||||
write_indice(fp, static_cast<T>(texCoords[1][i]));
|
|
||||||
}
|
|
||||||
if (indexMask & SG_IDX_TEXCOORDS_2) {
|
|
||||||
write_indice(fp, static_cast<T>(texCoords[2][i]));
|
|
||||||
}
|
|
||||||
if (indexMask & SG_IDX_TEXCOORDS_3) {
|
|
||||||
write_indice(fp, static_cast<T>(texCoords[3][i]));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (vaMask) {
|
|
||||||
if (vaMask & SG_VA_INTEGER_0) {
|
|
||||||
write_indice(fp, static_cast<T>(vas[0][i]));
|
|
||||||
}
|
|
||||||
if (vaMask & SG_VA_INTEGER_1) {
|
|
||||||
write_indice(fp, static_cast<T>(vas[1][i]));
|
|
||||||
}
|
|
||||||
if (vaMask & SG_VA_INTEGER_2) {
|
|
||||||
write_indice(fp, static_cast<T>(vas[2][i]));
|
|
||||||
}
|
|
||||||
if (vaMask & SG_VA_INTEGER_3) {
|
|
||||||
write_indice(fp, static_cast<T>(vas[3][i]));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (vaMask & SG_VA_FLOAT_0) {
|
|
||||||
write_indice(fp, static_cast<T>(vas[4][i]));
|
|
||||||
}
|
|
||||||
if (vaMask & SG_VA_FLOAT_1) {
|
|
||||||
write_indice(fp, static_cast<T>(vas[5][i]));
|
|
||||||
}
|
|
||||||
if (vaMask & SG_VA_FLOAT_2) {
|
|
||||||
write_indice(fp, static_cast<T>(vas[6][i]));
|
|
||||||
}
|
|
||||||
if (vaMask & SG_VA_FLOAT_3) {
|
|
||||||
write_indice(fp, static_cast<T>(vas[7][i]));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -372,13 +283,11 @@ void SGBinObject::read_object( gzFile fp,
|
|||||||
group_list& vertices,
|
group_list& vertices,
|
||||||
group_list& normals,
|
group_list& normals,
|
||||||
group_list& colors,
|
group_list& colors,
|
||||||
group_tci_list& texCoords,
|
group_list& texCoords,
|
||||||
group_vai_list& vertexAttribs,
|
|
||||||
string_list& materials)
|
string_list& materials)
|
||||||
{
|
{
|
||||||
unsigned int nbytes;
|
unsigned int nbytes;
|
||||||
unsigned char idx_mask;
|
unsigned char idx_mask;
|
||||||
unsigned int vertex_attrib_mask;
|
|
||||||
int j;
|
int j;
|
||||||
sgSimpleBuffer buf( 32768 ); // 32 Kb
|
sgSimpleBuffer buf( 32768 ); // 32 Kb
|
||||||
char material[256];
|
char material[256];
|
||||||
@@ -387,49 +296,26 @@ void SGBinObject::read_object( gzFile fp,
|
|||||||
if ( obj_type == SG_POINTS ) {
|
if ( obj_type == SG_POINTS ) {
|
||||||
idx_mask = SG_IDX_VERTICES;
|
idx_mask = SG_IDX_VERTICES;
|
||||||
} else {
|
} else {
|
||||||
idx_mask = (char)(SG_IDX_VERTICES | SG_IDX_TEXCOORDS_0);
|
idx_mask = (char)(SG_IDX_VERTICES | SG_IDX_TEXCOORDS);
|
||||||
}
|
}
|
||||||
vertex_attrib_mask = 0;
|
|
||||||
|
|
||||||
for ( j = 0; j < nproperties; ++j ) {
|
for ( j = 0; j < nproperties; ++j ) {
|
||||||
char prop_type;
|
char prop_type;
|
||||||
sgReadChar( fp, &prop_type );
|
sgReadChar( fp, &prop_type );
|
||||||
sgReadUInt( fp, &nbytes );
|
sgReadUInt( fp, &nbytes );
|
||||||
|
|
||||||
buf.resize(nbytes);
|
buf.resize(nbytes);
|
||||||
char *ptr = buf.get_ptr();
|
char *ptr = buf.get_ptr();
|
||||||
|
|
||||||
switch( prop_type )
|
|
||||||
{
|
|
||||||
case SG_MATERIAL:
|
|
||||||
sgReadBytes( fp, nbytes, ptr );
|
sgReadBytes( fp, nbytes, ptr );
|
||||||
|
if ( prop_type == SG_MATERIAL ) {
|
||||||
if (nbytes > 255) {
|
if (nbytes > 255) {
|
||||||
nbytes = 255;
|
nbytes = 255;
|
||||||
}
|
}
|
||||||
strncpy( material, ptr, nbytes );
|
strncpy( material, ptr, nbytes );
|
||||||
material[nbytes] = '\0';
|
material[nbytes] = '\0';
|
||||||
break;
|
// cout << "material type = " << material << endl;
|
||||||
|
} else if ( prop_type == SG_INDEX_TYPES ) {
|
||||||
case SG_INDEX_TYPES:
|
idx_mask = ptr[0];
|
||||||
if (nbytes == 1) {
|
//cout << std::hex << "index mask:" << idx_mask << std::dec << endl;
|
||||||
sgReadChar( fp, (char *)&idx_mask );
|
|
||||||
} else {
|
|
||||||
sgReadBytes( fp, nbytes, ptr );
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SG_VERT_ATTRIBS:
|
|
||||||
if (nbytes == 4) {
|
|
||||||
sgReadUInt( fp, &vertex_attrib_mask );
|
|
||||||
} else {
|
|
||||||
sgReadBytes( fp, nbytes, ptr );
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
sgReadBytes( fp, nbytes, ptr );
|
|
||||||
SG_LOG(SG_IO, SG_ALERT, "Found UNKNOWN property type with nbytes == " << nbytes << " mask is " << (int)idx_mask );
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -437,7 +323,7 @@ void SGBinObject::read_object( gzFile fp,
|
|||||||
throw sg_exception("Error reading object properties");
|
throw sg_exception("Error reading object properties");
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t indexCount = std::bitset<32>((int)idx_mask).count();
|
size_t indexCount = std::bitset<32>(idx_mask).count();
|
||||||
if (indexCount == 0) {
|
if (indexCount == 0) {
|
||||||
throw sg_exception("object index mask has no bits set");
|
throw sg_exception("object index mask has no bits set");
|
||||||
}
|
}
|
||||||
@@ -459,20 +345,17 @@ void SGBinObject::read_object( gzFile fp,
|
|||||||
int_list vs;
|
int_list vs;
|
||||||
int_list ns;
|
int_list ns;
|
||||||
int_list cs;
|
int_list cs;
|
||||||
tci_list tcs;
|
int_list tcs;
|
||||||
vai_list vas;
|
|
||||||
|
|
||||||
if (version >= 10) {
|
if (version >= 10) {
|
||||||
read_indices<uint32_t>(ptr, nbytes, idx_mask, vertex_attrib_mask, vs, ns, cs, tcs, vas );
|
read_indices<uint32_t>(ptr, nbytes, idx_mask, vs, ns, cs, tcs);
|
||||||
} else {
|
} else {
|
||||||
read_indices<uint16_t>(ptr, nbytes, idx_mask, vertex_attrib_mask, vs, ns, cs, tcs, vas );
|
read_indices<uint16_t>(ptr, nbytes, idx_mask, vs, ns, cs, tcs);
|
||||||
}
|
}
|
||||||
|
|
||||||
vertices.push_back( vs );
|
vertices.push_back( vs );
|
||||||
normals.push_back( ns );
|
normals.push_back( ns );
|
||||||
colors.push_back( cs );
|
colors.push_back( cs );
|
||||||
texCoords.push_back( tcs );
|
texCoords.push_back( tcs );
|
||||||
vertexAttribs.push_back( vas );
|
|
||||||
materials.push_back( material );
|
materials.push_back( material );
|
||||||
} // of element iteration
|
} // of element iteration
|
||||||
}
|
}
|
||||||
@@ -497,29 +380,25 @@ bool SGBinObject::read_bin( const string& file ) {
|
|||||||
pts_v.clear();
|
pts_v.clear();
|
||||||
pts_n.clear();
|
pts_n.clear();
|
||||||
pts_c.clear();
|
pts_c.clear();
|
||||||
pts_tcs.clear();
|
pts_tc.clear();
|
||||||
pts_vas.clear();
|
|
||||||
pt_materials.clear();
|
pt_materials.clear();
|
||||||
|
|
||||||
tris_v.clear();
|
tris_v.clear();
|
||||||
tris_n.clear();
|
tris_n.clear();
|
||||||
tris_c.clear();
|
tris_c.clear();
|
||||||
tris_tcs.clear();
|
tris_tc.clear();
|
||||||
tris_vas.clear();
|
|
||||||
tri_materials.clear();
|
tri_materials.clear();
|
||||||
|
|
||||||
strips_v.clear();
|
strips_v.clear();
|
||||||
strips_n.clear();
|
strips_n.clear();
|
||||||
strips_c.clear();
|
strips_c.clear();
|
||||||
strips_tcs.clear();
|
strips_tc.clear();
|
||||||
strips_vas.clear();
|
|
||||||
strip_materials.clear();
|
strip_materials.clear();
|
||||||
|
|
||||||
fans_v.clear();
|
fans_v.clear();
|
||||||
fans_n.clear();
|
fans_n.clear();
|
||||||
fans_c.clear();
|
fans_c.clear();
|
||||||
fans_tcs.clear();
|
fans_tc.clear();
|
||||||
fans_vas.clear();
|
|
||||||
fan_materials.clear();
|
fan_materials.clear();
|
||||||
|
|
||||||
gzFile fp;
|
gzFile fp;
|
||||||
@@ -540,9 +419,10 @@ bool SGBinObject::read_bin( const string& file ) {
|
|||||||
sgReadUInt( fp, &header );
|
sgReadUInt( fp, &header );
|
||||||
if ( ((header & 0xFF000000) >> 24) == 'S' &&
|
if ( ((header & 0xFF000000) >> 24) == 'S' &&
|
||||||
((header & 0x00FF0000) >> 16) == 'G' ) {
|
((header & 0x00FF0000) >> 16) == 'G' ) {
|
||||||
|
// cout << "Good header" << endl;
|
||||||
// read file version
|
// read file version
|
||||||
version = (header & 0x0000FFFF);
|
version = (header & 0x0000FFFF);
|
||||||
|
// cout << "File version = " << version << endl;
|
||||||
} else {
|
} else {
|
||||||
// close the file before we return
|
// close the file before we return
|
||||||
gzclose(fp);
|
gzclose(fp);
|
||||||
@@ -580,7 +460,7 @@ bool SGBinObject::read_bin( const string& file ) {
|
|||||||
nobjects = v;
|
nobjects = v;
|
||||||
}
|
}
|
||||||
|
|
||||||
SG_LOG(SG_IO, SG_DEBUG, "SGBinObject::read_bin Total objects to read = " << nobjects);
|
//cout << "Total objects to read = " << nobjects << endl;
|
||||||
|
|
||||||
if ( sgReadError() ) {
|
if ( sgReadError() ) {
|
||||||
throw sg_io_exception("Error reading BTG file header", sg_location(file));
|
throw sg_io_exception("Error reading BTG file header", sg_location(file));
|
||||||
@@ -609,9 +489,8 @@ bool SGBinObject::read_bin( const string& file ) {
|
|||||||
nelements = v;
|
nelements = v;
|
||||||
}
|
}
|
||||||
|
|
||||||
SG_LOG(SG_IO, SG_DEBUG, "SGBinObject::read_bin object " << i <<
|
//cout << "object " << i << " = " << (int)obj_type << " props = "
|
||||||
" = " << (int)obj_type << " props = " << nproperties <<
|
// << nproperties << " elements = " << nelements << endl;
|
||||||
" elements = " << nelements);
|
|
||||||
|
|
||||||
if ( obj_type == SG_BOUNDING_SPHERE ) {
|
if ( obj_type == SG_BOUNDING_SPHERE ) {
|
||||||
// read bounding sphere properties
|
// read bounding sphere properties
|
||||||
@@ -702,60 +581,23 @@ bool SGBinObject::read_bin( const string& file ) {
|
|||||||
texcoords.push_back( buf.readVec2f() );
|
texcoords.push_back( buf.readVec2f() );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if ( obj_type == SG_VA_FLOAT_LIST ) {
|
|
||||||
// read vertex attribute (float) properties
|
|
||||||
read_properties( fp, nproperties );
|
|
||||||
|
|
||||||
// read vertex attribute list elements
|
|
||||||
for ( j = 0; j < nelements; ++j ) {
|
|
||||||
sgReadUInt( fp, &nbytes );
|
|
||||||
buf.resize( nbytes );
|
|
||||||
buf.reset();
|
|
||||||
char *ptr = buf.get_ptr();
|
|
||||||
sgReadBytes( fp, nbytes, ptr );
|
|
||||||
int count = nbytes / (sizeof(float));
|
|
||||||
va_flt.reserve(count);
|
|
||||||
for ( k = 0; k < count; ++k ) {
|
|
||||||
va_flt.push_back( buf.readFloat() );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if ( obj_type == SG_VA_INTEGER_LIST ) {
|
|
||||||
// read vertex attribute (integer) properties
|
|
||||||
read_properties( fp, nproperties );
|
|
||||||
|
|
||||||
// read vertex attribute list elements
|
|
||||||
for ( j = 0; j < nelements; ++j ) {
|
|
||||||
sgReadUInt( fp, &nbytes );
|
|
||||||
buf.resize( nbytes );
|
|
||||||
buf.reset();
|
|
||||||
char *ptr = buf.get_ptr();
|
|
||||||
sgReadBytes( fp, nbytes, ptr );
|
|
||||||
int count = nbytes / (sizeof(unsigned int));
|
|
||||||
va_int.reserve(count);
|
|
||||||
for ( k = 0; k < count; ++k ) {
|
|
||||||
va_int.push_back( buf.readInt() );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if ( obj_type == SG_POINTS ) {
|
} else if ( obj_type == SG_POINTS ) {
|
||||||
// read point elements
|
// read point elements
|
||||||
read_object( fp, SG_POINTS, nproperties, nelements,
|
read_object( fp, SG_POINTS, nproperties, nelements,
|
||||||
pts_v, pts_n, pts_c, pts_tcs,
|
pts_v, pts_n, pts_c, pts_tc, pt_materials );
|
||||||
pts_vas, pt_materials );
|
|
||||||
} else if ( obj_type == SG_TRIANGLE_FACES ) {
|
} else if ( obj_type == SG_TRIANGLE_FACES ) {
|
||||||
// read triangle face properties
|
// read triangle face properties
|
||||||
read_object( fp, SG_TRIANGLE_FACES, nproperties, nelements,
|
read_object( fp, SG_TRIANGLE_FACES, nproperties, nelements,
|
||||||
tris_v, tris_n, tris_c, tris_tcs,
|
tris_v, tris_n, tris_c, tris_tc, tri_materials );
|
||||||
tris_vas, tri_materials );
|
|
||||||
} else if ( obj_type == SG_TRIANGLE_STRIPS ) {
|
} else if ( obj_type == SG_TRIANGLE_STRIPS ) {
|
||||||
// read triangle strip properties
|
// read triangle strip properties
|
||||||
read_object( fp, SG_TRIANGLE_STRIPS, nproperties, nelements,
|
read_object( fp, SG_TRIANGLE_STRIPS, nproperties, nelements,
|
||||||
strips_v, strips_n, strips_c, strips_tcs,
|
strips_v, strips_n, strips_c, strips_tc,
|
||||||
strips_vas, strip_materials );
|
strip_materials );
|
||||||
} else if ( obj_type == SG_TRIANGLE_FANS ) {
|
} else if ( obj_type == SG_TRIANGLE_FANS ) {
|
||||||
// read triangle fan properties
|
// read triangle fan properties
|
||||||
read_object( fp, SG_TRIANGLE_FANS, nproperties, nelements,
|
read_object( fp, SG_TRIANGLE_FANS, nproperties, nelements,
|
||||||
fans_v, fans_n, fans_c, fans_tcs,
|
fans_v, fans_n, fans_c, fans_tc, fan_materials );
|
||||||
fans_vas, fan_materials );
|
|
||||||
} else {
|
} else {
|
||||||
// unknown object type, just skip
|
// unknown object type, just skip
|
||||||
read_properties( fp, nproperties );
|
read_properties( fp, nproperties );
|
||||||
@@ -810,13 +652,9 @@ unsigned int SGBinObject::count_objects(const string_list& materials)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SGBinObject::write_objects(gzFile fp, int type,
|
void SGBinObject::write_objects(gzFile fp, int type, const group_list& verts,
|
||||||
const group_list& verts,
|
const group_list& normals, const group_list& colors,
|
||||||
const group_list& normals,
|
const group_list& texCoords, const string_list& materials)
|
||||||
const group_list& colors,
|
|
||||||
const group_tci_list& texCoords,
|
|
||||||
const group_vai_list& vertexAttribs,
|
|
||||||
const string_list& materials)
|
|
||||||
{
|
{
|
||||||
if (verts.empty()) {
|
if (verts.empty()) {
|
||||||
return;
|
return;
|
||||||
@@ -831,74 +669,42 @@ void SGBinObject::write_objects(gzFile fp, int type,
|
|||||||
// find range of objects with identical material, write out as a single object
|
// find range of objects with identical material, write out as a single object
|
||||||
for (end = start+1; (end < materials.size()) && (m == materials[end]); ++end) {}
|
for (end = start+1; (end < materials.size()) && (m == materials[end]); ++end) {}
|
||||||
|
|
||||||
// calc the number of elements
|
|
||||||
const int count = end - start;
|
const int count = end - start;
|
||||||
|
|
||||||
// calc the number of properties
|
|
||||||
unsigned int va_mask = 0;
|
|
||||||
unsigned int va_count = vertexAttribs.size();
|
|
||||||
for ( unsigned int va=0; va<va_count; va++ ) {
|
|
||||||
if ( !vertexAttribs[va].empty() && !vertexAttribs[va].front().empty() ) {
|
|
||||||
va_mask |= ( 1 << va );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( va_mask ) {
|
|
||||||
write_header(fp, type, 3, count);
|
|
||||||
} else {
|
|
||||||
write_header(fp, type, 2, count);
|
write_header(fp, type, 2, count);
|
||||||
}
|
|
||||||
|
|
||||||
// properties
|
// properties
|
||||||
// material property
|
|
||||||
sgWriteChar( fp, (char)SG_MATERIAL ); // property
|
sgWriteChar( fp, (char)SG_MATERIAL ); // property
|
||||||
sgWriteUInt( fp, m.length() ); // nbytes
|
sgWriteUInt( fp, m.length() ); // nbytes
|
||||||
sgWriteBytes( fp, m.length(), m.c_str() );
|
sgWriteBytes( fp, m.length(), m.c_str() );
|
||||||
|
|
||||||
// index mask property
|
|
||||||
unsigned char idx_mask = 0;
|
unsigned char idx_mask = 0;
|
||||||
if ( !verts.empty() && !verts[start].empty()) idx_mask |= SG_IDX_VERTICES;
|
if ( !verts.empty() && !verts.front().empty()) idx_mask |= SG_IDX_VERTICES;
|
||||||
if ( !normals.empty() && !normals[start].empty()) idx_mask |= SG_IDX_NORMALS;
|
if ( !normals.empty() && !normals.front().empty()) idx_mask |= SG_IDX_NORMALS;
|
||||||
if ( !colors.empty() && !colors[start].empty()) idx_mask |= SG_IDX_COLORS;
|
if ( !colors.empty() && !colors.front().empty()) idx_mask |= SG_IDX_COLORS;
|
||||||
if ( !texCoords.empty() && !texCoords[start][0].empty()) idx_mask |= SG_IDX_TEXCOORDS_0;
|
if ( !texCoords.empty() && !texCoords.front().empty()) idx_mask |= SG_IDX_TEXCOORDS;
|
||||||
if ( !texCoords.empty() && !texCoords[start][1].empty()) idx_mask |= SG_IDX_TEXCOORDS_1;
|
|
||||||
if ( !texCoords.empty() && !texCoords[start][2].empty()) idx_mask |= SG_IDX_TEXCOORDS_2;
|
|
||||||
if ( !texCoords.empty() && !texCoords[start][3].empty()) idx_mask |= SG_IDX_TEXCOORDS_3;
|
|
||||||
|
|
||||||
if (idx_mask == 0) {
|
if (idx_mask == 0) {
|
||||||
SG_LOG(SG_IO, SG_ALERT, "SGBinObject::write_objects: object with material:"
|
SG_LOG(SG_IO, SG_ALERT, "SGBinObject::write_objects: object with material:"
|
||||||
<< m << "has no indices set");
|
<< m << "has no indices set");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
sgWriteChar( fp, (char)SG_INDEX_TYPES ); // property
|
sgWriteChar( fp, (char)SG_INDEX_TYPES ); // property
|
||||||
sgWriteUInt( fp, 1 ); // nbytes
|
sgWriteUInt( fp, 1 ); // nbytes
|
||||||
sgWriteChar( fp, idx_mask );
|
sgWriteChar( fp, idx_mask );
|
||||||
|
|
||||||
// vertex attribute property
|
// cout << "material:" << m << ", count =" << count << endl;
|
||||||
if (va_mask != 0) {
|
|
||||||
sgWriteChar( fp, (char)SG_VERT_ATTRIBS ); // property
|
|
||||||
sgWriteUInt( fp, 4 ); // nbytes
|
|
||||||
sgWriteChar( fp, va_mask );
|
|
||||||
}
|
|
||||||
|
|
||||||
// elements
|
// elements
|
||||||
for (unsigned int i=start; i < end; ++i) {
|
for (unsigned int i=start; i < end; ++i) {
|
||||||
const int_list& va(verts[i]);
|
const int_list& va(verts[i]);
|
||||||
const int_list& na((idx_mask & SG_IDX_NORMALS) ? normals[i] : emptyList);
|
const int_list& na((idx_mask & SG_IDX_NORMALS) ? normals[i] : emptyList);
|
||||||
const int_list& ca((idx_mask & SG_IDX_COLORS) ? colors[i] : emptyList);
|
const int_list& ca((idx_mask & SG_IDX_COLORS) ? colors[i] : emptyList);
|
||||||
|
const int_list& tca((idx_mask & SG_IDX_TEXCOORDS) ? texCoords[i] : emptyList);
|
||||||
// pass the whole texcoord array - we'll figure out which indicies to write
|
|
||||||
// in write_indices
|
|
||||||
const tci_list& tca( texCoords[i] );
|
|
||||||
|
|
||||||
// pass the whole vertex array - we'll figure out which indicies to write
|
|
||||||
// in write_indices
|
|
||||||
const vai_list& vaa( vertexAttribs[i] );
|
|
||||||
|
|
||||||
if (version == 7) {
|
if (version == 7) {
|
||||||
write_indices<uint16_t>(fp, idx_mask, va_mask, va, na, ca, tca, vaa);
|
write_indices<uint16_t>(fp, idx_mask, va, na, ca, tca);
|
||||||
} else {
|
} else {
|
||||||
write_indices<uint32_t>(fp, idx_mask, va_mask, va, na, ca, tca, vaa);
|
write_indices<uint32_t>(fp, idx_mask, va, na, ca, tca);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -943,6 +749,7 @@ bool SGBinObject::write_bin_file(const SGPath& file)
|
|||||||
|
|
||||||
SGPath file2(file);
|
SGPath file2(file);
|
||||||
file2.create_dir( 0755 );
|
file2.create_dir( 0755 );
|
||||||
|
cout << "Output file = " << file.str() << endl;
|
||||||
|
|
||||||
gzFile fp;
|
gzFile fp;
|
||||||
if ( (fp = gzopen( file.c_str(), "wb9" )) == NULL ) {
|
if ( (fp = gzopen( file.c_str(), "wb9" )) == NULL ) {
|
||||||
@@ -952,19 +759,19 @@ bool SGBinObject::write_bin_file(const SGPath& file)
|
|||||||
|
|
||||||
sgClearWriteError();
|
sgClearWriteError();
|
||||||
|
|
||||||
SG_LOG(SG_IO, SG_DEBUG, "points size = " << pts_v.size()
|
cout << "points size = " << pts_v.size() << " pt_materials = "
|
||||||
<< " pt_materials = " << pt_materials.size() );
|
<< pt_materials.size() << endl;
|
||||||
SG_LOG(SG_IO, SG_DEBUG, "triangles size = " << tris_v.size()
|
cout << "triangles size = " << tris_v.size() << " tri_materials = "
|
||||||
<< " tri_materials = " << tri_materials.size() );
|
<< tri_materials.size() << endl;
|
||||||
SG_LOG(SG_IO, SG_DEBUG, "strips size = " << strips_v.size()
|
cout << "strips size = " << strips_v.size() << " strip_materials = "
|
||||||
<< " strip_materials = " << strip_materials.size() );
|
<< strip_materials.size() << endl;
|
||||||
SG_LOG(SG_IO, SG_DEBUG, "fans size = " << fans_v.size()
|
cout << "fans size = " << fans_v.size() << " fan_materials = "
|
||||||
<< " fan_materials = " << fan_materials.size() );
|
<< fan_materials.size() << endl;
|
||||||
|
|
||||||
SG_LOG(SG_IO, SG_DEBUG, "nodes = " << wgs84_nodes.size() );
|
cout << "nodes = " << wgs84_nodes.size() << endl;
|
||||||
SG_LOG(SG_IO, SG_DEBUG, "colors = " << colors.size() );
|
cout << "colors = " << colors.size() << endl;
|
||||||
SG_LOG(SG_IO, SG_DEBUG, "normals = " << normals.size() );
|
cout << "normals = " << normals.size() << endl;
|
||||||
SG_LOG(SG_IO, SG_DEBUG, "tex coords = " << texcoords.size() );
|
cout << "tex coords = " << texcoords.size() << endl;
|
||||||
|
|
||||||
version = 10;
|
version = 10;
|
||||||
bool shortMaterialsRanges =
|
bool shortMaterialsRanges =
|
||||||
@@ -996,8 +803,7 @@ bool SGBinObject::write_bin_file(const SGPath& file)
|
|||||||
nobjects += count_objects(strip_materials);
|
nobjects += count_objects(strip_materials);
|
||||||
nobjects += count_objects(fan_materials);
|
nobjects += count_objects(fan_materials);
|
||||||
|
|
||||||
SG_LOG(SG_IO, SG_DEBUG, "total top level objects = " << nobjects);
|
cout << "total top level objects = " << nobjects << endl;
|
||||||
|
|
||||||
if (version == 7) {
|
if (version == 7) {
|
||||||
sgWriteUShort( fp, (uint16_t) nobjects );
|
sgWriteUShort( fp, (uint16_t) nobjects );
|
||||||
} else {
|
} else {
|
||||||
@@ -1043,10 +849,10 @@ bool SGBinObject::write_bin_file(const SGPath& file)
|
|||||||
sgWriteVec2( fp, texcoords[i]);
|
sgWriteVec2( fp, texcoords[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
write_objects(fp, SG_POINTS, pts_v, pts_n, pts_c, pts_tcs, pts_vas, pt_materials);
|
write_objects(fp, SG_POINTS, pts_v, pts_n, pts_c, pts_tc, pt_materials);
|
||||||
write_objects(fp, SG_TRIANGLE_FACES, tris_v, tris_n, tris_c, tris_tcs, tris_vas, tri_materials);
|
write_objects(fp, SG_TRIANGLE_FACES, tris_v, tris_n, tris_c, tris_tc, tri_materials);
|
||||||
write_objects(fp, SG_TRIANGLE_STRIPS, strips_v, strips_n, strips_c, strips_tcs, strips_vas, strip_materials);
|
write_objects(fp, SG_TRIANGLE_STRIPS, strips_v, strips_n, strips_c, strips_tc, strip_materials);
|
||||||
write_objects(fp, SG_TRIANGLE_FANS, fans_v, fans_n, fans_c, fans_tcs, fans_vas, fan_materials);
|
write_objects(fp, SG_TRIANGLE_FANS, fans_v, fans_n, fans_c, fans_tc, fan_materials);
|
||||||
|
|
||||||
// close the file
|
// close the file
|
||||||
gzclose(fp);
|
gzclose(fp);
|
||||||
@@ -1146,7 +952,7 @@ bool SGBinObject::write_ascii( const string& base, const string& name,
|
|||||||
}
|
}
|
||||||
// cout << "group = " << start << " to " << end - 1 << endl;
|
// cout << "group = " << start << " to " << end - 1 << endl;
|
||||||
|
|
||||||
SGSphered d( SGVec3d(0.0, 0.0, 0.0), -1.0 );
|
SGSphered d;
|
||||||
for ( i = start; i < end; ++i ) {
|
for ( i = start; i < end; ++i ) {
|
||||||
for ( j = 0; j < (int)tris_v[i].size(); ++j ) {
|
for ( j = 0; j < (int)tris_v[i].size(); ++j ) {
|
||||||
d.expandBy(wgs84_nodes[ tris_v[i][j] ]);
|
d.expandBy(wgs84_nodes[ tris_v[i][j] ]);
|
||||||
@@ -1166,7 +972,7 @@ bool SGBinObject::write_ascii( const string& base, const string& name,
|
|||||||
for ( i = start; i < end; ++i ) {
|
for ( i = start; i < end; ++i ) {
|
||||||
fprintf(fp, "f");
|
fprintf(fp, "f");
|
||||||
for ( j = 0; j < (int)tris_v[i].size(); ++j ) {
|
for ( j = 0; j < (int)tris_v[i].size(); ++j ) {
|
||||||
fprintf(fp, " %d/%d", tris_v[i][j], tris_tcs[i][0][j] );
|
fprintf(fp, " %d/%d", tris_v[i][j], tris_tc[i][j] );
|
||||||
}
|
}
|
||||||
fprintf(fp, "\n");
|
fprintf(fp, "\n");
|
||||||
}
|
}
|
||||||
@@ -1195,7 +1001,7 @@ bool SGBinObject::write_ascii( const string& base, const string& name,
|
|||||||
// cout << "group = " << start << " to " << end - 1 << endl;
|
// cout << "group = " << start << " to " << end - 1 << endl;
|
||||||
|
|
||||||
|
|
||||||
SGSphered d( SGVec3d(0.0, 0.0, 0.0), -1.0 );
|
SGSphered d;
|
||||||
for ( i = start; i < end; ++i ) {
|
for ( i = start; i < end; ++i ) {
|
||||||
for ( j = 0; j < (int)tris_v[i].size(); ++j ) {
|
for ( j = 0; j < (int)tris_v[i].size(); ++j ) {
|
||||||
d.expandBy(wgs84_nodes[ tris_v[i][j] ]);
|
d.expandBy(wgs84_nodes[ tris_v[i][j] ]);
|
||||||
@@ -1215,7 +1021,7 @@ bool SGBinObject::write_ascii( const string& base, const string& name,
|
|||||||
for ( i = start; i < end; ++i ) {
|
for ( i = start; i < end; ++i ) {
|
||||||
fprintf(fp, "ts");
|
fprintf(fp, "ts");
|
||||||
for ( j = 0; j < (int)strips_v[i].size(); ++j ) {
|
for ( j = 0; j < (int)strips_v[i].size(); ++j ) {
|
||||||
fprintf(fp, " %d/%d", strips_v[i][j], strips_tcs[i][0][j] );
|
fprintf(fp, " %d/%d", strips_v[i][j], strips_tc[i][j] );
|
||||||
}
|
}
|
||||||
fprintf(fp, "\n");
|
fprintf(fp, "\n");
|
||||||
}
|
}
|
||||||
@@ -1255,27 +1061,3 @@ void SGBinObject::read_properties(gzFile fp, int nproperties)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SGBinObject::add_point( const SGBinObjectPoint& pt )
|
|
||||||
{
|
|
||||||
// add the point info
|
|
||||||
pt_materials.push_back( pt.material );
|
|
||||||
|
|
||||||
pts_v.push_back( pt.v_list );
|
|
||||||
pts_n.push_back( pt.n_list );
|
|
||||||
pts_c.push_back( pt.c_list );
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SGBinObject::add_triangle( const SGBinObjectTriangle& tri )
|
|
||||||
{
|
|
||||||
// add the triangle info and keep lists aligned
|
|
||||||
tri_materials.push_back( tri.material );
|
|
||||||
tris_v.push_back( tri.v_list );
|
|
||||||
tris_n.push_back( tri.n_list );
|
|
||||||
tris_c.push_back( tri.c_list );
|
|
||||||
tris_tcs.push_back( tri.tc_list );
|
|
||||||
tris_vas.push_back( tri.va_list );
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
+42
-102
@@ -36,79 +36,16 @@
|
|||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <boost/array.hpp>
|
|
||||||
|
|
||||||
#define MAX_TC_SETS (4)
|
/** STL Structure used to store object information */
|
||||||
#define MAX_VAS (8)
|
|
||||||
|
|
||||||
// I really want to pass around fixed length arrays, as the size
|
|
||||||
// has to be hardcoded
|
|
||||||
// but it's a C++0x feature use boost in its absence
|
|
||||||
typedef boost::array<int_list, MAX_TC_SETS> tci_list;
|
|
||||||
typedef boost::array<int_list, MAX_VAS> vai_list;
|
|
||||||
|
|
||||||
/** STL Structure used to store (integer index) object information */
|
|
||||||
typedef std::vector < int_list > group_list;
|
typedef std::vector < int_list > group_list;
|
||||||
typedef group_list::iterator group_list_iterator;
|
typedef group_list::iterator group_list_iterator;
|
||||||
typedef group_list::const_iterator const_group_list_iterator;
|
typedef group_list::const_iterator const_group_list_iterator;
|
||||||
|
|
||||||
/** STL Structure used to store (tc index) object information */
|
|
||||||
typedef std::vector < tci_list > group_tci_list;
|
|
||||||
typedef group_tci_list::iterator group_tci_list_iterator;
|
|
||||||
typedef group_tci_list::const_iterator const_group_tci_list_iterator;
|
|
||||||
|
|
||||||
/** STL Structure used to store (va index) object information */
|
|
||||||
typedef std::vector < vai_list > group_vai_list;
|
|
||||||
typedef group_vai_list::iterator group_vai_list_iterator;
|
|
||||||
typedef group_vai_list::const_iterator const_group_vai_list_iterator;
|
|
||||||
|
|
||||||
|
|
||||||
// forward decls
|
// forward decls
|
||||||
class SGBucket;
|
class SGBucket;
|
||||||
class SGPath;
|
class SGPath;
|
||||||
|
|
||||||
class SGBinObjectPoint {
|
|
||||||
public:
|
|
||||||
std::string material;
|
|
||||||
int_list v_list;
|
|
||||||
int_list n_list;
|
|
||||||
int_list c_list;
|
|
||||||
|
|
||||||
void clear( void ) {
|
|
||||||
material = "";
|
|
||||||
v_list.clear();
|
|
||||||
n_list.clear();
|
|
||||||
c_list.clear();
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
class SGBinObjectTriangle {
|
|
||||||
public:
|
|
||||||
std::string material;
|
|
||||||
int_list v_list;
|
|
||||||
int_list n_list;
|
|
||||||
int_list c_list;
|
|
||||||
|
|
||||||
tci_list tc_list;
|
|
||||||
vai_list va_list;
|
|
||||||
|
|
||||||
void clear( void ) {
|
|
||||||
material = "";
|
|
||||||
v_list.clear();
|
|
||||||
n_list.clear();
|
|
||||||
c_list.clear();
|
|
||||||
for ( unsigned int i=0; i<MAX_TC_SETS; i++ ) {
|
|
||||||
tc_list[i].clear();
|
|
||||||
}
|
|
||||||
for ( unsigned int i=0; i<MAX_VAS; i++ ) {
|
|
||||||
va_list[i].clear();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A class to manipulate the simgear 3d object format.
|
* A class to manipulate the simgear 3d object format.
|
||||||
* This class provides functionality to both read and write the binary format.
|
* This class provides functionality to both read and write the binary format.
|
||||||
@@ -153,35 +90,29 @@ private:
|
|||||||
std::vector<SGVec4f> colors; // color list
|
std::vector<SGVec4f> colors; // color list
|
||||||
std::vector<SGVec3f> normals; // normal list
|
std::vector<SGVec3f> normals; // normal list
|
||||||
std::vector<SGVec2f> texcoords; // texture coordinate list
|
std::vector<SGVec2f> texcoords; // texture coordinate list
|
||||||
std::vector<float> va_flt; // vertex attribute list (floats)
|
|
||||||
std::vector<int> va_int; // vertex attribute list (ints)
|
|
||||||
|
|
||||||
group_list pts_v; // points vertex index
|
group_list pts_v; // points vertex index
|
||||||
group_list pts_n; // points normal index
|
group_list pts_n; // points normal index
|
||||||
group_list pts_c; // points color index
|
group_list pts_c; // points color index
|
||||||
group_tci_list pts_tcs; // points texture coordinates ( up to 4 sets )
|
group_list pts_tc; // points texture coordinate index
|
||||||
group_vai_list pts_vas; // points vertex attributes ( up to 8 sets )
|
|
||||||
string_list pt_materials; // points materials
|
string_list pt_materials; // points materials
|
||||||
|
|
||||||
group_list tris_v; // triangles vertex index
|
group_list tris_v; // triangles vertex index
|
||||||
group_list tris_n; // triangles normal index
|
group_list tris_n; // triangles normal index
|
||||||
group_list tris_c; // triangles color index
|
group_list tris_c; // triangles color index
|
||||||
group_tci_list tris_tcs; // triangles texture coordinates ( up to 4 sets )
|
group_list tris_tc; // triangles texture coordinate index
|
||||||
group_vai_list tris_vas; // triangles vertex attributes ( up to 8 sets )
|
|
||||||
string_list tri_materials; // triangles materials
|
string_list tri_materials; // triangles materials
|
||||||
|
|
||||||
group_list strips_v; // tristrips vertex index
|
group_list strips_v; // tristrips vertex index
|
||||||
group_list strips_n; // tristrips normal index
|
group_list strips_n; // tristrips normal index
|
||||||
group_list strips_c; // tristrips color index
|
group_list strips_c; // tristrips color index
|
||||||
group_tci_list strips_tcs; // tristrips texture coordinates ( up to 4 sets )
|
group_list strips_tc; // tristrips texture coordinate index
|
||||||
group_vai_list strips_vas; // tristrips vertex attributes ( up to 8 sets )
|
string_list strip_materials;// tristrips materials
|
||||||
string_list strip_materials; // tristrips materials
|
|
||||||
|
|
||||||
group_list fans_v; // fans vertex index
|
group_list fans_v; // fans vertex index
|
||||||
group_list fans_n; // fans normal index
|
group_list fans_n; // fans normal index
|
||||||
group_list fans_c; // fans color index
|
group_list fans_c; // fans color index
|
||||||
group_tci_list fans_tcs; // fanss texture coordinates ( up to 4 sets )
|
group_list fans_tc; // fans texture coordinate index
|
||||||
group_vai_list fans_vas; // fans vertex attributes ( up to 8 sets )
|
|
||||||
string_list fan_materials; // fans materials
|
string_list fan_materials; // fans materials
|
||||||
|
|
||||||
void read_properties(gzFile fp, int nproperties);
|
void read_properties(gzFile fp, int nproperties);
|
||||||
@@ -193,23 +124,17 @@ private:
|
|||||||
group_list& vertices,
|
group_list& vertices,
|
||||||
group_list& normals,
|
group_list& normals,
|
||||||
group_list& colors,
|
group_list& colors,
|
||||||
group_tci_list& texCoords,
|
group_list& texCoords,
|
||||||
group_vai_list& vertexAttribs,
|
|
||||||
string_list& materials);
|
string_list& materials);
|
||||||
|
|
||||||
void write_header(gzFile fp, int type, int nProps, int nElements);
|
void write_header(gzFile fp, int type, int nProps, int nElements);
|
||||||
void write_objects(gzFile fp,
|
void write_objects(gzFile fp, int type, const group_list& verts,
|
||||||
int type,
|
const group_list& normals, const group_list& colors,
|
||||||
const group_list& verts,
|
const group_list& texCoords, const string_list& materials);
|
||||||
const group_list& normals,
|
|
||||||
const group_list& colors,
|
|
||||||
const group_tci_list& texCoords,
|
|
||||||
const group_vai_list& vertexAttribs,
|
|
||||||
const string_list& materials);
|
|
||||||
|
|
||||||
unsigned int count_objects(const string_list& materials);
|
unsigned int count_objects(const string_list& materials);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
inline unsigned short get_version() const { return version; }
|
inline unsigned short get_version() const { return version; }
|
||||||
|
|
||||||
inline const SGVec3d& get_gbs_center() const { return gbs_center; }
|
inline const SGVec3d& get_gbs_center() const { return gbs_center; }
|
||||||
@@ -218,8 +143,10 @@ public:
|
|||||||
inline float get_gbs_radius() const { return gbs_radius; }
|
inline float get_gbs_radius() const { return gbs_radius; }
|
||||||
inline void set_gbs_radius( float r ) { gbs_radius = r; }
|
inline void set_gbs_radius( float r ) { gbs_radius = r; }
|
||||||
|
|
||||||
inline const std::vector<SGVec3d>& get_wgs84_nodes() const { return wgs84_nodes; }
|
inline const std::vector<SGVec3d>& get_wgs84_nodes() const
|
||||||
inline void set_wgs84_nodes( const std::vector<SGVec3d>& n ) { wgs84_nodes = n; }
|
{ return wgs84_nodes; }
|
||||||
|
inline void set_wgs84_nodes( const std::vector<SGVec3d>& n )
|
||||||
|
{ wgs84_nodes = n; }
|
||||||
|
|
||||||
inline const std::vector<SGVec4f>& get_colors() const { return colors; }
|
inline const std::vector<SGVec4f>& get_colors() const { return colors; }
|
||||||
inline void set_colors( const std::vector<SGVec4f>& c ) { colors = c; }
|
inline void set_colors( const std::vector<SGVec4f>& c ) { colors = c; }
|
||||||
@@ -230,38 +157,51 @@ public:
|
|||||||
inline const std::vector<SGVec2f>& get_texcoords() const { return texcoords; }
|
inline const std::vector<SGVec2f>& get_texcoords() const { return texcoords; }
|
||||||
inline void set_texcoords( const std::vector<SGVec2f>& t ) { texcoords = t; }
|
inline void set_texcoords( const std::vector<SGVec2f>& t ) { texcoords = t; }
|
||||||
|
|
||||||
// Points API
|
|
||||||
bool add_point( const SGBinObjectPoint& pt );
|
|
||||||
inline const group_list& get_pts_v() const { return pts_v; }
|
inline const group_list& get_pts_v() const { return pts_v; }
|
||||||
|
inline void set_pts_v( const group_list& g ) { pts_v = g; }
|
||||||
inline const group_list& get_pts_n() const { return pts_n; }
|
inline const group_list& get_pts_n() const { return pts_n; }
|
||||||
inline const group_tci_list& get_pts_tcs() const { return pts_tcs; }
|
inline void set_pts_n( const group_list& g ) { pts_n = g; }
|
||||||
inline const group_vai_list& get_pts_vas() const { return pts_vas; }
|
inline const group_list& get_pts_c() const { return pts_c; }
|
||||||
|
inline void set_pts_c( const group_list& g ) { pts_c = g; }
|
||||||
|
inline const group_list& get_pts_tc() const { return pts_tc; }
|
||||||
|
inline void set_pts_tc( const group_list& g ) { pts_tc = g; }
|
||||||
inline const string_list& get_pt_materials() const { return pt_materials; }
|
inline const string_list& get_pt_materials() const { return pt_materials; }
|
||||||
|
inline void set_pt_materials( const string_list& s ) { pt_materials = s; }
|
||||||
|
|
||||||
// Triangles API
|
|
||||||
bool add_triangle( const SGBinObjectTriangle& tri );
|
|
||||||
inline const group_list& get_tris_v() const { return tris_v; }
|
inline const group_list& get_tris_v() const { return tris_v; }
|
||||||
|
inline void set_tris_v( const group_list& g ) { tris_v = g; }
|
||||||
inline const group_list& get_tris_n() const { return tris_n; }
|
inline const group_list& get_tris_n() const { return tris_n; }
|
||||||
|
inline void set_tris_n( const group_list& g ) { tris_n = g; }
|
||||||
inline const group_list& get_tris_c() const { return tris_c; }
|
inline const group_list& get_tris_c() const { return tris_c; }
|
||||||
inline const group_tci_list& get_tris_tcs() const { return tris_tcs; }
|
inline void set_tris_c( const group_list& g ) { tris_c = g; }
|
||||||
inline const group_vai_list& get_tris_vas() const { return tris_vas; }
|
inline const group_list& get_tris_tc() const { return tris_tc; }
|
||||||
|
inline void set_tris_tc( const group_list& g ) { tris_tc = g; }
|
||||||
inline const string_list& get_tri_materials() const { return tri_materials; }
|
inline const string_list& get_tri_materials() const { return tri_materials; }
|
||||||
|
inline void set_tri_materials( const string_list& s ) { tri_materials = s; }
|
||||||
|
|
||||||
// Strips API (deprecated - read only)
|
|
||||||
inline const group_list& get_strips_v() const { return strips_v; }
|
inline const group_list& get_strips_v() const { return strips_v; }
|
||||||
|
inline void set_strips_v( const group_list& g ) { strips_v = g; }
|
||||||
inline const group_list& get_strips_n() const { return strips_n; }
|
inline const group_list& get_strips_n() const { return strips_n; }
|
||||||
|
inline void set_strips_n( const group_list& g ) { strips_n = g; }
|
||||||
inline const group_list& get_strips_c() const { return strips_c; }
|
inline const group_list& get_strips_c() const { return strips_c; }
|
||||||
inline const group_tci_list& get_strips_tcs() const { return strips_tcs; }
|
inline void set_strips_c( const group_list& g ) { strips_c = g; }
|
||||||
inline const group_vai_list& get_strips_vas() const { return strips_vas; }
|
|
||||||
|
inline const group_list& get_strips_tc() const { return strips_tc; }
|
||||||
|
inline void set_strips_tc( const group_list& g ) { strips_tc = g; }
|
||||||
inline const string_list& get_strip_materials() const { return strip_materials; }
|
inline const string_list& get_strip_materials() const { return strip_materials; }
|
||||||
|
inline void set_strip_materials( const string_list& s ) { strip_materials = s; }
|
||||||
|
|
||||||
// Fans API (deprecated - read only )
|
|
||||||
inline const group_list& get_fans_v() const { return fans_v; }
|
inline const group_list& get_fans_v() const { return fans_v; }
|
||||||
|
inline void set_fans_v( const group_list& g ) { fans_v = g; }
|
||||||
inline const group_list& get_fans_n() const { return fans_n; }
|
inline const group_list& get_fans_n() const { return fans_n; }
|
||||||
|
inline void set_fans_n( const group_list& g ) { fans_n = g; }
|
||||||
inline const group_list& get_fans_c() const { return fans_c; }
|
inline const group_list& get_fans_c() const { return fans_c; }
|
||||||
inline const group_tci_list& get_fans_tcs() const { return fans_tcs; }
|
inline void set_fans_c( const group_list& g ) { fans_c = g; }
|
||||||
inline const group_vai_list& get_fans_vas() const { return fans_vas; }
|
|
||||||
|
inline const group_list& get_fans_tc() const { return fans_tc; }
|
||||||
|
inline void set_fans_tc( const group_list& g ) { fans_tc = g; }
|
||||||
inline const string_list& get_fan_materials() const { return fan_materials; }
|
inline const string_list& get_fan_materials() const { return fan_materials; }
|
||||||
|
inline void set_fan_materials( const string_list& s ) { fan_materials = s; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read a binary file object and populate the provided structures.
|
* Read a binary file object and populate the provided structures.
|
||||||
|
|||||||
+12
-20
@@ -103,15 +103,6 @@ int_list make_tri(int maxIndex)
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
tci_list make_tri_tcs(int maxIndex)
|
|
||||||
{
|
|
||||||
tci_list tci;
|
|
||||||
tci[0].push_back(random() % maxIndex);
|
|
||||||
tci[0].push_back(random() % maxIndex);
|
|
||||||
tci[0].push_back(random() % maxIndex);
|
|
||||||
return tci;
|
|
||||||
}
|
|
||||||
|
|
||||||
void compareTris(const SGBinObject& a, const SGBinObject& b)
|
void compareTris(const SGBinObject& a, const SGBinObject& b)
|
||||||
{
|
{
|
||||||
unsigned int count = a.get_tri_materials().size();
|
unsigned int count = a.get_tri_materials().size();
|
||||||
@@ -122,31 +113,32 @@ void compareTris(const SGBinObject& a, const SGBinObject& b)
|
|||||||
|
|
||||||
COMPARE(a.get_tri_materials()[i], b.get_tri_materials()[i]);
|
COMPARE(a.get_tri_materials()[i], b.get_tri_materials()[i]);
|
||||||
|
|
||||||
const int_list& tA(a.get_tris_tcs()[i][0]);
|
const int_list& tA(a.get_tris_tc()[i]);
|
||||||
const int_list& tB(b.get_tris_tcs()[i][0]);
|
const int_list& tB(b.get_tris_tc()[i]);
|
||||||
VERIFY(tA == tB);
|
VERIFY(tA == tB);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void generate_tris(SGBinObject& b, int count)
|
void generate_tris(SGBinObject& b, int count)
|
||||||
{
|
{
|
||||||
group_list v, n;
|
group_list v, n, tc;
|
||||||
group_tci_list tc;
|
|
||||||
string_list materials;
|
string_list materials;
|
||||||
|
|
||||||
int maxVertices = b.get_wgs84_nodes().size();
|
int maxVertices = b.get_wgs84_nodes().size();
|
||||||
int maxNormals = b.get_normals().size();
|
int maxNormals = b.get_normals().size();
|
||||||
int maxTCs = b.get_texcoords().size();
|
int maxTCs = b.get_texcoords().size();
|
||||||
|
|
||||||
SGBinObjectTriangle sgboTri;
|
|
||||||
for (int t=0; t<count; ++t) {
|
for (int t=0; t<count; ++t) {
|
||||||
sgboTri.material = "material1";
|
v.push_back(make_tri(maxVertices));
|
||||||
sgboTri.v_list = make_tri(maxVertices);
|
n.push_back(make_tri(maxNormals));
|
||||||
sgboTri.n_list = make_tri(maxNormals);
|
tc.push_back(make_tri(maxTCs));
|
||||||
sgboTri.tc_list[0] = make_tri(maxTCs);
|
materials.push_back("material1");
|
||||||
|
|
||||||
b.add_triangle( sgboTri );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
b.set_tris_v(v);
|
||||||
|
b.set_tris_n(n);
|
||||||
|
b.set_tris_tc(tc);
|
||||||
|
b.set_tri_materials(materials);
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_basic()
|
void test_basic()
|
||||||
|
|||||||
@@ -19,13 +19,10 @@
|
|||||||
# include <simgear_config.h>
|
# include <simgear_config.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <simgear/misc/test_macros.hxx>
|
|
||||||
|
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
#include "SGMath.hxx"
|
#include "SGMath.hxx"
|
||||||
#include "SGRect.hxx"
|
|
||||||
#include "sg_random.h"
|
#include "sg_random.h"
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
@@ -271,33 +268,6 @@ MatrixTest(void)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
void doRectTest()
|
|
||||||
{
|
|
||||||
SGRect<T> rect(10, 15, 20, 25);
|
|
||||||
|
|
||||||
COMPARE(rect.x(), 10)
|
|
||||||
COMPARE(rect.y(), 15)
|
|
||||||
COMPARE(rect.width(), 20)
|
|
||||||
COMPARE(rect.height(), 25)
|
|
||||||
|
|
||||||
COMPARE(rect.pos(), SGVec2<T>(10, 15))
|
|
||||||
COMPARE(rect.size(), SGVec2<T>(20, 25))
|
|
||||||
|
|
||||||
COMPARE(rect.l(), 10)
|
|
||||||
COMPARE(rect.t(), 15)
|
|
||||||
COMPARE(rect.r(), 30)
|
|
||||||
COMPARE(rect.b(), 40)
|
|
||||||
|
|
||||||
VERIFY(rect == rect)
|
|
||||||
VERIFY(rect == SGRect<T>(10, 15, 20, 25))
|
|
||||||
VERIFY(rect != SGRect<T>(11, 15, 20, 25))
|
|
||||||
|
|
||||||
VERIFY(rect.contains(10, 15))
|
|
||||||
VERIFY(!rect.contains(9, 15))
|
|
||||||
VERIFY(rect.contains(9, 15, 1))
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
GeodesyTest(void)
|
GeodesyTest(void)
|
||||||
{
|
{
|
||||||
@@ -381,10 +351,6 @@ main(void)
|
|||||||
if (!MatrixTest<double>())
|
if (!MatrixTest<double>())
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
|
|
||||||
// Do rect tests
|
|
||||||
doRectTest<int>();
|
|
||||||
doRectTest<double>();
|
|
||||||
|
|
||||||
// Check geodetic/geocentric/cartesian conversions
|
// Check geodetic/geocentric/cartesian conversions
|
||||||
if (!GeodesyTest())
|
if (!GeodesyTest())
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
|
|||||||
+1
-32
@@ -34,7 +34,7 @@ class SGRect
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
explicit SGRect(const SGVec2<T>& pt):
|
SGRect(const SGVec2<T>& pt):
|
||||||
_min(pt),
|
_min(pt),
|
||||||
_max(pt)
|
_max(pt)
|
||||||
{
|
{
|
||||||
@@ -88,15 +88,11 @@ class SGRect
|
|||||||
T y() const { return _min.y(); }
|
T y() const { return _min.y(); }
|
||||||
T width() const { return _max.x() - _min.x(); }
|
T width() const { return _max.x() - _min.x(); }
|
||||||
T height() const { return _max.y() - _min.y(); }
|
T height() const { return _max.y() - _min.y(); }
|
||||||
SGVec2<T> const& pos() const { return _min; }
|
|
||||||
SGVec2<T> size() const { return SGVec2<T>(width(), height()); }
|
|
||||||
|
|
||||||
void setX(T x) { T w = width(); _min.x() = x; _max.x() = x + w; }
|
void setX(T x) { T w = width(); _min.x() = x; _max.x() = x + w; }
|
||||||
void setY(T y) { T h = height(); _min.y() = y; _max.y() = y + h; }
|
void setY(T y) { T h = height(); _min.y() = y; _max.y() = y + h; }
|
||||||
void setWidth(T w) { _max.x() = _min.x() + w; }
|
void setWidth(T w) { _max.x() = _min.x() + w; }
|
||||||
void setHeight(T h) { _max.y() = _min.y() + h; }
|
void setHeight(T h) { _max.y() = _min.y() + h; }
|
||||||
void setPos(const SGVec2<T>& p) { setX(p.x()); setY(p.y()); }
|
|
||||||
void setSize(const SGVec2<T>& s) { setWidth(s.x()); setHeight(s.y()); }
|
|
||||||
|
|
||||||
T l() const { return _min.x(); }
|
T l() const { return _min.x(); }
|
||||||
T r() const { return _max.x(); }
|
T r() const { return _max.x(); }
|
||||||
@@ -113,18 +109,6 @@ class SGRect
|
|||||||
void setTop(T t) { _min.y() = t; }
|
void setTop(T t) { _min.y() = t; }
|
||||||
void setBottom(T b) { _max.y() = b; }
|
void setBottom(T b) { _max.y() = b; }
|
||||||
|
|
||||||
/**
|
|
||||||
* Expand rectangle to include the given position
|
|
||||||
*/
|
|
||||||
void expandBy(T x, T y)
|
|
||||||
{
|
|
||||||
if( x < _min.x() ) _min.x() = x;
|
|
||||||
if( x > _max.x() ) _max.x() = x;
|
|
||||||
|
|
||||||
if( y < _min.y() ) _min.y() = y;
|
|
||||||
if( y > _max.y() ) _max.y() = y;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Move rect by vector
|
* Move rect by vector
|
||||||
*/
|
*/
|
||||||
@@ -145,17 +129,6 @@ class SGRect
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator==(const SGRect<T>& rhs) const
|
|
||||||
{
|
|
||||||
return _min == rhs._min
|
|
||||||
&& _max == rhs._max;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator!=(const SGRect<T>& rhs) const
|
|
||||||
{
|
|
||||||
return !(*this == rhs);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool contains(T x, T y) const
|
bool contains(T x, T y) const
|
||||||
{
|
{
|
||||||
return _min.x() <= x && x <= _max.x()
|
return _min.x() <= x && x <= _max.x()
|
||||||
@@ -203,8 +176,4 @@ std::basic_ostream<char_type, traits_type>&
|
|||||||
operator<<(std::basic_ostream<char_type, traits_type>& s, const SGRect<T>& rect)
|
operator<<(std::basic_ostream<char_type, traits_type>& s, const SGRect<T>& rect)
|
||||||
{ return s << "min = " << rect.getMin() << ", max = " << rect.getMax(); }
|
{ return s << "min = " << rect.getMin() << ", max = " << rect.getMax(); }
|
||||||
|
|
||||||
typedef SGRect<int> SGRecti;
|
|
||||||
typedef SGRect<float> SGRectf;
|
|
||||||
typedef SGRect<double> SGRectd;
|
|
||||||
|
|
||||||
#endif /* SG_RECT_HXX_ */
|
#endif /* SG_RECT_HXX_ */
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#ifndef SGTriangle_H
|
#ifndef SGTriangle_H
|
||||||
#define SGTriangle_H
|
#define SGTrianlge_H
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
class SGTriangle {
|
class SGTriangle {
|
||||||
|
|||||||
@@ -5,8 +5,6 @@ set(HEADERS
|
|||||||
CSSBorder.hxx
|
CSSBorder.hxx
|
||||||
ListDiff.hxx
|
ListDiff.hxx
|
||||||
ResourceManager.hxx
|
ResourceManager.hxx
|
||||||
SimpleMarkdown.hxx
|
|
||||||
SVGpreserveAspectRatio.hxx
|
|
||||||
interpolator.hxx
|
interpolator.hxx
|
||||||
make_new.hxx
|
make_new.hxx
|
||||||
sg_dir.hxx
|
sg_dir.hxx
|
||||||
@@ -24,8 +22,6 @@ set(HEADERS
|
|||||||
set(SOURCES
|
set(SOURCES
|
||||||
CSSBorder.cxx
|
CSSBorder.cxx
|
||||||
ResourceManager.cxx
|
ResourceManager.cxx
|
||||||
SimpleMarkdown.cxx
|
|
||||||
SVGpreserveAspectRatio.cxx
|
|
||||||
interpolator.cxx
|
interpolator.cxx
|
||||||
sg_dir.cxx
|
sg_dir.cxx
|
||||||
sg_path.cxx
|
sg_path.cxx
|
||||||
@@ -37,10 +33,6 @@ set(SOURCES
|
|||||||
gzcontainerfile.cxx
|
gzcontainerfile.cxx
|
||||||
)
|
)
|
||||||
|
|
||||||
if (APPLE)
|
|
||||||
list(APPEND SOURCES CocoaHelpers.mm)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
simgear_component(misc misc "${SOURCES}" "${HEADERS}")
|
simgear_component(misc misc "${SOURCES}" "${HEADERS}")
|
||||||
|
|
||||||
if(ENABLE_TESTS)
|
if(ENABLE_TESTS)
|
||||||
@@ -53,6 +45,10 @@ add_executable(test_tabbed_values tabbed_values_test.cxx)
|
|||||||
add_test(tabbed_values ${EXECUTABLE_OUTPUT_PATH}/test_tabbed_values)
|
add_test(tabbed_values ${EXECUTABLE_OUTPUT_PATH}/test_tabbed_values)
|
||||||
target_link_libraries(test_tabbed_values ${TEST_LIBS})
|
target_link_libraries(test_tabbed_values ${TEST_LIBS})
|
||||||
|
|
||||||
|
add_executable(test_strings strutils_test.cxx )
|
||||||
|
add_test(strings ${EXECUTABLE_OUTPUT_PATH}/test_strings)
|
||||||
|
target_link_libraries(test_strings ${TEST_LIBS})
|
||||||
|
|
||||||
add_executable(test_streams sgstream_test.cxx )
|
add_executable(test_streams sgstream_test.cxx )
|
||||||
add_test(streams ${EXECUTABLE_OUTPUT_PATH}/test_streams)
|
add_test(streams ${EXECUTABLE_OUTPUT_PATH}/test_streams)
|
||||||
target_link_libraries(test_streams ${TEST_LIBS})
|
target_link_libraries(test_streams ${TEST_LIBS})
|
||||||
@@ -62,23 +58,3 @@ add_test(path ${EXECUTABLE_OUTPUT_PATH}/test_path)
|
|||||||
target_link_libraries(test_path ${TEST_LIBS})
|
target_link_libraries(test_path ${TEST_LIBS})
|
||||||
|
|
||||||
endif(ENABLE_TESTS)
|
endif(ENABLE_TESTS)
|
||||||
|
|
||||||
add_boost_test(SimpleMarkdown
|
|
||||||
SOURCES SimpleMarkdown_test.cxx
|
|
||||||
LIBRARIES ${TEST_LIBS}
|
|
||||||
)
|
|
||||||
|
|
||||||
add_boost_test(SVGpreserveAspectRatio
|
|
||||||
SOURCES SVGpreserveAspectRatio_test.cxx
|
|
||||||
LIBRARIES ${TEST_LIBS}
|
|
||||||
)
|
|
||||||
|
|
||||||
add_boost_test(strutils
|
|
||||||
SOURCES strutils_test.cxx
|
|
||||||
LIBRARIES ${TEST_LIBS}
|
|
||||||
)
|
|
||||||
|
|
||||||
add_boost_test(utf8tolatin1
|
|
||||||
SOURCES utf8tolatin1_test.cxx
|
|
||||||
LIBRARIES ${TEST_LIBS}
|
|
||||||
)
|
|
||||||
|
|||||||
@@ -1,41 +0,0 @@
|
|||||||
#include <Cocoa/Cocoa.h>
|
|
||||||
#include <Foundation/NSAutoreleasePool.h>
|
|
||||||
|
|
||||||
#include <simgear/misc/sg_path.hxx>
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
class CocoaAutoreleasePool
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
CocoaAutoreleasePool()
|
|
||||||
{
|
|
||||||
pool = [[NSAutoreleasePool alloc] init];
|
|
||||||
}
|
|
||||||
|
|
||||||
~CocoaAutoreleasePool()
|
|
||||||
{
|
|
||||||
[pool release];
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
NSAutoreleasePool* pool;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // of anonyous namespace
|
|
||||||
|
|
||||||
SGPath appleSpecialFolder(int dirType, int domainMask, const SGPath& def)
|
|
||||||
{
|
|
||||||
CocoaAutoreleasePool ap;
|
|
||||||
NSFileManager* fm = [NSFileManager defaultManager];
|
|
||||||
NSURL* pathUrl = [fm URLForDirectory:dirType
|
|
||||||
inDomain:domainMask
|
|
||||||
appropriateForURL:Nil
|
|
||||||
create:YES
|
|
||||||
error:nil];
|
|
||||||
if (!pathUrl) {
|
|
||||||
return def;;
|
|
||||||
}
|
|
||||||
|
|
||||||
return SGPath([[pathUrl path] UTF8String], def.getPermissionChecker());
|
|
||||||
}
|
|
||||||
@@ -1,192 +0,0 @@
|
|||||||
// Parse and represent SVG preserveAspectRatio attribute
|
|
||||||
//
|
|
||||||
// Copyright (C) 2014 Thomas Geymayer <tomgey@gmail.com>
|
|
||||||
//
|
|
||||||
// This library is free software; you can redistribute it and/or
|
|
||||||
// modify it under the terms of the GNU Library General Public
|
|
||||||
// License as published by the Free Software Foundation; either
|
|
||||||
// version 2 of the License, or (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
// Library General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Library General Public
|
|
||||||
// License along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
|
||||||
|
|
||||||
#include "SVGpreserveAspectRatio.hxx"
|
|
||||||
|
|
||||||
#include <simgear/debug/logstream.hxx>
|
|
||||||
#include <simgear/misc/strutils.hxx>
|
|
||||||
|
|
||||||
#include <boost/tokenizer.hpp>
|
|
||||||
|
|
||||||
namespace simgear
|
|
||||||
{
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
SVGpreserveAspectRatio::SVGpreserveAspectRatio():
|
|
||||||
_align_x(ALIGN_NONE),
|
|
||||||
_align_y(ALIGN_NONE),
|
|
||||||
_meet(true)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
SVGpreserveAspectRatio::Align SVGpreserveAspectRatio::alignX() const
|
|
||||||
{
|
|
||||||
return _align_x;
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
SVGpreserveAspectRatio::Align SVGpreserveAspectRatio::alignY() const
|
|
||||||
{
|
|
||||||
return _align_y;
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
bool SVGpreserveAspectRatio::scaleToFill() const
|
|
||||||
{
|
|
||||||
return (_align_x == ALIGN_NONE) && (_align_y == ALIGN_NONE);
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
bool SVGpreserveAspectRatio::scaleToFit() const
|
|
||||||
{
|
|
||||||
return !scaleToFill() && _meet;
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
bool SVGpreserveAspectRatio::scaleToCrop() const
|
|
||||||
{
|
|
||||||
return !scaleToFill() && !_meet;
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
bool SVGpreserveAspectRatio::meet() const
|
|
||||||
{
|
|
||||||
return _meet;
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
bool
|
|
||||||
SVGpreserveAspectRatio::operator==(const SVGpreserveAspectRatio& rhs) const
|
|
||||||
{
|
|
||||||
return (_align_x == rhs._align_x)
|
|
||||||
&& (_align_y == rhs._align_y)
|
|
||||||
&& (_meet == rhs._meet || scaleToFill());
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
SVGpreserveAspectRatio SVGpreserveAspectRatio::parse(const std::string& str)
|
|
||||||
{
|
|
||||||
SVGpreserveAspectRatio ret;
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
PARSE_defer,
|
|
||||||
PARSE_align,
|
|
||||||
PARSE_meetOrSlice,
|
|
||||||
PARSE_done,
|
|
||||||
PARSE_error
|
|
||||||
} parse_state = PARSE_defer;
|
|
||||||
|
|
||||||
typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
|
|
||||||
const boost::char_separator<char> del(" \t\n");
|
|
||||||
|
|
||||||
tokenizer tokens(str.begin(), str.end(), del);
|
|
||||||
for( tokenizer::const_iterator tok = tokens.begin();
|
|
||||||
tok != tokens.end()
|
|
||||||
&& parse_state != PARSE_error;
|
|
||||||
++tok )
|
|
||||||
{
|
|
||||||
const std::string& cur_tok = tok.current_token();
|
|
||||||
|
|
||||||
switch( parse_state )
|
|
||||||
{
|
|
||||||
case PARSE_defer:
|
|
||||||
if( cur_tok == "defer" )
|
|
||||||
{
|
|
||||||
SG_LOG( SG_GENERAL,
|
|
||||||
SG_INFO,
|
|
||||||
"SVGpreserveAspectRatio: 'defer' is ignored." );
|
|
||||||
parse_state = PARSE_align;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
// fall through
|
|
||||||
case PARSE_align:
|
|
||||||
if( cur_tok == "none" )
|
|
||||||
{
|
|
||||||
ret._align_x = ALIGN_NONE;
|
|
||||||
ret._align_y = ALIGN_NONE;
|
|
||||||
}
|
|
||||||
else if( cur_tok.length() == 8 )
|
|
||||||
{
|
|
||||||
if( strutils::starts_with(cur_tok, "xMin") )
|
|
||||||
ret._align_x = ALIGN_MIN;
|
|
||||||
else if( strutils::starts_with(cur_tok, "xMid") )
|
|
||||||
ret._align_x = ALIGN_MID;
|
|
||||||
else if( strutils::starts_with(cur_tok, "xMax") )
|
|
||||||
ret._align_x = ALIGN_MAX;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
parse_state = PARSE_error;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( strutils::ends_with(cur_tok, "YMin") )
|
|
||||||
ret._align_y = ALIGN_MIN;
|
|
||||||
else if( strutils::ends_with(cur_tok, "YMid") )
|
|
||||||
ret._align_y = ALIGN_MID;
|
|
||||||
else if( strutils::ends_with(cur_tok, "YMax") )
|
|
||||||
ret._align_y = ALIGN_MAX;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
parse_state = PARSE_error;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
parse_state = PARSE_error;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
parse_state = PARSE_meetOrSlice;
|
|
||||||
break;
|
|
||||||
case PARSE_meetOrSlice:
|
|
||||||
if( cur_tok == "meet" )
|
|
||||||
ret._meet = true;
|
|
||||||
else if( cur_tok == "slice" )
|
|
||||||
ret._meet = false;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
parse_state = PARSE_error;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
parse_state = PARSE_done;
|
|
||||||
break;
|
|
||||||
case PARSE_done:
|
|
||||||
SG_LOG( SG_GENERAL,
|
|
||||||
SG_WARN,
|
|
||||||
"SVGpreserveAspectRatio: Ignoring superfluous token"
|
|
||||||
" '" << cur_tok << "'" );
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if( parse_state == PARSE_error )
|
|
||||||
{
|
|
||||||
SG_LOG( SG_GENERAL,
|
|
||||||
SG_WARN,
|
|
||||||
"SVGpreserveAspectRatio: Failed to parse: '" << str << "'" );
|
|
||||||
return SVGpreserveAspectRatio();
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace simgear
|
|
||||||
@@ -1,67 +0,0 @@
|
|||||||
///@file Parse and represent SVG preserveAspectRatio attribute
|
|
||||||
//
|
|
||||||
// Copyright (C) 2014 Thomas Geymayer <tomgey@gmail.com>
|
|
||||||
//
|
|
||||||
// This library is free software; you can redistribute it and/or
|
|
||||||
// modify it under the terms of the GNU Library General Public
|
|
||||||
// License as published by the Free Software Foundation; either
|
|
||||||
// version 2 of the License, or (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
// Library General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Library General Public
|
|
||||||
// License along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
|
||||||
|
|
||||||
#ifndef SG_SVG_PRESERVE_ASPECT_RATIO_HXX_
|
|
||||||
#define SG_SVG_PRESERVE_ASPECT_RATIO_HXX_
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
namespace simgear
|
|
||||||
{
|
|
||||||
|
|
||||||
/**
|
|
||||||
* SVG preserveAspectRatio attribute
|
|
||||||
*
|
|
||||||
* @see http://www.w3.org/TR/SVG11/coords.html#PreserveAspectRatioAttribute
|
|
||||||
*/
|
|
||||||
class SVGpreserveAspectRatio
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
enum Align
|
|
||||||
{
|
|
||||||
ALIGN_NONE,
|
|
||||||
ALIGN_MIN,
|
|
||||||
ALIGN_MID,
|
|
||||||
ALIGN_MAX
|
|
||||||
};
|
|
||||||
|
|
||||||
SVGpreserveAspectRatio();
|
|
||||||
|
|
||||||
Align alignX() const;
|
|
||||||
Align alignY() const;
|
|
||||||
|
|
||||||
bool scaleToFill() const;
|
|
||||||
bool scaleToFit() const;
|
|
||||||
bool scaleToCrop() const;
|
|
||||||
|
|
||||||
bool meet() const;
|
|
||||||
|
|
||||||
bool operator==(const SVGpreserveAspectRatio& rhs) const;
|
|
||||||
|
|
||||||
static SVGpreserveAspectRatio parse(const std::string& str);
|
|
||||||
|
|
||||||
private:
|
|
||||||
Align _align_x,
|
|
||||||
_align_y;
|
|
||||||
bool _meet; //!< uniform scale to fit, if true
|
|
||||||
// uniform scale to fill+crop, if false
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace simgear
|
|
||||||
|
|
||||||
#endif /* SG_SVG_PRESERVE_ASPECT_RATIO_HXX_ */
|
|
||||||
@@ -1,60 +0,0 @@
|
|||||||
/// Unit tests for SVGpreserveAspectRatio
|
|
||||||
#define BOOST_TEST_MODULE misc
|
|
||||||
#include <BoostTestTargetConfig.h>
|
|
||||||
|
|
||||||
#include "SVGpreserveAspectRatio.hxx"
|
|
||||||
|
|
||||||
namespace simgear
|
|
||||||
{
|
|
||||||
std::ostream& operator<<( std::ostream& strm,
|
|
||||||
const SVGpreserveAspectRatio& ar )
|
|
||||||
{
|
|
||||||
strm << "[ align_x=" << ar.alignX() <<
|
|
||||||
", align_y=" << ar.alignY() <<
|
|
||||||
", meet=" << ar.meet() <<
|
|
||||||
"]";
|
|
||||||
return strm;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE( parse_attribute )
|
|
||||||
{
|
|
||||||
using simgear::SVGpreserveAspectRatio;
|
|
||||||
|
|
||||||
SVGpreserveAspectRatio ar = SVGpreserveAspectRatio::parse("none");
|
|
||||||
BOOST_CHECK( ar.scaleToFill() );
|
|
||||||
BOOST_CHECK( !ar.scaleToFit() );
|
|
||||||
BOOST_CHECK( !ar.scaleToCrop() );
|
|
||||||
BOOST_CHECK_EQUAL( ar.alignX(), SVGpreserveAspectRatio::ALIGN_NONE );
|
|
||||||
BOOST_CHECK_EQUAL( ar.alignY(), SVGpreserveAspectRatio::ALIGN_NONE );
|
|
||||||
|
|
||||||
SVGpreserveAspectRatio ar_meet = SVGpreserveAspectRatio::parse("none meet");
|
|
||||||
SVGpreserveAspectRatio ar_slice = SVGpreserveAspectRatio::parse("none slice");
|
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL( ar, ar_meet );
|
|
||||||
BOOST_CHECK_EQUAL( ar, ar_slice );
|
|
||||||
|
|
||||||
ar_meet = SVGpreserveAspectRatio::parse("xMidYMid meet");
|
|
||||||
BOOST_CHECK( !ar_meet.scaleToFill() );
|
|
||||||
BOOST_CHECK( ar_meet.scaleToFit() );
|
|
||||||
BOOST_CHECK( !ar_meet.scaleToCrop() );
|
|
||||||
BOOST_CHECK_EQUAL( ar_meet.alignX(), SVGpreserveAspectRatio::ALIGN_MID );
|
|
||||||
BOOST_CHECK_EQUAL( ar_meet.alignY(), SVGpreserveAspectRatio::ALIGN_MID );
|
|
||||||
|
|
||||||
ar_slice = SVGpreserveAspectRatio::parse("xMidYMid slice");
|
|
||||||
BOOST_CHECK( !ar_slice.scaleToFill() );
|
|
||||||
BOOST_CHECK( !ar_slice.scaleToFit() );
|
|
||||||
BOOST_CHECK( ar_slice.scaleToCrop() );
|
|
||||||
BOOST_CHECK_EQUAL( ar_slice.alignX(), SVGpreserveAspectRatio::ALIGN_MID );
|
|
||||||
BOOST_CHECK_EQUAL( ar_slice.alignY(), SVGpreserveAspectRatio::ALIGN_MID );
|
|
||||||
|
|
||||||
BOOST_CHECK_NE(ar_meet, ar_slice);
|
|
||||||
|
|
||||||
// defer is ignored, meet is default
|
|
||||||
ar_meet = SVGpreserveAspectRatio::parse("defer xMinYMin");
|
|
||||||
BOOST_CHECK( !ar_meet.scaleToFill() );
|
|
||||||
BOOST_CHECK( ar_meet.scaleToFit() );
|
|
||||||
BOOST_CHECK( !ar_meet.scaleToCrop() );
|
|
||||||
BOOST_CHECK_EQUAL( ar_meet.alignX(), SVGpreserveAspectRatio::ALIGN_MIN );
|
|
||||||
BOOST_CHECK_EQUAL( ar_meet.alignY(), SVGpreserveAspectRatio::ALIGN_MIN );
|
|
||||||
}
|
|
||||||
@@ -1,104 +0,0 @@
|
|||||||
// Really simple markdown parser
|
|
||||||
//
|
|
||||||
// Copyright (C) 2014 Thomas Geymayer <tomgey@gmail.com>
|
|
||||||
//
|
|
||||||
// This library is free software; you can redistribute it and/or
|
|
||||||
// modify it under the terms of the GNU Library General Public
|
|
||||||
// License as published by the Free Software Foundation; either
|
|
||||||
// version 2 of the License, or (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
// Library General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Library General Public
|
|
||||||
// License along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
|
||||||
|
|
||||||
#include "SimpleMarkdown.hxx"
|
|
||||||
|
|
||||||
namespace simgear
|
|
||||||
{
|
|
||||||
|
|
||||||
// White space
|
|
||||||
static bool isSpace(const char c)
|
|
||||||
{
|
|
||||||
return c == ' ' || c == '\t';
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unordered list item
|
|
||||||
static bool isULItem(const char c)
|
|
||||||
{
|
|
||||||
return c == '*' || c == '+' || c == '-';
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
std::string SimpleMarkdown::parse(const std::string& src)
|
|
||||||
{
|
|
||||||
std::string out;
|
|
||||||
|
|
||||||
int num_space = 0,
|
|
||||||
num_newline = 0;
|
|
||||||
bool line_empty = true;
|
|
||||||
|
|
||||||
for( std::string::const_iterator it = src.begin();
|
|
||||||
it != src.end();
|
|
||||||
++it )
|
|
||||||
{
|
|
||||||
if( isSpace(*it) )
|
|
||||||
{
|
|
||||||
++num_space;
|
|
||||||
}
|
|
||||||
else if( *it == '\n' )
|
|
||||||
{
|
|
||||||
// Two or more whitespace at end of line -> line break
|
|
||||||
if( !line_empty && num_space >= 2 )
|
|
||||||
{
|
|
||||||
out.push_back('\n');
|
|
||||||
line_empty = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
++num_newline;
|
|
||||||
num_space = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Remove all new lines before first printable character
|
|
||||||
if( out.empty() )
|
|
||||||
num_newline = 0;
|
|
||||||
|
|
||||||
// Two or more new lines (aka. at least one empty line) -> new paragraph
|
|
||||||
if( num_newline >= 2 )
|
|
||||||
{
|
|
||||||
out.append("\n\n");
|
|
||||||
|
|
||||||
line_empty = true;
|
|
||||||
num_newline = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Replace unordered list item markup at begin of line with bullet
|
|
||||||
// (TODO multilevel lists, indent multiple lines, etc.)
|
|
||||||
if( (line_empty || num_newline) && isULItem(*it) )
|
|
||||||
{
|
|
||||||
if( num_newline < 2 )
|
|
||||||
out.push_back('\n');
|
|
||||||
out.append("\xE2\x80\xA2");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Collapse multiple whitespace
|
|
||||||
if( !line_empty && (num_space || num_newline) )
|
|
||||||
out.push_back(' ');
|
|
||||||
out.push_back(*it);
|
|
||||||
}
|
|
||||||
|
|
||||||
line_empty = false;
|
|
||||||
num_space = 0;
|
|
||||||
num_newline = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace simgear
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
///@file Really simple markdown parser
|
|
||||||
//
|
|
||||||
// Copyright (C) 2014 Thomas Geymayer <tomgey@gmail.com>
|
|
||||||
//
|
|
||||||
// This library is free software; you can redistribute it and/or
|
|
||||||
// modify it under the terms of the GNU Library General Public
|
|
||||||
// License as published by the Free Software Foundation; either
|
|
||||||
// version 2 of the License, or (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
// Library General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Library General Public
|
|
||||||
// License along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
|
||||||
|
|
||||||
#ifndef SIMPLE_MARKDOWN_HXX_
|
|
||||||
#define SIMPLE_MARKDOWN_HXX_
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
namespace simgear
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Really simple mardown parser. Currently just paragraphs, new lines and
|
|
||||||
* one level of unordered lists are supported.
|
|
||||||
*
|
|
||||||
* @see http://en.wikipedia.org/wiki/Markdown
|
|
||||||
*/
|
|
||||||
class SimpleMarkdown
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
static std::string parse(const std::string& src);
|
|
||||||
};
|
|
||||||
} // namespace simgear
|
|
||||||
|
|
||||||
#endif /* SIMPLE_MARKDOWN_HXX_ */
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
/// Unit tests for simple markdown parser
|
|
||||||
#define BOOST_TEST_MODULE misc
|
|
||||||
#include <BoostTestTargetConfig.h>
|
|
||||||
|
|
||||||
#include "SimpleMarkdown.hxx"
|
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE( basic_markdown )
|
|
||||||
{
|
|
||||||
std::string const src(
|
|
||||||
" \n"
|
|
||||||
"\n"
|
|
||||||
"blub\n"
|
|
||||||
"* \tlist item\n"
|
|
||||||
"* another\t item\n"
|
|
||||||
"\n"
|
|
||||||
"test blubt\n"
|
|
||||||
" aha \n"
|
|
||||||
"asd\n"
|
|
||||||
" * 2nd list, another item\n"
|
|
||||||
" * 2nd list, one more..."
|
|
||||||
);
|
|
||||||
std::string const out(
|
|
||||||
"blub\n"
|
|
||||||
"\xE2\x80\xA2 list item\n"
|
|
||||||
"\xE2\x80\xA2 another item\n"
|
|
||||||
"\n"
|
|
||||||
"test blubt aha\n"
|
|
||||||
"asd\n"
|
|
||||||
"\xE2\x80\xA2 2nd list, another item\n"
|
|
||||||
"\xE2\x80\xA2 2nd list, one more..."
|
|
||||||
);
|
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(simgear::SimpleMarkdown::parse(src), out);
|
|
||||||
}
|
|
||||||
@@ -41,20 +41,6 @@ void test_dir()
|
|||||||
}
|
}
|
||||||
|
|
||||||
cout << temp.path().modTime() << endl;
|
cout << temp.path().modTime() << endl;
|
||||||
|
|
||||||
std::cout << "Standard Locations:"
|
|
||||||
<< "\n - Home: " << SGPath::standardLocation(SGPath::HOME)
|
|
||||||
<< "\n - Desktop: " << SGPath::standardLocation(SGPath::DESKTOP)
|
|
||||||
<< "\n - Downloads: " << SGPath::standardLocation(SGPath::DOWNLOADS)
|
|
||||||
<< "\n - Documents: " << SGPath::standardLocation(SGPath::DOCUMENTS)
|
|
||||||
<< "\n - Pictures: " << SGPath::standardLocation(SGPath::PICTURES)
|
|
||||||
<< std::endl;
|
|
||||||
|
|
||||||
VERIFY( !SGPath::standardLocation(SGPath::HOME ).isNull() );
|
|
||||||
VERIFY( !SGPath::standardLocation(SGPath::DESKTOP ).isNull() );
|
|
||||||
VERIFY( !SGPath::standardLocation(SGPath::DOWNLOADS).isNull() );
|
|
||||||
VERIFY( !SGPath::standardLocation(SGPath::DOCUMENTS).isNull() );
|
|
||||||
VERIFY( !SGPath::standardLocation(SGPath::PICTURES ).isNull() );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SGPath::Permissions validateNone(const SGPath&)
|
SGPath::Permissions validateNone(const SGPath&)
|
||||||
@@ -192,12 +178,12 @@ int main(int argc, char* argv[])
|
|||||||
pp.append("./test-dir/file.txt");
|
pp.append("./test-dir/file.txt");
|
||||||
COMPARE(pp.create_dir(0700), -3);
|
COMPARE(pp.create_dir(0700), -3);
|
||||||
|
|
||||||
pp.setPermissionChecker(&validateRead);
|
pp.setPermissonChecker(&validateRead);
|
||||||
COMPARE(pp.canRead(), true);
|
COMPARE(pp.canRead(), true);
|
||||||
COMPARE(pp.canWrite(), false);
|
COMPARE(pp.canWrite(), false);
|
||||||
COMPARE(pp.create_dir(0700), -3);
|
COMPARE(pp.create_dir(0700), -3);
|
||||||
|
|
||||||
pp.setPermissionChecker(&validateWrite);
|
pp.setPermissonChecker(&validateWrite);
|
||||||
COMPARE(pp.canRead(), false);
|
COMPARE(pp.canRead(), false);
|
||||||
COMPARE(pp.canWrite(), true);
|
COMPARE(pp.canWrite(), true);
|
||||||
|
|
||||||
|
|||||||
+91
-126
@@ -56,9 +56,10 @@ static const char sgSearchPathSep = ':';
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
|
||||||
#include <ShlObj.h> // for CSIDL
|
#include <ShlObj.h> // for CSIDL
|
||||||
|
|
||||||
static SGPath pathForCSIDL(int csidl, const SGPath& def)
|
static SGPath pathForCSIDL(int csidl, const SGPath::PermissonChecker& checker)
|
||||||
{
|
{
|
||||||
typedef BOOL (WINAPI*GetSpecialFolderPath)(HWND, LPSTR, int, BOOL);
|
typedef BOOL (WINAPI*GetSpecialFolderPath)(HWND, LPSTR, int, BOOL);
|
||||||
static GetSpecialFolderPath SHGetSpecialFolderPath = NULL;
|
static GetSpecialFolderPath SHGetSpecialFolderPath = NULL;
|
||||||
@@ -70,63 +71,17 @@ static SGPath pathForCSIDL(int csidl, const SGPath& def)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!SHGetSpecialFolderPath){
|
if (!SHGetSpecialFolderPath){
|
||||||
return def;
|
return SGPath();
|
||||||
}
|
}
|
||||||
|
|
||||||
char path[MAX_PATH];
|
char path[MAX_PATH];
|
||||||
if (SHGetSpecialFolderPath(0, path, csidl, false)) {
|
if (SHGetSpecialFolderPath(0, path, csidl, false)) {
|
||||||
return SGPath(path, def.getPermissionChecker());
|
return SGPath(path, checker);
|
||||||
}
|
}
|
||||||
|
|
||||||
return def;
|
return SGPath();
|
||||||
}
|
}
|
||||||
#elif __APPLE__
|
|
||||||
|
|
||||||
// defined in CocoaHelpers.mm
|
|
||||||
SGPath appleSpecialFolder(int dirType, int domainMask, const SGPath& def);
|
|
||||||
|
|
||||||
#else
|
|
||||||
static SGPath getXDGDir( const std::string& name,
|
|
||||||
const SGPath& def,
|
|
||||||
const std::string& fallback )
|
|
||||||
{
|
|
||||||
// http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
|
|
||||||
|
|
||||||
// $XDG_CONFIG_HOME defines the base directory relative to which user specific
|
|
||||||
// configuration files should be stored. If $XDG_CONFIG_HOME is either not set
|
|
||||||
// or empty, a default equal to $HOME/.config should be used.
|
|
||||||
const SGPath user_dirs = SGPath::fromEnv( "XDG_CONFIG_HOME",
|
|
||||||
SGPath::home() / ".config")
|
|
||||||
/ "user-dirs.dirs";
|
|
||||||
|
|
||||||
// Format is XDG_xxx_DIR="$HOME/yyy", where yyy is a shell-escaped
|
|
||||||
// homedir-relative path, or XDG_xxx_DIR="/yyy", where /yyy is an absolute
|
|
||||||
// path. No other format is supported.
|
|
||||||
const std::string XDG_ID = "XDG_" + name + "_DIR=\"";
|
|
||||||
|
|
||||||
std::ifstream user_dirs_file( user_dirs.c_str() );
|
|
||||||
std::string line;
|
|
||||||
while( std::getline(user_dirs_file, line).good() )
|
|
||||||
{
|
|
||||||
if( !starts_with(line, XDG_ID) || *line.rbegin() != '"' )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// Extract dir from XDG_<name>_DIR="<dir>"
|
|
||||||
line = line.substr(XDG_ID.length(), line.length() - XDG_ID.length() - 1 );
|
|
||||||
|
|
||||||
const std::string HOME = "$HOME";
|
|
||||||
if( starts_with(line, HOME) )
|
|
||||||
return SGPath::home(def)
|
|
||||||
/ simgear::strutils::unescape(line.substr(HOME.length()));
|
|
||||||
|
|
||||||
return SGPath(line, def.getPermissionChecker());
|
|
||||||
}
|
|
||||||
|
|
||||||
if( def.isNull() )
|
|
||||||
return SGPath::home(def) / fallback;
|
|
||||||
|
|
||||||
return def;
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// For windows, replace "\" by "/".
|
// For windows, replace "\" by "/".
|
||||||
@@ -148,7 +103,7 @@ SGPath::fix()
|
|||||||
|
|
||||||
|
|
||||||
// default constructor
|
// default constructor
|
||||||
SGPath::SGPath(PermissionChecker validator)
|
SGPath::SGPath(PermissonChecker validator)
|
||||||
: path(""),
|
: path(""),
|
||||||
_permission_checker(validator),
|
_permission_checker(validator),
|
||||||
_cached(false),
|
_cached(false),
|
||||||
@@ -159,7 +114,7 @@ SGPath::SGPath(PermissionChecker validator)
|
|||||||
|
|
||||||
|
|
||||||
// create a path based on "path"
|
// create a path based on "path"
|
||||||
SGPath::SGPath( const std::string& p, PermissionChecker validator )
|
SGPath::SGPath( const std::string& p, PermissonChecker validator )
|
||||||
: path(p),
|
: path(p),
|
||||||
_permission_checker(validator),
|
_permission_checker(validator),
|
||||||
_cached(false),
|
_cached(false),
|
||||||
@@ -172,7 +127,7 @@ SGPath::SGPath( const std::string& p, PermissionChecker validator )
|
|||||||
// create a path based on "path" and a "subpath"
|
// create a path based on "path" and a "subpath"
|
||||||
SGPath::SGPath( const SGPath& p,
|
SGPath::SGPath( const SGPath& p,
|
||||||
const std::string& r,
|
const std::string& r,
|
||||||
PermissionChecker validator )
|
PermissonChecker validator )
|
||||||
: path(p.path),
|
: path(p.path),
|
||||||
_permission_checker(validator),
|
_permission_checker(validator),
|
||||||
_cached(false),
|
_cached(false),
|
||||||
@@ -228,14 +183,14 @@ void SGPath::set( const string& p ) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
void SGPath::setPermissionChecker(PermissionChecker validator)
|
void SGPath::setPermissonChecker(PermissonChecker validator)
|
||||||
{
|
{
|
||||||
_permission_checker = validator;
|
_permission_checker = validator;
|
||||||
_rwCached = false;
|
_rwCached = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
SGPath::PermissionChecker SGPath::getPermissionChecker() const
|
SGPath::PermissonChecker SGPath::getPermissonChecker() const
|
||||||
{
|
{
|
||||||
return _permission_checker;
|
return _permission_checker;
|
||||||
}
|
}
|
||||||
@@ -379,7 +334,6 @@ string SGPath::complete_lower_extension() const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
void SGPath::validate() const
|
void SGPath::validate() const
|
||||||
{
|
{
|
||||||
if (_cached && _cacheEnabled) {
|
if (_cached && _cacheEnabled) {
|
||||||
@@ -424,7 +378,6 @@ void SGPath::validate() const
|
|||||||
_cached = true;
|
_cached = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
void SGPath::checkAccess() const
|
void SGPath::checkAccess() const
|
||||||
{
|
{
|
||||||
if( _rwCached && _cacheEnabled )
|
if( _rwCached && _cacheEnabled )
|
||||||
@@ -477,23 +430,14 @@ bool SGPath::isFile() const
|
|||||||
return _exists && _isFile;
|
return _exists && _isFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
# define sgMkDir(d,m) _mkdir(d)
|
# define sgMkDir(d,m) _mkdir(d)
|
||||||
#else
|
#else
|
||||||
# define sgMkDir(d,m) mkdir(d,m)
|
# define sgMkDir(d,m) mkdir(d,m)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int SGPath::create_dir(mode_t mode)
|
|
||||||
{
|
|
||||||
if( !canWrite() )
|
|
||||||
{
|
|
||||||
SG_LOG( SG_IO,
|
|
||||||
SG_WARN, "Error creating directory for '" << str() << "'"
|
|
||||||
" reason: access denied" );
|
|
||||||
return -3;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
int SGPath::create_dir( mode_t mode ) {
|
||||||
string_list dirlist = sgPathSplit(dir());
|
string_list dirlist = sgPathSplit(dir());
|
||||||
if ( dirlist.empty() )
|
if ( dirlist.empty() )
|
||||||
return -1;
|
return -1;
|
||||||
@@ -512,21 +456,27 @@ int SGPath::create_dir(mode_t mode)
|
|||||||
#endif
|
#endif
|
||||||
struct stat info;
|
struct stat info;
|
||||||
int r;
|
int r;
|
||||||
for(; (r = stat(dir.c_str(), &info)) == 0 && i < path_elements.size(); ++i)
|
for(; ( r = stat( dir.c_str(), &info ) ) == 0 && i < path_elements.size(); i++) {
|
||||||
dir.append(path_elements[i]);
|
dir.append(path_elements[i]);
|
||||||
if( r == 0 )
|
}
|
||||||
|
if ( r == 0 ) {
|
||||||
return 0; // Directory already exists
|
return 0; // Directory already exists
|
||||||
|
}
|
||||||
for(;;)
|
for(;;)
|
||||||
{
|
{
|
||||||
if( sgMkDir(dir.c_str(), mode) )
|
if( !dir.canWrite() )
|
||||||
|
{
|
||||||
|
SG_LOG( SG_IO,
|
||||||
|
SG_WARN, "Error creating directory: (" << dir.str() << ")" <<
|
||||||
|
" reason: access denied" );
|
||||||
|
return -3;
|
||||||
|
}
|
||||||
|
else if( sgMkDir(dir.c_str(), mode) )
|
||||||
{
|
{
|
||||||
SG_LOG( SG_IO,
|
SG_LOG( SG_IO,
|
||||||
SG_ALERT, "Error creating directory: (" << dir.str() << ")" );
|
SG_ALERT, "Error creating directory: (" << dir.str() << ")" );
|
||||||
return -2;
|
return -2;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
SG_LOG(SG_IO, SG_DEBUG, "Directory created: " << dir.str());
|
|
||||||
|
|
||||||
if( i >= path_elements.size() )
|
if( i >= path_elements.size() )
|
||||||
return 0;
|
return 0;
|
||||||
@@ -697,56 +647,6 @@ bool SGPath::rename(const SGPath& newName)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
SGPath SGPath::standardLocation(StandardLocation type, const SGPath& def)
|
|
||||||
{
|
|
||||||
switch(type)
|
|
||||||
{
|
|
||||||
case HOME:
|
|
||||||
return home(def);
|
|
||||||
#ifdef _WIN32
|
|
||||||
case DESKTOP:
|
|
||||||
return pathForCSIDL(CSIDL_DESKTOPDIRECTORY, def);
|
|
||||||
case DOWNLOADS:
|
|
||||||
// TODO use KnownFolders
|
|
||||||
// http://msdn.microsoft.com/en-us/library/bb776911%28v=vs.85%29.aspx
|
|
||||||
if( !def.isNull() )
|
|
||||||
return def;
|
|
||||||
|
|
||||||
return pathForCSIDL(CSIDL_DESKTOPDIRECTORY, def);
|
|
||||||
case DOCUMENTS:
|
|
||||||
return pathForCSIDL(CSIDL_MYDOCUMENTS, def);
|
|
||||||
case PICTURES:
|
|
||||||
return pathForCSIDL(CSIDL_MYPICTURES, def);
|
|
||||||
#elif __APPLE__
|
|
||||||
// since this is C++, we can't include NSPathUtilities.h to access the enum
|
|
||||||
// values, so hard-coding them here (they are stable, don't worry)
|
|
||||||
case DOWNLOADS:
|
|
||||||
return appleSpecialFolder(15, 1, def);
|
|
||||||
case DESKTOP:
|
|
||||||
return appleSpecialFolder(12, 1, def);
|
|
||||||
case DOCUMENTS:
|
|
||||||
return appleSpecialFolder(9, 1, def);
|
|
||||||
case PICTURES:
|
|
||||||
return appleSpecialFolder(19, 1, def);
|
|
||||||
#else
|
|
||||||
case DESKTOP:
|
|
||||||
return getXDGDir("DESKTOP", def, "Desktop");
|
|
||||||
case DOWNLOADS:
|
|
||||||
return getXDGDir("DOWNLOADS", def, "Downloads");
|
|
||||||
case DOCUMENTS:
|
|
||||||
return getXDGDir("DOCUMENTS", def, "Documents");
|
|
||||||
case PICTURES:
|
|
||||||
return getXDGDir("PICTURES", def, "Pictures");
|
|
||||||
#endif
|
|
||||||
default:
|
|
||||||
SG_LOG( SG_GENERAL,
|
|
||||||
SG_WARN,
|
|
||||||
"SGPath::standardLocation() unhandled type: " << type );
|
|
||||||
return def;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
SGPath SGPath::fromEnv(const char* name, const SGPath& def)
|
SGPath SGPath::fromEnv(const char* name, const SGPath& def)
|
||||||
{
|
{
|
||||||
@@ -771,19 +671,84 @@ SGPath SGPath::home(const SGPath& def)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
SGPath SGPath::desktop(const SGPath& def)
|
SGPath SGPath::desktop(const SGPath& def)
|
||||||
{
|
{
|
||||||
return standardLocation(DESKTOP, def);
|
SGPath r = pathForCSIDL(CSIDL_DESKTOPDIRECTORY, def._permission_checker);
|
||||||
|
if (!r.isNull()) {
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
SG_LOG(SG_GENERAL, SG_ALERT, "SGPath::desktop() failed, bad" );
|
||||||
|
return def;
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
SGPath SGPath::documents(const SGPath& def)
|
SGPath SGPath::documents(const SGPath& def)
|
||||||
{
|
{
|
||||||
return standardLocation(DOCUMENTS, def);
|
SGPath r = pathForCSIDL(CSIDL_MYDOCUMENTS, def._permission_checker);
|
||||||
|
if (!r.isNull()) {
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
SG_LOG(SG_GENERAL, SG_ALERT, "SGPath::documents() failed, bad" );
|
||||||
|
return def;
|
||||||
}
|
}
|
||||||
|
#elif __APPLE__
|
||||||
|
#include <CoreServices/CoreServices.h>
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
SGPath SGPath::desktop(const SGPath& def)
|
||||||
|
{
|
||||||
|
FSRef ref;
|
||||||
|
OSErr err = FSFindFolder(kUserDomain, kDesktopFolderType, false, &ref);
|
||||||
|
if (err)
|
||||||
|
return def;
|
||||||
|
|
||||||
|
unsigned char path[1024];
|
||||||
|
if (FSRefMakePath(&ref, path, 1024) != noErr)
|
||||||
|
return def;
|
||||||
|
|
||||||
|
return SGPath((const char*) path, def._permission_checker);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
SGPath SGPath::desktop(const SGPath& def)
|
||||||
|
{
|
||||||
|
// http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
|
||||||
|
|
||||||
|
// $XDG_CONFIG_HOME defines the base directory relative to which user specific
|
||||||
|
// configuration files should be stored. If $XDG_CONFIG_HOME is either not set
|
||||||
|
// or empty, a default equal to $HOME/.config should be used.
|
||||||
|
const SGPath user_dirs = fromEnv("XDG_CONFIG_HOME", home() / ".config")
|
||||||
|
/ "user-dirs.dirs";
|
||||||
|
|
||||||
|
// Format is XDG_xxx_DIR="$HOME/yyy", where yyy is a shell-escaped
|
||||||
|
// homedir-relative path, or XDG_xxx_DIR="/yyy", where /yyy is an absolute
|
||||||
|
// path. No other format is supported.
|
||||||
|
const std::string DESKTOP = "XDG_DESKTOP_DIR=\"";
|
||||||
|
|
||||||
|
std::ifstream user_dirs_file( user_dirs.c_str() );
|
||||||
|
std::string line;
|
||||||
|
while( std::getline(user_dirs_file, line).good() )
|
||||||
|
{
|
||||||
|
if( !starts_with(line, DESKTOP) || *line.rbegin() != '"' )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Extract dir from XDG_DESKTOP_DIR="<dir>"
|
||||||
|
line = line.substr(DESKTOP.length(), line.length() - DESKTOP.length() - 1 );
|
||||||
|
|
||||||
|
const std::string HOME = "$HOME";
|
||||||
|
if( starts_with(line, HOME) )
|
||||||
|
return home(def) / simgear::strutils::unescape(line.substr(HOME.length()));
|
||||||
|
|
||||||
|
return SGPath(line, def._permission_checker);
|
||||||
|
}
|
||||||
|
|
||||||
|
return home(def) / "Desktop";
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
std::string SGPath::realpath() const
|
std::string SGPath::realpath() const
|
||||||
{
|
{
|
||||||
#if (defined(__APPLE__) && MAC_OS_X_VERSION_MAX_ALLOWED <= 1050)
|
#if (defined(__APPLE__) && MAC_OS_X_VERSION_MAX_ALLOWED <= 1050)
|
||||||
|
|||||||
@@ -57,10 +57,10 @@ public:
|
|||||||
bool read : 1;
|
bool read : 1;
|
||||||
bool write : 1;
|
bool write : 1;
|
||||||
};
|
};
|
||||||
typedef Permissions (*PermissionChecker)(const SGPath&);
|
typedef Permissions (*PermissonChecker)(const SGPath&);
|
||||||
|
|
||||||
/** Default constructor */
|
/** Default constructor */
|
||||||
explicit SGPath(PermissionChecker validator = NULL);
|
explicit SGPath(PermissonChecker validator = NULL);
|
||||||
|
|
||||||
/** Copy contructor */
|
/** Copy contructor */
|
||||||
SGPath(const SGPath& p);
|
SGPath(const SGPath& p);
|
||||||
@@ -71,7 +71,7 @@ public:
|
|||||||
* Construct a path based on the starting path provided.
|
* Construct a path based on the starting path provided.
|
||||||
* @param p initial path
|
* @param p initial path
|
||||||
*/
|
*/
|
||||||
SGPath( const std::string& p, PermissionChecker validator = NULL );
|
SGPath( const std::string& p, PermissonChecker validator = NULL );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a path based on the starting path provided and a relative subpath
|
* Construct a path based on the starting path provided and a relative subpath
|
||||||
@@ -80,7 +80,7 @@ public:
|
|||||||
*/
|
*/
|
||||||
SGPath( const SGPath& p,
|
SGPath( const SGPath& p,
|
||||||
const std::string& r,
|
const std::string& r,
|
||||||
PermissionChecker validator = NULL );
|
PermissonChecker validator = NULL );
|
||||||
|
|
||||||
/** Destructor */
|
/** Destructor */
|
||||||
~SGPath();
|
~SGPath();
|
||||||
@@ -95,8 +95,8 @@ public:
|
|||||||
bool operator==(const SGPath& other) const;
|
bool operator==(const SGPath& other) const;
|
||||||
bool operator!=(const SGPath& other) const;
|
bool operator!=(const SGPath& other) const;
|
||||||
|
|
||||||
void setPermissionChecker(PermissionChecker validator);
|
void setPermissonChecker(PermissonChecker validator);
|
||||||
PermissionChecker getPermissionChecker() const;
|
PermissonChecker getPermissonChecker() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set if file information (exists, type, mod-time) is cached or
|
* Set if file information (exists, type, mod-time) is cached or
|
||||||
@@ -206,12 +206,9 @@ public:
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Create the designated directory.
|
* Create the designated directory.
|
||||||
*
|
|
||||||
* @param mode Permissions. See:
|
|
||||||
* http://en.wikipedia.org/wiki/File_system_permissions#Numeric_notation
|
|
||||||
* @return 0 on success, or <0 on failure.
|
* @return 0 on success, or <0 on failure.
|
||||||
*/
|
*/
|
||||||
int create_dir(mode_t mode = 0755);
|
int create_dir(mode_t mode);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if reading file is allowed. Readabilty does not imply the existance
|
* Check if reading file is allowed. Readabilty does not imply the existance
|
||||||
@@ -260,18 +257,6 @@ public:
|
|||||||
*/
|
*/
|
||||||
bool rename(const SGPath& newName);
|
bool rename(const SGPath& newName);
|
||||||
|
|
||||||
enum StandardLocation
|
|
||||||
{
|
|
||||||
HOME,
|
|
||||||
DESKTOP,
|
|
||||||
DOWNLOADS,
|
|
||||||
DOCUMENTS,
|
|
||||||
PICTURES
|
|
||||||
};
|
|
||||||
|
|
||||||
static SGPath standardLocation( StandardLocation type,
|
|
||||||
const SGPath& def = SGPath() );
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a path stored in the environment variable with the given \a name.
|
* Get a path stored in the environment variable with the given \a name.
|
||||||
*
|
*
|
||||||
@@ -295,7 +280,6 @@ public:
|
|||||||
* Get path to the user's documents directory
|
* Get path to the user's documents directory
|
||||||
*/
|
*/
|
||||||
static SGPath documents(const SGPath& def = SGPath());
|
static SGPath documents(const SGPath& def = SGPath());
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void fix();
|
void fix();
|
||||||
@@ -304,7 +288,7 @@ private:
|
|||||||
void checkAccess() const;
|
void checkAccess() const;
|
||||||
|
|
||||||
std::string path;
|
std::string path;
|
||||||
PermissionChecker _permission_checker;
|
PermissonChecker _permission_checker;
|
||||||
|
|
||||||
mutable bool _cached : 1;
|
mutable bool _cached : 1;
|
||||||
mutable bool _rwCached : 1;
|
mutable bool _rwCached : 1;
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ int main()
|
|||||||
"third line ends with both\r\n"
|
"third line ends with both\r\n"
|
||||||
"fourth line as well\r\n"
|
"fourth line as well\r\n"
|
||||||
"fifth line is another CR/LF line\r\n"
|
"fifth line is another CR/LF line\r\n"
|
||||||
"end of test\r\n", 158);
|
"end of test\r\n", 1024);
|
||||||
f.close();
|
f.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+14
-39
@@ -27,7 +27,6 @@
|
|||||||
#include "strutils.hxx"
|
#include "strutils.hxx"
|
||||||
|
|
||||||
#include <simgear/debug/logstream.hxx>
|
#include <simgear/debug/logstream.hxx>
|
||||||
#include <simgear/package/md5.h>
|
|
||||||
|
|
||||||
using std::string;
|
using std::string;
|
||||||
using std::vector;
|
using std::vector;
|
||||||
@@ -54,11 +53,8 @@ namespace simgear {
|
|||||||
size_t len = get_length (p);
|
size_t len = get_length (p);
|
||||||
if (len == 1) return *p;
|
if (len == 1) return *p;
|
||||||
value_type res = static_cast<unsigned char> ( *p & (0xff >> (len + 1))) << ((len - 1) * 6 );
|
value_type res = static_cast<unsigned char> ( *p & (0xff >> (len + 1))) << ((len - 1) * 6 );
|
||||||
for (--len; len; --len) {
|
for (--len; len; --len)
|
||||||
value_type next_byte = static_cast<unsigned char> (*(++p)) - 0x80;
|
res |= (static_cast<unsigned char> (*(++p)) - 0x80) << ((len - 1) * 6);
|
||||||
if (next_byte & 0xC0) return 0x00ffffff; // invalid UTF-8
|
|
||||||
res |= next_byte << ((len - 1) * 6);
|
|
||||||
}
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,7 +62,6 @@ namespace simgear {
|
|||||||
string s_latin1;
|
string s_latin1;
|
||||||
for (string::iterator p = s_utf8.begin(); p != s_utf8.end(); ++p) {
|
for (string::iterator p = s_utf8.begin(); p != s_utf8.end(); ++p) {
|
||||||
value_type value = get_value<string::iterator&>(p);
|
value_type value = get_value<string::iterator&>(p);
|
||||||
if (value > 0x10ffff) return s_utf8; // invalid UTF-8: guess that the input was already Latin-1
|
|
||||||
if (value > 0xff) SG_LOG(SG_IO, SG_WARN, "utf8ToLatin1: wrong char value: " << value);
|
if (value > 0xff) SG_LOG(SG_IO, SG_WARN, "utf8ToLatin1: wrong char value: " << value);
|
||||||
s_latin1 += static_cast<char>(value);
|
s_latin1 += static_cast<char>(value);
|
||||||
}
|
}
|
||||||
@@ -402,32 +397,8 @@ std::string convertWindowsLocal8BitToUtf8(const std::string& a)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
std::string md5(const unsigned char* data, size_t num)
|
|
||||||
{
|
|
||||||
SG_MD5_CTX md5_ctx;
|
|
||||||
SG_MD5Init(&md5_ctx);
|
|
||||||
SG_MD5Update(&md5_ctx, data, num);
|
|
||||||
|
|
||||||
unsigned char digest[MD5_DIGEST_LENGTH];
|
|
||||||
SG_MD5Final(digest, &md5_ctx);
|
|
||||||
|
|
||||||
return encodeHex(digest, MD5_DIGEST_LENGTH);
|
|
||||||
}
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
std::string md5(const char* data, size_t num)
|
|
||||||
{
|
|
||||||
return md5(reinterpret_cast<const unsigned char*>(data), num);
|
|
||||||
}
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
std::string md5(const std::string& str)
|
|
||||||
{
|
|
||||||
return md5(reinterpret_cast<const unsigned char*>(str.c_str()), str.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
static const std::string base64_chars =
|
static const std::string base64_chars =
|
||||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||||
"abcdefghijklmnopqrstuvwxyz"
|
"abcdefghijklmnopqrstuvwxyz"
|
||||||
@@ -507,24 +478,28 @@ void decodeBase64(const std::string& encoded_string, std::vector<unsigned char>&
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
const char hexChar[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
|
const char hexChar[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
|
||||||
|
|
||||||
std::string encodeHex(const std::string& bytes)
|
std::string encodeHex(const std::string& bytes)
|
||||||
{
|
{
|
||||||
return encodeHex(
|
std::string hex;
|
||||||
reinterpret_cast<const unsigned char*>(bytes.c_str()),
|
size_t count = bytes.size();
|
||||||
bytes.size()
|
for (unsigned int i=0; i<count;++i) {
|
||||||
);
|
unsigned char c = bytes[i];
|
||||||
|
hex.push_back(hexChar[c >> 4]);
|
||||||
|
hex.push_back(hexChar[c & 0x0f]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return hex;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string encodeHex(const unsigned char* rawBytes, unsigned int length)
|
std::string encodeHex(const unsigned char* rawBytes, unsigned int length)
|
||||||
{
|
{
|
||||||
std::string hex(length * 2, '\0');
|
std::string hex;
|
||||||
for (unsigned int i=0; i<length;++i) {
|
for (unsigned int i=0; i<length;++i) {
|
||||||
unsigned char c = *rawBytes++;
|
unsigned char c = *rawBytes++;
|
||||||
hex[i * 2] = hexChar[c >> 4];
|
hex.push_back(hexChar[c >> 4]);
|
||||||
hex[i * 2 + 1] = hexChar[c & 0x0f];
|
hex.push_back(hexChar[c & 0x0f]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return hex;
|
return hex;
|
||||||
|
|||||||
@@ -176,13 +176,6 @@ namespace simgear {
|
|||||||
WCharVec convertUtf8ToWString(const std::string& a);
|
WCharVec convertUtf8ToWString(const std::string& a);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
|
||||||
* Get md5 hash of raw data.
|
|
||||||
*/
|
|
||||||
std::string md5(const unsigned char* data, size_t num);
|
|
||||||
std::string md5(const char* data, size_t num);
|
|
||||||
std::string md5(const std::string& str);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* convert base-64 encoded data to raw bytes (possibly with embedded
|
* convert base-64 encoded data to raw bytes (possibly with embedded
|
||||||
* NULs). Throws an exception if input data is not base64, or is
|
* NULs). Throws an exception if input data is not base64, or is
|
||||||
|
|||||||
@@ -1,80 +1,84 @@
|
|||||||
/// Unit tests for function inside strutils package
|
////////////////////////////////////////////////////////////////////////
|
||||||
#define BOOST_TEST_MODULE misc
|
// Test harness.
|
||||||
#include <BoostTestTargetConfig.h>
|
////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#include <simgear/compiler.h>
|
#include <simgear/compiler.h>
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
#include "strutils.hxx"
|
#include "strutils.hxx"
|
||||||
|
|
||||||
namespace strutils = simgear::strutils;
|
using std::cout;
|
||||||
|
using std::cerr;
|
||||||
|
using std::endl;
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE( strutils_functions )
|
using namespace simgear::strutils;
|
||||||
|
|
||||||
|
#define COMPARE(a, b) \
|
||||||
|
if ((a) != (b)) { \
|
||||||
|
cerr << "failed:" << #a << " != " << #b << endl; \
|
||||||
|
exit(1); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define VERIFY(a) \
|
||||||
|
if (!(a)) { \
|
||||||
|
cerr << "failed:" << #a << endl; \
|
||||||
|
exit(1); \
|
||||||
|
}
|
||||||
|
|
||||||
|
int main (int ac, char ** av)
|
||||||
{
|
{
|
||||||
std::string a("abcd");
|
std::string a("abcd");
|
||||||
BOOST_CHECK_EQUAL(strutils::strip(a), a);
|
COMPARE(strip(a), a);
|
||||||
BOOST_CHECK_EQUAL(strutils::strip(" a "), "a");
|
COMPARE(strip(" a "), "a");
|
||||||
BOOST_CHECK_EQUAL(strutils::lstrip(" a "), "a ");
|
COMPARE(lstrip(" a "), "a ");
|
||||||
BOOST_CHECK_EQUAL(strutils::rstrip("\ta "), "\ta");
|
COMPARE(rstrip("\ta "), "\ta");
|
||||||
|
|
||||||
// check internal spacing is preserved
|
// check internal spacing is preserved
|
||||||
BOOST_CHECK_EQUAL(strutils::strip("\t \na \t b\r \n "), "a \t b");
|
COMPARE(strip("\t \na \t b\r \n "), "a \t b");
|
||||||
|
|
||||||
|
|
||||||
BOOST_CHECK(strutils::starts_with("banana", "ban"));
|
VERIFY(starts_with("banana", "ban"));
|
||||||
BOOST_CHECK(!strutils::starts_with("abanana", "ban"));
|
VERIFY(!starts_with("abanana", "ban"));
|
||||||
BOOST_CHECK(strutils::starts_with("banana", "banana")); // pass - string starts with itself
|
VERIFY(starts_with("banana", "banana")); // pass - string starts with itself
|
||||||
BOOST_CHECK(!strutils::starts_with("ban", "banana")); // fail - original string is prefix of
|
VERIFY(!starts_with("ban", "banana")); // fail - original string is prefix of
|
||||||
|
|
||||||
BOOST_CHECK(strutils::ends_with("banana", "ana"));
|
VERIFY(ends_with("banana", "ana"));
|
||||||
BOOST_CHECK(strutils::ends_with("foo.text", ".text"));
|
VERIFY(ends_with("foo.text", ".text"));
|
||||||
BOOST_CHECK(!strutils::ends_with("foo.text", ".html"));
|
VERIFY(!ends_with("foo.text", ".html"));
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(strutils::simplify("\ta\t b \nc\n\r \r\n"), "a b c");
|
COMPARE(simplify("\ta\t b \nc\n\r \r\n"), "a b c");
|
||||||
BOOST_CHECK_EQUAL(strutils::simplify("The quick - brown dog!"), "The quick - brown dog!");
|
COMPARE(simplify("The quick - brown dog!"), "The quick - brown dog!");
|
||||||
BOOST_CHECK_EQUAL(strutils::simplify("\r\n \r\n \t \r"), "");
|
COMPARE(simplify("\r\n \r\n \t \r"), "");
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(strutils::to_int("999"), 999);
|
COMPARE(to_int("999"), 999);
|
||||||
BOOST_CHECK_EQUAL(strutils::to_int("0000000"), 0);
|
COMPARE(to_int("0000000"), 0);
|
||||||
BOOST_CHECK_EQUAL(strutils::to_int("-10000"), -10000);
|
COMPARE(to_int("-10000"), -10000);
|
||||||
|
|
||||||
string_list la = strutils::split("zero one two three four five");
|
VERIFY(compare_versions("1.0.12", "1.1") < 0);
|
||||||
BOOST_CHECK_EQUAL(la[2], "two");
|
VERIFY(compare_versions("1.1", "1.0.12") > 0);
|
||||||
BOOST_CHECK_EQUAL(la[5], "five");
|
VERIFY(compare_versions("10.6.7", "10.6.7") == 0);
|
||||||
BOOST_CHECK_EQUAL(la.size(), 6);
|
VERIFY(compare_versions("2.0", "2.0.99") < 0);
|
||||||
|
VERIFY(compare_versions("99", "99") == 0);
|
||||||
|
VERIFY(compare_versions("99", "98") > 0);
|
||||||
|
|
||||||
string_list lb = strutils::split("alpha:beta:gamma:delta", ":", 2);
|
// since we compare numerically, leasing zeros shouldn't matter
|
||||||
BOOST_CHECK_EQUAL(lb.size(), 3);
|
VERIFY(compare_versions("0.06.7", "0.6.07") == 0);
|
||||||
BOOST_CHECK_EQUAL(lb[0], "alpha");
|
|
||||||
BOOST_CHECK_EQUAL(lb[1], "beta");
|
|
||||||
BOOST_CHECK_EQUAL(lb[2], "gamma:delta");
|
|
||||||
|
|
||||||
std::string j = strutils::join(la, "&");
|
string_list la = split("zero one two three four five");
|
||||||
BOOST_CHECK_EQUAL(j, "zero&one&two&three&four&five");
|
COMPARE(la[2], "two");
|
||||||
|
COMPARE(la[5], "five");
|
||||||
|
COMPARE(la.size(), 6);
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(strutils::unescape("\\ \\n\\t\\x41\\117a"), " \n\tAOa");
|
string_list lb = split("alpha:beta:gamma:delta", ":", 2);
|
||||||
}
|
COMPARE(lb.size(), 3);
|
||||||
|
COMPARE(lb[0], "alpha");
|
||||||
|
COMPARE(lb[1], "beta");
|
||||||
|
COMPARE(lb[2], "gamma:delta");
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE( compare_versions )
|
std::string j = join(la, "&");
|
||||||
{
|
COMPARE(j, "zero&one&two&three&four&five");
|
||||||
BOOST_CHECK_LT(strutils::compare_versions("1.0.12", "1.1"), 0);
|
|
||||||
BOOST_CHECK_GT(strutils::compare_versions("1.1", "1.0.12"), 0);
|
|
||||||
BOOST_CHECK_EQUAL(strutils::compare_versions("10.6.7", "10.6.7"), 0);
|
|
||||||
BOOST_CHECK_LT(strutils::compare_versions("2.0", "2.0.99"), 0);
|
|
||||||
BOOST_CHECK_EQUAL(strutils::compare_versions("99", "99"), 0);
|
|
||||||
BOOST_CHECK_GT(strutils::compare_versions("99", "98"), 0);
|
|
||||||
|
|
||||||
// since we compare numerically, leasing zeros shouldn't matter
|
COMPARE(unescape("\\ \\n\\t\\x41\\117a"), " \n\tAOa");
|
||||||
BOOST_CHECK_EQUAL(strutils::compare_versions("0.06.7", "0.6.07"), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE( md5_hex )
|
cout << "all tests passed successfully!" << endl;
|
||||||
{
|
return 0;
|
||||||
// hex encoding
|
|
||||||
unsigned char raw_data[] = {0x0f, 0x1a, 0xbc, 0xd2, 0xe3, 0x45, 0x67, 0x89};
|
|
||||||
const std::string& hex_data =
|
|
||||||
strutils::encodeHex(raw_data, sizeof(raw_data)/sizeof(raw_data[0]));
|
|
||||||
BOOST_REQUIRE_EQUAL(hex_data, "0f1abcd2e3456789");
|
|
||||||
BOOST_REQUIRE_EQUAL(strutils::encodeHex("abcde"), "6162636465");
|
|
||||||
|
|
||||||
// md5
|
|
||||||
BOOST_CHECK_EQUAL(strutils::md5("test"), "098f6bcd4621d373cade4e832627b4f6");
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,37 +2,18 @@
|
|||||||
#ifndef SG_MISC_TEST_MACROS_HXX
|
#ifndef SG_MISC_TEST_MACROS_HXX
|
||||||
#define SG_MISC_TEST_MACROS_HXX
|
#define SG_MISC_TEST_MACROS_HXX
|
||||||
|
|
||||||
#include <cmath> // for fabs()
|
|
||||||
|
|
||||||
#define COMPARE(a, b) \
|
#define COMPARE(a, b) \
|
||||||
if ((a) != (b)) { \
|
if ((a) != (b)) { \
|
||||||
std::cerr << "failed:" << #a << " != " << #b << std::endl; \
|
std::cerr << "failed:" << #a << " != " << #b << std::endl; \
|
||||||
std::cerr << "\tgot:'" << a << "'" << std::endl; \
|
std::cerr << "\tgot:'" << a << "'" << std::endl; \
|
||||||
std::cerr << "\tat:" << __FILE__ << ":" << __LINE__ << std::endl; \
|
|
||||||
exit(1); \
|
exit(1); \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define VERIFY(a) \
|
#define VERIFY(a) \
|
||||||
if (!(a)) { \
|
if (!(a)) { \
|
||||||
std::cerr << "failed:" << #a << std::endl; \
|
std::cerr << "failed:" << #a << std::endl; \
|
||||||
std::cerr << "\tat:" << __FILE__ << ":" << __LINE__ << std::endl; \
|
|
||||||
exit(1); \
|
exit(1); \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define COMPARE_EP(a, b) \
|
|
||||||
if (fabs(a - b) > SG_EPSILON) { \
|
|
||||||
std::cerr << "failed with epsilon:" << #a << " != " << #b << std::endl; \
|
|
||||||
std::cerr << "\tgot:'" << a << "'" << std::endl; \
|
|
||||||
std::cerr << "\tat:" << __FILE__ << ":" << __LINE__ << std::endl; \
|
|
||||||
exit(1); \
|
|
||||||
}
|
|
||||||
|
|
||||||
#define COMPARE_EP2(a, b, ep) \
|
|
||||||
if (fabs(a - b) > ep) { \
|
|
||||||
std::cerr << "failed with epsilon:" << #a << " != " << #b << std::endl; \
|
|
||||||
std::cerr << "\tgot:'" << a << "'" << std::endl; \
|
|
||||||
std::cerr << "\tat:" << __FILE__ << ":" << __LINE__ << std::endl; \
|
|
||||||
exit(1); \
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // of SG_MISC_TEST_MACROS_HXX
|
#endif // of SG_MISC_TEST_MACROS_HXX
|
||||||
|
|||||||
@@ -1,26 +0,0 @@
|
|||||||
/// Unit tests for utf8ToLatin1 conversion function
|
|
||||||
#define BOOST_TEST_MODULE misc
|
|
||||||
#include <BoostTestTargetConfig.h>
|
|
||||||
|
|
||||||
#include "strutils.hxx"
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE( utf8_latin1_conversion )
|
|
||||||
{
|
|
||||||
std::string utf8_string1 = "Zweibr\u00FCcken";
|
|
||||||
//valid UTF-8, convertible to Latin-1
|
|
||||||
std::string latin1_string1 = "Zweibr\374cken";
|
|
||||||
//Latin-1, not valid UTF-8
|
|
||||||
std::string utf8_string2 = "\u600f\U00010143";
|
|
||||||
//valid UTF-8, out of range for Latin-1
|
|
||||||
|
|
||||||
std::string output_string1u = simgear::strutils::utf8ToLatin1(utf8_string1);
|
|
||||||
BOOST_CHECK_EQUAL(output_string1u, latin1_string1);
|
|
||||||
|
|
||||||
std::string output_string1l = simgear::strutils::utf8ToLatin1(latin1_string1);
|
|
||||||
BOOST_CHECK_EQUAL(output_string1l, latin1_string1);
|
|
||||||
|
|
||||||
std::string output_string3 = simgear::strutils::utf8ToLatin1(utf8_string2);
|
|
||||||
//we don't check the result of this one as there is no right answer,
|
|
||||||
//just make sure it doesn't crash/hang
|
|
||||||
}
|
|
||||||
@@ -71,9 +71,7 @@ static double numify(naContext ctx, naRef o)
|
|||||||
else if(IS_NIL(o)) ERR(ctx, "nil used in numeric context");
|
else if(IS_NIL(o)) ERR(ctx, "nil used in numeric context");
|
||||||
else if(!IS_STR(o)) ERR(ctx, "non-scalar in numeric context");
|
else if(!IS_STR(o)) ERR(ctx, "non-scalar in numeric context");
|
||||||
else if(naStr_tonum(o, &n)) return n;
|
else if(naStr_tonum(o, &n)) return n;
|
||||||
else naRuntimeError( ctx,
|
else ERR(ctx, "non-numeric string in numeric context");
|
||||||
"non-numeric string in numeric context: '%s'",
|
|
||||||
naStr_data(o) );
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -594,9 +592,6 @@ static naRef run(naContext ctx)
|
|||||||
case OP_LTE: BINOP(l <= r ? 1 : 0); break;
|
case OP_LTE: BINOP(l <= r ? 1 : 0); break;
|
||||||
case OP_GT: BINOP(l > r ? 1 : 0); break;
|
case OP_GT: BINOP(l > r ? 1 : 0); break;
|
||||||
case OP_GTE: BINOP(l >= r ? 1 : 0); break;
|
case OP_GTE: BINOP(l >= r ? 1 : 0); break;
|
||||||
case OP_BIT_AND: BINOP((int)l & (int)r); break;
|
|
||||||
case OP_BIT_OR: BINOP((int)l | (int)r); break;
|
|
||||||
case OP_BIT_XOR: BINOP((int)l ^ (int)r); break;
|
|
||||||
#undef BINOP
|
#undef BINOP
|
||||||
|
|
||||||
case OP_EQ: case OP_NEQ:
|
case OP_EQ: case OP_NEQ:
|
||||||
@@ -610,9 +605,6 @@ static naRef run(naContext ctx)
|
|||||||
case OP_NEG:
|
case OP_NEG:
|
||||||
STK(1) = naNum(-numify(ctx, STK(1)));
|
STK(1) = naNum(-numify(ctx, STK(1)));
|
||||||
break;
|
break;
|
||||||
case OP_BIT_NEG:
|
|
||||||
STK(1) = naNum(~(int)numify(ctx, STK(1)));
|
|
||||||
break;
|
|
||||||
case OP_NOT:
|
case OP_NOT:
|
||||||
STK(1) = naNum(boolify(ctx, STK(1)) ? 0 : 1);
|
STK(1) = naNum(boolify(ctx, STK(1)) ? 0 : 1);
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -26,8 +26,7 @@ enum {
|
|||||||
OP_MEMBER, OP_SETMEMBER, OP_LOCAL, OP_SETLOCAL, OP_NEWVEC, OP_VAPPEND,
|
OP_MEMBER, OP_SETMEMBER, OP_LOCAL, OP_SETLOCAL, OP_NEWVEC, OP_VAPPEND,
|
||||||
OP_NEWHASH, OP_HAPPEND, OP_MARK, OP_UNMARK, OP_BREAK, OP_SETSYM, OP_DUP2,
|
OP_NEWHASH, OP_HAPPEND, OP_MARK, OP_UNMARK, OP_BREAK, OP_SETSYM, OP_DUP2,
|
||||||
OP_INDEX, OP_BREAK2, OP_PUSHEND, OP_JIFTRUE, OP_JIFNOT, OP_FCALLH,
|
OP_INDEX, OP_BREAK2, OP_PUSHEND, OP_JIFTRUE, OP_JIFNOT, OP_FCALLH,
|
||||||
OP_MCALLH, OP_XCHG2, OP_UNPACK, OP_SLICE, OP_SLICE2, OP_BIT_AND, OP_BIT_OR,
|
OP_MCALLH, OP_XCHG2, OP_UNPACK, OP_SLICE, OP_SLICE2
|
||||||
OP_BIT_XOR, OP_BIT_NEG
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Frame {
|
struct Frame {
|
||||||
|
|||||||
+4
-38
@@ -7,7 +7,6 @@
|
|||||||
// These are more sensical predicate names in most contexts in this file
|
// These are more sensical predicate names in most contexts in this file
|
||||||
#define LEFT(tok) ((tok)->children)
|
#define LEFT(tok) ((tok)->children)
|
||||||
#define RIGHT(tok) ((tok)->lastChild)
|
#define RIGHT(tok) ((tok)->lastChild)
|
||||||
#define UNARY(tok) (LEFT(tok) && LEFT(tok) == RIGHT(tok))
|
|
||||||
#define BINARY(tok) (LEFT(tok) && RIGHT(tok) && LEFT(tok)->next == RIGHT(tok))
|
#define BINARY(tok) (LEFT(tok) && RIGHT(tok) && LEFT(tok)->next == RIGHT(tok))
|
||||||
|
|
||||||
// Forward references for recursion
|
// Forward references for recursion
|
||||||
@@ -166,15 +165,6 @@ static int defArg(struct Parser* p, struct Token* t)
|
|||||||
RIGHT(t)->num *= -1;
|
RIGHT(t)->num *= -1;
|
||||||
return defArg(p, RIGHT(t));
|
return defArg(p, RIGHT(t));
|
||||||
}
|
}
|
||||||
if(t->type == TOK_CAT && RIGHT(t) &&
|
|
||||||
RIGHT(t)->type == TOK_LITERAL && !RIGHT(t)->str)
|
|
||||||
{
|
|
||||||
/* default arguments are constants, but "~1" parses as two
|
|
||||||
* tokens, so we have to subset the expression generator for that
|
|
||||||
* case */
|
|
||||||
RIGHT(t)->num = ~(int)RIGHT(t)->num;
|
|
||||||
return defArg(p, RIGHT(t));
|
|
||||||
}
|
|
||||||
return findConstantIndex(p, t);
|
return findConstantIndex(p, t);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -644,15 +634,11 @@ static void genExpr(struct Parser* p, struct Token* t)
|
|||||||
else genExpr(p, LEFT(t));
|
else genExpr(p, LEFT(t));
|
||||||
break;
|
break;
|
||||||
case TOK_LBRA:
|
case TOK_LBRA:
|
||||||
if(UNARY(t)) {
|
if(BINARY(t)) {
|
||||||
emit(p, OP_NEWVEC);
|
|
||||||
genList(p, LEFT(t), 1);
|
|
||||||
}
|
|
||||||
else if(BINARY(t)) {
|
|
||||||
genExtract(p, t);
|
genExtract(p, t);
|
||||||
} else {
|
} else {
|
||||||
// forbid usage as 'vec[]'
|
emit(p, OP_NEWVEC);
|
||||||
naParseError(p, "missing index or slice expression(s)", t->line);
|
genList(p, LEFT(t), 1);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case TOK_LCURL:
|
case TOK_LCURL:
|
||||||
@@ -687,21 +673,6 @@ static void genExpr(struct Parser* p, struct Token* t)
|
|||||||
genExpr(p, RIGHT(t)); // unary negation (see also TOK_MINUS!)
|
genExpr(p, RIGHT(t)); // unary negation (see also TOK_MINUS!)
|
||||||
emit(p, OP_NEG);
|
emit(p, OP_NEG);
|
||||||
break;
|
break;
|
||||||
case TOK_CAT:
|
|
||||||
if(BINARY(t)) {
|
|
||||||
genBinOp(OP_CAT, p, t); // string concatenation
|
|
||||||
} else if(RIGHT(t) && RIGHT(t)->type == TOK_LITERAL && !RIGHT(t)->str) {
|
|
||||||
RIGHT(t)->num = ~(int)RIGHT(t)->num; // Pre-negate constants
|
|
||||||
genScalarConstant(p, RIGHT(t));
|
|
||||||
} else {
|
|
||||||
genExpr(p, RIGHT(t)); // unary, bitwise negation
|
|
||||||
emit(p, OP_BIT_NEG);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case TOK_BIT_NEG:
|
|
||||||
genExpr(p, RIGHT(t)); // unary, bitwise negation (see also TOK_CAT!)
|
|
||||||
emit(p, OP_BIT_NEG);
|
|
||||||
break;
|
|
||||||
case TOK_DOT:
|
case TOK_DOT:
|
||||||
genExpr(p, LEFT(t));
|
genExpr(p, LEFT(t));
|
||||||
if(!RIGHT(t) || RIGHT(t)->type != TOK_SYMBOL)
|
if(!RIGHT(t) || RIGHT(t)->type != TOK_SYMBOL)
|
||||||
@@ -714,12 +685,10 @@ static void genExpr(struct Parser* p, struct Token* t)
|
|||||||
case TOK_AND: case TOK_OR:
|
case TOK_AND: case TOK_OR:
|
||||||
genShortCircuit(p, t);
|
genShortCircuit(p, t);
|
||||||
break;
|
break;
|
||||||
case TOK_BIT_AND:genBinOp(OP_BIT_AND, p, t); break;
|
|
||||||
case TOK_BIT_OR: genBinOp(OP_BIT_OR, p, t); break;
|
|
||||||
case TOK_BIT_XOR:genBinOp(OP_BIT_XOR, p, t); break;
|
|
||||||
case TOK_MUL: genBinOp(OP_MUL, p, t); break;
|
case TOK_MUL: genBinOp(OP_MUL, p, t); break;
|
||||||
case TOK_PLUS: genBinOp(OP_PLUS, p, t); break;
|
case TOK_PLUS: genBinOp(OP_PLUS, p, t); break;
|
||||||
case TOK_DIV: genBinOp(OP_DIV, p, t); break;
|
case TOK_DIV: genBinOp(OP_DIV, p, t); break;
|
||||||
|
case TOK_CAT: genBinOp(OP_CAT, p, t); break;
|
||||||
case TOK_LT: genBinOp(OP_LT, p, t); break;
|
case TOK_LT: genBinOp(OP_LT, p, t); break;
|
||||||
case TOK_LTE: genBinOp(OP_LTE, p, t); break;
|
case TOK_LTE: genBinOp(OP_LTE, p, t); break;
|
||||||
case TOK_EQ: genBinOp(OP_EQ, p, t); break;
|
case TOK_EQ: genBinOp(OP_EQ, p, t); break;
|
||||||
@@ -731,9 +700,6 @@ static void genExpr(struct Parser* p, struct Token* t)
|
|||||||
case TOK_MULEQ: genEqOp(OP_MUL, p, t); break;
|
case TOK_MULEQ: genEqOp(OP_MUL, p, t); break;
|
||||||
case TOK_DIVEQ: genEqOp(OP_DIV, p, t); break;
|
case TOK_DIVEQ: genEqOp(OP_DIV, p, t); break;
|
||||||
case TOK_CATEQ: genEqOp(OP_CAT, p, t); break;
|
case TOK_CATEQ: genEqOp(OP_CAT, p, t); break;
|
||||||
case TOK_BIT_ANDEQ: genEqOp(OP_BIT_AND, p, t); break;
|
|
||||||
case TOK_BIT_OREQ: genEqOp(OP_BIT_OR, p, t); break;
|
|
||||||
case TOK_BIT_XOREQ: genEqOp(OP_BIT_XOR, p, t); break;
|
|
||||||
default:
|
default:
|
||||||
naParseError(p, "parse error", t->line);
|
naParseError(p, "parse error", t->line);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ set(HEADERS
|
|||||||
Ghost.hxx
|
Ghost.hxx
|
||||||
NasalCallContext.hxx
|
NasalCallContext.hxx
|
||||||
NasalHash.hxx
|
NasalHash.hxx
|
||||||
NasalObject.hxx
|
|
||||||
NasalObjectHolder.hxx
|
NasalObjectHolder.hxx
|
||||||
NasalString.hxx
|
NasalString.hxx
|
||||||
from_nasal.hxx
|
from_nasal.hxx
|
||||||
@@ -20,10 +19,9 @@ set(DETAIL_HEADERS
|
|||||||
)
|
)
|
||||||
|
|
||||||
set(SOURCES
|
set(SOURCES
|
||||||
Ghost.cxx
|
|
||||||
NasalHash.cxx
|
NasalHash.cxx
|
||||||
|
NasalObjectHolder.cxx
|
||||||
NasalString.cxx
|
NasalString.cxx
|
||||||
NasalObject.cxx
|
|
||||||
detail/from_nasal_helper.cxx
|
detail/from_nasal_helper.cxx
|
||||||
detail/to_nasal_helper.cxx
|
detail/to_nasal_helper.cxx
|
||||||
)
|
)
|
||||||
@@ -36,13 +34,3 @@ if(ENABLE_TESTS)
|
|||||||
add_test(cppbind ${EXECUTABLE_OUTPUT_PATH}/test_cppbind)
|
add_test(cppbind ${EXECUTABLE_OUTPUT_PATH}/test_cppbind)
|
||||||
target_link_libraries(test_cppbind ${TEST_LIBS})
|
target_link_libraries(test_cppbind ${TEST_LIBS})
|
||||||
endif(ENABLE_TESTS)
|
endif(ENABLE_TESTS)
|
||||||
|
|
||||||
add_boost_test(cppbind_ghost
|
|
||||||
SOURCES cppbind_test_ghost.cxx
|
|
||||||
LIBRARIES ${TEST_LIBS}
|
|
||||||
)
|
|
||||||
|
|
||||||
add_boost_test(nasal_num
|
|
||||||
SOURCES nasal_num_test.cxx
|
|
||||||
LIBRARIES ${TEST_LIBS}
|
|
||||||
)
|
|
||||||
@@ -1,108 +0,0 @@
|
|||||||
// Expose C++ objects to Nasal as ghosts
|
|
||||||
//
|
|
||||||
// Copyright (C) 2014 Thomas Geymayer <tomgey@gmail.com>
|
|
||||||
//
|
|
||||||
// This library is free software; you can redistribute it and/or
|
|
||||||
// modify it under the terms of the GNU Library General Public
|
|
||||||
// License as published by the Free Software Foundation; either
|
|
||||||
// version 2 of the License, or (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
// Library General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Library General Public
|
|
||||||
// License along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
|
||||||
|
|
||||||
#include "Ghost.hxx"
|
|
||||||
|
|
||||||
namespace nasal
|
|
||||||
{
|
|
||||||
namespace internal
|
|
||||||
{
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
GhostMetadata::DestroyList GhostMetadata::_destroy_list;
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
void GhostMetadata::addNasalBase(const naRef& parent)
|
|
||||||
{
|
|
||||||
assert( naIsHash(parent) );
|
|
||||||
_parents.push_back(parent);
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
bool GhostMetadata::isBaseOf(naGhostType* ghost_type, bool& is_weak) const
|
|
||||||
{
|
|
||||||
if( ghost_type == _ghost_type_strong_ptr )
|
|
||||||
{
|
|
||||||
is_weak = false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( ghost_type == _ghost_type_weak_ptr )
|
|
||||||
{
|
|
||||||
is_weak = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
for( DerivedList::const_iterator derived = _derived_classes.begin();
|
|
||||||
derived != _derived_classes.end();
|
|
||||||
++derived )
|
|
||||||
{
|
|
||||||
if( (*derived)->isBaseOf(ghost_type, is_weak) )
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
GhostMetadata::GhostMetadata( const std::string& name,
|
|
||||||
const naGhostType* ghost_type_strong,
|
|
||||||
const naGhostType* ghost_type_weak ):
|
|
||||||
_name_strong(name),
|
|
||||||
_name_weak(name + " (weak ref)"),
|
|
||||||
_ghost_type_strong_ptr(ghost_type_strong),
|
|
||||||
_ghost_type_weak_ptr(ghost_type_weak)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
void GhostMetadata::addDerived(const GhostMetadata* derived)
|
|
||||||
{
|
|
||||||
assert(derived);
|
|
||||||
_derived_classes.push_back(derived);
|
|
||||||
|
|
||||||
SG_LOG
|
|
||||||
(
|
|
||||||
SG_NASAL,
|
|
||||||
SG_INFO,
|
|
||||||
"Ghost::addDerived: " << _name_strong << " -> "
|
|
||||||
<< derived->_name_strong
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
naRef GhostMetadata::getParents(naContext c)
|
|
||||||
{
|
|
||||||
return nasal::to_nasal(c, _parents);
|
|
||||||
}
|
|
||||||
} // namespace internal
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
void ghostProcessDestroyList()
|
|
||||||
{
|
|
||||||
using internal::GhostMetadata;
|
|
||||||
typedef GhostMetadata::DestroyList::const_iterator destroy_iterator;
|
|
||||||
for( destroy_iterator it = GhostMetadata::_destroy_list.begin();
|
|
||||||
it != GhostMetadata::_destroy_list.end();
|
|
||||||
++it )
|
|
||||||
it->first(it->second);
|
|
||||||
GhostMetadata::_destroy_list.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace nasal
|
|
||||||
|
|
||||||
+208
-668
File diff suppressed because it is too large
Load Diff
@@ -38,24 +38,30 @@ namespace nasal
|
|||||||
args(args)
|
args(args)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
#define SG_CTX_CHECK_ARG(name, check)\
|
bool isNumeric(size_t index) const
|
||||||
bool is##name(size_t index) const\
|
{
|
||||||
{\
|
return (index < argc && naIsNum(args[index]));
|
||||||
return (index < argc && naIs##check(args[index]));\
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SG_CTX_CHECK_ARG(Code, Code)
|
bool isString(size_t index) const
|
||||||
SG_CTX_CHECK_ARG(CCode, CCode)
|
{
|
||||||
SG_CTX_CHECK_ARG(Func, Func)
|
return (index < argc && naIsString(args[index]));
|
||||||
SG_CTX_CHECK_ARG(Ghost, Ghost)
|
}
|
||||||
SG_CTX_CHECK_ARG(Hash, Hash)
|
|
||||||
SG_CTX_CHECK_ARG(Nil, Nil)
|
|
||||||
SG_CTX_CHECK_ARG(Numeric, Num)
|
|
||||||
SG_CTX_CHECK_ARG(Scalar, Scalar)
|
|
||||||
SG_CTX_CHECK_ARG(String, String)
|
|
||||||
SG_CTX_CHECK_ARG(Vector, Vector)
|
|
||||||
|
|
||||||
#undef SG_CTX_CHECK_ARG
|
bool isHash(size_t index) const
|
||||||
|
{
|
||||||
|
return (index < argc && naIsHash(args[index]));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isVector(size_t index) const
|
||||||
|
{
|
||||||
|
return (index < argc && naIsVector(args[index]));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isGhost(size_t index) const
|
||||||
|
{
|
||||||
|
return (index < argc && naIsGhost(args[index]));
|
||||||
|
}
|
||||||
|
|
||||||
void popFront(size_t num = 1)
|
void popFront(size_t num = 1)
|
||||||
{
|
{
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user