Compare commits
190 Commits
version/3.
...
version/20
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
68fd8e8dba | ||
|
|
807330a616 | ||
|
|
2deb361f0f | ||
|
|
63e7a1fbb4 | ||
|
|
951859d8a7 | ||
|
|
41f40a9a10 | ||
|
|
a6290e367a | ||
|
|
af0a51930e | ||
|
|
ccb5d05eb4 | ||
|
|
9d7402242a | ||
|
|
819833a560 | ||
|
|
576ff21488 | ||
|
|
b60f8b4989 | ||
|
|
096d625445 | ||
|
|
dad77b3983 | ||
|
|
598b64fa95 | ||
|
|
b5d6aa3fe4 | ||
|
|
f32063e6dd | ||
|
|
3d9d44cf73 | ||
|
|
ac84115ac3 | ||
|
|
d58607242e | ||
|
|
7afd2be652 | ||
|
|
f256d45b65 | ||
|
|
edf15e9f55 | ||
|
|
2bb24f43fb | ||
|
|
be0447d4c0 | ||
|
|
ef7a0dc5a3 | ||
|
|
5d754c0419 | ||
|
|
1f23fb89c0 | ||
|
|
584ee1364f | ||
|
|
1e32c24a17 | ||
|
|
20ea55bdbc | ||
|
|
c62b4467b4 | ||
|
|
31095c39cc | ||
|
|
05d9d7cae8 | ||
|
|
78a548b861 | ||
|
|
6be4ad27ee | ||
|
|
589c5ba35a | ||
|
|
81d668784a | ||
|
|
75ad5a7e5c | ||
|
|
3f20a3d2c6 | ||
|
|
a57e969639 | ||
|
|
23b8c86e78 | ||
|
|
5c9ca9cbe2 | ||
|
|
5676f96fbf | ||
|
|
4104f7d18f | ||
|
|
10e6bbc2c5 | ||
|
|
21e6dd34b2 | ||
|
|
319922f044 | ||
|
|
ff3efaee93 | ||
|
|
08fb433923 | ||
|
|
1a752d28a4 | ||
|
|
00a20409f7 | ||
|
|
3bfd0c872a | ||
|
|
945cf5d963 | ||
|
|
4e40913aef | ||
|
|
3bc53474ed | ||
|
|
28dff1d5ca | ||
|
|
81bfec336c | ||
|
|
60a0c51e2b | ||
|
|
70c5d60564 | ||
|
|
1b2247103a | ||
|
|
a49c3a49d3 | ||
|
|
105438fc58 | ||
|
|
2910c6a77b | ||
|
|
6dd859c75e | ||
|
|
b7c7f66bf3 | ||
|
|
c7a60d4dc4 | ||
|
|
a841fcc89e | ||
|
|
b91d1a3f6a | ||
|
|
1378511c13 | ||
|
|
9a9cd62957 | ||
|
|
a9742fba7c | ||
|
|
9ea772f938 | ||
|
|
e64902ae8c | ||
|
|
0b1399479a | ||
|
|
0369d1f506 | ||
|
|
f19cf6d56a | ||
|
|
d12d1b2c3a | ||
|
|
b7fbb79565 | ||
|
|
541239ceac | ||
|
|
fd74095939 | ||
|
|
b24d190e55 | ||
|
|
8b351520bd | ||
|
|
5bbdcfd240 | ||
|
|
51ff30f386 | ||
|
|
6683092bb2 | ||
|
|
2c6f9de020 | ||
|
|
686f095f1e | ||
|
|
089fc5ea0a | ||
|
|
72ae14227e | ||
|
|
0e9948f9d4 | ||
|
|
0b6738b616 | ||
|
|
3c204e84f4 | ||
|
|
7774b76ad2 | ||
|
|
acd655b37b | ||
|
|
1a09683351 | ||
|
|
181afb7fd0 | ||
|
|
9d1354f6bd | ||
|
|
596591bb64 | ||
|
|
a67a984d29 | ||
|
|
37a963da92 | ||
|
|
384a700e05 | ||
|
|
7d2ecef14a | ||
|
|
bc72c34d0f | ||
|
|
ca7acb1f2c | ||
|
|
1365a02aea | ||
|
|
611785c04b | ||
|
|
e5995208a9 | ||
|
|
6f15bb415f | ||
|
|
ce7f78e0ca | ||
|
|
6323477a35 | ||
|
|
8c38f799ad | ||
|
|
1bf0b7222d | ||
|
|
0cc5374fe7 | ||
|
|
b2ac9982d4 | ||
|
|
84cbfb2e98 | ||
|
|
7479cadbba | ||
|
|
f711306085 | ||
|
|
148640be34 | ||
|
|
27a91062bd | ||
|
|
dc1816bb08 | ||
|
|
e836e85697 | ||
|
|
2d00653f6e | ||
|
|
4647ce2da5 | ||
|
|
51d43f809e | ||
|
|
370a115ab9 | ||
|
|
32b60f9b80 | ||
|
|
beeaef3868 | ||
|
|
ddd9691439 | ||
|
|
9da0031039 | ||
|
|
9537876bba | ||
|
|
958ae9bdf0 | ||
|
|
023b5a09f7 | ||
|
|
46fe57fb8d | ||
|
|
07e09bb88c | ||
|
|
1b7f310ea6 | ||
|
|
365ddb84a7 | ||
|
|
5fef44b11c | ||
|
|
1480aa9bb8 | ||
|
|
75271c44a8 | ||
|
|
543f1b7902 | ||
|
|
93a63a0678 | ||
|
|
2bf79a2fa1 | ||
|
|
ab956f15c3 | ||
|
|
deceee8997 | ||
|
|
b3c7d63809 | ||
|
|
2026c665b2 | ||
|
|
36fd005bb9 | ||
|
|
46bed67cce | ||
|
|
5b9af0c0aa | ||
|
|
85090180d0 | ||
|
|
f33ad357e9 | ||
|
|
c30ce67e16 | ||
|
|
3ca7369fb2 | ||
|
|
088ce31f7c | ||
|
|
4f94c22241 | ||
|
|
e1791b3006 | ||
|
|
e608ed5a01 | ||
|
|
35ebb16215 | ||
|
|
68d0891665 | ||
|
|
b11ff19a0f | ||
|
|
e7e616e07c | ||
|
|
14f2f9e917 | ||
|
|
791273c61d | ||
|
|
519326f751 | ||
|
|
d1f5d92a7b | ||
|
|
f448898531 | ||
|
|
d9b66fc0ef | ||
|
|
3bcd0bafd5 | ||
|
|
942181c8ae | ||
|
|
7df39b9fc8 | ||
|
|
f41b18f064 | ||
|
|
c5d649aa0b | ||
|
|
64ac22f50c | ||
|
|
719ee36f5c | ||
|
|
92851135d4 | ||
|
|
76fc47b24b | ||
|
|
f25abad9d7 | ||
|
|
23413b4781 | ||
|
|
e036dfc5bf | ||
|
|
9260bea850 | ||
|
|
c1f09034e0 | ||
|
|
557e4f75b5 | ||
|
|
e71d6b24d7 | ||
|
|
726a4c6d10 | ||
|
|
6af8d32078 | ||
|
|
f6b16e2ba8 | ||
|
|
e415b08da4 | ||
|
|
1d93e8d61e |
1
3rdparty/CMakeLists.txt
vendored
1
3rdparty/CMakeLists.txt
vendored
@@ -2,3 +2,4 @@ if (NOT SYSTEM_EXPAT)
|
||||
add_subdirectory(expat)
|
||||
endif()
|
||||
|
||||
add_subdirectory(utf8)
|
||||
|
||||
17
3rdparty/utf8/CMakeLists.txt
vendored
Normal file
17
3rdparty/utf8/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
include (SimGearComponent)
|
||||
|
||||
set(HEADERS
|
||||
source/utf8.h
|
||||
)
|
||||
|
||||
set(HEADERS_utf8
|
||||
source/utf8/checked.h
|
||||
source/utf8/core.h
|
||||
source/utf8/unchecked.h
|
||||
)
|
||||
|
||||
set(SOURCES
|
||||
)
|
||||
|
||||
simgear_component(utf8 3rdparty/utf8 "${SOURCES}" "${HEADERS}")
|
||||
simgear_component(utf8-internal 3rdparty/utf8/utf8 "" "${HEADERS_utf8}")
|
||||
12
3rdparty/utf8/doc/ReleaseNotes
vendored
Normal file
12
3rdparty/utf8/doc/ReleaseNotes
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
utf8 cpp library
|
||||
Release 2.3.4
|
||||
|
||||
A minor bug fix release. Thanks to all who reported bugs.
|
||||
|
||||
Note: Version 2.3.3 contained a regression, and therefore was removed.
|
||||
|
||||
Changes from version 2.3.2
|
||||
- Bug fix [39]: checked.h Line 273 and unchecked.h Line 182 have an extra ';'
|
||||
- Bug fix [36]: replace_invalid() only works with back_inserter
|
||||
|
||||
Files included in the release: utf8.h, core.h, checked.h, unchecked.h, utf8cpp.html, ReleaseNotes
|
||||
1789
3rdparty/utf8/doc/utf8cpp.html
vendored
Normal file
1789
3rdparty/utf8/doc/utf8cpp.html
vendored
Normal file
File diff suppressed because it is too large
Load Diff
34
3rdparty/utf8/source/utf8.h
vendored
Normal file
34
3rdparty/utf8/source/utf8.h
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
// Copyright 2006 Nemanja Trifunovic
|
||||
|
||||
/*
|
||||
Permission is hereby granted, free of charge, to any person or organization
|
||||
obtaining a copy of the software and accompanying documentation covered by
|
||||
this license (the "Software") to use, reproduce, display, distribute,
|
||||
execute, and transmit the Software, and to prepare derivative works of the
|
||||
Software, and to permit third-parties to whom the Software is furnished to
|
||||
do so, all subject to the following:
|
||||
|
||||
The copyright notices in the Software and this entire statement, including
|
||||
the above license grant, this restriction and the following disclaimer,
|
||||
must be included in all copies of the Software, in whole or in part, and
|
||||
all derivative works of the Software, unless such copies or derivative
|
||||
works are solely in the form of machine-executable object code generated by
|
||||
a source language processor.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef UTF8_FOR_CPP_2675DCD0_9480_4c0c_B92A_CC14C027B731
|
||||
#define UTF8_FOR_CPP_2675DCD0_9480_4c0c_B92A_CC14C027B731
|
||||
|
||||
#include "utf8/checked.h"
|
||||
#include "utf8/unchecked.h"
|
||||
|
||||
#endif // header guard
|
||||
327
3rdparty/utf8/source/utf8/checked.h
vendored
Normal file
327
3rdparty/utf8/source/utf8/checked.h
vendored
Normal file
@@ -0,0 +1,327 @@
|
||||
// Copyright 2006 Nemanja Trifunovic
|
||||
|
||||
/*
|
||||
Permission is hereby granted, free of charge, to any person or organization
|
||||
obtaining a copy of the software and accompanying documentation covered by
|
||||
this license (the "Software") to use, reproduce, display, distribute,
|
||||
execute, and transmit the Software, and to prepare derivative works of the
|
||||
Software, and to permit third-parties to whom the Software is furnished to
|
||||
do so, all subject to the following:
|
||||
|
||||
The copyright notices in the Software and this entire statement, including
|
||||
the above license grant, this restriction and the following disclaimer,
|
||||
must be included in all copies of the Software, in whole or in part, and
|
||||
all derivative works of the Software, unless such copies or derivative
|
||||
works are solely in the form of machine-executable object code generated by
|
||||
a source language processor.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef UTF8_FOR_CPP_CHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731
|
||||
#define UTF8_FOR_CPP_CHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731
|
||||
|
||||
#include "core.h"
|
||||
#include <stdexcept>
|
||||
|
||||
namespace utf8
|
||||
{
|
||||
// Base for the exceptions that may be thrown from the library
|
||||
class exception : public ::std::exception {
|
||||
};
|
||||
|
||||
// Exceptions that may be thrown from the library functions.
|
||||
class invalid_code_point : public exception {
|
||||
uint32_t cp;
|
||||
public:
|
||||
invalid_code_point(uint32_t cp) : cp(cp) {}
|
||||
virtual const char* what() const throw() { return "Invalid code point"; }
|
||||
uint32_t code_point() const {return cp;}
|
||||
};
|
||||
|
||||
class invalid_utf8 : public exception {
|
||||
uint8_t u8;
|
||||
public:
|
||||
invalid_utf8 (uint8_t u) : u8(u) {}
|
||||
virtual const char* what() const throw() { return "Invalid UTF-8"; }
|
||||
uint8_t utf8_octet() const {return u8;}
|
||||
};
|
||||
|
||||
class invalid_utf16 : public exception {
|
||||
uint16_t u16;
|
||||
public:
|
||||
invalid_utf16 (uint16_t u) : u16(u) {}
|
||||
virtual const char* what() const throw() { return "Invalid UTF-16"; }
|
||||
uint16_t utf16_word() const {return u16;}
|
||||
};
|
||||
|
||||
class not_enough_room : public exception {
|
||||
public:
|
||||
virtual const char* what() const throw() { return "Not enough space"; }
|
||||
};
|
||||
|
||||
/// The library API - functions intended to be called by the users
|
||||
|
||||
template <typename octet_iterator>
|
||||
octet_iterator append(uint32_t cp, octet_iterator result)
|
||||
{
|
||||
if (!utf8::internal::is_code_point_valid(cp))
|
||||
throw invalid_code_point(cp);
|
||||
|
||||
if (cp < 0x80) // one octet
|
||||
*(result++) = static_cast<uint8_t>(cp);
|
||||
else if (cp < 0x800) { // two octets
|
||||
*(result++) = static_cast<uint8_t>((cp >> 6) | 0xc0);
|
||||
*(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80);
|
||||
}
|
||||
else if (cp < 0x10000) { // three octets
|
||||
*(result++) = static_cast<uint8_t>((cp >> 12) | 0xe0);
|
||||
*(result++) = static_cast<uint8_t>(((cp >> 6) & 0x3f) | 0x80);
|
||||
*(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80);
|
||||
}
|
||||
else { // four octets
|
||||
*(result++) = static_cast<uint8_t>((cp >> 18) | 0xf0);
|
||||
*(result++) = static_cast<uint8_t>(((cp >> 12) & 0x3f) | 0x80);
|
||||
*(result++) = static_cast<uint8_t>(((cp >> 6) & 0x3f) | 0x80);
|
||||
*(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename octet_iterator, typename output_iterator>
|
||||
output_iterator replace_invalid(octet_iterator start, octet_iterator end, output_iterator out, uint32_t replacement)
|
||||
{
|
||||
while (start != end) {
|
||||
octet_iterator sequence_start = start;
|
||||
internal::utf_error err_code = utf8::internal::validate_next(start, end);
|
||||
switch (err_code) {
|
||||
case internal::UTF8_OK :
|
||||
for (octet_iterator it = sequence_start; it != start; ++it)
|
||||
*out++ = *it;
|
||||
break;
|
||||
case internal::NOT_ENOUGH_ROOM:
|
||||
throw not_enough_room();
|
||||
case internal::INVALID_LEAD:
|
||||
out = utf8::append (replacement, out);
|
||||
++start;
|
||||
break;
|
||||
case internal::INCOMPLETE_SEQUENCE:
|
||||
case internal::OVERLONG_SEQUENCE:
|
||||
case internal::INVALID_CODE_POINT:
|
||||
out = utf8::append (replacement, out);
|
||||
++start;
|
||||
// just one replacement mark for the sequence
|
||||
while (start != end && utf8::internal::is_trail(*start))
|
||||
++start;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
template <typename octet_iterator, typename output_iterator>
|
||||
inline output_iterator replace_invalid(octet_iterator start, octet_iterator end, output_iterator out)
|
||||
{
|
||||
static const uint32_t replacement_marker = utf8::internal::mask16(0xfffd);
|
||||
return utf8::replace_invalid(start, end, out, replacement_marker);
|
||||
}
|
||||
|
||||
template <typename octet_iterator>
|
||||
uint32_t next(octet_iterator& it, octet_iterator end)
|
||||
{
|
||||
uint32_t cp = 0;
|
||||
internal::utf_error err_code = utf8::internal::validate_next(it, end, cp);
|
||||
switch (err_code) {
|
||||
case internal::UTF8_OK :
|
||||
break;
|
||||
case internal::NOT_ENOUGH_ROOM :
|
||||
throw not_enough_room();
|
||||
case internal::INVALID_LEAD :
|
||||
case internal::INCOMPLETE_SEQUENCE :
|
||||
case internal::OVERLONG_SEQUENCE :
|
||||
throw invalid_utf8(*it);
|
||||
case internal::INVALID_CODE_POINT :
|
||||
throw invalid_code_point(cp);
|
||||
}
|
||||
return cp;
|
||||
}
|
||||
|
||||
template <typename octet_iterator>
|
||||
uint32_t peek_next(octet_iterator it, octet_iterator end)
|
||||
{
|
||||
return utf8::next(it, end);
|
||||
}
|
||||
|
||||
template <typename octet_iterator>
|
||||
uint32_t prior(octet_iterator& it, octet_iterator start)
|
||||
{
|
||||
// can't do much if it == start
|
||||
if (it == start)
|
||||
throw not_enough_room();
|
||||
|
||||
octet_iterator end = it;
|
||||
// Go back until we hit either a lead octet or start
|
||||
while (utf8::internal::is_trail(*(--it)))
|
||||
if (it == start)
|
||||
throw invalid_utf8(*it); // error - no lead byte in the sequence
|
||||
return utf8::peek_next(it, end);
|
||||
}
|
||||
|
||||
/// Deprecated in versions that include "prior"
|
||||
template <typename octet_iterator>
|
||||
uint32_t previous(octet_iterator& it, octet_iterator pass_start)
|
||||
{
|
||||
octet_iterator end = it;
|
||||
while (utf8::internal::is_trail(*(--it)))
|
||||
if (it == pass_start)
|
||||
throw invalid_utf8(*it); // error - no lead byte in the sequence
|
||||
octet_iterator temp = it;
|
||||
return utf8::next(temp, end);
|
||||
}
|
||||
|
||||
template <typename octet_iterator, typename distance_type>
|
||||
void advance (octet_iterator& it, distance_type n, octet_iterator end)
|
||||
{
|
||||
for (distance_type i = 0; i < n; ++i)
|
||||
utf8::next(it, end);
|
||||
}
|
||||
|
||||
template <typename octet_iterator>
|
||||
typename std::iterator_traits<octet_iterator>::difference_type
|
||||
distance (octet_iterator first, octet_iterator last)
|
||||
{
|
||||
typename std::iterator_traits<octet_iterator>::difference_type dist;
|
||||
for (dist = 0; first < last; ++dist)
|
||||
utf8::next(first, last);
|
||||
return dist;
|
||||
}
|
||||
|
||||
template <typename u16bit_iterator, typename octet_iterator>
|
||||
octet_iterator utf16to8 (u16bit_iterator start, u16bit_iterator end, octet_iterator result)
|
||||
{
|
||||
while (start != end) {
|
||||
uint32_t cp = utf8::internal::mask16(*start++);
|
||||
// Take care of surrogate pairs first
|
||||
if (utf8::internal::is_lead_surrogate(cp)) {
|
||||
if (start != end) {
|
||||
uint32_t trail_surrogate = utf8::internal::mask16(*start++);
|
||||
if (utf8::internal::is_trail_surrogate(trail_surrogate))
|
||||
cp = (cp << 10) + trail_surrogate + internal::SURROGATE_OFFSET;
|
||||
else
|
||||
throw invalid_utf16(static_cast<uint16_t>(trail_surrogate));
|
||||
}
|
||||
else
|
||||
throw invalid_utf16(static_cast<uint16_t>(cp));
|
||||
|
||||
}
|
||||
// Lone trail surrogate
|
||||
else if (utf8::internal::is_trail_surrogate(cp))
|
||||
throw invalid_utf16(static_cast<uint16_t>(cp));
|
||||
|
||||
result = utf8::append(cp, result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename u16bit_iterator, typename octet_iterator>
|
||||
u16bit_iterator utf8to16 (octet_iterator start, octet_iterator end, u16bit_iterator result)
|
||||
{
|
||||
while (start != end) {
|
||||
uint32_t cp = utf8::next(start, end);
|
||||
if (cp > 0xffff) { //make a surrogate pair
|
||||
*result++ = static_cast<uint16_t>((cp >> 10) + internal::LEAD_OFFSET);
|
||||
*result++ = static_cast<uint16_t>((cp & 0x3ff) + internal::TRAIL_SURROGATE_MIN);
|
||||
}
|
||||
else
|
||||
*result++ = static_cast<uint16_t>(cp);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename octet_iterator, typename u32bit_iterator>
|
||||
octet_iterator utf32to8 (u32bit_iterator start, u32bit_iterator end, octet_iterator result)
|
||||
{
|
||||
while (start != end)
|
||||
result = utf8::append(*(start++), result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename octet_iterator, typename u32bit_iterator>
|
||||
u32bit_iterator utf8to32 (octet_iterator start, octet_iterator end, u32bit_iterator result)
|
||||
{
|
||||
while (start != end)
|
||||
(*result++) = utf8::next(start, end);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// The iterator class
|
||||
template <typename octet_iterator>
|
||||
class iterator : public std::iterator <std::bidirectional_iterator_tag, uint32_t> {
|
||||
octet_iterator it;
|
||||
octet_iterator range_start;
|
||||
octet_iterator range_end;
|
||||
public:
|
||||
iterator () {}
|
||||
explicit iterator (const octet_iterator& octet_it,
|
||||
const octet_iterator& range_start,
|
||||
const octet_iterator& range_end) :
|
||||
it(octet_it), range_start(range_start), range_end(range_end)
|
||||
{
|
||||
if (it < range_start || it > range_end)
|
||||
throw std::out_of_range("Invalid utf-8 iterator position");
|
||||
}
|
||||
// the default "big three" are OK
|
||||
octet_iterator base () const { return it; }
|
||||
uint32_t operator * () const
|
||||
{
|
||||
octet_iterator temp = it;
|
||||
return utf8::next(temp, range_end);
|
||||
}
|
||||
bool operator == (const iterator& rhs) const
|
||||
{
|
||||
if (range_start != rhs.range_start || range_end != rhs.range_end)
|
||||
throw std::logic_error("Comparing utf-8 iterators defined with different ranges");
|
||||
return (it == rhs.it);
|
||||
}
|
||||
bool operator != (const iterator& rhs) const
|
||||
{
|
||||
return !(operator == (rhs));
|
||||
}
|
||||
iterator& operator ++ ()
|
||||
{
|
||||
utf8::next(it, range_end);
|
||||
return *this;
|
||||
}
|
||||
iterator operator ++ (int)
|
||||
{
|
||||
iterator temp = *this;
|
||||
utf8::next(it, range_end);
|
||||
return temp;
|
||||
}
|
||||
iterator& operator -- ()
|
||||
{
|
||||
utf8::prior(it, range_start);
|
||||
return *this;
|
||||
}
|
||||
iterator operator -- (int)
|
||||
{
|
||||
iterator temp = *this;
|
||||
utf8::prior(it, range_start);
|
||||
return temp;
|
||||
}
|
||||
}; // class iterator
|
||||
|
||||
} // namespace utf8
|
||||
|
||||
#endif //header guard
|
||||
|
||||
|
||||
329
3rdparty/utf8/source/utf8/core.h
vendored
Normal file
329
3rdparty/utf8/source/utf8/core.h
vendored
Normal file
@@ -0,0 +1,329 @@
|
||||
// Copyright 2006 Nemanja Trifunovic
|
||||
|
||||
/*
|
||||
Permission is hereby granted, free of charge, to any person or organization
|
||||
obtaining a copy of the software and accompanying documentation covered by
|
||||
this license (the "Software") to use, reproduce, display, distribute,
|
||||
execute, and transmit the Software, and to prepare derivative works of the
|
||||
Software, and to permit third-parties to whom the Software is furnished to
|
||||
do so, all subject to the following:
|
||||
|
||||
The copyright notices in the Software and this entire statement, including
|
||||
the above license grant, this restriction and the following disclaimer,
|
||||
must be included in all copies of the Software, in whole or in part, and
|
||||
all derivative works of the Software, unless such copies or derivative
|
||||
works are solely in the form of machine-executable object code generated by
|
||||
a source language processor.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef UTF8_FOR_CPP_CORE_H_2675DCD0_9480_4c0c_B92A_CC14C027B731
|
||||
#define UTF8_FOR_CPP_CORE_H_2675DCD0_9480_4c0c_B92A_CC14C027B731
|
||||
|
||||
#include <iterator>
|
||||
|
||||
namespace utf8
|
||||
{
|
||||
// The typedefs for 8-bit, 16-bit and 32-bit unsigned integers
|
||||
// You may need to change them to match your system.
|
||||
// These typedefs have the same names as ones from cstdint, or boost/cstdint
|
||||
typedef unsigned char uint8_t;
|
||||
typedef unsigned short uint16_t;
|
||||
typedef unsigned int uint32_t;
|
||||
|
||||
// Helper code - not intended to be directly called by the library users. May be changed at any time
|
||||
namespace internal
|
||||
{
|
||||
// Unicode constants
|
||||
// Leading (high) surrogates: 0xd800 - 0xdbff
|
||||
// Trailing (low) surrogates: 0xdc00 - 0xdfff
|
||||
const uint16_t LEAD_SURROGATE_MIN = 0xd800u;
|
||||
const uint16_t LEAD_SURROGATE_MAX = 0xdbffu;
|
||||
const uint16_t TRAIL_SURROGATE_MIN = 0xdc00u;
|
||||
const uint16_t TRAIL_SURROGATE_MAX = 0xdfffu;
|
||||
const uint16_t LEAD_OFFSET = LEAD_SURROGATE_MIN - (0x10000 >> 10);
|
||||
const uint32_t SURROGATE_OFFSET = 0x10000u - (LEAD_SURROGATE_MIN << 10) - TRAIL_SURROGATE_MIN;
|
||||
|
||||
// Maximum valid value for a Unicode code point
|
||||
const uint32_t CODE_POINT_MAX = 0x0010ffffu;
|
||||
|
||||
template<typename octet_type>
|
||||
inline uint8_t mask8(octet_type oc)
|
||||
{
|
||||
return static_cast<uint8_t>(0xff & oc);
|
||||
}
|
||||
template<typename u16_type>
|
||||
inline uint16_t mask16(u16_type oc)
|
||||
{
|
||||
return static_cast<uint16_t>(0xffff & oc);
|
||||
}
|
||||
template<typename octet_type>
|
||||
inline bool is_trail(octet_type oc)
|
||||
{
|
||||
return ((utf8::internal::mask8(oc) >> 6) == 0x2);
|
||||
}
|
||||
|
||||
template <typename u16>
|
||||
inline bool is_lead_surrogate(u16 cp)
|
||||
{
|
||||
return (cp >= LEAD_SURROGATE_MIN && cp <= LEAD_SURROGATE_MAX);
|
||||
}
|
||||
|
||||
template <typename u16>
|
||||
inline bool is_trail_surrogate(u16 cp)
|
||||
{
|
||||
return (cp >= TRAIL_SURROGATE_MIN && cp <= TRAIL_SURROGATE_MAX);
|
||||
}
|
||||
|
||||
template <typename u16>
|
||||
inline bool is_surrogate(u16 cp)
|
||||
{
|
||||
return (cp >= LEAD_SURROGATE_MIN && cp <= TRAIL_SURROGATE_MAX);
|
||||
}
|
||||
|
||||
template <typename u32>
|
||||
inline bool is_code_point_valid(u32 cp)
|
||||
{
|
||||
return (cp <= CODE_POINT_MAX && !utf8::internal::is_surrogate(cp));
|
||||
}
|
||||
|
||||
template <typename octet_iterator>
|
||||
inline typename std::iterator_traits<octet_iterator>::difference_type
|
||||
sequence_length(octet_iterator lead_it)
|
||||
{
|
||||
uint8_t lead = utf8::internal::mask8(*lead_it);
|
||||
if (lead < 0x80)
|
||||
return 1;
|
||||
else if ((lead >> 5) == 0x6)
|
||||
return 2;
|
||||
else if ((lead >> 4) == 0xe)
|
||||
return 3;
|
||||
else if ((lead >> 3) == 0x1e)
|
||||
return 4;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <typename octet_difference_type>
|
||||
inline bool is_overlong_sequence(uint32_t cp, octet_difference_type length)
|
||||
{
|
||||
if (cp < 0x80) {
|
||||
if (length != 1)
|
||||
return true;
|
||||
}
|
||||
else if (cp < 0x800) {
|
||||
if (length != 2)
|
||||
return true;
|
||||
}
|
||||
else if (cp < 0x10000) {
|
||||
if (length != 3)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
enum utf_error {UTF8_OK, NOT_ENOUGH_ROOM, INVALID_LEAD, INCOMPLETE_SEQUENCE, OVERLONG_SEQUENCE, INVALID_CODE_POINT};
|
||||
|
||||
/// Helper for get_sequence_x
|
||||
template <typename octet_iterator>
|
||||
utf_error increase_safely(octet_iterator& it, octet_iterator end)
|
||||
{
|
||||
if (++it == end)
|
||||
return NOT_ENOUGH_ROOM;
|
||||
|
||||
if (!utf8::internal::is_trail(*it))
|
||||
return INCOMPLETE_SEQUENCE;
|
||||
|
||||
return UTF8_OK;
|
||||
}
|
||||
|
||||
#define UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(IT, END) {utf_error ret = increase_safely(IT, END); if (ret != UTF8_OK) return ret;}
|
||||
|
||||
/// get_sequence_x functions decode utf-8 sequences of the length x
|
||||
template <typename octet_iterator>
|
||||
utf_error get_sequence_1(octet_iterator& it, octet_iterator end, uint32_t& code_point)
|
||||
{
|
||||
if (it == end)
|
||||
return NOT_ENOUGH_ROOM;
|
||||
|
||||
code_point = utf8::internal::mask8(*it);
|
||||
|
||||
return UTF8_OK;
|
||||
}
|
||||
|
||||
template <typename octet_iterator>
|
||||
utf_error get_sequence_2(octet_iterator& it, octet_iterator end, uint32_t& code_point)
|
||||
{
|
||||
if (it == end)
|
||||
return NOT_ENOUGH_ROOM;
|
||||
|
||||
code_point = utf8::internal::mask8(*it);
|
||||
|
||||
UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
|
||||
|
||||
code_point = ((code_point << 6) & 0x7ff) + ((*it) & 0x3f);
|
||||
|
||||
return UTF8_OK;
|
||||
}
|
||||
|
||||
template <typename octet_iterator>
|
||||
utf_error get_sequence_3(octet_iterator& it, octet_iterator end, uint32_t& code_point)
|
||||
{
|
||||
if (it == end)
|
||||
return NOT_ENOUGH_ROOM;
|
||||
|
||||
code_point = utf8::internal::mask8(*it);
|
||||
|
||||
UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
|
||||
|
||||
code_point = ((code_point << 12) & 0xffff) + ((utf8::internal::mask8(*it) << 6) & 0xfff);
|
||||
|
||||
UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
|
||||
|
||||
code_point += (*it) & 0x3f;
|
||||
|
||||
return UTF8_OK;
|
||||
}
|
||||
|
||||
template <typename octet_iterator>
|
||||
utf_error get_sequence_4(octet_iterator& it, octet_iterator end, uint32_t& code_point)
|
||||
{
|
||||
if (it == end)
|
||||
return NOT_ENOUGH_ROOM;
|
||||
|
||||
code_point = utf8::internal::mask8(*it);
|
||||
|
||||
UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
|
||||
|
||||
code_point = ((code_point << 18) & 0x1fffff) + ((utf8::internal::mask8(*it) << 12) & 0x3ffff);
|
||||
|
||||
UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
|
||||
|
||||
code_point += (utf8::internal::mask8(*it) << 6) & 0xfff;
|
||||
|
||||
UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
|
||||
|
||||
code_point += (*it) & 0x3f;
|
||||
|
||||
return UTF8_OK;
|
||||
}
|
||||
|
||||
#undef UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR
|
||||
|
||||
template <typename octet_iterator>
|
||||
utf_error validate_next(octet_iterator& it, octet_iterator end, uint32_t& code_point)
|
||||
{
|
||||
// Save the original value of it so we can go back in case of failure
|
||||
// Of course, it does not make much sense with i.e. stream iterators
|
||||
octet_iterator original_it = it;
|
||||
|
||||
uint32_t cp = 0;
|
||||
// Determine the sequence length based on the lead octet
|
||||
typedef typename std::iterator_traits<octet_iterator>::difference_type octet_difference_type;
|
||||
const octet_difference_type length = utf8::internal::sequence_length(it);
|
||||
|
||||
// Get trail octets and calculate the code point
|
||||
utf_error err = UTF8_OK;
|
||||
switch (length) {
|
||||
case 0:
|
||||
return INVALID_LEAD;
|
||||
case 1:
|
||||
err = utf8::internal::get_sequence_1(it, end, cp);
|
||||
break;
|
||||
case 2:
|
||||
err = utf8::internal::get_sequence_2(it, end, cp);
|
||||
break;
|
||||
case 3:
|
||||
err = utf8::internal::get_sequence_3(it, end, cp);
|
||||
break;
|
||||
case 4:
|
||||
err = utf8::internal::get_sequence_4(it, end, cp);
|
||||
break;
|
||||
}
|
||||
|
||||
if (err == UTF8_OK) {
|
||||
// Decoding succeeded. Now, security checks...
|
||||
if (utf8::internal::is_code_point_valid(cp)) {
|
||||
if (!utf8::internal::is_overlong_sequence(cp, length)){
|
||||
// Passed! Return here.
|
||||
code_point = cp;
|
||||
++it;
|
||||
return UTF8_OK;
|
||||
}
|
||||
else
|
||||
err = OVERLONG_SEQUENCE;
|
||||
}
|
||||
else
|
||||
err = INVALID_CODE_POINT;
|
||||
}
|
||||
|
||||
// Failure branch - restore the original value of the iterator
|
||||
it = original_it;
|
||||
return err;
|
||||
}
|
||||
|
||||
template <typename octet_iterator>
|
||||
inline utf_error validate_next(octet_iterator& it, octet_iterator end) {
|
||||
uint32_t ignored;
|
||||
return utf8::internal::validate_next(it, end, ignored);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
/// The library API - functions intended to be called by the users
|
||||
|
||||
// Byte order mark
|
||||
const uint8_t bom[] = {0xef, 0xbb, 0xbf};
|
||||
|
||||
template <typename octet_iterator>
|
||||
octet_iterator find_invalid(octet_iterator start, octet_iterator end)
|
||||
{
|
||||
octet_iterator result = start;
|
||||
while (result != end) {
|
||||
utf8::internal::utf_error err_code = utf8::internal::validate_next(result, end);
|
||||
if (err_code != internal::UTF8_OK)
|
||||
return result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename octet_iterator>
|
||||
inline bool is_valid(octet_iterator start, octet_iterator end)
|
||||
{
|
||||
return (utf8::find_invalid(start, end) == end);
|
||||
}
|
||||
|
||||
template <typename octet_iterator>
|
||||
inline bool starts_with_bom (octet_iterator it, octet_iterator end)
|
||||
{
|
||||
return (
|
||||
((it != end) && (utf8::internal::mask8(*it++)) == bom[0]) &&
|
||||
((it != end) && (utf8::internal::mask8(*it++)) == bom[1]) &&
|
||||
((it != end) && (utf8::internal::mask8(*it)) == bom[2])
|
||||
);
|
||||
}
|
||||
|
||||
//Deprecated in release 2.3
|
||||
template <typename octet_iterator>
|
||||
inline bool is_bom (octet_iterator it)
|
||||
{
|
||||
return (
|
||||
(utf8::internal::mask8(*it++)) == bom[0] &&
|
||||
(utf8::internal::mask8(*it++)) == bom[1] &&
|
||||
(utf8::internal::mask8(*it)) == bom[2]
|
||||
);
|
||||
}
|
||||
} // namespace utf8
|
||||
|
||||
#endif // header guard
|
||||
|
||||
|
||||
228
3rdparty/utf8/source/utf8/unchecked.h
vendored
Normal file
228
3rdparty/utf8/source/utf8/unchecked.h
vendored
Normal file
@@ -0,0 +1,228 @@
|
||||
// Copyright 2006 Nemanja Trifunovic
|
||||
|
||||
/*
|
||||
Permission is hereby granted, free of charge, to any person or organization
|
||||
obtaining a copy of the software and accompanying documentation covered by
|
||||
this license (the "Software") to use, reproduce, display, distribute,
|
||||
execute, and transmit the Software, and to prepare derivative works of the
|
||||
Software, and to permit third-parties to whom the Software is furnished to
|
||||
do so, all subject to the following:
|
||||
|
||||
The copyright notices in the Software and this entire statement, including
|
||||
the above license grant, this restriction and the following disclaimer,
|
||||
must be included in all copies of the Software, in whole or in part, and
|
||||
all derivative works of the Software, unless such copies or derivative
|
||||
works are solely in the form of machine-executable object code generated by
|
||||
a source language processor.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef UTF8_FOR_CPP_UNCHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731
|
||||
#define UTF8_FOR_CPP_UNCHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731
|
||||
|
||||
#include "core.h"
|
||||
|
||||
namespace utf8
|
||||
{
|
||||
namespace unchecked
|
||||
{
|
||||
template <typename octet_iterator>
|
||||
octet_iterator append(uint32_t cp, octet_iterator result)
|
||||
{
|
||||
if (cp < 0x80) // one octet
|
||||
*(result++) = static_cast<uint8_t>(cp);
|
||||
else if (cp < 0x800) { // two octets
|
||||
*(result++) = static_cast<uint8_t>((cp >> 6) | 0xc0);
|
||||
*(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80);
|
||||
}
|
||||
else if (cp < 0x10000) { // three octets
|
||||
*(result++) = static_cast<uint8_t>((cp >> 12) | 0xe0);
|
||||
*(result++) = static_cast<uint8_t>(((cp >> 6) & 0x3f) | 0x80);
|
||||
*(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80);
|
||||
}
|
||||
else { // four octets
|
||||
*(result++) = static_cast<uint8_t>((cp >> 18) | 0xf0);
|
||||
*(result++) = static_cast<uint8_t>(((cp >> 12) & 0x3f)| 0x80);
|
||||
*(result++) = static_cast<uint8_t>(((cp >> 6) & 0x3f) | 0x80);
|
||||
*(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename octet_iterator>
|
||||
uint32_t next(octet_iterator& it)
|
||||
{
|
||||
uint32_t cp = utf8::internal::mask8(*it);
|
||||
typename std::iterator_traits<octet_iterator>::difference_type length = utf8::internal::sequence_length(it);
|
||||
switch (length) {
|
||||
case 1:
|
||||
break;
|
||||
case 2:
|
||||
it++;
|
||||
cp = ((cp << 6) & 0x7ff) + ((*it) & 0x3f);
|
||||
break;
|
||||
case 3:
|
||||
++it;
|
||||
cp = ((cp << 12) & 0xffff) + ((utf8::internal::mask8(*it) << 6) & 0xfff);
|
||||
++it;
|
||||
cp += (*it) & 0x3f;
|
||||
break;
|
||||
case 4:
|
||||
++it;
|
||||
cp = ((cp << 18) & 0x1fffff) + ((utf8::internal::mask8(*it) << 12) & 0x3ffff);
|
||||
++it;
|
||||
cp += (utf8::internal::mask8(*it) << 6) & 0xfff;
|
||||
++it;
|
||||
cp += (*it) & 0x3f;
|
||||
break;
|
||||
}
|
||||
++it;
|
||||
return cp;
|
||||
}
|
||||
|
||||
template <typename octet_iterator>
|
||||
uint32_t peek_next(octet_iterator it)
|
||||
{
|
||||
return utf8::unchecked::next(it);
|
||||
}
|
||||
|
||||
template <typename octet_iterator>
|
||||
uint32_t prior(octet_iterator& it)
|
||||
{
|
||||
while (utf8::internal::is_trail(*(--it))) ;
|
||||
octet_iterator temp = it;
|
||||
return utf8::unchecked::next(temp);
|
||||
}
|
||||
|
||||
// Deprecated in versions that include prior, but only for the sake of consistency (see utf8::previous)
|
||||
template <typename octet_iterator>
|
||||
inline uint32_t previous(octet_iterator& it)
|
||||
{
|
||||
return utf8::unchecked::prior(it);
|
||||
}
|
||||
|
||||
template <typename octet_iterator, typename distance_type>
|
||||
void advance (octet_iterator& it, distance_type n)
|
||||
{
|
||||
for (distance_type i = 0; i < n; ++i)
|
||||
utf8::unchecked::next(it);
|
||||
}
|
||||
|
||||
template <typename octet_iterator>
|
||||
typename std::iterator_traits<octet_iterator>::difference_type
|
||||
distance (octet_iterator first, octet_iterator last)
|
||||
{
|
||||
typename std::iterator_traits<octet_iterator>::difference_type dist;
|
||||
for (dist = 0; first < last; ++dist)
|
||||
utf8::unchecked::next(first);
|
||||
return dist;
|
||||
}
|
||||
|
||||
template <typename u16bit_iterator, typename octet_iterator>
|
||||
octet_iterator utf16to8 (u16bit_iterator start, u16bit_iterator end, octet_iterator result)
|
||||
{
|
||||
while (start != end) {
|
||||
uint32_t cp = utf8::internal::mask16(*start++);
|
||||
// Take care of surrogate pairs first
|
||||
if (utf8::internal::is_lead_surrogate(cp)) {
|
||||
uint32_t trail_surrogate = utf8::internal::mask16(*start++);
|
||||
cp = (cp << 10) + trail_surrogate + internal::SURROGATE_OFFSET;
|
||||
}
|
||||
result = utf8::unchecked::append(cp, result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename u16bit_iterator, typename octet_iterator>
|
||||
u16bit_iterator utf8to16 (octet_iterator start, octet_iterator end, u16bit_iterator result)
|
||||
{
|
||||
while (start < end) {
|
||||
uint32_t cp = utf8::unchecked::next(start);
|
||||
if (cp > 0xffff) { //make a surrogate pair
|
||||
*result++ = static_cast<uint16_t>((cp >> 10) + internal::LEAD_OFFSET);
|
||||
*result++ = static_cast<uint16_t>((cp & 0x3ff) + internal::TRAIL_SURROGATE_MIN);
|
||||
}
|
||||
else
|
||||
*result++ = static_cast<uint16_t>(cp);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename octet_iterator, typename u32bit_iterator>
|
||||
octet_iterator utf32to8 (u32bit_iterator start, u32bit_iterator end, octet_iterator result)
|
||||
{
|
||||
while (start != end)
|
||||
result = utf8::unchecked::append(*(start++), result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename octet_iterator, typename u32bit_iterator>
|
||||
u32bit_iterator utf8to32 (octet_iterator start, octet_iterator end, u32bit_iterator result)
|
||||
{
|
||||
while (start < end)
|
||||
(*result++) = utf8::unchecked::next(start);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// The iterator class
|
||||
template <typename octet_iterator>
|
||||
class iterator : public std::iterator <std::bidirectional_iterator_tag, uint32_t> {
|
||||
octet_iterator it;
|
||||
public:
|
||||
iterator () {}
|
||||
explicit iterator (const octet_iterator& octet_it): it(octet_it) {}
|
||||
// the default "big three" are OK
|
||||
octet_iterator base () const { return it; }
|
||||
uint32_t operator * () const
|
||||
{
|
||||
octet_iterator temp = it;
|
||||
return utf8::unchecked::next(temp);
|
||||
}
|
||||
bool operator == (const iterator& rhs) const
|
||||
{
|
||||
return (it == rhs.it);
|
||||
}
|
||||
bool operator != (const iterator& rhs) const
|
||||
{
|
||||
return !(operator == (rhs));
|
||||
}
|
||||
iterator& operator ++ ()
|
||||
{
|
||||
::std::advance(it, utf8::internal::sequence_length(it));
|
||||
return *this;
|
||||
}
|
||||
iterator operator ++ (int)
|
||||
{
|
||||
iterator temp = *this;
|
||||
::std::advance(it, utf8::internal::sequence_length(it));
|
||||
return temp;
|
||||
}
|
||||
iterator& operator -- ()
|
||||
{
|
||||
utf8::unchecked::prior(it);
|
||||
return *this;
|
||||
}
|
||||
iterator operator -- (int)
|
||||
{
|
||||
iterator temp = *this;
|
||||
utf8::unchecked::prior(it);
|
||||
return temp;
|
||||
}
|
||||
}; // class iterator
|
||||
|
||||
} // namespace utf8::unchecked
|
||||
} // namespace utf8
|
||||
|
||||
|
||||
#endif // header guard
|
||||
|
||||
130
CMakeLists.txt
130
CMakeLists.txt
@@ -1,8 +1,26 @@
|
||||
cmake_minimum_required (VERSION 2.6.4)
|
||||
cmake_minimum_required (VERSION 2.8.11)
|
||||
|
||||
if(COMMAND cmake_policy)
|
||||
if(POLICY CMP0054)
|
||||
cmake_policy(SET CMP0054 NEW)
|
||||
endif()
|
||||
if(POLICY CMP0042)
|
||||
cmake_policy(SET CMP0042 NEW)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
include (CheckFunctionExists)
|
||||
include (CheckIncludeFile)
|
||||
include (CheckLibraryExists)
|
||||
include (CheckCXXSourceCompiles)
|
||||
include (CheckCXXCompilerFlag)
|
||||
include (GenerateExportHeader)
|
||||
|
||||
# using 10.7 because boost requires libc++ and 10.6 doesn't include it
|
||||
set(CMAKE_OSX_DEPLOYMENT_TARGET 10.7)
|
||||
|
||||
# only relevant for building shared libs but let's set it regardless
|
||||
set(CMAKE_OSX_RPATH 1)
|
||||
|
||||
project(SimGear)
|
||||
|
||||
@@ -34,7 +52,7 @@ SET(CPACK_INSTALL_CMAKE_PROJECTS ${CMAKE_CURRENT_BINARY_DIR};SimGear;ALL;/)
|
||||
|
||||
# split version string into components, note CMAKE_MATCH_0 is the entire regexp match
|
||||
string(REGEX MATCH "([0-9]+)\\.([0-9]+)\\.([0-9]+)" CPACK_PACKAGE_VERSION ${SIMGEAR_VERSION} )
|
||||
set(CPACK_PACKAGE_VERSION_MAJOR ${CMAKE_MATCH_1})
|
||||
set(CPACK_PACKAGE_VERSION_MAJOR ${CMAKE_MATCH_1})
|
||||
set(CPACK_PACKAGE_VERSION_MINOR ${CMAKE_MATCH_2})
|
||||
set(CPACK_PACKAGE_VERSION_PATCH ${CMAKE_MATCH_3})
|
||||
|
||||
@@ -62,12 +80,7 @@ endif(NOT CMAKE_BUILD_TYPE)
|
||||
# Determine name of library installation directory, i.e. "lib" vs "lib64", which
|
||||
# differs between all Debian-based vs all other Linux distros.
|
||||
# See cmake bug #11964, http://cmake.org/gitweb?p=cmake.git;a=commit;h=126c993d
|
||||
# GNUInstallDirs requires CMake >= 2.8.5, use own file for older cmake
|
||||
if(${CMAKE_VERSION} VERSION_GREATER 2.8.4)
|
||||
include(GNUInstallDirs)
|
||||
else(${CMAKE_VERSION} VERSION_GREATER 2.8.4)
|
||||
include(OldGNUInstallDirs)
|
||||
endif(${CMAKE_VERSION} VERSION_GREATER 2.8.4)
|
||||
include(GNUInstallDirs)
|
||||
message(STATUS "Library installation directory: ${CMAKE_INSTALL_LIBDIR}")
|
||||
|
||||
#####################################################################################
|
||||
@@ -104,6 +117,7 @@ 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_SOUND "Set to OFF to disable building SimGear's sound support" ON)
|
||||
option(ENABLE_PKGUTIL "Set to ON to build the sg_pkgutil application (default)" ON)
|
||||
option(ENABLE_CURL "Set to ON to use libCurl as the HTTP client backend" OFF)
|
||||
|
||||
if (MSVC)
|
||||
GET_FILENAME_COMPONENT(PARENT_DIR ${PROJECT_BINARY_DIR} PATH)
|
||||
@@ -161,13 +175,23 @@ endif (MSVC AND MSVC_3RDPARTY_ROOT)
|
||||
|
||||
if(APPLE)
|
||||
find_library(COCOA_LIBRARY Cocoa)
|
||||
|
||||
# this should be handled by setting CMAKE_OSX_DEPLOYMENT_TARGET
|
||||
# but it's not working reliably, so forcing it for now
|
||||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mmacosx-version-min=10.7")
|
||||
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mmacosx-version-min=10.7")
|
||||
endif()
|
||||
|
||||
if(${CMAKE_SYSTEM_NAME} MATCHES "Linux" OR
|
||||
${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD")
|
||||
find_package(Threads REQUIRED)
|
||||
endif()
|
||||
|
||||
# Somehow this only works if included before searching for Boost...
|
||||
include(BoostTestTargets)
|
||||
|
||||
find_package(Boost REQUIRED)
|
||||
set (BOOST_CXX_FLAGS "-DBOOST_MULTI_INDEX_DISABLE_SERIALIZATION -DBOOST_BIMAP_DISABLE_SERIALIZATION")
|
||||
set (BOOST_CXX_FLAGS "-DBOOST_BIMAP_DISABLE_SERIALIZATION")
|
||||
|
||||
if(SIMGEAR_HEADLESS)
|
||||
message(STATUS "SimGear mode: HEADLESS")
|
||||
@@ -175,17 +199,21 @@ if(SIMGEAR_HEADLESS)
|
||||
else()
|
||||
message(STATUS "SimGear mode: NORMAL")
|
||||
find_package(OpenGL REQUIRED)
|
||||
|
||||
|
||||
if (ENABLE_SOUND)
|
||||
find_package(OpenAL REQUIRED)
|
||||
message(STATUS "Sound support: ENABLED")
|
||||
endif(ENABLE_SOUND)
|
||||
|
||||
find_package(OpenSceneGraph 3.2.0 REQUIRED osgText osgSim osgDB osgParticle osgGA osgUtil)
|
||||
|
||||
find_package(OpenSceneGraph 3.2.0 REQUIRED osgText osgSim osgDB osgParticle osgGA osgViewer osgUtil)
|
||||
endif(SIMGEAR_HEADLESS)
|
||||
|
||||
find_package(ZLIB REQUIRED)
|
||||
find_package(Threads REQUIRED)
|
||||
|
||||
if (ENABLE_CURL)
|
||||
find_package(CURL REQUIRED)
|
||||
message(STATUS "Curl HTTP client: ENABLED")
|
||||
endif()
|
||||
|
||||
if (SYSTEM_EXPAT)
|
||||
message(STATUS "Requested to use system Expat library, forcing SIMGEAR_SHARED to true")
|
||||
@@ -197,8 +225,8 @@ else()
|
||||
# XML_STATIC is important to avoid sg_expat_external.h
|
||||
# declaring symbols as declspec(import)
|
||||
add_definitions(-DHAVE_EXPAT_CONFIG_H -DXML_STATIC)
|
||||
set(EXPAT_INCLUDE_DIRS
|
||||
${PROJECT_SOURCE_DIR}/3rdparty/expat
|
||||
set(EXPAT_INCLUDE_DIRS
|
||||
${PROJECT_SOURCE_DIR}/3rdparty/expat
|
||||
${PROJECT_BINARY_DIR}/3rdparty/expat)
|
||||
endif(SYSTEM_EXPAT)
|
||||
|
||||
@@ -275,13 +303,13 @@ SET(CMAKE_MINSIZEREL_POSTFIX "" CACHE STRING "add a postfix, usually empty on wi
|
||||
|
||||
# isnan might not be real symbol, so can't check using function_exists
|
||||
check_cxx_source_compiles(
|
||||
"#include <cmath>
|
||||
void f() { isnan(0.0);} "
|
||||
"#include <cmath>
|
||||
int main() { return isnan(0.0);} "
|
||||
HAVE_ISNAN)
|
||||
|
||||
check_cxx_source_compiles(
|
||||
"#include <cmath>
|
||||
void f() { std::isnan(0.0);} "
|
||||
"#include <cmath>
|
||||
int main() { return std::isnan(0.0);} "
|
||||
HAVE_STD_ISNAN)
|
||||
|
||||
if(CMAKE_COMPILER_IS_GNUCXX)
|
||||
@@ -297,8 +325,12 @@ if(CMAKE_COMPILER_IS_GNUCXX)
|
||||
endif(CMAKE_COMPILER_IS_GNUCXX)
|
||||
|
||||
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
||||
set(WARNING_FLAGS_CXX "-Wall -Wno-overloaded-virtual")
|
||||
set(WARNING_FLAGS_C "-Wall")
|
||||
# Boost redeclares class members
|
||||
set(WARNING_FLAGS_CXX "-Wall -Wno-overloaded-virtual -Wno-redeclared-class-member")
|
||||
set(WARNING_FLAGS_C "-Wall")
|
||||
set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LIBRARY "libc++")
|
||||
set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LANGUAGE_STANDARD "c++11")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -stdlib=libc++")
|
||||
endif()
|
||||
|
||||
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
||||
@@ -320,16 +352,16 @@ if(WIN32)
|
||||
# foreach(warning 4244 4251 4267 4275 4290 4786 4305 4996)
|
||||
# SET(WARNING_FLAGS "${WARNING_FLAGS} /wd${warning}")
|
||||
# endforeach(warning)
|
||||
|
||||
|
||||
set(MSVC_FLAGS "-DWIN32 -DNOMINMAX -D_USE_MATH_DEFINES -D_CRT_SECURE_NO_WARNINGS -D__CRT_NONSTDC_NO_WARNINGS /wd4996 /wd4250 -Dstrdup=_strdup")
|
||||
if (${MSVC_VERSION} GREATER 1599)
|
||||
set( MSVC_LD_FLAGS "/FORCE:MULTIPLE" )
|
||||
endif (${MSVC_VERSION} GREATER 1599)
|
||||
endif(MSVC)
|
||||
|
||||
|
||||
# assumed on Windows
|
||||
set(HAVE_GETLOCALTIME 1)
|
||||
|
||||
|
||||
set( WINSOCK_LIBRARY "ws2_32.lib" )
|
||||
set( RT_LIBRARY "winmm" )
|
||||
endif(WIN32)
|
||||
@@ -338,16 +370,17 @@ 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_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${MSVC_LD_FLAGS}")
|
||||
|
||||
# use BEFORE to ensure local directories are used first,
|
||||
# use BEFORE to ensure local directories are used first,
|
||||
# ahead of system-installed libs
|
||||
include_directories(BEFORE ${PROJECT_SOURCE_DIR})
|
||||
include_directories(BEFORE ${PROJECT_SOURCE_DIR}/simgear/canvas/ShivaVG/include)
|
||||
include_directories(BEFORE ${PROJECT_BINARY_DIR}/simgear)
|
||||
|
||||
include_directories(${OPENSCENEGRAPH_INCLUDE_DIRS}
|
||||
${Boost_INCLUDE_DIRS}
|
||||
${ZLIB_INCLUDE_DIR}
|
||||
include_directories(${OPENSCENEGRAPH_INCLUDE_DIRS}
|
||||
${Boost_INCLUDE_DIRS}
|
||||
${ZLIB_INCLUDE_DIR}
|
||||
${OPENAL_INCLUDE_DIR}
|
||||
${CURL_INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
add_definitions(-DHAVE_CONFIG_H)
|
||||
@@ -376,7 +409,8 @@ set(TEST_LIBS_INTERNAL_CORE
|
||||
${WINSOCK_LIBRARY}
|
||||
${RT_LIBRARY}
|
||||
${DL_LIBRARY}
|
||||
${COCOA_LIBRARY})
|
||||
${COCOA_LIBRARY}
|
||||
${CURL_LIBRARIES})
|
||||
set(TEST_LIBS SimGearCore ${TEST_LIBS_INTERNAL_CORE})
|
||||
|
||||
if(NOT SIMGEAR_HEADLESS)
|
||||
@@ -385,9 +419,45 @@ endif()
|
||||
|
||||
install (FILES ${PROJECT_BINARY_DIR}/simgear/simgear_config.h DESTINATION include/simgear/)
|
||||
|
||||
include_directories(3rdparty/utf8/source)
|
||||
|
||||
add_subdirectory(3rdparty)
|
||||
add_subdirectory(simgear)
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
### Export stuff, see https://cmake.org/cmake/help/v3.2/manual/cmake-packages.7.html#creating-packages
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
generate_export_header(SimGearCore)
|
||||
if(NOT SIMGEAR_HEADLESS)
|
||||
generate_export_header(SimGearScene)
|
||||
endif()
|
||||
|
||||
include(CMakePackageConfigHelpers)
|
||||
|
||||
write_basic_package_version_file(
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/SimGear/SimGearConfigVersion.cmake"
|
||||
VERSION ${SIMGEAR_VERSION}
|
||||
COMPATIBILITY AnyNewerVersion
|
||||
)
|
||||
|
||||
configure_file(SimGearConfig.cmake.in
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/SimGear/SimGearConfig.cmake"
|
||||
@ONLY
|
||||
)
|
||||
|
||||
set(ConfigPackageLocation lib/cmake/SimGear)
|
||||
install(EXPORT SimGearTargets
|
||||
DESTINATION ${ConfigPackageLocation}
|
||||
)
|
||||
install(
|
||||
FILES
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/SimGear/SimGearConfig.cmake"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/SimGear/SimGearConfigVersion.cmake"
|
||||
DESTINATION ${ConfigPackageLocation}
|
||||
COMPONENT Devel
|
||||
)
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
### uninstall target
|
||||
#-----------------------------------------------------------------------------
|
||||
@@ -397,5 +467,3 @@ CONFIGURE_FILE(
|
||||
IMMEDIATE @ONLY)
|
||||
ADD_CUSTOM_TARGET(uninstall
|
||||
"${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake")
|
||||
|
||||
|
||||
|
||||
@@ -51,15 +51,15 @@ if("${Boost_VERSION}0" LESS "1034000")
|
||||
"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)
|
||||
if(ENABLE_TESTS)
|
||||
message(FATAL_ERROR
|
||||
${_shared_msg}
|
||||
"You may disable BUILD_TESTING to continue without the "
|
||||
"You may disable ENABLE_TESTS to continue without the "
|
||||
"tests.")
|
||||
else()
|
||||
message(STATUS
|
||||
${_shared_msg}
|
||||
"BUILD_TESTING disabled, so continuing anyway.")
|
||||
"ENABLE_TESTS disabled, so continuing anyway.")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
@@ -88,7 +88,7 @@ if(Boost_FOUND AND NOT "${Boost_VERSION}0" LESS "1034000")
|
||||
endif()
|
||||
|
||||
function(add_boost_test _name)
|
||||
if(NOT BUILD_TESTING)
|
||||
if(NOT ENABLE_TESTS)
|
||||
return()
|
||||
endif()
|
||||
|
||||
|
||||
@@ -1,182 +0,0 @@
|
||||
# - Define GNU standard installation directories
|
||||
# Provides install directory variables as defined for GNU software:
|
||||
# http://www.gnu.org/prep/standards/html_node/Directory-Variables.html
|
||||
# Inclusion of this module defines the following variables:
|
||||
# CMAKE_INSTALL_<dir> - destination for files of a given type
|
||||
# CMAKE_INSTALL_FULL_<dir> - corresponding absolute path
|
||||
# where <dir> is one of:
|
||||
# BINDIR - user executables (bin)
|
||||
# SBINDIR - system admin executables (sbin)
|
||||
# LIBEXECDIR - program executables (libexec)
|
||||
# SYSCONFDIR - read-only single-machine data (etc)
|
||||
# SHAREDSTATEDIR - modifiable architecture-independent data (com)
|
||||
# LOCALSTATEDIR - modifiable single-machine data (var)
|
||||
# LIBDIR - object code libraries (lib or lib64)
|
||||
# INCLUDEDIR - C header files (include)
|
||||
# OLDINCLUDEDIR - C header files for non-gcc (/usr/include)
|
||||
# DATAROOTDIR - read-only architecture-independent data root (share)
|
||||
# DATADIR - read-only architecture-independent data (DATAROOTDIR)
|
||||
# INFODIR - info documentation (DATAROOTDIR/info)
|
||||
# LOCALEDIR - locale-dependent data (DATAROOTDIR/locale)
|
||||
# MANDIR - man documentation (DATAROOTDIR/man)
|
||||
# DOCDIR - documentation root (DATAROOTDIR/doc/PROJECT_NAME)
|
||||
# Each CMAKE_INSTALL_<dir> value may be passed to the DESTINATION options of
|
||||
# install() commands for the corresponding file type. If the includer does
|
||||
# not define a value the above-shown default will be used and the value will
|
||||
# appear in the cache for editing by the user.
|
||||
# Each CMAKE_INSTALL_FULL_<dir> value contains an absolute path constructed
|
||||
# from the corresponding destination by prepending (if necessary) the value
|
||||
# of CMAKE_INSTALL_PREFIX.
|
||||
|
||||
#=============================================================================
|
||||
# Copyright 2011 Nikita Krupen'ko <krnekit@gmail.com>
|
||||
# Copyright 2011 Kitware, Inc.
|
||||
#
|
||||
# Distributed under the OSI-approved BSD License (the "License");
|
||||
# see accompanying file Copyright.txt for details.
|
||||
#
|
||||
# This software is distributed WITHOUT ANY WARRANTY; without even the
|
||||
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
# See the License for more information.
|
||||
#=============================================================================
|
||||
# (To distribute this file outside of CMake, substitute the full
|
||||
# License text for the above reference.)
|
||||
|
||||
# Installation directories
|
||||
#
|
||||
if(NOT DEFINED CMAKE_INSTALL_BINDIR)
|
||||
set(CMAKE_INSTALL_BINDIR "bin" CACHE PATH "user executables (bin)")
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED CMAKE_INSTALL_SBINDIR)
|
||||
set(CMAKE_INSTALL_SBINDIR "sbin" CACHE PATH "system admin executables (sbin)")
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED CMAKE_INSTALL_LIBEXECDIR)
|
||||
set(CMAKE_INSTALL_LIBEXECDIR "libexec" CACHE PATH "program executables (libexec)")
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED CMAKE_INSTALL_SYSCONFDIR)
|
||||
set(CMAKE_INSTALL_SYSCONFDIR "etc" CACHE PATH "read-only single-machine data (etc)")
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED CMAKE_INSTALL_SHAREDSTATEDIR)
|
||||
set(CMAKE_INSTALL_SHAREDSTATEDIR "com" CACHE PATH "modifiable architecture-independent data (com)")
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED CMAKE_INSTALL_LOCALSTATEDIR)
|
||||
set(CMAKE_INSTALL_LOCALSTATEDIR "var" CACHE PATH "modifiable single-machine data (var)")
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED CMAKE_INSTALL_LIBDIR)
|
||||
set(_LIBDIR_DEFAULT "lib")
|
||||
# Override this default 'lib' with 'lib64' iff:
|
||||
# - we are on Linux system but NOT cross-compiling
|
||||
# - we are NOT on debian
|
||||
# - we are on a 64 bits system
|
||||
# reason is: amd64 ABI: http://www.x86-64.org/documentation/abi.pdf
|
||||
# Note that the future of multi-arch handling may be even
|
||||
# more complicated than that: http://wiki.debian.org/Multiarch
|
||||
if(CMAKE_SYSTEM_NAME MATCHES "Linux"
|
||||
AND NOT CMAKE_CROSSCOMPILING
|
||||
AND NOT EXISTS "/etc/debian_version")
|
||||
if(NOT DEFINED CMAKE_SIZEOF_VOID_P)
|
||||
message(AUTHOR_WARNING
|
||||
"Unable to determine default CMAKE_INSTALL_LIBDIR directory because no target architecture is known. "
|
||||
"Please enable at least one language before including GNUInstallDirs.")
|
||||
else()
|
||||
if("${CMAKE_SIZEOF_VOID_P}" EQUAL "8")
|
||||
set(_LIBDIR_DEFAULT "lib64")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
set(CMAKE_INSTALL_LIBDIR "${_LIBDIR_DEFAULT}" CACHE PATH "object code libraries (${_LIBDIR_DEFAULT})")
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED CMAKE_INSTALL_INCLUDEDIR)
|
||||
set(CMAKE_INSTALL_INCLUDEDIR "include" CACHE PATH "C header files (include)")
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED CMAKE_INSTALL_OLDINCLUDEDIR)
|
||||
set(CMAKE_INSTALL_OLDINCLUDEDIR "/usr/include" CACHE PATH "C header files for non-gcc (/usr/include)")
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED CMAKE_INSTALL_DATAROOTDIR)
|
||||
set(CMAKE_INSTALL_DATAROOTDIR "share" CACHE PATH "read-only architecture-independent data root (share)")
|
||||
endif()
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# Values whose defaults are relative to DATAROOTDIR. Store empty values in
|
||||
# the cache and store the defaults in local variables if the cache values are
|
||||
# not set explicitly. This auto-updates the defaults as DATAROOTDIR changes.
|
||||
|
||||
if(NOT CMAKE_INSTALL_DATADIR)
|
||||
set(CMAKE_INSTALL_DATADIR "" CACHE PATH "read-only architecture-independent data (DATAROOTDIR)")
|
||||
set(CMAKE_INSTALL_DATADIR "${CMAKE_INSTALL_DATAROOTDIR}")
|
||||
endif()
|
||||
|
||||
if(NOT CMAKE_INSTALL_INFODIR)
|
||||
set(CMAKE_INSTALL_INFODIR "" CACHE PATH "info documentation (DATAROOTDIR/info)")
|
||||
set(CMAKE_INSTALL_INFODIR "${CMAKE_INSTALL_DATAROOTDIR}/info")
|
||||
endif()
|
||||
|
||||
if(NOT CMAKE_INSTALL_LOCALEDIR)
|
||||
set(CMAKE_INSTALL_LOCALEDIR "" CACHE PATH "locale-dependent data (DATAROOTDIR/locale)")
|
||||
set(CMAKE_INSTALL_LOCALEDIR "${CMAKE_INSTALL_DATAROOTDIR}/locale")
|
||||
endif()
|
||||
|
||||
if(NOT CMAKE_INSTALL_MANDIR)
|
||||
set(CMAKE_INSTALL_MANDIR "" CACHE PATH "man documentation (DATAROOTDIR/man)")
|
||||
set(CMAKE_INSTALL_MANDIR "${CMAKE_INSTALL_DATAROOTDIR}/man")
|
||||
endif()
|
||||
|
||||
if(NOT CMAKE_INSTALL_DOCDIR)
|
||||
set(CMAKE_INSTALL_DOCDIR "" CACHE PATH "documentation root (DATAROOTDIR/doc/PROJECT_NAME)")
|
||||
set(CMAKE_INSTALL_DOCDIR "${CMAKE_INSTALL_DATAROOTDIR}/doc/${PROJECT_NAME}")
|
||||
endif()
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
mark_as_advanced(
|
||||
CMAKE_INSTALL_BINDIR
|
||||
CMAKE_INSTALL_SBINDIR
|
||||
CMAKE_INSTALL_LIBEXECDIR
|
||||
CMAKE_INSTALL_SYSCONFDIR
|
||||
CMAKE_INSTALL_SHAREDSTATEDIR
|
||||
CMAKE_INSTALL_LOCALSTATEDIR
|
||||
CMAKE_INSTALL_LIBDIR
|
||||
CMAKE_INSTALL_INCLUDEDIR
|
||||
CMAKE_INSTALL_OLDINCLUDEDIR
|
||||
CMAKE_INSTALL_DATAROOTDIR
|
||||
CMAKE_INSTALL_DATADIR
|
||||
CMAKE_INSTALL_INFODIR
|
||||
CMAKE_INSTALL_LOCALEDIR
|
||||
CMAKE_INSTALL_MANDIR
|
||||
CMAKE_INSTALL_DOCDIR
|
||||
)
|
||||
|
||||
# Result directories
|
||||
#
|
||||
foreach(dir
|
||||
BINDIR
|
||||
SBINDIR
|
||||
LIBEXECDIR
|
||||
SYSCONFDIR
|
||||
SHAREDSTATEDIR
|
||||
LOCALSTATEDIR
|
||||
LIBDIR
|
||||
INCLUDEDIR
|
||||
OLDINCLUDEDIR
|
||||
DATAROOTDIR
|
||||
DATADIR
|
||||
INFODIR
|
||||
LOCALEDIR
|
||||
MANDIR
|
||||
DOCDIR
|
||||
)
|
||||
if(NOT IS_ABSOLUTE ${CMAKE_INSTALL_${dir}})
|
||||
set(CMAKE_INSTALL_FULL_${dir} "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_${dir}}")
|
||||
else()
|
||||
set(CMAKE_INSTALL_FULL_${dir} "${CMAKE_INSTALL_${dir}}")
|
||||
endif()
|
||||
endforeach()
|
||||
31
Doxyfile
31
Doxyfile
@@ -38,7 +38,7 @@ PROJECT_NAME = SimGear
|
||||
# could be handy for archiving the generated documentation or if some version
|
||||
# control system is used.
|
||||
|
||||
PROJECT_NUMBER = 2.11.0
|
||||
PROJECT_NUMBER = 3.3.0
|
||||
|
||||
# Using the PROJECT_BRIEF tag one can provide an optional one line description
|
||||
# for a project that appears at the top of each page and should give viewer a
|
||||
@@ -744,30 +744,7 @@ WARN_LOGFILE =
|
||||
# Note: If this tag is empty the current directory is searched.
|
||||
|
||||
INPUT = DoxygenMain.cxx \
|
||||
simgear/bucket \
|
||||
simgear/canvas \
|
||||
simgear/compiler.h \
|
||||
simgear/constants.h \
|
||||
simgear/debug \
|
||||
simgear/environment \
|
||||
simgear/ephemeris \
|
||||
simgear/io \
|
||||
simgear/magvar \
|
||||
simgear/math \
|
||||
simgear/misc \
|
||||
simgear/nasal \
|
||||
simgear/props \
|
||||
simgear/route \
|
||||
simgear/scene \
|
||||
simgear/screen \
|
||||
simgear/serial \
|
||||
simgear/structure \
|
||||
simgear/sg_inlines.h \
|
||||
simgear/sg_traits.hxx \
|
||||
simgear/sound \
|
||||
simgear/threads \
|
||||
simgear/timing \
|
||||
simgear/xml
|
||||
simgear
|
||||
|
||||
# This tag can be used to specify the character encoding of the source files
|
||||
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
|
||||
@@ -1568,7 +1545,7 @@ EXTRA_SEARCH_MAPPINGS =
|
||||
# If the GENERATE_LATEX tag is set to YES doxygen will generate LaTeX output.
|
||||
# The default value is: YES.
|
||||
|
||||
GENERATE_LATEX = YES
|
||||
GENERATE_LATEX = NO
|
||||
|
||||
# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
|
||||
# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
|
||||
@@ -1923,7 +1900,7 @@ ENABLE_PREPROCESSING = YES
|
||||
# The default value is: NO.
|
||||
# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
|
||||
|
||||
MACRO_EXPANSION = NO
|
||||
MACRO_EXPANSION = YES
|
||||
|
||||
# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
|
||||
# the macro expansion is limited to the macros specified with the PREDEFINED and
|
||||
|
||||
16
SimGearConfig.cmake.in
Normal file
16
SimGearConfig.cmake.in
Normal file
@@ -0,0 +1,16 @@
|
||||
include(CMakeFindDependencyMacro)
|
||||
|
||||
find_dependency(ZLIB)
|
||||
find_dependency(Threads)
|
||||
|
||||
# OSG
|
||||
|
||||
set(SIMGEAR_HEADLESS @SIMGEAR_HEADLESS@)
|
||||
set(SIMGEAR_SOUND @ENABLE_SOUND@)
|
||||
|
||||
# OpenAL isn't a public dependency, so maybe not needed
|
||||
#if (SIMGEAR_SOUND)
|
||||
# find_dependency(OpenAL)
|
||||
#endif()
|
||||
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/SimGearTargets.cmake")
|
||||
@@ -1,7 +1,7 @@
|
||||
|
||||
file(WRITE ${PROJECT_BINARY_DIR}/simgear/version.h "#define SIMGEAR_VERSION ${SIMGEAR_VERSION}")
|
||||
|
||||
foreach( mylibfolder
|
||||
foreach( mylibfolder
|
||||
bucket
|
||||
bvh
|
||||
debug
|
||||
@@ -54,9 +54,11 @@ if(SIMGEAR_SHARED)
|
||||
set_property(TARGET SimGearCore PROPERTY LINKER_LANGUAGE CXX)
|
||||
set_property(TARGET SimGearCore PROPERTY VERSION ${SIMGEAR_VERSION})
|
||||
set_property(TARGET SimGearCore PROPERTY SOVERSION ${SIMGEAR_SOVERSION})
|
||||
install(TARGETS SimGearCore EXPORT SimGearCoreConfig LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR})
|
||||
install(EXPORT SimGearCoreConfig DESTINATION share/SimGearCore)
|
||||
|
||||
install(TARGETS SimGearCore
|
||||
EXPORT SimGearTargets
|
||||
LIBRARY DESTINATION
|
||||
${CMAKE_INSTALL_LIBDIR})
|
||||
|
||||
if(NOT SIMGEAR_HEADLESS)
|
||||
add_library(SimGearScene SHARED ${sceneSources})
|
||||
set_property(TARGET SimGearScene PROPERTY LINKER_LANGUAGE CXX)
|
||||
@@ -64,10 +66,12 @@ if(SIMGEAR_SHARED)
|
||||
set_property(TARGET SimGearScene PROPERTY SOVERSION ${SIMGEAR_SOVERSION})
|
||||
|
||||
# EXPORT SimGearSceneConfig
|
||||
install(TARGETS SimGearScene LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} )
|
||||
# install(EXPORT SimGearSceneConfig DESTINATION share/SimGearScene)
|
||||
install(TARGETS SimGearScene
|
||||
EXPORT SimGearTargets
|
||||
LIBRARY
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR} )
|
||||
endif()
|
||||
|
||||
|
||||
else()
|
||||
message(STATUS "Library building mode: STATIC LIBRARIES")
|
||||
|
||||
@@ -90,8 +94,10 @@ else()
|
||||
endforeach()
|
||||
|
||||
add_library(SimGearCore STATIC ${coreSources} ${localExpatSources})
|
||||
install(TARGETS SimGearCore ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
|
||||
|
||||
install(TARGETS SimGearCore
|
||||
EXPORT SimGearTargets
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
|
||||
|
||||
if(NOT SIMGEAR_HEADLESS)
|
||||
get_property(FG_GROUPS_SCENE_SOURCES_C GLOBAL PROPERTY FG_GROUPS_SCENE_SOURCES_C)
|
||||
string(REPLACE "@" ";" groups ${FG_GROUPS_SCENE_SOURCES_C} )
|
||||
@@ -112,7 +118,9 @@ else()
|
||||
endforeach()
|
||||
|
||||
add_library(SimGearScene STATIC ${sceneSources})
|
||||
install(TARGETS SimGearScene ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
|
||||
install(TARGETS SimGearScene
|
||||
EXPORT SimGearTargets
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
|
||||
endif(NOT SIMGEAR_HEADLESS)
|
||||
endif(SIMGEAR_SHARED)
|
||||
|
||||
@@ -122,7 +130,8 @@ target_link_libraries(SimGearCore
|
||||
${DL_LIBRARY}
|
||||
${EXPAT_LIBRARIES}
|
||||
${CMAKE_THREAD_LIBS_INIT}
|
||||
${COCOA_LIBRARY})
|
||||
${COCOA_LIBRARY}
|
||||
${CURL_LIBRARIES})
|
||||
|
||||
if(NOT SIMGEAR_HEADLESS)
|
||||
target_link_libraries(SimGearScene
|
||||
|
||||
@@ -127,21 +127,22 @@ public:
|
||||
|
||||
/**
|
||||
* Construct a bucket given a specific location.
|
||||
* @param dlon longitude specified in degrees
|
||||
* @param dlat latitude specified in degrees
|
||||
*
|
||||
* @param geod Geodetic location
|
||||
*/
|
||||
SGBucket(const SGGeod& geod);
|
||||
|
||||
/** Construct a bucket given a unique bucket index number.
|
||||
*
|
||||
* @param bindex unique bucket index
|
||||
*/
|
||||
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
|
||||
* Reset a bucket to represent a new location.
|
||||
*
|
||||
* @param geod New geodetic location
|
||||
*/
|
||||
void set_bucket(const SGGeod& geod);
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ public:
|
||||
void removeChild(BVHNode* child);
|
||||
|
||||
unsigned getNumChildren() const
|
||||
{ return _children.size(); }
|
||||
{ return static_cast<unsigned>(_children.size()); }
|
||||
const BVHNode* getChild(unsigned i) const
|
||||
{ if (_children.size() <= i) return 0; return _children[i]; }
|
||||
BVHNode* getChild(unsigned i)
|
||||
|
||||
@@ -31,13 +31,13 @@ public:
|
||||
virtual ~BVHStaticData() {}
|
||||
|
||||
unsigned addVertex(const SGVec3f& vertex)
|
||||
{ _vertices.push_back(vertex); return _vertices.size() - 1; }
|
||||
{ _vertices.push_back(vertex); return static_cast<unsigned>(_vertices.size() - 1); }
|
||||
const SGVec3f& getVertex(unsigned i) const
|
||||
{ return _vertices[i]; }
|
||||
|
||||
|
||||
unsigned addMaterial(const BVHMaterial* material)
|
||||
{ _materials.push_back(material); return _materials.size() - 1; }
|
||||
{ _materials.push_back(material); return static_cast<unsigned>(_materials.size() - 1); }
|
||||
const BVHMaterial* getMaterial(unsigned i) const
|
||||
{ if (_materials.size() <= i) return 0; return _materials[i]; }
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "CanvasEventManager.hxx"
|
||||
#include "CanvasEventVisitor.hxx"
|
||||
#include "CanvasPlacement.hxx"
|
||||
#include <simgear/canvas/events/KeyboardEvent.hxx>
|
||||
#include <simgear/canvas/events/MouseEvent.hxx>
|
||||
#include <simgear/scene/util/parse_color.hxx>
|
||||
#include <simgear/scene/util/RenderConstants.hxx>
|
||||
@@ -196,7 +197,25 @@ namespace canvas
|
||||
{
|
||||
_layout = layout;
|
||||
_layout->setCanvas(this);
|
||||
_status |= LAYOUT_DIRTY;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Canvas::setFocusElement(const ElementPtr& el)
|
||||
{
|
||||
if( el && el->getCanvas().lock() != this )
|
||||
{
|
||||
SG_LOG(SG_GUI, SG_WARN, "setFocusElement: element not from this canvas");
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO focus out/in events
|
||||
_focus_element = el;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Canvas::clearFocusElement()
|
||||
{
|
||||
_focus_element.reset();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
@@ -256,15 +275,7 @@ namespace canvas
|
||||
}
|
||||
|
||||
if( _layout )
|
||||
{
|
||||
if( (_status & LAYOUT_DIRTY) )
|
||||
{
|
||||
_layout->setGeometry(SGRecti(0, 0, _view_width, _view_height));
|
||||
_status &= ~LAYOUT_DIRTY;
|
||||
}
|
||||
else
|
||||
_layout->update();
|
||||
}
|
||||
_layout->setGeometry(SGRecti(0, 0, _view_width, _view_height));
|
||||
|
||||
if( _visible || _render_always )
|
||||
{
|
||||
@@ -410,7 +421,6 @@ namespace canvas
|
||||
if( _view_width == w )
|
||||
return;
|
||||
_view_width = w;
|
||||
_status |= LAYOUT_DIRTY;
|
||||
|
||||
_texture.setViewSize(_view_width, _view_height);
|
||||
}
|
||||
@@ -421,7 +431,6 @@ namespace canvas
|
||||
if( _view_height == h )
|
||||
return;
|
||||
_view_height = h;
|
||||
_status |= LAYOUT_DIRTY;
|
||||
|
||||
_texture.setViewSize(_view_width, _view_height);
|
||||
}
|
||||
@@ -459,6 +468,18 @@ namespace canvas
|
||||
return _event_manager->handleEvent(event, visitor.getPropagationPath());
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
bool Canvas::handleKeyboardEvent(const KeyboardEventPtr& event)
|
||||
{
|
||||
ElementPtr target = _focus_element.lock();
|
||||
if( !target )
|
||||
target = _root_group;
|
||||
if( !target )
|
||||
return false;
|
||||
|
||||
return target->dispatchEvent(event);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
bool Canvas::propagateEvent( EventPtr const& event,
|
||||
EventPropagationPath const& path )
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
///@file The canvas for rendering with the 2d API
|
||||
///@file
|
||||
/// The canvas for rendering with the 2d API
|
||||
//
|
||||
// Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com>
|
||||
//
|
||||
@@ -43,6 +44,9 @@ namespace canvas
|
||||
class CanvasMgr;
|
||||
class MouseEvent;
|
||||
|
||||
/**
|
||||
* Canvas to draw onto (to an off-screen render target).
|
||||
*/
|
||||
class Canvas:
|
||||
public PropertyBasedElement,
|
||||
public nasal::Object
|
||||
@@ -53,8 +57,7 @@ namespace canvas
|
||||
{
|
||||
STATUS_OK,
|
||||
STATUS_DIRTY = 1,
|
||||
LAYOUT_DIRTY = STATUS_DIRTY << 1,
|
||||
MISSING_SIZE_X = LAYOUT_DIRTY << 1,
|
||||
MISSING_SIZE_X = STATUS_DIRTY << 1,
|
||||
MISSING_SIZE_Y = MISSING_SIZE_X << 1,
|
||||
MISSING_SIZE = MISSING_SIZE_X | MISSING_SIZE_Y,
|
||||
CREATE_FAILED = MISSING_SIZE_Y << 1
|
||||
@@ -133,6 +136,22 @@ namespace canvas
|
||||
*/
|
||||
void setLayout(const LayoutRef& layout);
|
||||
|
||||
/**
|
||||
* Set the focus to the given element.
|
||||
*
|
||||
* The focus element will receive all keyboard events propagated to this
|
||||
* canvas. If there is no valid focus element the root group will receive
|
||||
* the events instead.
|
||||
*/
|
||||
void setFocusElement(const ElementPtr& el);
|
||||
|
||||
/**
|
||||
* Clear the focus element.
|
||||
*
|
||||
* @see setFocusElement()
|
||||
*/
|
||||
void clearFocusElement();
|
||||
|
||||
/**
|
||||
* Enable rendering for the next frame
|
||||
*
|
||||
@@ -160,6 +179,8 @@ namespace canvas
|
||||
SGRect<int> getViewport() const;
|
||||
|
||||
bool handleMouseEvent(const MouseEventPtr& event);
|
||||
bool handleKeyboardEvent(const KeyboardEventPtr& event);
|
||||
|
||||
bool propagateEvent( EventPtr const& event,
|
||||
EventPropagationPath const& path );
|
||||
|
||||
@@ -211,13 +232,15 @@ namespace canvas
|
||||
GroupPtr _root_group;
|
||||
LayoutRef _layout;
|
||||
|
||||
ElementWeakPtr _focus_element;
|
||||
|
||||
CullCallbackPtr _cull_callback;
|
||||
bool _render_always; //<! Used to disable automatic lazy rendering (culling)
|
||||
bool _render_always; //!< Used to disable automatic lazy rendering (culling)
|
||||
|
||||
std::vector<SGPropertyNode*> _dirty_placements;
|
||||
std::vector<Placements> _placements;
|
||||
std::set<CanvasWeakPtr> _parent_canvases, //<! Canvases showing this canvas
|
||||
_child_canvases; //<! Canvases displayed within
|
||||
std::set<CanvasWeakPtr> _parent_canvases, //!< Canvases showing this canvas
|
||||
_child_canvases; //!< Canvases displayed within
|
||||
// this canvas
|
||||
|
||||
typedef std::map<std::string, PlacementFactory> PlacementFactoryMap;
|
||||
|
||||
@@ -27,7 +27,8 @@ namespace canvas
|
||||
Event::Event():
|
||||
type(UNKNOWN),
|
||||
time(-1),
|
||||
propagation_stopped(false)
|
||||
propagation_stopped(false),
|
||||
default_prevented(false)
|
||||
{
|
||||
|
||||
}
|
||||
@@ -80,6 +81,18 @@ namespace canvas
|
||||
propagation_stopped = true;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Event::preventDefault()
|
||||
{
|
||||
default_prevented = true;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
bool Event::defaultPrevented() const
|
||||
{
|
||||
return default_prevented;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
int Event::getOrRegisterType(const std::string& type_str)
|
||||
{
|
||||
@@ -125,7 +138,7 @@ namespace canvas
|
||||
|
||||
if( type_map.empty() )
|
||||
{
|
||||
# define ENUM_MAPPING(type, str)\
|
||||
# define ENUM_MAPPING(type, str, class_name)\
|
||||
type_map.insert(TypeMap::value_type(str, type));
|
||||
# include "CanvasEventTypes.hxx"
|
||||
# undef ENUM_MAPPING
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
// Canvas Event for event model similar to DOM Level 3 Event Model
|
||||
/// @file
|
||||
/// Canvas Event for event model similar to DOM Level 3 Event Model
|
||||
//
|
||||
// Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com>
|
||||
//
|
||||
@@ -27,26 +28,36 @@ namespace simgear
|
||||
namespace canvas
|
||||
{
|
||||
|
||||
/**
|
||||
* Base class for all Canvas events.
|
||||
*
|
||||
* The event system is closely following the specification of the DOM Level 3
|
||||
* Event Model.
|
||||
*/
|
||||
class Event:
|
||||
public SGReferenced
|
||||
{
|
||||
public:
|
||||
|
||||
/// Event type identifier
|
||||
enum Type
|
||||
{
|
||||
UNKNOWN,
|
||||
# define ENUM_MAPPING(name, str) name,
|
||||
# define ENUM_MAPPING(name, str, class_name)\
|
||||
name, /*!< class_name (type=str) */
|
||||
# include "CanvasEventTypes.hxx"
|
||||
# undef ENUM_MAPPING
|
||||
CUSTOM_EVENT ///< all user defined event types share the same id. They
|
||||
/// are just differentiated by using the type string.
|
||||
CUSTOM_EVENT ///< First event type id available for user defined event
|
||||
/// type.
|
||||
/// @see CustomEvent
|
||||
};
|
||||
|
||||
int type;
|
||||
ElementWeakPtr target,
|
||||
current_target;
|
||||
double time;
|
||||
bool propagation_stopped;
|
||||
bool propagation_stopped,
|
||||
default_prevented;
|
||||
|
||||
Event();
|
||||
|
||||
@@ -72,10 +83,33 @@ namespace canvas
|
||||
ElementWeakPtr getTarget() const;
|
||||
ElementWeakPtr getCurrentTarget() const;
|
||||
|
||||
/**
|
||||
* Get time at which the event was generated.
|
||||
*/
|
||||
double getTime() const;
|
||||
|
||||
/**
|
||||
* Prevent further propagation of the event during event flow.
|
||||
*
|
||||
* @note This does not prevent calling further event handlers registered
|
||||
* on the current event target.
|
||||
*/
|
||||
void stopPropagation();
|
||||
|
||||
/**
|
||||
* Cancel any default action normally taken as result of this event.
|
||||
*
|
||||
* @note For event handlers registered on the DesktopGroup (Nasal:
|
||||
* canvas.getDesktop()) this stops the event from being further
|
||||
* propagated to the normal FlightGear input event handling code.
|
||||
*/
|
||||
void preventDefault();
|
||||
|
||||
/**
|
||||
* Get if preventDefault() has been called.
|
||||
*/
|
||||
bool defaultPrevented() const;
|
||||
|
||||
static int getOrRegisterType(const std::string& type);
|
||||
static int strToType(const std::string& type);
|
||||
static std::string typeToStr(int type);
|
||||
|
||||
@@ -20,14 +20,17 @@
|
||||
# error "Don't include this file directly!"
|
||||
#endif
|
||||
|
||||
ENUM_MAPPING(MOUSE_DOWN, "mousedown")
|
||||
ENUM_MAPPING(MOUSE_UP, "mouseup")
|
||||
ENUM_MAPPING(CLICK, "click")
|
||||
ENUM_MAPPING(DBL_CLICK, "dblclick")
|
||||
ENUM_MAPPING(DRAG, "drag")
|
||||
ENUM_MAPPING(WHEEL, "wheel")
|
||||
ENUM_MAPPING(MOUSE_MOVE, "mousemove")
|
||||
ENUM_MAPPING(MOUSE_OVER, "mouseover")
|
||||
ENUM_MAPPING(MOUSE_OUT, "mouseout")
|
||||
ENUM_MAPPING(MOUSE_ENTER, "mouseenter")
|
||||
ENUM_MAPPING(MOUSE_LEAVE, "mouseleave")
|
||||
ENUM_MAPPING(MOUSE_DOWN, "mousedown", MouseEvent)
|
||||
ENUM_MAPPING(MOUSE_UP, "mouseup", MouseEvent)
|
||||
ENUM_MAPPING(CLICK, "click", MouseEvent)
|
||||
ENUM_MAPPING(DBL_CLICK, "dblclick", MouseEvent)
|
||||
ENUM_MAPPING(DRAG, "drag", MouseEvent)
|
||||
ENUM_MAPPING(WHEEL, "wheel", MouseEvent)
|
||||
ENUM_MAPPING(MOUSE_MOVE, "mousemove", MouseEvent)
|
||||
ENUM_MAPPING(MOUSE_OVER, "mouseover", MouseEvent)
|
||||
ENUM_MAPPING(MOUSE_OUT, "mouseout", MouseEvent)
|
||||
ENUM_MAPPING(MOUSE_ENTER, "mouseenter", MouseEvent)
|
||||
ENUM_MAPPING(MOUSE_LEAVE, "mouseleave", MouseEvent)
|
||||
ENUM_MAPPING(KEY_DOWN, "keydown", KeyboardEvent)
|
||||
ENUM_MAPPING(KEY_UP, "keyup", KeyboardEvent)
|
||||
ENUM_MAPPING(KEY_PRESS, "keypress", KeyboardEvent)
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
///@file Placement for putting a canvas texture onto OpenSceneGraph objects.
|
||||
//
|
||||
// It also provides a SGPickCallback for passing mouse events to the canvas and
|
||||
// manages emissive lighting of the placed canvas.
|
||||
///@file
|
||||
/// Placement for putting a canvas texture onto OpenSceneGraph objects.
|
||||
///
|
||||
/// It also provides a SGPickCallback for passing mouse events to the canvas and
|
||||
/// manages emissive lighting of the placed canvas.
|
||||
//
|
||||
// Copyright (C) 2013 Thomas Geymayer <tomgey@gmail.com>
|
||||
//
|
||||
|
||||
@@ -172,6 +172,19 @@ namespace canvas
|
||||
return _capture_events;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Window::setVisible(bool visible)
|
||||
{
|
||||
LayoutItem::setVisible(visible);
|
||||
Element::setVisible(LayoutItem::isVisible());
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
bool Window::isVisible() const
|
||||
{
|
||||
return Element::isVisible();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Window::raise()
|
||||
{
|
||||
@@ -267,6 +280,9 @@ namespace canvas
|
||||
->createChild<Image>("content");
|
||||
_image_content->setSrcCanvas(content);
|
||||
|
||||
// Forward keyboard events to content
|
||||
_image_content->setFocus();
|
||||
|
||||
// Draw content on top of decoration
|
||||
_image_content->set<int>("z-index", 1);
|
||||
}
|
||||
|
||||
@@ -84,6 +84,9 @@ namespace canvas
|
||||
bool isResizable() const;
|
||||
bool isCapturingEvents() const;
|
||||
|
||||
virtual void setVisible(bool visible);
|
||||
virtual bool isVisible() const;
|
||||
|
||||
/**
|
||||
* Moves window on top of all other windows with the same z-index.
|
||||
*
|
||||
|
||||
@@ -44,6 +44,7 @@
|
||||
#include <osg/ShadeModel>
|
||||
#include <osg/StateSet>
|
||||
#include <osg/FrameBufferObject> // for GL_DEPTH_STENCIL_EXT on Windows
|
||||
#include <osg/Version>
|
||||
#include <osgUtil/RenderBin>
|
||||
|
||||
#include <cassert>
|
||||
@@ -266,7 +267,15 @@ namespace canvas
|
||||
//----------------------------------------------------------------------------
|
||||
void ODGauge::reinit()
|
||||
{
|
||||
osg::NodeCallback* cull_callback = camera ? camera->getCullCallback() : 0;
|
||||
osg::NodeCallback* cull_callback =
|
||||
camera
|
||||
#if OSG_VERSION_LESS_THAN(3,3,2)
|
||||
? camera->getCullCallback()
|
||||
#else
|
||||
? dynamic_cast<osg::NodeCallback*>(camera->getCullCallback())
|
||||
#endif
|
||||
: 0;
|
||||
|
||||
clear();
|
||||
allocRT(cull_callback);
|
||||
}
|
||||
|
||||
@@ -156,7 +156,7 @@ SHfloat getMaxFloat();
|
||||
|
||||
/* OpenGL headers */
|
||||
|
||||
#if defined(VG_API_LINUX)
|
||||
#if defined(VG_API_LINUX) || defined(VG_API_FREEBSD)
|
||||
#include <GL/gl.h>
|
||||
#include <GL/glx.h>
|
||||
#elif defined(VG_API_MACOSX)
|
||||
|
||||
@@ -53,6 +53,8 @@ namespace canvas
|
||||
|
||||
SG_FWD_DECL(Event)
|
||||
SG_FWD_DECL(CustomEvent)
|
||||
SG_FWD_DECL(DeviceEvent)
|
||||
SG_FWD_DECL(KeyboardEvent)
|
||||
SG_FWD_DECL(MouseEvent)
|
||||
|
||||
#undef SG_FWD_DECL
|
||||
|
||||
@@ -26,7 +26,8 @@
|
||||
|
||||
#include <osg/Drawable>
|
||||
#include <osg/Geode>
|
||||
#include <osg/Scissor>
|
||||
#include <osg/StateAttribute>
|
||||
#include <osg/Version>
|
||||
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
@@ -46,27 +47,34 @@ namespace canvas
|
||||
* glScissor with coordinates relative to different reference frames.
|
||||
*/
|
||||
class Element::RelativeScissor:
|
||||
public osg::Scissor
|
||||
public osg::StateAttribute
|
||||
{
|
||||
public:
|
||||
|
||||
ReferenceFrame _coord_reference;
|
||||
osg::observer_ptr<osg::Node> _node;
|
||||
|
||||
RelativeScissor(osg::Node* node = NULL):
|
||||
explicit RelativeScissor(osg::Node* node = NULL):
|
||||
_coord_reference(GLOBAL),
|
||||
_node(node)
|
||||
_node(node),
|
||||
_x(0),
|
||||
_y(0),
|
||||
_width(0),
|
||||
_height(0)
|
||||
{
|
||||
_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),
|
||||
StateAttribute(vp, copyop),
|
||||
_coord_reference(vp._coord_reference),
|
||||
_node(vp._node)
|
||||
_node(vp._node),
|
||||
_x(vp._x),
|
||||
_y(vp._y),
|
||||
_width(vp._width),
|
||||
_height(vp._height)
|
||||
{}
|
||||
|
||||
META_StateAttribute(simgear, RelativeScissor, SCISSOR);
|
||||
@@ -89,6 +97,24 @@ namespace canvas
|
||||
return 0; // passed all the above comparison macros, must be equal.
|
||||
}
|
||||
|
||||
virtual bool getModeUsage(StateAttribute::ModeUsage& usage) const
|
||||
{
|
||||
usage.usesMode(GL_SCISSOR_TEST);
|
||||
return true;
|
||||
}
|
||||
|
||||
inline float& x() { return _x; }
|
||||
inline float x() const { return _x; }
|
||||
|
||||
inline float& y() { return _y; }
|
||||
inline float y() const { return _y; }
|
||||
|
||||
inline float& width() { return _width; }
|
||||
inline float width() const { return _width; }
|
||||
|
||||
inline float& height() { return _height; }
|
||||
inline float height() const { return _height; }
|
||||
|
||||
virtual void apply(osg::State& state) const
|
||||
{
|
||||
if( _width <= 0 || _height <= 0 )
|
||||
@@ -163,6 +189,12 @@ namespace canvas
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected:
|
||||
float _x,
|
||||
_y,
|
||||
_width,
|
||||
_height;
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
@@ -175,19 +207,6 @@ namespace canvas
|
||||
//----------------------------------------------------------------------------
|
||||
Element::~Element()
|
||||
{
|
||||
if( !_transform.valid() )
|
||||
return;
|
||||
|
||||
for(unsigned int i = 0; i < _transform->getNumChildren(); ++i)
|
||||
{
|
||||
OSGUserData* ud =
|
||||
static_cast<OSGUserData*>(_transform->getChild(i)->getUserData());
|
||||
|
||||
if( ud )
|
||||
// Ensure parent is cleared to prevent accessing released memory if an
|
||||
// element somehow survives longer than his parent.
|
||||
ud->element->_parent = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
@@ -214,7 +233,7 @@ namespace canvas
|
||||
//----------------------------------------------------------------------------
|
||||
ElementPtr Element::getParent() const
|
||||
{
|
||||
return _parent;
|
||||
return _parent.lock();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
@@ -272,6 +291,14 @@ namespace canvas
|
||||
_listener.clear();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Element::setFocus()
|
||||
{
|
||||
CanvasPtr canvas = _canvas.lock();
|
||||
if( canvas )
|
||||
canvas->setFocusElement(this);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
bool Element::accept(EventVisitor& visitor)
|
||||
{
|
||||
@@ -284,8 +311,9 @@ namespace canvas
|
||||
//----------------------------------------------------------------------------
|
||||
bool Element::ascend(EventVisitor& visitor)
|
||||
{
|
||||
if( _parent )
|
||||
return _parent->accept(visitor);
|
||||
ElementPtr parent = getParent();
|
||||
if( parent )
|
||||
return parent->accept(visitor);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -295,6 +323,15 @@ namespace canvas
|
||||
return true;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
size_t Element::numEventHandler(int type) const
|
||||
{
|
||||
ListenerMap::const_iterator listeners = _listener.find(type);
|
||||
if( listeners != _listener.end() )
|
||||
return listeners->second.size();
|
||||
return 0;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
bool Element::handleEvent(const EventPtr& event)
|
||||
{
|
||||
@@ -325,9 +362,9 @@ namespace canvas
|
||||
EventPropagationPath path;
|
||||
path.push_back( EventTarget(this) );
|
||||
|
||||
for( Element* parent = _parent;
|
||||
parent != NULL;
|
||||
parent = parent->_parent )
|
||||
for( ElementPtr parent = getParent();
|
||||
parent.valid();
|
||||
parent = parent->getParent() )
|
||||
path.push_front( EventTarget(parent) );
|
||||
|
||||
CanvasPtr canvas = _canvas.lock();
|
||||
@@ -349,7 +386,13 @@ namespace canvas
|
||||
|
||||
// Drawables have a bounding box...
|
||||
if( _drawable )
|
||||
return _drawable->getBound().contains(osg::Vec3f(local_pos, 0));
|
||||
return _drawable->
|
||||
#if OSG_VERSION_LESS_THAN(3,3,2)
|
||||
getBound()
|
||||
#else
|
||||
getBoundingBox()
|
||||
#endif
|
||||
.contains(osg::Vec3f(local_pos, 0));
|
||||
else if( _transform.valid() )
|
||||
// ... for other elements, i.e. groups only a bounding sphere is available
|
||||
return _transform->getBound().contains(osg::Vec3f(parent_pos, 0));
|
||||
@@ -576,10 +619,10 @@ namespace canvas
|
||||
_scissor = new RelativeScissor(_transform.get());
|
||||
|
||||
// <top>, <right>, <bottom>, <left>
|
||||
_scissor->x() = SGMiscf::roundToInt(values[3]);
|
||||
_scissor->y() = SGMiscf::roundToInt(values[0]);
|
||||
_scissor->width() = SGMiscf::roundToInt(width);
|
||||
_scissor->height() = SGMiscf::roundToInt(height);
|
||||
_scissor->x() = values[3];
|
||||
_scissor->y() = values[0];
|
||||
_scissor->width() = width;
|
||||
_scissor->height() = height;
|
||||
|
||||
SGPropertyNode* clip_frame = _node->getChild("clip-frame", 0);
|
||||
if( clip_frame )
|
||||
@@ -601,7 +644,11 @@ namespace canvas
|
||||
osg::BoundingBox Element::getBoundingBox() const
|
||||
{
|
||||
if( _drawable )
|
||||
#if OSG_VERSION_LESS_THAN(3,3,2)
|
||||
return _drawable->getBound();
|
||||
#else
|
||||
return _drawable->getBoundingBox();
|
||||
#endif
|
||||
|
||||
osg::BoundingBox bb;
|
||||
|
||||
@@ -624,7 +671,13 @@ namespace canvas
|
||||
return osg::BoundingBox();
|
||||
|
||||
osg::BoundingBox transformed;
|
||||
const osg::BoundingBox& bb = _drawable->getBound();
|
||||
const osg::BoundingBox& bb =
|
||||
#if OSG_VERSION_LESS_THAN(3,3,2)
|
||||
_drawable->getBound();
|
||||
#else
|
||||
_drawable->getBoundingBox();
|
||||
#endif
|
||||
|
||||
for(int i = 0; i < 4; ++i)
|
||||
transformed.expandBy( bb.corner(i) * m );
|
||||
|
||||
@@ -707,7 +760,7 @@ namespace canvas
|
||||
Element::Element( const CanvasWeakPtr& canvas,
|
||||
const SGPropertyNode_ptr& node,
|
||||
const Style& parent_style,
|
||||
Element* parent ):
|
||||
ElementWeakPtr parent ):
|
||||
PropertyBasedElement(node),
|
||||
_canvas( canvas ),
|
||||
_parent( parent ),
|
||||
@@ -806,11 +859,12 @@ namespace canvas
|
||||
Element::getParentStyle(const SGPropertyNode* child) const
|
||||
{
|
||||
// Try to get value from parent...
|
||||
if( _parent )
|
||||
ElementPtr parent = getParent();
|
||||
if( parent )
|
||||
{
|
||||
Style::const_iterator style =
|
||||
_parent->_style.find(child->getNameString());
|
||||
if( style != _parent->_style.end() )
|
||||
parent->_style.find(child->getNameString());
|
||||
if( style != parent->_style.end() )
|
||||
return style->second;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
///@file Interface for 2D Canvas elements
|
||||
///@file
|
||||
/// Interface for 2D Canvas elements
|
||||
//
|
||||
// Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com>
|
||||
//
|
||||
@@ -42,7 +43,7 @@ namespace canvas
|
||||
{
|
||||
|
||||
/**
|
||||
* Baseclass for Elements displayed inside a Canvas.
|
||||
* Base class for Elements displayed inside a Canvas.
|
||||
*/
|
||||
class Element:
|
||||
public PropertyBasedElement
|
||||
@@ -108,10 +109,16 @@ namespace canvas
|
||||
bool addEventListener(const std::string& type, const EventListener& cb);
|
||||
virtual void clearEventListener();
|
||||
|
||||
/// Get (keyboard) input focus.
|
||||
void setFocus();
|
||||
|
||||
virtual bool accept(EventVisitor& visitor);
|
||||
virtual bool ascend(EventVisitor& visitor);
|
||||
virtual bool traverse(EventVisitor& visitor);
|
||||
|
||||
/// Get the number of event handlers for the given type
|
||||
size_t numEventHandler(int type) const;
|
||||
|
||||
virtual bool handleEvent(const EventPtr& event);
|
||||
bool dispatchEvent(const EventPtr& event);
|
||||
|
||||
@@ -128,12 +135,12 @@ namespace canvas
|
||||
/**
|
||||
* Set visibility of the element.
|
||||
*/
|
||||
void setVisible(bool visible);
|
||||
virtual void setVisible(bool visible);
|
||||
|
||||
/**
|
||||
* Get whether the element is visible or hidden.
|
||||
*/
|
||||
bool isVisible() const;
|
||||
virtual bool isVisible() const;
|
||||
|
||||
osg::MatrixTransform* getMatrixTransform();
|
||||
osg::MatrixTransform const* getMatrixTransform() const;
|
||||
@@ -225,8 +232,8 @@ namespace canvas
|
||||
|
||||
class RelativeScissor;
|
||||
|
||||
CanvasWeakPtr _canvas;
|
||||
Element *_parent;
|
||||
CanvasWeakPtr _canvas;
|
||||
ElementWeakPtr _parent;
|
||||
|
||||
mutable uint32_t _attributes_dirty;
|
||||
|
||||
@@ -249,7 +256,7 @@ namespace canvas
|
||||
Element( const CanvasWeakPtr& canvas,
|
||||
const SGPropertyNode_ptr& node,
|
||||
const Style& parent_style,
|
||||
Element* parent );
|
||||
ElementWeakPtr parent );
|
||||
|
||||
/**
|
||||
* Returns false on first call and true on any successive call. Use to
|
||||
@@ -272,9 +279,10 @@ namespace canvas
|
||||
/**
|
||||
* Register a function for setting a style specified by the given property
|
||||
*
|
||||
* @param name Property name
|
||||
* @param type Interpolation type
|
||||
* @param setter Setter function
|
||||
* @param name Property name
|
||||
* @param type Interpolation type
|
||||
* @param setter Setter function
|
||||
* @param inheritable If this style propagates to child elements
|
||||
*
|
||||
* @tparam T1 Type of value used to retrieve value from property
|
||||
* node
|
||||
@@ -556,7 +564,7 @@ namespace canvas
|
||||
/**
|
||||
* Get stateset of drawable if available or use transform otherwise
|
||||
*/
|
||||
osg::StateSet* getOrCreateStateSet();
|
||||
virtual osg::StateSet* getOrCreateStateSet();
|
||||
|
||||
void setupStyle();
|
||||
|
||||
|
||||
@@ -70,7 +70,7 @@ namespace canvas
|
||||
Group::Group( const CanvasWeakPtr& canvas,
|
||||
const SGPropertyNode_ptr& node,
|
||||
const Style& parent_style,
|
||||
Element* parent ):
|
||||
ElementWeakPtr parent ):
|
||||
Element(canvas, node, parent_style, parent)
|
||||
{
|
||||
staticInit();
|
||||
|
||||
@@ -45,7 +45,7 @@ namespace canvas
|
||||
Group( const CanvasWeakPtr& canvas,
|
||||
const SGPropertyNode_ptr& node,
|
||||
const Style& parent_style = Style(),
|
||||
Element* parent = 0 );
|
||||
ElementWeakPtr parent = 0 );
|
||||
virtual ~Group();
|
||||
|
||||
ElementPtr createChild( const std::string& type,
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include <simgear/canvas/Canvas.hxx>
|
||||
#include <simgear/canvas/CanvasMgr.hxx>
|
||||
#include <simgear/canvas/CanvasSystemAdapter.hxx>
|
||||
#include <simgear/canvas/events/KeyboardEvent.hxx>
|
||||
#include <simgear/canvas/events/MouseEvent.hxx>
|
||||
#include <simgear/scene/util/OsgMath.hxx>
|
||||
#include <simgear/scene/util/parse_color.hxx>
|
||||
@@ -30,6 +31,7 @@
|
||||
#include <osg/Geometry>
|
||||
#include <osg/PrimitiveSet>
|
||||
#include <osgDB/Registry>
|
||||
#include <osg/Version>
|
||||
|
||||
namespace simgear
|
||||
{
|
||||
@@ -100,13 +102,17 @@ namespace canvas
|
||||
addStyle("preserveAspectRatio", "", &Image::setPreserveAspectRatio);
|
||||
addStyle("slice", "", &Image::setSlice);
|
||||
addStyle("slice-width", "", &Image::setSliceWidth);
|
||||
|
||||
osgDB::Registry* reg = osgDB::Registry::instance();
|
||||
if( !reg->getReaderWriterForExtension("png") )
|
||||
SG_LOG(SG_GL, SG_ALERT, "canvas::Image: Missing 'png' image reader");
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
Image::Image( const CanvasWeakPtr& canvas,
|
||||
const SGPropertyNode_ptr& node,
|
||||
const Style& parent_style,
|
||||
Element* parent ):
|
||||
ElementWeakPtr parent ):
|
||||
Element(canvas, node, parent_style, parent),
|
||||
_texture(new osg::Texture2D),
|
||||
_node_src_rect( node->getNode("source", 0, true) ),
|
||||
@@ -408,7 +414,14 @@ namespace canvas
|
||||
&& child->getNameString() == "visible"
|
||||
&& child->getBoolValue() )
|
||||
{
|
||||
CullCallback* cb = static_cast<CullCallback*>(_geom->getCullCallback());
|
||||
CullCallback* cb =
|
||||
#if OSG_VERSION_LESS_THAN(3,3,2)
|
||||
static_cast<CullCallback*>
|
||||
#else
|
||||
dynamic_cast<CullCallback*>
|
||||
#endif
|
||||
( _geom->getCullCallback() );
|
||||
|
||||
if( cb )
|
||||
cb->cullNextFrame();
|
||||
}
|
||||
@@ -521,8 +534,7 @@ namespace canvas
|
||||
if( !src_canvas )
|
||||
return handled;
|
||||
|
||||
MouseEventPtr mouse_event = dynamic_cast<MouseEvent*>(event.get());
|
||||
if( mouse_event )
|
||||
if( MouseEventPtr mouse_event = dynamic_cast<MouseEvent*>(event.get()) )
|
||||
{
|
||||
mouse_event.reset( new MouseEvent(*mouse_event) );
|
||||
|
||||
@@ -547,6 +559,11 @@ namespace canvas
|
||||
|
||||
handled |= src_canvas->handleMouseEvent(mouse_event);
|
||||
}
|
||||
else if( KeyboardEventPtr keyboard_event =
|
||||
dynamic_cast<KeyboardEvent*>(event.get()) )
|
||||
{
|
||||
handled |= src_canvas->handleKeyboardEvent(keyboard_event);
|
||||
}
|
||||
|
||||
return handled;
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ namespace canvas
|
||||
Image( const CanvasWeakPtr& canvas,
|
||||
const SGPropertyNode_ptr& node,
|
||||
const Style& parent_style = Style(),
|
||||
Element* parent = 0 );
|
||||
ElementWeakPtr parent = 0 );
|
||||
virtual ~Image();
|
||||
|
||||
virtual void update(double dt);
|
||||
|
||||
@@ -44,6 +44,7 @@ namespace canvas
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
const std::string GEO = "-geo";
|
||||
const std::string HDG = "hdg";
|
||||
const std::string Map::TYPE_NAME = "map";
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
@@ -61,7 +62,7 @@ namespace canvas
|
||||
Map::Map( const CanvasWeakPtr& canvas,
|
||||
const SGPropertyNode_ptr& node,
|
||||
const Style& parent_style,
|
||||
Element* parent ):
|
||||
ElementWeakPtr parent ):
|
||||
Group(canvas, node, parent_style, parent),
|
||||
// TODO make projection configurable
|
||||
_projection(new SansonFlamsteedProjection),
|
||||
@@ -112,87 +113,50 @@ namespace canvas
|
||||
//----------------------------------------------------------------------------
|
||||
void Map::childAdded(SGPropertyNode* parent, SGPropertyNode* child)
|
||||
{
|
||||
if( !boost::ends_with(child->getNameString(), GEO) )
|
||||
if( boost::ends_with(child->getNameString(), GEO) )
|
||||
_geo_nodes[child].reset(new GeoNodePair());
|
||||
else if( parent != _node && child->getNameString() == HDG )
|
||||
_hdg_nodes.insert(child);
|
||||
else
|
||||
return Element::childAdded(parent, child);
|
||||
|
||||
_geo_nodes[child].reset(new GeoNodePair());
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Map::childRemoved(SGPropertyNode* parent, SGPropertyNode* child)
|
||||
{
|
||||
if( !boost::ends_with(child->getNameString(), GEO) )
|
||||
return Element::childRemoved(parent, child);
|
||||
|
||||
// TODO remove from other node
|
||||
_geo_nodes.erase(child);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Map::valueChanged(SGPropertyNode * child)
|
||||
{
|
||||
const std::string& name = child->getNameString();
|
||||
|
||||
if( !boost::ends_with(name, GEO) )
|
||||
return Group::valueChanged(child);
|
||||
|
||||
GeoNodes::iterator it_geo_node = _geo_nodes.find(child);
|
||||
if( it_geo_node == _geo_nodes.end() )
|
||||
LOG_GEO_RET("geo node not found!")
|
||||
GeoNodePair* geo_node = it_geo_node->second.get();
|
||||
|
||||
geo_node->setDirty();
|
||||
|
||||
if( geo_node->getStatus() & GeoNodePair::INCOMPLETE )
|
||||
if( boost::ends_with(child->getNameString(), GEO) )
|
||||
// TODO remove from other node
|
||||
_geo_nodes.erase(child);
|
||||
else if( parent != _node && child->getName() == HDG )
|
||||
{
|
||||
// Detect lat, lon tuples...
|
||||
GeoCoord coord = parseGeoCoord(child->getStringValue());
|
||||
int index_other = -1;
|
||||
_hdg_nodes.erase(child);
|
||||
|
||||
switch( coord.type )
|
||||
{
|
||||
case GeoCoord::LATITUDE:
|
||||
index_other = child->getIndex() + 1;
|
||||
geo_node->setNodeLat(child);
|
||||
break;
|
||||
case GeoCoord::LONGITUDE:
|
||||
index_other = child->getIndex() - 1;
|
||||
geo_node->setNodeLon(child);
|
||||
break;
|
||||
default:
|
||||
LOG_GEO_RET("Invalid geo coord")
|
||||
}
|
||||
|
||||
SGPropertyNode *other = child->getParent()->getChild(name, index_other);
|
||||
if( !other )
|
||||
return;
|
||||
|
||||
GeoCoord coord_other = parseGeoCoord(other->getStringValue());
|
||||
if( coord_other.type == GeoCoord::INVALID
|
||||
|| coord_other.type == coord.type )
|
||||
return;
|
||||
|
||||
GeoNodes::iterator it_geo_node_other = _geo_nodes.find(other);
|
||||
if( it_geo_node_other == _geo_nodes.end() )
|
||||
LOG_GEO_RET("other geo node not found!")
|
||||
GeoNodePair* geo_node_other = it_geo_node_other->second.get();
|
||||
|
||||
// Let use both nodes use the same GeoNodePair instance
|
||||
if( geo_node_other != geo_node )
|
||||
it_geo_node_other->second = it_geo_node->second;
|
||||
|
||||
if( coord_other.type == GeoCoord::LATITUDE )
|
||||
geo_node->setNodeLat(other);
|
||||
else
|
||||
geo_node->setNodeLon(other);
|
||||
|
||||
// Set name for resulting screen coordinate nodes
|
||||
geo_node->setTargetName( name.substr(0, name.length() - GEO.length()) );
|
||||
// Remove rotation matrix (tf[0]) and return to element always being
|
||||
// oriented upwards (or any orientation inside other matrices).
|
||||
child->getParent()->removeChild("tf", 0);
|
||||
}
|
||||
else
|
||||
return Element::childRemoved(parent, child);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Map::childChanged(SGPropertyNode * child)
|
||||
void Map::valueChanged(SGPropertyNode* child)
|
||||
{
|
||||
if( child->getParent() != _node )
|
||||
{
|
||||
const std::string& name = child->getNameString();
|
||||
|
||||
if( boost::ends_with(name, GEO) )
|
||||
return geoNodeChanged(child);
|
||||
else if( name == HDG )
|
||||
return hdgNodeChanged(child);
|
||||
}
|
||||
|
||||
return Group::valueChanged(child);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Map::childChanged(SGPropertyNode* child)
|
||||
{
|
||||
if( child->getParent() != _node )
|
||||
return Group::childChanged(child);
|
||||
@@ -201,8 +165,14 @@ namespace canvas
|
||||
|| child->getNameString() == "ref-lon" )
|
||||
_projection->setWorldPosition( _node->getDoubleValue("ref-lat"),
|
||||
_node->getDoubleValue("ref-lon") );
|
||||
else if( child->getNameString() == "hdg" )
|
||||
else if( child->getNameString() == HDG )
|
||||
{
|
||||
_projection->setOrientation(child->getFloatValue());
|
||||
for( NodeSet::iterator it = _hdg_nodes.begin();
|
||||
it != _hdg_nodes.end();
|
||||
++it )
|
||||
hdgNodeChanged(*it);
|
||||
}
|
||||
else if( child->getNameString() == "range" )
|
||||
_projection->setRange(child->getDoubleValue());
|
||||
else if( child->getNameString() == "screen-range" )
|
||||
@@ -213,6 +183,74 @@ namespace canvas
|
||||
_projection_dirty = true;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Map::geoNodeChanged(SGPropertyNode* child)
|
||||
{
|
||||
GeoNodes::iterator it_geo_node = _geo_nodes.find(child);
|
||||
if( it_geo_node == _geo_nodes.end() )
|
||||
LOG_GEO_RET("GeoNode not found!")
|
||||
GeoNodePair* geo_node = it_geo_node->second.get();
|
||||
|
||||
geo_node->setDirty();
|
||||
|
||||
if( !(geo_node->getStatus() & GeoNodePair::INCOMPLETE) )
|
||||
return;
|
||||
|
||||
// Detect lat, lon tuples...
|
||||
GeoCoord coord = parseGeoCoord(child->getStringValue());
|
||||
int index_other = -1;
|
||||
|
||||
switch( coord.type )
|
||||
{
|
||||
case GeoCoord::LATITUDE:
|
||||
index_other = child->getIndex() + 1;
|
||||
geo_node->setNodeLat(child);
|
||||
break;
|
||||
case GeoCoord::LONGITUDE:
|
||||
index_other = child->getIndex() - 1;
|
||||
geo_node->setNodeLon(child);
|
||||
break;
|
||||
default:
|
||||
LOG_GEO_RET("Invalid geo coord")
|
||||
}
|
||||
|
||||
const std::string& name = child->getNameString();
|
||||
SGPropertyNode *other = child->getParent()->getChild(name, index_other);
|
||||
if( !other )
|
||||
return;
|
||||
|
||||
GeoCoord coord_other = parseGeoCoord(other->getStringValue());
|
||||
if( coord_other.type == GeoCoord::INVALID
|
||||
|| coord_other.type == coord.type )
|
||||
return;
|
||||
|
||||
GeoNodes::iterator it_geo_node_other = _geo_nodes.find(other);
|
||||
if( it_geo_node_other == _geo_nodes.end() )
|
||||
LOG_GEO_RET("other geo node not found!")
|
||||
GeoNodePair* geo_node_other = it_geo_node_other->second.get();
|
||||
|
||||
// Let use both nodes use the same GeoNodePair instance
|
||||
if( geo_node_other != geo_node )
|
||||
it_geo_node_other->second = it_geo_node->second;
|
||||
|
||||
if( coord_other.type == GeoCoord::LATITUDE )
|
||||
geo_node->setNodeLat(other);
|
||||
else
|
||||
geo_node->setNodeLon(other);
|
||||
|
||||
// Set name for resulting screen coordinate nodes
|
||||
geo_node->setTargetName( name.substr(0, name.length() - GEO.length()) );
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Map::hdgNodeChanged(SGPropertyNode* child)
|
||||
{
|
||||
child->getParent()->setFloatValue(
|
||||
"tf[0]/rot",
|
||||
SGMiscf::deg2rad(child->getFloatValue() - _projection->orientation())
|
||||
);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
Map::GeoCoord Map::parseGeoCoord(const std::string& val) const
|
||||
{
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include <boost/unordered_set.hpp>
|
||||
|
||||
namespace simgear
|
||||
{
|
||||
@@ -41,7 +42,7 @@ namespace canvas
|
||||
Map( const CanvasWeakPtr& canvas,
|
||||
const SGPropertyNode_ptr& node,
|
||||
const Style& parent_style,
|
||||
Element* parent = 0 );
|
||||
ElementWeakPtr parent = 0 );
|
||||
virtual ~Map();
|
||||
|
||||
virtual void update(double dt);
|
||||
@@ -59,14 +60,18 @@ namespace canvas
|
||||
typedef boost::unordered_map< SGPropertyNode*,
|
||||
boost::shared_ptr<GeoNodePair>
|
||||
> GeoNodes;
|
||||
typedef boost::unordered_set<SGPropertyNode*> NodeSet;
|
||||
|
||||
GeoNodes _geo_nodes;
|
||||
NodeSet _hdg_nodes;
|
||||
boost::shared_ptr<HorizontalProjection> _projection;
|
||||
bool _projection_dirty;
|
||||
|
||||
struct GeoCoord
|
||||
{
|
||||
GeoCoord():
|
||||
type(INVALID)
|
||||
type(INVALID),
|
||||
value(0)
|
||||
{}
|
||||
enum
|
||||
{
|
||||
@@ -77,6 +82,9 @@ namespace canvas
|
||||
double value;
|
||||
};
|
||||
|
||||
void geoNodeChanged(SGPropertyNode * child);
|
||||
void hdgNodeChanged(SGPropertyNode * child);
|
||||
|
||||
GeoCoord parseGeoCoord(const std::string& val) const;
|
||||
};
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include <simgear/scene/util/parse_color.hxx>
|
||||
|
||||
#include <osg/Drawable>
|
||||
#include <osg/Version>
|
||||
|
||||
#include <vg/openvg.h>
|
||||
#include <cassert>
|
||||
@@ -69,7 +70,8 @@ namespace canvas
|
||||
_mode(0),
|
||||
_fill_rule(VG_EVEN_ODD),
|
||||
_stroke_width(1),
|
||||
_stroke_linecap(VG_CAP_BUTT)
|
||||
_stroke_linecap(VG_CAP_BUTT),
|
||||
_stroke_linejoin(VG_JOIN_MITER)
|
||||
{
|
||||
setSupportsDisplayList(false);
|
||||
setDataVariance(Object::DYNAMIC);
|
||||
@@ -202,6 +204,21 @@ namespace canvas
|
||||
_stroke_linecap = VG_CAP_BUTT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set stroke-linejoin
|
||||
*
|
||||
* @see http://www.w3.org/TR/SVG/painting.html#StrokeLinejoinProperty
|
||||
*/
|
||||
void setStrokeLinejoin(const std::string& linejoin)
|
||||
{
|
||||
if( linejoin == "round" )
|
||||
_stroke_linejoin = VG_JOIN_ROUND;
|
||||
else if( linejoin == "bevel" )
|
||||
_stroke_linejoin = VG_JOIN_BEVEL;
|
||||
else
|
||||
_stroke_linejoin = VG_JOIN_MITER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw callback
|
||||
*/
|
||||
@@ -251,6 +268,7 @@ namespace canvas
|
||||
|
||||
vgSetf(VG_STROKE_LINE_WIDTH, _stroke_width);
|
||||
vgSeti(VG_STROKE_CAP_STYLE, _stroke_linecap);
|
||||
vgSeti(VG_STROKE_JOIN_STYLE, _stroke_linejoin);
|
||||
vgSetfv( VG_STROKE_DASH_PATTERN,
|
||||
_stroke_dash.size(),
|
||||
_stroke_dash.empty() ? 0 : &_stroke_dash[0] );
|
||||
@@ -372,7 +390,13 @@ namespace canvas
|
||||
/**
|
||||
* Compute the bounding box
|
||||
*/
|
||||
virtual osg::BoundingBox computeBound() const
|
||||
virtual osg::BoundingBox
|
||||
#if OSG_VERSION_LESS_THAN(3,3,2)
|
||||
computeBound()
|
||||
#else
|
||||
computeBoundingBox()
|
||||
#endif
|
||||
const
|
||||
{
|
||||
if( _path == VG_INVALID_HANDLE || (_attributes_dirty & PATH) )
|
||||
return osg::BoundingBox();
|
||||
@@ -419,6 +443,7 @@ namespace canvas
|
||||
VGfloat _stroke_width;
|
||||
std::vector<VGfloat> _stroke_dash;
|
||||
VGCapStyle _stroke_linecap;
|
||||
VGJoinStyle _stroke_linejoin;
|
||||
|
||||
osg::Vec3f transformPoint( const osg::Matrix& m,
|
||||
osg::Vec2f pos ) const
|
||||
@@ -499,13 +524,14 @@ namespace canvas
|
||||
addStyle("stroke-width", "numeric", &PathDrawable::setStrokeWidth, path);
|
||||
addStyle("stroke-dasharray", "", &PathDrawable::setStrokeDashArray, path);
|
||||
addStyle("stroke-linecap", "", &PathDrawable::setStrokeLinecap, path);
|
||||
addStyle("stroke-linejoin", "", &PathDrawable::setStrokeLinejoin, path);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
Path::Path( const CanvasWeakPtr& canvas,
|
||||
const SGPropertyNode_ptr& node,
|
||||
const Style& parent_style,
|
||||
Element* parent ):
|
||||
ElementWeakPtr parent ):
|
||||
Element(canvas, node, parent_style, parent),
|
||||
_path( new PathDrawable(this) )
|
||||
{
|
||||
|
||||
@@ -36,7 +36,7 @@ namespace canvas
|
||||
Path( const CanvasWeakPtr& canvas,
|
||||
const SGPropertyNode_ptr& node,
|
||||
const Style& parent_style,
|
||||
Element* parent = 0 );
|
||||
ElementWeakPtr parent = 0 );
|
||||
virtual ~Path();
|
||||
|
||||
virtual void update(double dt);
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include <simgear/canvas/CanvasSystemAdapter.hxx>
|
||||
#include <simgear/scene/util/parse_color.hxx>
|
||||
#include <osg/Version>
|
||||
#include <osgDB/Registry>
|
||||
#include <osgText/Text>
|
||||
|
||||
namespace simgear
|
||||
@@ -31,27 +32,199 @@ namespace canvas
|
||||
public osgText::Text
|
||||
{
|
||||
public:
|
||||
|
||||
TextOSG(canvas::Text* text);
|
||||
|
||||
void setFontResolution(int res);
|
||||
void setCharacterAspect(float aspect);
|
||||
void setLineHeight(float factor);
|
||||
void setFill(const std::string& fill);
|
||||
void setStroke(const std::string& color);
|
||||
void setBackgroundColor(const std::string& fill);
|
||||
|
||||
SGVec2i sizeForWidth(int w) const;
|
||||
osg::Vec2 handleHit(const osg::Vec2f& pos);
|
||||
float lineHeight() const;
|
||||
|
||||
virtual osg::BoundingBox computeBound() const;
|
||||
/// Get the number of lines
|
||||
size_t lineCount() const;
|
||||
|
||||
/// Get line @a i
|
||||
TextLine lineAt(size_t i) const;
|
||||
|
||||
/// Get nearest line to given y-coordinate
|
||||
TextLine nearestLine(float pos_y) const;
|
||||
|
||||
|
||||
SGVec2i sizeForWidth(int w) const;
|
||||
|
||||
virtual osg::BoundingBox
|
||||
#if OSG_VERSION_LESS_THAN(3,3,2)
|
||||
computeBound()
|
||||
#else
|
||||
computeBoundingBox()
|
||||
#endif
|
||||
const;
|
||||
|
||||
protected:
|
||||
|
||||
friend class TextLine;
|
||||
|
||||
canvas::Text *_text_element;
|
||||
|
||||
virtual void computePositions(unsigned int contextID) const;
|
||||
};
|
||||
|
||||
class TextLine
|
||||
{
|
||||
public:
|
||||
TextLine();
|
||||
TextLine(size_t line, Text::TextOSG const* text);
|
||||
|
||||
/// Number of characters on this line
|
||||
size_t size() const;
|
||||
bool empty() const;
|
||||
|
||||
osg::Vec2 cursorPos(size_t i) const;
|
||||
osg::Vec2 nearestCursor(float x) const;
|
||||
|
||||
protected:
|
||||
typedef Text::TextOSG::GlyphQuads GlyphQuads;
|
||||
|
||||
Text::TextOSG const *_text;
|
||||
GlyphQuads const *_quads;
|
||||
|
||||
size_t _line,
|
||||
_begin,
|
||||
_end;
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
TextLine::TextLine():
|
||||
_text(NULL),
|
||||
_quads(NULL),
|
||||
_line(0),
|
||||
_begin(-1),
|
||||
_end(-1)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
TextLine::TextLine(size_t line, Text::TextOSG const* text):
|
||||
_text(text),
|
||||
_quads(NULL),
|
||||
_line(line),
|
||||
_begin(-1),
|
||||
_end(-1)
|
||||
{
|
||||
if( !text || text->_textureGlyphQuadMap.empty() || !_text->lineCount() )
|
||||
return;
|
||||
|
||||
_quads = &text->_textureGlyphQuadMap.begin()->second;
|
||||
|
||||
GlyphQuads::LineNumbers const& line_numbers = _quads->_lineNumbers;
|
||||
GlyphQuads::LineNumbers::const_iterator begin_it =
|
||||
std::lower_bound(line_numbers.begin(), line_numbers.end(), _line);
|
||||
|
||||
if( begin_it == line_numbers.end() || *begin_it != _line )
|
||||
// empty line or past last line
|
||||
return;
|
||||
|
||||
_begin = begin_it - line_numbers.begin();
|
||||
_end = std::upper_bound(begin_it, line_numbers.end(), _line)
|
||||
- line_numbers.begin();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
size_t TextLine::size() const
|
||||
{
|
||||
return _end - _begin;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
bool TextLine::empty() const
|
||||
{
|
||||
return _end == _begin;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
osg::Vec2 TextLine::cursorPos(size_t i) const
|
||||
{
|
||||
if( !_quads )
|
||||
return osg::Vec2(0, 0);
|
||||
|
||||
if( i > size() )
|
||||
// Position after last character if out of range (TODO better exception?)
|
||||
i = size();
|
||||
|
||||
osg::Vec2 pos(0, _text->_offset.y() + _line * _text->lineHeight());
|
||||
|
||||
if( empty() )
|
||||
return pos;
|
||||
#if OSG_VERSION_LESS_THAN(3,3,5)
|
||||
GlyphQuads::Coords2 const& coords = _quads->_coords;
|
||||
#else
|
||||
GlyphQuads::Coords2 refCoords = _quads->_coords;
|
||||
GlyphQuads::Coords2::element_type &coords = *refCoords.get();
|
||||
#endif
|
||||
size_t global_i = _begin + i;
|
||||
|
||||
if( global_i == _begin )
|
||||
// before first character of line
|
||||
pos.x() = coords[_begin * 4].x();
|
||||
else if( global_i == _end )
|
||||
// After Last character of line
|
||||
pos.x() = coords[(_end - 1) * 4 + 2].x();
|
||||
else
|
||||
{
|
||||
float prev_l = coords[(global_i - 1) * 4].x(),
|
||||
prev_r = coords[(global_i - 1) * 4 + 2].x(),
|
||||
cur_l = coords[global_i * 4].x();
|
||||
|
||||
if( prev_l == prev_r )
|
||||
// If previous character width is zero set to begin of next character
|
||||
// (Happens eg. with spaces)
|
||||
pos.x() = cur_l;
|
||||
else
|
||||
// position at center between characters
|
||||
pos.x() = 0.5 * (prev_r + cur_l);
|
||||
}
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
osg::Vec2 TextLine::nearestCursor(float x) const
|
||||
{
|
||||
if( empty() )
|
||||
return cursorPos(0);
|
||||
|
||||
GlyphQuads::Glyphs const& glyphs = _quads->_glyphs;
|
||||
#if OSG_VERSION_LESS_THAN(3,3,5)
|
||||
GlyphQuads::Coords2 const& coords = _quads->_coords;
|
||||
#else
|
||||
GlyphQuads::Coords2 refCoords = _quads->_coords;
|
||||
GlyphQuads::Coords2::element_type &coords = *refCoords.get();
|
||||
#endif
|
||||
|
||||
float const HIT_FRACTION = 0.6;
|
||||
float const character_width = _text->getCharacterHeight()
|
||||
* _text->getCharacterAspectRatio();
|
||||
|
||||
size_t i = _begin;
|
||||
for(; i < _end; ++i)
|
||||
{
|
||||
// Get threshold for mouse x position for setting cursor before or after
|
||||
// current character
|
||||
float threshold = coords[i * 4].x()
|
||||
+ HIT_FRACTION * glyphs[i]->getHorizontalAdvance()
|
||||
* character_width;
|
||||
|
||||
if( x <= threshold )
|
||||
break;
|
||||
}
|
||||
|
||||
return cursorPos(i - _begin);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
Text::TextOSG::TextOSG(canvas::Text* text):
|
||||
_text_element(text)
|
||||
@@ -88,6 +261,19 @@ namespace canvas
|
||||
setColor( color );
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Text::TextOSG::setStroke(const std::string& stroke)
|
||||
{
|
||||
osg::Vec4 color;
|
||||
if( stroke == "none" || !parseColor(stroke, color) )
|
||||
setBackdropType(NONE);
|
||||
else
|
||||
{
|
||||
setBackdropType(OUTLINE);
|
||||
setBackdropColor(color);
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Text::TextOSG::setBackgroundColor(const std::string& fill)
|
||||
{
|
||||
@@ -96,6 +282,45 @@ namespace canvas
|
||||
setBoundingBoxColor( color );
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
float Text::TextOSG::lineHeight() const
|
||||
{
|
||||
return (1 + _lineSpacing) * _characterHeight;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
size_t Text::TextOSG::lineCount() const
|
||||
{
|
||||
return _lineCount;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
TextLine Text::TextOSG::lineAt(size_t i) const
|
||||
{
|
||||
return TextLine(i, this);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
TextLine Text::TextOSG::nearestLine(float pos_y) const
|
||||
{
|
||||
osgText::Font const* font = getActiveFont();
|
||||
if( !font || lineCount() <= 0 )
|
||||
return TextLine(0, this);
|
||||
|
||||
float asc = .9f, desc = -.2f;
|
||||
font->getVerticalSize(asc, desc);
|
||||
|
||||
float first_line_y = _offset.y()
|
||||
- (1 + _lineSpacing / 2 + desc) * _characterHeight;
|
||||
|
||||
size_t line_num = std::min<size_t>(
|
||||
std::max<size_t>(0, (pos_y - first_line_y) / lineHeight()),
|
||||
lineCount() - 1
|
||||
);
|
||||
|
||||
return TextLine(line_num, this);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// simplified version of osgText::Text::computeGlyphRepresentation() to
|
||||
// just calculate the size for a given weight. Glpyh calculations/creating
|
||||
@@ -372,89 +597,20 @@ namespace canvas
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
osg::Vec2 Text::TextOSG::handleHit(const osg::Vec2f& pos)
|
||||
osg::BoundingBox
|
||||
#if OSG_VERSION_LESS_THAN(3,3,2)
|
||||
Text::TextOSG::computeBound()
|
||||
#else
|
||||
Text::TextOSG::computeBoundingBox()
|
||||
#endif
|
||||
const
|
||||
{
|
||||
float line_height = _characterHeight + _lineSpacing;
|
||||
|
||||
// TODO check with align other than TOP
|
||||
float first_line_y = -0.5 * _lineSpacing;//_offset.y() - _characterHeight;
|
||||
size_t line = std::max<int>(0, (pos.y() - first_line_y) / line_height);
|
||||
|
||||
if( _textureGlyphQuadMap.empty() )
|
||||
return osg::Vec2(-1, -1);
|
||||
|
||||
// TODO check when it can be larger
|
||||
assert( _textureGlyphQuadMap.size() == 1 );
|
||||
|
||||
const GlyphQuads& glyphquad = _textureGlyphQuadMap.begin()->second;
|
||||
const GlyphQuads::Glyphs& glyphs = glyphquad._glyphs;
|
||||
const GlyphQuads::Coords2& coords = glyphquad._coords;
|
||||
const GlyphQuads::LineNumbers& line_numbers = glyphquad._lineNumbers;
|
||||
|
||||
const float HIT_FRACTION = 0.6;
|
||||
const float character_width = getCharacterHeight()
|
||||
* getCharacterAspectRatio();
|
||||
|
||||
float y = (line + 0.5) * line_height;
|
||||
|
||||
bool line_found = false;
|
||||
for(size_t i = 0; i < line_numbers.size(); ++i)
|
||||
{
|
||||
if( line_numbers[i] != line )
|
||||
{
|
||||
if( !line_found )
|
||||
{
|
||||
if( line_numbers[i] < line )
|
||||
// Wait for the correct line...
|
||||
continue;
|
||||
|
||||
// We have already passed the correct line -> It's empty...
|
||||
return osg::Vec2(0, y);
|
||||
}
|
||||
|
||||
// Next line and not returned -> not before any character
|
||||
// -> return position after last character of line
|
||||
return osg::Vec2(coords[(i - 1) * 4 + 2].x(), y);
|
||||
}
|
||||
|
||||
line_found = true;
|
||||
|
||||
// Get threshold for mouse x position for setting cursor before or after
|
||||
// current character
|
||||
float threshold = coords[i * 4].x()
|
||||
+ HIT_FRACTION * glyphs[i]->getHorizontalAdvance()
|
||||
* character_width;
|
||||
|
||||
if( pos.x() <= threshold )
|
||||
{
|
||||
osg::Vec2 hit(0, y);
|
||||
if( i == 0 || line_numbers[i - 1] != line )
|
||||
// first character of line
|
||||
hit.x() = coords[i * 4].x();
|
||||
else if( coords[(i - 1) * 4].x() == coords[(i - 1) * 4 + 2].x() )
|
||||
// If previous character width is zero set to begin of next character
|
||||
// (Happens eg. with spaces)
|
||||
hit.x() = coords[i * 4].x();
|
||||
else
|
||||
// position at center between characters
|
||||
hit.x() = 0.5 * (coords[(i - 1) * 4 + 2].x() + coords[i * 4].x());
|
||||
|
||||
return hit;
|
||||
}
|
||||
}
|
||||
|
||||
// Nothing found -> return position after last character
|
||||
return osg::Vec2
|
||||
(
|
||||
coords.back().x(),
|
||||
(_lineCount - 0.5) * line_height
|
||||
);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
osg::BoundingBox Text::TextOSG::computeBound() const
|
||||
{
|
||||
osg::BoundingBox bb = osgText::Text::computeBound();
|
||||
osg::BoundingBox bb =
|
||||
#if OSG_VERSION_LESS_THAN(3,3,2)
|
||||
osgText::Text::computeBound();
|
||||
#else
|
||||
osgText::Text::computeBoundingBox();
|
||||
#endif
|
||||
|
||||
#if OSG_VERSION_LESS_THAN(3,1,0)
|
||||
if( bb.valid() )
|
||||
@@ -480,7 +636,13 @@ namespace canvas
|
||||
|
||||
const GlyphQuads& quads = _textureGlyphQuadMap.begin()->second;
|
||||
const GlyphQuads::Glyphs& glyphs = quads._glyphs;
|
||||
const GlyphQuads::Coords2& coords = quads._coords;
|
||||
#if OSG_VERSION_LESS_THAN(3,3,5)
|
||||
GlyphQuads::Coords2 const& coords = quads._coords;
|
||||
#else
|
||||
GlyphQuads::Coords2 refCoords = quads._coords;
|
||||
GlyphQuads::Coords2::element_type &coords = *refCoords.get();
|
||||
#endif
|
||||
|
||||
const GlyphQuads::LineNumbers& line_numbers = quads._lineNumbers;
|
||||
|
||||
float wr = _characterHeight / getCharacterAspectRatio();
|
||||
@@ -546,6 +708,7 @@ namespace canvas
|
||||
|
||||
addStyle("fill", "color", &TextOSG::setFill, text);
|
||||
addStyle("background", "color", &TextOSG::setBackgroundColor, text);
|
||||
addStyle("stroke", "color", &TextOSG::setStroke, text);
|
||||
addStyle("character-size",
|
||||
"numeric",
|
||||
static_cast<
|
||||
@@ -567,13 +730,17 @@ namespace canvas
|
||||
addStyle("font", "", &Text::setFont);
|
||||
addStyle("alignment", "", &Text::setAlignment);
|
||||
addStyle("text", "", &Text::setText, false);
|
||||
|
||||
osgDB::Registry* reg = osgDB::Registry::instance();
|
||||
if( !reg->getReaderWriterForExtension("ttf") )
|
||||
SG_LOG(SG_GL, SG_ALERT, "canvas::Text: Missing 'ttf' font reader");
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
Text::Text( const CanvasWeakPtr& canvas,
|
||||
const SGPropertyNode_ptr& node,
|
||||
const Style& parent_style,
|
||||
Element* parent ):
|
||||
ElementWeakPtr parent ):
|
||||
Element(canvas, node, parent_style, parent),
|
||||
_text( new Text::TextOSG(this) )
|
||||
{
|
||||
@@ -657,10 +824,39 @@ namespace canvas
|
||||
return _text->sizeForWidth(INT_MAX).x();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
size_t Text::lineCount() const
|
||||
{
|
||||
return _text->lineCount();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
size_t Text::lineLength(size_t line) const
|
||||
{
|
||||
return _text->lineAt(line).size();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
osg::Vec2 Text::getNearestCursor(const osg::Vec2& pos) const
|
||||
{
|
||||
return _text->handleHit(pos);
|
||||
return _text->nearestLine(pos.y()).nearestCursor(pos.x());
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
osg::Vec2 Text::getCursorPos(size_t line, size_t character) const
|
||||
{
|
||||
return _text->lineAt(line).cursorPos(character);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
osg::StateSet* Text::getOrCreateStateSet()
|
||||
{
|
||||
if( !_transform.valid() )
|
||||
return 0;
|
||||
|
||||
// Only check for StateSet on Transform, as the text stateset is shared
|
||||
// between all text instances using the same font (texture).
|
||||
return _transform->getOrCreateStateSet();
|
||||
}
|
||||
|
||||
} // namespace canvas
|
||||
|
||||
@@ -29,6 +29,7 @@ namespace simgear
|
||||
namespace canvas
|
||||
{
|
||||
|
||||
class TextLine;
|
||||
class Text:
|
||||
public Element
|
||||
{
|
||||
@@ -39,7 +40,7 @@ namespace canvas
|
||||
Text( const CanvasWeakPtr& canvas,
|
||||
const SGPropertyNode_ptr& node,
|
||||
const Style& parent_style,
|
||||
Element* parent = 0 );
|
||||
ElementWeakPtr parent = 0 );
|
||||
~Text();
|
||||
|
||||
void setText(const char* text);
|
||||
@@ -48,13 +49,24 @@ namespace canvas
|
||||
|
||||
int heightForWidth(int w) const;
|
||||
int maxWidth() const;
|
||||
|
||||
/// Number of text lines.
|
||||
size_t lineCount() const;
|
||||
|
||||
/// Number of characters in @a line.
|
||||
size_t lineLength(size_t line) const;
|
||||
|
||||
osg::Vec2 getNearestCursor(const osg::Vec2& pos) const;
|
||||
osg::Vec2 getCursorPos(size_t line, size_t character) const;
|
||||
|
||||
protected:
|
||||
|
||||
friend class TextLine;
|
||||
class TextOSG;
|
||||
osg::ref_ptr<TextOSG> _text;
|
||||
|
||||
virtual osg::StateSet* getOrCreateStateSet();
|
||||
|
||||
};
|
||||
|
||||
} // namespace canvas
|
||||
|
||||
@@ -34,7 +34,10 @@ namespace canvas
|
||||
public:
|
||||
struct ScreenPosition
|
||||
{
|
||||
ScreenPosition() {}
|
||||
ScreenPosition():
|
||||
x(0),
|
||||
y(0)
|
||||
{}
|
||||
|
||||
ScreenPosition(double x, double y):
|
||||
x(x),
|
||||
@@ -67,8 +70,11 @@ namespace canvas
|
||||
public:
|
||||
|
||||
HorizontalProjection():
|
||||
_cos_rot(1),
|
||||
_sin_rot(0),
|
||||
_ref_lat(0),
|
||||
_ref_lon(0),
|
||||
_angle(0),
|
||||
_cos_angle(1),
|
||||
_sin_angle(0),
|
||||
_range(5)
|
||||
{
|
||||
setScreenRange(200);
|
||||
@@ -88,9 +94,19 @@ namespace canvas
|
||||
*/
|
||||
void setOrientation(float hdg)
|
||||
{
|
||||
_angle = hdg;
|
||||
|
||||
hdg = SGMiscf::deg2rad(hdg);
|
||||
_sin_rot = sin(hdg);
|
||||
_cos_rot = cos(hdg);
|
||||
_sin_angle = sin(hdg);
|
||||
_cos_angle = cos(hdg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get orientation/heading of the projection (in degree)
|
||||
*/
|
||||
float orientation() const
|
||||
{
|
||||
return _angle;
|
||||
}
|
||||
|
||||
void setRange(double range)
|
||||
@@ -114,8 +130,8 @@ namespace canvas
|
||||
pos.y *= scale;
|
||||
return ScreenPosition
|
||||
(
|
||||
_cos_rot * pos.x - _sin_rot * pos.y,
|
||||
-_sin_rot * pos.x - _cos_rot * pos.y
|
||||
_cos_angle * pos.x - _sin_angle * pos.y,
|
||||
-_sin_angle * pos.x - _cos_angle * pos.y
|
||||
);
|
||||
}
|
||||
|
||||
@@ -129,10 +145,11 @@ namespace canvas
|
||||
*/
|
||||
virtual ScreenPosition project(double lat, double lon) const = 0;
|
||||
|
||||
double _ref_lat,
|
||||
_ref_lon,
|
||||
_cos_rot,
|
||||
_sin_rot,
|
||||
double _ref_lat, ///<! Reference latitude (radian)
|
||||
_ref_lon, ///<! Reference latitude (radian)
|
||||
_angle, ///<! Map rotation angle (degree)
|
||||
_cos_angle,
|
||||
_sin_angle,
|
||||
_range;
|
||||
};
|
||||
|
||||
|
||||
@@ -2,11 +2,15 @@ include (SimGearComponent)
|
||||
|
||||
set(HEADERS
|
||||
CustomEvent.hxx
|
||||
DeviceEvent.hxx
|
||||
KeyboardEvent.hxx
|
||||
MouseEvent.hxx
|
||||
)
|
||||
|
||||
set(SOURCES
|
||||
CustomEvent.cxx
|
||||
DeviceEvent.cxx
|
||||
KeyboardEvent.cxx
|
||||
MouseEvent.cxx
|
||||
)
|
||||
|
||||
@@ -15,4 +19,10 @@ simgear_scene_component(canvas-events canvas/events "${SOURCES}" "${HEADERS}")
|
||||
add_boost_test(canvas_event
|
||||
SOURCES event_test.cpp
|
||||
LIBRARIES ${TEST_LIBS}
|
||||
)
|
||||
|
||||
add_executable(input_event_demo input_event_demo.cxx)
|
||||
target_link_libraries(input_event_demo
|
||||
${TEST_LIBS}
|
||||
${OPENSCENEGRAPH_LIBRARIES}
|
||||
)
|
||||
@@ -1,4 +1,5 @@
|
||||
///@file Canvas user defined event
|
||||
///@file
|
||||
/// Canvas user defined event
|
||||
//
|
||||
// Copyright (C) 2014 Thomas Geymayer <tomgey@gmail.com>
|
||||
//
|
||||
@@ -27,6 +28,10 @@ namespace simgear
|
||||
namespace canvas
|
||||
{
|
||||
|
||||
/**
|
||||
* User defined event (optionally carrying additional context information or
|
||||
* data).
|
||||
*/
|
||||
class CustomEvent:
|
||||
public Event
|
||||
{
|
||||
@@ -36,6 +41,7 @@ namespace canvas
|
||||
*
|
||||
* @param type_str Event type name (if name does not exist yet it will
|
||||
* be registered as new event type)
|
||||
* @param bubbles If this event should take part in the bubbling phase
|
||||
* @param data Optional user data stored in event
|
||||
*/
|
||||
CustomEvent( std::string const& type_str,
|
||||
@@ -45,6 +51,7 @@ namespace canvas
|
||||
/**
|
||||
*
|
||||
* @param type_id Event type id
|
||||
* @param bubbles If this event should take part in the bubbling phase
|
||||
* @param data Optional user data stored in event
|
||||
*/
|
||||
CustomEvent( int type_id,
|
||||
@@ -61,10 +68,16 @@ namespace canvas
|
||||
*/
|
||||
StringMap const& getDetail() const { return detail; }
|
||||
|
||||
/**
|
||||
* Get whether this event supports bubbling.
|
||||
*
|
||||
* @see #bubbles
|
||||
* @see CustomEvent()
|
||||
*/
|
||||
virtual bool canBubble() const { return bubbles; }
|
||||
|
||||
StringMap detail; //<! user data map
|
||||
bool bubbles;
|
||||
StringMap detail; //!< User data map
|
||||
bool bubbles; //!< Whether the event supports bubbling
|
||||
};
|
||||
|
||||
} // namespace canvas
|
||||
|
||||
66
simgear/canvas/events/DeviceEvent.cxx
Normal file
66
simgear/canvas/events/DeviceEvent.cxx
Normal file
@@ -0,0 +1,66 @@
|
||||
// Input device 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 "DeviceEvent.hxx"
|
||||
#include <osgGA/GUIEventAdapter>
|
||||
|
||||
namespace simgear
|
||||
{
|
||||
namespace canvas
|
||||
{
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
DeviceEvent::DeviceEvent():
|
||||
modifiers(0)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
DeviceEvent::DeviceEvent(const osgGA::GUIEventAdapter& ea):
|
||||
modifiers(ea.getModKeyMask())
|
||||
{
|
||||
time = ea.getTime();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
bool DeviceEvent::ctrlKey() const
|
||||
{
|
||||
return (modifiers & osgGA::GUIEventAdapter::MODKEY_CTRL) != 0;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
bool DeviceEvent::shiftKey() const
|
||||
{
|
||||
return (modifiers & osgGA::GUIEventAdapter::MODKEY_SHIFT) != 0;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
bool DeviceEvent::altKey() const
|
||||
{
|
||||
return (modifiers & osgGA::GUIEventAdapter::MODKEY_ALT) != 0;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
bool DeviceEvent::metaKey() const
|
||||
{
|
||||
return (modifiers & osgGA::GUIEventAdapter::MODKEY_META) != 0;
|
||||
}
|
||||
|
||||
} // namespace canvas
|
||||
} // namespace simgear
|
||||
67
simgear/canvas/events/DeviceEvent.hxx
Normal file
67
simgear/canvas/events/DeviceEvent.hxx
Normal file
@@ -0,0 +1,67 @@
|
||||
///@file
|
||||
/// Input device event (keyboard/mouse)
|
||||
//
|
||||
// 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_DEVICE_EVENT_HXX_
|
||||
#define CANVAS_DEVICE_EVENT_HXX_
|
||||
|
||||
#include <simgear/canvas/CanvasEvent.hxx>
|
||||
|
||||
namespace osgGA { class GUIEventAdapter; }
|
||||
|
||||
namespace simgear
|
||||
{
|
||||
namespace canvas
|
||||
{
|
||||
|
||||
/**
|
||||
* Common interface for input device events.
|
||||
*/
|
||||
class DeviceEvent:
|
||||
public Event
|
||||
{
|
||||
public:
|
||||
/// Default initialization (no active keyboard modifier).
|
||||
DeviceEvent();
|
||||
|
||||
/// Initialize from an OpenSceneGraph event.
|
||||
DeviceEvent(const osgGA::GUIEventAdapter& ea);
|
||||
|
||||
/// Get mask of active keyboard modifiers at the time of the event.
|
||||
int getModifiers() const { return modifiers; }
|
||||
|
||||
/// Get if a Ctrl modifier was active.
|
||||
bool ctrlKey() const;
|
||||
|
||||
/// Get if a Shift modifier was active.
|
||||
bool shiftKey() const;
|
||||
|
||||
/// Get if an Alt modifier was active.
|
||||
bool altKey() const;
|
||||
|
||||
/// Get if a Meta modifier was active.
|
||||
bool metaKey() const;
|
||||
|
||||
protected:
|
||||
int modifiers; //!< Keyboard modifier state
|
||||
};
|
||||
|
||||
} // namespace canvas
|
||||
} // namespace simgear
|
||||
|
||||
#endif /* CANVAS_DEVICE_EVENT_HXX_ */
|
||||
323
simgear/canvas/events/KeyboardEvent.cxx
Normal file
323
simgear/canvas/events/KeyboardEvent.cxx
Normal file
@@ -0,0 +1,323 @@
|
||||
// Keyboard 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 "KeyboardEvent.hxx"
|
||||
#include "utf8.h"
|
||||
|
||||
#include <osgGA/GUIEventAdapter>
|
||||
|
||||
#include <boost/version.hpp>
|
||||
#if BOOST_VERSION >= 104800
|
||||
# include <boost/container/flat_map.hpp>
|
||||
# include <boost/container/flat_set.hpp>
|
||||
#else
|
||||
# include <map>
|
||||
# include <set>
|
||||
#endif
|
||||
|
||||
#include <iterator>
|
||||
|
||||
namespace simgear
|
||||
{
|
||||
namespace canvas
|
||||
{
|
||||
typedef osgGA::GUIEventAdapter EA;
|
||||
|
||||
// TODO check Win/Mac keycode for altgr/ISO Level3 Shift
|
||||
const uint32_t KEY_AltGraph = 0xfe03;
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
KeyboardEvent::KeyboardEvent():
|
||||
_key(0),
|
||||
_unmodified_key(0),
|
||||
_repeat(false),
|
||||
_location(DOM_KEY_LOCATION_STANDARD)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
KeyboardEvent::KeyboardEvent(const osgGA::GUIEventAdapter& ea):
|
||||
DeviceEvent(ea),
|
||||
_key(ea.getKey()),
|
||||
_unmodified_key(ea.getUnmodifiedKey()),
|
||||
_repeat(false),
|
||||
_location(DOM_KEY_LOCATION_STANDARD)
|
||||
{
|
||||
if( ea.getEventType() == EA::KEYDOWN )
|
||||
type = KEY_DOWN;
|
||||
else if( ea.getEventType() == EA::KEYUP )
|
||||
type = KEY_UP;
|
||||
// else
|
||||
// // TODO what to do with wrong event type?
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void KeyboardEvent::setKey(uint32_t key)
|
||||
{
|
||||
_name.clear();
|
||||
_key = key;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void KeyboardEvent::setUnmodifiedKey(uint32_t key)
|
||||
{
|
||||
_name.clear();
|
||||
_unmodified_key = key;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void KeyboardEvent::setRepeat(bool repeat)
|
||||
{
|
||||
_repeat = repeat;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
std::string KeyboardEvent::key() const
|
||||
{
|
||||
if( !_name.empty() )
|
||||
return _name;
|
||||
|
||||
// We need to make sure only valid const char* pointers are passed. The best
|
||||
// way is just to use string constants.
|
||||
// Use an empty string ("") to just use the value reported by the operating
|
||||
// system.
|
||||
typedef std::pair<const char*, uint8_t> InternalKeyInfo;
|
||||
|
||||
#if BOOST_VERSION >= 104800
|
||||
typedef boost::container::flat_map<int, InternalKeyInfo> InternalKeyMap;
|
||||
typedef boost::container::flat_set<int> KeyList;
|
||||
#else
|
||||
# warning "Use Boost >= 1.48 for faster and more memory efficient key lookup"
|
||||
typedef std::map<int, InternalKeyInfo> InternalKeyMap;
|
||||
typedef std::set<int> KeyList;
|
||||
#endif
|
||||
|
||||
static InternalKeyMap key_map;
|
||||
static KeyList num_pad_keys;
|
||||
|
||||
if( key_map.empty() )
|
||||
{
|
||||
const uint8_t S = DOM_KEY_LOCATION_STANDARD,
|
||||
L = DOM_KEY_LOCATION_LEFT,
|
||||
R = DOM_KEY_LOCATION_RIGHT,
|
||||
N = DOM_KEY_LOCATION_NUMPAD;
|
||||
|
||||
key_map[ EA::KEY_BackSpace ] = std::make_pair("Backspace", S);
|
||||
key_map[ EA::KEY_Tab ] = std::make_pair("Tab", S);
|
||||
key_map[ EA::KEY_Linefeed ] = std::make_pair("Linefeed", S);
|
||||
key_map[ EA::KEY_Clear ] = std::make_pair("Clear", S);
|
||||
key_map[ EA::KEY_Return ] = std::make_pair("Enter", S);
|
||||
key_map[ EA::KEY_Pause ] = std::make_pair("Pause", S);
|
||||
key_map[ EA::KEY_Scroll_Lock ] = std::make_pair("ScrollLock", S);
|
||||
key_map[ EA::KEY_Sys_Req ] = std::make_pair("SystemRequest", S);
|
||||
key_map[ EA::KEY_Escape ] = std::make_pair("Escape", S);
|
||||
key_map[ EA::KEY_Delete ] = std::make_pair("Delete", S);
|
||||
|
||||
key_map[ EA::KEY_Home ] = std::make_pair("Home", S);
|
||||
key_map[ EA::KEY_Left ] = std::make_pair("Left", S);
|
||||
key_map[ EA::KEY_Up ] = std::make_pair("Up", S);
|
||||
key_map[ EA::KEY_Right ] = std::make_pair("Right", S);
|
||||
key_map[ EA::KEY_Down ] = std::make_pair("Down", S);
|
||||
key_map[ EA::KEY_Page_Up ] = std::make_pair("PageUp", S);
|
||||
key_map[ EA::KEY_Page_Down ] = std::make_pair("PageDown", S);
|
||||
key_map[ EA::KEY_End ] = std::make_pair("End", S);
|
||||
key_map[ EA::KEY_Begin ] = std::make_pair("Begin", S);
|
||||
|
||||
key_map[ EA::KEY_Select ] = std::make_pair("Select", S);
|
||||
key_map[ EA::KEY_Print ] = std::make_pair("PrintScreen", S);
|
||||
key_map[ EA::KEY_Execute ] = std::make_pair("Execute", S);
|
||||
key_map[ EA::KEY_Insert ] = std::make_pair("Insert", S);
|
||||
key_map[ EA::KEY_Undo ] = std::make_pair("Undo", S);
|
||||
key_map[ EA::KEY_Redo ] = std::make_pair("Redo", S);
|
||||
key_map[ EA::KEY_Menu ] = std::make_pair("ContextMenu", S);
|
||||
key_map[ EA::KEY_Find ] = std::make_pair("Find", S);
|
||||
key_map[ EA::KEY_Cancel ] = std::make_pair("Cancel", S);
|
||||
key_map[ EA::KEY_Help ] = std::make_pair("Help", S);
|
||||
key_map[ EA::KEY_Break ] = std::make_pair("Break", S);
|
||||
key_map[ EA::KEY_Mode_switch ] = std::make_pair("ModeChange", S);
|
||||
key_map[ EA::KEY_Num_Lock ] = std::make_pair("NumLock", S);
|
||||
|
||||
key_map[ EA::KEY_KP_Space ] = std::make_pair(" ", N);
|
||||
key_map[ EA::KEY_KP_Tab ] = std::make_pair("Tab", N);
|
||||
key_map[ EA::KEY_KP_Enter ] = std::make_pair("Enter", N);
|
||||
key_map[ EA::KEY_KP_F1 ] = std::make_pair("F1", N);
|
||||
key_map[ EA::KEY_KP_F2 ] = std::make_pair("F2", N);
|
||||
key_map[ EA::KEY_KP_F3 ] = std::make_pair("F3", N);
|
||||
key_map[ EA::KEY_KP_F4 ] = std::make_pair("F4", N);
|
||||
key_map[ EA::KEY_KP_Home ] = std::make_pair("Home", N);
|
||||
key_map[ EA::KEY_KP_Left ] = std::make_pair("Left", N);
|
||||
key_map[ EA::KEY_KP_Up ] = std::make_pair("Up", N);
|
||||
key_map[ EA::KEY_KP_Right ] = std::make_pair("Right", N);
|
||||
key_map[ EA::KEY_KP_Down ] = std::make_pair("Down", N);
|
||||
key_map[ EA::KEY_KP_Page_Up ] = std::make_pair("PageUp", N);
|
||||
key_map[ EA::KEY_KP_Page_Down ] = std::make_pair("PageDown", N);
|
||||
key_map[ EA::KEY_KP_End ] = std::make_pair("End", N);
|
||||
key_map[ EA::KEY_KP_Begin ] = std::make_pair("Begin", N);
|
||||
key_map[ EA::KEY_KP_Insert ] = std::make_pair("Insert", N);
|
||||
key_map[ EA::KEY_KP_Delete ] = std::make_pair("Delete", N);
|
||||
key_map[ EA::KEY_KP_Equal ] = std::make_pair("=", N);
|
||||
key_map[ EA::KEY_KP_Multiply ] = std::make_pair("*", N);
|
||||
key_map[ EA::KEY_KP_Add ] = std::make_pair("+", N);
|
||||
key_map[ EA::KEY_KP_Separator ] = std::make_pair("", N);
|
||||
key_map[ EA::KEY_KP_Subtract ] = std::make_pair("-", N);
|
||||
key_map[ EA::KEY_KP_Decimal ] = std::make_pair("", N);
|
||||
key_map[ EA::KEY_KP_Divide ] = std::make_pair("/", N);
|
||||
|
||||
key_map[ EA::KEY_KP_0 ] = std::make_pair("0", N);
|
||||
key_map[ EA::KEY_KP_1 ] = std::make_pair("1", N);
|
||||
key_map[ EA::KEY_KP_2 ] = std::make_pair("2", N);
|
||||
key_map[ EA::KEY_KP_3 ] = std::make_pair("3", N);
|
||||
key_map[ EA::KEY_KP_4 ] = std::make_pair("4", N);
|
||||
key_map[ EA::KEY_KP_5 ] = std::make_pair("5", N);
|
||||
key_map[ EA::KEY_KP_6 ] = std::make_pair("6", N);
|
||||
key_map[ EA::KEY_KP_7 ] = std::make_pair("7", N);
|
||||
key_map[ EA::KEY_KP_8 ] = std::make_pair("8", N);
|
||||
key_map[ EA::KEY_KP_9 ] = std::make_pair("9", N);
|
||||
|
||||
key_map[ EA::KEY_F1 ] = std::make_pair("F1", S);
|
||||
key_map[ EA::KEY_F2 ] = std::make_pair("F2", S);
|
||||
key_map[ EA::KEY_F3 ] = std::make_pair("F3", S);
|
||||
key_map[ EA::KEY_F4 ] = std::make_pair("F4", S);
|
||||
key_map[ EA::KEY_F5 ] = std::make_pair("F5", S);
|
||||
key_map[ EA::KEY_F6 ] = std::make_pair("F6", S);
|
||||
key_map[ EA::KEY_F7 ] = std::make_pair("F7", S);
|
||||
key_map[ EA::KEY_F8 ] = std::make_pair("F8", S);
|
||||
key_map[ EA::KEY_F9 ] = std::make_pair("F9", S);
|
||||
key_map[ EA::KEY_F10 ] = std::make_pair("F10", S);
|
||||
key_map[ EA::KEY_F11 ] = std::make_pair("F11", S);
|
||||
key_map[ EA::KEY_F12 ] = std::make_pair("F12", S);
|
||||
key_map[ EA::KEY_F13 ] = std::make_pair("F13", S);
|
||||
key_map[ EA::KEY_F14 ] = std::make_pair("F14", S);
|
||||
key_map[ EA::KEY_F15 ] = std::make_pair("F15", S);
|
||||
key_map[ EA::KEY_F16 ] = std::make_pair("F16", S);
|
||||
key_map[ EA::KEY_F17 ] = std::make_pair("F17", S);
|
||||
key_map[ EA::KEY_F18 ] = std::make_pair("F18", S);
|
||||
key_map[ EA::KEY_F19 ] = std::make_pair("F19", S);
|
||||
key_map[ EA::KEY_F20 ] = std::make_pair("F20", S);
|
||||
key_map[ EA::KEY_F21 ] = std::make_pair("F21", S);
|
||||
key_map[ EA::KEY_F22 ] = std::make_pair("F22", S);
|
||||
key_map[ EA::KEY_F23 ] = std::make_pair("F23", S);
|
||||
key_map[ EA::KEY_F24 ] = std::make_pair("F24", S);
|
||||
key_map[ EA::KEY_F25 ] = std::make_pair("F25", S);
|
||||
key_map[ EA::KEY_F26 ] = std::make_pair("F26", S);
|
||||
key_map[ EA::KEY_F27 ] = std::make_pair("F27", S);
|
||||
key_map[ EA::KEY_F28 ] = std::make_pair("F28", S);
|
||||
key_map[ EA::KEY_F29 ] = std::make_pair("F29", S);
|
||||
key_map[ EA::KEY_F30 ] = std::make_pair("F30", S);
|
||||
key_map[ EA::KEY_F31 ] = std::make_pair("F31", S);
|
||||
key_map[ EA::KEY_F32 ] = std::make_pair("F32", S);
|
||||
key_map[ EA::KEY_F33 ] = std::make_pair("F33", S);
|
||||
key_map[ EA::KEY_F34 ] = std::make_pair("F34", S);
|
||||
key_map[ EA::KEY_F35 ] = std::make_pair("F35", S);
|
||||
|
||||
key_map[ KEY_AltGraph ] = std::make_pair("AltGraph", S);
|
||||
key_map[ EA::KEY_Shift_L ] = std::make_pair("Shift", L);
|
||||
key_map[ EA::KEY_Shift_R ] = std::make_pair("Shift", R);
|
||||
key_map[ EA::KEY_Control_L ] = std::make_pair("Control", L);
|
||||
key_map[ EA::KEY_Control_R ] = std::make_pair("Control", R);
|
||||
key_map[ EA::KEY_Caps_Lock ] = std::make_pair("CapsLock", S);
|
||||
key_map[ EA::KEY_Shift_Lock ] = std::make_pair("ShiftLock", S);
|
||||
key_map[ EA::KEY_Meta_L ] = std::make_pair("Meta", L);
|
||||
key_map[ EA::KEY_Meta_R ] = std::make_pair("Meta", R);
|
||||
key_map[ EA::KEY_Alt_L ] = std::make_pair("Alt", L);
|
||||
key_map[ EA::KEY_Alt_R ] = std::make_pair("Alt", R);
|
||||
key_map[ EA::KEY_Super_L ] = std::make_pair("Super", L);
|
||||
key_map[ EA::KEY_Super_R ] = std::make_pair("Super", R);
|
||||
key_map[ EA::KEY_Hyper_L ] = std::make_pair("Hyper", L);
|
||||
key_map[ EA::KEY_Hyper_R ] = std::make_pair("Hyper", R);
|
||||
|
||||
num_pad_keys.insert(EA::KEY_KP_Home );
|
||||
num_pad_keys.insert(EA::KEY_KP_Left );
|
||||
num_pad_keys.insert(EA::KEY_KP_Up );
|
||||
num_pad_keys.insert(EA::KEY_KP_Right );
|
||||
num_pad_keys.insert(EA::KEY_KP_Down );
|
||||
num_pad_keys.insert(EA::KEY_KP_Page_Up );
|
||||
num_pad_keys.insert(EA::KEY_KP_Page_Down);
|
||||
num_pad_keys.insert(EA::KEY_KP_End );
|
||||
num_pad_keys.insert(EA::KEY_KP_Begin );
|
||||
num_pad_keys.insert(EA::KEY_KP_Insert );
|
||||
num_pad_keys.insert(EA::KEY_KP_Delete );
|
||||
}
|
||||
|
||||
_location = DOM_KEY_LOCATION_STANDARD;
|
||||
|
||||
InternalKeyMap::const_iterator it = key_map.find(_key);
|
||||
if( it != key_map.end())
|
||||
{
|
||||
_name = it->second.first;
|
||||
_location = it->second.second;
|
||||
}
|
||||
|
||||
// Empty or no mapping -> convert UTF-32 key value to UTF-8
|
||||
if( _name.empty() )
|
||||
{
|
||||
if( !utf8::internal::is_code_point_valid(_key) )
|
||||
_name = "Unidentified";
|
||||
else
|
||||
utf8::unchecked::append(_key, std::back_inserter(_name));
|
||||
}
|
||||
|
||||
// Keys on the numpad with NumLock enabled are reported just like their
|
||||
// equivalent keys in the standard key block. Using the unmodified key value
|
||||
// we can detect such keys and set the location accordingly.
|
||||
if( num_pad_keys.find(_unmodified_key) != num_pad_keys.end() )
|
||||
_location = DOM_KEY_LOCATION_NUMPAD;
|
||||
|
||||
return _name;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
KeyboardEvent::DOMKeyLocation KeyboardEvent::location() const
|
||||
{
|
||||
key(); // ensure location is up-to-date
|
||||
return static_cast<DOMKeyLocation>(_location);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
bool KeyboardEvent::isModifier() const
|
||||
{
|
||||
return ( _key >= EA::KEY_Shift_L
|
||||
&& _key <= EA::KEY_Hyper_R
|
||||
)
|
||||
|| _key == KEY_AltGraph;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
bool KeyboardEvent::isPrint() const
|
||||
{
|
||||
const std::string& key_name = key();
|
||||
if( key_name.empty() )
|
||||
return false;
|
||||
|
||||
std::string::const_iterator it = key_name.begin();
|
||||
uint32_t cp = utf8::next(it, key_name.end());
|
||||
|
||||
// Check if _name contains exactly one (UTF-8 encoded) character.
|
||||
if( it != key_name.end() )
|
||||
return false;
|
||||
|
||||
// C0 and C1 control characters are not printable.
|
||||
if( cp <= 0x1f || (0x7f <= cp && cp <= 0x9f) )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace canvas
|
||||
} // namespace simgear
|
||||
81
simgear/canvas/events/KeyboardEvent.hxx
Normal file
81
simgear/canvas/events/KeyboardEvent.hxx
Normal file
@@ -0,0 +1,81 @@
|
||||
///@file
|
||||
/// Keyboard 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_KEYBOARD_EVENT_HXX_
|
||||
#define CANVAS_KEYBOARD_EVENT_HXX_
|
||||
|
||||
#include "DeviceEvent.hxx"
|
||||
|
||||
namespace simgear
|
||||
{
|
||||
namespace canvas
|
||||
{
|
||||
|
||||
/**
|
||||
* Keyboard (button up/down) event
|
||||
*/
|
||||
class KeyboardEvent:
|
||||
public DeviceEvent
|
||||
{
|
||||
public:
|
||||
|
||||
enum DOMKeyLocation
|
||||
{
|
||||
DOM_KEY_LOCATION_STANDARD = 0,
|
||||
DOM_KEY_LOCATION_LEFT,
|
||||
DOM_KEY_LOCATION_RIGHT,
|
||||
DOM_KEY_LOCATION_NUMPAD
|
||||
};
|
||||
|
||||
KeyboardEvent();
|
||||
KeyboardEvent(const osgGA::GUIEventAdapter& ea);
|
||||
|
||||
void setKey(uint32_t key);
|
||||
void setUnmodifiedKey(uint32_t key);
|
||||
void setRepeat(bool repeat);
|
||||
|
||||
std::string key() const;
|
||||
DOMKeyLocation location() const;
|
||||
bool repeat() const { return _repeat; }
|
||||
|
||||
uint32_t charCode() const { return _key; }
|
||||
uint32_t keyCode() const { return _unmodified_key; }
|
||||
|
||||
/// Whether the key which has triggered this event is a modifier
|
||||
bool isModifier() const;
|
||||
|
||||
/// Whether this events represents an input of a printable character
|
||||
bool isPrint() const;
|
||||
|
||||
protected:
|
||||
uint32_t _key, //!< Key identifier for this event
|
||||
_unmodified_key; //!< Virtual key identifier without any
|
||||
// modifiers applied
|
||||
bool _repeat; //!< If key has been depressed long enough to
|
||||
// generate key repetition
|
||||
|
||||
mutable std::string _name; //!< Printable representation/name
|
||||
mutable uint8_t _location; //!< Location of the key on the keyboard
|
||||
|
||||
};
|
||||
|
||||
} // namespace canvas
|
||||
} // namespace simgear
|
||||
|
||||
#endif /* CANVAS_KEYBOARD_EVENT_HXX_ */
|
||||
@@ -17,6 +17,7 @@
|
||||
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
|
||||
#include "MouseEvent.hxx"
|
||||
#include <osgGA/GUIEventAdapter>
|
||||
|
||||
namespace simgear
|
||||
{
|
||||
@@ -27,7 +28,6 @@ namespace canvas
|
||||
MouseEvent::MouseEvent():
|
||||
button(0),
|
||||
buttons(0),
|
||||
modifiers(0),
|
||||
click_count(0)
|
||||
{
|
||||
|
||||
@@ -35,13 +35,11 @@ namespace canvas
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
MouseEvent::MouseEvent(const osgGA::GUIEventAdapter& ea):
|
||||
DeviceEvent(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 )
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
///@file Mouse event
|
||||
///@file
|
||||
/// Mouse event
|
||||
//
|
||||
// Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com>
|
||||
//
|
||||
@@ -19,16 +20,18 @@
|
||||
#ifndef CANVAS_MOUSE_EVENT_HXX_
|
||||
#define CANVAS_MOUSE_EVENT_HXX_
|
||||
|
||||
#include <simgear/canvas/CanvasEvent.hxx>
|
||||
#include <osgGA/GUIEventAdapter>
|
||||
#include "DeviceEvent.hxx"
|
||||
|
||||
namespace simgear
|
||||
{
|
||||
namespace canvas
|
||||
{
|
||||
|
||||
/**
|
||||
* Mouse (button/move/wheel) event
|
||||
*/
|
||||
class MouseEvent:
|
||||
public Event
|
||||
public DeviceEvent
|
||||
{
|
||||
public:
|
||||
MouseEvent();
|
||||
@@ -55,18 +58,16 @@ namespace canvas
|
||||
|
||||
int getButton() const { return button; }
|
||||
int getButtonMask() const { return buttons; }
|
||||
int getModifiers() const { return modifiers; }
|
||||
|
||||
int getCurrentClickCount() const { return click_count; }
|
||||
|
||||
osg::Vec2f screen_pos, //<! Position in screen coordinates
|
||||
client_pos, //<! Position in window/canvas coordinates
|
||||
local_pos, //<! Position in local/element coordinates
|
||||
osg::Vec2f screen_pos, //!< Position in screen coordinates
|
||||
client_pos, //!< Position in window/canvas coordinates
|
||||
local_pos, //!< Position in local/element coordinates
|
||||
delta;
|
||||
int button, //<! Button for this event
|
||||
buttons, //<! Current button state
|
||||
modifiers, //<! Keyboard modifier state
|
||||
click_count; //<! Current click count
|
||||
int button, //!< Button for this event
|
||||
buttons, //!< Current button state
|
||||
click_count; //!< Current click count
|
||||
};
|
||||
|
||||
} // namespace canvas
|
||||
|
||||
78
simgear/canvas/events/input_event_demo.cxx
Normal file
78
simgear/canvas/events/input_event_demo.cxx
Normal file
@@ -0,0 +1,78 @@
|
||||
// Keyboard event demo. Press some keys and get some info...
|
||||
//
|
||||
// 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 "KeyboardEvent.hxx"
|
||||
|
||||
#include <osgViewer/Viewer>
|
||||
#include <iostream>
|
||||
|
||||
class DemoEventHandler:
|
||||
public osgGA::GUIEventHandler
|
||||
{
|
||||
public:
|
||||
bool handle( const osgGA::GUIEventAdapter& ea,
|
||||
osgGA::GUIActionAdapter&,
|
||||
osg::Object*,
|
||||
osg::NodeVisitor* )
|
||||
{
|
||||
switch( ea.getEventType() )
|
||||
{
|
||||
case osgGA::GUIEventAdapter::PUSH:
|
||||
case osgGA::GUIEventAdapter::RELEASE:
|
||||
case osgGA::GUIEventAdapter::DRAG:
|
||||
case osgGA::GUIEventAdapter::MOVE:
|
||||
case osgGA::GUIEventAdapter::SCROLL:
|
||||
return handleMouse(ea);
|
||||
case osgGA::GUIEventAdapter::KEYDOWN:
|
||||
case osgGA::GUIEventAdapter::KEYUP:
|
||||
return handleKeyboard(ea);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
bool handleMouse(const osgGA::GUIEventAdapter&)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool handleKeyboard(const osgGA::GUIEventAdapter& ea)
|
||||
{
|
||||
simgear::canvas::KeyboardEvent evt(ea);
|
||||
std::cout << evt.getTypeString() << " '" << evt.key() << "'"
|
||||
<< ", loc=" << evt.location()
|
||||
<< ", char=" << evt.charCode()
|
||||
<< ", key=" << evt.keyCode()
|
||||
<< (evt.isPrint() ? ", printable" : "")
|
||||
<< std::endl;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
int main()
|
||||
{
|
||||
osgViewer::Viewer viewer;
|
||||
|
||||
osg::ref_ptr<DemoEventHandler> handler( new DemoEventHandler );
|
||||
viewer.addEventHandler(handler);
|
||||
|
||||
viewer.setUpViewInWindow(100, 100, 200, 100, 0);
|
||||
viewer.setRunMaxFrameRate(5);
|
||||
return viewer.run();
|
||||
}
|
||||
43
simgear/canvas/layout/AlignFlag_values.hxx
Normal file
43
simgear/canvas/layout/AlignFlag_values.hxx
Normal file
@@ -0,0 +1,43 @@
|
||||
///@file
|
||||
/// Enumeration of layout alignment flags.
|
||||
//
|
||||
// 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 ALIGN_ENUM_MAPPING
|
||||
# error "Only include with ALIGN_ENUM_MAPPING defined!"
|
||||
#endif
|
||||
|
||||
ALIGN_ENUM_MAPPING(AlignFill, 0, Use all available space)
|
||||
|
||||
ALIGN_ENUM_MAPPING(AlignLeft, 0x01, Align with left edge)
|
||||
ALIGN_ENUM_MAPPING(AlignRight, 0x02, Align with right edge)
|
||||
ALIGN_ENUM_MAPPING(AlignHCenter, 0x04, Center horizontally in available space)
|
||||
|
||||
ALIGN_ENUM_MAPPING(AlignTop, 0x20, Align with top edge)
|
||||
ALIGN_ENUM_MAPPING(AlignBottom, 0x40, Align with bottom edge)
|
||||
ALIGN_ENUM_MAPPING(AlignVCenter, 0x80, Center vertically in available space)
|
||||
|
||||
ALIGN_ENUM_MAPPING( AlignCenter,
|
||||
AlignVCenter | AlignHCenter,
|
||||
Center both vertically and horizontally )
|
||||
|
||||
ALIGN_ENUM_MAPPING( AlignHorizontal_Mask,
|
||||
AlignLeft | AlignRight | AlignHCenter,
|
||||
Mask of all horizontal alignment flags )
|
||||
ALIGN_ENUM_MAPPING( AlignVertical_Mask,
|
||||
AlignTop | AlignBottom | AlignVCenter,
|
||||
Mask of all vertical alignment flags )
|
||||
@@ -46,9 +46,11 @@ namespace canvas
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void BoxLayout::addItem(const LayoutItemRef& item, int stretch)
|
||||
void BoxLayout::addItem( const LayoutItemRef& item,
|
||||
int stretch,
|
||||
uint8_t alignment )
|
||||
{
|
||||
insertItem(-1, item, stretch);
|
||||
insertItem(-1, item, stretch, alignment);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
@@ -64,14 +66,24 @@ namespace canvas
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void BoxLayout::insertItem(int index, const LayoutItemRef& item, int stretch)
|
||||
void BoxLayout::insertItem( int index,
|
||||
const LayoutItemRef& item,
|
||||
int stretch,
|
||||
uint8_t alignment )
|
||||
{
|
||||
ItemData item_data = {0};
|
||||
item_data.layout_item = item;
|
||||
item_data.stretch = std::max(0, stretch);
|
||||
|
||||
item->setCanvas(_canvas);
|
||||
item->setParent(this);
|
||||
if( alignment != AlignFill )
|
||||
item->setAlignment(alignment);
|
||||
|
||||
if( SGWeakReferenced::count(this) )
|
||||
item->setParent(this);
|
||||
else
|
||||
SG_LOG( SG_GUI,
|
||||
SG_WARN,
|
||||
"Adding item to expired or non-refcounted layout" );
|
||||
|
||||
if( index < 0 )
|
||||
_layout_items.push_back(item_data);
|
||||
@@ -122,6 +134,7 @@ namespace canvas
|
||||
LayoutItems::iterator it = _layout_items.begin() + index;
|
||||
LayoutItemRef item = it->layout_item;
|
||||
item->onRemove();
|
||||
item->setParent(LayoutItemWeakRef());
|
||||
_layout_items.erase(it);
|
||||
|
||||
invalidate();
|
||||
@@ -137,6 +150,7 @@ namespace canvas
|
||||
++it )
|
||||
{
|
||||
it->layout_item->onRemove();
|
||||
it->layout_item->setParent(LayoutItemWeakRef());
|
||||
}
|
||||
_layout_items.clear();
|
||||
invalidate();
|
||||
@@ -223,26 +237,6 @@ namespace canvas
|
||||
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)
|
||||
{
|
||||
@@ -272,16 +266,23 @@ namespace canvas
|
||||
|
||||
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.visible = item.isVisible();
|
||||
if( !item_data.visible )
|
||||
continue;
|
||||
|
||||
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();
|
||||
|
||||
uint8_t alignment_mask = horiz()
|
||||
? AlignHorizontal_Mask
|
||||
: AlignVertical_Mask;
|
||||
item_data.has_align = (item.alignment() & alignment_mask) != 0;
|
||||
|
||||
if( !dynamic_cast<SpacerItem*>(item_data.layout_item.get()) )
|
||||
{
|
||||
if( is_first )
|
||||
@@ -297,9 +298,9 @@ namespace canvas
|
||||
}
|
||||
|
||||
// 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);
|
||||
SGMisc<int>::addClipOverflowInplace(min_size.x(), item_data.min_size);
|
||||
SGMisc<int>::addClipOverflowInplace(max_size.x(), item_data.max_size);
|
||||
SGMisc<int>::addClipOverflowInplace(size_hint.x(), item_data.size_hint);
|
||||
|
||||
// Take maximum in fixed (non-layouted) direction
|
||||
min_size.y() = std::max( min_size.y(),
|
||||
@@ -312,9 +313,9 @@ namespace canvas
|
||||
_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);
|
||||
SGMisc<int>::addClipOverflowInplace(min_size.x(), _layout_data.padding);
|
||||
SGMisc<int>::addClipOverflowInplace(max_size.x(), _layout_data.padding);
|
||||
SGMisc<int>::addClipOverflowInplace(size_hint.x(), _layout_data.padding);
|
||||
|
||||
_layout_data.min_size = min_size.x();
|
||||
_layout_data.max_size = max_size.x();
|
||||
@@ -348,6 +349,9 @@ namespace canvas
|
||||
for(size_t i = 0; i < _layout_items.size(); ++i)
|
||||
{
|
||||
ItemData const& data = _layout_items[i];
|
||||
if( !data.visible )
|
||||
continue;
|
||||
|
||||
_hfw_height = std::max(_hfw_height, data.hfw(data.size));
|
||||
_hfw_min_height = std::max(_hfw_min_height, data.mhfw(data.size));
|
||||
}
|
||||
@@ -357,6 +361,9 @@ namespace canvas
|
||||
for(size_t i = 0; i < _layout_items.size(); ++i)
|
||||
{
|
||||
ItemData const& data = _layout_items[i];
|
||||
if( !data.visible )
|
||||
continue;
|
||||
|
||||
_hfw_height += data.hfw(w) + data.padding_orig;
|
||||
_hfw_min_height += data.mhfw(w) + data.padding_orig;
|
||||
}
|
||||
@@ -386,6 +393,27 @@ namespace canvas
|
||||
return _max_size;
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
int BoxLayout::heightForWidthImpl(int w) const
|
||||
{
|
||||
if( !hasHeightForWidth() )
|
||||
return -1;
|
||||
|
||||
updateWFHCache(w);
|
||||
return _hfw_height;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
int BoxLayout::minimumHeightForWidthImpl(int w) const
|
||||
{
|
||||
if( !hasHeightForWidth() )
|
||||
return -1;
|
||||
|
||||
updateWFHCache(w);
|
||||
return _hfw_min_height;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void BoxLayout::doLayout(const SGRecti& geom)
|
||||
{
|
||||
@@ -406,6 +434,9 @@ namespace canvas
|
||||
for(size_t i = 0; i < _layout_items.size(); ++i)
|
||||
{
|
||||
ItemData& data = _layout_items[i];
|
||||
if( !data.visible )
|
||||
continue;
|
||||
|
||||
if( data.has_hfw )
|
||||
{
|
||||
int w = SGMisc<int>::clip( geom.width(),
|
||||
@@ -434,7 +465,10 @@ namespace canvas
|
||||
_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 size( 0,
|
||||
// Always assign all available space. Alignment handles final
|
||||
// size.
|
||||
(geom.size().*_get_fixed_coord)() );
|
||||
SGVec2i cur_pos( (geom.pos().*_get_layout_coord)(),
|
||||
(geom.pos().*_get_fixed_coord)() );
|
||||
|
||||
@@ -445,17 +479,11 @@ namespace canvas
|
||||
for(size_t i = 0; i < _layout_items.size(); ++i)
|
||||
{
|
||||
ItemData const& data = _layout_items[i];
|
||||
if( !data.visible )
|
||||
continue;
|
||||
|
||||
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;
|
||||
size.x() = data.size;
|
||||
|
||||
data.layout_item->setGeometry(SGRecti(
|
||||
(cur_pos.*_get_layout_coord)(),
|
||||
@@ -466,10 +494,16 @@ namespace canvas
|
||||
|
||||
if( !reverse )
|
||||
cur_pos.x() += data.size;
|
||||
cur_pos.y() -= offset_fixed;
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void BoxLayout::visibilityChanged(bool visible)
|
||||
{
|
||||
for(size_t i = 0; i < _layout_items.size(); ++i)
|
||||
callSetVisibleInternal(_layout_items[i].layout_item.get(), visible);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
HBoxLayout::HBoxLayout():
|
||||
BoxLayout(LeftToRight)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Align items horizontally or vertically in a box
|
||||
/// @file
|
||||
//
|
||||
// Copyright (C) 2014 Thomas Geymayer <tomgey@gmail.com>
|
||||
//
|
||||
@@ -26,6 +26,11 @@ namespace simgear
|
||||
namespace canvas
|
||||
{
|
||||
|
||||
/**
|
||||
* Align LayoutItems horizontally or vertically in a box.
|
||||
*
|
||||
* @see http://qt-project.org/doc/qt-4.8/qboxlayout.html#details
|
||||
*/
|
||||
class BoxLayout:
|
||||
public Layout
|
||||
{
|
||||
@@ -44,13 +49,18 @@ namespace canvas
|
||||
|
||||
virtual void addItem(const LayoutItemRef& item);
|
||||
|
||||
void addItem(const LayoutItemRef& item, int stretch);
|
||||
void addItem( const LayoutItemRef& item,
|
||||
int stretch,
|
||||
uint8_t alignment = 0 );
|
||||
|
||||
void addStretch(int stretch = 0);
|
||||
|
||||
void addSpacing(int size);
|
||||
|
||||
void insertItem(int index, const LayoutItemRef& item, int stretch = 0);
|
||||
void insertItem( int index,
|
||||
const LayoutItemRef& item,
|
||||
int stretch = 0,
|
||||
uint8_t alignment = 0 );
|
||||
|
||||
void insertStretch(int index, int stretch = 0);
|
||||
|
||||
@@ -86,8 +96,6 @@ namespace canvas
|
||||
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);
|
||||
|
||||
@@ -96,9 +104,9 @@ namespace canvas
|
||||
protected:
|
||||
|
||||
typedef const int& (SGVec2i::*CoordGetter)() const;
|
||||
CoordGetter _get_layout_coord, //<! getter for coordinate in layout
|
||||
CoordGetter _get_layout_coord, //!< getter for coordinate in layout
|
||||
// direction
|
||||
_get_fixed_coord; //<! getter for coordinate in secondary
|
||||
_get_fixed_coord; //!< getter for coordinate in secondary
|
||||
// (fixed) direction
|
||||
|
||||
int _padding;
|
||||
@@ -121,7 +129,12 @@ namespace canvas
|
||||
virtual SGVec2i minimumSizeImpl() const;
|
||||
virtual SGVec2i maximumSizeImpl() const;
|
||||
|
||||
virtual int heightForWidthImpl(int w) const;
|
||||
virtual int minimumHeightForWidthImpl(int w) const;
|
||||
|
||||
virtual void doLayout(const SGRecti& geom);
|
||||
|
||||
virtual void visibilityChanged(bool visible);
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
include (SimGearComponent)
|
||||
|
||||
set(HEADERS
|
||||
AlignFlag_values.hxx
|
||||
BoxLayout.hxx
|
||||
Layout.hxx
|
||||
LayoutItem.hxx
|
||||
|
||||
@@ -24,36 +24,6 @@ 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)
|
||||
{
|
||||
@@ -74,6 +44,19 @@ namespace canvas
|
||||
takeAt(0);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
SGRecti Layout::alignmentRect(const SGRecti& geom) const
|
||||
{
|
||||
return alignment() == AlignFill
|
||||
// Without explicit alignment (default == AlignFill) use the whole
|
||||
// available space and let the layout and its items distribute the
|
||||
// excess space.
|
||||
? geom
|
||||
|
||||
// Otherwise align according to flags.
|
||||
: LayoutItem::alignmentRect(geom);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Layout::ItemData::reset()
|
||||
{
|
||||
@@ -85,6 +68,8 @@ namespace canvas
|
||||
padding = 0;
|
||||
size = 0;
|
||||
stretch = 0;
|
||||
visible = false;
|
||||
has_align = false;
|
||||
has_hfw = false;
|
||||
done = false;
|
||||
}
|
||||
@@ -108,19 +93,28 @@ namespace canvas
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Layout::safeAdd(int& a, int b)
|
||||
Layout::Layout():
|
||||
_num_not_done(0),
|
||||
_sum_stretch(0),
|
||||
_space_stretch(0),
|
||||
_space_left(0)
|
||||
{
|
||||
if( SGLimits<int>::max() - b < a )
|
||||
a = SGLimits<int>::max();
|
||||
else
|
||||
a += b;
|
||||
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Layout::contentsRectChanged(const SGRecti& rect)
|
||||
{
|
||||
doLayout(rect);
|
||||
|
||||
_flags &= ~LAYOUT_DIRTY;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Layout::distribute(std::vector<ItemData>& items, const ItemData& space)
|
||||
{
|
||||
const int num_children = static_cast<int>(items.size());
|
||||
_num_not_done = num_children;
|
||||
_num_not_done = 0;
|
||||
|
||||
SG_LOG( SG_GUI,
|
||||
SG_DEBUG,
|
||||
@@ -148,6 +142,9 @@ namespace canvas
|
||||
for(int i = 0; i < num_children; ++i)
|
||||
{
|
||||
ItemData& d = items[i];
|
||||
if( !d.visible )
|
||||
continue;
|
||||
|
||||
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);
|
||||
@@ -162,10 +159,8 @@ namespace canvas
|
||||
);
|
||||
|
||||
if( d.done )
|
||||
{
|
||||
_num_not_done -= 1;
|
||||
continue;
|
||||
}
|
||||
_num_not_done += 1;
|
||||
|
||||
if( d.stretch > 0 )
|
||||
{
|
||||
@@ -191,6 +186,8 @@ namespace canvas
|
||||
for(int i = 0; i < num_children; ++i)
|
||||
{
|
||||
ItemData& d = items[i];
|
||||
if( !d.visible )
|
||||
continue;
|
||||
|
||||
SG_LOG(
|
||||
SG_GUI,
|
||||
@@ -265,18 +262,59 @@ namespace canvas
|
||||
else
|
||||
{
|
||||
_space_left = space.size - space.max_size;
|
||||
int num_align = 0;
|
||||
for(int i = 0; i < num_children; ++i)
|
||||
{
|
||||
if( !items[i].visible )
|
||||
continue;
|
||||
|
||||
_num_not_done += 1;
|
||||
|
||||
if( items[i].has_align )
|
||||
num_align += 1;
|
||||
}
|
||||
|
||||
SG_LOG(
|
||||
SG_GUI,
|
||||
SG_DEBUG,
|
||||
"Distributing excess space:"
|
||||
" not_done=" << _num_not_done
|
||||
<< ", num_align=" << num_align
|
||||
<< ", space_left=" << _space_left
|
||||
);
|
||||
|
||||
for(int i = 0; i < num_children; ++i)
|
||||
{
|
||||
ItemData& d = items[i];
|
||||
if( !d.visible )
|
||||
continue;
|
||||
|
||||
d.padding = d.padding_orig;
|
||||
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);
|
||||
int space_add = 0;
|
||||
|
||||
_space_left -= d.padding - d.padding_orig;
|
||||
_num_not_done -= 1;
|
||||
if( d.has_align )
|
||||
{
|
||||
// Equally distribute superfluous space and let each child items
|
||||
// alignment handle the exact usage.
|
||||
space_add = _space_left / num_align;
|
||||
num_align -= 1;
|
||||
|
||||
d.size += space_add;
|
||||
}
|
||||
else if( num_align <= 0 )
|
||||
{
|
||||
// Add superfluous space as padding
|
||||
space_add = _space_left
|
||||
// Padding after last child...
|
||||
/ (_num_not_done + 1);
|
||||
_num_not_done -= 1;
|
||||
|
||||
d.padding += space_add;
|
||||
}
|
||||
|
||||
_space_left -= space_add;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -284,10 +322,11 @@ namespace canvas
|
||||
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 );
|
||||
if( d.visible )
|
||||
SG_LOG(SG_GUI, SG_DEBUG, i << ") pad=" << d.padding
|
||||
<< ", size= " << d.size);
|
||||
else
|
||||
SG_LOG(SG_GUI, SG_DEBUG, i << ") [hidden]");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Basic class for canvas layouts
|
||||
/// @file
|
||||
//
|
||||
// Copyright (C) 2014 Thomas Geymayer <tomgey@gmail.com>
|
||||
//
|
||||
@@ -27,15 +27,13 @@ namespace simgear
|
||||
namespace canvas
|
||||
{
|
||||
|
||||
/**
|
||||
* Base class for all Canvas layouts.
|
||||
*/
|
||||
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;
|
||||
@@ -71,11 +69,22 @@ namespace canvas
|
||||
*/
|
||||
virtual void clear();
|
||||
|
||||
/**
|
||||
* Get the actual geometry of this layout given the rectangle \a geom
|
||||
* taking into account the alignment flags and size hints. For layouts,
|
||||
* if no alignment (different to AlignFill) is set, the whole area is
|
||||
* used. Excess space is distributed by the layouting algorithm and
|
||||
* handled by the individual children.
|
||||
*
|
||||
* @param geom Area available to this layout.
|
||||
* @return The resulting geometry for this layout.
|
||||
*/
|
||||
virtual SGRecti alignmentRect(const SGRecti& geom) const;
|
||||
|
||||
protected:
|
||||
enum LayoutFlags
|
||||
{
|
||||
LAYOUT_DIRTY = LayoutItem::LAST_FLAG << 1,
|
||||
LAST_FLAG = LAYOUT_DIRTY
|
||||
LAST_FLAG = LayoutItem::LAST_FLAG
|
||||
};
|
||||
|
||||
struct ItemData
|
||||
@@ -84,12 +93,14 @@ namespace canvas
|
||||
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
|
||||
padding_orig, //!< original padding as specified by the user
|
||||
padding, //!< padding before element (layouted)
|
||||
size, //!< layouted size
|
||||
stretch; //!< stretch factor
|
||||
bool visible : 1,
|
||||
has_align: 1, //!< Has alignment factor set (!= AlignFill)
|
||||
has_hfw : 1, //!< height for width
|
||||
done : 1; //!< layouting done
|
||||
|
||||
/** Clear values (reset to default/empty state) */
|
||||
void reset();
|
||||
@@ -98,16 +109,15 @@ namespace canvas
|
||||
int mhfw(int w) const;
|
||||
};
|
||||
|
||||
Layout();
|
||||
|
||||
virtual void contentsRectChanged(const SGRecti& rect);
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
@@ -115,12 +125,12 @@ namespace canvas
|
||||
|
||||
private:
|
||||
|
||||
int _num_not_done, //<! number of children not layouted yet
|
||||
_sum_stretch, //<! sum of stretch factors of all not yet layouted
|
||||
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
|
||||
_space_stretch,//!< space currently assigned to all not yet layouted
|
||||
// stretchable children
|
||||
_space_left; //<! remaining space not used by any child yet
|
||||
_space_left; //!< remaining space not used by any child yet
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -23,12 +23,61 @@ namespace simgear
|
||||
{
|
||||
namespace canvas
|
||||
{
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
Margins::Margins(int m):
|
||||
l(m), t(m), r(m), b(m)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
Margins::Margins(int h, int v):
|
||||
l(h), t(v),
|
||||
r(h), b(v)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
Margins::Margins(int l, int t, int r, int b):
|
||||
l(l), t(t), r(r), b(b)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
int Margins::horiz() const
|
||||
{
|
||||
return l + r;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
int Margins::vert() const
|
||||
{
|
||||
return t + b;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
SGVec2i Margins::size() const
|
||||
{
|
||||
return SGVec2i(horiz(), vert());
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
bool Margins::isNull() const
|
||||
{
|
||||
return l == 0 && t == 0 && r == 0 && b == 0;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
const SGVec2i LayoutItem::MAX_SIZE( SGLimits<int>::max(),
|
||||
SGLimits<int>::max() );
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
LayoutItem::LayoutItem():
|
||||
_flags(0),
|
||||
_alignment(AlignFill),
|
||||
_flags(VISIBLE),
|
||||
_size_hint(0, 0),
|
||||
_min_size(0, 0),
|
||||
_max_size(MAX_SIZE)
|
||||
@@ -42,6 +91,44 @@ namespace canvas
|
||||
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void LayoutItem::setContentsMargins(const Margins& margins)
|
||||
{
|
||||
_margins = margins;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void LayoutItem::setContentsMargins(int left, int top, int right, int bottom)
|
||||
{
|
||||
_margins.l = left;
|
||||
_margins.t = top;
|
||||
_margins.r = right;
|
||||
_margins.b = bottom;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void LayoutItem::setContentsMargin(int margin)
|
||||
{
|
||||
setContentsMargins(margin, margin, margin, margin);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
Margins LayoutItem::getContentsMargins() const
|
||||
{
|
||||
return _margins;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
SGRecti LayoutItem::contentsRect() const
|
||||
{
|
||||
return SGRecti(
|
||||
_geometry.x() + _margins.l,
|
||||
_geometry.y() + _margins.t,
|
||||
std::max(0, _geometry.width() - _margins.horiz()),
|
||||
std::max(0, _geometry.height() - _margins.vert())
|
||||
);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
SGVec2i LayoutItem::sizeHint() const
|
||||
{
|
||||
@@ -51,7 +138,7 @@ namespace canvas
|
||||
_flags &= ~SIZE_HINT_DIRTY;
|
||||
}
|
||||
|
||||
return _size_hint;
|
||||
return addClipOverflow(_size_hint, _margins.size());
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
@@ -63,7 +150,7 @@ namespace canvas
|
||||
_flags &= ~MINIMUM_SIZE_DIRTY;
|
||||
}
|
||||
|
||||
return _min_size;
|
||||
return addClipOverflow(_min_size, _margins.size());
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
@@ -75,7 +162,7 @@ namespace canvas
|
||||
_flags &= ~MAXIMUM_SIZE_DIRTY;
|
||||
}
|
||||
|
||||
return _max_size;
|
||||
return addClipOverflow(_max_size, _margins.size());
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
@@ -87,19 +174,60 @@ namespace canvas
|
||||
//----------------------------------------------------------------------------
|
||||
int LayoutItem::heightForWidth(int w) const
|
||||
{
|
||||
return -1;
|
||||
int h = heightForWidthImpl(w - _margins.horiz());
|
||||
return h < 0 ? -1 : SGMisc<int>::addClipOverflow(h, _margins.vert());
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
int LayoutItem::minimumHeightForWidth(int w) const
|
||||
{
|
||||
return heightForWidth(w);
|
||||
int h = minimumHeightForWidthImpl(w - _margins.horiz());
|
||||
return h < 0 ? -1 : SGMisc<int>::addClipOverflow(h, _margins.vert());
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void LayoutItem::setAlignment(uint8_t align)
|
||||
{
|
||||
if( align == _alignment )
|
||||
return;
|
||||
|
||||
_alignment = align;
|
||||
invalidateParent();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
uint8_t LayoutItem::alignment() const
|
||||
{
|
||||
return _alignment;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void LayoutItem::setVisible(bool visible)
|
||||
{
|
||||
if( visible )
|
||||
_flags &= ~EXPLICITLY_HIDDEN;
|
||||
else
|
||||
_flags |= EXPLICITLY_HIDDEN;
|
||||
|
||||
setVisibleInternal(visible);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
bool LayoutItem::isVisible() const
|
||||
{
|
||||
return _flags & VISIBLE;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
bool LayoutItem::isExplicitlyHidden() const
|
||||
{
|
||||
return _flags & EXPLICITLY_HIDDEN;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void LayoutItem::invalidate()
|
||||
{
|
||||
_flags |= SIZE_INFO_DIRTY;
|
||||
_flags |= SIZE_INFO_DIRTY | LAYOUT_DIRTY;
|
||||
invalidateParent();
|
||||
}
|
||||
|
||||
@@ -111,10 +239,24 @@ namespace canvas
|
||||
parent->invalidate();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void LayoutItem::update()
|
||||
{
|
||||
if( (_flags & LAYOUT_DIRTY) && isVisible() )
|
||||
contentsRectChanged( contentsRect() );
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void LayoutItem::setGeometry(const SGRecti& geom)
|
||||
{
|
||||
_geometry = geom;
|
||||
SGRecti ar = alignmentRect(geom);
|
||||
if( ar != _geometry )
|
||||
{
|
||||
_geometry = ar;
|
||||
_flags |= LAYOUT_DIRTY;
|
||||
}
|
||||
|
||||
update();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
@@ -123,6 +265,41 @@ namespace canvas
|
||||
return _geometry;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
SGRecti LayoutItem::alignmentRect(const SGRecti& geom) const
|
||||
{
|
||||
uint8_t halign = alignment() & AlignHorizontal_Mask,
|
||||
valign = alignment() & AlignVertical_Mask;
|
||||
|
||||
// Size
|
||||
SGVec2i size = sizeHint();
|
||||
|
||||
if( halign == AlignFill )
|
||||
size.x() = maximumSize().x();
|
||||
size.x() = std::min(size.x(), geom.width());
|
||||
|
||||
if( valign == AlignFill )
|
||||
size.y() = maximumSize().y();
|
||||
else if( hasHeightForWidth() )
|
||||
size.y() = heightForWidth(size.x());
|
||||
size.y() = std::min(size.y(), geom.height());
|
||||
|
||||
// Position
|
||||
SGVec2i pos = geom.pos();
|
||||
|
||||
if( halign & AlignRight )
|
||||
pos.x() += geom.width() - size.x();
|
||||
else if( !(halign & AlignLeft) )
|
||||
pos.x() += (geom.width() - size.x()) / 2;
|
||||
|
||||
if( valign & AlignBottom )
|
||||
pos.y() += geom.height() - size.y();
|
||||
else if( !(valign & AlignTop) )
|
||||
pos.y() += (geom.height() - size.y()) / 2;
|
||||
|
||||
return SGRecti(pos, pos + size);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void LayoutItem::setCanvas(const CanvasWeakPtr& canvas)
|
||||
{
|
||||
@@ -140,7 +317,14 @@ namespace canvas
|
||||
{
|
||||
_parent = parent;
|
||||
LayoutItemRef parent_ref = parent.lock();
|
||||
setCanvas(parent_ref ? parent_ref->_canvas : CanvasWeakPtr());
|
||||
|
||||
if( parent_ref )
|
||||
// Only change the canvas if there is a new parent. If the item is removed
|
||||
// keep the old canvas, as it may be used for example during the call to
|
||||
// onRemove.
|
||||
setCanvas(parent_ref->_canvas);
|
||||
|
||||
setVisibleInternal(!parent_ref || parent_ref->isVisible());
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
@@ -167,5 +351,43 @@ namespace canvas
|
||||
return _max_size;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
int LayoutItem::heightForWidthImpl(int w) const
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
int LayoutItem::minimumHeightForWidthImpl(int w) const
|
||||
{
|
||||
return heightForWidth(w);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void LayoutItem::setVisibleInternal(bool visible)
|
||||
{
|
||||
LayoutItemRef parent = getParent();
|
||||
if( isExplicitlyHidden() || (parent && !parent->isVisible()) )
|
||||
visible = false;
|
||||
|
||||
if( isVisible() == visible )
|
||||
return;
|
||||
|
||||
invalidateParent();
|
||||
|
||||
if( visible )
|
||||
_flags |= VISIBLE;
|
||||
else
|
||||
_flags &= ~VISIBLE;
|
||||
|
||||
visibilityChanged(visible);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void LayoutItem::callSetVisibleInternal(LayoutItem* item, bool visible)
|
||||
{
|
||||
item->setVisibleInternal(visible);
|
||||
}
|
||||
|
||||
} // namespace canvas
|
||||
} // namespace simgear
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
///@file Basic element for layouting canvas elements
|
||||
///@file
|
||||
/// Basic element for layouting canvas elements.
|
||||
//
|
||||
// Copyright (C) 2014 Thomas Geymayer <tomgey@gmail.com>
|
||||
//
|
||||
@@ -34,6 +35,65 @@ namespace canvas
|
||||
typedef SGSharedPtr<LayoutItem> LayoutItemRef;
|
||||
typedef SGWeakPtr<LayoutItem> LayoutItemWeakRef;
|
||||
|
||||
/**
|
||||
* Holds the four margins for a rectangle.
|
||||
*/
|
||||
struct Margins
|
||||
{
|
||||
int l, t, r, b;
|
||||
|
||||
/**
|
||||
* Set all margins to the same value @a m.
|
||||
*/
|
||||
explicit Margins(int m = 0);
|
||||
|
||||
/**
|
||||
* Set horizontal and vertical margins to the same values @a h and @a v
|
||||
* respectively.
|
||||
*
|
||||
* @param h Horizontal margins
|
||||
* @param v Vertical margins
|
||||
*/
|
||||
Margins(int h, int v);
|
||||
|
||||
/**
|
||||
* Set the margins to the given values.
|
||||
*/
|
||||
Margins(int left, int top, int right, int bottom);
|
||||
|
||||
/**
|
||||
* Get the total horizontal margin (sum of left and right margin).
|
||||
*/
|
||||
int horiz() const;
|
||||
|
||||
/**
|
||||
* Get the total vertical margin (sum of top and bottom margin).
|
||||
*/
|
||||
int vert() const;
|
||||
|
||||
/**
|
||||
* Get total horizontal and vertical margin as vector.
|
||||
*/
|
||||
SGVec2i size() const;
|
||||
|
||||
/**
|
||||
* Returns true if all margins are 0.
|
||||
*/
|
||||
bool isNull() const;
|
||||
};
|
||||
|
||||
/**
|
||||
* Flags for LayoutItem alignment inside {@link Layout Layouts}.
|
||||
*
|
||||
* @note You can only use one horizontal and one vertical flag at the same.
|
||||
*/
|
||||
enum AlignmentFlag
|
||||
{
|
||||
#define ALIGN_ENUM_MAPPING(key, val, comment) key = val, /*!< comment */
|
||||
# include "AlignFlag_values.hxx"
|
||||
#undef ALIGN_ENUM_MAPPING
|
||||
};
|
||||
|
||||
/**
|
||||
* Base class for all layouting elements. Specializations either implement a
|
||||
* layouting algorithm or a widget.
|
||||
@@ -49,6 +109,49 @@ namespace canvas
|
||||
LayoutItem();
|
||||
virtual ~LayoutItem();
|
||||
|
||||
/**
|
||||
* Set the margins to use by the layout system around the item.
|
||||
*
|
||||
* The margins define the size of the clear area around an item. It
|
||||
* increases the size hints and reduces the size of the geometry()
|
||||
* available to child layouts and widgets.
|
||||
*
|
||||
* @see Margins
|
||||
*/
|
||||
void setContentsMargins(const Margins& margins);
|
||||
|
||||
/**
|
||||
* Set the individual margins.
|
||||
*
|
||||
* @see setContentsMargins(const Margins&)
|
||||
*/
|
||||
void setContentsMargins(int left, int top, int right, int bottom);
|
||||
|
||||
/**
|
||||
* Set all margins to the same value.
|
||||
*
|
||||
* @see setContentsMargins(const Margins&)
|
||||
*/
|
||||
void setContentsMargin(int margin);
|
||||
|
||||
/**
|
||||
* Get the currently used margins.
|
||||
*
|
||||
* @see setContentsMargins(const Margins&)
|
||||
* @see Margins
|
||||
*/
|
||||
Margins getContentsMargins() const;
|
||||
|
||||
/**
|
||||
* Get the area available to the contents.
|
||||
*
|
||||
* This is equal to the geometry() reduced by the sizes of the margins.
|
||||
*
|
||||
* @see setContentsMargins(const Margins&)
|
||||
* @see geometry()
|
||||
*/
|
||||
SGRecti contentsRect() const;
|
||||
|
||||
/**
|
||||
* Get the preferred size of this item.
|
||||
*/
|
||||
@@ -64,9 +167,60 @@ namespace canvas
|
||||
*/
|
||||
SGVec2i maximumSize() const;
|
||||
|
||||
/**
|
||||
* Returns true if this items preferred and minimum height depend on its
|
||||
* width.
|
||||
*
|
||||
* The default implementation returns false. Reimplement for items
|
||||
* providing height for width.
|
||||
*
|
||||
* @see heightForWidth()
|
||||
* @see minimumHeightForWidth()
|
||||
*/
|
||||
virtual bool hasHeightForWidth() const;
|
||||
virtual int heightForWidth(int w) const;
|
||||
virtual int minimumHeightForWidth(int w) const;
|
||||
|
||||
/**
|
||||
* Returns the preferred height for the given width @a w.
|
||||
*
|
||||
* Reimplement heightForWidthImpl() for items providing height for width.
|
||||
*
|
||||
* @see hasHeightForWidth()
|
||||
*/
|
||||
int heightForWidth(int w) const;
|
||||
|
||||
/**
|
||||
* Returns the minimum height for the given width @a w.
|
||||
*
|
||||
* Reimplement minimumHeightForWidthImpl() for items providing height for
|
||||
* width.
|
||||
*
|
||||
* @see hasHeightForWidth()
|
||||
*/
|
||||
int minimumHeightForWidth(int w) const;
|
||||
|
||||
/**
|
||||
* Set alignment of item within {@link Layout Layouts}.
|
||||
*
|
||||
* @param alignment Bitwise combination of vertical and horizontal
|
||||
* alignment flags.
|
||||
* @see AlignmentFlag
|
||||
*/
|
||||
void setAlignment(uint8_t alignment);
|
||||
|
||||
/**
|
||||
* Get all alignment flags.
|
||||
*
|
||||
* @see AlignmentFlag
|
||||
*/
|
||||
uint8_t alignment() const;
|
||||
|
||||
virtual void setVisible(bool visible);
|
||||
virtual bool isVisible() const;
|
||||
|
||||
bool isExplicitlyHidden() const;
|
||||
|
||||
void show() { setVisible(true); }
|
||||
void hide() { setVisible(false); }
|
||||
|
||||
/**
|
||||
* Mark all cached data as invalid and require it to be recalculated.
|
||||
@@ -74,10 +228,15 @@ namespace canvas
|
||||
virtual void invalidate();
|
||||
|
||||
/**
|
||||
* Mark all cached data of parent item as invalid (if it is known)
|
||||
* Mark all cached data of parent item as invalid (if the parent is set).
|
||||
*/
|
||||
void invalidateParent();
|
||||
|
||||
/**
|
||||
* Apply any changes not applied yet.
|
||||
*/
|
||||
void update();
|
||||
|
||||
/**
|
||||
* Set position and size of this element. For layouts this triggers a
|
||||
* recalculation of the layout.
|
||||
@@ -89,6 +248,20 @@ namespace canvas
|
||||
*/
|
||||
virtual SGRecti geometry() const;
|
||||
|
||||
/**
|
||||
* Get the actual geometry of this item given the rectangle \a geom
|
||||
* taking into account the alignment flags and size hints.
|
||||
*
|
||||
* @param geom Area available to this item.
|
||||
* @return The resulting geometry for this item.
|
||||
*
|
||||
* @see setAlignment()
|
||||
* @see minimumSize()
|
||||
* @see maximumSize()
|
||||
* @see sizeHint()
|
||||
*/
|
||||
virtual SGRecti alignmentRect(const SGRecti& geom) const;
|
||||
|
||||
/**
|
||||
* Set the canvas this item is attached to.
|
||||
*/
|
||||
@@ -124,13 +297,18 @@ namespace canvas
|
||||
SIZE_INFO_DIRTY = SIZE_HINT_DIRTY
|
||||
| MINIMUM_SIZE_DIRTY
|
||||
| MAXIMUM_SIZE_DIRTY,
|
||||
LAST_FLAG = MAXIMUM_SIZE_DIRTY
|
||||
EXPLICITLY_HIDDEN = MAXIMUM_SIZE_DIRTY << 1,
|
||||
VISIBLE = EXPLICITLY_HIDDEN << 1,
|
||||
LAYOUT_DIRTY = VISIBLE << 1,
|
||||
LAST_FLAG = LAYOUT_DIRTY
|
||||
};
|
||||
|
||||
CanvasWeakPtr _canvas;
|
||||
LayoutItemWeakRef _parent;
|
||||
|
||||
SGRecti _geometry;
|
||||
Margins _margins;
|
||||
uint8_t _alignment;
|
||||
|
||||
mutable uint32_t _flags;
|
||||
mutable SGVec2i _size_hint,
|
||||
@@ -141,6 +319,50 @@ namespace canvas
|
||||
virtual SGVec2i minimumSizeImpl() const;
|
||||
virtual SGVec2i maximumSizeImpl() const;
|
||||
|
||||
/**
|
||||
* Returns the preferred height for the given width @a w.
|
||||
*
|
||||
* The default implementation returns -1, indicating that the preferred
|
||||
* height is independent of the given width.
|
||||
*
|
||||
* Reimplement this function for items supporting height for width.
|
||||
*
|
||||
* @note Do not take margins into account, as this is already handled
|
||||
* before calling this function.
|
||||
*
|
||||
* @see hasHeightForWidth()
|
||||
*/
|
||||
virtual int heightForWidthImpl(int w) const;
|
||||
|
||||
/**
|
||||
* Returns the minimum height for the given width @a w.
|
||||
*
|
||||
* The default implementation returns -1, indicating that the minimum
|
||||
* height is independent of the given width.
|
||||
*
|
||||
* Reimplement this function for items supporting height for width.
|
||||
*
|
||||
* @note Do not take margins into account, as this is already handled
|
||||
* before calling this function.
|
||||
*
|
||||
* @see hasHeightForWidth()
|
||||
*/
|
||||
virtual int minimumHeightForWidthImpl(int w) const;
|
||||
|
||||
/**
|
||||
* @return whether the visibility has changed.
|
||||
*/
|
||||
void setVisibleInternal(bool visible);
|
||||
|
||||
virtual void contentsRectChanged(const SGRecti& rect) {};
|
||||
|
||||
virtual void visibilityChanged(bool visible) {}
|
||||
|
||||
/**
|
||||
* Allow calling the protected setVisibleImpl from derived classes
|
||||
*/
|
||||
static void callSetVisibleInternal(LayoutItem* item, bool visible);
|
||||
|
||||
};
|
||||
|
||||
} // namespace canvas
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "NasalWidget.hxx"
|
||||
|
||||
#include <simgear/canvas/Canvas.hxx>
|
||||
#include <simgear/nasal/cppbind/NasalContext.hxx>
|
||||
#include <simgear/nasal/cppbind/Ghost.hxx>
|
||||
|
||||
namespace simgear
|
||||
@@ -45,53 +46,12 @@ namespace canvas
|
||||
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));
|
||||
callMethod<void>("onRemove");
|
||||
}
|
||||
catch( std::exception const& ex )
|
||||
{
|
||||
@@ -101,7 +61,6 @@ namespace canvas
|
||||
"NasalWidget::onRemove: callback error: '" << ex.what() << "'"
|
||||
);
|
||||
}
|
||||
naFreeContext(c);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
@@ -192,22 +151,6 @@ namespace canvas
|
||||
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)
|
||||
{
|
||||
@@ -291,5 +234,62 @@ namespace canvas
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
int NasalWidget::heightForWidthImpl(int w) const
|
||||
{
|
||||
return callHeightForWidthFunc( _height_for_width.empty()
|
||||
? _min_height_for_width
|
||||
: _height_for_width, w );
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
int NasalWidget::minimumHeightForWidthImpl(int w) const
|
||||
{
|
||||
return callHeightForWidthFunc( _min_height_for_width.empty()
|
||||
? _height_for_width
|
||||
: _min_height_for_width, w );
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void NasalWidget::contentsRectChanged(const SGRect<int>& rect)
|
||||
{
|
||||
if( !_set_geometry )
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
nasal::Context c;
|
||||
_set_geometry(nasal::to_nasal(c, this), rect);
|
||||
_flags &= ~LAYOUT_DIRTY;
|
||||
}
|
||||
catch( std::exception const& ex )
|
||||
{
|
||||
SG_LOG(
|
||||
SG_GUI,
|
||||
SG_WARN,
|
||||
"NasalWidget::setGeometry: callback error: '" << ex.what() << "'"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void NasalWidget::visibilityChanged(bool visible)
|
||||
{
|
||||
try
|
||||
{
|
||||
callMethod<void>("visibilityChanged", visible);
|
||||
}
|
||||
catch( std::exception const& ex )
|
||||
{
|
||||
SG_LOG(
|
||||
SG_GUI,
|
||||
SG_WARN,
|
||||
"NasalWidget::visibilityChanged: callback error: '" << ex.what() << "'"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace canvas
|
||||
} // namespace simgear
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
///@file Glue for GUI widgets implemented in Nasal space
|
||||
///@file
|
||||
/// Glue for GUI widgets implemented in Nasal space.
|
||||
//
|
||||
// Copyright (C) 2014 Thomas Geymayer <tomgey@gmail.com>
|
||||
//
|
||||
@@ -31,7 +32,7 @@ namespace canvas
|
||||
{
|
||||
|
||||
/**
|
||||
* Baseclass/ghost to create widgets with Nasal.
|
||||
* Base class/ghost to implement gui widgets in Nasal space.
|
||||
*/
|
||||
class NasalWidget:
|
||||
public LayoutItem,
|
||||
@@ -51,8 +52,6 @@ namespace canvas
|
||||
|
||||
~NasalWidget();
|
||||
|
||||
virtual void invalidate();
|
||||
virtual void setGeometry(const SGRecti& geom);
|
||||
virtual void onRemove();
|
||||
|
||||
void setSetGeometryFunc(const SetGeometryFunc& func);
|
||||
@@ -85,8 +84,6 @@ namespace canvas
|
||||
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
|
||||
@@ -118,6 +115,13 @@ namespace canvas
|
||||
virtual SGVec2i minimumSizeImpl() const;
|
||||
virtual SGVec2i maximumSizeImpl() const;
|
||||
|
||||
virtual int heightForWidthImpl(int w) const;
|
||||
virtual int minimumHeightForWidthImpl(int w) const;
|
||||
|
||||
virtual void contentsRectChanged(const SGRecti& rect);
|
||||
|
||||
virtual void visibilityChanged(bool visible);
|
||||
|
||||
};
|
||||
|
||||
typedef SGSharedPtr<NasalWidget> NasalWidgetRef;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
///@file Element providing blank space in a layout.
|
||||
///@file
|
||||
//
|
||||
// Copyright (C) 2014 Thomas Geymayer <tomgey@gmail.com>
|
||||
//
|
||||
|
||||
@@ -23,6 +23,8 @@
|
||||
#include "NasalWidget.hxx"
|
||||
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
#include <simgear/nasal/cppbind/NasalContext.hxx>
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@@ -62,16 +64,17 @@ class TestWidget:
|
||||
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; }
|
||||
|
||||
virtual void visibilityChanged(bool visible)
|
||||
{
|
||||
if( !visible )
|
||||
_geometry.set(0, 0, 0, 0);
|
||||
}
|
||||
};
|
||||
|
||||
class TestWidgetHFW:
|
||||
@@ -91,12 +94,12 @@ class TestWidgetHFW:
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual int heightForWidth(int w) const
|
||||
virtual int heightForWidthImpl(int w) const
|
||||
{
|
||||
return _size_hint.x() * _size_hint.y() / w;
|
||||
}
|
||||
|
||||
virtual int minimumHeightForWidth(int w) const
|
||||
virtual int minimumHeightForWidthImpl(int w) const
|
||||
{
|
||||
return _min_size.x() * _min_size.y() / w;
|
||||
}
|
||||
@@ -107,45 +110,45 @@ typedef SGSharedPtr<TestWidget> TestWidgetRef;
|
||||
//------------------------------------------------------------------------------
|
||||
BOOST_AUTO_TEST_CASE( horizontal_layout )
|
||||
{
|
||||
sc::BoxLayout box_layout(sc::BoxLayout::BottomToTop);
|
||||
box_layout.setSpacing(5);
|
||||
sc::BoxLayoutRef box_layout(new sc::BoxLayout(sc::BoxLayout::BottomToTop));
|
||||
box_layout->setSpacing(5);
|
||||
|
||||
BOOST_CHECK_EQUAL(box_layout.direction(), sc::BoxLayout::BottomToTop);
|
||||
BOOST_CHECK_EQUAL(box_layout.spacing(), 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);
|
||||
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);
|
||||
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);
|
||||
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));
|
||||
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);
|
||||
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));
|
||||
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);
|
||||
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));
|
||||
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));
|
||||
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));
|
||||
@@ -154,12 +157,12 @@ BOOST_AUTO_TEST_CASE( horizontal_layout )
|
||||
TestWidgetRef stretch_widget( new TestWidget( SGVec2i(16, 16),
|
||||
SGVec2i(32, 32),
|
||||
SGVec2i(128, 32) ) );
|
||||
box_layout.addItem(stretch_widget, 1);
|
||||
box_layout.update();
|
||||
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));
|
||||
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.
|
||||
@@ -169,63 +172,101 @@ BOOST_AUTO_TEST_CASE( horizontal_layout )
|
||||
|
||||
// Test stretch factor
|
||||
TestWidgetRef fast_stretch( new TestWidget(*stretch_widget) );
|
||||
sc::BoxLayout box_layout_stretch(sc::BoxLayout::LeftToRight);
|
||||
sc::BoxLayoutRef box_layout_stretch(
|
||||
new sc::BoxLayout(sc::BoxLayout::LeftToRight)
|
||||
);
|
||||
|
||||
box_layout_stretch.addItem(stretch_widget, 1);
|
||||
box_layout_stretch.addItem(fast_stretch, 2);
|
||||
box_layout_stretch->addItem(stretch_widget, 1);
|
||||
box_layout_stretch->addItem(fast_stretch, 2);
|
||||
|
||||
box_layout_stretch.setGeometry(SGRecti(0,0,128,32));
|
||||
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));
|
||||
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));
|
||||
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) );
|
||||
// ...and now with alignment
|
||||
//
|
||||
// All widgets without alignment get their maximum space and the remaining
|
||||
// space is equally distributed to the remaining items. All items with
|
||||
// alignment are set to their size hint and positioned according to their
|
||||
// alignment.
|
||||
|
||||
hbox.addItem(w1);
|
||||
hbox.addItem(w2);
|
||||
// Left widget: size hint and positioned on the left
|
||||
// Right widget: maximum size and positioned on the right
|
||||
stretch_widget->setAlignment(sc::AlignLeft);
|
||||
box_layout_stretch->update();
|
||||
BOOST_CHECK_EQUAL(stretch_widget->geometry(), SGRecti(0, 0, 32, 32));
|
||||
BOOST_CHECK_EQUAL(fast_stretch->geometry(), SGRecti(384, 0, 128, 32));
|
||||
|
||||
hbox.setGeometry( SGRecti(0, 0, 256, 32) );
|
||||
// Left widget: align right
|
||||
stretch_widget->setAlignment(sc::AlignRight);
|
||||
box_layout_stretch->update();
|
||||
BOOST_CHECK_EQUAL(stretch_widget->geometry(), SGRecti(347, 0, 32, 32));
|
||||
BOOST_CHECK_EQUAL(fast_stretch->geometry(), SGRecti(384, 0, 128, 32));
|
||||
|
||||
BOOST_CHECK_EQUAL(w1->geometry(), SGRecti(0, 0, 126, 32));
|
||||
BOOST_CHECK_EQUAL(w2->geometry(), SGRecti(131, 0, 125, 32));
|
||||
// Left widget: size hint and positioned on the right
|
||||
// Right widget: size hint and positioned on the left of the right half
|
||||
fast_stretch->setAlignment(sc::AlignLeft);
|
||||
box_layout_stretch->update();
|
||||
BOOST_CHECK_EQUAL(stretch_widget->geometry(), SGRecti(221, 0, 32, 32));
|
||||
BOOST_CHECK_EQUAL(fast_stretch->geometry(), SGRecti(258, 0, 32, 32));
|
||||
|
||||
hbox.setStretch(0, 1);
|
||||
hbox.setStretch(1, 1);
|
||||
// Also check vertical alignment
|
||||
stretch_widget->setAlignment(sc::AlignLeft | sc::AlignTop);
|
||||
fast_stretch->setAlignment(sc::AlignLeft | sc::AlignBottom);
|
||||
box_layout_stretch->setGeometry(SGRecti(0,0,512,64));
|
||||
BOOST_CHECK_EQUAL(stretch_widget->geometry(), SGRecti(0, 0, 32, 32));
|
||||
BOOST_CHECK_EQUAL(fast_stretch->geometry(), SGRecti(258, 32, 32, 32));
|
||||
}
|
||||
|
||||
BOOST_CHECK_EQUAL(hbox.stretch(0), 1);
|
||||
BOOST_CHECK_EQUAL(hbox.stretch(1), 1);
|
||||
//------------------------------------------------------------------------------
|
||||
// Test more space then preferred, but less than maximum
|
||||
BOOST_AUTO_TEST_CASE( hbox_pref_to_max )
|
||||
{
|
||||
sc::BoxLayoutRef hbox(new sc::HBoxLayout());
|
||||
TestWidgetRef w1( new TestWidget( SGVec2i(16, 16),
|
||||
SGVec2i(32, 32),
|
||||
SGVec2i(9999, 32) ) ),
|
||||
w2( new TestWidget(*w1) );
|
||||
|
||||
hbox.update();
|
||||
hbox->addItem(w1);
|
||||
hbox->addItem(w2);
|
||||
|
||||
BOOST_CHECK_EQUAL(w1->geometry(), SGRecti(0, 0, 125, 32));
|
||||
BOOST_CHECK_EQUAL(w2->geometry(), SGRecti(130, 0, 126, 32));
|
||||
hbox->setGeometry( SGRecti(0, 0, 256, 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);
|
||||
BOOST_CHECK_EQUAL(w1->geometry(), SGRecti(0, 0, 126, 32));
|
||||
BOOST_CHECK_EQUAL(w2->geometry(), SGRecti(131, 0, 125, 32));
|
||||
|
||||
hbox.removeItem(w1);
|
||||
hbox->setStretch(0, 1);
|
||||
hbox->setStretch(1, 1);
|
||||
|
||||
BOOST_CHECK( !hbox.setStretchFactor(w1, 0) );
|
||||
}
|
||||
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) );
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@@ -295,35 +336,203 @@ BOOST_AUTO_TEST_CASE( vertical_layout)
|
||||
//------------------------------------------------------------------------------
|
||||
BOOST_AUTO_TEST_CASE( boxlayout_insert_remove )
|
||||
{
|
||||
sc::HBoxLayout hbox;
|
||||
sc::BoxLayoutRef hbox( new sc::HBoxLayout );
|
||||
|
||||
BOOST_CHECK_EQUAL(hbox.count(), 0);
|
||||
BOOST_CHECK(!hbox.itemAt(0));
|
||||
BOOST_CHECK(!hbox.takeAt(0));
|
||||
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->addItem(w1);
|
||||
BOOST_CHECK_EQUAL(hbox->count(), 1);
|
||||
BOOST_CHECK_EQUAL(hbox->itemAt(0), w1);
|
||||
BOOST_CHECK_EQUAL(w1->getParent(), hbox);
|
||||
|
||||
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->insertItem(0, w2);
|
||||
BOOST_CHECK_EQUAL(hbox->count(), 2);
|
||||
BOOST_CHECK_EQUAL(hbox->itemAt(0), w2);
|
||||
BOOST_CHECK_EQUAL(hbox->itemAt(1), w1);
|
||||
BOOST_CHECK_EQUAL(w2->getParent(), hbox);
|
||||
|
||||
hbox.removeItem(w2);
|
||||
BOOST_CHECK_EQUAL(hbox.count(), 1);
|
||||
BOOST_CHECK_EQUAL(hbox.itemAt(0), w1);
|
||||
hbox->removeItem(w2);
|
||||
BOOST_CHECK_EQUAL(hbox->count(), 1);
|
||||
BOOST_CHECK_EQUAL(hbox->itemAt(0), w1);
|
||||
BOOST_CHECK( !w2->getParent() );
|
||||
|
||||
hbox.addItem(w2);
|
||||
BOOST_CHECK_EQUAL(hbox.count(), 2);
|
||||
hbox->addItem(w2);
|
||||
BOOST_CHECK_EQUAL(hbox->count(), 2);
|
||||
BOOST_CHECK_EQUAL(w2->getParent(), hbox);
|
||||
|
||||
hbox.clear();
|
||||
BOOST_CHECK_EQUAL(hbox.count(), 0);
|
||||
hbox->clear();
|
||||
BOOST_CHECK_EQUAL(hbox->count(), 0);
|
||||
BOOST_CHECK( !w1->getParent() );
|
||||
BOOST_CHECK( !w2->getParent() );
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
BOOST_AUTO_TEST_CASE( boxlayout_visibility )
|
||||
{
|
||||
sc::BoxLayoutRef hbox( new sc::HBoxLayout );
|
||||
TestWidgetRef w1( new TestWidget( SGVec2i(16, 16),
|
||||
SGVec2i(32, 32) ) ),
|
||||
w2( new TestWidget(*w1) ),
|
||||
w3( new TestWidget(*w1) );
|
||||
|
||||
hbox->addItem(w1);
|
||||
hbox->addItem(w2);
|
||||
hbox->addItem(w3);
|
||||
|
||||
BOOST_REQUIRE_EQUAL(hbox->sizeHint().x(), 3 * 32 + 2 * hbox->spacing());
|
||||
|
||||
hbox->setGeometry(SGRecti(0, 0, 69, 32));
|
||||
|
||||
BOOST_CHECK_EQUAL(w1->geometry(), SGRecti(0, 0, 20, 32));
|
||||
BOOST_CHECK_EQUAL(w2->geometry(), SGRecti(25, 0, 20, 32));
|
||||
BOOST_CHECK_EQUAL(w3->geometry(), SGRecti(50, 0, 19, 32));
|
||||
|
||||
w2->setVisible(false);
|
||||
|
||||
BOOST_REQUIRE(hbox->isVisible());
|
||||
BOOST_REQUIRE(w1->isVisible());
|
||||
BOOST_REQUIRE(!w2->isVisible());
|
||||
BOOST_REQUIRE(w2->isExplicitlyHidden());
|
||||
BOOST_REQUIRE(w3->isVisible());
|
||||
|
||||
BOOST_CHECK_EQUAL(hbox->sizeHint().x(), 2 * 32 + 1 * hbox->spacing());
|
||||
|
||||
hbox->update();
|
||||
|
||||
BOOST_CHECK_EQUAL(w1->geometry(), SGRecti(0, 0, 32, 32));
|
||||
BOOST_CHECK_EQUAL(w2->geometry(), SGRecti(0, 0, 0, 0));
|
||||
BOOST_CHECK_EQUAL(w3->geometry(), SGRecti(37, 0, 32, 32));
|
||||
|
||||
hbox->setVisible(false);
|
||||
|
||||
BOOST_REQUIRE(!hbox->isVisible());
|
||||
BOOST_REQUIRE(hbox->isExplicitlyHidden());
|
||||
BOOST_REQUIRE(!w1->isVisible());
|
||||
BOOST_REQUIRE(!w1->isExplicitlyHidden());
|
||||
BOOST_REQUIRE(!w2->isVisible());
|
||||
BOOST_REQUIRE(w2->isExplicitlyHidden());
|
||||
BOOST_REQUIRE(!w3->isVisible());
|
||||
BOOST_REQUIRE(!w3->isExplicitlyHidden());
|
||||
|
||||
BOOST_CHECK_EQUAL(w1->geometry(), SGRecti(0, 0, 0, 0));
|
||||
BOOST_CHECK_EQUAL(w2->geometry(), SGRecti(0, 0, 0, 0));
|
||||
BOOST_CHECK_EQUAL(w3->geometry(), SGRecti(0, 0, 0, 0));
|
||||
|
||||
w2->setVisible(true);
|
||||
|
||||
BOOST_REQUIRE(!w2->isVisible());
|
||||
BOOST_REQUIRE(!w2->isExplicitlyHidden());
|
||||
|
||||
hbox->setVisible(true);
|
||||
|
||||
BOOST_REQUIRE(hbox->isVisible());
|
||||
BOOST_REQUIRE(w1->isVisible());
|
||||
BOOST_REQUIRE(w2->isVisible());
|
||||
BOOST_REQUIRE(w3->isVisible());
|
||||
|
||||
hbox->update();
|
||||
|
||||
BOOST_CHECK_EQUAL(w1->geometry(), SGRecti(0, 0, 20, 32));
|
||||
BOOST_CHECK_EQUAL(w2->geometry(), SGRecti(25, 0, 20, 32));
|
||||
BOOST_CHECK_EQUAL(w3->geometry(), SGRecti(50, 0, 19, 32));
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
BOOST_AUTO_TEST_CASE( boxlayout_contents_margins )
|
||||
{
|
||||
sc::Margins m;
|
||||
|
||||
BOOST_REQUIRE(m.isNull());
|
||||
|
||||
m = sc::Margins(5);
|
||||
|
||||
BOOST_REQUIRE_EQUAL(m.l, 5);
|
||||
BOOST_REQUIRE_EQUAL(m.t, 5);
|
||||
BOOST_REQUIRE_EQUAL(m.r, 5);
|
||||
BOOST_REQUIRE_EQUAL(m.b, 5);
|
||||
|
||||
m = sc::Margins(6, 7);
|
||||
|
||||
BOOST_REQUIRE_EQUAL(m.l, 6);
|
||||
BOOST_REQUIRE_EQUAL(m.t, 7);
|
||||
BOOST_REQUIRE_EQUAL(m.r, 6);
|
||||
BOOST_REQUIRE_EQUAL(m.b, 7);
|
||||
|
||||
BOOST_REQUIRE_EQUAL(m.horiz(), 12);
|
||||
BOOST_REQUIRE_EQUAL(m.vert(), 14);
|
||||
BOOST_REQUIRE(!m.isNull());
|
||||
|
||||
m = sc::Margins(1, 2, 3, 4);
|
||||
|
||||
BOOST_REQUIRE_EQUAL(m.l, 1);
|
||||
BOOST_REQUIRE_EQUAL(m.t, 2);
|
||||
BOOST_REQUIRE_EQUAL(m.r, 3);
|
||||
BOOST_REQUIRE_EQUAL(m.b, 4);
|
||||
|
||||
BOOST_REQUIRE_EQUAL(m.horiz(), 4);
|
||||
BOOST_REQUIRE_EQUAL(m.vert(), 6);
|
||||
BOOST_REQUIRE_EQUAL(m.size(), SGVec2i(4, 6));
|
||||
|
||||
sc::BoxLayoutRef hbox( new sc::HBoxLayout );
|
||||
|
||||
hbox->setContentsMargins(5, 10, 15, 20);
|
||||
|
||||
BOOST_CHECK_EQUAL(hbox->minimumSize(), SGVec2i(20, 30));
|
||||
BOOST_CHECK_EQUAL(hbox->sizeHint(), SGVec2i(20, 30));
|
||||
BOOST_CHECK_EQUAL(hbox->maximumSize(), SGVec2i(20, 30));
|
||||
|
||||
hbox->setGeometry(SGRecti(0, 0, 30, 40));
|
||||
|
||||
BOOST_CHECK_EQUAL(hbox->geometry(), SGRecti(0, 0, 30, 40));
|
||||
BOOST_CHECK_EQUAL(hbox->contentsRect(), SGRecti(5, 10, 10, 10));
|
||||
|
||||
TestWidgetRef w1( new TestWidget( SGVec2i(16, 16),
|
||||
SGVec2i(32, 32) ) ),
|
||||
w2( new TestWidget(*w1) ),
|
||||
w3( new TestWidget(*w1) );
|
||||
|
||||
w1->setContentsMargin(5);
|
||||
w2->setContentsMargin(6);
|
||||
w3->setContentsMargin(7);
|
||||
|
||||
BOOST_CHECK_EQUAL(w1->minimumSize(), SGVec2i(26, 26));
|
||||
BOOST_CHECK_EQUAL(w1->sizeHint(), SGVec2i(42, 42));
|
||||
BOOST_CHECK_EQUAL(w1->maximumSize(), sc::LayoutItem::MAX_SIZE);
|
||||
|
||||
BOOST_CHECK_EQUAL(w2->minimumSize(), SGVec2i(28, 28));
|
||||
BOOST_CHECK_EQUAL(w2->sizeHint(), SGVec2i(44, 44));
|
||||
BOOST_CHECK_EQUAL(w2->maximumSize(), sc::LayoutItem::MAX_SIZE);
|
||||
|
||||
BOOST_CHECK_EQUAL(w3->minimumSize(), SGVec2i(30, 30));
|
||||
BOOST_CHECK_EQUAL(w3->sizeHint(), SGVec2i(46, 46));
|
||||
BOOST_CHECK_EQUAL(w3->maximumSize(), sc::LayoutItem::MAX_SIZE);
|
||||
|
||||
hbox->addItem(w1);
|
||||
hbox->addItem(w2);
|
||||
hbox->addItem(w3);
|
||||
|
||||
BOOST_CHECK_EQUAL(hbox->minimumSize(), SGVec2i(114, 60));
|
||||
BOOST_CHECK_EQUAL(hbox->sizeHint(), SGVec2i(162, 76));
|
||||
BOOST_CHECK_EQUAL(hbox->maximumSize(), sc::LayoutItem::MAX_SIZE);
|
||||
|
||||
hbox->setGeometry(SGRecti(0, 0, hbox->sizeHint().x(), hbox->sizeHint().y()));
|
||||
|
||||
BOOST_CHECK_EQUAL(hbox->contentsRect(), SGRecti(5, 10, 142, 46));
|
||||
|
||||
BOOST_CHECK_EQUAL(w1->geometry(), SGRecti(5, 10, 42, 46));
|
||||
BOOST_CHECK_EQUAL(w2->geometry(), SGRecti(52, 10, 44, 46));
|
||||
BOOST_CHECK_EQUAL(w3->geometry(), SGRecti(101, 10, 46, 46));
|
||||
|
||||
BOOST_CHECK_EQUAL(w1->contentsRect(), SGRecti(10, 15, 32, 36));
|
||||
BOOST_CHECK_EQUAL(w2->contentsRect(), SGRecti(58, 16, 32, 34));
|
||||
BOOST_CHECK_EQUAL(w3->contentsRect(), SGRecti(108, 17, 32, 32));
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@@ -417,13 +626,77 @@ BOOST_AUTO_TEST_CASE( boxlayout_hfw )
|
||||
BOOST_CHECK_EQUAL(w_no_hfw->geometry(), SGRecti(0, 90, 24, 32));
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
BOOST_AUTO_TEST_CASE( item_alignment_rect )
|
||||
{
|
||||
TestWidgetRef w1( new TestWidget( SGVec2i(16, 16),
|
||||
SGVec2i(32, 32) ) );
|
||||
|
||||
const SGRecti r(10, 10, 64, 64);
|
||||
|
||||
// Default: AlignFill -> fill up to maximum size
|
||||
BOOST_CHECK_EQUAL(w1->alignmentRect(r), r);
|
||||
|
||||
// Horizontal
|
||||
|
||||
// AlignLeft -> width from size hint, positioned on the left
|
||||
w1->setAlignment(sc::AlignLeft);
|
||||
BOOST_CHECK_EQUAL(w1->alignmentRect(r), SGRecti(10, 10, 32, 64));
|
||||
|
||||
// AlignRight -> width from size hint, positioned on the left
|
||||
w1->setAlignment(sc::AlignRight);
|
||||
BOOST_CHECK_EQUAL(w1->alignmentRect(r), SGRecti(42, 10, 32, 64));
|
||||
|
||||
// AlignHCenter -> width from size hint, positioned in the center
|
||||
w1->setAlignment(sc::AlignHCenter);
|
||||
BOOST_CHECK_EQUAL(w1->alignmentRect(r), SGRecti(26, 10, 32, 64));
|
||||
|
||||
|
||||
// Vertical
|
||||
|
||||
// AlignTop -> height from size hint, positioned on the top
|
||||
w1->setAlignment(sc::AlignTop);
|
||||
BOOST_CHECK_EQUAL(w1->alignmentRect(r), SGRecti(10, 10, 64, 32));
|
||||
|
||||
// AlignBottom -> height from size hint, positioned on the bottom
|
||||
w1->setAlignment(sc::AlignBottom);
|
||||
BOOST_CHECK_EQUAL(w1->alignmentRect(r), SGRecti(10, 42, 64, 32));
|
||||
|
||||
// AlignVCenter -> height from size hint, positioned in the center
|
||||
w1->setAlignment(sc::AlignVCenter);
|
||||
BOOST_CHECK_EQUAL(w1->alignmentRect(r), SGRecti(10, 26, 64, 32));
|
||||
|
||||
|
||||
// Vertical + Horizontal
|
||||
w1->setAlignment(sc::AlignCenter);
|
||||
BOOST_CHECK_EQUAL(w1->alignmentRect(r), SGRecti(26, 26, 32, 32));
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// TODO extend to_nasal_helper for automatic argument conversion
|
||||
static naRef f_Widget_visibilityChanged(nasal::CallContext ctx)
|
||||
{
|
||||
sc::NasalWidget* w = ctx.from_nasal<sc::NasalWidget*>(ctx.me);
|
||||
|
||||
if( !ctx.requireArg<bool>(0) )
|
||||
w->setGeometry(SGRecti(0, 0, -1, -1));
|
||||
|
||||
return naNil();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
BOOST_AUTO_TEST_CASE( nasal_widget )
|
||||
{
|
||||
naContext c = naNewContext();
|
||||
naRef me = naNewHash(c);
|
||||
nasal::Context c;
|
||||
nasal::Hash globals = c.newHash();
|
||||
|
||||
sc::NasalWidgetRef w( new sc::NasalWidget(me) );
|
||||
nasal::Object::setupGhost();
|
||||
nasal::Ghost<sc::LayoutItemRef>::init("LayoutItem");
|
||||
sc::NasalWidget::setupGhost(globals);
|
||||
|
||||
nasal::Hash me = c.newHash();
|
||||
me.set("visibilityChanged", &f_Widget_visibilityChanged);
|
||||
sc::NasalWidgetRef w( new sc::NasalWidget(me.get_naRef()) );
|
||||
|
||||
// Default layout sizes (no user set values)
|
||||
BOOST_CHECK_EQUAL(w->minimumSize(), SGVec2i(16, 16));
|
||||
@@ -457,5 +730,6 @@ BOOST_AUTO_TEST_CASE( nasal_widget )
|
||||
BOOST_CHECK_EQUAL(w->sizeHint(), SGVec2i(3, 22));
|
||||
BOOST_CHECK_EQUAL(w->maximumSize(), SGVec2i(4, 23));
|
||||
|
||||
naFreeContext(c);
|
||||
w->setVisible(false);
|
||||
BOOST_CHECK_EQUAL(w->geometry(), SGRecti(0, 0, -1, -1));
|
||||
}
|
||||
|
||||
@@ -190,6 +190,12 @@ inline int (isnan)(double r) { return !(r <= 0 || r >= 0); }
|
||||
# define DEPRECATED
|
||||
#endif
|
||||
|
||||
#if defined(__clang__)
|
||||
# define SG_NO_RETURN [[noreturn]]
|
||||
#else
|
||||
# define SG_NO_RETURN
|
||||
#endif
|
||||
|
||||
//
|
||||
// No user modifiable definitions beyond here.
|
||||
//
|
||||
|
||||
@@ -26,6 +26,8 @@
|
||||
#include <simgear/sg_inlines.h>
|
||||
#include <simgear/threads/SGThread.hxx>
|
||||
#include <simgear/threads/SGGuard.hxx>
|
||||
|
||||
#include <cstdlib> // for malloc
|
||||
|
||||
namespace simgear
|
||||
{
|
||||
|
||||
@@ -32,7 +32,8 @@ typedef enum {
|
||||
SG_SOUND = 0x00200000,
|
||||
SG_NAVAID = 0x00400000,
|
||||
SG_GUI = 0x00800000,
|
||||
SG_UNDEFD = 0x01000000, // For range checking
|
||||
SG_TERRASYNC = 0x01000000,
|
||||
SG_UNDEFD = 0x02000000, // For range checking
|
||||
|
||||
SG_ALL = 0xFFFFFFFF
|
||||
} sgDebugClass;
|
||||
|
||||
@@ -71,6 +71,7 @@ const char* debugClassToString(sgDebugClass c)
|
||||
case SG_SOUND: return "sound";
|
||||
case SG_NAVAID: return "navaid";
|
||||
case SG_GUI: return "gui";
|
||||
case SG_TERRASYNC: return "terrasync";
|
||||
default: return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
* Build a new OSG object from osgParticle.
|
||||
*/
|
||||
SGPrecipitation::SGPrecipitation() :
|
||||
_freeze(false), _enabled(true), _snow_intensity(0.0), _rain_intensity(0.0), _clip_distance(5.0)
|
||||
_freeze(false), _enabled(true), _droplet_external(false), _snow_intensity(0.0), _rain_intensity(0.0), _clip_distance(5.0), _rain_droplet_size(0.0), _snow_flake_size(0.0), _illumination(1.0)
|
||||
{
|
||||
_precipitationEffect = new osgParticle::PrecipitationEffect;
|
||||
}
|
||||
@@ -47,6 +47,11 @@ void SGPrecipitation::setEnabled( bool value )
|
||||
_enabled = value;
|
||||
}
|
||||
|
||||
void SGPrecipitation::setDropletExternal( bool value )
|
||||
{
|
||||
_droplet_external = value;
|
||||
}
|
||||
|
||||
bool SGPrecipitation::getEnabled() const
|
||||
{
|
||||
return _enabled;
|
||||
@@ -66,7 +71,7 @@ osg::Group* SGPrecipitation::build(void)
|
||||
_precipitationEffect->rain(0);
|
||||
|
||||
if (_clip_distance!=0.0)
|
||||
{
|
||||
{
|
||||
osg::ref_ptr<osg::ClipNode> clipNode = new osg::ClipNode;
|
||||
clipNode->addClipPlane( new osg::ClipPlane( 0 ) );
|
||||
clipNode->getClipPlane(0)->setClipPlane( 0.0, 0.0, -1.0, -_clip_distance );
|
||||
@@ -119,17 +124,72 @@ void SGPrecipitation::setRainIntensity(float intensity)
|
||||
this->_rain_intensity = intensity;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Define the rain droplet size
|
||||
*
|
||||
* This function permits you to define and change the rain droplet size
|
||||
* which is used if external droplet size control is enabled
|
||||
*/
|
||||
|
||||
/**
|
||||
void SGPrecipitation::setRainDropletSize(float size)
|
||||
{
|
||||
_rain_droplet_size = size;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Define the illumination multiplier
|
||||
*
|
||||
* This function permits you to define and change the rain droplet size
|
||||
* which is used if external droplet size control is enabled
|
||||
*/
|
||||
|
||||
void SGPrecipitation::setIllumination(float illumination)
|
||||
{
|
||||
_illumination = illumination;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Define the snow flake size
|
||||
*
|
||||
* This function permits you to define and change the snow flake size
|
||||
* which is used if external droplet size control is enabled
|
||||
*/
|
||||
|
||||
void SGPrecipitation::setSnowFlakeSize(float size)
|
||||
{
|
||||
_snow_flake_size = size;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Define the rain droplet size
|
||||
*
|
||||
* This function permits you to define and change the rain droplet size
|
||||
* which is used if external droplet size control is enabled
|
||||
*/
|
||||
|
||||
void SGPrecipitation::setClipDistance(float distance)
|
||||
{
|
||||
_clip_distance = distance;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Freeze the rain to snow
|
||||
*
|
||||
* @param freeze Boolean
|
||||
*
|
||||
*
|
||||
* @param freeze Boolean
|
||||
*
|
||||
* This function permits you to turn off the rain to snow.
|
||||
*/
|
||||
void SGPrecipitation::setFreezing(bool freeze)
|
||||
{
|
||||
if ((this->_freeze)&&(!freeze)) // rain freezes suddenly, so we need to unfreeze
|
||||
{
|
||||
this->_rain_intensity = this->_snow_intensity;
|
||||
this->_snow_intensity = 0.0;
|
||||
}
|
||||
this->_freeze = freeze;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -137,7 +197,7 @@ void SGPrecipitation::setFreezing(bool freeze)
|
||||
* @brief Define the wind direction and speed
|
||||
*
|
||||
* This function permits you to define and change the wind direction
|
||||
*
|
||||
*
|
||||
* After apply the MatrixTransform to the osg::Precipitation object,
|
||||
* x points full south... From wind heading and speed, we can calculate
|
||||
* the wind vector.
|
||||
@@ -169,34 +229,74 @@ void SGPrecipitation::setWindProperty(double heading, double speed)
|
||||
bool SGPrecipitation::update(void)
|
||||
{
|
||||
if (this->_freeze) {
|
||||
if (this->_rain_intensity > 0)
|
||||
this->_snow_intensity = this->_rain_intensity;
|
||||
if (this->_rain_intensity > 0) {
|
||||
this->_snow_intensity = this->_rain_intensity;
|
||||
}
|
||||
}
|
||||
|
||||
if (_enabled && this->_snow_intensity > 0) {
|
||||
_precipitationEffect->setWind(_wind_vec);
|
||||
_precipitationEffect->setParticleSpeed( -0.75f - 0.25f*_snow_intensity);
|
||||
|
||||
|
||||
_precipitationEffect->setParticleSize(0.02f + 0.03f*_snow_intensity);
|
||||
_precipitationEffect->setMaximumParticleDensity(_snow_intensity * 7.2f);
|
||||
if(_droplet_external)
|
||||
{
|
||||
|
||||
if ((_freeze) && (_rain_droplet_size > 0.03)) // this is hail or sleet
|
||||
{
|
||||
_precipitationEffect->setParticleSize(_rain_droplet_size*1.5f);
|
||||
_precipitationEffect->setParticleSpeed( -1.0f - 22.36f*sqrtf(_rain_droplet_size));
|
||||
_precipitationEffect->setMaximumParticleDensity(_snow_intensity * 4.8f);
|
||||
}
|
||||
else if (_freeze) // this is snow from frozen small rain droplets
|
||||
{
|
||||
_precipitationEffect->setParticleSize(_rain_droplet_size*1.3f);
|
||||
_precipitationEffect->setParticleSpeed( -0.75f - 0.25f*_snow_intensity);
|
||||
_precipitationEffect->setMaximumParticleDensity(_snow_intensity * 10.0f);
|
||||
}
|
||||
else // this was snow in the first place
|
||||
{
|
||||
_precipitationEffect->setParticleSize(_snow_flake_size);
|
||||
_precipitationEffect->setParticleSpeed( -0.75f - 0.25f*_snow_intensity);
|
||||
_precipitationEffect->setMaximumParticleDensity(_snow_intensity * 7.2f);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_precipitationEffect->setMaximumParticleDensity(_snow_intensity * 7.2f);
|
||||
_precipitationEffect->setParticleSize(0.02f + 0.03f*_snow_intensity);
|
||||
_precipitationEffect->setParticleSpeed( -0.75f - 0.25f*_snow_intensity);
|
||||
}
|
||||
|
||||
|
||||
_precipitationEffect->setCellSize(osg::Vec3(5.0f / (0.25f+_snow_intensity), 5.0f / (0.25f+_snow_intensity), 5.0f));
|
||||
|
||||
_precipitationEffect->setNearTransition(25.f);
|
||||
_precipitationEffect->setFarTransition(100.0f - 60.0f*sqrtf(_snow_intensity));
|
||||
|
||||
_precipitationEffect->setParticleColor(osg::Vec4(0.85, 0.85, 0.85, 1.0) - osg::Vec4(0.1, 0.1, 0.1, 1.0) * _snow_intensity);
|
||||
_precipitationEffect->setParticleColor(osg::Vec4(0.85 * _illumination, 0.85 * _illumination, 0.85 * _illumination, 1.0) - osg::Vec4(0.1, 0.1, 0.1, 1.0) * _snow_intensity);
|
||||
} else if (_enabled && this->_rain_intensity > 0) {
|
||||
|
||||
_precipitationEffect->setWind(_wind_vec);
|
||||
_precipitationEffect->setParticleSpeed( -2.0f + -5.0f*_rain_intensity);
|
||||
|
||||
|
||||
if(_droplet_external)
|
||||
{
|
||||
_precipitationEffect->setParticleSize(_rain_droplet_size);
|
||||
_precipitationEffect->setParticleSpeed( -1.0f - 22.36f*sqrtf(_rain_droplet_size));
|
||||
}
|
||||
else
|
||||
{
|
||||
_precipitationEffect->setParticleSize(0.01 + 0.02*_rain_intensity);
|
||||
_precipitationEffect->setParticleSpeed( -2.0f + -5.0f*_rain_intensity);
|
||||
}
|
||||
|
||||
_precipitationEffect->setParticleSize(0.01 + 0.02*_rain_intensity);
|
||||
_precipitationEffect->setMaximumParticleDensity(_rain_intensity * 7.5f);
|
||||
_precipitationEffect->setCellSize(osg::Vec3(5.0f / (0.25f+_rain_intensity), 5.0f / (0.25f+_rain_intensity), 5.0f));
|
||||
|
||||
_precipitationEffect->setNearTransition(25.f);
|
||||
_precipitationEffect->setFarTransition(100.0f - 60.0f*sqrtf(_rain_intensity));
|
||||
|
||||
_precipitationEffect->setParticleColor( osg::Vec4(0x7A, 0xCE, 0xFF, 0x80));
|
||||
_precipitationEffect->setParticleColor( osg::Vec4(0.64 * _illumination, 0.64 * _illumination, 0.64 * _illumination, 0.5));
|
||||
} else {
|
||||
_precipitationEffect->snow(0);
|
||||
_precipitationEffect->rain(0);
|
||||
|
||||
@@ -37,10 +37,14 @@ class SGPrecipitation : public osg::Referenced
|
||||
private:
|
||||
bool _freeze;
|
||||
bool _enabled;
|
||||
bool _droplet_external;
|
||||
|
||||
float _snow_intensity;
|
||||
float _rain_intensity;
|
||||
float _clip_distance;
|
||||
float _rain_droplet_size;
|
||||
float _snow_flake_size;
|
||||
float _illumination;
|
||||
|
||||
osg::Vec3 _wind_vec;
|
||||
|
||||
@@ -54,8 +58,13 @@ public:
|
||||
|
||||
void setWindProperty(double, double);
|
||||
void setFreezing(bool);
|
||||
void setDropletExternal(bool);
|
||||
void setRainIntensity(float);
|
||||
void setSnowIntensity(float);
|
||||
void setRainDropletSize(float);
|
||||
void setSnowFlakeSize(float);
|
||||
void setIllumination(float);
|
||||
void setClipDistance(float);
|
||||
|
||||
void setEnabled( bool );
|
||||
bool getEnabled() const;
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
* $Id$
|
||||
**************************************************************************/
|
||||
|
||||
#include <math.h>
|
||||
#include <cmath>
|
||||
|
||||
#include "jupiter.hxx"
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
* $Id$
|
||||
**************************************************************************/
|
||||
|
||||
#include <math.h>
|
||||
#include <cmath>
|
||||
|
||||
#include "mars.hxx"
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
* $Id$
|
||||
**************************************************************************/
|
||||
|
||||
#include <math.h>
|
||||
#include <cmath>
|
||||
|
||||
#include "mercury.hxx"
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
#ifdef __BORLANDC__
|
||||
# define exception c_exception
|
||||
#endif
|
||||
#include <math.h>
|
||||
#include <cmath>
|
||||
|
||||
#include "neptune.hxx"
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
* $Id$
|
||||
**************************************************************************/
|
||||
|
||||
#include <math.h>
|
||||
#include <cmath>
|
||||
|
||||
#include "saturn.hxx"
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
* $Id$
|
||||
**************************************************************************/
|
||||
|
||||
#include <math.h>
|
||||
#include <cmath>
|
||||
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ public:
|
||||
bool load( const SGPath& path );
|
||||
|
||||
// stars
|
||||
inline int getNumStars() const { return _stars.size(); }
|
||||
inline int getNumStars() const { return static_cast<int>(_stars.size()); }
|
||||
inline SGVec3d *getStars() { return &(_stars[0]); }
|
||||
|
||||
private:
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
* $Id$
|
||||
**************************************************************************/
|
||||
|
||||
#include <math.h>
|
||||
#include <cmath>
|
||||
|
||||
#include "uranus.hxx"
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
* $Id$
|
||||
**************************************************************************/
|
||||
|
||||
#include <math.h>
|
||||
#include <cmath>
|
||||
|
||||
#include "venus.hxx"
|
||||
|
||||
|
||||
@@ -18,7 +18,6 @@ set(HEADERS
|
||||
HTTPFileRequest.hxx
|
||||
HTTPMemoryRequest.hxx
|
||||
HTTPRequest.hxx
|
||||
HTTPContentDecode.hxx
|
||||
DAVMultiStatus.hxx
|
||||
SVNRepository.hxx
|
||||
SVNDirectory.hxx
|
||||
@@ -41,13 +40,17 @@ set(SOURCES
|
||||
HTTPFileRequest.cxx
|
||||
HTTPMemoryRequest.cxx
|
||||
HTTPRequest.cxx
|
||||
HTTPContentDecode.cxx
|
||||
DAVMultiStatus.cxx
|
||||
SVNRepository.cxx
|
||||
SVNDirectory.cxx
|
||||
SVNReportParser.cxx
|
||||
)
|
||||
|
||||
if (NOT ENABLE_CURL)
|
||||
list(APPEND SOURCES HTTPContentDecode.cxx)
|
||||
list(APPEND HEADERS HTTPContentDecode.hxx)
|
||||
endif()
|
||||
|
||||
simgear_component(io io "${SOURCES}" "${HEADERS}")
|
||||
|
||||
if(ENABLE_TESTS)
|
||||
@@ -70,8 +73,8 @@ add_executable(decode_binobj decode_binobj.cxx)
|
||||
target_link_libraries(decode_binobj ${TEST_LIBS})
|
||||
|
||||
add_executable(test_binobj test_binobj.cxx)
|
||||
target_link_libraries(test_binobj ${TEST_LIBS})
|
||||
|
||||
target_link_libraries(test_binobj ${TEST_LIBS})
|
||||
|
||||
add_test(binobj ${EXECUTABLE_OUTPUT_PATH}/test_binobj)
|
||||
|
||||
endif(ENABLE_TESTS)
|
||||
|
||||
@@ -193,7 +193,7 @@ public:
|
||||
{
|
||||
if (tagStack.empty()) {
|
||||
if (strcmp(name, DAV_MULTISTATUS_TAG)) {
|
||||
SG_LOG(SG_IO, SG_WARN, "root element is not " <<
|
||||
SG_LOG(SG_TERRASYNC, SG_WARN, "root element is not " <<
|
||||
DAV_MULTISTATUS_TAG << ", got:" << name);
|
||||
} else {
|
||||
|
||||
@@ -202,7 +202,7 @@ public:
|
||||
// not at the root element
|
||||
if (tagStack.back() == DAV_MULTISTATUS_TAG) {
|
||||
if (strcmp(name, DAV_RESPONSE_TAG)) {
|
||||
SG_LOG(SG_IO, SG_WARN, "multistatus child is not response: saw:"
|
||||
SG_LOG(SG_TERRASYNC, SG_WARN, "multistatus child is not response: saw:"
|
||||
<< name);
|
||||
}
|
||||
}
|
||||
@@ -362,7 +362,7 @@ void DAVMultiStatus::parseXML(const char* data, int size)
|
||||
}
|
||||
|
||||
if (!XML_Parse(_d->xmlParser, data, size, false)) {
|
||||
SG_LOG(SG_IO, SG_WARN, "DAV parse error:" << XML_ErrorString(XML_GetErrorCode(_d->xmlParser))
|
||||
SG_LOG(SG_TERRASYNC, SG_WARN, "DAV parse error:" << XML_ErrorString(XML_GetErrorCode(_d->xmlParser))
|
||||
<< " at line:" << XML_GetCurrentLineNumber(_d->xmlParser)
|
||||
<< " column " << XML_GetCurrentColumnNumber(_d->xmlParser));
|
||||
|
||||
@@ -376,7 +376,7 @@ void DAVMultiStatus::finishParse()
|
||||
{
|
||||
if (_d->parserInited) {
|
||||
if (!XML_Parse(_d->xmlParser, NULL, 0, true)) {
|
||||
SG_LOG(SG_IO, SG_WARN, "DAV parse error:" << XML_ErrorString(XML_GetErrorCode(_d->xmlParser))
|
||||
SG_LOG(SG_TERRASYNC, SG_WARN, "DAV parse error:" << XML_ErrorString(XML_GetErrorCode(_d->xmlParser))
|
||||
<< " at line:" << XML_GetCurrentLineNumber(_d->xmlParser)
|
||||
<< " column " << XML_GetCurrentColumnNumber(_d->xmlParser));
|
||||
_d->valid = false;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -38,15 +38,15 @@ namespace HTTP
|
||||
|
||||
// forward decls
|
||||
class Connection;
|
||||
|
||||
|
||||
class Client
|
||||
{
|
||||
public:
|
||||
Client();
|
||||
~Client();
|
||||
|
||||
|
||||
void update(int waitTimeout = 0);
|
||||
|
||||
|
||||
void makeRequest(const Request_ptr& r);
|
||||
|
||||
/**
|
||||
@@ -68,44 +68,51 @@ public:
|
||||
|
||||
void setUserAgent(const std::string& ua);
|
||||
void setProxy(const std::string& proxy, int port, const std::string& auth = "");
|
||||
|
||||
|
||||
/**
|
||||
* Specify the maximum permitted simultaneous connections
|
||||
* (default value is 1)
|
||||
*/
|
||||
void setMaxConnections(unsigned int maxCons);
|
||||
|
||||
|
||||
const std::string& userAgent() const;
|
||||
|
||||
|
||||
const std::string& proxyHost() const;
|
||||
|
||||
|
||||
const std::string& proxyAuth() const;
|
||||
|
||||
|
||||
/**
|
||||
* predicate, check if at least one connection is active, with at
|
||||
* least one request active or queued.
|
||||
*/
|
||||
bool hasActiveRequests() const;
|
||||
|
||||
|
||||
/**
|
||||
* crude tracking of bytes-per-second transferred over the socket.
|
||||
* suitable for user feedback and rough profiling, nothing more.
|
||||
*/
|
||||
unsigned int transferRateBytesPerSec() const;
|
||||
|
||||
|
||||
/**
|
||||
* total bytes downloaded by this HTTP client, for bandwidth usage
|
||||
* monitoring
|
||||
*/
|
||||
uint64_t totalBytesDownloaded() const;
|
||||
|
||||
void debugDumpRequests();
|
||||
private:
|
||||
// libCurl callbacks
|
||||
static size_t requestWriteCallback(char *ptr, size_t size, size_t nmemb, void *userdata);
|
||||
static size_t requestReadCallback(char *ptr, size_t size, size_t nmemb, void *userdata);
|
||||
static size_t requestHeaderCallback(char *buffer, size_t size, size_t nitems, void *userdata);
|
||||
|
||||
void requestFinished(Connection* con);
|
||||
|
||||
|
||||
void receivedBytes(unsigned int count);
|
||||
|
||||
|
||||
friend class Connection;
|
||||
friend class Request;
|
||||
|
||||
|
||||
class ClientPrivate;
|
||||
std::auto_ptr<ClientPrivate> d;
|
||||
};
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
///@file HTTP request writing response to a file.
|
||||
///@file
|
||||
//
|
||||
// Copyright (C) 2013 Thomas Geymayer <tomgey@gmail.com>
|
||||
//
|
||||
@@ -27,6 +27,9 @@ namespace simgear
|
||||
namespace HTTP
|
||||
{
|
||||
|
||||
/**
|
||||
* HTTP request writing response to a file.
|
||||
*/
|
||||
class FileRequest:
|
||||
public Request
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
///@file HTTP request keeping response in memory.
|
||||
///@file
|
||||
//
|
||||
// Copyright (C) 2013 Thomas Geymayer <tomgey@gmail.com>
|
||||
//
|
||||
@@ -27,6 +27,9 @@ namespace simgear
|
||||
namespace HTTP
|
||||
{
|
||||
|
||||
/**
|
||||
* HTTP request keeping response in memory.
|
||||
*/
|
||||
class MemoryRequest:
|
||||
public Request
|
||||
{
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
// Copyright (C) 2011 James Turner <zakalawe@mac.com>
|
||||
// Copyright (C) 2013 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 "HTTPRequest.hxx"
|
||||
|
||||
#include <simgear/compiler.h>
|
||||
@@ -116,19 +133,25 @@ void Request::responseStart(const std::string& r)
|
||||
const int maxSplit = 2; // HTTP/1.1 nnn reason-string
|
||||
string_list parts = strutils::split(r, NULL, maxSplit);
|
||||
if (parts.size() != 3) {
|
||||
throw sg_io_exception("bad HTTP response");
|
||||
throw sg_io_exception("bad HTTP response:" + r);
|
||||
}
|
||||
|
||||
|
||||
_responseVersion = decodeHTTPVersion(parts[0]);
|
||||
_responseStatus = strutils::to_int(parts[1]);
|
||||
_responseReason = parts[2];
|
||||
|
||||
setReadyState(STATUS_RECEIVED);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void Request::responseHeader(const std::string& key, const std::string& value)
|
||||
{
|
||||
if( key == "connection" )
|
||||
if( key == "connection" ) {
|
||||
_willClose = (value.find("close") != std::string::npos);
|
||||
} else if (key == "content-length") {
|
||||
int sz = strutils::to_int(value);
|
||||
setResponseLength(sz);
|
||||
}
|
||||
|
||||
_responseHeaders[key] = value;
|
||||
}
|
||||
@@ -190,7 +213,7 @@ std::string Request::scheme() const
|
||||
if (firstColon > 0) {
|
||||
return url().substr(0, firstColon);
|
||||
}
|
||||
|
||||
|
||||
return ""; // couldn't parse scheme
|
||||
}
|
||||
|
||||
@@ -202,20 +225,20 @@ std::string Request::path() const
|
||||
if (schemeEnd < 0) {
|
||||
return ""; // couldn't parse scheme
|
||||
}
|
||||
|
||||
|
||||
int hostEnd = u.find('/', schemeEnd + 3);
|
||||
if (hostEnd < 0) {
|
||||
// couldn't parse host, or URL looks like 'http://foo.com' (no trailing '/')
|
||||
// fixup to root resource path: '/'
|
||||
return "/";
|
||||
// couldn't parse host, or URL looks like 'http://foo.com' (no trailing '/')
|
||||
// fixup to root resource path: '/'
|
||||
return "/";
|
||||
}
|
||||
|
||||
|
||||
int query = u.find('?', hostEnd + 1);
|
||||
if (query < 0) {
|
||||
// all remainder of URL is path
|
||||
return u.substr(hostEnd);
|
||||
}
|
||||
|
||||
|
||||
return u.substr(hostEnd, query - hostEnd);
|
||||
}
|
||||
|
||||
@@ -227,7 +250,7 @@ std::string Request::query() const
|
||||
if (query < 0) {
|
||||
return ""; //no query string found
|
||||
}
|
||||
|
||||
|
||||
return u.substr(query); //includes question mark
|
||||
}
|
||||
|
||||
@@ -302,6 +325,7 @@ unsigned int Request::responseLength() const
|
||||
//------------------------------------------------------------------------------
|
||||
void Request::setFailure(int code, const std::string& reason)
|
||||
{
|
||||
SG_LOG(SG_IO, SG_WARN, "HTTP request: set failure:" << code << " reason " << reason);
|
||||
_responseStatus = code;
|
||||
_responseReason = reason;
|
||||
|
||||
|
||||
@@ -1,3 +1,22 @@
|
||||
///@file
|
||||
//
|
||||
// Copyright (C) 2011 James Turner <zakalawe@mac.com>
|
||||
// Copyright (C) 2013 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_HTTP_REQUEST_HXX
|
||||
#define SG_HTTP_REQUEST_HXX
|
||||
|
||||
@@ -18,6 +37,9 @@ namespace simgear
|
||||
namespace HTTP
|
||||
{
|
||||
|
||||
/**
|
||||
* Base class for HTTP request (and answer).
|
||||
*/
|
||||
class Request:
|
||||
public SGReferenced
|
||||
{
|
||||
@@ -28,6 +50,7 @@ public:
|
||||
{
|
||||
UNSENT = 0,
|
||||
OPENED,
|
||||
STATUS_RECEIVED,
|
||||
HEADERS_RECEIVED,
|
||||
LOADING,
|
||||
DONE,
|
||||
@@ -102,19 +125,19 @@ public:
|
||||
void setBodyData( const SGPropertyNode* data );
|
||||
|
||||
virtual void setUrl(const std::string& url);
|
||||
|
||||
|
||||
virtual std::string method() const
|
||||
{ return _method; }
|
||||
virtual std::string url() const
|
||||
{ return _url; }
|
||||
|
||||
|
||||
virtual std::string scheme() const;
|
||||
virtual std::string path() const;
|
||||
virtual std::string host() const;
|
||||
virtual std::string hostAndPort() const;
|
||||
virtual unsigned short port() const;
|
||||
virtual std::string query() const;
|
||||
|
||||
|
||||
StringMap const& responseHeaders() const
|
||||
{ return _responseHeaders; }
|
||||
|
||||
@@ -122,13 +145,13 @@ public:
|
||||
|
||||
virtual int responseCode() const
|
||||
{ return _responseStatus; }
|
||||
|
||||
|
||||
virtual std::string responseReason() const
|
||||
{ return _responseReason; }
|
||||
|
||||
|
||||
void setResponseLength(unsigned int l);
|
||||
virtual unsigned int responseLength() const;
|
||||
|
||||
|
||||
/**
|
||||
* Check if request contains body data.
|
||||
*/
|
||||
@@ -143,32 +166,32 @@ public:
|
||||
* Retrieve the size of the request body.
|
||||
*/
|
||||
virtual size_t bodyLength() const;
|
||||
|
||||
|
||||
/**
|
||||
* Retrieve the body data bytes. Will be passed the maximum body bytes
|
||||
* to return in the buffer, and must return the actual number
|
||||
* of bytes written.
|
||||
* of bytes written.
|
||||
*/
|
||||
virtual size_t getBodyData(char* s, size_t offset, size_t max_count) const;
|
||||
|
||||
|
||||
/**
|
||||
* running total of body bytes received so far. Can be used
|
||||
* to generate a completion percentage, if the response length is
|
||||
* known.
|
||||
* known.
|
||||
*/
|
||||
unsigned int responseBytesReceived() const
|
||||
{ return _receivedBodyBytes; }
|
||||
|
||||
|
||||
enum HTTPVersion {
|
||||
HTTP_VERSION_UNKNOWN = 0,
|
||||
HTTP_0_x, // 0.9 or similar
|
||||
HTTP_1_0,
|
||||
HTTP_1_1
|
||||
};
|
||||
|
||||
|
||||
HTTPVersion responseVersion() const
|
||||
{ return _responseVersion; }
|
||||
|
||||
|
||||
ReadyState readyState() const { return _ready_state; }
|
||||
|
||||
/**
|
||||
@@ -204,7 +227,7 @@ private:
|
||||
friend class Client;
|
||||
friend class Connection;
|
||||
friend class ContentDecoder;
|
||||
|
||||
|
||||
Request(const Request&); // = delete;
|
||||
Request& operator=(const Request&); // = delete;
|
||||
|
||||
|
||||
@@ -96,14 +96,14 @@ void SVNDirectory::parseCache()
|
||||
LineState lineState = LINESTATE_HREF;
|
||||
std::ifstream file(p.c_str());
|
||||
if (!file.is_open()) {
|
||||
SG_LOG(SG_IO, SG_WARN, "unable to open cache file for reading:" << p);
|
||||
SG_LOG(SG_TERRASYNC, SG_WARN, "unable to open cache file for reading:" << p);
|
||||
return;
|
||||
}
|
||||
bool doneSelf = false;
|
||||
|
||||
file.getline(href, 1024);
|
||||
if (strcmp(CACHE_VERSION_4_TOKEN, href)) {
|
||||
SG_LOG(SG_IO, SG_WARN, "invalid cache file [missing header token]:" << p << " '" << href << "'");
|
||||
SG_LOG(SG_TERRASYNC, SG_WARN, "invalid cache file [missing header token]:" << p << " '" << href << "'");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -183,7 +183,7 @@ void SVNDirectory::writeCache()
|
||||
void SVNDirectory::setBaseUrl(const string& url)
|
||||
{
|
||||
if (_parent) {
|
||||
SG_LOG(SG_IO, SG_ALERT, "setting base URL on non-root directory " << url);
|
||||
SG_LOG(SG_TERRASYNC, SG_ALERT, "setting base URL on non-root directory " << url);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -239,7 +239,6 @@ void SVNDirectory::deleteChildByName(const std::string& nm)
|
||||
{
|
||||
DAVResource* child = dav->childWithName(nm);
|
||||
if (!child) {
|
||||
// std::cerr << "ZZZ: deleteChildByName: unknown:" << nm << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -247,17 +246,24 @@ void SVNDirectory::deleteChildByName(const std::string& nm)
|
||||
|
||||
if (child->isCollection()) {
|
||||
Dir d(path);
|
||||
d.remove(true);
|
||||
|
||||
bool ok = d.remove(true);
|
||||
if (!ok) {
|
||||
SG_LOG(SG_TERRASYNC, SG_ALERT, "SVNDirectory::deleteChildByName: failed to remove dir:"
|
||||
<< nm << " at path:\n\t" << path);
|
||||
}
|
||||
|
||||
DirectoryList::iterator it = findChildDir(nm);
|
||||
if (it != _children.end()) {
|
||||
SVNDirectory* c = *it;
|
||||
// std::cout << "YYY: deleting SVNDirectory for:" << nm << std::endl;
|
||||
delete c;
|
||||
_children.erase(it);
|
||||
}
|
||||
} else {
|
||||
path.remove();
|
||||
bool ok = path.remove();
|
||||
if (!ok) {
|
||||
SG_LOG(SG_TERRASYNC, SG_ALERT, "SVNDirectory::deleteChildByName: failed to remove path:" << nm
|
||||
<< " at path:\n\t" << path);
|
||||
}
|
||||
}
|
||||
|
||||
dav->removeChild(child);
|
||||
|
||||
@@ -73,7 +73,7 @@ public:
|
||||
|
||||
void updateFailed(HTTP::Request* req, SVNRepository::ResultCode err)
|
||||
{
|
||||
SG_LOG(SG_IO, SG_WARN, "SVN: failed to update from:" << req->url()
|
||||
SG_LOG(SG_TERRASYNC, SG_WARN, "SVN: failed to update from:" << req->url()
|
||||
<< "\n(repository:" << p->baseUrl() << ")");
|
||||
isUpdating = false;
|
||||
status = err;
|
||||
@@ -120,6 +120,7 @@ namespace { // anonmouse
|
||||
Request(repo->baseUrl, "PROPFIND"),
|
||||
_repo(repo)
|
||||
{
|
||||
assert(repo);
|
||||
requestHeader("Depth") = "0";
|
||||
setBodyData( PROPFIND_REQUEST_BODY,
|
||||
"application/xml; charset=\"utf-8\"" );
|
||||
@@ -133,11 +134,13 @@ namespace { // anonmouse
|
||||
} else if (responseCode() == 404) {
|
||||
_repo->propFindFailed(this, SVNRepository::SVN_ERROR_NOT_FOUND);
|
||||
} else {
|
||||
SG_LOG(SG_IO, SG_WARN, "request for:" << url() <<
|
||||
SG_LOG(SG_TERRASYNC, SG_WARN, "request for:" << url() <<
|
||||
" return code " << responseCode());
|
||||
_repo->propFindFailed(this, SVNRepository::SVN_ERROR_SOCKET);
|
||||
_repo = NULL;
|
||||
}
|
||||
|
||||
Request::responseHeadersComplete();
|
||||
}
|
||||
|
||||
virtual void onDone()
|
||||
@@ -228,7 +231,7 @@ protected:
|
||||
_repo->updateFailed(this, SVNRepository::SVN_ERROR_NOT_FOUND);
|
||||
_failed = true;
|
||||
} else {
|
||||
SG_LOG(SG_IO, SG_WARN, "SVN: request for:" << url() <<
|
||||
SG_LOG(SG_TERRASYNC, SG_WARN, "SVN: request for:" << url() <<
|
||||
" got HTTP status " << responseCode());
|
||||
_repo->updateFailed(this, SVNRepository::SVN_ERROR_HTTP);
|
||||
_failed = true;
|
||||
@@ -328,7 +331,7 @@ void SVNRepository::update()
|
||||
}
|
||||
|
||||
if (_d->targetRevision == rootDir()->cachedRevision()) {
|
||||
SG_LOG(SG_IO, SG_DEBUG, baseUrl() << " in sync at version " << _d->targetRevision);
|
||||
SG_LOG(SG_TERRASYNC, SG_DEBUG, baseUrl() << " in sync at version " << _d->targetRevision);
|
||||
_d->isUpdating = false;
|
||||
return;
|
||||
}
|
||||
@@ -372,7 +375,7 @@ void SVNRepoPrivate::propFindComplete(HTTP::Request* req, DAVCollection* c)
|
||||
void SVNRepoPrivate::propFindFailed(HTTP::Request *req, SVNRepository::ResultCode err)
|
||||
{
|
||||
if (err != SVNRepository::SVN_ERROR_NOT_FOUND) {
|
||||
SG_LOG(SG_IO, SG_WARN, "PropFind failed for:" << req->url());
|
||||
SG_LOG(SG_TERRASYNC, SG_WARN, "PropFind failed for:" << req->url());
|
||||
}
|
||||
|
||||
isUpdating = false;
|
||||
|
||||
@@ -274,6 +274,15 @@ static void read_indices(char* buffer,
|
||||
if (vaMask & SG_VA_FLOAT_3) vas[7].push_back(*src++);
|
||||
}
|
||||
} // of elements in the index
|
||||
|
||||
// WS2.0 fix : toss zero area triangles
|
||||
if ( ( count == 3 ) && (indexMask & SG_IDX_VERTICES) ) {
|
||||
if ( (vertices[0] == vertices[1]) ||
|
||||
(vertices[1] == vertices[2]) ||
|
||||
(vertices[2] == vertices[0]) ) {
|
||||
vertices.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
@@ -468,12 +477,15 @@ void SGBinObject::read_object( gzFile fp,
|
||||
read_indices<uint16_t>(ptr, nbytes, idx_mask, vertex_attrib_mask, vs, ns, cs, tcs, vas );
|
||||
}
|
||||
|
||||
vertices.push_back( vs );
|
||||
normals.push_back( ns );
|
||||
colors.push_back( cs );
|
||||
texCoords.push_back( tcs );
|
||||
vertexAttribs.push_back( vas );
|
||||
materials.push_back( material );
|
||||
// Fix for WS2.0 - ignore zero area triangles
|
||||
if ( !vs.empty() ) {
|
||||
vertices.push_back( vs );
|
||||
normals.push_back( ns );
|
||||
colors.push_back( cs );
|
||||
texCoords.push_back( tcs );
|
||||
vertexAttribs.push_back( vas );
|
||||
materials.push_back( material );
|
||||
}
|
||||
} // of element iteration
|
||||
}
|
||||
|
||||
|
||||
@@ -44,9 +44,8 @@
|
||||
|
||||
#include "sg_file.hxx"
|
||||
|
||||
using std::string;
|
||||
|
||||
SGFile::SGFile(const string &file, int repeat_)
|
||||
SGFile::SGFile(const std::string &file, int repeat_)
|
||||
: file_name(file), fp(-1), eof_flag(true), repeat(repeat_), iteration(0)
|
||||
{
|
||||
set_type( sgFileType );
|
||||
|
||||
@@ -1,37 +1,31 @@
|
||||
/** \file sg_file.hxx
|
||||
* File I/O routines.
|
||||
*/
|
||||
|
||||
///@file
|
||||
/// File I/O routines.
|
||||
//
|
||||
// Written by Curtis Olson, started November 1999.
|
||||
//
|
||||
// Copyright (C) 1999 Curtis L. Olson - http://www.flightgear.org/~curt
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU 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 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 program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// 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
|
||||
// General Public License for more details.
|
||||
// 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$
|
||||
|
||||
// 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_FILE_HXX
|
||||
#define _SG_FILE_HXX
|
||||
|
||||
#include <simgear/compiler.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "iochannel.hxx"
|
||||
|
||||
#include <string>
|
||||
|
||||
/**
|
||||
* A file I/O class based on SGIOChannel.
|
||||
@@ -91,7 +85,4 @@ public:
|
||||
virtual bool eof() const { return eof_flag; };
|
||||
};
|
||||
|
||||
|
||||
#endif // _SG_FILE_HXX
|
||||
|
||||
|
||||
|
||||
@@ -227,6 +227,13 @@ void NetChannel::handleAccept (void) {
|
||||
|
||||
void NetChannel::handleError (int error)
|
||||
{
|
||||
if (error == EINPROGRESS) {
|
||||
// this shoudl never happen, because we should use isNonBlocking to check
|
||||
// such error codes.
|
||||
SG_LOG(SG_IO, SG_WARN, "Got EINPROGRESS at NetChannel::handleError: suggests broken logic somewhere else");
|
||||
return; // not an actual error, don't warn
|
||||
}
|
||||
|
||||
// warn about address lookup failures seperately, don't warn again.
|
||||
// (and we (ab-)use ENOENT to mean 'name not found'.
|
||||
if (error != ENOENT) {
|
||||
@@ -251,6 +258,11 @@ NetChannelPoller::removeChannel(NetChannel* channel)
|
||||
assert(channel->poller == this);
|
||||
channel->poller = NULL;
|
||||
|
||||
// portability: MSVC throws assertion failure when empty
|
||||
if (channels.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
ChannelList::iterator it = channels.begin();
|
||||
for (; it != channels.end(); ++it) {
|
||||
if (*it == channel) {
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
|
||||
#include <cstring>
|
||||
#include <cstdlib>
|
||||
#include <algorithm>
|
||||
|
||||
namespace simgear {
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
|
||||
#include <cstring>
|
||||
#include <cstdlib> // for atoi
|
||||
#include <algorithm>
|
||||
|
||||
using std::string;
|
||||
|
||||
|
||||
@@ -3,15 +3,23 @@
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <sstream>
|
||||
#include <errno.h>
|
||||
|
||||
#include <boost/algorithm/string/case_conv.hpp>
|
||||
|
||||
#include <simgear/simgear_config.h>
|
||||
|
||||
#include "HTTPClient.hxx"
|
||||
#include "HTTPRequest.hxx"
|
||||
|
||||
#include <simgear/io/sg_netChat.hxx>
|
||||
#include <simgear/misc/strutils.hxx>
|
||||
#include <simgear/timing/timestamp.hxx>
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
|
||||
#if defined(ENABLE_CURL)
|
||||
#include <curl/multi.h>
|
||||
#endif
|
||||
|
||||
using std::cout;
|
||||
using std::cerr;
|
||||
@@ -46,7 +54,7 @@ char body2[body2Size];
|
||||
cerr << "failed:" << #a << endl; \
|
||||
exit(1); \
|
||||
}
|
||||
|
||||
|
||||
class TestRequest : public HTTP::Request
|
||||
{
|
||||
public:
|
||||
@@ -54,41 +62,43 @@ public:
|
||||
bool failed;
|
||||
string bodyData;
|
||||
|
||||
TestRequest(const std::string& url, const std::string method = "GET") :
|
||||
TestRequest(const std::string& url, const std::string method = "GET") :
|
||||
HTTP::Request(url, method),
|
||||
complete(false)
|
||||
complete(false),
|
||||
failed(false)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
std::map<string, string> headers;
|
||||
protected:
|
||||
|
||||
|
||||
virtual void onDone()
|
||||
{
|
||||
complete = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
virtual void onFail()
|
||||
{
|
||||
failed = true;
|
||||
}
|
||||
|
||||
|
||||
virtual void gotBodyData(const char* s, int n)
|
||||
{
|
||||
//std::cout << "got body data:'" << string(s, n) << "'" <<std::endl;
|
||||
bodyData += string(s, n);
|
||||
}
|
||||
|
||||
|
||||
virtual void responseHeader(const string& header, const string& value)
|
||||
{
|
||||
Request::responseHeader(header, value);
|
||||
headers[header] = value;
|
||||
}
|
||||
};
|
||||
|
||||
class TestServerChannel : public NetChat
|
||||
{
|
||||
public:
|
||||
public:
|
||||
enum State
|
||||
{
|
||||
STATE_IDLE = 0,
|
||||
@@ -96,19 +106,19 @@ public:
|
||||
STATE_CLOSING,
|
||||
STATE_REQUEST_BODY
|
||||
};
|
||||
|
||||
|
||||
TestServerChannel()
|
||||
{
|
||||
state = STATE_IDLE;
|
||||
setTerminator("\r\n");
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
virtual void collectIncomingData(const char* s, int n)
|
||||
{
|
||||
buffer += string(s, n);
|
||||
}
|
||||
|
||||
|
||||
virtual void foundTerminator(void)
|
||||
{
|
||||
if (state == STATE_IDLE) {
|
||||
@@ -118,16 +128,16 @@ public:
|
||||
cerr << "malformed request:" << buffer << endl;
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
|
||||
method = line[0];
|
||||
path = line[1];
|
||||
|
||||
|
||||
string::size_type queryPos = path.find('?');
|
||||
if (queryPos != string::npos) {
|
||||
parseArgs(path.substr(queryPos + 1));
|
||||
path = path.substr(0, queryPos);
|
||||
}
|
||||
|
||||
|
||||
httpVersion = line[2];
|
||||
requestHeaders.clear();
|
||||
buffer.clear();
|
||||
@@ -138,10 +148,10 @@ public:
|
||||
receivedRequestHeaders();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
string::size_type colonPos = buffer.find(':');
|
||||
if (colonPos == string::npos) {
|
||||
cerr << "malformed HTTP response header:" << buffer << endl;
|
||||
cerr << "test malformed HTTP response header:" << buffer << endl;
|
||||
buffer.clear();
|
||||
return;
|
||||
}
|
||||
@@ -156,8 +166,8 @@ public:
|
||||
} else if (state == STATE_CLOSING) {
|
||||
// ignore!
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void parseArgs(const string& argData)
|
||||
{
|
||||
string_list argv = strutils::split(argData, "&");
|
||||
@@ -173,11 +183,10 @@ public:
|
||||
args[key] = value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void receivedRequestHeaders()
|
||||
{
|
||||
state = STATE_IDLE;
|
||||
|
||||
if (path == "/test1") {
|
||||
string contentStr(BODY1);
|
||||
stringstream d;
|
||||
@@ -205,7 +214,7 @@ public:
|
||||
} else if (path == "/test_headers") {
|
||||
COMPARE(requestHeaders["X-Foo"], string("Bar"));
|
||||
COMPARE(requestHeaders["X-AnotherHeader"], string("A longer value"));
|
||||
|
||||
|
||||
string contentStr(BODY1);
|
||||
stringstream d;
|
||||
d << "HTTP/1.1 " << 200 << " " << reasonForCode(200) << "\r\n";
|
||||
@@ -235,11 +244,11 @@ public:
|
||||
if (requestHeaders["Host"] != "www.google.com") {
|
||||
sendErrorResponse(400, true, "bad destination");
|
||||
}
|
||||
|
||||
|
||||
if (requestHeaders["Proxy-Authorization"] != string()) {
|
||||
sendErrorResponse(401, false, "bad auth"); // shouldn't supply auth
|
||||
sendErrorResponse(401, false, "bad auth, not empty"); // shouldn't supply auth
|
||||
}
|
||||
|
||||
|
||||
sendBody2();
|
||||
} else if (path == "http://www.google.com/test3") {
|
||||
// proxy test
|
||||
@@ -247,8 +256,28 @@ public:
|
||||
sendErrorResponse(400, true, "bad destination");
|
||||
}
|
||||
|
||||
if (requestHeaders["Proxy-Authorization"] != "ABCDEF") {
|
||||
sendErrorResponse(401, false, "bad auth"); // forbidden
|
||||
string credentials = requestHeaders["Proxy-Authorization"];
|
||||
if (credentials.substr(0, 5) != "Basic") {
|
||||
// request basic auth
|
||||
stringstream d;
|
||||
d << "HTTP/1.1 " << 407 << " " << reasonForCode(407) << "\r\n";
|
||||
d << "WWW-Authenticate: Basic real=\"simgear\"\r\n";
|
||||
d << "\r\n"; // final CRLF to terminate the headers
|
||||
push(d.str().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<unsigned char> userAndPass;
|
||||
strutils::decodeBase64(credentials.substr(6), userAndPass);
|
||||
std::string decodedUserPass((char*) userAndPass.data(), userAndPass.size());
|
||||
|
||||
if (decodedUserPass != "johndoe:swordfish") {
|
||||
std::map<string, string>::const_iterator it;
|
||||
for (it = requestHeaders.begin(); it != requestHeaders.end(); ++it) {
|
||||
cerr << "header:" << it->first << " = " << it->second << endl;
|
||||
}
|
||||
|
||||
sendErrorResponse(401, false, "bad auth, not as set"); // forbidden
|
||||
}
|
||||
|
||||
sendBody2();
|
||||
@@ -272,6 +301,12 @@ public:
|
||||
d << contentStr;
|
||||
push(d.str().c_str());
|
||||
closeAfterSending();
|
||||
} else if (path == "/test_abrupt_close") {
|
||||
// simulate server doing socket close before sending any
|
||||
// response - this used to cause a TerraSync failure since we
|
||||
// would get stuck restarting the request
|
||||
closeAfterSending();
|
||||
|
||||
} else if (path == "/test_args") {
|
||||
if ((args["foo"] != "abc") || (args["bar"] != "1234") || (args["username"] != "johndoe")) {
|
||||
sendErrorResponse(400, true, "bad arguments");
|
||||
@@ -291,43 +326,78 @@ public:
|
||||
sendErrorResponse(400, true, "bad content type");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
requestContentLength = strutils::to_int(requestHeaders["Content-Length"]);
|
||||
setByteCount(requestContentLength);
|
||||
state = STATE_REQUEST_BODY;
|
||||
} else if ((path == "/test_put") || (path == "/test_create")) {
|
||||
if (requestHeaders["Content-Type"] != "x-application/foobar") {
|
||||
cerr << "bad content type: '" << requestHeaders["Content-Type"] << "'" << endl;
|
||||
sendErrorResponse(400, true, "bad content type");
|
||||
return;
|
||||
}
|
||||
|
||||
requestContentLength = strutils::to_int(requestHeaders["Content-Length"]);
|
||||
setByteCount(requestContentLength);
|
||||
state = STATE_REQUEST_BODY;
|
||||
} else {
|
||||
sendErrorResponse(404, false, "");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void closeAfterSending()
|
||||
{
|
||||
state = STATE_CLOSING;
|
||||
closeWhenDone();
|
||||
}
|
||||
|
||||
|
||||
void receivedBody()
|
||||
{
|
||||
state = STATE_IDLE;
|
||||
if (method == "POST") {
|
||||
parseArgs(buffer);
|
||||
}
|
||||
|
||||
|
||||
if (path == "/test_post") {
|
||||
if ((args["foo"] != "abc") || (args["bar"] != "1234") || (args["username"] != "johndoe")) {
|
||||
sendErrorResponse(400, true, "bad arguments");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
stringstream d;
|
||||
d << "HTTP/1.1 " << 204 << " " << reasonForCode(204) << "\r\n";
|
||||
d << "\r\n"; // final CRLF to terminate the headers
|
||||
push(d.str().c_str());
|
||||
|
||||
cerr << "sent 204 response ok" << endl;
|
||||
} else if (path == "/test_put") {
|
||||
std::cerr << "sending PUT response" << std::endl;
|
||||
|
||||
COMPARE(buffer, BODY3);
|
||||
stringstream d;
|
||||
d << "HTTP/1.1 " << 204 << " " << reasonForCode(204) << "\r\n";
|
||||
d << "\r\n"; // final CRLF to terminate the headers
|
||||
push(d.str().c_str());
|
||||
} else if (path == "/test_create") {
|
||||
std::cerr << "sending create response" << std::endl;
|
||||
|
||||
std::string entityStr = "http://localhost:2000/something.txt";
|
||||
|
||||
COMPARE(buffer, BODY3);
|
||||
stringstream d;
|
||||
d << "HTTP/1.1 " << 201 << " " << reasonForCode(201) << "\r\n";
|
||||
d << "Location:" << entityStr << "\r\n";
|
||||
d << "Content-Length:" << entityStr.size() << "\r\n";
|
||||
d << "\r\n"; // final CRLF to terminate the headers
|
||||
d << entityStr;
|
||||
|
||||
push(d.str().c_str());
|
||||
} else {
|
||||
std::cerr << "weird URL " << path << std::endl;
|
||||
sendErrorResponse(400, true, "bad URL:" + path);
|
||||
}
|
||||
|
||||
buffer.clear();
|
||||
}
|
||||
|
||||
|
||||
void sendBody2()
|
||||
{
|
||||
stringstream d;
|
||||
@@ -337,32 +407,36 @@ public:
|
||||
push(d.str().c_str());
|
||||
bufferSend(body2, body2Size);
|
||||
}
|
||||
|
||||
|
||||
void sendErrorResponse(int code, bool close, string content)
|
||||
{
|
||||
cerr << "sending error " << code << " for " << path << endl;
|
||||
cerr << "\tcontent:" << content << endl;
|
||||
|
||||
stringstream headerData;
|
||||
headerData << "HTTP/1.1 " << code << " " << reasonForCode(code) << "\r\n";
|
||||
headerData << "Content-Length:" << content.size() << "\r\n";
|
||||
headerData << "\r\n"; // final CRLF to terminate the headers
|
||||
push(headerData.str().c_str());
|
||||
push(content.c_str());
|
||||
|
||||
|
||||
if (close) {
|
||||
closeWhenDone();
|
||||
}
|
||||
}
|
||||
|
||||
string reasonForCode(int code)
|
||||
|
||||
string reasonForCode(int code)
|
||||
{
|
||||
switch (code) {
|
||||
case 200: return "OK";
|
||||
case 201: return "Created";
|
||||
case 204: return "no content";
|
||||
case 404: return "not found";
|
||||
case 407: return "proxy authentication required";
|
||||
default: return "unknown code";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
State state;
|
||||
string buffer;
|
||||
string method;
|
||||
@@ -376,20 +450,22 @@ public:
|
||||
class TestServer : public NetChannel
|
||||
{
|
||||
simgear::NetChannelPoller _poller;
|
||||
public:
|
||||
public:
|
||||
TestServer()
|
||||
{
|
||||
Socket::initSockets();
|
||||
|
||||
open();
|
||||
bind(NULL, 2000); // localhost, any port
|
||||
listen(5);
|
||||
|
||||
|
||||
_poller.addChannel(this);
|
||||
}
|
||||
|
||||
|
||||
virtual ~TestServer()
|
||||
{
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
virtual bool writable (void) { return false ; }
|
||||
|
||||
virtual void handleAccept (void)
|
||||
@@ -399,10 +475,10 @@ public:
|
||||
//cout << "did accept from " << addr.getHost() << ":" << addr.getPort() << endl;
|
||||
TestServerChannel* chan = new TestServerChannel();
|
||||
chan->setHandle(handle);
|
||||
|
||||
|
||||
_poller.addChannel(chan);
|
||||
}
|
||||
|
||||
|
||||
void poll()
|
||||
{
|
||||
_poller.poll();
|
||||
@@ -414,42 +490,43 @@ TestServer testServer;
|
||||
void waitForComplete(HTTP::Client* cl, TestRequest* tr)
|
||||
{
|
||||
SGTimeStamp start(SGTimeStamp::now());
|
||||
while (start.elapsedMSec() < 1000) {
|
||||
while (start.elapsedMSec() < 10000) {
|
||||
cl->update();
|
||||
testServer.poll();
|
||||
|
||||
|
||||
if (tr->complete) {
|
||||
return;
|
||||
}
|
||||
SGTimeStamp::sleepForMSec(1);
|
||||
SGTimeStamp::sleepForMSec(15);
|
||||
}
|
||||
|
||||
|
||||
cerr << "timed out" << endl;
|
||||
}
|
||||
|
||||
void waitForFailed(HTTP::Client* cl, TestRequest* tr)
|
||||
{
|
||||
SGTimeStamp start(SGTimeStamp::now());
|
||||
while (start.elapsedMSec() < 1000) {
|
||||
while (start.elapsedMSec() < 10000) {
|
||||
cl->update();
|
||||
testServer.poll();
|
||||
|
||||
|
||||
if (tr->failed) {
|
||||
return;
|
||||
}
|
||||
SGTimeStamp::sleepForMSec(1);
|
||||
SGTimeStamp::sleepForMSec(15);
|
||||
}
|
||||
|
||||
|
||||
cerr << "timed out waiting for failure" << endl;
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
|
||||
sglog().setLogLevels( SG_ALL, SG_INFO );
|
||||
|
||||
HTTP::Client cl;
|
||||
// force all requests to use the same connection for this test
|
||||
cl.setMaxConnections(1);
|
||||
|
||||
cl.setMaxConnections(1);
|
||||
|
||||
// test URL parsing
|
||||
TestRequest* tr1 = new TestRequest("http://localhost.woo.zar:2000/test1?foo=bar");
|
||||
COMPARE(tr1->scheme(), "http");
|
||||
@@ -457,14 +534,14 @@ int main(int argc, char* argv[])
|
||||
COMPARE(tr1->host(), "localhost.woo.zar");
|
||||
COMPARE(tr1->port(), 2000);
|
||||
COMPARE(tr1->path(), "/test1");
|
||||
|
||||
|
||||
TestRequest* tr2 = new TestRequest("http://192.168.1.1/test1/dir/thing/file.png");
|
||||
COMPARE(tr2->scheme(), "http");
|
||||
COMPARE(tr2->hostAndPort(), "192.168.1.1");
|
||||
COMPARE(tr2->host(), "192.168.1.1");
|
||||
COMPARE(tr2->port(), 80);
|
||||
COMPARE(tr2->path(), "/test1/dir/thing/file.png");
|
||||
|
||||
|
||||
// basic get request
|
||||
{
|
||||
TestRequest* tr = new TestRequest("http://localhost:2000/test1");
|
||||
@@ -478,12 +555,12 @@ int main(int argc, char* argv[])
|
||||
COMPARE(tr->responseBytesReceived(), strlen(BODY1));
|
||||
COMPARE(tr->bodyData, string(BODY1));
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
TestRequest* tr = new TestRequest("http://localhost:2000/testLorem");
|
||||
HTTP::Request_ptr own(tr);
|
||||
cl.makeRequest(tr);
|
||||
|
||||
|
||||
waitForComplete(&cl, tr);
|
||||
COMPARE(tr->responseCode(), 200);
|
||||
COMPARE(tr->responseReason(), string("OK"));
|
||||
@@ -491,7 +568,7 @@ int main(int argc, char* argv[])
|
||||
COMPARE(tr->responseBytesReceived(), strlen(BODY3));
|
||||
COMPARE(tr->bodyData, string(BODY3));
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
TestRequest* tr = new TestRequest("http://localhost:2000/test_args?foo=abc&bar=1234&username=johndoe");
|
||||
HTTP::Request_ptr own(tr);
|
||||
@@ -499,9 +576,7 @@ int main(int argc, char* argv[])
|
||||
waitForComplete(&cl, tr);
|
||||
COMPARE(tr->responseCode(), 200);
|
||||
}
|
||||
|
||||
cerr << "done args" << endl;
|
||||
|
||||
|
||||
{
|
||||
TestRequest* tr = new TestRequest("http://localhost:2000/test_headers");
|
||||
HTTP::Request_ptr own(tr);
|
||||
@@ -516,12 +591,12 @@ int main(int argc, char* argv[])
|
||||
COMPARE(tr->responseBytesReceived(), strlen(BODY1));
|
||||
COMPARE(tr->bodyData, string(BODY1));
|
||||
}
|
||||
|
||||
|
||||
// larger get request
|
||||
for (unsigned int i=0; i<body2Size; ++i) {
|
||||
body2[i] = (i << 4) | (i >> 2);
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
TestRequest* tr = new TestRequest("http://localhost:2000/test2");
|
||||
HTTP::Request_ptr own(tr);
|
||||
@@ -531,8 +606,8 @@ int main(int argc, char* argv[])
|
||||
COMPARE(tr->responseBytesReceived(), body2Size);
|
||||
COMPARE(tr->bodyData, string(body2, body2Size));
|
||||
}
|
||||
|
||||
cerr << "testing chunked" << endl;
|
||||
|
||||
cerr << "testing chunked transfer encoding" << endl;
|
||||
{
|
||||
TestRequest* tr = new TestRequest("http://localhost:2000/testchunked");
|
||||
HTTP::Request_ptr own(tr);
|
||||
@@ -546,7 +621,7 @@ int main(int argc, char* argv[])
|
||||
// check trailers made it too
|
||||
COMPARE(tr->headers["x-foobar"], string("wibble"));
|
||||
}
|
||||
|
||||
|
||||
// test 404
|
||||
{
|
||||
TestRequest* tr = new TestRequest("http://localhost:2000/not-found");
|
||||
@@ -593,15 +668,40 @@ int main(int argc, char* argv[])
|
||||
}
|
||||
cout << "done3" << endl;
|
||||
// test connectToHost failure
|
||||
/*
|
||||
|
||||
{
|
||||
TestRequest* tr = new TestRequest("http://not.found/something");
|
||||
HTTP::Request_ptr own(tr);
|
||||
cl.makeRequest(tr);
|
||||
waitForFailed(tr);
|
||||
COMPARE(tr->responseCode(), -1);
|
||||
waitForFailed(&cl, tr);
|
||||
|
||||
|
||||
|
||||
#if defined(ENABLE_CURL)
|
||||
const int HOST_NOT_FOUND_CODE = CURLE_COULDNT_RESOLVE_HOST;
|
||||
#else
|
||||
const int HOST_NOT_FOUND_CODE = ENOENT;
|
||||
#endif
|
||||
COMPARE(tr->responseCode(), HOST_NOT_FOUND_CODE);
|
||||
}
|
||||
*/
|
||||
|
||||
cout << "testing abrupt close" << endl;
|
||||
// test server-side abrupt close
|
||||
{
|
||||
TestRequest* tr = new TestRequest("http://localhost:2000/test_abrupt_close");
|
||||
HTTP::Request_ptr own(tr);
|
||||
cl.makeRequest(tr);
|
||||
waitForFailed(&cl, tr);
|
||||
|
||||
#if defined(ENABLE_CURL)
|
||||
const int SERVER_NO_DATA_CODE = CURLE_GOT_NOTHING;
|
||||
#else
|
||||
const int SERVER_NO_DATA_CODE = 500;
|
||||
#endif
|
||||
COMPARE(tr->responseCode(), SERVER_NO_DATA_CODE);
|
||||
}
|
||||
|
||||
cout << "testing proxy close" << endl;
|
||||
// test proxy
|
||||
{
|
||||
cl.setProxy("localhost", 2000);
|
||||
@@ -613,9 +713,10 @@ int main(int argc, char* argv[])
|
||||
COMPARE(tr->responseLength(), body2Size);
|
||||
COMPARE(tr->bodyData, string(body2, body2Size));
|
||||
}
|
||||
|
||||
|
||||
#if defined(ENABLE_CURL)
|
||||
{
|
||||
cl.setProxy("localhost", 2000, "ABCDEF");
|
||||
cl.setProxy("localhost", 2000, "johndoe:swordfish");
|
||||
TestRequest* tr = new TestRequest("http://www.google.com/test3");
|
||||
HTTP::Request_ptr own(tr);
|
||||
cl.makeRequest(tr);
|
||||
@@ -624,81 +725,105 @@ int main(int argc, char* argv[])
|
||||
COMPARE(tr->responseBytesReceived(), body2Size);
|
||||
COMPARE(tr->bodyData, string(body2, body2Size));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// pipelining
|
||||
cout << "testing HTTP 1.1 pipelineing" << endl;
|
||||
|
||||
cout << "testing HTTP 1.1 pipelining" << endl;
|
||||
|
||||
{
|
||||
|
||||
|
||||
cl.setProxy("", 80);
|
||||
TestRequest* tr = new TestRequest("http://localhost:2000/test1");
|
||||
HTTP::Request_ptr own(tr);
|
||||
cl.makeRequest(tr);
|
||||
|
||||
|
||||
|
||||
|
||||
TestRequest* tr2 = new TestRequest("http://localhost:2000/testLorem");
|
||||
HTTP::Request_ptr own2(tr2);
|
||||
cl.makeRequest(tr2);
|
||||
|
||||
|
||||
TestRequest* tr3 = new TestRequest("http://localhost:2000/test1");
|
||||
HTTP::Request_ptr own3(tr3);
|
||||
cl.makeRequest(tr3);
|
||||
|
||||
|
||||
waitForComplete(&cl, tr3);
|
||||
VERIFY(tr->complete);
|
||||
VERIFY(tr2->complete);
|
||||
COMPARE(tr->bodyData, string(BODY1));
|
||||
|
||||
|
||||
COMPARE(tr2->responseLength(), strlen(BODY3));
|
||||
COMPARE(tr2->responseBytesReceived(), strlen(BODY3));
|
||||
COMPARE(tr2->bodyData, string(BODY3));
|
||||
|
||||
|
||||
COMPARE(tr3->bodyData, string(BODY1));
|
||||
}
|
||||
|
||||
|
||||
// multiple requests with an HTTP 1.0 server
|
||||
{
|
||||
cout << "http 1.0 multiple requests" << endl;
|
||||
|
||||
|
||||
cl.setProxy("", 80);
|
||||
TestRequest* tr = new TestRequest("http://localhost:2000/test_1_0/A");
|
||||
HTTP::Request_ptr own(tr);
|
||||
cl.makeRequest(tr);
|
||||
|
||||
|
||||
TestRequest* tr2 = new TestRequest("http://localhost:2000/test_1_0/B");
|
||||
HTTP::Request_ptr own2(tr2);
|
||||
cl.makeRequest(tr2);
|
||||
|
||||
|
||||
TestRequest* tr3 = new TestRequest("http://localhost:2000/test_1_0/C");
|
||||
HTTP::Request_ptr own3(tr3);
|
||||
cl.makeRequest(tr3);
|
||||
|
||||
|
||||
waitForComplete(&cl, tr3);
|
||||
VERIFY(tr->complete);
|
||||
VERIFY(tr2->complete);
|
||||
|
||||
|
||||
COMPARE(tr->responseLength(), strlen(BODY1));
|
||||
COMPARE(tr->responseBytesReceived(), strlen(BODY1));
|
||||
COMPARE(tr->bodyData, string(BODY1));
|
||||
|
||||
|
||||
COMPARE(tr2->responseLength(), strlen(BODY3));
|
||||
COMPARE(tr2->responseBytesReceived(), strlen(BODY3));
|
||||
COMPARE(tr2->bodyData, string(BODY3));
|
||||
COMPARE(tr3->bodyData, string(BODY1));
|
||||
}
|
||||
|
||||
|
||||
// POST
|
||||
{
|
||||
cout << "POST" << endl;
|
||||
cout << "testing POST" << endl;
|
||||
TestRequest* tr = new TestRequest("http://localhost:2000/test_post?foo=abc&bar=1234&username=johndoe", "POST");
|
||||
tr->setBodyData("", "application/x-www-form-urlencoded");
|
||||
|
||||
|
||||
HTTP::Request_ptr own(tr);
|
||||
cl.makeRequest(tr);
|
||||
waitForComplete(&cl, tr);
|
||||
COMPARE(tr->responseCode(), 204);
|
||||
}
|
||||
|
||||
|
||||
// PUT
|
||||
{
|
||||
cout << "testing PUT" << endl;
|
||||
TestRequest* tr = new TestRequest("http://localhost:2000/test_put", "PUT");
|
||||
tr->setBodyData(BODY3, "x-application/foobar");
|
||||
|
||||
HTTP::Request_ptr own(tr);
|
||||
cl.makeRequest(tr);
|
||||
waitForComplete(&cl, tr);
|
||||
COMPARE(tr->responseCode(), 204);
|
||||
}
|
||||
|
||||
{
|
||||
cout << "testing PUT create" << endl;
|
||||
TestRequest* tr = new TestRequest("http://localhost:2000/test_create", "PUT");
|
||||
tr->setBodyData(BODY3, "x-application/foobar");
|
||||
|
||||
HTTP::Request_ptr own(tr);
|
||||
cl.makeRequest(tr);
|
||||
waitForComplete(&cl, tr);
|
||||
COMPARE(tr->responseCode(), 201);
|
||||
}
|
||||
|
||||
// test_zero_length_content
|
||||
{
|
||||
cout << "zero-length-content-response" << endl;
|
||||
@@ -710,8 +835,8 @@ int main(int argc, char* argv[])
|
||||
COMPARE(tr->bodyData, string());
|
||||
COMPARE(tr->responseBytesReceived(), 0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
cout << "all tests passed ok" << endl;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -93,13 +93,32 @@ void compareTexCoords(const SGBinObject& rd, const std::vector<SGVec2f>& b)
|
||||
VERIFY(equivalent(pos, b[i], 0.001f));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int_list make_tri(int maxIndex)
|
||||
{
|
||||
int_list r;
|
||||
r.push_back(random() % maxIndex);
|
||||
r.push_back(random() % maxIndex);
|
||||
r.push_back(random() % maxIndex);
|
||||
int a, b, c;
|
||||
|
||||
bool valid = false;
|
||||
int retry = 10;
|
||||
|
||||
while(!valid && retry--) {
|
||||
a = (random() % maxIndex);
|
||||
b = (random() % maxIndex);
|
||||
c = (random() % maxIndex);
|
||||
|
||||
valid = ( (a!=b) && (b!=c) && (c!=a) );
|
||||
}
|
||||
|
||||
if (!valid) {
|
||||
cerr << "can't generate valid triangle" << endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
r.push_back(a);
|
||||
r.push_back(b);
|
||||
r.push_back(c);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
// Put in some bullet-proofing to handle magnetic and geographic poles.
|
||||
// 3/28/2000 EAW
|
||||
//
|
||||
// Updated coefficient arrays to use the current WMM2005 model,
|
||||
// Updated coefficient arrays to use the current wmm2005 model,
|
||||
// (valid between 2005.0 and 2010.0)
|
||||
// Also removed unused variables and corrected earth radii constants
|
||||
// to the values for WGS84 and WMM2005.
|
||||
@@ -36,6 +36,20 @@
|
||||
//
|
||||
// 25/10/2006 Wim Van Hoydonck -- wim.van.hoydonck@gmail.com
|
||||
//
|
||||
//
|
||||
// Updated coefficient arrays to use the current WMM2015 model,
|
||||
// (valid between 2015.0 and 2020.0)
|
||||
// Also removed unused variables and corrected earth radii constants
|
||||
// to the values for WGS84 and WMM2015.
|
||||
// Reference:
|
||||
// A. Chulliat , S. Macmillan, P. Alken, C. Beggan, M.
|
||||
// Nair, B. Hamilton, A. Woods, V. Ridley,
|
||||
// S Maus, and A Thomson, December 2014, The
|
||||
// US/UK World Magnetic Model for 2015-2020,
|
||||
// NOAA Technical Report WMM2015_Report.pdf
|
||||
//
|
||||
// 18/06/2015 Jean-Paul Anceaux -- j.p.r.anceaux@gmail.com
|
||||
|
||||
|
||||
// The routine uses a spherical harmonic expansion of the magnetic
|
||||
// potential up to twelfth order, together with its time variation, as
|
||||
@@ -52,7 +66,7 @@
|
||||
// the magnetic poles (where it is ill-defined) where the error may reach
|
||||
// 4 degrees or more.
|
||||
//
|
||||
// Variation is undefined at both the geographic and
|
||||
// Variation is undefined at both the geographic and
|
||||
// magnetic poles, even though the field itself is well-behaved. To
|
||||
// avoid the routine blowing up, latitude entries corresponding to
|
||||
// the geographic poles are slightly offset. At the magnetic poles,
|
||||
@@ -79,7 +93,7 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <cmath>
|
||||
|
||||
#include <simgear/constants.h>
|
||||
#include <simgear/sg_inlines.h>
|
||||
@@ -90,72 +104,72 @@ static const double a = 6378.137; /* semi-major axis (equatorial radius) o
|
||||
static const double b = 6356.7523142; /* semi-minor axis referenced to the WGS84 ellipsoid */
|
||||
static const double r_0 = 6371.2; /* standard Earth magnetic reference radius */
|
||||
|
||||
static double gnm_wmm2005[13][13] =
|
||||
static double gnm_wmm2015[13][13] =
|
||||
{
|
||||
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{-29556.8, -1671.7, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{-2340.6, 3046.9, 1657.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{1335.4, -2305.1, 1246.7, 674.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{919.8, 798.1, 211.3, -379.4, 100.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{-227.4, 354.6, 208.7, -136.5, -168.3, -14.1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{73.2, 69.7, 76.7, -151.2, -14.9, 14.6, -86.3, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{80.1, -74.5, -1.4, 38.5, 12.4, 9.5, 5.7, 1.8, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{24.9, 7.7, -11.6, -6.9, -18.2, 10.0, 9.2, -11.6, -5.2, 0.0, 0.0, 0.0, 0.0},
|
||||
{5.6, 9.9, 3.5, -7.0, 5.1, -10.8, -1.3, 8.8, -6.7, -9.1, 0.0, 0.0, 0.0},
|
||||
{-2.3, -6.3, 1.6, -2.6, 0.0, 3.1, 0.4, 2.1, 3.9, -0.1, -2.3, 0.0, 0.0},
|
||||
{2.8, -1.6, -1.7, 1.7, -0.1, 0.1, -0.7, 0.7, 1.8, 0.0, 1.1, 4.1, 0.0},
|
||||
{-2.4, -0.4, 0.2, 0.8, -0.3, 1.1, -0.5, 0.4, -0.3, -0.3, -0.1, -0.3, -0.1},
|
||||
{-29438.5, -1501.1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{-2445.3, 3012.5, 1676.6, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{1351.1, -2352.3, 1225.6, 581.9, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{907.2, 813.7, 120.3, -335.0, 70.3, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{-232.6, 360.1, 192.4, -141.0, -157.4, 4.3, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{69.5, 67.4, 72.8, -129.8, -29.0, 13.2, -70.9, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{81.6, -76.1, -6.8, 51.9, 15.0, 9.3, -2.8, 6.7, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{24.0, 8.6, -16.9, -3.2, -20.6, 13.3, 11.7, -16.0, -2.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{5.4, 8.8, 3.1, -3.1, 0.6, -13.3, -0.1, 8.7, -9.1, -10.5, 0.0, 0.0, 0.0},
|
||||
{-1.9, -6.5, 0.2, 0.6, -0.6, 1.7, -0.7, 2.1, 2.3, -1.8, -3.6, 0.0, 0.0},
|
||||
{3.1, -1.5, -2.3, 2.1, -0.9, 0.6, -0.7, 0.2, 1.7, -0.2, 0.4, 3.5, 0.0},
|
||||
{-2.0, -0.3, 0.4, 1.3, -0.9, 0.9, 0.1, 0.5, -0.4, -0.4, 0.2, -0.9, 0.0},
|
||||
};
|
||||
|
||||
static double hnm_wmm2005[13][13]=
|
||||
static double hnm_wmm2015[13][13]=
|
||||
{
|
||||
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, 5079.8, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, -2594.7, -516.7, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, -199.9, 269.3, -524.2, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, 281.5, -226.0, 145.8, -304.7, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, 42.4, 179.8, -123.0, -19.5, 103.6, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, -20.3, 54.7, 63.6, -63.4, -0.1, 50.4, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, -61.5, -22.4, 7.2, 25.4, 11.0, -26.4, -5.1, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, 11.2, -21.0, 9.6, -19.8, 16.1, 7.7, -12.9, -0.2, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, -20.1, 12.9, 12.6, -6.7, -8.1, 8.0, 2.9, -7.9, 6.0, 0.0, 0.0, 0.0},
|
||||
{0.0, 2.4, 0.2, 4.4, 4.8, -6.5, -1.1, -3.4, -0.8, -2.3, -7.9, 0.0, 0.0},
|
||||
{0.0, 0.3, 1.2, -0.8, -2.5, 0.9, -0.6, -2.7, -0.9, -1.3, -2.0, -1.2, 0.0},
|
||||
{0.0, -0.4, 0.3, 2.4, -2.6, 0.6, 0.3, 0.0, 0.0, 0.3, -0.9, -0.4, 0.8},
|
||||
{0.0, 4796.2, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, -2845.6, -642.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, -115.3, 245.0, -538.3, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, 283.4, -188.6, 180.9, -329.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, 47.4, 196.9, -119.4, 16.1, 100.1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, -20.7, 33.2, 58.8, -66.5, 7.3, 62.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, -54.1, -19.4, 5.6, 24.4, 3.3, -27.5, -2.3, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, 10.2, -18.1, 13.2, -14.6, 16.2, 5.7, -9.1, 2.2, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, -21.6, 10.8, 11.7, -6.8, -6.9, 7.8, 1.0, -3.9, 8.5, 0.0, 0.0, 0.0},
|
||||
{0.0, 3.3, -0.3, 4.6, 4.4, -7.9, -0.6, -4.1, -2.8, -1.1, -8.7, 0.0, 0.0},
|
||||
{0.0, -0.1, 2.1, -0.7, -1.1, 0.7, -0.2, -2.1, -1.5, -2.5, -2.0, -2.3, 0.0},
|
||||
{0.0, -1.0, 0.5, 1.8, -2.2, 0.3, 0.7, -0.1, 0.3, 0.2, -0.9, -0.2, 0.7},
|
||||
};
|
||||
|
||||
static double gtnm_wmm2005[13][13]=
|
||||
static double gtnm_wmm2015[13][13]=
|
||||
{
|
||||
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{8.0, 10.6, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{-15.1, -7.8, -0.8, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.4, -2.6, -1.2, -6.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{-2.5, 2.8, -7.0, 6.2, -3.8, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{-2.8, 0.7, -3.2, -1.1, 0.1, -0.8, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{-0.7, 0.4, -0.3, 2.3, -2.1, -0.6, 1.4, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.2, -0.1, -0.3, 1.1, 0.6, 0.5, -0.4, 0.6, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.1, 0.3, -0.4, 0.3, -0.3, 0.2, 0.4, -0.7, 0.4, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{10.7, 17.9, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{-8.6, -3.3, 2.4, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{3.1, -6.2, -0.4, -10.4, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{-0.4, 0.8, -9.2, 4.0, -4.2, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{-0.2, 0.1, -1.4, 0.0, 1.3, 3.8, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{-0.5, -0.2, -0.6, 2.4, -1.1, 0.3, 1.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.2, -0.2, -0.4, 1.3, 0.2, -0.4, -0.9, 0.3, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, 0.1, -0.5, 0.5, -0.2, 0.4, 0.2, -0.4, 0.3, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, -0.1, -0.1, 0.4, -0.5, -0.2, 0.1, 0.0, -0.2, -0.1, 0.0, 0.0, 0.0},
|
||||
{0.0, 0.0, -0.1, 0.3, -0.1, -0.1, -0.1, 0.0, -0.2, -0.1, -0.2, 0.0, 0.0},
|
||||
{0.0, 0.0, -0.1, 0.1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -0.1, -0.1, 0.0},
|
||||
{0.1, 0.0, 0.0, 0.1, -0.1, 0.0, 0.1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
};
|
||||
|
||||
static double htnm_wmm2005[13][13]=
|
||||
static double htnm_wmm2015[13][13]=
|
||||
{
|
||||
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, -20.9, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, -23.2, -14.6, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, 5.0, -7.0, -0.6, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, 2.2, 1.6, 5.8, 0.1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, 0.0, 1.7, 2.1, 4.8, -1.1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, -0.6, -1.9, -0.4, -0.5, -0.3, 0.7, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, 0.6, 0.4, 0.2, 0.3, -0.8, -0.2, 0.1, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, -0.2, 0.1, 0.3, 0.4, 0.1, -0.2, 0.4, 0.4, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, -26.8, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, -27.1, -13.3, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, 8.4, -0.4, 2.3, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, -0.6, 5.3, 3.0, -5.3, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, 0.4, 1.6, -1.1, 3.3, 0.1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, 0.0, -2.2, -0.7, 0.1, 1.0, 1.3, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, 0.7, 0.5, -0.2, -0.1, -0.7, 0.1, 0.1, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, -0.3, 0.3, 0.3, 0.6, -0.1, -0.2, 0.3, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
{0.0, -0.2, -0.1, -0.2, 0.1, 0.1, 0.0, -0.2, 0.4, 0.3, 0.0, 0.0, 0.0},
|
||||
{0.0, 0.1, -0.1, 0.0, 0.0, -0.2, 0.1, -0.1, -0.2, 0.1, -0.1, 0.0, 0.0},
|
||||
{0.0, 0.0, 0.1, 0.0, 0.1, 0.0, 0.0, 0.1, 0.0, -0.1, 0.0, -0.1, 0.0},
|
||||
{0.0, 0.0, 0.0, -0.1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
|
||||
};
|
||||
|
||||
static const int nmax = 12;
|
||||
@@ -174,7 +188,7 @@ static double roots[13][13][2];
|
||||
unsigned long int yymmdd_to_julian_days( int yy, int mm, int dd )
|
||||
{
|
||||
unsigned long jd;
|
||||
|
||||
|
||||
yy = (yy < 50) ? (2000 + yy) : (1900 + yy);
|
||||
jd = dd - 32075L + 1461L * (yy + 4800L + (mm - 14) / 12 ) / 4;
|
||||
jd = jd + 367L * (mm - 2 - (mm - 14) / 12*12) / 12;
|
||||
@@ -182,7 +196,7 @@ unsigned long int yymmdd_to_julian_days( int yy, int mm, int dd )
|
||||
|
||||
/* printf("julian date = %d\n", jd ); */
|
||||
return jd;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
@@ -195,8 +209,8 @@ double calc_magvar( double lat, double lon, double h, long dat, double* field )
|
||||
{
|
||||
/* output field B_r,B_th,B_phi,B_x,B_y,B_z */
|
||||
int n,m;
|
||||
/* reference date for current model is 1 januari 2005 */
|
||||
long date0_wmm2005 = yymmdd_to_julian_days(5,1,1);
|
||||
/* reference date for current model is 1 januari 2015 */
|
||||
long date0_wmm2015 = yymmdd_to_julian_days(15,1,1);
|
||||
|
||||
double yearfrac,sr,r,theta,c,s,psi,fn,fn_0,B_r,B_theta,B_phi,X,Y,Z;
|
||||
double sinpsi, cospsi, inv_s;
|
||||
@@ -215,7 +229,7 @@ double calc_magvar( double lat, double lon, double h, long dat, double* field )
|
||||
/* theta is geocentric co-latitude */
|
||||
|
||||
r = h*h + 2.0*h * sr +
|
||||
(a*a*a*a - ( a*a*a*a - b*b*b*b ) * sinlat*sinlat ) /
|
||||
(a*a*a*a - ( a*a*a*a - b*b*b*b ) * sinlat*sinlat ) /
|
||||
(a*a - (a*a - b*b) * sinlat*sinlat );
|
||||
|
||||
r = sqrt(r);
|
||||
@@ -224,7 +238,7 @@ double calc_magvar( double lat, double lon, double h, long dat, double* field )
|
||||
c = cos(theta);
|
||||
s = sin(theta);
|
||||
/* protect against zero divide at geographic poles */
|
||||
inv_s = 1.0 / (s + (s == 0.)*1.0e-8);
|
||||
inv_s = 1.0 / (s + (s == 0.)*1.0e-8);
|
||||
|
||||
/* zero out arrays */
|
||||
for ( n = 0; n <= nmax; n++ ) {
|
||||
@@ -283,12 +297,12 @@ double calc_magvar( double lat, double lon, double h, long dat, double* field )
|
||||
|
||||
/* compute Gauss coefficients gnm and hnm of degree n and order m for the desired time
|
||||
achieved by adjusting the coefficients at time t0 for linear secular variation */
|
||||
/* WMM2005 */
|
||||
yearfrac = (dat - date0_wmm2005) / 365.25;
|
||||
/* WMM2015 */
|
||||
yearfrac = (dat - date0_wmm2015) / 365.25;
|
||||
for ( n = 1; n <= nmax; n++ ) {
|
||||
for ( m = 0; m <= nmax; m++ ) {
|
||||
gnm[n][m] = gnm_wmm2005[n][m] + yearfrac * gtnm_wmm2005[n][m];
|
||||
hnm[n][m] = hnm_wmm2005[n][m] + yearfrac * htnm_wmm2005[n][m];
|
||||
gnm[n][m] = gnm_wmm2015[n][m] + yearfrac * gtnm_wmm2015[n][m];
|
||||
hnm[n][m] = hnm_wmm2015[n][m] + yearfrac * htnm_wmm2015[n][m];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -310,7 +324,7 @@ double calc_magvar( double lat, double lon, double h, long dat, double* field )
|
||||
double c2_n=0;
|
||||
double c3_n=0;
|
||||
for ( m = 0; m <= n; m++ ) {
|
||||
double tmp = (gnm[n][m] * cm[m] + hnm[n][m] * sm[m]);
|
||||
double tmp = (gnm[n][m] * cm[m] + hnm[n][m] * sm[m]);
|
||||
c1_n=c1_n + tmp * P[n][m];
|
||||
c2_n=c2_n + tmp * DP[n][m];
|
||||
c3_n=c3_n + m * (gnm[n][m] * sm[m] - hnm[n][m] * cm[m]) * P[n][m];
|
||||
@@ -340,7 +354,7 @@ double calc_magvar( double lat, double lon, double h, long dat, double* field )
|
||||
/* find variation in radians */
|
||||
/* return zero variation at magnetic pole X=Y=0. */
|
||||
/* E is positive */
|
||||
return (X != 0. || Y != 0.) ? atan2(Y, X) : (double) 0.;
|
||||
return (X != 0. || Y != 0.) ? atan2(Y, X) : (double) 0.;
|
||||
}
|
||||
|
||||
|
||||
@@ -350,7 +364,7 @@ double SGMagVarOrig( double lat, double lon, double h, long dat, double* field )
|
||||
/* output field B_r,B_th,B_phi,B_x,B_y,B_z */
|
||||
int n,m;
|
||||
/* reference dates */
|
||||
long date0_wmm2005 = yymmdd_to_julian_days(5,1,1);
|
||||
long date0_wmm2015 = yymmdd_to_julian_days(5,1,1);
|
||||
|
||||
double yearfrac,sr,r,theta,c,s,psi,fn,B_r,B_theta,B_phi,X,Y,Z;
|
||||
|
||||
@@ -362,7 +376,7 @@ double SGMagVarOrig( double lat, double lon, double h, long dat, double* field )
|
||||
/* theta is geocentric co-latitude */
|
||||
|
||||
r = h * h + 2.0*h * sr +
|
||||
(pow(a,4.0) - (pow(a,4.0) - pow(b,4.0)) * pow(sin(lat),2.0)) /
|
||||
(pow(a,4.0) - (pow(a,4.0) - pow(b,4.0)) * pow(sin(lat),2.0)) /
|
||||
(a * a - (a * a - b * b) * pow(sin(lat),2.0));
|
||||
|
||||
r = sqrt(r);
|
||||
@@ -407,12 +421,12 @@ double SGMagVarOrig( double lat, double lon, double h, long dat, double* field )
|
||||
}
|
||||
|
||||
/* compute gnm, hnm at dat */
|
||||
/* WMM2005 */
|
||||
yearfrac = (dat - date0_wmm2005) / 365.25;
|
||||
/* WMM2015 */
|
||||
yearfrac = (dat - date0_wmm2015) / 365.25;
|
||||
for ( n = 1; n <= nmax; n++ ) {
|
||||
for ( m = 0; m <= nmax; m++ ) {
|
||||
gnm[n][m] = gnm_wmm2005[n][m] + yearfrac * gtnm_wmm2005[n][m];
|
||||
hnm[n][m] = hnm_wmm2005[n][m] + yearfrac * htnm_wmm2005[n][m];
|
||||
gnm[n][m] = gnm_wmm2015[n][m] + yearfrac * gtnm_wmm2015[n][m];
|
||||
hnm[n][m] = hnm_wmm2015[n][m] + yearfrac * htnm_wmm2015[n][m];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
#endif
|
||||
|
||||
|
||||
#include <math.h>
|
||||
#include <cmath>
|
||||
|
||||
#include <simgear/magvar/magvar.hxx>
|
||||
#include <simgear/math/SGMath.hxx>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/* 2/14/00 fixed help message- dip angle (down positive), variation (E positive) */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <cmath>
|
||||
|
||||
#include <simgear/constants.h>
|
||||
|
||||
|
||||
@@ -41,6 +41,30 @@ public:
|
||||
static T clip(const T& a, const T& _min, const T& _max)
|
||||
{ return max(_min, min(_max, a)); }
|
||||
|
||||
|
||||
/// Add two (integer) values taking care of overflows.
|
||||
static T addClipOverflow(T a, T b)
|
||||
{
|
||||
if( b > 0 )
|
||||
{
|
||||
if( SGLimits<T>::max() - b < a )
|
||||
return SGLimits<T>::max();
|
||||
}
|
||||
else
|
||||
{
|
||||
if( SGLimits<T>::min() - b > a )
|
||||
return SGLimits<T>::min();
|
||||
}
|
||||
|
||||
return a + b;
|
||||
}
|
||||
|
||||
/// Add two (integer) values in place, taking care of overflows.
|
||||
static T& addClipOverflowInplace(T& a, T b)
|
||||
{
|
||||
return a = addClipOverflow(a, b);
|
||||
}
|
||||
|
||||
/**
|
||||
* Seek a variable towards a target value with given rate and timestep
|
||||
*
|
||||
@@ -130,7 +154,7 @@ public:
|
||||
static bool isNaN(const T& v)
|
||||
{
|
||||
#ifdef HAVE_ISNAN
|
||||
return isnan(v);
|
||||
return (isnan(v) != 0);
|
||||
#elif defined HAVE_STD_ISNAN
|
||||
return std::isnan(v);
|
||||
#else
|
||||
|
||||
@@ -196,6 +196,17 @@ SGVec2<T>
|
||||
max(S s, const SGVec2<T>& v)
|
||||
{ return SGVec2<T>(SGMisc<T>::max(s, v(0)), SGMisc<T>::max(s, v(1))); }
|
||||
|
||||
/// Add two vectors taking care of (integer) overflows. The values are limited
|
||||
/// to the respective minimum and maximum values.
|
||||
template<class T>
|
||||
SGVec2<T> addClipOverflow(SGVec2<T> const& lhs, SGVec2<T> const& rhs)
|
||||
{
|
||||
return SGVec2<T>(
|
||||
SGMisc<T>::addClipOverflow(lhs.x(), rhs.x()),
|
||||
SGMisc<T>::addClipOverflow(lhs.y(), rhs.y())
|
||||
);
|
||||
}
|
||||
|
||||
/// Scalar dot product
|
||||
template<typename T>
|
||||
inline
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user