Compare commits
70
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
506b9130a8 | ||
|
|
5d1b70a7f2 | ||
|
|
eff3df57d9 | ||
|
|
2931f3380f | ||
|
|
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 |
Vendored
+1
@@ -2,3 +2,4 @@ if (NOT SYSTEM_EXPAT)
|
|||||||
add_subdirectory(expat)
|
add_subdirectory(expat)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
add_subdirectory(utf8)
|
||||||
|
|||||||
Vendored
+17
@@ -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}")
|
||||||
Vendored
+12
@@ -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
|
||||||
Vendored
+1789
File diff suppressed because it is too large
Load Diff
Vendored
+34
@@ -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
|
||||||
Vendored
+327
@@ -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
|
||||||
|
|
||||||
|
|
||||||
Vendored
+329
@@ -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
@@ -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
|
||||||
|
|
||||||
+11
-3
@@ -6,6 +6,9 @@ include (CheckCXXCompilerFlag)
|
|||||||
|
|
||||||
project(SimGear)
|
project(SimGear)
|
||||||
|
|
||||||
|
# using 10.7 because boost requires libc++ and 10.6 doesn't include it
|
||||||
|
set(CMAKE_OSX_DEPLOYMENT_TARGET 10.7)
|
||||||
|
|
||||||
# read 'version' file into a variable (stripping any newlines or spaces)
|
# read 'version' file into a variable (stripping any newlines or spaces)
|
||||||
file(READ version versionFile)
|
file(READ version versionFile)
|
||||||
string(STRIP ${versionFile} SIMGEAR_VERSION)
|
string(STRIP ${versionFile} SIMGEAR_VERSION)
|
||||||
@@ -181,7 +184,7 @@ else()
|
|||||||
message(STATUS "Sound support: ENABLED")
|
message(STATUS "Sound support: ENABLED")
|
||||||
endif(ENABLE_SOUND)
|
endif(ENABLE_SOUND)
|
||||||
|
|
||||||
find_package(OpenSceneGraph 3.2.0 REQUIRED osgText osgSim osgDB osgParticle osgGA osgUtil)
|
find_package(OpenSceneGraph 3.2.0 REQUIRED osgText osgSim osgDB osgParticle osgGA osgViewer osgUtil)
|
||||||
endif(SIMGEAR_HEADLESS)
|
endif(SIMGEAR_HEADLESS)
|
||||||
|
|
||||||
find_package(ZLIB REQUIRED)
|
find_package(ZLIB REQUIRED)
|
||||||
@@ -276,12 +279,12 @@ 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
|
# isnan might not be real symbol, so can't check using function_exists
|
||||||
check_cxx_source_compiles(
|
check_cxx_source_compiles(
|
||||||
"#include <cmath>
|
"#include <cmath>
|
||||||
void f() { isnan(0.0);} "
|
int main() { return isnan(0.0);} "
|
||||||
HAVE_ISNAN)
|
HAVE_ISNAN)
|
||||||
|
|
||||||
check_cxx_source_compiles(
|
check_cxx_source_compiles(
|
||||||
"#include <cmath>
|
"#include <cmath>
|
||||||
void f() { std::isnan(0.0);} "
|
int main() { return std::isnan(0.0);} "
|
||||||
HAVE_STD_ISNAN)
|
HAVE_STD_ISNAN)
|
||||||
|
|
||||||
if(CMAKE_COMPILER_IS_GNUCXX)
|
if(CMAKE_COMPILER_IS_GNUCXX)
|
||||||
@@ -299,6 +302,9 @@ endif(CMAKE_COMPILER_IS_GNUCXX)
|
|||||||
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
||||||
set(WARNING_FLAGS_CXX "-Wall -Wno-overloaded-virtual")
|
set(WARNING_FLAGS_CXX "-Wall -Wno-overloaded-virtual")
|
||||||
set(WARNING_FLAGS_C "-Wall")
|
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()
|
endif()
|
||||||
|
|
||||||
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
||||||
@@ -385,6 +391,8 @@ endif()
|
|||||||
|
|
||||||
install (FILES ${PROJECT_BINARY_DIR}/simgear/simgear_config.h DESTINATION include/simgear/)
|
install (FILES ${PROJECT_BINARY_DIR}/simgear/simgear_config.h DESTINATION include/simgear/)
|
||||||
|
|
||||||
|
include_directories(3rdparty/utf8/source)
|
||||||
|
|
||||||
add_subdirectory(3rdparty)
|
add_subdirectory(3rdparty)
|
||||||
add_subdirectory(simgear)
|
add_subdirectory(simgear)
|
||||||
|
|
||||||
|
|||||||
@@ -51,15 +51,15 @@ if("${Boost_VERSION}0" LESS "1034000")
|
|||||||
"NOTE: boost::test-based targets and tests cannot "
|
"NOTE: boost::test-based targets and tests cannot "
|
||||||
"be added: boost >= 1.34.0 required but not found. "
|
"be added: boost >= 1.34.0 required but not found. "
|
||||||
"(found: '${Boost_VERSION}'; want >=103400) ")
|
"(found: '${Boost_VERSION}'; want >=103400) ")
|
||||||
if(BUILD_TESTING)
|
if(ENABLE_TESTS)
|
||||||
message(FATAL_ERROR
|
message(FATAL_ERROR
|
||||||
${_shared_msg}
|
${_shared_msg}
|
||||||
"You may disable BUILD_TESTING to continue without the "
|
"You may disable ENABLE_TESTS to continue without the "
|
||||||
"tests.")
|
"tests.")
|
||||||
else()
|
else()
|
||||||
message(STATUS
|
message(STATUS
|
||||||
${_shared_msg}
|
${_shared_msg}
|
||||||
"BUILD_TESTING disabled, so continuing anyway.")
|
"ENABLE_TESTS disabled, so continuing anyway.")
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
@@ -88,7 +88,7 @@ if(Boost_FOUND AND NOT "${Boost_VERSION}0" LESS "1034000")
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
function(add_boost_test _name)
|
function(add_boost_test _name)
|
||||||
if(NOT BUILD_TESTING)
|
if(NOT ENABLE_TESTS)
|
||||||
return()
|
return()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ PROJECT_NAME = SimGear
|
|||||||
# could be handy for archiving the generated documentation or if some version
|
# could be handy for archiving the generated documentation or if some version
|
||||||
# control system is used.
|
# 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
|
# 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
|
# 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.
|
# Note: If this tag is empty the current directory is searched.
|
||||||
|
|
||||||
INPUT = DoxygenMain.cxx \
|
INPUT = DoxygenMain.cxx \
|
||||||
simgear/bucket \
|
simgear
|
||||||
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
|
|
||||||
|
|
||||||
# This tag can be used to specify the character encoding of the source files
|
# 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
|
# 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.
|
# If the GENERATE_LATEX tag is set to YES doxygen will generate LaTeX output.
|
||||||
# The default value is: YES.
|
# 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
|
# 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
|
# 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.
|
# The default value is: NO.
|
||||||
# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
|
# 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
|
# 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
|
# the macro expansion is limited to the macros specified with the PREDEFINED and
|
||||||
|
|||||||
@@ -127,21 +127,22 @@ public:
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a bucket given a specific location.
|
* 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);
|
SGBucket(const SGGeod& geod);
|
||||||
|
|
||||||
/** Construct a bucket given a unique bucket index number.
|
/** Construct a bucket given a unique bucket index number.
|
||||||
|
*
|
||||||
* @param bindex unique bucket index
|
* @param bindex unique bucket index
|
||||||
*/
|
*/
|
||||||
SGBucket(const long int bindex);
|
SGBucket(const long int bindex);
|
||||||
|
|
||||||
#ifndef NO_DEPRECATED_API
|
#ifndef NO_DEPRECATED_API
|
||||||
/**
|
/**
|
||||||
* Reset a bucket to represent a new lat and lon
|
* Reset a bucket to represent a new location.
|
||||||
* @param dlon longitude specified in degrees
|
*
|
||||||
* @param dlat latitude specified in degrees
|
* @param geod New geodetic location
|
||||||
*/
|
*/
|
||||||
void set_bucket(const SGGeod& geod);
|
void set_bucket(const SGGeod& geod);
|
||||||
|
|
||||||
|
|||||||
+32
-11
@@ -20,6 +20,7 @@
|
|||||||
#include "CanvasEventManager.hxx"
|
#include "CanvasEventManager.hxx"
|
||||||
#include "CanvasEventVisitor.hxx"
|
#include "CanvasEventVisitor.hxx"
|
||||||
#include "CanvasPlacement.hxx"
|
#include "CanvasPlacement.hxx"
|
||||||
|
#include <simgear/canvas/events/KeyboardEvent.hxx>
|
||||||
#include <simgear/canvas/events/MouseEvent.hxx>
|
#include <simgear/canvas/events/MouseEvent.hxx>
|
||||||
#include <simgear/scene/util/parse_color.hxx>
|
#include <simgear/scene/util/parse_color.hxx>
|
||||||
#include <simgear/scene/util/RenderConstants.hxx>
|
#include <simgear/scene/util/RenderConstants.hxx>
|
||||||
@@ -196,7 +197,25 @@ namespace canvas
|
|||||||
{
|
{
|
||||||
_layout = layout;
|
_layout = layout;
|
||||||
_layout->setCanvas(this);
|
_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( _layout )
|
||||||
{
|
|
||||||
if( (_status & LAYOUT_DIRTY) )
|
|
||||||
{
|
|
||||||
_layout->setGeometry(SGRecti(0, 0, _view_width, _view_height));
|
_layout->setGeometry(SGRecti(0, 0, _view_width, _view_height));
|
||||||
_status &= ~LAYOUT_DIRTY;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
_layout->update();
|
|
||||||
}
|
|
||||||
|
|
||||||
if( _visible || _render_always )
|
if( _visible || _render_always )
|
||||||
{
|
{
|
||||||
@@ -410,7 +421,6 @@ namespace canvas
|
|||||||
if( _view_width == w )
|
if( _view_width == w )
|
||||||
return;
|
return;
|
||||||
_view_width = w;
|
_view_width = w;
|
||||||
_status |= LAYOUT_DIRTY;
|
|
||||||
|
|
||||||
_texture.setViewSize(_view_width, _view_height);
|
_texture.setViewSize(_view_width, _view_height);
|
||||||
}
|
}
|
||||||
@@ -421,7 +431,6 @@ namespace canvas
|
|||||||
if( _view_height == h )
|
if( _view_height == h )
|
||||||
return;
|
return;
|
||||||
_view_height = h;
|
_view_height = h;
|
||||||
_status |= LAYOUT_DIRTY;
|
|
||||||
|
|
||||||
_texture.setViewSize(_view_width, _view_height);
|
_texture.setViewSize(_view_width, _view_height);
|
||||||
}
|
}
|
||||||
@@ -459,6 +468,18 @@ namespace canvas
|
|||||||
return _event_manager->handleEvent(event, visitor.getPropagationPath());
|
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,
|
bool Canvas::propagateEvent( EventPtr const& event,
|
||||||
EventPropagationPath const& path )
|
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>
|
// Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com>
|
||||||
//
|
//
|
||||||
@@ -43,6 +44,9 @@ namespace canvas
|
|||||||
class CanvasMgr;
|
class CanvasMgr;
|
||||||
class MouseEvent;
|
class MouseEvent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Canvas to draw onto (to an off-screen render target).
|
||||||
|
*/
|
||||||
class Canvas:
|
class Canvas:
|
||||||
public PropertyBasedElement,
|
public PropertyBasedElement,
|
||||||
public nasal::Object
|
public nasal::Object
|
||||||
@@ -53,8 +57,7 @@ namespace canvas
|
|||||||
{
|
{
|
||||||
STATUS_OK,
|
STATUS_OK,
|
||||||
STATUS_DIRTY = 1,
|
STATUS_DIRTY = 1,
|
||||||
LAYOUT_DIRTY = STATUS_DIRTY << 1,
|
MISSING_SIZE_X = STATUS_DIRTY << 1,
|
||||||
MISSING_SIZE_X = LAYOUT_DIRTY << 1,
|
|
||||||
MISSING_SIZE_Y = MISSING_SIZE_X << 1,
|
MISSING_SIZE_Y = MISSING_SIZE_X << 1,
|
||||||
MISSING_SIZE = MISSING_SIZE_X | MISSING_SIZE_Y,
|
MISSING_SIZE = MISSING_SIZE_X | MISSING_SIZE_Y,
|
||||||
CREATE_FAILED = MISSING_SIZE_Y << 1
|
CREATE_FAILED = MISSING_SIZE_Y << 1
|
||||||
@@ -133,6 +136,22 @@ namespace canvas
|
|||||||
*/
|
*/
|
||||||
void setLayout(const LayoutRef& layout);
|
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
|
* Enable rendering for the next frame
|
||||||
*
|
*
|
||||||
@@ -160,6 +179,8 @@ namespace canvas
|
|||||||
SGRect<int> getViewport() const;
|
SGRect<int> getViewport() const;
|
||||||
|
|
||||||
bool handleMouseEvent(const MouseEventPtr& event);
|
bool handleMouseEvent(const MouseEventPtr& event);
|
||||||
|
bool handleKeyboardEvent(const KeyboardEventPtr& event);
|
||||||
|
|
||||||
bool propagateEvent( EventPtr const& event,
|
bool propagateEvent( EventPtr const& event,
|
||||||
EventPropagationPath const& path );
|
EventPropagationPath const& path );
|
||||||
|
|
||||||
@@ -211,13 +232,15 @@ namespace canvas
|
|||||||
GroupPtr _root_group;
|
GroupPtr _root_group;
|
||||||
LayoutRef _layout;
|
LayoutRef _layout;
|
||||||
|
|
||||||
|
ElementWeakPtr _focus_element;
|
||||||
|
|
||||||
CullCallbackPtr _cull_callback;
|
CullCallbackPtr _cull_callback;
|
||||||
bool _render_always; //<! Used to disable automatic lazy rendering (culling)
|
bool _render_always; //!< Used to disable automatic lazy rendering (culling)
|
||||||
|
|
||||||
std::vector<SGPropertyNode*> _dirty_placements;
|
std::vector<SGPropertyNode*> _dirty_placements;
|
||||||
std::vector<Placements> _placements;
|
std::vector<Placements> _placements;
|
||||||
std::set<CanvasWeakPtr> _parent_canvases, //<! Canvases showing this canvas
|
std::set<CanvasWeakPtr> _parent_canvases, //!< Canvases showing this canvas
|
||||||
_child_canvases; //<! Canvases displayed within
|
_child_canvases; //!< Canvases displayed within
|
||||||
// this canvas
|
// this canvas
|
||||||
|
|
||||||
typedef std::map<std::string, PlacementFactory> PlacementFactoryMap;
|
typedef std::map<std::string, PlacementFactory> PlacementFactoryMap;
|
||||||
|
|||||||
@@ -27,7 +27,8 @@ namespace canvas
|
|||||||
Event::Event():
|
Event::Event():
|
||||||
type(UNKNOWN),
|
type(UNKNOWN),
|
||||||
time(-1),
|
time(-1),
|
||||||
propagation_stopped(false)
|
propagation_stopped(false),
|
||||||
|
default_prevented(false)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -80,6 +81,18 @@ namespace canvas
|
|||||||
propagation_stopped = true;
|
propagation_stopped = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void Event::preventDefault()
|
||||||
|
{
|
||||||
|
default_prevented = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
bool Event::defaultPrevented() const
|
||||||
|
{
|
||||||
|
return default_prevented;
|
||||||
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
int Event::getOrRegisterType(const std::string& type_str)
|
int Event::getOrRegisterType(const std::string& type_str)
|
||||||
{
|
{
|
||||||
@@ -125,7 +138,7 @@ namespace canvas
|
|||||||
|
|
||||||
if( type_map.empty() )
|
if( type_map.empty() )
|
||||||
{
|
{
|
||||||
# define ENUM_MAPPING(type, str)\
|
# define ENUM_MAPPING(type, str, class_name)\
|
||||||
type_map.insert(TypeMap::value_type(str, type));
|
type_map.insert(TypeMap::value_type(str, type));
|
||||||
# include "CanvasEventTypes.hxx"
|
# include "CanvasEventTypes.hxx"
|
||||||
# undef ENUM_MAPPING
|
# 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>
|
// Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com>
|
||||||
//
|
//
|
||||||
@@ -27,26 +28,36 @@ namespace simgear
|
|||||||
namespace canvas
|
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:
|
class Event:
|
||||||
public SGReferenced
|
public SGReferenced
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
/// Event type identifier
|
||||||
enum Type
|
enum Type
|
||||||
{
|
{
|
||||||
UNKNOWN,
|
UNKNOWN,
|
||||||
# define ENUM_MAPPING(name, str) name,
|
# define ENUM_MAPPING(name, str, class_name)\
|
||||||
|
name, /*!< class_name (type=str) */
|
||||||
# include "CanvasEventTypes.hxx"
|
# include "CanvasEventTypes.hxx"
|
||||||
# undef ENUM_MAPPING
|
# undef ENUM_MAPPING
|
||||||
CUSTOM_EVENT ///< all user defined event types share the same id. They
|
CUSTOM_EVENT ///< First event type id available for user defined event
|
||||||
/// are just differentiated by using the type string.
|
/// type.
|
||||||
|
/// @see CustomEvent
|
||||||
};
|
};
|
||||||
|
|
||||||
int type;
|
int type;
|
||||||
ElementWeakPtr target,
|
ElementWeakPtr target,
|
||||||
current_target;
|
current_target;
|
||||||
double time;
|
double time;
|
||||||
bool propagation_stopped;
|
bool propagation_stopped,
|
||||||
|
default_prevented;
|
||||||
|
|
||||||
Event();
|
Event();
|
||||||
|
|
||||||
@@ -72,10 +83,33 @@ namespace canvas
|
|||||||
ElementWeakPtr getTarget() const;
|
ElementWeakPtr getTarget() const;
|
||||||
ElementWeakPtr getCurrentTarget() const;
|
ElementWeakPtr getCurrentTarget() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get time at which the event was generated.
|
||||||
|
*/
|
||||||
double getTime() const;
|
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();
|
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 getOrRegisterType(const std::string& type);
|
||||||
static int strToType(const std::string& type);
|
static int strToType(const std::string& type);
|
||||||
static std::string typeToStr(int type);
|
static std::string typeToStr(int type);
|
||||||
|
|||||||
@@ -20,14 +20,17 @@
|
|||||||
# error "Don't include this file directly!"
|
# error "Don't include this file directly!"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
ENUM_MAPPING(MOUSE_DOWN, "mousedown")
|
ENUM_MAPPING(MOUSE_DOWN, "mousedown", MouseEvent)
|
||||||
ENUM_MAPPING(MOUSE_UP, "mouseup")
|
ENUM_MAPPING(MOUSE_UP, "mouseup", MouseEvent)
|
||||||
ENUM_MAPPING(CLICK, "click")
|
ENUM_MAPPING(CLICK, "click", MouseEvent)
|
||||||
ENUM_MAPPING(DBL_CLICK, "dblclick")
|
ENUM_MAPPING(DBL_CLICK, "dblclick", MouseEvent)
|
||||||
ENUM_MAPPING(DRAG, "drag")
|
ENUM_MAPPING(DRAG, "drag", MouseEvent)
|
||||||
ENUM_MAPPING(WHEEL, "wheel")
|
ENUM_MAPPING(WHEEL, "wheel", MouseEvent)
|
||||||
ENUM_MAPPING(MOUSE_MOVE, "mousemove")
|
ENUM_MAPPING(MOUSE_MOVE, "mousemove", MouseEvent)
|
||||||
ENUM_MAPPING(MOUSE_OVER, "mouseover")
|
ENUM_MAPPING(MOUSE_OVER, "mouseover", MouseEvent)
|
||||||
ENUM_MAPPING(MOUSE_OUT, "mouseout")
|
ENUM_MAPPING(MOUSE_OUT, "mouseout", MouseEvent)
|
||||||
ENUM_MAPPING(MOUSE_ENTER, "mouseenter")
|
ENUM_MAPPING(MOUSE_ENTER, "mouseenter", MouseEvent)
|
||||||
ENUM_MAPPING(MOUSE_LEAVE, "mouseleave")
|
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.
|
///@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.
|
/// 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>
|
// Copyright (C) 2013 Thomas Geymayer <tomgey@gmail.com>
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -172,6 +172,19 @@ namespace canvas
|
|||||||
return _capture_events;
|
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()
|
void Window::raise()
|
||||||
{
|
{
|
||||||
@@ -267,6 +280,9 @@ namespace canvas
|
|||||||
->createChild<Image>("content");
|
->createChild<Image>("content");
|
||||||
_image_content->setSrcCanvas(content);
|
_image_content->setSrcCanvas(content);
|
||||||
|
|
||||||
|
// Forward keyboard events to content
|
||||||
|
_image_content->setFocus();
|
||||||
|
|
||||||
// Draw content on top of decoration
|
// Draw content on top of decoration
|
||||||
_image_content->set<int>("z-index", 1);
|
_image_content->set<int>("z-index", 1);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -84,6 +84,9 @@ namespace canvas
|
|||||||
bool isResizable() const;
|
bool isResizable() const;
|
||||||
bool isCapturingEvents() 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.
|
* Moves window on top of all other windows with the same z-index.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -44,6 +44,7 @@
|
|||||||
#include <osg/ShadeModel>
|
#include <osg/ShadeModel>
|
||||||
#include <osg/StateSet>
|
#include <osg/StateSet>
|
||||||
#include <osg/FrameBufferObject> // for GL_DEPTH_STENCIL_EXT on Windows
|
#include <osg/FrameBufferObject> // for GL_DEPTH_STENCIL_EXT on Windows
|
||||||
|
#include <osg/Version>
|
||||||
#include <osgUtil/RenderBin>
|
#include <osgUtil/RenderBin>
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
@@ -266,7 +267,15 @@ namespace canvas
|
|||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
void ODGauge::reinit()
|
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();
|
clear();
|
||||||
allocRT(cull_callback);
|
allocRT(cull_callback);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -156,7 +156,7 @@ SHfloat getMaxFloat();
|
|||||||
|
|
||||||
/* OpenGL headers */
|
/* OpenGL headers */
|
||||||
|
|
||||||
#if defined(VG_API_LINUX)
|
#if defined(VG_API_LINUX) || defined(VG_API_FREEBSD)
|
||||||
#include <GL/gl.h>
|
#include <GL/gl.h>
|
||||||
#include <GL/glx.h>
|
#include <GL/glx.h>
|
||||||
#elif defined(VG_API_MACOSX)
|
#elif defined(VG_API_MACOSX)
|
||||||
|
|||||||
@@ -53,6 +53,8 @@ namespace canvas
|
|||||||
|
|
||||||
SG_FWD_DECL(Event)
|
SG_FWD_DECL(Event)
|
||||||
SG_FWD_DECL(CustomEvent)
|
SG_FWD_DECL(CustomEvent)
|
||||||
|
SG_FWD_DECL(DeviceEvent)
|
||||||
|
SG_FWD_DECL(KeyboardEvent)
|
||||||
SG_FWD_DECL(MouseEvent)
|
SG_FWD_DECL(MouseEvent)
|
||||||
|
|
||||||
#undef SG_FWD_DECL
|
#undef SG_FWD_DECL
|
||||||
|
|||||||
@@ -26,7 +26,8 @@
|
|||||||
|
|
||||||
#include <osg/Drawable>
|
#include <osg/Drawable>
|
||||||
#include <osg/Geode>
|
#include <osg/Geode>
|
||||||
#include <osg/Scissor>
|
#include <osg/StateAttribute>
|
||||||
|
#include <osg/Version>
|
||||||
|
|
||||||
#include <boost/algorithm/string/predicate.hpp>
|
#include <boost/algorithm/string/predicate.hpp>
|
||||||
#include <boost/foreach.hpp>
|
#include <boost/foreach.hpp>
|
||||||
@@ -46,27 +47,34 @@ namespace canvas
|
|||||||
* glScissor with coordinates relative to different reference frames.
|
* glScissor with coordinates relative to different reference frames.
|
||||||
*/
|
*/
|
||||||
class Element::RelativeScissor:
|
class Element::RelativeScissor:
|
||||||
public osg::Scissor
|
public osg::StateAttribute
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
ReferenceFrame _coord_reference;
|
ReferenceFrame _coord_reference;
|
||||||
osg::observer_ptr<osg::Node> _node;
|
osg::observer_ptr<osg::Node> _node;
|
||||||
|
|
||||||
RelativeScissor(osg::Node* node = NULL):
|
explicit RelativeScissor(osg::Node* node = NULL):
|
||||||
_coord_reference(GLOBAL),
|
_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. */
|
/** Copy constructor using CopyOp to manage deep vs shallow copy. */
|
||||||
RelativeScissor( const RelativeScissor& vp,
|
RelativeScissor( const RelativeScissor& vp,
|
||||||
const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY ):
|
const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY ):
|
||||||
Scissor(vp, copyop),
|
StateAttribute(vp, copyop),
|
||||||
_coord_reference(vp._coord_reference),
|
_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);
|
META_StateAttribute(simgear, RelativeScissor, SCISSOR);
|
||||||
@@ -89,6 +97,24 @@ namespace canvas
|
|||||||
return 0; // passed all the above comparison macros, must be equal.
|
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
|
virtual void apply(osg::State& state) const
|
||||||
{
|
{
|
||||||
if( _width <= 0 || _height <= 0 )
|
if( _width <= 0 || _height <= 0 )
|
||||||
@@ -163,6 +189,12 @@ namespace canvas
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
float _x,
|
||||||
|
_y,
|
||||||
|
_width,
|
||||||
|
_height;
|
||||||
};
|
};
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
@@ -272,6 +304,14 @@ namespace canvas
|
|||||||
_listener.clear();
|
_listener.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void Element::setFocus()
|
||||||
|
{
|
||||||
|
CanvasPtr canvas = _canvas.lock();
|
||||||
|
if( canvas )
|
||||||
|
canvas->setFocusElement(this);
|
||||||
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
bool Element::accept(EventVisitor& visitor)
|
bool Element::accept(EventVisitor& visitor)
|
||||||
{
|
{
|
||||||
@@ -295,6 +335,15 @@ namespace canvas
|
|||||||
return true;
|
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)
|
bool Element::handleEvent(const EventPtr& event)
|
||||||
{
|
{
|
||||||
@@ -349,7 +398,13 @@ namespace canvas
|
|||||||
|
|
||||||
// Drawables have a bounding box...
|
// Drawables have a bounding box...
|
||||||
if( _drawable )
|
if( _drawable )
|
||||||
return _drawable->getBound().contains(osg::Vec3f(local_pos, 0));
|
return _drawable->
|
||||||
|
#if OSG_VERSION_LESS_THAN(3,3,2)
|
||||||
|
getBound()
|
||||||
|
#else
|
||||||
|
getBoundingBox()
|
||||||
|
#endif
|
||||||
|
.contains(osg::Vec3f(local_pos, 0));
|
||||||
else if( _transform.valid() )
|
else if( _transform.valid() )
|
||||||
// ... for other elements, i.e. groups only a bounding sphere is available
|
// ... for other elements, i.e. groups only a bounding sphere is available
|
||||||
return _transform->getBound().contains(osg::Vec3f(parent_pos, 0));
|
return _transform->getBound().contains(osg::Vec3f(parent_pos, 0));
|
||||||
@@ -576,10 +631,10 @@ namespace canvas
|
|||||||
_scissor = new RelativeScissor(_transform.get());
|
_scissor = new RelativeScissor(_transform.get());
|
||||||
|
|
||||||
// <top>, <right>, <bottom>, <left>
|
// <top>, <right>, <bottom>, <left>
|
||||||
_scissor->x() = SGMiscf::roundToInt(values[3]);
|
_scissor->x() = values[3];
|
||||||
_scissor->y() = SGMiscf::roundToInt(values[0]);
|
_scissor->y() = values[0];
|
||||||
_scissor->width() = SGMiscf::roundToInt(width);
|
_scissor->width() = width;
|
||||||
_scissor->height() = SGMiscf::roundToInt(height);
|
_scissor->height() = height;
|
||||||
|
|
||||||
SGPropertyNode* clip_frame = _node->getChild("clip-frame", 0);
|
SGPropertyNode* clip_frame = _node->getChild("clip-frame", 0);
|
||||||
if( clip_frame )
|
if( clip_frame )
|
||||||
@@ -601,7 +656,11 @@ namespace canvas
|
|||||||
osg::BoundingBox Element::getBoundingBox() const
|
osg::BoundingBox Element::getBoundingBox() const
|
||||||
{
|
{
|
||||||
if( _drawable )
|
if( _drawable )
|
||||||
|
#if OSG_VERSION_LESS_THAN(3,3,2)
|
||||||
return _drawable->getBound();
|
return _drawable->getBound();
|
||||||
|
#else
|
||||||
|
return _drawable->getBoundingBox();
|
||||||
|
#endif
|
||||||
|
|
||||||
osg::BoundingBox bb;
|
osg::BoundingBox bb;
|
||||||
|
|
||||||
@@ -624,7 +683,13 @@ namespace canvas
|
|||||||
return osg::BoundingBox();
|
return osg::BoundingBox();
|
||||||
|
|
||||||
osg::BoundingBox transformed;
|
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)
|
for(int i = 0; i < 4; ++i)
|
||||||
transformed.expandBy( bb.corner(i) * m );
|
transformed.expandBy( bb.corner(i) * m );
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
///@file Interface for 2D Canvas elements
|
///@file
|
||||||
|
/// Interface for 2D Canvas elements
|
||||||
//
|
//
|
||||||
// Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com>
|
// 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:
|
class Element:
|
||||||
public PropertyBasedElement
|
public PropertyBasedElement
|
||||||
@@ -108,10 +109,16 @@ namespace canvas
|
|||||||
bool addEventListener(const std::string& type, const EventListener& cb);
|
bool addEventListener(const std::string& type, const EventListener& cb);
|
||||||
virtual void clearEventListener();
|
virtual void clearEventListener();
|
||||||
|
|
||||||
|
/// Get (keyboard) input focus.
|
||||||
|
void setFocus();
|
||||||
|
|
||||||
virtual bool accept(EventVisitor& visitor);
|
virtual bool accept(EventVisitor& visitor);
|
||||||
virtual bool ascend(EventVisitor& visitor);
|
virtual bool ascend(EventVisitor& visitor);
|
||||||
virtual bool traverse(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);
|
virtual bool handleEvent(const EventPtr& event);
|
||||||
bool dispatchEvent(const EventPtr& event);
|
bool dispatchEvent(const EventPtr& event);
|
||||||
|
|
||||||
@@ -128,12 +135,12 @@ namespace canvas
|
|||||||
/**
|
/**
|
||||||
* Set visibility of the element.
|
* Set visibility of the element.
|
||||||
*/
|
*/
|
||||||
void setVisible(bool visible);
|
virtual void setVisible(bool visible);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get whether the element is visible or hidden.
|
* Get whether the element is visible or hidden.
|
||||||
*/
|
*/
|
||||||
bool isVisible() const;
|
virtual bool isVisible() const;
|
||||||
|
|
||||||
osg::MatrixTransform* getMatrixTransform();
|
osg::MatrixTransform* getMatrixTransform();
|
||||||
osg::MatrixTransform const* getMatrixTransform() const;
|
osg::MatrixTransform const* getMatrixTransform() const;
|
||||||
@@ -275,6 +282,7 @@ namespace canvas
|
|||||||
* @param name Property name
|
* @param name Property name
|
||||||
* @param type Interpolation type
|
* @param type Interpolation type
|
||||||
* @param setter Setter function
|
* @param setter Setter function
|
||||||
|
* @param inheritable If this style propagates to child elements
|
||||||
*
|
*
|
||||||
* @tparam T1 Type of value used to retrieve value from property
|
* @tparam T1 Type of value used to retrieve value from property
|
||||||
* node
|
* node
|
||||||
@@ -556,7 +564,7 @@ namespace canvas
|
|||||||
/**
|
/**
|
||||||
* Get stateset of drawable if available or use transform otherwise
|
* Get stateset of drawable if available or use transform otherwise
|
||||||
*/
|
*/
|
||||||
osg::StateSet* getOrCreateStateSet();
|
virtual osg::StateSet* getOrCreateStateSet();
|
||||||
|
|
||||||
void setupStyle();
|
void setupStyle();
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
#include <simgear/canvas/Canvas.hxx>
|
#include <simgear/canvas/Canvas.hxx>
|
||||||
#include <simgear/canvas/CanvasMgr.hxx>
|
#include <simgear/canvas/CanvasMgr.hxx>
|
||||||
#include <simgear/canvas/CanvasSystemAdapter.hxx>
|
#include <simgear/canvas/CanvasSystemAdapter.hxx>
|
||||||
|
#include <simgear/canvas/events/KeyboardEvent.hxx>
|
||||||
#include <simgear/canvas/events/MouseEvent.hxx>
|
#include <simgear/canvas/events/MouseEvent.hxx>
|
||||||
#include <simgear/scene/util/OsgMath.hxx>
|
#include <simgear/scene/util/OsgMath.hxx>
|
||||||
#include <simgear/scene/util/parse_color.hxx>
|
#include <simgear/scene/util/parse_color.hxx>
|
||||||
@@ -30,6 +31,7 @@
|
|||||||
#include <osg/Geometry>
|
#include <osg/Geometry>
|
||||||
#include <osg/PrimitiveSet>
|
#include <osg/PrimitiveSet>
|
||||||
#include <osgDB/Registry>
|
#include <osgDB/Registry>
|
||||||
|
#include <osg/Version>
|
||||||
|
|
||||||
namespace simgear
|
namespace simgear
|
||||||
{
|
{
|
||||||
@@ -100,6 +102,10 @@ namespace canvas
|
|||||||
addStyle("preserveAspectRatio", "", &Image::setPreserveAspectRatio);
|
addStyle("preserveAspectRatio", "", &Image::setPreserveAspectRatio);
|
||||||
addStyle("slice", "", &Image::setSlice);
|
addStyle("slice", "", &Image::setSlice);
|
||||||
addStyle("slice-width", "", &Image::setSliceWidth);
|
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");
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
@@ -408,7 +414,14 @@ namespace canvas
|
|||||||
&& child->getNameString() == "visible"
|
&& child->getNameString() == "visible"
|
||||||
&& child->getBoolValue() )
|
&& 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 )
|
if( cb )
|
||||||
cb->cullNextFrame();
|
cb->cullNextFrame();
|
||||||
}
|
}
|
||||||
@@ -521,8 +534,7 @@ namespace canvas
|
|||||||
if( !src_canvas )
|
if( !src_canvas )
|
||||||
return handled;
|
return handled;
|
||||||
|
|
||||||
MouseEventPtr mouse_event = dynamic_cast<MouseEvent*>(event.get());
|
if( MouseEventPtr mouse_event = dynamic_cast<MouseEvent*>(event.get()) )
|
||||||
if( mouse_event )
|
|
||||||
{
|
{
|
||||||
mouse_event.reset( new MouseEvent(*mouse_event) );
|
mouse_event.reset( new MouseEvent(*mouse_event) );
|
||||||
|
|
||||||
@@ -547,6 +559,11 @@ namespace canvas
|
|||||||
|
|
||||||
handled |= src_canvas->handleMouseEvent(mouse_event);
|
handled |= src_canvas->handleMouseEvent(mouse_event);
|
||||||
}
|
}
|
||||||
|
else if( KeyboardEventPtr keyboard_event =
|
||||||
|
dynamic_cast<KeyboardEvent*>(event.get()) )
|
||||||
|
{
|
||||||
|
handled |= src_canvas->handleKeyboardEvent(keyboard_event);
|
||||||
|
}
|
||||||
|
|
||||||
return handled;
|
return handled;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
#include <simgear/scene/util/parse_color.hxx>
|
#include <simgear/scene/util/parse_color.hxx>
|
||||||
|
|
||||||
#include <osg/Drawable>
|
#include <osg/Drawable>
|
||||||
|
#include <osg/Version>
|
||||||
|
|
||||||
#include <vg/openvg.h>
|
#include <vg/openvg.h>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
@@ -69,7 +70,8 @@ namespace canvas
|
|||||||
_mode(0),
|
_mode(0),
|
||||||
_fill_rule(VG_EVEN_ODD),
|
_fill_rule(VG_EVEN_ODD),
|
||||||
_stroke_width(1),
|
_stroke_width(1),
|
||||||
_stroke_linecap(VG_CAP_BUTT)
|
_stroke_linecap(VG_CAP_BUTT),
|
||||||
|
_stroke_linejoin(VG_JOIN_MITER)
|
||||||
{
|
{
|
||||||
setSupportsDisplayList(false);
|
setSupportsDisplayList(false);
|
||||||
setDataVariance(Object::DYNAMIC);
|
setDataVariance(Object::DYNAMIC);
|
||||||
@@ -202,6 +204,21 @@ namespace canvas
|
|||||||
_stroke_linecap = VG_CAP_BUTT;
|
_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
|
* Draw callback
|
||||||
*/
|
*/
|
||||||
@@ -251,6 +268,7 @@ namespace canvas
|
|||||||
|
|
||||||
vgSetf(VG_STROKE_LINE_WIDTH, _stroke_width);
|
vgSetf(VG_STROKE_LINE_WIDTH, _stroke_width);
|
||||||
vgSeti(VG_STROKE_CAP_STYLE, _stroke_linecap);
|
vgSeti(VG_STROKE_CAP_STYLE, _stroke_linecap);
|
||||||
|
vgSeti(VG_STROKE_JOIN_STYLE, _stroke_linejoin);
|
||||||
vgSetfv( VG_STROKE_DASH_PATTERN,
|
vgSetfv( VG_STROKE_DASH_PATTERN,
|
||||||
_stroke_dash.size(),
|
_stroke_dash.size(),
|
||||||
_stroke_dash.empty() ? 0 : &_stroke_dash[0] );
|
_stroke_dash.empty() ? 0 : &_stroke_dash[0] );
|
||||||
@@ -372,7 +390,13 @@ namespace canvas
|
|||||||
/**
|
/**
|
||||||
* Compute the bounding box
|
* 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) )
|
if( _path == VG_INVALID_HANDLE || (_attributes_dirty & PATH) )
|
||||||
return osg::BoundingBox();
|
return osg::BoundingBox();
|
||||||
@@ -419,6 +443,7 @@ namespace canvas
|
|||||||
VGfloat _stroke_width;
|
VGfloat _stroke_width;
|
||||||
std::vector<VGfloat> _stroke_dash;
|
std::vector<VGfloat> _stroke_dash;
|
||||||
VGCapStyle _stroke_linecap;
|
VGCapStyle _stroke_linecap;
|
||||||
|
VGJoinStyle _stroke_linejoin;
|
||||||
|
|
||||||
osg::Vec3f transformPoint( const osg::Matrix& m,
|
osg::Vec3f transformPoint( const osg::Matrix& m,
|
||||||
osg::Vec2f pos ) const
|
osg::Vec2f pos ) const
|
||||||
@@ -499,6 +524,7 @@ namespace canvas
|
|||||||
addStyle("stroke-width", "numeric", &PathDrawable::setStrokeWidth, path);
|
addStyle("stroke-width", "numeric", &PathDrawable::setStrokeWidth, path);
|
||||||
addStyle("stroke-dasharray", "", &PathDrawable::setStrokeDashArray, path);
|
addStyle("stroke-dasharray", "", &PathDrawable::setStrokeDashArray, path);
|
||||||
addStyle("stroke-linecap", "", &PathDrawable::setStrokeLinecap, path);
|
addStyle("stroke-linecap", "", &PathDrawable::setStrokeLinecap, path);
|
||||||
|
addStyle("stroke-linejoin", "", &PathDrawable::setStrokeLinejoin, path);
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
#include <simgear/canvas/CanvasSystemAdapter.hxx>
|
#include <simgear/canvas/CanvasSystemAdapter.hxx>
|
||||||
#include <simgear/scene/util/parse_color.hxx>
|
#include <simgear/scene/util/parse_color.hxx>
|
||||||
#include <osg/Version>
|
#include <osg/Version>
|
||||||
|
#include <osgDB/Registry>
|
||||||
#include <osgText/Text>
|
#include <osgText/Text>
|
||||||
|
|
||||||
namespace simgear
|
namespace simgear
|
||||||
@@ -31,27 +32,190 @@ namespace canvas
|
|||||||
public osgText::Text
|
public osgText::Text
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
TextOSG(canvas::Text* text);
|
TextOSG(canvas::Text* text);
|
||||||
|
|
||||||
void setFontResolution(int res);
|
void setFontResolution(int res);
|
||||||
void setCharacterAspect(float aspect);
|
void setCharacterAspect(float aspect);
|
||||||
void setLineHeight(float factor);
|
void setLineHeight(float factor);
|
||||||
void setFill(const std::string& fill);
|
void setFill(const std::string& fill);
|
||||||
|
void setStroke(const std::string& color);
|
||||||
void setBackgroundColor(const std::string& fill);
|
void setBackgroundColor(const std::string& fill);
|
||||||
|
|
||||||
SGVec2i sizeForWidth(int w) const;
|
float lineHeight() const;
|
||||||
osg::Vec2 handleHit(const osg::Vec2f& pos);
|
|
||||||
|
|
||||||
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:
|
protected:
|
||||||
|
|
||||||
|
friend class TextLine;
|
||||||
|
|
||||||
canvas::Text *_text_element;
|
canvas::Text *_text_element;
|
||||||
|
|
||||||
virtual void computePositions(unsigned int contextID) const;
|
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;
|
||||||
|
|
||||||
|
GlyphQuads::Coords2 const& coords = _quads->_coords;
|
||||||
|
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;
|
||||||
|
GlyphQuads::Coords2 const& coords = _quads->_coords;
|
||||||
|
|
||||||
|
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::TextOSG::TextOSG(canvas::Text* text):
|
||||||
_text_element(text)
|
_text_element(text)
|
||||||
@@ -88,6 +252,19 @@ namespace canvas
|
|||||||
setColor( color );
|
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)
|
void Text::TextOSG::setBackgroundColor(const std::string& fill)
|
||||||
{
|
{
|
||||||
@@ -96,6 +273,45 @@ namespace canvas
|
|||||||
setBoundingBoxColor( color );
|
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
|
// simplified version of osgText::Text::computeGlyphRepresentation() to
|
||||||
// just calculate the size for a given weight. Glpyh calculations/creating
|
// just calculate the size for a given weight. Glpyh calculations/creating
|
||||||
@@ -372,89 +588,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;
|
osg::BoundingBox bb =
|
||||||
|
#if OSG_VERSION_LESS_THAN(3,3,2)
|
||||||
// TODO check with align other than TOP
|
osgText::Text::computeBound();
|
||||||
float first_line_y = -0.5 * _lineSpacing;//_offset.y() - _characterHeight;
|
#else
|
||||||
size_t line = std::max<int>(0, (pos.y() - first_line_y) / line_height);
|
osgText::Text::computeBoundingBox();
|
||||||
|
#endif
|
||||||
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();
|
|
||||||
|
|
||||||
#if OSG_VERSION_LESS_THAN(3,1,0)
|
#if OSG_VERSION_LESS_THAN(3,1,0)
|
||||||
if( bb.valid() )
|
if( bb.valid() )
|
||||||
@@ -546,6 +693,7 @@ namespace canvas
|
|||||||
|
|
||||||
addStyle("fill", "color", &TextOSG::setFill, text);
|
addStyle("fill", "color", &TextOSG::setFill, text);
|
||||||
addStyle("background", "color", &TextOSG::setBackgroundColor, text);
|
addStyle("background", "color", &TextOSG::setBackgroundColor, text);
|
||||||
|
addStyle("stroke", "color", &TextOSG::setStroke, text);
|
||||||
addStyle("character-size",
|
addStyle("character-size",
|
||||||
"numeric",
|
"numeric",
|
||||||
static_cast<
|
static_cast<
|
||||||
@@ -567,6 +715,10 @@ namespace canvas
|
|||||||
addStyle("font", "", &Text::setFont);
|
addStyle("font", "", &Text::setFont);
|
||||||
addStyle("alignment", "", &Text::setAlignment);
|
addStyle("alignment", "", &Text::setAlignment);
|
||||||
addStyle("text", "", &Text::setText, false);
|
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");
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
@@ -657,10 +809,39 @@ namespace canvas
|
|||||||
return _text->sizeForWidth(INT_MAX).x();
|
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
|
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
|
} // namespace canvas
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ namespace simgear
|
|||||||
namespace canvas
|
namespace canvas
|
||||||
{
|
{
|
||||||
|
|
||||||
|
class TextLine;
|
||||||
class Text:
|
class Text:
|
||||||
public Element
|
public Element
|
||||||
{
|
{
|
||||||
@@ -48,13 +49,24 @@ namespace canvas
|
|||||||
|
|
||||||
int heightForWidth(int w) const;
|
int heightForWidth(int w) const;
|
||||||
int maxWidth() 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 getNearestCursor(const osg::Vec2& pos) const;
|
||||||
|
osg::Vec2 getCursorPos(size_t line, size_t character) const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
|
friend class TextLine;
|
||||||
class TextOSG;
|
class TextOSG;
|
||||||
osg::ref_ptr<TextOSG> _text;
|
osg::ref_ptr<TextOSG> _text;
|
||||||
|
|
||||||
|
virtual osg::StateSet* getOrCreateStateSet();
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace canvas
|
} // namespace canvas
|
||||||
|
|||||||
@@ -2,11 +2,15 @@ include (SimGearComponent)
|
|||||||
|
|
||||||
set(HEADERS
|
set(HEADERS
|
||||||
CustomEvent.hxx
|
CustomEvent.hxx
|
||||||
|
DeviceEvent.hxx
|
||||||
|
KeyboardEvent.hxx
|
||||||
MouseEvent.hxx
|
MouseEvent.hxx
|
||||||
)
|
)
|
||||||
|
|
||||||
set(SOURCES
|
set(SOURCES
|
||||||
CustomEvent.cxx
|
CustomEvent.cxx
|
||||||
|
DeviceEvent.cxx
|
||||||
|
KeyboardEvent.cxx
|
||||||
MouseEvent.cxx
|
MouseEvent.cxx
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -16,3 +20,9 @@ add_boost_test(canvas_event
|
|||||||
SOURCES event_test.cpp
|
SOURCES event_test.cpp
|
||||||
LIBRARIES ${TEST_LIBS}
|
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>
|
// Copyright (C) 2014 Thomas Geymayer <tomgey@gmail.com>
|
||||||
//
|
//
|
||||||
@@ -27,6 +28,10 @@ namespace simgear
|
|||||||
namespace canvas
|
namespace canvas
|
||||||
{
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* User defined event (optionally carrying additional context information or
|
||||||
|
* data).
|
||||||
|
*/
|
||||||
class CustomEvent:
|
class CustomEvent:
|
||||||
public Event
|
public Event
|
||||||
{
|
{
|
||||||
@@ -36,6 +41,7 @@ namespace canvas
|
|||||||
*
|
*
|
||||||
* @param type_str Event type name (if name does not exist yet it will
|
* @param type_str Event type name (if name does not exist yet it will
|
||||||
* be registered as new event type)
|
* 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
|
* @param data Optional user data stored in event
|
||||||
*/
|
*/
|
||||||
CustomEvent( std::string const& type_str,
|
CustomEvent( std::string const& type_str,
|
||||||
@@ -45,6 +51,7 @@ namespace canvas
|
|||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param type_id Event type id
|
* @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
|
* @param data Optional user data stored in event
|
||||||
*/
|
*/
|
||||||
CustomEvent( int type_id,
|
CustomEvent( int type_id,
|
||||||
@@ -61,10 +68,16 @@ namespace canvas
|
|||||||
*/
|
*/
|
||||||
StringMap const& getDetail() const { return detail; }
|
StringMap const& getDetail() const { return detail; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get whether this event supports bubbling.
|
||||||
|
*
|
||||||
|
* @see #bubbles
|
||||||
|
* @see CustomEvent()
|
||||||
|
*/
|
||||||
virtual bool canBubble() const { return bubbles; }
|
virtual bool canBubble() const { return bubbles; }
|
||||||
|
|
||||||
StringMap detail; //<! user data map
|
StringMap detail; //!< User data map
|
||||||
bool bubbles;
|
bool bubbles; //!< Whether the event supports bubbling
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace canvas
|
} // namespace canvas
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -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_ */
|
||||||
@@ -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
|
||||||
@@ -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
|
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||||
|
|
||||||
#include "MouseEvent.hxx"
|
#include "MouseEvent.hxx"
|
||||||
|
#include <osgGA/GUIEventAdapter>
|
||||||
|
|
||||||
namespace simgear
|
namespace simgear
|
||||||
{
|
{
|
||||||
@@ -27,7 +28,6 @@ namespace canvas
|
|||||||
MouseEvent::MouseEvent():
|
MouseEvent::MouseEvent():
|
||||||
button(0),
|
button(0),
|
||||||
buttons(0),
|
buttons(0),
|
||||||
modifiers(0),
|
|
||||||
click_count(0)
|
click_count(0)
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -35,13 +35,11 @@ namespace canvas
|
|||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
MouseEvent::MouseEvent(const osgGA::GUIEventAdapter& ea):
|
MouseEvent::MouseEvent(const osgGA::GUIEventAdapter& ea):
|
||||||
|
DeviceEvent(ea),
|
||||||
button(0),
|
button(0),
|
||||||
buttons(ea.getButtonMask()),
|
buttons(ea.getButtonMask()),
|
||||||
modifiers(ea.getModKeyMask()),
|
|
||||||
click_count(0)
|
click_count(0)
|
||||||
{
|
{
|
||||||
time = ea.getTime();
|
|
||||||
|
|
||||||
// Convert button mask to index
|
// Convert button mask to index
|
||||||
int button_mask = ea.getButton();
|
int button_mask = ea.getButton();
|
||||||
while( (button_mask >>= 1) > 0 )
|
while( (button_mask >>= 1) > 0 )
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
///@file Mouse event
|
///@file
|
||||||
|
/// Mouse event
|
||||||
//
|
//
|
||||||
// Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com>
|
// Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com>
|
||||||
//
|
//
|
||||||
@@ -19,16 +20,18 @@
|
|||||||
#ifndef CANVAS_MOUSE_EVENT_HXX_
|
#ifndef CANVAS_MOUSE_EVENT_HXX_
|
||||||
#define CANVAS_MOUSE_EVENT_HXX_
|
#define CANVAS_MOUSE_EVENT_HXX_
|
||||||
|
|
||||||
#include <simgear/canvas/CanvasEvent.hxx>
|
#include "DeviceEvent.hxx"
|
||||||
#include <osgGA/GUIEventAdapter>
|
|
||||||
|
|
||||||
namespace simgear
|
namespace simgear
|
||||||
{
|
{
|
||||||
namespace canvas
|
namespace canvas
|
||||||
{
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mouse (button/move/wheel) event
|
||||||
|
*/
|
||||||
class MouseEvent:
|
class MouseEvent:
|
||||||
public Event
|
public DeviceEvent
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
MouseEvent();
|
MouseEvent();
|
||||||
@@ -55,18 +58,16 @@ namespace canvas
|
|||||||
|
|
||||||
int getButton() const { return button; }
|
int getButton() const { return button; }
|
||||||
int getButtonMask() const { return buttons; }
|
int getButtonMask() const { return buttons; }
|
||||||
int getModifiers() const { return modifiers; }
|
|
||||||
|
|
||||||
int getCurrentClickCount() const { return click_count; }
|
int getCurrentClickCount() const { return click_count; }
|
||||||
|
|
||||||
osg::Vec2f screen_pos, //<! Position in screen coordinates
|
osg::Vec2f screen_pos, //!< Position in screen coordinates
|
||||||
client_pos, //<! Position in window/canvas coordinates
|
client_pos, //!< Position in window/canvas coordinates
|
||||||
local_pos, //<! Position in local/element coordinates
|
local_pos, //!< Position in local/element coordinates
|
||||||
delta;
|
delta;
|
||||||
int button, //<! Button for this event
|
int button, //!< Button for this event
|
||||||
buttons, //<! Current button state
|
buttons, //!< Current button state
|
||||||
modifiers, //<! Keyboard modifier state
|
click_count; //!< Current click count
|
||||||
click_count; //<! Current click count
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace canvas
|
} // namespace canvas
|
||||||
|
|||||||
@@ -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();
|
||||||
|
}
|
||||||
@@ -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};
|
ItemData item_data = {0};
|
||||||
item_data.layout_item = item;
|
item_data.layout_item = item;
|
||||||
item_data.stretch = std::max(0, stretch);
|
item_data.stretch = std::max(0, stretch);
|
||||||
|
|
||||||
item->setCanvas(_canvas);
|
if( alignment != AlignFill )
|
||||||
|
item->setAlignment(alignment);
|
||||||
|
|
||||||
|
if( SGWeakReferenced::count(this) )
|
||||||
item->setParent(this);
|
item->setParent(this);
|
||||||
|
else
|
||||||
|
SG_LOG( SG_GUI,
|
||||||
|
SG_WARN,
|
||||||
|
"Adding item to expired or non-refcounted layout" );
|
||||||
|
|
||||||
if( index < 0 )
|
if( index < 0 )
|
||||||
_layout_items.push_back(item_data);
|
_layout_items.push_back(item_data);
|
||||||
@@ -122,6 +134,7 @@ namespace canvas
|
|||||||
LayoutItems::iterator it = _layout_items.begin() + index;
|
LayoutItems::iterator it = _layout_items.begin() + index;
|
||||||
LayoutItemRef item = it->layout_item;
|
LayoutItemRef item = it->layout_item;
|
||||||
item->onRemove();
|
item->onRemove();
|
||||||
|
item->setParent(LayoutItemWeakRef());
|
||||||
_layout_items.erase(it);
|
_layout_items.erase(it);
|
||||||
|
|
||||||
invalidate();
|
invalidate();
|
||||||
@@ -137,6 +150,7 @@ namespace canvas
|
|||||||
++it )
|
++it )
|
||||||
{
|
{
|
||||||
it->layout_item->onRemove();
|
it->layout_item->onRemove();
|
||||||
|
it->layout_item->setParent(LayoutItemWeakRef());
|
||||||
}
|
}
|
||||||
_layout_items.clear();
|
_layout_items.clear();
|
||||||
invalidate();
|
invalidate();
|
||||||
@@ -223,26 +237,6 @@ namespace canvas
|
|||||||
return _layout_data.has_hfw;
|
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)
|
void BoxLayout::setCanvas(const CanvasWeakPtr& canvas)
|
||||||
{
|
{
|
||||||
@@ -272,16 +266,23 @@ namespace canvas
|
|||||||
|
|
||||||
for(size_t i = 0; i < _layout_items.size(); ++i)
|
for(size_t i = 0; i < _layout_items.size(); ++i)
|
||||||
{
|
{
|
||||||
// TODO check visible
|
|
||||||
|
|
||||||
ItemData& item_data = _layout_items[i];
|
ItemData& item_data = _layout_items[i];
|
||||||
LayoutItem const& item = *item_data.layout_item;
|
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.min_size = (item.minimumSize().*_get_layout_coord)();
|
||||||
item_data.max_size = (item.maximumSize().*_get_layout_coord)();
|
item_data.max_size = (item.maximumSize().*_get_layout_coord)();
|
||||||
item_data.size_hint = (item.sizeHint().*_get_layout_coord)();
|
item_data.size_hint = (item.sizeHint().*_get_layout_coord)();
|
||||||
item_data.has_hfw = item.hasHeightForWidth();
|
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( !dynamic_cast<SpacerItem*>(item_data.layout_item.get()) )
|
||||||
{
|
{
|
||||||
if( is_first )
|
if( is_first )
|
||||||
@@ -297,9 +298,9 @@ namespace canvas
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Add sizes of all children in layout direction
|
// Add sizes of all children in layout direction
|
||||||
safeAdd(min_size.x(), item_data.min_size);
|
SGMisc<int>::addClipOverflowInplace(min_size.x(), item_data.min_size);
|
||||||
safeAdd(max_size.x(), item_data.max_size);
|
SGMisc<int>::addClipOverflowInplace(max_size.x(), item_data.max_size);
|
||||||
safeAdd(size_hint.x(), item_data.size_hint);
|
SGMisc<int>::addClipOverflowInplace(size_hint.x(), item_data.size_hint);
|
||||||
|
|
||||||
// Take maximum in fixed (non-layouted) direction
|
// Take maximum in fixed (non-layouted) direction
|
||||||
min_size.y() = std::max( min_size.y(),
|
min_size.y() = std::max( min_size.y(),
|
||||||
@@ -312,9 +313,9 @@ namespace canvas
|
|||||||
_layout_data.has_hfw = _layout_data.has_hfw || item.hasHeightForWidth();
|
_layout_data.has_hfw = _layout_data.has_hfw || item.hasHeightForWidth();
|
||||||
}
|
}
|
||||||
|
|
||||||
safeAdd(min_size.x(), _layout_data.padding);
|
SGMisc<int>::addClipOverflowInplace(min_size.x(), _layout_data.padding);
|
||||||
safeAdd(max_size.x(), _layout_data.padding);
|
SGMisc<int>::addClipOverflowInplace(max_size.x(), _layout_data.padding);
|
||||||
safeAdd(size_hint.x(), _layout_data.padding);
|
SGMisc<int>::addClipOverflowInplace(size_hint.x(), _layout_data.padding);
|
||||||
|
|
||||||
_layout_data.min_size = min_size.x();
|
_layout_data.min_size = min_size.x();
|
||||||
_layout_data.max_size = max_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)
|
for(size_t i = 0; i < _layout_items.size(); ++i)
|
||||||
{
|
{
|
||||||
ItemData const& data = _layout_items[i];
|
ItemData const& data = _layout_items[i];
|
||||||
|
if( !data.visible )
|
||||||
|
continue;
|
||||||
|
|
||||||
_hfw_height = std::max(_hfw_height, data.hfw(data.size));
|
_hfw_height = std::max(_hfw_height, data.hfw(data.size));
|
||||||
_hfw_min_height = std::max(_hfw_min_height, data.mhfw(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)
|
for(size_t i = 0; i < _layout_items.size(); ++i)
|
||||||
{
|
{
|
||||||
ItemData const& data = _layout_items[i];
|
ItemData const& data = _layout_items[i];
|
||||||
|
if( !data.visible )
|
||||||
|
continue;
|
||||||
|
|
||||||
_hfw_height += data.hfw(w) + data.padding_orig;
|
_hfw_height += data.hfw(w) + data.padding_orig;
|
||||||
_hfw_min_height += data.mhfw(w) + data.padding_orig;
|
_hfw_min_height += data.mhfw(w) + data.padding_orig;
|
||||||
}
|
}
|
||||||
@@ -386,6 +393,27 @@ namespace canvas
|
|||||||
return _max_size;
|
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)
|
void BoxLayout::doLayout(const SGRecti& geom)
|
||||||
{
|
{
|
||||||
@@ -406,6 +434,9 @@ namespace canvas
|
|||||||
for(size_t i = 0; i < _layout_items.size(); ++i)
|
for(size_t i = 0; i < _layout_items.size(); ++i)
|
||||||
{
|
{
|
||||||
ItemData& data = _layout_items[i];
|
ItemData& data = _layout_items[i];
|
||||||
|
if( !data.visible )
|
||||||
|
continue;
|
||||||
|
|
||||||
if( data.has_hfw )
|
if( data.has_hfw )
|
||||||
{
|
{
|
||||||
int w = SGMisc<int>::clip( geom.width(),
|
int w = SGMisc<int>::clip( geom.width(),
|
||||||
@@ -434,7 +465,10 @@ namespace canvas
|
|||||||
_layout_data.size_hint = size_hint_save;
|
_layout_data.size_hint = size_hint_save;
|
||||||
|
|
||||||
// and finally set the layouted geometry for each item
|
// 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)(),
|
SGVec2i cur_pos( (geom.pos().*_get_layout_coord)(),
|
||||||
(geom.pos().*_get_fixed_coord)() );
|
(geom.pos().*_get_fixed_coord)() );
|
||||||
|
|
||||||
@@ -445,17 +479,11 @@ namespace canvas
|
|||||||
for(size_t i = 0; i < _layout_items.size(); ++i)
|
for(size_t i = 0; i < _layout_items.size(); ++i)
|
||||||
{
|
{
|
||||||
ItemData const& data = _layout_items[i];
|
ItemData const& data = _layout_items[i];
|
||||||
|
if( !data.visible )
|
||||||
|
continue;
|
||||||
|
|
||||||
cur_pos.x() += reverse ? -data.padding - data.size : data.padding;
|
cur_pos.x() += reverse ? -data.padding - data.size : data.padding;
|
||||||
|
size.x() = data.size;
|
||||||
SGVec2i size(
|
|
||||||
data.size,
|
|
||||||
std::min( (data.layout_item->maximumSize().*_get_fixed_coord)(),
|
|
||||||
fixed_size )
|
|
||||||
);
|
|
||||||
|
|
||||||
// Center in fixed direction (TODO allow specifying alignment)
|
|
||||||
int offset_fixed = (fixed_size - size.y()) / 2;
|
|
||||||
cur_pos.y() += offset_fixed;
|
|
||||||
|
|
||||||
data.layout_item->setGeometry(SGRecti(
|
data.layout_item->setGeometry(SGRecti(
|
||||||
(cur_pos.*_get_layout_coord)(),
|
(cur_pos.*_get_layout_coord)(),
|
||||||
@@ -466,10 +494,16 @@ namespace canvas
|
|||||||
|
|
||||||
if( !reverse )
|
if( !reverse )
|
||||||
cur_pos.x() += data.size;
|
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():
|
HBoxLayout::HBoxLayout():
|
||||||
BoxLayout(LeftToRight)
|
BoxLayout(LeftToRight)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Align items horizontally or vertically in a box
|
/// @file
|
||||||
//
|
//
|
||||||
// Copyright (C) 2014 Thomas Geymayer <tomgey@gmail.com>
|
// Copyright (C) 2014 Thomas Geymayer <tomgey@gmail.com>
|
||||||
//
|
//
|
||||||
@@ -26,6 +26,11 @@ namespace simgear
|
|||||||
namespace canvas
|
namespace canvas
|
||||||
{
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Align LayoutItems horizontally or vertically in a box.
|
||||||
|
*
|
||||||
|
* @see http://qt-project.org/doc/qt-4.8/qboxlayout.html#details
|
||||||
|
*/
|
||||||
class BoxLayout:
|
class BoxLayout:
|
||||||
public Layout
|
public Layout
|
||||||
{
|
{
|
||||||
@@ -44,13 +49,18 @@ namespace canvas
|
|||||||
|
|
||||||
virtual void addItem(const LayoutItemRef& item);
|
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 addStretch(int stretch = 0);
|
||||||
|
|
||||||
void addSpacing(int size);
|
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);
|
void insertStretch(int index, int stretch = 0);
|
||||||
|
|
||||||
@@ -86,8 +96,6 @@ namespace canvas
|
|||||||
Direction direction() const;
|
Direction direction() const;
|
||||||
|
|
||||||
virtual bool hasHeightForWidth() const;
|
virtual bool hasHeightForWidth() const;
|
||||||
virtual int heightForWidth(int w) const;
|
|
||||||
virtual int minimumHeightForWidth(int w) const;
|
|
||||||
|
|
||||||
virtual void setCanvas(const CanvasWeakPtr& canvas);
|
virtual void setCanvas(const CanvasWeakPtr& canvas);
|
||||||
|
|
||||||
@@ -96,9 +104,9 @@ namespace canvas
|
|||||||
protected:
|
protected:
|
||||||
|
|
||||||
typedef const int& (SGVec2i::*CoordGetter)() const;
|
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
|
// direction
|
||||||
_get_fixed_coord; //<! getter for coordinate in secondary
|
_get_fixed_coord; //!< getter for coordinate in secondary
|
||||||
// (fixed) direction
|
// (fixed) direction
|
||||||
|
|
||||||
int _padding;
|
int _padding;
|
||||||
@@ -121,7 +129,12 @@ namespace canvas
|
|||||||
virtual SGVec2i minimumSizeImpl() const;
|
virtual SGVec2i minimumSizeImpl() const;
|
||||||
virtual SGVec2i maximumSizeImpl() 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 doLayout(const SGRecti& geom);
|
||||||
|
|
||||||
|
virtual void visibilityChanged(bool visible);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
include (SimGearComponent)
|
include (SimGearComponent)
|
||||||
|
|
||||||
set(HEADERS
|
set(HEADERS
|
||||||
|
AlignFlag_values.hxx
|
||||||
BoxLayout.hxx
|
BoxLayout.hxx
|
||||||
Layout.hxx
|
Layout.hxx
|
||||||
LayoutItem.hxx
|
LayoutItem.hxx
|
||||||
|
|||||||
@@ -24,36 +24,6 @@ namespace simgear
|
|||||||
namespace canvas
|
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)
|
void Layout::removeItem(const LayoutItemRef& item)
|
||||||
{
|
{
|
||||||
@@ -74,6 +44,19 @@ namespace canvas
|
|||||||
takeAt(0);
|
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()
|
void Layout::ItemData::reset()
|
||||||
{
|
{
|
||||||
@@ -85,6 +68,8 @@ namespace canvas
|
|||||||
padding = 0;
|
padding = 0;
|
||||||
size = 0;
|
size = 0;
|
||||||
stretch = 0;
|
stretch = 0;
|
||||||
|
visible = false;
|
||||||
|
has_align = false;
|
||||||
has_hfw = false;
|
has_hfw = false;
|
||||||
done = 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)
|
void Layout::distribute(std::vector<ItemData>& items, const ItemData& space)
|
||||||
{
|
{
|
||||||
const int num_children = static_cast<int>(items.size());
|
const int num_children = static_cast<int>(items.size());
|
||||||
_num_not_done = num_children;
|
_num_not_done = 0;
|
||||||
|
|
||||||
SG_LOG( SG_GUI,
|
SG_LOG( SG_GUI,
|
||||||
SG_DEBUG,
|
SG_DEBUG,
|
||||||
@@ -148,6 +142,9 @@ namespace canvas
|
|||||||
for(int i = 0; i < num_children; ++i)
|
for(int i = 0; i < num_children; ++i)
|
||||||
{
|
{
|
||||||
ItemData& d = items[i];
|
ItemData& d = items[i];
|
||||||
|
if( !d.visible )
|
||||||
|
continue;
|
||||||
|
|
||||||
d.size = less_then_hint ? d.min_size : d.size_hint;
|
d.size = less_then_hint ? d.min_size : d.size_hint;
|
||||||
d.padding = d.padding_orig;
|
d.padding = d.padding_orig;
|
||||||
d.done = d.size >= (less_then_hint ? d.size_hint : d.max_size);
|
d.done = d.size >= (less_then_hint ? d.size_hint : d.max_size);
|
||||||
@@ -162,10 +159,8 @@ namespace canvas
|
|||||||
);
|
);
|
||||||
|
|
||||||
if( d.done )
|
if( d.done )
|
||||||
{
|
|
||||||
_num_not_done -= 1;
|
|
||||||
continue;
|
continue;
|
||||||
}
|
_num_not_done += 1;
|
||||||
|
|
||||||
if( d.stretch > 0 )
|
if( d.stretch > 0 )
|
||||||
{
|
{
|
||||||
@@ -191,6 +186,8 @@ namespace canvas
|
|||||||
for(int i = 0; i < num_children; ++i)
|
for(int i = 0; i < num_children; ++i)
|
||||||
{
|
{
|
||||||
ItemData& d = items[i];
|
ItemData& d = items[i];
|
||||||
|
if( !d.visible )
|
||||||
|
continue;
|
||||||
|
|
||||||
SG_LOG(
|
SG_LOG(
|
||||||
SG_GUI,
|
SG_GUI,
|
||||||
@@ -265,18 +262,59 @@ namespace canvas
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
_space_left = space.size - space.max_size;
|
_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)
|
for(int i = 0; i < num_children; ++i)
|
||||||
{
|
{
|
||||||
ItemData& d = items[i];
|
ItemData& d = items[i];
|
||||||
|
if( !d.visible )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
d.padding = d.padding_orig;
|
||||||
d.size = d.max_size;
|
d.size = d.max_size;
|
||||||
|
|
||||||
|
int space_add = 0;
|
||||||
|
|
||||||
|
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
|
// Add superfluous space as padding
|
||||||
d.padding = d.padding_orig + _space_left
|
space_add = _space_left
|
||||||
// Padding after last child...
|
// Padding after last child...
|
||||||
/ (_num_not_done + 1);
|
/ (_num_not_done + 1);
|
||||||
|
|
||||||
_space_left -= d.padding - d.padding_orig;
|
|
||||||
_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)
|
for(int i = 0; i < num_children; ++i)
|
||||||
{
|
{
|
||||||
ItemData const& d = items[i];
|
ItemData const& d = items[i];
|
||||||
SG_LOG( SG_GUI,
|
if( d.visible )
|
||||||
SG_DEBUG,
|
SG_LOG(SG_GUI, SG_DEBUG, i << ") pad=" << d.padding
|
||||||
i << ") pad=" << d.padding
|
<< ", size= " << d.size);
|
||||||
<< ", 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>
|
// Copyright (C) 2014 Thomas Geymayer <tomgey@gmail.com>
|
||||||
//
|
//
|
||||||
@@ -27,15 +27,13 @@ namespace simgear
|
|||||||
namespace canvas
|
namespace canvas
|
||||||
{
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base class for all Canvas layouts.
|
||||||
|
*/
|
||||||
class Layout:
|
class Layout:
|
||||||
public LayoutItem
|
public LayoutItem
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
void update();
|
|
||||||
|
|
||||||
virtual void invalidate();
|
|
||||||
virtual void setGeometry(const SGRecti& geom);
|
|
||||||
|
|
||||||
virtual void addItem(const LayoutItemRef& item) = 0;
|
virtual void addItem(const LayoutItemRef& item) = 0;
|
||||||
virtual void setSpacing(int spacing) = 0;
|
virtual void setSpacing(int spacing) = 0;
|
||||||
virtual int spacing() const = 0;
|
virtual int spacing() const = 0;
|
||||||
@@ -71,11 +69,22 @@ namespace canvas
|
|||||||
*/
|
*/
|
||||||
virtual void clear();
|
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:
|
protected:
|
||||||
enum LayoutFlags
|
enum LayoutFlags
|
||||||
{
|
{
|
||||||
LAYOUT_DIRTY = LayoutItem::LAST_FLAG << 1,
|
LAST_FLAG = LayoutItem::LAST_FLAG
|
||||||
LAST_FLAG = LAYOUT_DIRTY
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ItemData
|
struct ItemData
|
||||||
@@ -84,12 +93,14 @@ namespace canvas
|
|||||||
int size_hint,
|
int size_hint,
|
||||||
min_size,
|
min_size,
|
||||||
max_size,
|
max_size,
|
||||||
padding_orig, //<! original padding as specified by the user
|
padding_orig, //!< original padding as specified by the user
|
||||||
padding, //<! padding before element (layouted)
|
padding, //!< padding before element (layouted)
|
||||||
size, //<! layouted size
|
size, //!< layouted size
|
||||||
stretch; //<! stretch factor
|
stretch; //!< stretch factor
|
||||||
bool has_hfw : 1, //<! height for width
|
bool visible : 1,
|
||||||
done : 1; //<! layouting done
|
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) */
|
/** Clear values (reset to default/empty state) */
|
||||||
void reset();
|
void reset();
|
||||||
@@ -98,16 +109,15 @@ namespace canvas
|
|||||||
int mhfw(int w) const;
|
int mhfw(int w) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Layout();
|
||||||
|
|
||||||
|
virtual void contentsRectChanged(const SGRecti& rect);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Override to implement the actual layouting
|
* Override to implement the actual layouting
|
||||||
*/
|
*/
|
||||||
virtual void doLayout(const SGRecti& geom) = 0;
|
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
|
* Distribute the available @a space to all @a items
|
||||||
*/
|
*/
|
||||||
@@ -115,12 +125,12 @@ namespace canvas
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
int _num_not_done, //<! number of children not layouted yet
|
int _num_not_done, //!< number of children not layouted yet
|
||||||
_sum_stretch, //<! sum of stretch factors of all not yet layouted
|
_sum_stretch, //!< sum of stretch factors of all not yet layouted
|
||||||
// children
|
// children
|
||||||
_space_stretch,//<! space currently assigned to all not yet layouted
|
_space_stretch,//!< space currently assigned to all not yet layouted
|
||||||
// stretchable children
|
// 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
|
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(),
|
const SGVec2i LayoutItem::MAX_SIZE( SGLimits<int>::max(),
|
||||||
SGLimits<int>::max() );
|
SGLimits<int>::max() );
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
LayoutItem::LayoutItem():
|
LayoutItem::LayoutItem():
|
||||||
_flags(0),
|
_alignment(AlignFill),
|
||||||
|
_flags(VISIBLE),
|
||||||
_size_hint(0, 0),
|
_size_hint(0, 0),
|
||||||
_min_size(0, 0),
|
_min_size(0, 0),
|
||||||
_max_size(MAX_SIZE)
|
_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
|
SGVec2i LayoutItem::sizeHint() const
|
||||||
{
|
{
|
||||||
@@ -51,7 +138,7 @@ namespace canvas
|
|||||||
_flags &= ~SIZE_HINT_DIRTY;
|
_flags &= ~SIZE_HINT_DIRTY;
|
||||||
}
|
}
|
||||||
|
|
||||||
return _size_hint;
|
return addClipOverflow(_size_hint, _margins.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
@@ -63,7 +150,7 @@ namespace canvas
|
|||||||
_flags &= ~MINIMUM_SIZE_DIRTY;
|
_flags &= ~MINIMUM_SIZE_DIRTY;
|
||||||
}
|
}
|
||||||
|
|
||||||
return _min_size;
|
return addClipOverflow(_min_size, _margins.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
@@ -75,7 +162,7 @@ namespace canvas
|
|||||||
_flags &= ~MAXIMUM_SIZE_DIRTY;
|
_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
|
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
|
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()
|
void LayoutItem::invalidate()
|
||||||
{
|
{
|
||||||
_flags |= SIZE_INFO_DIRTY;
|
_flags |= SIZE_INFO_DIRTY | LAYOUT_DIRTY;
|
||||||
invalidateParent();
|
invalidateParent();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -111,10 +239,24 @@ namespace canvas
|
|||||||
parent->invalidate();
|
parent->invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void LayoutItem::update()
|
||||||
|
{
|
||||||
|
if( (_flags & LAYOUT_DIRTY) && isVisible() )
|
||||||
|
contentsRectChanged( contentsRect() );
|
||||||
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
void LayoutItem::setGeometry(const SGRecti& geom)
|
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;
|
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)
|
void LayoutItem::setCanvas(const CanvasWeakPtr& canvas)
|
||||||
{
|
{
|
||||||
@@ -140,7 +317,14 @@ namespace canvas
|
|||||||
{
|
{
|
||||||
_parent = parent;
|
_parent = parent;
|
||||||
LayoutItemRef parent_ref = parent.lock();
|
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;
|
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 canvas
|
||||||
} // namespace simgear
|
} // 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>
|
// Copyright (C) 2014 Thomas Geymayer <tomgey@gmail.com>
|
||||||
//
|
//
|
||||||
@@ -34,6 +35,65 @@ namespace canvas
|
|||||||
typedef SGSharedPtr<LayoutItem> LayoutItemRef;
|
typedef SGSharedPtr<LayoutItem> LayoutItemRef;
|
||||||
typedef SGWeakPtr<LayoutItem> LayoutItemWeakRef;
|
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
|
* Base class for all layouting elements. Specializations either implement a
|
||||||
* layouting algorithm or a widget.
|
* layouting algorithm or a widget.
|
||||||
@@ -49,6 +109,49 @@ namespace canvas
|
|||||||
LayoutItem();
|
LayoutItem();
|
||||||
virtual ~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.
|
* Get the preferred size of this item.
|
||||||
*/
|
*/
|
||||||
@@ -64,9 +167,60 @@ namespace canvas
|
|||||||
*/
|
*/
|
||||||
SGVec2i maximumSize() const;
|
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 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.
|
* Mark all cached data as invalid and require it to be recalculated.
|
||||||
@@ -74,10 +228,15 @@ namespace canvas
|
|||||||
virtual void invalidate();
|
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();
|
void invalidateParent();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply any changes not applied yet.
|
||||||
|
*/
|
||||||
|
void update();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set position and size of this element. For layouts this triggers a
|
* Set position and size of this element. For layouts this triggers a
|
||||||
* recalculation of the layout.
|
* recalculation of the layout.
|
||||||
@@ -89,6 +248,20 @@ namespace canvas
|
|||||||
*/
|
*/
|
||||||
virtual SGRecti geometry() const;
|
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.
|
* Set the canvas this item is attached to.
|
||||||
*/
|
*/
|
||||||
@@ -124,13 +297,18 @@ namespace canvas
|
|||||||
SIZE_INFO_DIRTY = SIZE_HINT_DIRTY
|
SIZE_INFO_DIRTY = SIZE_HINT_DIRTY
|
||||||
| MINIMUM_SIZE_DIRTY
|
| MINIMUM_SIZE_DIRTY
|
||||||
| MAXIMUM_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;
|
CanvasWeakPtr _canvas;
|
||||||
LayoutItemWeakRef _parent;
|
LayoutItemWeakRef _parent;
|
||||||
|
|
||||||
SGRecti _geometry;
|
SGRecti _geometry;
|
||||||
|
Margins _margins;
|
||||||
|
uint8_t _alignment;
|
||||||
|
|
||||||
mutable uint32_t _flags;
|
mutable uint32_t _flags;
|
||||||
mutable SGVec2i _size_hint,
|
mutable SGVec2i _size_hint,
|
||||||
@@ -141,6 +319,50 @@ namespace canvas
|
|||||||
virtual SGVec2i minimumSizeImpl() const;
|
virtual SGVec2i minimumSizeImpl() const;
|
||||||
virtual SGVec2i maximumSizeImpl() 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
|
} // namespace canvas
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
#include "NasalWidget.hxx"
|
#include "NasalWidget.hxx"
|
||||||
|
|
||||||
#include <simgear/canvas/Canvas.hxx>
|
#include <simgear/canvas/Canvas.hxx>
|
||||||
|
#include <simgear/nasal/cppbind/NasalContext.hxx>
|
||||||
#include <simgear/nasal/cppbind/Ghost.hxx>
|
#include <simgear/nasal/cppbind/Ghost.hxx>
|
||||||
|
|
||||||
namespace simgear
|
namespace simgear
|
||||||
@@ -45,53 +46,12 @@ namespace canvas
|
|||||||
onRemove();
|
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()
|
void NasalWidget::onRemove()
|
||||||
{
|
{
|
||||||
if( !_nasal_impl.valid() )
|
|
||||||
return;
|
|
||||||
|
|
||||||
typedef boost::function<void(nasal::Me)> Deleter;
|
|
||||||
|
|
||||||
naContext c = naNewContext();
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Deleter del =
|
callMethod<void>("onRemove");
|
||||||
nasal::get_member<Deleter>(c, _nasal_impl.get_naRef(), "onRemove");
|
|
||||||
if( del )
|
|
||||||
del(nasal::to_nasal(c, this));
|
|
||||||
}
|
}
|
||||||
catch( std::exception const& ex )
|
catch( std::exception const& ex )
|
||||||
{
|
{
|
||||||
@@ -101,7 +61,6 @@ namespace canvas
|
|||||||
"NasalWidget::onRemove: callback error: '" << ex.what() << "'"
|
"NasalWidget::onRemove: callback error: '" << ex.what() << "'"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
naFreeContext(c);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
@@ -192,22 +151,6 @@ namespace canvas
|
|||||||
return !_height_for_width.empty() || !_min_height_for_width.empty();
|
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)
|
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 canvas
|
||||||
} // namespace simgear
|
} // 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>
|
// 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:
|
class NasalWidget:
|
||||||
public LayoutItem,
|
public LayoutItem,
|
||||||
@@ -51,8 +52,6 @@ namespace canvas
|
|||||||
|
|
||||||
~NasalWidget();
|
~NasalWidget();
|
||||||
|
|
||||||
virtual void invalidate();
|
|
||||||
virtual void setGeometry(const SGRecti& geom);
|
|
||||||
virtual void onRemove();
|
virtual void onRemove();
|
||||||
|
|
||||||
void setSetGeometryFunc(const SetGeometryFunc& func);
|
void setSetGeometryFunc(const SetGeometryFunc& func);
|
||||||
@@ -85,8 +84,6 @@ namespace canvas
|
|||||||
void setLayoutMaximumSize(const SGVec2i& s);
|
void setLayoutMaximumSize(const SGVec2i& s);
|
||||||
|
|
||||||
virtual bool hasHeightForWidth() const;
|
virtual bool hasHeightForWidth() const;
|
||||||
virtual int heightForWidth(int w) const;
|
|
||||||
virtual int minimumHeightForWidth(int w) const;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param ns Namespace to register the class interface
|
* @param ns Namespace to register the class interface
|
||||||
@@ -118,6 +115,13 @@ namespace canvas
|
|||||||
virtual SGVec2i minimumSizeImpl() const;
|
virtual SGVec2i minimumSizeImpl() const;
|
||||||
virtual SGVec2i maximumSizeImpl() 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;
|
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>
|
// Copyright (C) 2014 Thomas Geymayer <tomgey@gmail.com>
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -23,6 +23,8 @@
|
|||||||
#include "NasalWidget.hxx"
|
#include "NasalWidget.hxx"
|
||||||
|
|
||||||
#include <simgear/debug/logstream.hxx>
|
#include <simgear/debug/logstream.hxx>
|
||||||
|
#include <simgear/nasal/cppbind/NasalContext.hxx>
|
||||||
|
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
@@ -62,16 +64,17 @@ class TestWidget:
|
|||||||
void setMaxSize(const SGVec2i& size) { _max_size = size; }
|
void setMaxSize(const SGVec2i& size) { _max_size = size; }
|
||||||
void setSizeHint(const SGVec2i& size) { _size_hint = size; }
|
void setSizeHint(const SGVec2i& size) { _size_hint = size; }
|
||||||
|
|
||||||
virtual void setGeometry(const SGRecti& geom) { _geom = geom; }
|
|
||||||
virtual SGRecti geometry() const { return _geom; }
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
SGRecti _geom;
|
|
||||||
|
|
||||||
virtual SGVec2i sizeHintImpl() const { return _size_hint; }
|
virtual SGVec2i sizeHintImpl() const { return _size_hint; }
|
||||||
virtual SGVec2i minimumSizeImpl() const { return _min_size; }
|
virtual SGVec2i minimumSizeImpl() const { return _min_size; }
|
||||||
virtual SGVec2i maximumSizeImpl() const { return _max_size; }
|
virtual SGVec2i maximumSizeImpl() const { return _max_size; }
|
||||||
|
|
||||||
|
virtual void visibilityChanged(bool visible)
|
||||||
|
{
|
||||||
|
if( !visible )
|
||||||
|
_geometry.set(0, 0, 0, 0);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class TestWidgetHFW:
|
class TestWidgetHFW:
|
||||||
@@ -91,12 +94,12 @@ class TestWidgetHFW:
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual int heightForWidth(int w) const
|
virtual int heightForWidthImpl(int w) const
|
||||||
{
|
{
|
||||||
return _size_hint.x() * _size_hint.y() / w;
|
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;
|
return _min_size.x() * _min_size.y() / w;
|
||||||
}
|
}
|
||||||
@@ -107,45 +110,45 @@ typedef SGSharedPtr<TestWidget> TestWidgetRef;
|
|||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
BOOST_AUTO_TEST_CASE( horizontal_layout )
|
BOOST_AUTO_TEST_CASE( horizontal_layout )
|
||||||
{
|
{
|
||||||
sc::BoxLayout box_layout(sc::BoxLayout::BottomToTop);
|
sc::BoxLayoutRef box_layout(new sc::BoxLayout(sc::BoxLayout::BottomToTop));
|
||||||
box_layout.setSpacing(5);
|
box_layout->setSpacing(5);
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(box_layout.direction(), sc::BoxLayout::BottomToTop);
|
BOOST_CHECK_EQUAL(box_layout->direction(), sc::BoxLayout::BottomToTop);
|
||||||
BOOST_CHECK_EQUAL(box_layout.spacing(), 5);
|
BOOST_CHECK_EQUAL(box_layout->spacing(), 5);
|
||||||
|
|
||||||
box_layout.setDirection(sc::BoxLayout::LeftToRight);
|
box_layout->setDirection(sc::BoxLayout::LeftToRight);
|
||||||
box_layout.setSpacing(9);
|
box_layout->setSpacing(9);
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(box_layout.direction(), sc::BoxLayout::LeftToRight);
|
BOOST_CHECK_EQUAL(box_layout->direction(), sc::BoxLayout::LeftToRight);
|
||||||
BOOST_CHECK_EQUAL(box_layout.spacing(), 9);
|
BOOST_CHECK_EQUAL(box_layout->spacing(), 9);
|
||||||
|
|
||||||
TestWidgetRef fixed_size_widget( new TestWidget( SGVec2i(16, 16),
|
TestWidgetRef fixed_size_widget( new TestWidget( SGVec2i(16, 16),
|
||||||
SGVec2i(16, 16),
|
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->minimumSize(), SGVec2i(16, 16));
|
||||||
BOOST_CHECK_EQUAL(box_layout.sizeHint(), 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->maximumSize(), SGVec2i(16, 16));
|
||||||
|
|
||||||
TestWidgetRef limited_resize_widget( new TestWidget( SGVec2i(16, 16),
|
TestWidgetRef limited_resize_widget( new TestWidget( SGVec2i(16, 16),
|
||||||
SGVec2i(32, 32),
|
SGVec2i(32, 32),
|
||||||
SGVec2i(256, 64) ) );
|
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
|
// Combined sizes of both widget plus the padding between them
|
||||||
BOOST_CHECK_EQUAL(box_layout.minimumSize(), SGVec2i(41, 16));
|
BOOST_CHECK_EQUAL(box_layout->minimumSize(), SGVec2i(41, 16));
|
||||||
BOOST_CHECK_EQUAL(box_layout.sizeHint(), SGVec2i(57, 32));
|
BOOST_CHECK_EQUAL(box_layout->sizeHint(), SGVec2i(57, 32));
|
||||||
BOOST_CHECK_EQUAL(box_layout.maximumSize(), SGVec2i(281, 64));
|
BOOST_CHECK_EQUAL(box_layout->maximumSize(), SGVec2i(281, 64));
|
||||||
|
|
||||||
// Test with different spacing/padding
|
// 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->minimumSize(), SGVec2i(37, 16));
|
||||||
BOOST_CHECK_EQUAL(box_layout.sizeHint(), SGVec2i(53, 32));
|
BOOST_CHECK_EQUAL(box_layout->sizeHint(), SGVec2i(53, 32));
|
||||||
BOOST_CHECK_EQUAL(box_layout.maximumSize(), SGVec2i(277, 64));
|
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
|
// Fixed size for first widget and remaining space goes to second widget
|
||||||
BOOST_CHECK_EQUAL(fixed_size_widget->geometry(), SGRecti(0, 8, 16, 16));
|
BOOST_CHECK_EQUAL(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),
|
TestWidgetRef stretch_widget( new TestWidget( SGVec2i(16, 16),
|
||||||
SGVec2i(32, 32),
|
SGVec2i(32, 32),
|
||||||
SGVec2i(128, 32) ) );
|
SGVec2i(128, 32) ) );
|
||||||
box_layout.addItem(stretch_widget, 1);
|
box_layout->addItem(stretch_widget, 1);
|
||||||
box_layout.update();
|
box_layout->update();
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(box_layout.minimumSize(), SGVec2i(58, 16));
|
BOOST_CHECK_EQUAL(box_layout->minimumSize(), SGVec2i(58, 16));
|
||||||
BOOST_CHECK_EQUAL(box_layout.sizeHint(), SGVec2i(90, 32));
|
BOOST_CHECK_EQUAL(box_layout->sizeHint(), SGVec2i(90, 32));
|
||||||
BOOST_CHECK_EQUAL(box_layout.maximumSize(), SGVec2i(410, 64));
|
BOOST_CHECK_EQUAL(box_layout->maximumSize(), SGVec2i(410, 64));
|
||||||
|
|
||||||
// Due to the stretch factor only the last widget gets additional space. All
|
// Due to the stretch factor only the last widget gets additional space. All
|
||||||
// other widgets get the preferred size.
|
// other widgets get the preferred size.
|
||||||
@@ -169,63 +172,101 @@ BOOST_AUTO_TEST_CASE( horizontal_layout )
|
|||||||
|
|
||||||
// Test stretch factor
|
// Test stretch factor
|
||||||
TestWidgetRef fast_stretch( new TestWidget(*stretch_widget) );
|
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(stretch_widget, 1);
|
||||||
box_layout_stretch.addItem(fast_stretch, 2);
|
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(stretch_widget->geometry(), SGRecti(0, 0, 41, 32));
|
||||||
BOOST_CHECK_EQUAL(fast_stretch->geometry(), SGRecti(46, 0, 82, 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(stretch_widget->geometry(), SGRecti(0, 0, 123, 32));
|
||||||
BOOST_CHECK_EQUAL(fast_stretch->geometry(), SGRecti(128, 0, 128, 32));
|
BOOST_CHECK_EQUAL(fast_stretch->geometry(), SGRecti(128, 0, 128, 32));
|
||||||
|
|
||||||
// Test superflous space to padding
|
// 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(stretch_widget->geometry(), SGRecti(83, 0, 128, 32));
|
||||||
BOOST_CHECK_EQUAL(fast_stretch->geometry(), SGRecti(300, 0, 128, 32));
|
BOOST_CHECK_EQUAL(fast_stretch->geometry(), SGRecti(300, 0, 128, 32));
|
||||||
|
|
||||||
// Test more space then preferred, but less than maximum
|
// ...and now with alignment
|
||||||
{
|
//
|
||||||
sc::HBoxLayout hbox;
|
// 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.
|
||||||
|
|
||||||
|
// 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));
|
||||||
|
|
||||||
|
// 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));
|
||||||
|
|
||||||
|
// 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));
|
||||||
|
|
||||||
|
// 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));
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// 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),
|
TestWidgetRef w1( new TestWidget( SGVec2i(16, 16),
|
||||||
SGVec2i(32, 32),
|
SGVec2i(32, 32),
|
||||||
SGVec2i(9999, 32) ) ),
|
SGVec2i(9999, 32) ) ),
|
||||||
w2( new TestWidget(*w1) );
|
w2( new TestWidget(*w1) );
|
||||||
|
|
||||||
hbox.addItem(w1);
|
hbox->addItem(w1);
|
||||||
hbox.addItem(w2);
|
hbox->addItem(w2);
|
||||||
|
|
||||||
hbox.setGeometry( SGRecti(0, 0, 256, 32) );
|
hbox->setGeometry( SGRecti(0, 0, 256, 32) );
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(w1->geometry(), SGRecti(0, 0, 126, 32));
|
BOOST_CHECK_EQUAL(w1->geometry(), SGRecti(0, 0, 126, 32));
|
||||||
BOOST_CHECK_EQUAL(w2->geometry(), SGRecti(131, 0, 125, 32));
|
BOOST_CHECK_EQUAL(w2->geometry(), SGRecti(131, 0, 125, 32));
|
||||||
|
|
||||||
hbox.setStretch(0, 1);
|
hbox->setStretch(0, 1);
|
||||||
hbox.setStretch(1, 1);
|
hbox->setStretch(1, 1);
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(hbox.stretch(0), 1);
|
BOOST_CHECK_EQUAL(hbox->stretch(0), 1);
|
||||||
BOOST_CHECK_EQUAL(hbox.stretch(1), 1);
|
BOOST_CHECK_EQUAL(hbox->stretch(1), 1);
|
||||||
|
|
||||||
hbox.update();
|
hbox->update();
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(w1->geometry(), SGRecti(0, 0, 125, 32));
|
BOOST_CHECK_EQUAL(w1->geometry(), SGRecti(0, 0, 125, 32));
|
||||||
BOOST_CHECK_EQUAL(w2->geometry(), SGRecti(130, 0, 126, 32));
|
BOOST_CHECK_EQUAL(w2->geometry(), SGRecti(130, 0, 126, 32));
|
||||||
|
|
||||||
BOOST_REQUIRE( hbox.setStretchFactor(w1, 2) );
|
BOOST_REQUIRE( hbox->setStretchFactor(w1, 2) );
|
||||||
BOOST_REQUIRE( hbox.setStretchFactor(w2, 3) );
|
BOOST_REQUIRE( hbox->setStretchFactor(w2, 3) );
|
||||||
BOOST_CHECK_EQUAL(hbox.stretch(0), 2);
|
BOOST_CHECK_EQUAL(hbox->stretch(0), 2);
|
||||||
BOOST_CHECK_EQUAL(hbox.stretch(1), 3);
|
BOOST_CHECK_EQUAL(hbox->stretch(1), 3);
|
||||||
|
|
||||||
hbox.removeItem(w1);
|
hbox->removeItem(w1);
|
||||||
|
|
||||||
BOOST_CHECK( !hbox.setStretchFactor(w1, 0) );
|
BOOST_CHECK( !hbox->setStretchFactor(w1, 0) );
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
@@ -295,35 +336,203 @@ BOOST_AUTO_TEST_CASE( vertical_layout)
|
|||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
BOOST_AUTO_TEST_CASE( boxlayout_insert_remove )
|
BOOST_AUTO_TEST_CASE( boxlayout_insert_remove )
|
||||||
{
|
{
|
||||||
sc::HBoxLayout hbox;
|
sc::BoxLayoutRef hbox( new sc::HBoxLayout );
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(hbox.count(), 0);
|
BOOST_CHECK_EQUAL(hbox->count(), 0);
|
||||||
BOOST_CHECK(!hbox.itemAt(0));
|
BOOST_CHECK(!hbox->itemAt(0));
|
||||||
BOOST_CHECK(!hbox.takeAt(0));
|
BOOST_CHECK(!hbox->takeAt(0));
|
||||||
|
|
||||||
TestWidgetRef w1( new TestWidget( SGVec2i(16, 16),
|
TestWidgetRef w1( new TestWidget( SGVec2i(16, 16),
|
||||||
SGVec2i(32, 32),
|
SGVec2i(32, 32),
|
||||||
SGVec2i(9999, 32) ) ),
|
SGVec2i(9999, 32) ) ),
|
||||||
w2( new TestWidget(*w1) );
|
w2( new TestWidget(*w1) );
|
||||||
|
|
||||||
hbox.addItem(w1);
|
hbox->addItem(w1);
|
||||||
BOOST_CHECK_EQUAL(hbox.count(), 1);
|
BOOST_CHECK_EQUAL(hbox->count(), 1);
|
||||||
BOOST_CHECK_EQUAL(hbox.itemAt(0), w1);
|
BOOST_CHECK_EQUAL(hbox->itemAt(0), w1);
|
||||||
|
BOOST_CHECK_EQUAL(w1->getParent(), hbox);
|
||||||
|
|
||||||
hbox.insertItem(0, w2);
|
hbox->insertItem(0, w2);
|
||||||
BOOST_CHECK_EQUAL(hbox.count(), 2);
|
BOOST_CHECK_EQUAL(hbox->count(), 2);
|
||||||
BOOST_CHECK_EQUAL(hbox.itemAt(0), w2);
|
BOOST_CHECK_EQUAL(hbox->itemAt(0), w2);
|
||||||
BOOST_CHECK_EQUAL(hbox.itemAt(1), w1);
|
BOOST_CHECK_EQUAL(hbox->itemAt(1), w1);
|
||||||
|
BOOST_CHECK_EQUAL(w2->getParent(), hbox);
|
||||||
|
|
||||||
hbox.removeItem(w2);
|
hbox->removeItem(w2);
|
||||||
BOOST_CHECK_EQUAL(hbox.count(), 1);
|
BOOST_CHECK_EQUAL(hbox->count(), 1);
|
||||||
BOOST_CHECK_EQUAL(hbox.itemAt(0), w1);
|
BOOST_CHECK_EQUAL(hbox->itemAt(0), w1);
|
||||||
|
BOOST_CHECK( !w2->getParent() );
|
||||||
|
|
||||||
hbox.addItem(w2);
|
hbox->addItem(w2);
|
||||||
BOOST_CHECK_EQUAL(hbox.count(), 2);
|
BOOST_CHECK_EQUAL(hbox->count(), 2);
|
||||||
|
BOOST_CHECK_EQUAL(w2->getParent(), hbox);
|
||||||
|
|
||||||
hbox.clear();
|
hbox->clear();
|
||||||
BOOST_CHECK_EQUAL(hbox.count(), 0);
|
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_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 )
|
BOOST_AUTO_TEST_CASE( nasal_widget )
|
||||||
{
|
{
|
||||||
naContext c = naNewContext();
|
nasal::Context c;
|
||||||
naRef me = naNewHash(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)
|
// Default layout sizes (no user set values)
|
||||||
BOOST_CHECK_EQUAL(w->minimumSize(), SGVec2i(16, 16));
|
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->sizeHint(), SGVec2i(3, 22));
|
||||||
BOOST_CHECK_EQUAL(w->maximumSize(), SGVec2i(4, 23));
|
BOOST_CHECK_EQUAL(w->maximumSize(), SGVec2i(4, 23));
|
||||||
|
|
||||||
naFreeContext(c);
|
w->setVisible(false);
|
||||||
|
BOOST_CHECK_EQUAL(w->geometry(), SGRecti(0, 0, -1, -1));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,6 +27,8 @@
|
|||||||
#include <simgear/threads/SGThread.hxx>
|
#include <simgear/threads/SGThread.hxx>
|
||||||
#include <simgear/threads/SGGuard.hxx>
|
#include <simgear/threads/SGGuard.hxx>
|
||||||
|
|
||||||
|
#include <cstdlib> // for malloc
|
||||||
|
|
||||||
namespace simgear
|
namespace simgear
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|||||||
@@ -37,7 +37,7 @@
|
|||||||
* Build a new OSG object from osgParticle.
|
* Build a new OSG object from osgParticle.
|
||||||
*/
|
*/
|
||||||
SGPrecipitation::SGPrecipitation() :
|
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;
|
_precipitationEffect = new osgParticle::PrecipitationEffect;
|
||||||
}
|
}
|
||||||
@@ -47,6 +47,11 @@ void SGPrecipitation::setEnabled( bool value )
|
|||||||
_enabled = value;
|
_enabled = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SGPrecipitation::setDropletExternal( bool value )
|
||||||
|
{
|
||||||
|
_droplet_external = value;
|
||||||
|
}
|
||||||
|
|
||||||
bool SGPrecipitation::getEnabled() const
|
bool SGPrecipitation::getEnabled() const
|
||||||
{
|
{
|
||||||
return _enabled;
|
return _enabled;
|
||||||
@@ -119,6 +124,55 @@ void SGPrecipitation::setRainIntensity(float intensity)
|
|||||||
this->_rain_intensity = 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
|
* @brief Freeze the rain to snow
|
||||||
@@ -129,7 +183,13 @@ void SGPrecipitation::setRainIntensity(float intensity)
|
|||||||
*/
|
*/
|
||||||
void SGPrecipitation::setFreezing(bool freeze)
|
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;
|
this->_freeze = freeze;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -169,34 +229,74 @@ void SGPrecipitation::setWindProperty(double heading, double speed)
|
|||||||
bool SGPrecipitation::update(void)
|
bool SGPrecipitation::update(void)
|
||||||
{
|
{
|
||||||
if (this->_freeze) {
|
if (this->_freeze) {
|
||||||
if (this->_rain_intensity > 0)
|
if (this->_rain_intensity > 0) {
|
||||||
this->_snow_intensity = this->_rain_intensity;
|
this->_snow_intensity = this->_rain_intensity;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (_enabled && this->_snow_intensity > 0) {
|
if (_enabled && this->_snow_intensity > 0) {
|
||||||
_precipitationEffect->setWind(_wind_vec);
|
_precipitationEffect->setWind(_wind_vec);
|
||||||
_precipitationEffect->setParticleSpeed( -0.75f - 0.25f*_snow_intensity);
|
|
||||||
|
|
||||||
_precipitationEffect->setParticleSize(0.02f + 0.03f*_snow_intensity);
|
|
||||||
|
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);
|
_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->setCellSize(osg::Vec3(5.0f / (0.25f+_snow_intensity), 5.0f / (0.25f+_snow_intensity), 5.0f));
|
||||||
|
|
||||||
_precipitationEffect->setNearTransition(25.f);
|
_precipitationEffect->setNearTransition(25.f);
|
||||||
_precipitationEffect->setFarTransition(100.0f - 60.0f*sqrtf(_snow_intensity));
|
_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) {
|
} else if (_enabled && this->_rain_intensity > 0) {
|
||||||
_precipitationEffect->setWind(_wind_vec);
|
|
||||||
_precipitationEffect->setParticleSpeed( -2.0f + -5.0f*_rain_intensity);
|
|
||||||
|
|
||||||
|
_precipitationEffect->setWind(_wind_vec);
|
||||||
|
|
||||||
|
|
||||||
|
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->setParticleSize(0.01 + 0.02*_rain_intensity);
|
||||||
|
_precipitationEffect->setParticleSpeed( -2.0f + -5.0f*_rain_intensity);
|
||||||
|
}
|
||||||
|
|
||||||
_precipitationEffect->setMaximumParticleDensity(_rain_intensity * 7.5f);
|
_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->setCellSize(osg::Vec3(5.0f / (0.25f+_rain_intensity), 5.0f / (0.25f+_rain_intensity), 5.0f));
|
||||||
|
|
||||||
_precipitationEffect->setNearTransition(25.f);
|
_precipitationEffect->setNearTransition(25.f);
|
||||||
_precipitationEffect->setFarTransition(100.0f - 60.0f*sqrtf(_rain_intensity));
|
_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 {
|
} else {
|
||||||
_precipitationEffect->snow(0);
|
_precipitationEffect->snow(0);
|
||||||
_precipitationEffect->rain(0);
|
_precipitationEffect->rain(0);
|
||||||
|
|||||||
@@ -37,10 +37,14 @@ class SGPrecipitation : public osg::Referenced
|
|||||||
private:
|
private:
|
||||||
bool _freeze;
|
bool _freeze;
|
||||||
bool _enabled;
|
bool _enabled;
|
||||||
|
bool _droplet_external;
|
||||||
|
|
||||||
float _snow_intensity;
|
float _snow_intensity;
|
||||||
float _rain_intensity;
|
float _rain_intensity;
|
||||||
float _clip_distance;
|
float _clip_distance;
|
||||||
|
float _rain_droplet_size;
|
||||||
|
float _snow_flake_size;
|
||||||
|
float _illumination;
|
||||||
|
|
||||||
osg::Vec3 _wind_vec;
|
osg::Vec3 _wind_vec;
|
||||||
|
|
||||||
@@ -54,8 +58,13 @@ public:
|
|||||||
|
|
||||||
void setWindProperty(double, double);
|
void setWindProperty(double, double);
|
||||||
void setFreezing(bool);
|
void setFreezing(bool);
|
||||||
|
void setDropletExternal(bool);
|
||||||
void setRainIntensity(float);
|
void setRainIntensity(float);
|
||||||
void setSnowIntensity(float);
|
void setSnowIntensity(float);
|
||||||
|
void setRainDropletSize(float);
|
||||||
|
void setSnowFlakeSize(float);
|
||||||
|
void setIllumination(float);
|
||||||
|
void setClipDistance(float);
|
||||||
|
|
||||||
void setEnabled( bool );
|
void setEnabled( bool );
|
||||||
bool getEnabled() const;
|
bool getEnabled() const;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
///@file HTTP request writing response to a file.
|
///@file
|
||||||
//
|
//
|
||||||
// Copyright (C) 2013 Thomas Geymayer <tomgey@gmail.com>
|
// Copyright (C) 2013 Thomas Geymayer <tomgey@gmail.com>
|
||||||
//
|
//
|
||||||
@@ -27,6 +27,9 @@ namespace simgear
|
|||||||
namespace HTTP
|
namespace HTTP
|
||||||
{
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* HTTP request writing response to a file.
|
||||||
|
*/
|
||||||
class FileRequest:
|
class FileRequest:
|
||||||
public Request
|
public Request
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
///@file HTTP request keeping response in memory.
|
///@file
|
||||||
//
|
//
|
||||||
// Copyright (C) 2013 Thomas Geymayer <tomgey@gmail.com>
|
// Copyright (C) 2013 Thomas Geymayer <tomgey@gmail.com>
|
||||||
//
|
//
|
||||||
@@ -27,6 +27,9 @@ namespace simgear
|
|||||||
namespace HTTP
|
namespace HTTP
|
||||||
{
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* HTTP request keeping response in memory.
|
||||||
|
*/
|
||||||
class MemoryRequest:
|
class MemoryRequest:
|
||||||
public Request
|
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 "HTTPRequest.hxx"
|
||||||
|
|
||||||
#include <simgear/compiler.h>
|
#include <simgear/compiler.h>
|
||||||
|
|||||||
@@ -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
|
#ifndef SG_HTTP_REQUEST_HXX
|
||||||
#define SG_HTTP_REQUEST_HXX
|
#define SG_HTTP_REQUEST_HXX
|
||||||
|
|
||||||
@@ -18,6 +37,9 @@ namespace simgear
|
|||||||
namespace HTTP
|
namespace HTTP
|
||||||
{
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base class for HTTP request (and answer).
|
||||||
|
*/
|
||||||
class Request:
|
class Request:
|
||||||
public SGReferenced
|
public SGReferenced
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -274,6 +274,15 @@ static void read_indices(char* buffer,
|
|||||||
if (vaMask & SG_VA_FLOAT_3) vas[7].push_back(*src++);
|
if (vaMask & SG_VA_FLOAT_3) vas[7].push_back(*src++);
|
||||||
}
|
}
|
||||||
} // of elements in the index
|
} // 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>
|
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 );
|
read_indices<uint16_t>(ptr, nbytes, idx_mask, vertex_attrib_mask, vs, ns, cs, tcs, vas );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fix for WS2.0 - ignore zero area triangles
|
||||||
|
if ( !vs.empty() ) {
|
||||||
vertices.push_back( vs );
|
vertices.push_back( vs );
|
||||||
normals.push_back( ns );
|
normals.push_back( ns );
|
||||||
colors.push_back( cs );
|
colors.push_back( cs );
|
||||||
texCoords.push_back( tcs );
|
texCoords.push_back( tcs );
|
||||||
vertexAttribs.push_back( vas );
|
vertexAttribs.push_back( vas );
|
||||||
materials.push_back( material );
|
materials.push_back( material );
|
||||||
|
}
|
||||||
} // of element iteration
|
} // of element iteration
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -44,9 +44,8 @@
|
|||||||
|
|
||||||
#include "sg_file.hxx"
|
#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)
|
: file_name(file), fp(-1), eof_flag(true), repeat(repeat_), iteration(0)
|
||||||
{
|
{
|
||||||
set_type( sgFileType );
|
set_type( sgFileType );
|
||||||
|
|||||||
+14
-23
@@ -1,37 +1,31 @@
|
|||||||
/** \file sg_file.hxx
|
///@file
|
||||||
* File I/O routines.
|
/// File I/O routines.
|
||||||
*/
|
//
|
||||||
|
|
||||||
// Written by Curtis Olson, started November 1999.
|
// Written by Curtis Olson, started November 1999.
|
||||||
//
|
//
|
||||||
// Copyright (C) 1999 Curtis L. Olson - http://www.flightgear.org/~curt
|
// Copyright (C) 1999 Curtis L. Olson - http://www.flightgear.org/~curt
|
||||||
//
|
//
|
||||||
// This program is free software; you can redistribute it and/or
|
// This library is free software; you can redistribute it and/or
|
||||||
// modify it under the terms of the GNU General Public License as
|
// modify it under the terms of the GNU Library General Public
|
||||||
// published by the Free Software Foundation; either version 2 of the
|
// License as published by the Free Software Foundation; either
|
||||||
// License, or (at your option) any later version.
|
// 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
|
// This library is distributed in the hope that it will be useful,
|
||||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
// 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
|
// You should have received a copy of the GNU Library General Public
|
||||||
// along with this program; if not, write to the Free Software
|
// License along with this library; if not, write to the Free Software
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
//
|
|
||||||
// $Id$
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef _SG_FILE_HXX
|
#ifndef _SG_FILE_HXX
|
||||||
#define _SG_FILE_HXX
|
#define _SG_FILE_HXX
|
||||||
|
|
||||||
#include <simgear/compiler.h>
|
#include <simgear/compiler.h>
|
||||||
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
#include "iochannel.hxx"
|
#include "iochannel.hxx"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A file I/O class based on SGIOChannel.
|
* A file I/O class based on SGIOChannel.
|
||||||
@@ -91,7 +85,4 @@ public:
|
|||||||
virtual bool eof() const { return eof_flag; };
|
virtual bool eof() const { return eof_flag; };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
#endif // _SG_FILE_HXX
|
#endif // _SG_FILE_HXX
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -97,9 +97,28 @@ void compareTexCoords(const SGBinObject& rd, const std::vector<SGVec2f>& b)
|
|||||||
int_list make_tri(int maxIndex)
|
int_list make_tri(int maxIndex)
|
||||||
{
|
{
|
||||||
int_list r;
|
int_list r;
|
||||||
r.push_back(random() % maxIndex);
|
int a, b, c;
|
||||||
r.push_back(random() % maxIndex);
|
|
||||||
r.push_back(random() % maxIndex);
|
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;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -41,6 +41,30 @@ public:
|
|||||||
static T clip(const T& a, const T& _min, const T& _max)
|
static T clip(const T& a, const T& _min, const T& _max)
|
||||||
{ return max(_min, min(_max, a)); }
|
{ 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
|
* Seek a variable towards a target value with given rate and timestep
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -196,6 +196,17 @@ SGVec2<T>
|
|||||||
max(S s, const SGVec2<T>& v)
|
max(S s, const SGVec2<T>& v)
|
||||||
{ return SGVec2<T>(SGMisc<T>::max(s, v(0)), SGMisc<T>::max(s, v(1))); }
|
{ 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
|
/// Scalar dot product
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline
|
inline
|
||||||
|
|||||||
@@ -288,6 +288,18 @@ max(S s, const SGVec3<T>& v)
|
|||||||
SGMisc<T>::max(s, v(2)));
|
SGMisc<T>::max(s, v(2)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Add two vectors taking care of (integer) overflows. The values are limited
|
||||||
|
/// to the respective minimum and maximum values.
|
||||||
|
template<class T>
|
||||||
|
SGVec3<T> addClipOverflow(SGVec3<T> const& lhs, SGVec3<T> const& rhs)
|
||||||
|
{
|
||||||
|
return SGVec3<T>(
|
||||||
|
SGMisc<T>::addClipOverflow(lhs.x(), rhs.x()),
|
||||||
|
SGMisc<T>::addClipOverflow(lhs.y(), rhs.y()),
|
||||||
|
SGMisc<T>::addClipOverflow(lhs.z(), rhs.z())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/// Scalar dot product
|
/// Scalar dot product
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline
|
inline
|
||||||
|
|||||||
@@ -244,6 +244,19 @@ max(S s, const SGVec4<T>& v)
|
|||||||
SGMisc<T>::max(s, v(3)));
|
SGMisc<T>::max(s, v(3)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Add two vectors taking care of (integer) overflows. The values are limited
|
||||||
|
/// to the respective minimum and maximum values.
|
||||||
|
template<class T>
|
||||||
|
SGVec4<T> addClipOverflow(SGVec4<T> const& lhs, SGVec4<T> const& rhs)
|
||||||
|
{
|
||||||
|
return SGVec4<T>(
|
||||||
|
SGMisc<T>::addClipOverflow(lhs.x(), rhs.x()),
|
||||||
|
SGMisc<T>::addClipOverflow(lhs.y(), rhs.y()),
|
||||||
|
SGMisc<T>::addClipOverflow(lhs.z(), rhs.z()),
|
||||||
|
SGMisc<T>::addClipOverflow(lhs.w(), rhs.w())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/// Scalar dot product
|
/// Scalar dot product
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline
|
inline
|
||||||
|
|||||||
@@ -36,8 +36,6 @@
|
|||||||
|
|
||||||
#include "interpolater.hxx"
|
#include "interpolater.hxx"
|
||||||
|
|
||||||
using std::string;
|
|
||||||
|
|
||||||
// Constructor -- starts with an empty table.
|
// Constructor -- starts with an empty table.
|
||||||
SGInterpTable::SGInterpTable()
|
SGInterpTable::SGInterpTable()
|
||||||
{
|
{
|
||||||
@@ -55,7 +53,7 @@ SGInterpTable::SGInterpTable(const SGPropertyNode* interpolation)
|
|||||||
|
|
||||||
// Constructor -- loads the interpolation table from the specified
|
// Constructor -- loads the interpolation table from the specified
|
||||||
// file
|
// file
|
||||||
SGInterpTable::SGInterpTable( const string& file )
|
SGInterpTable::SGInterpTable( const std::string& file )
|
||||||
{
|
{
|
||||||
SG_LOG( SG_MATH, SG_INFO, "Initializing Interpolator for " << file );
|
SG_LOG( SG_MATH, SG_INFO, "Initializing Interpolator for " << file );
|
||||||
|
|
||||||
|
|||||||
@@ -28,7 +28,8 @@ SGPath appleSpecialFolder(int dirType, int domainMask, const SGPath& def)
|
|||||||
{
|
{
|
||||||
CocoaAutoreleasePool ap;
|
CocoaAutoreleasePool ap;
|
||||||
NSFileManager* fm = [NSFileManager defaultManager];
|
NSFileManager* fm = [NSFileManager defaultManager];
|
||||||
NSURL* pathUrl = [fm URLForDirectory:dirType
|
NSSearchPathDirectory d = static_cast<NSSearchPathDirectory>(dirType);
|
||||||
|
NSURL* pathUrl = [fm URLForDirectory:d
|
||||||
inDomain:domainMask
|
inDomain:domainMask
|
||||||
appropriateForURL:Nil
|
appropriateForURL:Nil
|
||||||
create:YES
|
create:YES
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
///@file Parse and represent SVG preserveAspectRatio attribute
|
///@file
|
||||||
|
/// Parse and represent SVG preserveAspectRatio attribute.
|
||||||
//
|
//
|
||||||
// Copyright (C) 2014 Thomas Geymayer <tomgey@gmail.com>
|
// Copyright (C) 2014 Thomas Geymayer <tomgey@gmail.com>
|
||||||
//
|
//
|
||||||
@@ -53,6 +54,7 @@ namespace simgear
|
|||||||
|
|
||||||
bool operator==(const SVGpreserveAspectRatio& rhs) const;
|
bool operator==(const SVGpreserveAspectRatio& rhs) const;
|
||||||
|
|
||||||
|
/// Parse preserveAspectRatio from string.
|
||||||
static SVGpreserveAspectRatio parse(const std::string& str);
|
static SVGpreserveAspectRatio parse(const std::string& str);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
///@file Really simple markdown parser
|
///@file
|
||||||
|
/// Really simple markdown parser.
|
||||||
//
|
//
|
||||||
// Copyright (C) 2014 Thomas Geymayer <tomgey@gmail.com>
|
// Copyright (C) 2014 Thomas Geymayer <tomgey@gmail.com>
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -27,7 +27,6 @@
|
|||||||
|
|
||||||
#include "sgstream.hxx"
|
#include "sgstream.hxx"
|
||||||
|
|
||||||
using std::string;
|
|
||||||
using std::istream;
|
using std::istream;
|
||||||
using std::ostream;
|
using std::ostream;
|
||||||
|
|
||||||
@@ -40,7 +39,7 @@ sg_gzifstream::sg_gzifstream()
|
|||||||
//
|
//
|
||||||
// Open a possibly gzipped file for reading.
|
// Open a possibly gzipped file for reading.
|
||||||
//
|
//
|
||||||
sg_gzifstream::sg_gzifstream( const string& name, ios_openmode io_mode )
|
sg_gzifstream::sg_gzifstream( const std::string& name, ios_openmode io_mode )
|
||||||
: istream(&gzbuf)
|
: istream(&gzbuf)
|
||||||
{
|
{
|
||||||
this->open( name, io_mode );
|
this->open( name, io_mode );
|
||||||
@@ -65,12 +64,12 @@ sg_gzifstream::sg_gzifstream( int fd, ios_openmode io_mode )
|
|||||||
// then append ".gz" and try again.
|
// then append ".gz" and try again.
|
||||||
//
|
//
|
||||||
void
|
void
|
||||||
sg_gzifstream::open( const string& name, ios_openmode io_mode )
|
sg_gzifstream::open( const std::string& name, ios_openmode io_mode )
|
||||||
{
|
{
|
||||||
gzbuf.open( name.c_str(), io_mode );
|
gzbuf.open( name.c_str(), io_mode );
|
||||||
if ( ! gzbuf.is_open() )
|
if ( ! gzbuf.is_open() )
|
||||||
{
|
{
|
||||||
string s = name;
|
std::string s = name;
|
||||||
if ( s.substr( s.length() - 3, 3 ) == ".gz" )
|
if ( s.substr( s.length() - 3, 3 ) == ".gz" )
|
||||||
{
|
{
|
||||||
// remove ".gz" suffix
|
// remove ".gz" suffix
|
||||||
@@ -160,7 +159,7 @@ sg_gzofstream::sg_gzofstream()
|
|||||||
//
|
//
|
||||||
// Open a file for gzipped writing.
|
// Open a file for gzipped writing.
|
||||||
//
|
//
|
||||||
sg_gzofstream::sg_gzofstream( const string& name, ios_openmode io_mode )
|
sg_gzofstream::sg_gzofstream( const std::string& name, ios_openmode io_mode )
|
||||||
: ostream(&gzbuf)
|
: ostream(&gzbuf)
|
||||||
{
|
{
|
||||||
this->open( name, io_mode );
|
this->open( name, io_mode );
|
||||||
@@ -181,7 +180,7 @@ sg_gzofstream::sg_gzofstream( int fd, ios_openmode io_mode )
|
|||||||
// Open a file for gzipped writing.
|
// Open a file for gzipped writing.
|
||||||
//
|
//
|
||||||
void
|
void
|
||||||
sg_gzofstream::open( const string& name, ios_openmode io_mode )
|
sg_gzofstream::open( const std::string& name, ios_openmode io_mode )
|
||||||
{
|
{
|
||||||
gzbuf.open( name.c_str(), io_mode );
|
gzbuf.open( name.c_str(), io_mode );
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ include (SimGearComponent)
|
|||||||
set(HEADERS
|
set(HEADERS
|
||||||
Ghost.hxx
|
Ghost.hxx
|
||||||
NasalCallContext.hxx
|
NasalCallContext.hxx
|
||||||
|
NasalContext.hxx
|
||||||
NasalHash.hxx
|
NasalHash.hxx
|
||||||
NasalObject.hxx
|
NasalObject.hxx
|
||||||
NasalObjectHolder.hxx
|
NasalObjectHolder.hxx
|
||||||
@@ -16,11 +17,13 @@ set(DETAIL_HEADERS
|
|||||||
detail/from_nasal_helper.hxx
|
detail/from_nasal_helper.hxx
|
||||||
detail/functor_templates.hxx
|
detail/functor_templates.hxx
|
||||||
detail/nasal_traits.hxx
|
detail/nasal_traits.hxx
|
||||||
|
detail/NasalObject_callMethod_templates.hxx
|
||||||
detail/to_nasal_helper.hxx
|
detail/to_nasal_helper.hxx
|
||||||
)
|
)
|
||||||
|
|
||||||
set(SOURCES
|
set(SOURCES
|
||||||
Ghost.cxx
|
Ghost.cxx
|
||||||
|
NasalContext.cxx
|
||||||
NasalHash.cxx
|
NasalHash.cxx
|
||||||
NasalString.cxx
|
NasalString.cxx
|
||||||
NasalObject.cxx
|
NasalObject.cxx
|
||||||
@@ -31,18 +34,22 @@ set(SOURCES
|
|||||||
simgear_component(nasal/cppbind nasal/cppbind "${SOURCES}" "${HEADERS}")
|
simgear_component(nasal/cppbind nasal/cppbind "${SOURCES}" "${HEADERS}")
|
||||||
simgear_component(nasal/cppbind/detail nasal/cppbind/detail "" "${DETAIL_HEADERS}")
|
simgear_component(nasal/cppbind/detail nasal/cppbind/detail "" "${DETAIL_HEADERS}")
|
||||||
|
|
||||||
if(ENABLE_TESTS)
|
|
||||||
add_executable(test_cppbind cppbind_test.cxx)
|
|
||||||
add_test(cppbind ${EXECUTABLE_OUTPUT_PATH}/test_cppbind)
|
|
||||||
target_link_libraries(test_cppbind ${TEST_LIBS})
|
|
||||||
endif(ENABLE_TESTS)
|
|
||||||
|
|
||||||
add_boost_test(cppbind_ghost
|
add_boost_test(cppbind_ghost
|
||||||
SOURCES cppbind_test_ghost.cxx
|
SOURCES test/cppbind_test_ghost.cxx
|
||||||
|
LIBRARIES ${TEST_LIBS}
|
||||||
|
)
|
||||||
|
|
||||||
|
add_boost_test(cppbind_misc
|
||||||
|
SOURCES test/cppbind_test.cxx
|
||||||
|
LIBRARIES ${TEST_LIBS}
|
||||||
|
)
|
||||||
|
|
||||||
|
add_boost_test(nasal_gc_test
|
||||||
|
SOURCES test/nasal_gc_test.cxx
|
||||||
LIBRARIES ${TEST_LIBS}
|
LIBRARIES ${TEST_LIBS}
|
||||||
)
|
)
|
||||||
|
|
||||||
add_boost_test(nasal_num
|
add_boost_test(nasal_num
|
||||||
SOURCES nasal_num_test.cxx
|
SOURCES test/nasal_num_test.cxx
|
||||||
LIBRARIES ${TEST_LIBS}
|
LIBRARIES ${TEST_LIBS}
|
||||||
)
|
)
|
||||||
@@ -33,7 +33,7 @@ namespace nasal
|
|||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
//--------------------------------------------------------------------------
|
||||||
bool GhostMetadata::isBaseOf(naGhostType* ghost_type, bool& is_weak) const
|
bool GhostMetadata::isInstance(naGhostType* ghost_type, bool& is_weak) const
|
||||||
{
|
{
|
||||||
if( ghost_type == _ghost_type_strong_ptr )
|
if( ghost_type == _ghost_type_strong_ptr )
|
||||||
{
|
{
|
||||||
@@ -47,14 +47,6 @@ namespace nasal
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
for( DerivedList::const_iterator derived = _derived_classes.begin();
|
|
||||||
derived != _derived_classes.end();
|
|
||||||
++derived )
|
|
||||||
{
|
|
||||||
if( (*derived)->isBaseOf(ghost_type, is_weak) )
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -74,7 +66,6 @@ namespace nasal
|
|||||||
void GhostMetadata::addDerived(const GhostMetadata* derived)
|
void GhostMetadata::addDerived(const GhostMetadata* derived)
|
||||||
{
|
{
|
||||||
assert(derived);
|
assert(derived);
|
||||||
_derived_classes.push_back(derived);
|
|
||||||
|
|
||||||
SG_LOG
|
SG_LOG
|
||||||
(
|
(
|
||||||
|
|||||||
+167
-66
@@ -78,6 +78,11 @@ get_pointer(T ptr)
|
|||||||
// The old version of g++ used on Jenkins (16.11.2012) only compiles
|
// The old version of g++ used on Jenkins (16.11.2012) only compiles
|
||||||
// this version.
|
// this version.
|
||||||
# define SG_GET_TEMPLATE_MEMBER(type, member) &member
|
# define SG_GET_TEMPLATE_MEMBER(type, member) &member
|
||||||
|
|
||||||
|
// With old g++ on Jenkins (21.07.2014), ADL for static_pointer_cast does not
|
||||||
|
// work.
|
||||||
|
using boost::static_pointer_cast;
|
||||||
|
using osg::static_pointer_cast;
|
||||||
#else
|
#else
|
||||||
// VS (2008, 2010, ... ?) only allow this version.
|
// VS (2008, 2010, ... ?) only allow this version.
|
||||||
# define SG_GET_TEMPLATE_MEMBER(type, member) &type::template member
|
# define SG_GET_TEMPLATE_MEMBER(type, member) &type::template member
|
||||||
@@ -107,17 +112,14 @@ namespace nasal
|
|||||||
*/
|
*/
|
||||||
void addNasalBase(const naRef& parent);
|
void addNasalBase(const naRef& parent);
|
||||||
|
|
||||||
bool isBaseOf(naGhostType* ghost_type, bool& is_weak) const;
|
bool isInstance(naGhostType* ghost_type, bool& is_weak) const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
typedef std::vector<const GhostMetadata*> DerivedList;
|
|
||||||
|
|
||||||
const std::string _name_strong,
|
const std::string _name_strong,
|
||||||
_name_weak;
|
_name_weak;
|
||||||
const naGhostType *_ghost_type_strong_ptr,
|
const naGhostType *_ghost_type_strong_ptr,
|
||||||
*_ghost_type_weak_ptr;
|
*_ghost_type_weak_ptr;
|
||||||
DerivedList _derived_classes;
|
|
||||||
std::vector<naRef> _parents;
|
std::vector<naRef> _parents;
|
||||||
|
|
||||||
GhostMetadata( const std::string& name,
|
GhostMetadata( const std::string& name,
|
||||||
@@ -307,7 +309,7 @@ namespace nasal
|
|||||||
|
|
||||||
// Keep reference for duration of call to prevent expiring
|
// Keep reference for duration of call to prevent expiring
|
||||||
// TODO not needed for strong referenced ghost
|
// TODO not needed for strong referenced ghost
|
||||||
strong_ref ref = fromNasal<strong_ref>(c, me);
|
strong_ref ref = fromNasal(c, me);
|
||||||
if( !ref )
|
if( !ref )
|
||||||
{
|
{
|
||||||
naGhostType* ghost_type = naGhost_type(me);
|
naGhostType* ghost_type = naGhost_type(me);
|
||||||
@@ -325,7 +327,7 @@ namespace nasal
|
|||||||
return holder->_method
|
return holder->_method
|
||||||
(
|
(
|
||||||
*get_pointer(ref),
|
*get_pointer(ref),
|
||||||
CallContext(c, argc, args)
|
CallContext(c, me, argc, args)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
catch(const std::exception& ex)
|
catch(const std::exception& ex)
|
||||||
@@ -416,10 +418,13 @@ namespace nasal
|
|||||||
boost::is_base_of<typename BaseGhost::raw_type, raw_type>::value
|
boost::is_base_of<typename BaseGhost::raw_type, raw_type>::value
|
||||||
));
|
));
|
||||||
|
|
||||||
|
typedef typename BaseGhost::strong_ref base_ref;
|
||||||
|
|
||||||
BaseGhost* base = BaseGhost::getSingletonPtr();
|
BaseGhost* base = BaseGhost::getSingletonPtr();
|
||||||
base->addDerived(
|
base->addDerived(
|
||||||
this,
|
this,
|
||||||
SG_GET_TEMPLATE_MEMBER(Ghost, getTypeFor<BaseGhost>)
|
SG_GET_TEMPLATE_MEMBER(Ghost, toNasal<BaseGhost>),
|
||||||
|
SG_GET_TEMPLATE_MEMBER(Ghost, fromNasalWithCast<base_ref>)
|
||||||
);
|
);
|
||||||
|
|
||||||
// Replace any getter that is not available in the current class.
|
// Replace any getter that is not available in the current class.
|
||||||
@@ -809,7 +814,7 @@ namespace nasal
|
|||||||
makeGhost(naContext c, RefType const& ref_ptr)
|
makeGhost(naContext c, RefType const& ref_ptr)
|
||||||
{
|
{
|
||||||
strong_ref ref(ref_ptr);
|
strong_ref ref(ref_ptr);
|
||||||
raw_type* ptr = get_pointer(ref_ptr);
|
raw_type* ptr = get_pointer(ref);
|
||||||
if( !ptr )
|
if( !ptr )
|
||||||
return naNil();
|
return naNil();
|
||||||
|
|
||||||
@@ -817,15 +822,11 @@ namespace nasal
|
|||||||
// will then be hold be a new shared pointer. We therefore have to
|
// will then be hold be a new shared pointer. We therefore have to
|
||||||
// check for the dynamic type of the object as it might differ from
|
// check for the dynamic type of the object as it might differ from
|
||||||
// the passed static type.
|
// the passed static type.
|
||||||
naGhostType* ghost_type =
|
return toNasal<Ghost>(
|
||||||
getTypeFor<Ghost>(ptr, shared_ptr_traits<RefType>::is_strong::value);
|
c,
|
||||||
|
ref,
|
||||||
if( !ghost_type )
|
shared_ptr_traits<RefType>::is_strong::value
|
||||||
return naNil();
|
);
|
||||||
|
|
||||||
return naNewGhost2( c,
|
|
||||||
ghost_type,
|
|
||||||
shared_ptr_storage<RefType>::ref(ref_ptr) );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -833,25 +834,36 @@ namespace nasal
|
|||||||
* Nasal objects has to be derived class of the target class (Either
|
* Nasal objects has to be derived class of the target class (Either
|
||||||
* derived in C++ or in Nasal using a 'parents' vector)
|
* derived in C++ or in Nasal using a 'parents' vector)
|
||||||
*/
|
*/
|
||||||
template<class Type>
|
static strong_ref fromNasal(naContext c, naRef me)
|
||||||
static Type fromNasal(naContext c, naRef me)
|
|
||||||
{
|
{
|
||||||
|
naGhostType* ghost_type = naGhost_type(me);
|
||||||
|
if( ghost_type )
|
||||||
|
{
|
||||||
|
// Check if we got an instance of this class
|
||||||
bool is_weak = false;
|
bool is_weak = false;
|
||||||
|
if( isInstance(ghost_type, is_weak) )
|
||||||
// Check if it's a ghost and if it can be converted
|
|
||||||
if( isBaseOf(naGhost_type(me), is_weak) )
|
|
||||||
{
|
{
|
||||||
void* ghost = naGhost_ptr(me);
|
return is_weak ? getPtr<strong_ref, true>(naGhost_ptr(me))
|
||||||
return is_weak ? getPtr<Type, true>(ghost)
|
: getPtr<strong_ref, false>(naGhost_ptr(me));
|
||||||
: getPtr<Type, false>(ghost);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now if it is derived from a ghost (hash with ghost in parent vector)
|
// otherwise try the derived classes
|
||||||
|
for( typename DerivedList::reverse_iterator
|
||||||
|
derived = getSingletonPtr()->_derived_types.rbegin();
|
||||||
|
derived != getSingletonPtr()->_derived_types.rend();
|
||||||
|
++derived )
|
||||||
|
{
|
||||||
|
strong_ref ref = (derived->from_nasal)(c, me);
|
||||||
|
|
||||||
|
if( get_pointer(ref) )
|
||||||
|
return ref;
|
||||||
|
}
|
||||||
|
}
|
||||||
else if( naIsHash(me) )
|
else if( naIsHash(me) )
|
||||||
{
|
{
|
||||||
naRef na_parents = naHash_cget(me, const_cast<char*>("parents"));
|
naRef na_parents = naHash_cget(me, const_cast<char*>("parents"));
|
||||||
if( !naIsVector(na_parents) )
|
if( !naIsVector(na_parents) )
|
||||||
return Type();
|
return strong_ref();
|
||||||
|
|
||||||
typedef std::vector<naRef> naRefs;
|
typedef std::vector<naRef> naRefs;
|
||||||
naRefs parents = from_nasal<naRefs>(c, na_parents);
|
naRefs parents = from_nasal<naRefs>(c, na_parents);
|
||||||
@@ -859,19 +871,48 @@ namespace nasal
|
|||||||
parent != parents.end();
|
parent != parents.end();
|
||||||
++parent )
|
++parent )
|
||||||
{
|
{
|
||||||
Type ptr = fromNasal<Type>(c, *parent);
|
strong_ref ref = fromNasal(c, *parent);
|
||||||
if( get_pointer(ptr) )
|
if( get_pointer(ref) )
|
||||||
return ptr;
|
return ref;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Type();
|
return strong_ref();
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool isBaseOf(naRef obj)
|
/**
|
||||||
|
* Convert Nasal object to C++ object and check if it has the correct
|
||||||
|
* type.
|
||||||
|
*
|
||||||
|
* @see fromNasal
|
||||||
|
*/
|
||||||
|
static strong_ref fromNasalChecked(naContext c, naRef me)
|
||||||
{
|
{
|
||||||
bool is_weak;
|
strong_ref obj = fromNasal(c, me);
|
||||||
return isBaseOf(naGhost_type(obj), is_weak);
|
if( obj )
|
||||||
|
return obj;
|
||||||
|
if( naIsNil(me) )
|
||||||
|
return strong_ref();
|
||||||
|
|
||||||
|
std::string msg = "Can not convert to '"
|
||||||
|
+ getSingletonPtr()->_name_strong
|
||||||
|
+ "': ";
|
||||||
|
|
||||||
|
naGhostType* ghost_type = naGhost_type(me);
|
||||||
|
if( ghost_type )
|
||||||
|
msg += "not a derived class (or expired weak ref): "
|
||||||
|
"'" + std::string(ghost_type->name) + "'";
|
||||||
|
else if( naIsHash(me) )
|
||||||
|
{
|
||||||
|
if( !naIsVector(naHash_cget(me, const_cast<char*>("parents"))) )
|
||||||
|
msg += "missing parents vector";
|
||||||
|
else
|
||||||
|
msg += "not a derived hash";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
msg += "not an object";
|
||||||
|
|
||||||
|
throw bad_nasal_cast(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -882,21 +923,30 @@ namespace nasal
|
|||||||
static naGhostType _ghost_type_strong, //!< Stored as shared pointer
|
static naGhostType _ghost_type_strong, //!< Stored as shared pointer
|
||||||
_ghost_type_weak; //!< Stored as weak shared pointer
|
_ghost_type_weak; //!< Stored as weak shared pointer
|
||||||
|
|
||||||
typedef naGhostType* (*type_checker_t)(const raw_type*, bool);
|
typedef naRef (*to_nasal_t)(naContext, const strong_ref&, bool);
|
||||||
typedef std::vector<type_checker_t> DerivedList;
|
typedef strong_ref (*from_nasal_t)(naContext, naRef);
|
||||||
|
struct DerivedInfo
|
||||||
|
{
|
||||||
|
to_nasal_t to_nasal;
|
||||||
|
from_nasal_t from_nasal;
|
||||||
|
|
||||||
|
DerivedInfo( to_nasal_t to_nasal_func,
|
||||||
|
from_nasal_t from_nasal_func ):
|
||||||
|
to_nasal(to_nasal_func),
|
||||||
|
from_nasal(from_nasal_func)
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::vector<DerivedInfo> DerivedList;
|
||||||
DerivedList _derived_types;
|
DerivedList _derived_types;
|
||||||
|
|
||||||
static bool isBaseOf(naGhostType* ghost_type, bool& is_weak)
|
static bool isInstance(naGhostType* ghost_type, bool& is_weak)
|
||||||
{
|
{
|
||||||
if( !ghost_type || !getSingletonPtr() )
|
if( !ghost_type || !getSingletonPtr() )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return getSingletonPtr()->GhostMetadata::isBaseOf(ghost_type, is_weak);
|
return getSingletonPtr()->GhostMetadata::isInstance( ghost_type,
|
||||||
}
|
is_weak );
|
||||||
|
|
||||||
static bool isBaseOf(naRef obj, bool& is_weak)
|
|
||||||
{
|
|
||||||
return isBaseOf(naGhost_type(obj), is_weak);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class RefPtr, bool is_weak>
|
template<class RefPtr, bool is_weak>
|
||||||
@@ -945,28 +995,33 @@ namespace nasal
|
|||||||
}
|
}
|
||||||
|
|
||||||
void addDerived( const internal::GhostMetadata* derived_meta,
|
void addDerived( const internal::GhostMetadata* derived_meta,
|
||||||
type_checker_t derived_type_checker )
|
to_nasal_t to_nasal_func,
|
||||||
|
from_nasal_t from_nasal_func )
|
||||||
{
|
{
|
||||||
GhostMetadata::addDerived(derived_meta);
|
GhostMetadata::addDerived(derived_meta);
|
||||||
_derived_types.push_back(derived_type_checker);
|
_derived_types.push_back(DerivedInfo(to_nasal_func, from_nasal_func));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class BaseGhost>
|
template<class BaseGhost>
|
||||||
static
|
static
|
||||||
typename boost::enable_if
|
typename boost::enable_if
|
||||||
< boost::is_polymorphic<typename BaseGhost::raw_type>,
|
< boost::is_polymorphic<typename BaseGhost::raw_type>,
|
||||||
naGhostType*
|
naRef
|
||||||
>::type
|
>::type
|
||||||
getTypeFor(const typename BaseGhost::raw_type* base, bool strong)
|
toNasal( naContext c,
|
||||||
|
const typename BaseGhost::strong_ref& base_ref,
|
||||||
|
bool strong )
|
||||||
{
|
{
|
||||||
|
typename BaseGhost::raw_type* ptr = get_pointer(base_ref);
|
||||||
|
|
||||||
// Check first if passed pointer can by converted to instance of class
|
// Check first if passed pointer can by converted to instance of class
|
||||||
// this ghost wraps.
|
// this ghost wraps.
|
||||||
if( !boost::is_same
|
if( !boost::is_same
|
||||||
< typename BaseGhost::raw_type,
|
< typename BaseGhost::raw_type,
|
||||||
typename Ghost::raw_type
|
typename Ghost::raw_type
|
||||||
>::value
|
>::value
|
||||||
&& dynamic_cast<const typename Ghost::raw_type*>(base) != base )
|
&& dynamic_cast<const typename Ghost::raw_type*>(ptr) != ptr )
|
||||||
return 0;
|
return naNil();
|
||||||
|
|
||||||
if( !getSingletonPtr() )
|
if( !getSingletonPtr() )
|
||||||
{
|
{
|
||||||
@@ -976,45 +1031,52 @@ namespace nasal
|
|||||||
SG_INFO,
|
SG_INFO,
|
||||||
"Ghost::getTypeFor: can not get type for unregistered ghost"
|
"Ghost::getTypeFor: can not get type for unregistered ghost"
|
||||||
);
|
);
|
||||||
return 0;
|
return naNil();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
strong_ref ref =
|
||||||
|
static_pointer_cast<typename Ghost::raw_type>(base_ref);
|
||||||
|
|
||||||
// Now check if we can further downcast to one of our derived classes.
|
// Now check if we can further downcast to one of our derived classes.
|
||||||
for( typename DerivedList::reverse_iterator
|
for( typename DerivedList::reverse_iterator
|
||||||
derived = getSingletonPtr()->_derived_types.rbegin();
|
derived = getSingletonPtr()->_derived_types.rbegin();
|
||||||
derived != getSingletonPtr()->_derived_types.rend();
|
derived != getSingletonPtr()->_derived_types.rend();
|
||||||
++derived )
|
++derived )
|
||||||
{
|
{
|
||||||
naGhostType* ghost_type =
|
naRef ghost = (derived->to_nasal)(c, ref, strong);
|
||||||
(*derived)(
|
|
||||||
static_cast<const typename Ghost::raw_type*>(base),
|
|
||||||
strong
|
|
||||||
);
|
|
||||||
|
|
||||||
if( ghost_type )
|
if( !naIsNil(ghost) )
|
||||||
return ghost_type;
|
return ghost;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If base is not an instance of any derived class, this class has to
|
// If base is not an instance of any derived class, this class has to
|
||||||
// be the dynamic type.
|
// be the dynamic type.
|
||||||
return strong
|
return strong
|
||||||
? &_ghost_type_strong
|
? create<false>(c, ref)
|
||||||
: &_ghost_type_weak;
|
: create<true>(c, ref);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class BaseGhost>
|
template<class BaseGhost>
|
||||||
static
|
static
|
||||||
typename boost::disable_if
|
typename boost::disable_if
|
||||||
< boost::is_polymorphic<typename BaseGhost::raw_type>,
|
< boost::is_polymorphic<typename BaseGhost::raw_type>,
|
||||||
naGhostType*
|
naRef
|
||||||
>::type
|
>::type
|
||||||
getTypeFor(const typename BaseGhost::raw_type* base, bool strong)
|
toNasal( naContext c,
|
||||||
|
const typename BaseGhost::strong_ref& ref,
|
||||||
|
bool strong )
|
||||||
{
|
{
|
||||||
// For non polymorphic classes there is no possibility to get the actual
|
// For non polymorphic classes there is no possibility to get the actual
|
||||||
// dynamic type, therefore we can only use its static type.
|
// dynamic type, therefore we can only use its static type.
|
||||||
return strong
|
return strong
|
||||||
? &BaseGhost::_ghost_type_strong
|
? create<false>(c, ref)
|
||||||
: &BaseGhost::_ghost_type_weak;
|
: create<true>(c, ref);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Type>
|
||||||
|
static Type fromNasalWithCast(naContext c, naRef me)
|
||||||
|
{
|
||||||
|
return Type(fromNasal(c, me));
|
||||||
}
|
}
|
||||||
|
|
||||||
static Ghost* getSingletonPtr()
|
static Ghost* getSingletonPtr()
|
||||||
@@ -1176,6 +1238,45 @@ namespace nasal
|
|||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<bool is_weak>
|
||||||
|
static
|
||||||
|
typename boost::enable_if_c<
|
||||||
|
!is_weak,
|
||||||
|
naRef
|
||||||
|
>::type
|
||||||
|
create(naContext c, const strong_ref& ref_ptr)
|
||||||
|
{
|
||||||
|
typedef shared_ptr_storage<strong_ref> storage_type;
|
||||||
|
return naNewGhost2( c,
|
||||||
|
&Ghost::_ghost_type_strong,
|
||||||
|
storage_type::ref(ref_ptr) );
|
||||||
|
}
|
||||||
|
|
||||||
|
template<bool is_weak>
|
||||||
|
static
|
||||||
|
typename boost::enable_if_c<
|
||||||
|
is_weak && supports_weak_ref<T>::value,
|
||||||
|
naRef
|
||||||
|
>::type
|
||||||
|
create(naContext c, const strong_ref& ref_ptr)
|
||||||
|
{
|
||||||
|
typedef shared_ptr_storage<weak_ref> storage_type;
|
||||||
|
return naNewGhost2( c,
|
||||||
|
&Ghost::_ghost_type_weak,
|
||||||
|
storage_type::ref(ref_ptr) );
|
||||||
|
}
|
||||||
|
|
||||||
|
template<bool is_weak>
|
||||||
|
static
|
||||||
|
typename boost::enable_if_c<
|
||||||
|
is_weak && !supports_weak_ref<T>::value,
|
||||||
|
naRef
|
||||||
|
>::type
|
||||||
|
create(naContext, const strong_ref&)
|
||||||
|
{
|
||||||
|
return naNil();
|
||||||
|
}
|
||||||
|
|
||||||
template<class Type>
|
template<class Type>
|
||||||
static void destroy(void *ptr)
|
static void destroy(void *ptr)
|
||||||
{
|
{
|
||||||
@@ -1354,7 +1455,7 @@ typename boost::enable_if<
|
|||||||
from_nasal_helper(naContext c, naRef ref, const T*)
|
from_nasal_helper(naContext c, naRef ref, const T*)
|
||||||
{
|
{
|
||||||
typedef typename nasal::shared_ptr_traits<T>::strong_ref strong_ref;
|
typedef typename nasal::shared_ptr_traits<T>::strong_ref strong_ref;
|
||||||
return nasal::Ghost<strong_ref>::template fromNasal<T>(c, ref);
|
return T(nasal::Ghost<strong_ref>::fromNasalChecked(c, ref));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1389,7 +1490,7 @@ typename boost::enable_if_c<
|
|||||||
from_nasal_helper(naContext c, naRef ref, const T*)
|
from_nasal_helper(naContext c, naRef ref, const T*)
|
||||||
{
|
{
|
||||||
typedef SGSharedPtr<typename boost::remove_pointer<T>::type> TypeRef;
|
typedef SGSharedPtr<typename boost::remove_pointer<T>::type> TypeRef;
|
||||||
return nasal::Ghost<TypeRef>::template fromNasal<T>(c, ref);
|
return T(nasal::Ghost<TypeRef>::fromNasalChecked(c, ref));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1416,7 +1517,7 @@ typename boost::enable_if<
|
|||||||
from_nasal_helper(naContext c, naRef ref, const T*)
|
from_nasal_helper(naContext c, naRef ref, const T*)
|
||||||
{
|
{
|
||||||
typedef osg::ref_ptr<typename boost::remove_pointer<T>::type> TypeRef;
|
typedef osg::ref_ptr<typename boost::remove_pointer<T>::type> TypeRef;
|
||||||
return nasal::Ghost<TypeRef>::template fromNasal<T>(c, ref);
|
return T(nasal::Ghost<TypeRef>::fromNasalChecked(c, ref));
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* SG_NASAL_GHOST_HXX_ */
|
#endif /* SG_NASAL_GHOST_HXX_ */
|
||||||
|
|||||||
@@ -32,8 +32,9 @@ namespace nasal
|
|||||||
class CallContext
|
class CallContext
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CallContext(naContext c, size_t argc, naRef* args):
|
CallContext(naContext c, naRef me, size_t argc, naRef* args):
|
||||||
c(c),
|
c(c),
|
||||||
|
me(me),
|
||||||
argc(argc),
|
argc(argc),
|
||||||
args(args)
|
args(args)
|
||||||
{}
|
{}
|
||||||
@@ -120,6 +121,7 @@ namespace nasal
|
|||||||
}
|
}
|
||||||
|
|
||||||
naContext c;
|
naContext c;
|
||||||
|
naRef me;
|
||||||
size_t argc;
|
size_t argc;
|
||||||
naRef *args;
|
naRef *args;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,49 @@
|
|||||||
|
// Manage lifetime and encapsulate a Nasal context
|
||||||
|
//
|
||||||
|
// 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 "NasalContext.hxx"
|
||||||
|
|
||||||
|
namespace nasal
|
||||||
|
{
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
Context::Context():
|
||||||
|
_ctx(naNewContext())
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
Context::~Context()
|
||||||
|
{
|
||||||
|
naFreeContext(_ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
Context::operator naContext()
|
||||||
|
{
|
||||||
|
return _ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
Hash Context::newHash()
|
||||||
|
{
|
||||||
|
return Hash(_ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace nasal
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
///@file
|
||||||
|
//
|
||||||
|
// Copyright (C) 2014 Thomas Geymayer <tomgey@gmail.com>
|
||||||
|
//
|
||||||
|
// This library is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU Library General Public
|
||||||
|
// License as published by the Free Software Foundation; either
|
||||||
|
// version 2 of the License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// Library General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Library General Public
|
||||||
|
// License along with this library; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||||
|
|
||||||
|
#ifndef SG_NASAL_CONTEXT_HXX_
|
||||||
|
#define SG_NASAL_CONTEXT_HXX_
|
||||||
|
|
||||||
|
#include "NasalHash.hxx"
|
||||||
|
|
||||||
|
namespace nasal
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Manage lifetime and encapsulate a Nasal context.
|
||||||
|
*/
|
||||||
|
class Context
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Context();
|
||||||
|
~Context();
|
||||||
|
|
||||||
|
operator naContext();
|
||||||
|
|
||||||
|
Hash newHash();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
naContext _ctx;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace nasal
|
||||||
|
|
||||||
|
#endif /* SG_NASAL_CONTEXT_HXX_ */
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
///@file Wrapper class for Nasal hashes
|
///@file
|
||||||
//
|
//
|
||||||
// Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com>
|
// Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com>
|
||||||
//
|
//
|
||||||
@@ -29,7 +29,7 @@ namespace nasal
|
|||||||
{
|
{
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A Nasal Hash
|
* Wrapper class for Nasal hashes.
|
||||||
*/
|
*/
|
||||||
class Hash
|
class Hash
|
||||||
{
|
{
|
||||||
@@ -118,7 +118,6 @@ namespace nasal
|
|||||||
*
|
*
|
||||||
* @tparam Sig Function signature
|
* @tparam Sig Function signature
|
||||||
* @param name Member name
|
* @param name Member name
|
||||||
* @param key Member key
|
|
||||||
*/
|
*/
|
||||||
template<class Sig, class Key>
|
template<class Sig, class Key>
|
||||||
typename boost::enable_if< boost::is_function<Sig>,
|
typename boost::enable_if< boost::is_function<Sig>,
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
///@file Object exposed to Nasal including a Nasal hash for data storage.
|
///@file
|
||||||
//
|
//
|
||||||
// Copyright (C) 2014 Thomas Geymayer <tomgey@gmail.com>
|
// Copyright (C) 2014 Thomas Geymayer <tomgey@gmail.com>
|
||||||
//
|
//
|
||||||
@@ -19,11 +19,18 @@
|
|||||||
#ifndef SG_NASAL_OBJECT_HXX_
|
#ifndef SG_NASAL_OBJECT_HXX_
|
||||||
#define SG_NASAL_OBJECT_HXX_
|
#define SG_NASAL_OBJECT_HXX_
|
||||||
|
|
||||||
|
#include "NasalContext.hxx"
|
||||||
#include "NasalObjectHolder.hxx"
|
#include "NasalObjectHolder.hxx"
|
||||||
#include "Ghost.hxx"
|
#include "Ghost.hxx"
|
||||||
|
|
||||||
|
#include <boost/preprocessor/iteration/iterate.hpp>
|
||||||
|
#include <boost/preprocessor/repetition/enum_trailing_binary_params.hpp>
|
||||||
|
|
||||||
namespace nasal
|
namespace nasal
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* Object exposed to Nasal including a Nasal hash for data storage.
|
||||||
|
*/
|
||||||
class Object:
|
class Object:
|
||||||
public virtual SGVirtualWeakReferenced
|
public virtual SGVirtualWeakReferenced
|
||||||
{
|
{
|
||||||
@@ -41,6 +48,15 @@ namespace nasal
|
|||||||
|
|
||||||
bool valid() const;
|
bool valid() const;
|
||||||
|
|
||||||
|
// Build dependency for CMake, gcc, etc.
|
||||||
|
#define SG_DONT_DO_ANYTHING
|
||||||
|
# include <simgear/nasal/cppbind/detail/NasalObject_callMethod_templates.hxx>
|
||||||
|
#undef SG_DONT_DO_ANYTHING
|
||||||
|
|
||||||
|
#define BOOST_PP_ITERATION_LIMITS (0, 9)
|
||||||
|
#define BOOST_PP_FILENAME_1 <simgear/nasal/cppbind/detail/NasalObject_callMethod_templates.hxx>
|
||||||
|
#include BOOST_PP_ITERATE()
|
||||||
|
|
||||||
bool _set(naContext c, const std::string& key, naRef val);
|
bool _set(naContext c, const std::string& key, naRef val);
|
||||||
bool _get(naContext c, const std::string& key, naRef& out);
|
bool _get(naContext c, const std::string& key, naRef& out);
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
///@file Wrapper class for keeping Nasal objects save from the garbage collector
|
///@file
|
||||||
|
/// Wrapper class for keeping Nasal objects save from the garbage collector.
|
||||||
//
|
//
|
||||||
// Copyright (C) 2013 Thomas Geymayer <tomgey@gmail.com>
|
// Copyright (C) 2013 Thomas Geymayer <tomgey@gmail.com>
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
///@file Wrapper class for Nasal strings
|
///@file
|
||||||
//
|
//
|
||||||
// Copyright (C) 2013 Thomas Geymayer <tomgey@gmail.com>
|
// Copyright (C) 2013 Thomas Geymayer <tomgey@gmail.com>
|
||||||
//
|
//
|
||||||
@@ -26,7 +26,7 @@ namespace nasal
|
|||||||
{
|
{
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A Nasal String
|
* Wrapper class for Nasal strings.
|
||||||
*/
|
*/
|
||||||
class String
|
class String
|
||||||
{
|
{
|
||||||
@@ -47,7 +47,7 @@ namespace nasal
|
|||||||
*
|
*
|
||||||
* @param str Existing Nasal String
|
* @param str Existing Nasal String
|
||||||
*/
|
*/
|
||||||
String(naRef string);
|
String(naRef str);
|
||||||
|
|
||||||
const char* c_str() const;
|
const char* c_str() const;
|
||||||
const char* begin() const;
|
const char* begin() const;
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
#ifndef SG_NASAL_OBJECT_HXX_
|
||||||
|
# error Nasal cppbind - do not include this file!
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef SG_DONT_DO_ANYTHING
|
||||||
|
#define n BOOST_PP_ITERATION()
|
||||||
|
|
||||||
|
#define SG_CALL_ARG(z, n, dummy)\
|
||||||
|
to_nasal<typename boost::call_traits<A##n>::param_type>(ctx, a##n)
|
||||||
|
|
||||||
|
template<
|
||||||
|
class Ret
|
||||||
|
BOOST_PP_ENUM_TRAILING_PARAMS(n, class A)
|
||||||
|
>
|
||||||
|
Ret callMethod( const std::string& name
|
||||||
|
BOOST_PP_ENUM_TRAILING_BINARY_PARAMS(n, A, a) )
|
||||||
|
{
|
||||||
|
if( !_nasal_impl.valid() )
|
||||||
|
return Ret();
|
||||||
|
|
||||||
|
typedef boost::function<Ret (nasal::Me BOOST_PP_ENUM_TRAILING_PARAMS(n, A))>
|
||||||
|
MemFunc;
|
||||||
|
|
||||||
|
Context ctx;
|
||||||
|
MemFunc f = get_member<MemFunc>(ctx, _nasal_impl.get_naRef(), name.c_str());
|
||||||
|
if( f )
|
||||||
|
return f(nasal::to_nasal(ctx, this) BOOST_PP_ENUM_TRAILING_PARAMS(n, a));
|
||||||
|
|
||||||
|
return Ret();
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef SG_CALL_ARG
|
||||||
|
|
||||||
|
#undef n
|
||||||
|
#endif // SG_DONT_DO_ANYTHING
|
||||||
@@ -43,6 +43,9 @@ namespace osg
|
|||||||
template<class T> class ref_ptr;
|
template<class T> class ref_ptr;
|
||||||
template<class T> class observer_ptr;
|
template<class T> class observer_ptr;
|
||||||
|
|
||||||
|
template<class T, class Y>
|
||||||
|
ref_ptr<T> static_pointer_cast(const ref_ptr<Y>&);
|
||||||
|
|
||||||
class Vec2b;
|
class Vec2b;
|
||||||
class Vec2d;
|
class Vec2d;
|
||||||
class Vec2f;
|
class Vec2f;
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ namespace nasal
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return (*func)(nasal::CallContext(c, argc, args));
|
return (*func)(nasal::CallContext(c, me, argc, args));
|
||||||
}
|
}
|
||||||
catch(const std::exception& ex)
|
catch(const std::exception& ex)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ namespace nasal
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get pointer to specific version of from_nasal, converting to a type
|
* Get pointer to specific version of from_nasal, converting to a type
|
||||||
* compatible to Var.
|
* compatible to \a Var.
|
||||||
*/
|
*/
|
||||||
template<class Var>
|
template<class Var>
|
||||||
struct from_nasal_ptr
|
struct from_nasal_ptr
|
||||||
@@ -63,6 +63,9 @@ namespace nasal
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get member of hash, ghost (also searching in parent objects).
|
||||||
|
*/
|
||||||
template<class T>
|
template<class T>
|
||||||
T get_member(naContext c, naRef obj, const std::string& name)
|
T get_member(naContext c, naRef obj, const std::string& name)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -0,0 +1,76 @@
|
|||||||
|
///@file
|
||||||
|
/// Nasal context for testing and executing code
|
||||||
|
///
|
||||||
|
// Copyright (C) 2014 Thomas Geymayer <tomgey@gmail.com>
|
||||||
|
//
|
||||||
|
// This library is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU Library General Public
|
||||||
|
// License as published by the Free Software Foundation; either
|
||||||
|
// version 2 of the License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// Library General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Library General Public
|
||||||
|
// License along with this library; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||||
|
|
||||||
|
#ifndef SG_NASAL_TESTCONTEXT_HXX_
|
||||||
|
#define SG_NASAL_TESTCONTEXT_HXX_
|
||||||
|
|
||||||
|
#include <simgear/nasal/cppbind/NasalCallContext.hxx>
|
||||||
|
|
||||||
|
class TestContext:
|
||||||
|
public nasal::CallContext
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
TestContext():
|
||||||
|
CallContext(naNewContext(), naNil(), 0, 0)
|
||||||
|
{}
|
||||||
|
|
||||||
|
~TestContext()
|
||||||
|
{
|
||||||
|
naFreeContext(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
void runGC()
|
||||||
|
{
|
||||||
|
naFreeContext(c);
|
||||||
|
naGC();
|
||||||
|
c = naNewContext();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
T from_str(const std::string& str)
|
||||||
|
{
|
||||||
|
return from_nasal<T>(to_nasal(str));
|
||||||
|
}
|
||||||
|
|
||||||
|
naRef exec(const std::string& code_str, nasal::Me me)
|
||||||
|
{
|
||||||
|
int err_line = -1;
|
||||||
|
naRef code = naParseCode( c, to_nasal("<TextContext::exec>"), 0,
|
||||||
|
(char*)code_str.c_str(), code_str.length(),
|
||||||
|
&err_line );
|
||||||
|
if( !naIsCode(code) )
|
||||||
|
throw std::runtime_error("Failed to parse code: " + code_str);
|
||||||
|
|
||||||
|
return naCallMethod(code, me, 0, 0, naNil());
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
T exec(const std::string& code)
|
||||||
|
{
|
||||||
|
return from_nasal<T>(exec(code, naNil()));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
T convert(const std::string& str)
|
||||||
|
{
|
||||||
|
return from_nasal<T>(to_nasal(str));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* SG_NASAL_TESTCONTEXT_HXX_ */
|
||||||
+121
-138
@@ -1,22 +1,16 @@
|
|||||||
#include <simgear/math/SGMath.hxx>
|
#define BOOST_TEST_MODULE cppbind
|
||||||
|
#include <BoostTestTargetConfig.h>
|
||||||
|
|
||||||
#include "Ghost.hxx"
|
#include <simgear/nasal/cppbind/Ghost.hxx>
|
||||||
#include "NasalHash.hxx"
|
#include <simgear/nasal/cppbind/NasalHash.hxx>
|
||||||
#include "NasalString.hxx"
|
#include <simgear/nasal/cppbind/NasalString.hxx>
|
||||||
|
#include <simgear/math/SGMath.hxx>
|
||||||
#include <simgear/structure/map.hxx>
|
#include <simgear/structure/map.hxx>
|
||||||
|
|
||||||
#include <boost/shared_ptr.hpp>
|
#include <boost/shared_ptr.hpp>
|
||||||
#include <boost/weak_ptr.hpp>
|
#include <boost/weak_ptr.hpp>
|
||||||
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
#define VERIFY(a) \
|
|
||||||
if( !(a) ) \
|
|
||||||
{ \
|
|
||||||
std::cerr << "failed: line " << __LINE__ << ": " << #a << std::endl; \
|
|
||||||
return 1; \
|
|
||||||
}
|
|
||||||
|
|
||||||
enum MyEnum
|
enum MyEnum
|
||||||
{
|
{
|
||||||
@@ -121,7 +115,7 @@ naRef f_derivedGetX(const Derived& d, naContext c)
|
|||||||
}
|
}
|
||||||
naRef f_freeFunction(nasal::CallContext c) { return c.requireArg<naRef>(0); }
|
naRef f_freeFunction(nasal::CallContext c) { return c.requireArg<naRef>(0); }
|
||||||
|
|
||||||
int main(int argc, char* argv[])
|
BOOST_AUTO_TEST_CASE( cppbind_misc_testing )
|
||||||
{
|
{
|
||||||
naContext c = naNewContext();
|
naContext c = naNewContext();
|
||||||
naRef r;
|
naRef r;
|
||||||
@@ -129,44 +123,36 @@ int main(int argc, char* argv[])
|
|||||||
using namespace nasal;
|
using namespace nasal;
|
||||||
|
|
||||||
r = to_nasal(c, ENUM_ANOTHER);
|
r = to_nasal(c, ENUM_ANOTHER);
|
||||||
VERIFY( from_nasal<int>(c, r) == ENUM_ANOTHER );
|
BOOST_CHECK_EQUAL(from_nasal<int>(c, r), ENUM_ANOTHER);
|
||||||
|
|
||||||
r = to_nasal(c, "Test");
|
r = to_nasal(c, "Test");
|
||||||
VERIFY( strncmp("Test", naStr_data(r), naStr_len(r)) == 0 );
|
BOOST_CHECK( strncmp("Test", naStr_data(r), naStr_len(r)) == 0 );
|
||||||
VERIFY( from_nasal<std::string>(c, r) == "Test" );
|
BOOST_CHECK_EQUAL(from_nasal<std::string>(c, r), "Test");
|
||||||
|
|
||||||
r = to_nasal(c, std::string("Test"));
|
r = to_nasal(c, std::string("Test"));
|
||||||
VERIFY( strncmp("Test", naStr_data(r), naStr_len(r)) == 0 );
|
BOOST_CHECK( strncmp("Test", naStr_data(r), naStr_len(r)) == 0 );
|
||||||
VERIFY( from_nasal<std::string>(c, r) == "Test" );
|
BOOST_CHECK_EQUAL(from_nasal<std::string>(c, r), "Test");
|
||||||
|
|
||||||
r = to_nasal(c, 42);
|
r = to_nasal(c, 42);
|
||||||
VERIFY( naNumValue(r).num == 42 );
|
BOOST_CHECK_EQUAL(naNumValue(r).num, 42);
|
||||||
VERIFY( from_nasal<int>(c, r) == 42 );
|
BOOST_CHECK_EQUAL(from_nasal<int>(c, r), 42);
|
||||||
|
|
||||||
r = to_nasal(c, 4.2f);
|
r = to_nasal(c, 4.2f);
|
||||||
VERIFY( naNumValue(r).num == 4.2f );
|
BOOST_CHECK_EQUAL(naNumValue(r).num, 4.2f);
|
||||||
VERIFY( from_nasal<float>(c, r) == 4.2f );
|
BOOST_CHECK_EQUAL(from_nasal<float>(c, r), 4.2f);
|
||||||
|
|
||||||
float test_data[3] = {0, 4, 2};
|
float test_data[3] = {0, 4, 2};
|
||||||
r = to_nasal(c, test_data);
|
r = to_nasal(c, test_data);
|
||||||
|
|
||||||
SGVec2f vec(0,2);
|
SGVec2f vec(0,2);
|
||||||
r = to_nasal(c, vec);
|
r = to_nasal(c, vec);
|
||||||
VERIFY( from_nasal<SGVec2f>(c, r) == vec );
|
BOOST_CHECK_EQUAL(from_nasal<SGVec2f>(c, r), vec);
|
||||||
|
|
||||||
std::vector<int> std_vec;
|
std::vector<int> std_vec;
|
||||||
r = to_nasal(c, std_vec);
|
r = to_nasal(c, std_vec);
|
||||||
|
|
||||||
r = to_nasal(c, "string");
|
r = to_nasal(c, "string");
|
||||||
try
|
BOOST_CHECK_THROW(from_nasal<int>(c, r), bad_nasal_cast);
|
||||||
{
|
|
||||||
from_nasal<int>(c, r);
|
|
||||||
|
|
||||||
std::cerr << "failed: Expected bad_nasal_cast to be thrown" << std::endl;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
catch(nasal::bad_nasal_cast&)
|
|
||||||
{}
|
|
||||||
|
|
||||||
Hash hash(c);
|
Hash hash(c);
|
||||||
hash.set("vec", r);
|
hash.set("vec", r);
|
||||||
@@ -175,9 +161,10 @@ int main(int argc, char* argv[])
|
|||||||
hash.set("string", std::string("blub"));
|
hash.set("string", std::string("blub"));
|
||||||
hash.set("func", &f_freeFunction);
|
hash.set("func", &f_freeFunction);
|
||||||
|
|
||||||
VERIFY( hash.size() == 5 )
|
BOOST_CHECK_EQUAL(hash.size(), 5);
|
||||||
for(Hash::const_iterator it = hash.begin(); it != hash.end(); ++it)
|
for(Hash::const_iterator it = hash.begin(); it != hash.end(); ++it)
|
||||||
VERIFY( hash.get<std::string>(it->getKey()) == it->getValue<std::string>() )
|
BOOST_CHECK_EQUAL( hash.get<std::string>(it->getKey()),
|
||||||
|
it->getValue<std::string>() );
|
||||||
|
|
||||||
Hash::iterator it1, it2;
|
Hash::iterator it1, it2;
|
||||||
Hash::const_iterator it3 = it1, it4(it2);
|
Hash::const_iterator it3 = it1, it4(it2);
|
||||||
@@ -185,15 +172,15 @@ int main(int argc, char* argv[])
|
|||||||
it3 = it2;
|
it3 = it2;
|
||||||
|
|
||||||
r = to_nasal(c, hash);
|
r = to_nasal(c, hash);
|
||||||
VERIFY( naIsHash(r) );
|
BOOST_REQUIRE( naIsHash(r) );
|
||||||
|
|
||||||
simgear::StringMap string_map = from_nasal<simgear::StringMap>(c, r);
|
simgear::StringMap string_map = from_nasal<simgear::StringMap>(c, r);
|
||||||
VERIFY( string_map.at("vec") == "string" )
|
BOOST_CHECK_EQUAL(string_map.at("vec"), "string");
|
||||||
VERIFY( string_map.at("name") == "my-name" )
|
BOOST_CHECK_EQUAL(string_map.at("name"), "my-name");
|
||||||
VERIFY( string_map.at("string") == "blub" )
|
BOOST_CHECK_EQUAL(string_map.at("string"), "blub");
|
||||||
|
|
||||||
VERIFY( hash.get<std::string>("name") == "my-name" );
|
BOOST_CHECK_EQUAL(hash.get<std::string>("name"), "my-name");
|
||||||
VERIFY( naIsString(hash.get("name")) );
|
BOOST_CHECK(naIsString(hash.get("name")));
|
||||||
|
|
||||||
Hash mod = hash.createHash("mod");
|
Hash mod = hash.createHash("mod");
|
||||||
mod.set("parent", hash);
|
mod.set("parent", hash);
|
||||||
@@ -201,35 +188,35 @@ int main(int argc, char* argv[])
|
|||||||
|
|
||||||
// 'func' is a C++ function registered to Nasal and now converted back to C++
|
// 'func' is a C++ function registered to Nasal and now converted back to C++
|
||||||
boost::function<int (int)> f = hash.get<int (int)>("func");
|
boost::function<int (int)> f = hash.get<int (int)>("func");
|
||||||
VERIFY( f );
|
BOOST_REQUIRE( f );
|
||||||
VERIFY( f(3) == 3 );
|
BOOST_CHECK_EQUAL(f(3), 3);
|
||||||
|
|
||||||
boost::function<std::string (int)> fs = hash.get<std::string (int)>("func");
|
boost::function<std::string (int)> fs = hash.get<std::string (int)>("func");
|
||||||
VERIFY( fs );
|
BOOST_REQUIRE( fs );
|
||||||
VERIFY( fs(14) == "14" );
|
BOOST_CHECK_EQUAL(fs(14), "14");
|
||||||
|
|
||||||
typedef boost::function<void (int)> FuncVoidInt;
|
typedef boost::function<void (int)> FuncVoidInt;
|
||||||
FuncVoidInt fvi = hash.get<FuncVoidInt>("func");
|
FuncVoidInt fvi = hash.get<FuncVoidInt>("func");
|
||||||
VERIFY( fvi );
|
BOOST_REQUIRE( fvi );
|
||||||
fvi(123);
|
fvi(123);
|
||||||
|
|
||||||
typedef boost::function<std::string (const std::string&, int, float)> FuncMultiArg;
|
typedef boost::function<std::string (const std::string&, int, float)> FuncMultiArg;
|
||||||
FuncMultiArg fma = hash.get<FuncMultiArg>("func");
|
FuncMultiArg fma = hash.get<FuncMultiArg>("func");
|
||||||
VERIFY( fma );
|
BOOST_REQUIRE( fma );
|
||||||
VERIFY( fma("test", 3, .5) == "test" );
|
BOOST_CHECK_EQUAL(fma("test", 3, .5), "test");
|
||||||
|
|
||||||
typedef boost::function<naRef (naRef)> naRefMemFunc;
|
typedef boost::function<naRef (naRef)> naRefMemFunc;
|
||||||
naRefMemFunc fmem = hash.get<naRefMemFunc>("func");
|
naRefMemFunc fmem = hash.get<naRefMemFunc>("func");
|
||||||
VERIFY( fmem );
|
BOOST_REQUIRE( fmem );
|
||||||
naRef ret = fmem(hash.get_naRef()),
|
naRef ret = fmem(hash.get_naRef()),
|
||||||
hash_ref = hash.get_naRef();
|
hash_ref = hash.get_naRef();
|
||||||
VERIFY( naIsIdentical(ret, hash_ref) );
|
BOOST_CHECK( naIsIdentical(ret, hash_ref) );
|
||||||
|
|
||||||
// Check if nasal::Me gets passed as self/me and remaining arguments are
|
// Check if nasal::Me gets passed as self/me and remaining arguments are
|
||||||
// passed on to function
|
// passed on to function
|
||||||
typedef boost::function<int (Me, int)> MeIntFunc;
|
typedef boost::function<int (Me, int)> MeIntFunc;
|
||||||
MeIntFunc fmeint = hash.get<MeIntFunc>("func");
|
MeIntFunc fmeint = hash.get<MeIntFunc>("func");
|
||||||
VERIFY( fmeint(naNil(), 5) == 5 );
|
BOOST_CHECK_EQUAL(fmeint(naNil(), 5), 5);
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
// Test exposing classes to Nasal
|
// Test exposing classes to Nasal
|
||||||
@@ -276,82 +263,80 @@ int main(int argc, char* argv[])
|
|||||||
naRef nasal_ref = to_nasal(c, weak_ptr),
|
naRef nasal_ref = to_nasal(c, weak_ptr),
|
||||||
nasal_ptr = to_nasal(c, weak_ptr.get());
|
nasal_ptr = to_nasal(c, weak_ptr.get());
|
||||||
|
|
||||||
VERIFY( naIsGhost(nasal_ref) );
|
BOOST_REQUIRE( naIsGhost(nasal_ref) );
|
||||||
VERIFY( naIsGhost(nasal_ptr) );
|
BOOST_REQUIRE( naIsGhost(nasal_ptr) );
|
||||||
|
|
||||||
SGWeakRefBasedPtr ptr1 = from_nasal<SGWeakRefBasedPtr>(c, nasal_ref),
|
SGWeakRefBasedPtr ptr1 = from_nasal<SGWeakRefBasedPtr>(c, nasal_ref),
|
||||||
ptr2 = from_nasal<SGWeakRefBasedPtr>(c, nasal_ptr);
|
ptr2 = from_nasal<SGWeakRefBasedPtr>(c, nasal_ptr);
|
||||||
|
|
||||||
VERIFY( weak_ptr == ptr1 );
|
BOOST_CHECK_EQUAL(weak_ptr, ptr1);
|
||||||
VERIFY( weak_ptr == ptr2 );
|
BOOST_CHECK_EQUAL(weak_ptr, ptr2);
|
||||||
|
|
||||||
|
|
||||||
VERIFY( Ghost<BasePtr>::isInit() );
|
BOOST_REQUIRE( Ghost<BasePtr>::isInit() );
|
||||||
nasal::to_nasal(c, DoubleDerived2Ptr());
|
nasal::to_nasal(c, DoubleDerived2Ptr());
|
||||||
|
|
||||||
BasePtr d( new Derived );
|
BasePtr d( new Derived );
|
||||||
naRef derived = to_nasal(c, d);
|
naRef derived = to_nasal(c, d);
|
||||||
VERIFY( naIsGhost(derived) );
|
BOOST_REQUIRE( naIsGhost(derived) );
|
||||||
VERIFY( std::string("DerivedPtr") == naGhost_type(derived)->name );
|
BOOST_CHECK_EQUAL( std::string("DerivedPtr"), naGhost_type(derived)->name );
|
||||||
|
|
||||||
// Get member function from ghost...
|
// Get member function from ghost...
|
||||||
naRef thisGetter = naNil();
|
naRef thisGetter = naNil();
|
||||||
VERIFY( naMember_get(c, derived, to_nasal(c, "this"), &thisGetter) );
|
BOOST_CHECK( naMember_get(c, derived, to_nasal(c, "this"), &thisGetter) );
|
||||||
VERIFY( naIsFunc(thisGetter) );
|
BOOST_CHECK( naIsFunc(thisGetter) );
|
||||||
|
|
||||||
// ...and check if it really gets passed the correct instance
|
// ...and check if it really gets passed the correct instance
|
||||||
typedef boost::function<unsigned long (Me)> MemFunc;
|
typedef boost::function<unsigned long (Me)> MemFunc;
|
||||||
MemFunc fGetThis = from_nasal<MemFunc>(c, thisGetter);
|
MemFunc fGetThis = from_nasal<MemFunc>(c, thisGetter);
|
||||||
VERIFY( fGetThis );
|
BOOST_REQUIRE( fGetThis );
|
||||||
VERIFY( fGetThis(derived) == (unsigned long)d.get() );
|
BOOST_CHECK_EQUAL( fGetThis(derived), (unsigned long)d.get() );
|
||||||
|
|
||||||
BasePtr d2( new DoubleDerived );
|
BasePtr d2( new DoubleDerived );
|
||||||
derived = to_nasal(c, d2);
|
derived = to_nasal(c, d2);
|
||||||
VERIFY( naIsGhost(derived) );
|
BOOST_CHECK( naIsGhost(derived) );
|
||||||
VERIFY( std::string("DoubleDerivedPtr") == naGhost_type(derived)->name );
|
BOOST_CHECK_EQUAL( std::string("DoubleDerivedPtr"),
|
||||||
|
naGhost_type(derived)->name );
|
||||||
|
|
||||||
BasePtr d3( new DoubleDerived2 );
|
BasePtr d3( new DoubleDerived2 );
|
||||||
derived = to_nasal(c, d3);
|
derived = to_nasal(c, d3);
|
||||||
VERIFY( naIsGhost(derived) );
|
BOOST_CHECK( naIsGhost(derived) );
|
||||||
VERIFY( std::string("DoubleDerived2Ptr") == naGhost_type(derived)->name );
|
BOOST_CHECK_EQUAL( std::string("DoubleDerived2Ptr"),
|
||||||
|
naGhost_type(derived)->name );
|
||||||
|
|
||||||
SGRefBasedPtr ref_based( new SGReferenceBasedClass );
|
SGRefBasedPtr ref_based( new SGReferenceBasedClass );
|
||||||
naRef na_ref_based = to_nasal(c, ref_based.get());
|
naRef na_ref_based = to_nasal(c, ref_based.get());
|
||||||
VERIFY( naIsGhost(na_ref_based) );
|
BOOST_CHECK( naIsGhost(na_ref_based) );
|
||||||
VERIFY( from_nasal<SGReferenceBasedClass*>(c, na_ref_based)
|
BOOST_CHECK_EQUAL( from_nasal<SGReferenceBasedClass*>(c, na_ref_based),
|
||||||
== ref_based.get() );
|
ref_based.get() );
|
||||||
VERIFY( from_nasal<SGRefBasedPtr>(c, na_ref_based) == ref_based );
|
BOOST_CHECK_EQUAL( from_nasal<SGRefBasedPtr>(c, na_ref_based), ref_based );
|
||||||
|
|
||||||
VERIFY( Ghost<BasePtr>::isBaseOf(derived) );
|
BOOST_CHECK_EQUAL( from_nasal<BasePtr>(c, derived), d3 );
|
||||||
VERIFY( Ghost<DerivedPtr>::isBaseOf(derived) );
|
BOOST_CHECK_NE( from_nasal<BasePtr>(c, derived), d2 );
|
||||||
VERIFY( Ghost<DoubleDerived2Ptr>::isBaseOf(derived) );
|
BOOST_CHECK_EQUAL( from_nasal<DerivedPtr>(c, derived),
|
||||||
|
boost::dynamic_pointer_cast<Derived>(d3) );
|
||||||
VERIFY( from_nasal<BasePtr>(c, derived) == d3 );
|
BOOST_CHECK_EQUAL( from_nasal<DoubleDerived2Ptr>(c, derived),
|
||||||
VERIFY( from_nasal<BasePtr>(c, derived) != d2 );
|
boost::dynamic_pointer_cast<DoubleDerived2>(d3) );
|
||||||
VERIFY( from_nasal<DerivedPtr>(c, derived)
|
BOOST_CHECK_THROW( from_nasal<DoubleDerivedPtr>(c, derived), bad_nasal_cast );
|
||||||
== boost::dynamic_pointer_cast<Derived>(d3) );
|
|
||||||
VERIFY( from_nasal<DoubleDerived2Ptr>(c, derived)
|
|
||||||
== boost::dynamic_pointer_cast<DoubleDerived2>(d3) );
|
|
||||||
VERIFY( !from_nasal<DoubleDerivedPtr>(c, derived) );
|
|
||||||
|
|
||||||
std::map<std::string, BasePtr> instances;
|
std::map<std::string, BasePtr> instances;
|
||||||
VERIFY( naIsHash(to_nasal(c, instances)) );
|
BOOST_CHECK( naIsHash(to_nasal(c, instances)) );
|
||||||
|
|
||||||
std::map<std::string, DerivedPtr> instances_d;
|
std::map<std::string, DerivedPtr> instances_d;
|
||||||
VERIFY( naIsHash(to_nasal(c, instances_d)) );
|
BOOST_CHECK( naIsHash(to_nasal(c, instances_d)) );
|
||||||
|
|
||||||
std::map<std::string, int> int_map;
|
std::map<std::string, int> int_map;
|
||||||
VERIFY( naIsHash(to_nasal(c, int_map)) );
|
BOOST_CHECK( naIsHash(to_nasal(c, int_map)) );
|
||||||
|
|
||||||
std::map<std::string, std::vector<int> > int_vector_map;
|
std::map<std::string, std::vector<int> > int_vector_map;
|
||||||
VERIFY( naIsHash(to_nasal(c, int_vector_map)) );
|
BOOST_CHECK( naIsHash(to_nasal(c, int_vector_map)) );
|
||||||
|
|
||||||
simgear::StringMap dict =
|
simgear::StringMap dict =
|
||||||
simgear::StringMap("hello", "value")
|
simgear::StringMap("hello", "value")
|
||||||
("key2", "value2");
|
("key2", "value2");
|
||||||
naRef na_dict = to_nasal(c, dict);
|
naRef na_dict = to_nasal(c, dict);
|
||||||
VERIFY( naIsHash(na_dict) );
|
BOOST_REQUIRE( naIsHash(na_dict) );
|
||||||
VERIFY( Hash(na_dict, c).get<std::string>("key2") == "value2" );
|
BOOST_CHECK_EQUAL( Hash(na_dict, c).get<std::string>("key2"), "value2" );
|
||||||
|
|
||||||
// Check converting to Ghost if using Nasal hashes with actual ghost inside
|
// Check converting to Ghost if using Nasal hashes with actual ghost inside
|
||||||
// the hashes parents vector
|
// the hashes parents vector
|
||||||
@@ -361,14 +346,14 @@ int main(int argc, char* argv[])
|
|||||||
|
|
||||||
Hash obj(c);
|
Hash obj(c);
|
||||||
obj.set("parents", parents);
|
obj.set("parents", parents);
|
||||||
VERIFY( from_nasal<BasePtr>(c, obj.get_naRef()) == d3 );
|
BOOST_CHECK_EQUAL( from_nasal<BasePtr>(c, obj.get_naRef()), d3 );
|
||||||
|
|
||||||
// Check recursive parents (aka parent-of-parent)
|
// Check recursive parents (aka parent-of-parent)
|
||||||
std::vector<naRef> parents2;
|
std::vector<naRef> parents2;
|
||||||
parents2.push_back(obj.get_naRef());
|
parents2.push_back(obj.get_naRef());
|
||||||
Hash derived_obj(c);
|
Hash derived_obj(c);
|
||||||
derived_obj.set("parents", parents2);
|
derived_obj.set("parents", parents2);
|
||||||
VERIFY( from_nasal<BasePtr>(c, derived_obj.get_naRef()) == d3 );
|
BOOST_CHECK_EQUAL( from_nasal<BasePtr>(c, derived_obj.get_naRef()), d3 );
|
||||||
|
|
||||||
std::vector<naRef> nasal_objects;
|
std::vector<naRef> nasal_objects;
|
||||||
nasal_objects.push_back( Ghost<BasePtr>::makeGhost(c, d) );
|
nasal_objects.push_back( Ghost<BasePtr>::makeGhost(c, d) );
|
||||||
@@ -377,9 +362,9 @@ int main(int argc, char* argv[])
|
|||||||
naRef obj_vec = to_nasal(c, nasal_objects);
|
naRef obj_vec = to_nasal(c, nasal_objects);
|
||||||
|
|
||||||
std::vector<BasePtr> objects = from_nasal<std::vector<BasePtr> >(c, obj_vec);
|
std::vector<BasePtr> objects = from_nasal<std::vector<BasePtr> >(c, obj_vec);
|
||||||
VERIFY( objects[0] == d );
|
BOOST_CHECK_EQUAL( objects[0], d );
|
||||||
VERIFY( objects[1] == d2 );
|
BOOST_CHECK_EQUAL( objects[1], d2 );
|
||||||
VERIFY( objects[2] == d3 );
|
BOOST_CHECK_EQUAL( objects[2], d3 );
|
||||||
|
|
||||||
{
|
{
|
||||||
// Calling fallback setter for unset values
|
// Calling fallback setter for unset values
|
||||||
@@ -390,9 +375,9 @@ int main(int argc, char* argv[])
|
|||||||
&errLine );
|
&errLine );
|
||||||
ret = naCallMethod(code, derived, 0, 0, naNil());
|
ret = naCallMethod(code, derived, 0, 0, naNil());
|
||||||
|
|
||||||
VERIFY( !naGetError(c) ) // TODO real error check (this seems to always
|
BOOST_REQUIRE( !naGetError(c) ); // TODO real error check (this seems to
|
||||||
// return 0...
|
// always return 0...
|
||||||
VERIFY( from_nasal<int>(c, ret) == 3 )
|
BOOST_CHECK_EQUAL( from_nasal<int>(c, ret), 3 );
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
// Calling generic (fallback) getter
|
// Calling generic (fallback) getter
|
||||||
@@ -403,9 +388,9 @@ int main(int argc, char* argv[])
|
|||||||
&errLine );
|
&errLine );
|
||||||
ret = naCallMethod(code, derived, 0, 0, naNil());
|
ret = naCallMethod(code, derived, 0, 0, naNil());
|
||||||
|
|
||||||
VERIFY( !naGetError(c) ) // TODO real error check (this seems to always
|
BOOST_REQUIRE( !naGetError(c) ); // TODO real error check (this seems to
|
||||||
// return 0...
|
// always return 0...
|
||||||
VERIFY( from_nasal<std::string>(c, ret) == "generic-get" );
|
BOOST_CHECK_EQUAL( from_nasal<std::string>(c, ret), "generic-get" );
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
@@ -421,55 +406,53 @@ int main(int argc, char* argv[])
|
|||||||
to_nasal(c, int_vec),
|
to_nasal(c, int_vec),
|
||||||
to_nasal(c, map)
|
to_nasal(c, map)
|
||||||
};
|
};
|
||||||
CallContext cc(c, sizeof(args)/sizeof(args[0]), args);
|
CallContext cc(c, naNil(), sizeof(args)/sizeof(args[0]), args);
|
||||||
VERIFY( cc.requireArg<std::string>(0) == "test-arg" );
|
BOOST_CHECK_EQUAL( cc.requireArg<std::string>(0), "test-arg" );
|
||||||
VERIFY( cc.getArg<std::string>(0) == "test-arg" );
|
BOOST_CHECK_EQUAL( cc.getArg<std::string>(0), "test-arg" );
|
||||||
VERIFY( cc.getArg<std::string>(10) == "" );
|
BOOST_CHECK_EQUAL( cc.getArg<std::string>(10), "" );
|
||||||
VERIFY( cc.isString(0) );
|
BOOST_CHECK( cc.isString(0) );
|
||||||
VERIFY( !cc.isNumeric(0) );
|
BOOST_CHECK( !cc.isNumeric(0) );
|
||||||
VERIFY( !cc.isVector(0) );
|
BOOST_CHECK( !cc.isVector(0) );
|
||||||
VERIFY( !cc.isHash(0) );
|
BOOST_CHECK( !cc.isHash(0) );
|
||||||
VERIFY( !cc.isGhost(0) );
|
BOOST_CHECK( !cc.isGhost(0) );
|
||||||
VERIFY( cc.isNumeric(1) );
|
BOOST_CHECK( cc.isNumeric(1) );
|
||||||
VERIFY( cc.isVector(2) );
|
BOOST_CHECK( cc.isVector(2) );
|
||||||
VERIFY( cc.isHash(3) );
|
BOOST_CHECK( cc.isHash(3) );
|
||||||
|
|
||||||
naRef args_vec = nasal::to_nasal(c, args);
|
naRef args_vec = nasal::to_nasal(c, args);
|
||||||
VERIFY( naIsVector(args_vec) );
|
BOOST_CHECK( naIsVector(args_vec) );
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
// Test nasal::String
|
// Test nasal::String
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
|
|
||||||
String string( to_nasal(c, "Test") );
|
String string( to_nasal(c, "Test") );
|
||||||
VERIFY( from_nasal<std::string>(c, string.get_naRef()) == "Test" );
|
BOOST_CHECK_EQUAL( from_nasal<std::string>(c, string.get_naRef()), "Test" );
|
||||||
VERIFY( string.c_str() == std::string("Test") );
|
BOOST_CHECK_EQUAL( string.c_str(), std::string("Test") );
|
||||||
VERIFY( string.starts_with(string) );
|
BOOST_CHECK( string.starts_with(string) );
|
||||||
VERIFY( string.starts_with(String(c, "T")) );
|
BOOST_CHECK( string.starts_with(String(c, "T")) );
|
||||||
VERIFY( string.starts_with(String(c, "Te")) );
|
BOOST_CHECK( string.starts_with(String(c, "Te")) );
|
||||||
VERIFY( string.starts_with(String(c, "Tes")) );
|
BOOST_CHECK( string.starts_with(String(c, "Tes")) );
|
||||||
VERIFY( string.starts_with(String(c, "Test")) );
|
BOOST_CHECK( string.starts_with(String(c, "Test")) );
|
||||||
VERIFY( !string.starts_with(String(c, "Test1")) );
|
BOOST_CHECK( !string.starts_with(String(c, "Test1")) );
|
||||||
VERIFY( !string.starts_with(String(c, "bb")) );
|
BOOST_CHECK( !string.starts_with(String(c, "bb")) );
|
||||||
VERIFY( !string.starts_with(String(c, "bbasdasdafasd")) );
|
BOOST_CHECK( !string.starts_with(String(c, "bbasdasdafasd")) );
|
||||||
VERIFY( string.ends_with(String(c, "t")) );
|
BOOST_CHECK( string.ends_with(String(c, "t")) );
|
||||||
VERIFY( string.ends_with(String(c, "st")) );
|
BOOST_CHECK( string.ends_with(String(c, "st")) );
|
||||||
VERIFY( string.ends_with(String(c, "est")) );
|
BOOST_CHECK( string.ends_with(String(c, "est")) );
|
||||||
VERIFY( string.ends_with(String(c, "Test")) );
|
BOOST_CHECK( string.ends_with(String(c, "Test")) );
|
||||||
VERIFY( !string.ends_with(String(c, "1Test")) );
|
BOOST_CHECK( !string.ends_with(String(c, "1Test")) );
|
||||||
VERIFY( !string.ends_with(String(c, "abc")) );
|
BOOST_CHECK( !string.ends_with(String(c, "abc")) );
|
||||||
VERIFY( !string.ends_with(String(c, "estasdasd")) );
|
BOOST_CHECK( !string.ends_with(String(c, "estasdasd")) );
|
||||||
VERIFY( string.find('e') == 1 );
|
BOOST_CHECK_EQUAL( string.find('e'), 1 );
|
||||||
VERIFY( string.find('9') == String::npos );
|
BOOST_CHECK_EQUAL( string.find('9'), String::npos );
|
||||||
VERIFY( string.find_first_of(String(c, "st")) == 2 );
|
BOOST_CHECK_EQUAL( string.find_first_of(String(c, "st")), 2 );
|
||||||
VERIFY( string.find_first_of(String(c, "st"), 3) == 3 );
|
BOOST_CHECK_EQUAL( string.find_first_of(String(c, "st"), 3), 3 );
|
||||||
VERIFY( string.find_first_of(String(c, "xyz")) == String::npos );
|
BOOST_CHECK_EQUAL( string.find_first_of(String(c, "xyz")), String::npos );
|
||||||
VERIFY( string.find_first_not_of(String(c, "Tst")) == 1 );
|
BOOST_CHECK_EQUAL( string.find_first_not_of(String(c, "Tst")), 1 );
|
||||||
VERIFY( string.find_first_not_of(String(c, "Tse"), 2) == 3 );
|
BOOST_CHECK_EQUAL( string.find_first_not_of(String(c, "Tse"), 2), 3 );
|
||||||
VERIFY( string.find_first_not_of(String(c, "abc")) == 0 );
|
BOOST_CHECK_EQUAL( string.find_first_not_of(String(c, "abc")), 0 );
|
||||||
VERIFY( string.find_first_not_of(String(c, "abc"), 20) == String::npos );
|
BOOST_CHECK_EQUAL( string.find_first_not_of(String(c, "abc"), 20), String::npos );
|
||||||
|
|
||||||
naFreeContext(c);
|
naFreeContext(c);
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
+50
-3
@@ -1,7 +1,9 @@
|
|||||||
#define BOOST_TEST_MODULE cppbind
|
#define BOOST_TEST_MODULE cppbind
|
||||||
#include <BoostTestTargetConfig.h>
|
#include <BoostTestTargetConfig.h>
|
||||||
|
|
||||||
#include "Ghost.hxx"
|
#include <simgear/nasal/cppbind/Ghost.hxx>
|
||||||
|
#include <simgear/nasal/cppbind/NasalContext.hxx>
|
||||||
|
|
||||||
#include <boost/shared_ptr.hpp>
|
#include <boost/shared_ptr.hpp>
|
||||||
#include <boost/weak_ptr.hpp>
|
#include <boost/weak_ptr.hpp>
|
||||||
|
|
||||||
@@ -49,14 +51,19 @@ BOOST_STATIC_ASSERT(( nasal::supports_weak_ref<DerivedPtr>::value));
|
|||||||
BOOST_STATIC_ASSERT(( nasal::supports_weak_ref<DerivedWeakPtr>::value));
|
BOOST_STATIC_ASSERT(( nasal::supports_weak_ref<DerivedWeakPtr>::value));
|
||||||
BOOST_STATIC_ASSERT((!nasal::supports_weak_ref<SGReferencedPtr>::value));
|
BOOST_STATIC_ASSERT((!nasal::supports_weak_ref<SGReferencedPtr>::value));
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE( ghost_weak_strong_nasal_conversion )
|
static void setupGhosts()
|
||||||
{
|
{
|
||||||
nasal::Ghost<Base1Ptr>::init("Base1");
|
nasal::Ghost<Base1Ptr>::init("Base1");
|
||||||
nasal::Ghost<Base2Ptr>::init("Base2");
|
nasal::Ghost<Base2Ptr>::init("Base2");
|
||||||
nasal::Ghost<DerivedPtr>::init("Derived")
|
nasal::Ghost<DerivedPtr>::init("Derived")
|
||||||
.bases<Base1Ptr>()
|
.bases<Base1Ptr>()
|
||||||
.bases<Base2Ptr>();
|
.bases<Base2Ptr>();
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
BOOST_AUTO_TEST_CASE( ghost_weak_strong_nasal_conversion )
|
||||||
|
{
|
||||||
|
setupGhosts();
|
||||||
naContext c = naNewContext();
|
naContext c = naNewContext();
|
||||||
|
|
||||||
DerivedPtr d = new Derived();
|
DerivedPtr d = new Derived();
|
||||||
@@ -70,7 +77,8 @@ BOOST_AUTO_TEST_CASE( ghost_weak_strong_nasal_conversion )
|
|||||||
BOOST_CHECK_EQUAL( nasal::from_nasal<DerivedPtr>(c, na_d), d );
|
BOOST_CHECK_EQUAL( nasal::from_nasal<DerivedPtr>(c, na_d), d );
|
||||||
|
|
||||||
d.reset();
|
d.reset();
|
||||||
BOOST_REQUIRE( !nasal::from_nasal<DerivedPtr>(c, na_d) );
|
BOOST_REQUIRE_THROW( nasal::from_nasal<DerivedPtr>(c, na_d),
|
||||||
|
nasal::bad_nasal_cast );
|
||||||
|
|
||||||
// store strong pointer and extract weak pointer
|
// store strong pointer and extract weak pointer
|
||||||
d.reset(new Derived);
|
d.reset(new Derived);
|
||||||
@@ -91,6 +99,45 @@ BOOST_AUTO_TEST_CASE( ghost_weak_strong_nasal_conversion )
|
|||||||
BOOST_REQUIRE( !weak.lock() );
|
BOOST_REQUIRE( !weak.lock() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
BOOST_AUTO_TEST_CASE( ghost_casting_storage )
|
||||||
|
{
|
||||||
|
setupGhosts();
|
||||||
|
nasal::Context c;
|
||||||
|
|
||||||
|
// Check converting to and from every class in the hierarchy for an instance
|
||||||
|
// of the leaf class
|
||||||
|
DerivedPtr d = new Derived();
|
||||||
|
|
||||||
|
naRef na_d = nasal::to_nasal(c, d),
|
||||||
|
na_b1 = nasal::to_nasal(c, Base1Ptr(d)),
|
||||||
|
na_b2 = nasal::to_nasal(c, Base2Ptr(d));
|
||||||
|
|
||||||
|
Derived *d0 = nasal::from_nasal<Derived*>(c, na_d),
|
||||||
|
*d1 = nasal::from_nasal<Derived*>(c, na_b1),
|
||||||
|
*d2 = nasal::from_nasal<Derived*>(c, na_b2);
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL(d0, d.get());
|
||||||
|
BOOST_CHECK_EQUAL(d1, d.get());
|
||||||
|
BOOST_CHECK_EQUAL(d2, d.get());
|
||||||
|
|
||||||
|
Base1 *b1 = nasal::from_nasal<Base1*>(c, na_b1);
|
||||||
|
BOOST_CHECK_EQUAL(b1, static_cast<Base1*>(d.get()));
|
||||||
|
|
||||||
|
Base2 *b2 = nasal::from_nasal<Base2*>(c, na_b2);
|
||||||
|
BOOST_CHECK_EQUAL(b2, static_cast<Base2*>(d.get()));
|
||||||
|
|
||||||
|
// Check converting from base class instance to derived classes is not
|
||||||
|
// possible
|
||||||
|
Base1Ptr b1_ref = new Base1();
|
||||||
|
na_b1 = nasal::to_nasal(c, b1_ref);
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL(nasal::from_nasal<Base1*>(c, na_b1), b1_ref.get());
|
||||||
|
BOOST_CHECK_THROW(nasal::from_nasal<Base2*>(c, na_b1), nasal::bad_nasal_cast);
|
||||||
|
BOOST_CHECK_THROW(nasal::from_nasal<Derived*>(c, na_b1), nasal::bad_nasal_cast);
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
#define CHECK_PTR_STORAGE_TRAIT_TYPE(ptr_t, storage)\
|
#define CHECK_PTR_STORAGE_TRAIT_TYPE(ptr_t, storage)\
|
||||||
BOOST_STATIC_ASSERT((boost::is_same<\
|
BOOST_STATIC_ASSERT((boost::is_same<\
|
||||||
nasal::shared_ptr_storage<ptr_t>::storage_type,\
|
nasal::shared_ptr_storage<ptr_t>::storage_type,\
|
||||||
@@ -0,0 +1,93 @@
|
|||||||
|
#define BOOST_TEST_MODULE nasal
|
||||||
|
#include <BoostTestTargetConfig.h>
|
||||||
|
|
||||||
|
#include "TestContext.hxx"
|
||||||
|
#include <iostream>
|
||||||
|
#include <set>
|
||||||
|
|
||||||
|
static std::set<intptr_t> active_instances;
|
||||||
|
|
||||||
|
static void ghost_destroy(void* p)
|
||||||
|
{
|
||||||
|
active_instances.erase((intptr_t)p);
|
||||||
|
}
|
||||||
|
|
||||||
|
static naGhostType ghost_type = {
|
||||||
|
&ghost_destroy,
|
||||||
|
"TestGhost",
|
||||||
|
0, // get_member
|
||||||
|
0 // set_member
|
||||||
|
};
|
||||||
|
|
||||||
|
static naRef createTestGhost(TestContext& c, intptr_t p)
|
||||||
|
{
|
||||||
|
active_instances.insert(p);
|
||||||
|
return naNewGhost(c.c, &ghost_type, (void*)p);
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
BOOST_AUTO_TEST_CASE( ghost_gc )
|
||||||
|
{
|
||||||
|
TestContext c;
|
||||||
|
BOOST_REQUIRE(active_instances.empty());
|
||||||
|
|
||||||
|
//-----------------------------------------------
|
||||||
|
// Just create ghosts and let the gc destroy them
|
||||||
|
|
||||||
|
naRef g1 = createTestGhost(c, 1),
|
||||||
|
g2 = createTestGhost(c, 2);
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL(active_instances.count(1), 1);
|
||||||
|
BOOST_CHECK_EQUAL(active_instances.count(2), 1);
|
||||||
|
BOOST_CHECK_EQUAL(active_instances.size(), 2);
|
||||||
|
|
||||||
|
c.runGC();
|
||||||
|
|
||||||
|
BOOST_REQUIRE(active_instances.empty());
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------
|
||||||
|
// Create some more ghosts and save one instance
|
||||||
|
// from being garbage collected.
|
||||||
|
|
||||||
|
g1 = createTestGhost(c, 1);
|
||||||
|
g2 = createTestGhost(c, 2);
|
||||||
|
|
||||||
|
int gc1 = naGCSave(g1);
|
||||||
|
c.runGC();
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL(active_instances.count(1), 1);
|
||||||
|
BOOST_CHECK_EQUAL(active_instances.size(), 1);
|
||||||
|
|
||||||
|
naGCRelease(gc1);
|
||||||
|
c.runGC();
|
||||||
|
|
||||||
|
BOOST_REQUIRE(active_instances.empty());
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------
|
||||||
|
// Now test attaching one ghost to another
|
||||||
|
|
||||||
|
g1 = createTestGhost(c, 1);
|
||||||
|
g2 = createTestGhost(c, 2);
|
||||||
|
|
||||||
|
gc1 = naGCSave(g1);
|
||||||
|
naGhost_setData(g1, g2); // bind lifetime of g2 to g1...
|
||||||
|
|
||||||
|
c.runGC();
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL(active_instances.count(1), 1);
|
||||||
|
BOOST_CHECK_EQUAL(active_instances.count(2), 1);
|
||||||
|
BOOST_CHECK_EQUAL(active_instances.size(), 2);
|
||||||
|
|
||||||
|
naGhost_setData(g1, naNil()); // cut connection
|
||||||
|
c.runGC();
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL(active_instances.count(1), 1);
|
||||||
|
BOOST_CHECK_EQUAL(active_instances.size(), 1);
|
||||||
|
|
||||||
|
naGCRelease(gc1);
|
||||||
|
c.runGC();
|
||||||
|
|
||||||
|
BOOST_REQUIRE(active_instances.empty());
|
||||||
|
}
|
||||||
+2
-46
@@ -1,51 +1,7 @@
|
|||||||
#define BOOST_TEST_MODULE cppbind
|
#define BOOST_TEST_MODULE nasal
|
||||||
#include <BoostTestTargetConfig.h>
|
#include <BoostTestTargetConfig.h>
|
||||||
|
|
||||||
#include "NasalCallContext.hxx"
|
#include "TestContext.hxx"
|
||||||
|
|
||||||
class TestContext:
|
|
||||||
public nasal::CallContext
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
TestContext():
|
|
||||||
CallContext(naNewContext(), 0, 0)
|
|
||||||
{}
|
|
||||||
|
|
||||||
~TestContext()
|
|
||||||
{
|
|
||||||
naFreeContext(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class T>
|
|
||||||
T from_str(const std::string& str)
|
|
||||||
{
|
|
||||||
return from_nasal<T>(to_nasal(str));
|
|
||||||
}
|
|
||||||
|
|
||||||
naRef exec(const std::string& code_str, nasal::Me me)
|
|
||||||
{
|
|
||||||
int err_line = -1;
|
|
||||||
naRef code = naParseCode( c, to_nasal("<TextContext::exec>"), 0,
|
|
||||||
(char*)code_str.c_str(), code_str.length(),
|
|
||||||
&err_line );
|
|
||||||
if( !naIsCode(code) )
|
|
||||||
throw std::runtime_error("Failed to parse code: " + code_str);
|
|
||||||
|
|
||||||
return naCallMethod(code, me, 0, 0, naNil());
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class T>
|
|
||||||
T exec(const std::string& code)
|
|
||||||
{
|
|
||||||
return from_nasal<T>(exec(code, naNil()));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class T>
|
|
||||||
T convert(const std::string& str)
|
|
||||||
{
|
|
||||||
return from_nasal<T>(to_nasal(str));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
static void runNumTests( double (TestContext::*test_double)(const std::string&),
|
static void runNumTests( double (TestContext::*test_double)(const std::string&),
|
||||||
int (TestContext::*test_int)(const std::string&) )
|
int (TestContext::*test_int)(const std::string&) )
|
||||||
@@ -161,7 +161,7 @@ struct naFunc {
|
|||||||
struct naCCode {
|
struct naCCode {
|
||||||
GC_HEADER;
|
GC_HEADER;
|
||||||
union {
|
union {
|
||||||
naCFunction fptr; //<! pointer to simple callback function. Invalid if
|
naCFunction fptr; //!< pointer to simple callback function. Invalid if
|
||||||
// fptru is not NULL.
|
// fptru is not NULL.
|
||||||
struct {
|
struct {
|
||||||
void* user_data;
|
void* user_data;
|
||||||
@@ -175,6 +175,7 @@ struct naGhost {
|
|||||||
GC_HEADER;
|
GC_HEADER;
|
||||||
naGhostType* gtype;
|
naGhostType* gtype;
|
||||||
void* ptr;
|
void* ptr;
|
||||||
|
naRef data; //!< Nasal data bound to the lifetime of the ghost.
|
||||||
};
|
};
|
||||||
|
|
||||||
struct naPool {
|
struct naPool {
|
||||||
|
|||||||
@@ -263,6 +263,9 @@ static void mark(naRef r)
|
|||||||
mark(PTR(r).func->namespace);
|
mark(PTR(r).func->namespace);
|
||||||
mark(PTR(r).func->next);
|
mark(PTR(r).func->next);
|
||||||
break;
|
break;
|
||||||
|
case T_GHOST:
|
||||||
|
mark(PTR(r).ghost->data);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -147,6 +147,7 @@ naRef naNewGhost(naContext c, naGhostType* type, void* ptr)
|
|||||||
ghost = naNew(c, T_GHOST);
|
ghost = naNew(c, T_GHOST);
|
||||||
PTR(ghost).ghost->gtype = type;
|
PTR(ghost).ghost->gtype = type;
|
||||||
PTR(ghost).ghost->ptr = ptr;
|
PTR(ghost).ghost->ptr = ptr;
|
||||||
|
PTR(ghost).ghost->data = naNil();
|
||||||
return ghost;
|
return ghost;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -155,6 +156,7 @@ naRef naNewGhost2(naContext c, naGhostType* t, void* ptr)
|
|||||||
naRef ghost = naNew(c, T_GHOST);
|
naRef ghost = naNew(c, T_GHOST);
|
||||||
PTR(ghost).ghost->gtype = t;
|
PTR(ghost).ghost->gtype = t;
|
||||||
PTR(ghost).ghost->ptr = ptr;
|
PTR(ghost).ghost->ptr = ptr;
|
||||||
|
PTR(ghost).ghost->data = naNil();
|
||||||
return ghost;
|
return ghost;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -170,6 +172,18 @@ void* naGhost_ptr(naRef ghost)
|
|||||||
return PTR(ghost).ghost->ptr;
|
return PTR(ghost).ghost->ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void naGhost_setData(naRef ghost, naRef data)
|
||||||
|
{
|
||||||
|
if(IS_GHOST(ghost))
|
||||||
|
PTR(ghost).ghost->data = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
naRef naGhost_data(naRef ghost)
|
||||||
|
{
|
||||||
|
if(!IS_GHOST(ghost)) return naNil();
|
||||||
|
return PTR(ghost).ghost->data;
|
||||||
|
}
|
||||||
|
|
||||||
naRef naNil()
|
naRef naNil()
|
||||||
{
|
{
|
||||||
naRef r;
|
naRef r;
|
||||||
|
|||||||
@@ -281,6 +281,16 @@ naRef naNewGhost(naContext c, naGhostType* t, void* ghost);
|
|||||||
naRef naNewGhost2(naContext c, naGhostType* t, void* ghost);
|
naRef naNewGhost2(naContext c, naGhostType* t, void* ghost);
|
||||||
naGhostType* naGhost_type(naRef ghost);
|
naGhostType* naGhost_type(naRef ghost);
|
||||||
void* naGhost_ptr(naRef ghost);
|
void* naGhost_ptr(naRef ghost);
|
||||||
|
/**
|
||||||
|
* Attach a nasal object to the given ghost. Binds the lifetime of @a data to
|
||||||
|
* the lifetime of the @a ghost.
|
||||||
|
*/
|
||||||
|
void naGhost_setData(naRef ghost, naRef data);
|
||||||
|
/**
|
||||||
|
* Retrieve the object attached to the @a ghost, previously set with
|
||||||
|
* naGhost_setData().
|
||||||
|
*/
|
||||||
|
naRef naGhost_data(naRef ghost);
|
||||||
int naIsGhost(naRef r);
|
int naIsGhost(naRef r);
|
||||||
|
|
||||||
// Acquires a "modification lock" on a context, allowing the C code to
|
// Acquires a "modification lock" on a context, allowing the C code to
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ voidpf ZCALLBACK fopen_mem_func (opaque, filename, mode)
|
|||||||
* size of an int and therefore may need addressing for 64bit
|
* size of an int and therefore may need addressing for 64bit
|
||||||
* architectures
|
* architectures
|
||||||
*/
|
*/
|
||||||
if (sscanf(filename,"%p+%x",&mem->base,&mem->size)!=2)
|
if (sscanf(filename,"%p+%lx",&mem->base,&mem->size)!=2)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (mode & ZLIB_FILEFUNC_MODE_CREATE)
|
if (mode & ZLIB_FILEFUNC_MODE_CREATE)
|
||||||
@@ -202,7 +202,7 @@ int ZCALLBACK ferror_mem_func (opaque, stream)
|
|||||||
voidpf opaque;
|
voidpf opaque;
|
||||||
voidpf stream;
|
voidpf stream;
|
||||||
{
|
{
|
||||||
ourmemory_t *mem = (ourmemory_t *)stream;
|
// ourmemory_t *mem = (ourmemory_t *)stream;
|
||||||
/* We never return errors */
|
/* We never return errors */
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,8 +39,8 @@ namespace simgear
|
|||||||
/**
|
/**
|
||||||
* Remove the property listener of the element.
|
* Remove the property listener of the element.
|
||||||
*
|
*
|
||||||
* You will need to call the appropriate methods (#childAdded,
|
* You will need to call the appropriate methods (childAdded(),
|
||||||
* #childRemoved, #valueChanged) yourself to ensure the element still
|
* childRemoved(), valueChanged()) yourself to ensure the element still
|
||||||
* receives the needed events.
|
* receives the needed events.
|
||||||
*/
|
*/
|
||||||
void removeListener();
|
void removeListener();
|
||||||
|
|||||||
@@ -60,11 +60,22 @@ namespace simgear
|
|||||||
return 0.5 + 0.5 * (*easeOut)(t - 1);
|
return 0.5 + 0.5 * (*easeOut)(t - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper for exponential ease out with integer exponent.
|
||||||
|
*
|
||||||
|
* @tparam N Exponent.
|
||||||
|
* @tparam is_odd If the exponent is odd.
|
||||||
|
*/
|
||||||
template<size_t N, bool is_odd>
|
template<size_t N, bool is_odd>
|
||||||
struct easeOutImpl;
|
struct easeOutImpl;
|
||||||
|
|
||||||
/// http://easings.net/#easeOutCubic (N = 3)
|
/**
|
||||||
/// http://easings.net/#easeOutQuint (N = 5)
|
* Ease out with odd integer exponent.
|
||||||
|
*
|
||||||
|
* @tparam N Exponent.
|
||||||
|
* @see http://easings.net/#easeOutCubic (N = 3)
|
||||||
|
* @see http://easings.net/#easeOutQuint (N = 5)
|
||||||
|
*/
|
||||||
template<size_t N>
|
template<size_t N>
|
||||||
struct easeOutImpl<N, true>
|
struct easeOutImpl<N, true>
|
||||||
{
|
{
|
||||||
@@ -74,8 +85,13 @@ namespace simgear
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/// http://easings.net/#easeOutQuad (N = 2)
|
/**
|
||||||
/// http://easings.net/#easeOutQuart (N = 4)
|
* Ease out with even integer exponent.
|
||||||
|
*
|
||||||
|
* @tparam N Exponent.
|
||||||
|
* @see http://easings.net/#easeOutQuad (N = 2)
|
||||||
|
* @see http://easings.net/#easeOutQuart (N = 4)
|
||||||
|
*/
|
||||||
template<size_t N>
|
template<size_t N>
|
||||||
struct easeOutImpl<N, false>
|
struct easeOutImpl<N, false>
|
||||||
{
|
{
|
||||||
@@ -85,10 +101,15 @@ namespace simgear
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/// http://easings.net/#easeOutQuad (N = 2)
|
/**
|
||||||
/// http://easings.net/#easeOutCubic (N = 3)
|
* Exponential ease out with integer exponent.
|
||||||
/// http://easings.net/#easeOutQuart (N = 4)
|
*
|
||||||
/// http://easings.net/#easeOutQuint (N = 5)
|
* @see http://easings.net/#easeOutQuad (N = 2)
|
||||||
|
* @see http://easings.net/#easeOutCubic (N = 3)
|
||||||
|
* @see http://easings.net/#easeOutQuart (N = 4)
|
||||||
|
* @see http://easings.net/#easeOutQuint (N = 5)
|
||||||
|
* @see easeOutImpl
|
||||||
|
*/
|
||||||
template<size_t N>
|
template<size_t N>
|
||||||
double easeOutPow(double t)
|
double easeOutPow(double t)
|
||||||
{
|
{
|
||||||
|
|||||||
+18
-19
@@ -52,7 +52,6 @@ using std::cerr;
|
|||||||
using std::endl;
|
using std::endl;
|
||||||
using std::find;
|
using std::find;
|
||||||
using std::sort;
|
using std::sort;
|
||||||
using std::string;
|
|
||||||
using std::vector;
|
using std::vector;
|
||||||
using std::stringstream;
|
using std::stringstream;
|
||||||
|
|
||||||
@@ -104,7 +103,7 @@ parse_name (const SGPropertyNode *node, const Range &path)
|
|||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
if (i != max && *i != '/')
|
if (i != max && *i != '/')
|
||||||
throw string("illegal character after . or ..");
|
throw std::string("illegal character after . or ..");
|
||||||
} else if (isalpha(*i) || *i == '_') {
|
} else if (isalpha(*i) || *i == '_') {
|
||||||
i++;
|
i++;
|
||||||
|
|
||||||
@@ -117,7 +116,7 @@ parse_name (const SGPropertyNode *node, const Range &path)
|
|||||||
} else if (*i == '[' || *i == '/') {
|
} else if (*i == '[' || *i == '/') {
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
string err = "'";
|
std::string err = "'";
|
||||||
err.push_back(*i);
|
err.push_back(*i);
|
||||||
err.append("' found in propertyname after '"+node->getNameString()+"'");
|
err.append("' found in propertyname after '"+node->getNameString()+"'");
|
||||||
err.append("\nname may contain only ._- and alphanumeric characters");
|
err.append("\nname may contain only ._- and alphanumeric characters");
|
||||||
@@ -129,7 +128,7 @@ parse_name (const SGPropertyNode *node, const Range &path)
|
|||||||
|
|
||||||
else {
|
else {
|
||||||
if (path.begin() == i) {
|
if (path.begin() == i) {
|
||||||
string err = "'";
|
std::string err = "'";
|
||||||
err.push_back(*i);
|
err.push_back(*i);
|
||||||
err.append("' found in propertyname after '"+node->getNameString()+"'");
|
err.append("' found in propertyname after '"+node->getNameString()+"'");
|
||||||
err.append("\nname must begin with alpha or '_'");
|
err.append("\nname must begin with alpha or '_'");
|
||||||
@@ -140,7 +139,7 @@ parse_name (const SGPropertyNode *node, const Range &path)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Validate the name of a single node
|
// Validate the name of a single node
|
||||||
inline bool validateName(const string& name)
|
inline bool validateName(const std::string& name)
|
||||||
{
|
{
|
||||||
using namespace boost;
|
using namespace boost;
|
||||||
if (name.empty())
|
if (name.empty())
|
||||||
@@ -287,7 +286,7 @@ find_node_aux(SGPropertyNode * current, SplitItr& itr, bool create,
|
|||||||
if (equals(name, "..")) {
|
if (equals(name, "..")) {
|
||||||
SGPropertyNode * parent = current->getParent();
|
SGPropertyNode * parent = current->getParent();
|
||||||
if (parent == 0)
|
if (parent == 0)
|
||||||
throw string("attempt to move past root with '..'");
|
throw std::string("attempt to move past root with '..'");
|
||||||
return find_node_aux(parent, ++itr, create, last_index);
|
return find_node_aux(parent, ++itr, create, last_index);
|
||||||
}
|
}
|
||||||
int index = -1;
|
int index = -1;
|
||||||
@@ -320,10 +319,10 @@ find_node_aux(SGPropertyNode * current, SplitItr& itr, bool create,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (i == token.end() || *i != ']')
|
if (i == token.end() || *i != ']')
|
||||||
throw string("unterminated index (looking for ']')");
|
throw std::string("unterminated index (looking for ']')");
|
||||||
} else {
|
} else {
|
||||||
throw string("illegal characters in token: ")
|
throw std::string("illegal characters in token: ")
|
||||||
+ string(name.begin(), name.end());
|
+ std::string(name.begin(), name.end());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -733,10 +732,10 @@ SGPropertyNode::SGPropertyNode (Itr begin, Itr end,
|
|||||||
_local_val.string_val = 0;
|
_local_val.string_val = 0;
|
||||||
_value.val = 0;
|
_value.val = 0;
|
||||||
if (!validateName(_name))
|
if (!validateName(_name))
|
||||||
throw string("plain name expected instead of '") + _name + '\'';
|
throw std::string("plain name expected instead of '") + _name + '\'';
|
||||||
}
|
}
|
||||||
|
|
||||||
SGPropertyNode::SGPropertyNode (const string& name,
|
SGPropertyNode::SGPropertyNode( const std::string& name,
|
||||||
int index,
|
int index,
|
||||||
SGPropertyNode * parent)
|
SGPropertyNode * parent)
|
||||||
: _index(index),
|
: _index(index),
|
||||||
@@ -750,7 +749,7 @@ SGPropertyNode::SGPropertyNode (const string& name,
|
|||||||
_local_val.string_val = 0;
|
_local_val.string_val = 0;
|
||||||
_value.val = 0;
|
_value.val = 0;
|
||||||
if (!validateName(name))
|
if (!validateName(name))
|
||||||
throw string("plain name expected instead of '") + _name + '\'';
|
throw std::string("plain name expected instead of '") + _name + '\'';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -956,7 +955,7 @@ SGPropertyNode::getChild (const char * name, int index, bool create)
|
|||||||
}
|
}
|
||||||
|
|
||||||
SGPropertyNode *
|
SGPropertyNode *
|
||||||
SGPropertyNode::getChild (const string& name, int index, bool create)
|
SGPropertyNode::getChild (const std::string& name, int index, bool create)
|
||||||
{
|
{
|
||||||
SGPropertyNode* node = getExistingChild(name.begin(), name.end(), index);
|
SGPropertyNode* node = getExistingChild(name.begin(), name.end(), index);
|
||||||
if (node) {
|
if (node) {
|
||||||
@@ -1072,10 +1071,10 @@ SGPropertyNode::removeAllChildren()
|
|||||||
_children.clear();
|
_children.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
string
|
std::string
|
||||||
SGPropertyNode::getDisplayName (bool simplify) const
|
SGPropertyNode::getDisplayName (bool simplify) const
|
||||||
{
|
{
|
||||||
string display_name = _name;
|
std::string display_name = _name;
|
||||||
if (_index != 0 || !simplify) {
|
if (_index != 0 || !simplify) {
|
||||||
stringstream sstr;
|
stringstream sstr;
|
||||||
sstr << '[' << _index << ']';
|
sstr << '[' << _index << ']';
|
||||||
@@ -1084,14 +1083,14 @@ SGPropertyNode::getDisplayName (bool simplify) const
|
|||||||
return display_name;
|
return display_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
string
|
std::string
|
||||||
SGPropertyNode::getPath (bool simplify) const
|
SGPropertyNode::getPath (bool simplify) const
|
||||||
{
|
{
|
||||||
typedef std::vector<SGConstPropertyNode_ptr> PList;
|
typedef std::vector<SGConstPropertyNode_ptr> PList;
|
||||||
PList pathList;
|
PList pathList;
|
||||||
for (const SGPropertyNode* node = this; node->_parent; node = node->_parent)
|
for (const SGPropertyNode* node = this; node->_parent; node = node->_parent)
|
||||||
pathList.push_back(node);
|
pathList.push_back(node);
|
||||||
string result;
|
std::string result;
|
||||||
for (PList::reverse_iterator itr = pathList.rbegin(),
|
for (PList::reverse_iterator itr = pathList.rbegin(),
|
||||||
rend = pathList.rend();
|
rend = pathList.rend();
|
||||||
itr != rend;
|
itr != rend;
|
||||||
@@ -1672,7 +1671,7 @@ bool SGPropertyNode::interpolate( const std::string& type,
|
|||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
bool SGPropertyNode::interpolate( const std::string& type,
|
bool SGPropertyNode::interpolate( const std::string& type,
|
||||||
const PropertyList& values,
|
const simgear::PropertyList& values,
|
||||||
const double_list& deltas,
|
const double_list& deltas,
|
||||||
const std::string& easing )
|
const std::string& easing )
|
||||||
{
|
{
|
||||||
@@ -1810,7 +1809,7 @@ SGPropertyNode::untie ()
|
|||||||
}
|
}
|
||||||
case props::STRING:
|
case props::STRING:
|
||||||
case props::UNSPECIFIED: {
|
case props::UNSPECIFIED: {
|
||||||
string val = getStringValue();
|
std::string val = getStringValue();
|
||||||
clearValue();
|
clearValue();
|
||||||
_type = props::STRING;
|
_type = props::STRING;
|
||||||
_local_val.string_val = copy_string(val.c_str());
|
_local_val.string_val = copy_string(val.c_str());
|
||||||
|
|||||||
+22
-18
@@ -252,15 +252,14 @@ class SGRawBase<T, 0> : public SGRawExtended
|
|||||||
/**
|
/**
|
||||||
* Abstract base class for a raw value.
|
* Abstract base class for a raw value.
|
||||||
*
|
*
|
||||||
* <p>The property manager is implemented in two layers. The {@link
|
* The property manager is implemented in two layers. The SGPropertyNode is the
|
||||||
* SGPropertyNode} is the highest and most abstract layer,
|
* highest and most abstract layer, representing an LValue/RValue pair: it
|
||||||
* representing an LValue/RValue pair: it records the position of the
|
* records the position of the property in the property tree and contains
|
||||||
* property in the property tree and contains facilities for
|
* facilities for navigation to other nodes. It is guaranteed to be persistent:
|
||||||
* navigation to other nodes. It is guaranteed to be persistent: the
|
* the SGPropertyNode will not change during a session, even if the property is
|
||||||
* {@link SGPropertyNode} will not change during a session, even if
|
* bound and unbound multiple times.
|
||||||
* the property is bound and unbound multiple times.</p>
|
|
||||||
*
|
*
|
||||||
* <p>When the property value is not managed internally in the
|
* When the property value is not managed internally in the
|
||||||
* SGPropertyNode, the SGPropertyNode will contain a reference to an
|
* SGPropertyNode, the SGPropertyNode will contain a reference to an
|
||||||
* SGRawValue (this class), which provides an abstract way to get,
|
* SGRawValue (this class), which provides an abstract way to get,
|
||||||
* set, and clone the underlying value. The SGRawValue may change
|
* set, and clone the underlying value. The SGRawValue may change
|
||||||
@@ -268,13 +267,12 @@ class SGRawBase<T, 0> : public SGRawExtended
|
|||||||
* unbound to various data source, but the abstract SGPropertyNode
|
* unbound to various data source, but the abstract SGPropertyNode
|
||||||
* layer insulates the application from those changes.
|
* layer insulates the application from those changes.
|
||||||
*
|
*
|
||||||
* <p>The SGPropertyNode class always keeps a *copy* of a raw value,
|
* The SGPropertyNode class always keeps a *copy* of a raw value, not the
|
||||||
* not the original one passed to it; if you override a derived class
|
* original one passed to it; if you override a derived class but do not replace
|
||||||
* but do not replace the {@link #clone} method, strange things will
|
* the {@link SGRaw::clone clone()} method, strange things will happen.
|
||||||
* happen.</p>
|
|
||||||
*
|
*
|
||||||
* <p>All derived SGRawValue classes must implement {@link #getValue},
|
* All derived SGRawValue classes must implement getValue(), setValue(), and
|
||||||
* {@link #setValue}, and {@link #clone} for the appropriate type.</p>
|
* {@link SGRaw::clone clone()} for the appropriate type.
|
||||||
*
|
*
|
||||||
* @see SGPropertyNode
|
* @see SGPropertyNode
|
||||||
* @see SGRawValuePointer
|
* @see SGRawValuePointer
|
||||||
@@ -696,9 +694,15 @@ class SGPropertyChangeListener
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual ~SGPropertyChangeListener ();
|
virtual ~SGPropertyChangeListener ();
|
||||||
virtual void valueChanged (SGPropertyNode * node);
|
|
||||||
virtual void childAdded (SGPropertyNode * parent, SGPropertyNode * child);
|
/// Called if value of \a node has changed.
|
||||||
virtual void childRemoved (SGPropertyNode * parent, SGPropertyNode * child);
|
virtual void valueChanged(SGPropertyNode * node);
|
||||||
|
|
||||||
|
/// Called if \a child has been added to the given \a parent.
|
||||||
|
virtual void childAdded(SGPropertyNode * parent, SGPropertyNode * child);
|
||||||
|
|
||||||
|
/// Called if \a child has been removed from its \a parent.
|
||||||
|
virtual void childRemoved(SGPropertyNode * parent, SGPropertyNode * child);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
friend class SGPropertyNode;
|
friend class SGPropertyNode;
|
||||||
@@ -1289,7 +1293,7 @@ public:
|
|||||||
*
|
*
|
||||||
* @param type Type of interpolation ("numeric", "color", etc.)
|
* @param type Type of interpolation ("numeric", "color", etc.)
|
||||||
* @param values Nodes containing intermediate and target values
|
* @param values Nodes containing intermediate and target values
|
||||||
* @param duration Durations for each interpolation step (in seconds)
|
* @param deltas Durations for each interpolation step (in seconds)
|
||||||
* @param easing Easing function (http://easings.net/)
|
* @param easing Easing function (http://easings.net/)
|
||||||
*/
|
*/
|
||||||
bool interpolate( const std::string& type,
|
bool interpolate( const std::string& type,
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/** \file
|
||||||
* \file propsfwwd.hxx
|
*
|
||||||
* Forward declarations for properties (and related structures)
|
* Forward declarations for properties (and related structures)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|||||||
@@ -30,6 +30,7 @@
|
|||||||
#include <functional>
|
#include <functional>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <queue>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <boost/tr1/unordered_map.hpp>
|
#include <boost/tr1/unordered_map.hpp>
|
||||||
|
|
||||||
@@ -77,7 +78,8 @@
|
|||||||
#include <simgear/structure/OSGUtils.hxx>
|
#include <simgear/structure/OSGUtils.hxx>
|
||||||
#include <simgear/structure/SGExpression.hxx>
|
#include <simgear/structure/SGExpression.hxx>
|
||||||
#include <simgear/props/vectorPropTemplates.hxx>
|
#include <simgear/props/vectorPropTemplates.hxx>
|
||||||
|
#include <simgear/threads/SGThread.hxx>
|
||||||
|
#include <simgear/threads/SGGuard.hxx>
|
||||||
|
|
||||||
namespace simgear
|
namespace simgear
|
||||||
{
|
{
|
||||||
@@ -87,6 +89,143 @@ using namespace osgUtil;
|
|||||||
|
|
||||||
using namespace effect;
|
using namespace effect;
|
||||||
|
|
||||||
|
class UniformFactoryImpl {
|
||||||
|
public:
|
||||||
|
ref_ptr<Uniform> getUniform( Effect * effect,
|
||||||
|
const string & name,
|
||||||
|
Uniform::Type uniformType,
|
||||||
|
SGConstPropertyNode_ptr valProp,
|
||||||
|
const SGReaderWriterOptions* options );
|
||||||
|
void updateListeners( SGPropertyNode* propRoot );
|
||||||
|
void addListener(DeferredPropertyListener* listener);
|
||||||
|
private:
|
||||||
|
// Default names for vector property components
|
||||||
|
static const char* vec3Names[];
|
||||||
|
static const char* vec4Names[];
|
||||||
|
|
||||||
|
SGMutex _mutex;
|
||||||
|
|
||||||
|
typedef boost::tuple<std::string, Uniform::Type, std::string, std::string> UniformCacheKey;
|
||||||
|
typedef boost::tuple<ref_ptr<Uniform>, SGPropertyChangeListener*> UniformCacheValue;
|
||||||
|
std::map<UniformCacheKey,ref_ptr<Uniform> > uniformCache;
|
||||||
|
|
||||||
|
typedef std::queue<DeferredPropertyListener*> DeferredListenerList;
|
||||||
|
DeferredListenerList deferredListenerList;
|
||||||
|
};
|
||||||
|
|
||||||
|
const char* UniformFactoryImpl::vec3Names[] = {"x", "y", "z"};
|
||||||
|
const char* UniformFactoryImpl::vec4Names[] = {"x", "y", "z", "w"};
|
||||||
|
|
||||||
|
ref_ptr<Uniform> UniformFactoryImpl::getUniform( Effect * effect,
|
||||||
|
const string & name,
|
||||||
|
Uniform::Type uniformType,
|
||||||
|
SGConstPropertyNode_ptr valProp,
|
||||||
|
const SGReaderWriterOptions* options )
|
||||||
|
{
|
||||||
|
SGGuard<SGMutex> scopeLock(_mutex);
|
||||||
|
std::string val = "0";
|
||||||
|
|
||||||
|
if (valProp->nChildren() == 0) {
|
||||||
|
// Completely static value
|
||||||
|
val = valProp->getStringValue();
|
||||||
|
} else {
|
||||||
|
// Value references <parameters> section of Effect
|
||||||
|
const SGPropertyNode* prop = getEffectPropertyNode(effect, valProp);
|
||||||
|
|
||||||
|
if (prop) {
|
||||||
|
if (prop->nChildren() == 0) {
|
||||||
|
// Static value in parameters section
|
||||||
|
val = prop->getStringValue();
|
||||||
|
} else {
|
||||||
|
// Dynamic property value in parameters section
|
||||||
|
val = getGlobalProperty(prop, options);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
SG_LOG(SG_GL,SG_DEBUG,"Invalid parameter " << valProp->getName() << " for uniform " << name << " in Effect ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UniformCacheKey key = boost::make_tuple(name, uniformType, val, effect->getName());
|
||||||
|
ref_ptr<Uniform> uniform = uniformCache[key];
|
||||||
|
|
||||||
|
if (uniform.valid()) {
|
||||||
|
// We've got a hit to cache - simply return it
|
||||||
|
return uniform;
|
||||||
|
}
|
||||||
|
|
||||||
|
SG_LOG(SG_GL,SG_DEBUG,"new uniform " << name << " value " << uniformCache.size());
|
||||||
|
uniformCache[key] = uniform = new Uniform;
|
||||||
|
|
||||||
|
uniform->setName(name);
|
||||||
|
uniform->setType(uniformType);
|
||||||
|
switch (uniformType) {
|
||||||
|
case Uniform::BOOL:
|
||||||
|
initFromParameters(effect, valProp, uniform.get(),
|
||||||
|
static_cast<bool (Uniform::*)(bool)>(&Uniform::set),
|
||||||
|
options);
|
||||||
|
break;
|
||||||
|
case Uniform::FLOAT:
|
||||||
|
initFromParameters(effect, valProp, uniform.get(),
|
||||||
|
static_cast<bool (Uniform::*)(float)>(&Uniform::set),
|
||||||
|
options);
|
||||||
|
break;
|
||||||
|
case Uniform::FLOAT_VEC3:
|
||||||
|
initFromParameters(effect, valProp, uniform.get(),
|
||||||
|
static_cast<bool (Uniform::*)(const Vec3&)>(&Uniform::set),
|
||||||
|
vec3Names, options);
|
||||||
|
break;
|
||||||
|
case Uniform::FLOAT_VEC4:
|
||||||
|
initFromParameters(effect, valProp, uniform.get(),
|
||||||
|
static_cast<bool (Uniform::*)(const Vec4&)>(&Uniform::set),
|
||||||
|
vec4Names, options);
|
||||||
|
break;
|
||||||
|
case Uniform::INT:
|
||||||
|
case Uniform::SAMPLER_1D:
|
||||||
|
case Uniform::SAMPLER_2D:
|
||||||
|
case Uniform::SAMPLER_3D:
|
||||||
|
case Uniform::SAMPLER_1D_SHADOW:
|
||||||
|
case Uniform::SAMPLER_2D_SHADOW:
|
||||||
|
case Uniform::SAMPLER_CUBE:
|
||||||
|
initFromParameters(effect, valProp, uniform.get(),
|
||||||
|
static_cast<bool (Uniform::*)(int)>(&Uniform::set),
|
||||||
|
options);
|
||||||
|
break;
|
||||||
|
default: // avoid compiler warning
|
||||||
|
SG_LOG(SG_ALL,SG_ALERT,"UNKNOWN Uniform type '" << uniformType << "'");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return uniform;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UniformFactoryImpl::addListener(DeferredPropertyListener* listener)
|
||||||
|
{
|
||||||
|
if (listener != 0) {
|
||||||
|
// Uniform requires a property listener. Add it to the list to be
|
||||||
|
// created when the main thread gets to it.
|
||||||
|
deferredListenerList.push(listener);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UniformFactoryImpl::updateListeners( SGPropertyNode* propRoot )
|
||||||
|
{
|
||||||
|
SGGuard<SGMutex> scopeLock(_mutex);
|
||||||
|
|
||||||
|
if (deferredListenerList.empty()) return;
|
||||||
|
|
||||||
|
SG_LOG(SG_GL,SG_DEBUG,"Adding " << deferredListenerList.size() << " listeners for effects.");
|
||||||
|
|
||||||
|
// Instantiate all queued listeners
|
||||||
|
while (! deferredListenerList.empty()) {
|
||||||
|
DeferredPropertyListener* listener = deferredListenerList.front();
|
||||||
|
listener->activate(propRoot);
|
||||||
|
deferredListenerList.pop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef Singleton<UniformFactoryImpl> UniformFactory;
|
||||||
|
|
||||||
|
|
||||||
Effect::Effect()
|
Effect::Effect()
|
||||||
: _cache(0), _isRealized(false)
|
: _cache(0), _isRealized(false)
|
||||||
{
|
{
|
||||||
@@ -104,6 +243,8 @@ Effect::Effect(const Effect& rhs, const CopyOp& copyop)
|
|||||||
techniques.push_back(static_cast<Technique*>(copyop(itr->get())));
|
techniques.push_back(static_cast<Technique*>(copyop(itr->get())));
|
||||||
|
|
||||||
generator = rhs.generator;
|
generator = rhs.generator;
|
||||||
|
_name = rhs._name;
|
||||||
|
_name += " clone";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Assume that the last technique is always valid.
|
// Assume that the last technique is always valid.
|
||||||
@@ -173,10 +314,6 @@ void buildPass(Effect* effect, Technique* tniq, const SGPropertyNode* prop,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Default names for vector property components
|
|
||||||
const char* vec3Names[] = {"x", "y", "z"};
|
|
||||||
const char* vec4Names[] = {"x", "y", "z", "w"};
|
|
||||||
|
|
||||||
osg::Vec4f getColor(const SGPropertyNode* prop)
|
osg::Vec4f getColor(const SGPropertyNode* prop)
|
||||||
{
|
{
|
||||||
if (prop->nChildren() == 0) {
|
if (prop->nChildren() == 0) {
|
||||||
@@ -898,10 +1035,10 @@ struct UniformBuilder :public PassAttributeBuilder
|
|||||||
}
|
}
|
||||||
if (!isAttributeActive(effect, prop))
|
if (!isAttributeActive(effect, prop))
|
||||||
return;
|
return;
|
||||||
const SGPropertyNode* nameProp = prop->getChild("name");
|
SGConstPropertyNode_ptr nameProp = prop->getChild("name");
|
||||||
const SGPropertyNode* typeProp = prop->getChild("type");
|
SGConstPropertyNode_ptr typeProp = prop->getChild("type");
|
||||||
const SGPropertyNode* positionedProp = prop->getChild("positioned");
|
SGConstPropertyNode_ptr positionedProp = prop->getChild("positioned");
|
||||||
const SGPropertyNode* valProp = prop->getChild("value");
|
SGConstPropertyNode_ptr valProp = prop->getChild("value");
|
||||||
string name;
|
string name;
|
||||||
Uniform::Type uniformType = Uniform::FLOAT;
|
Uniform::Type uniformType = Uniform::FLOAT;
|
||||||
if (nameProp) {
|
if (nameProp) {
|
||||||
@@ -941,44 +1078,9 @@ struct UniformBuilder :public PassAttributeBuilder
|
|||||||
} else {
|
} else {
|
||||||
findAttr(uniformTypes, typeProp, uniformType);
|
findAttr(uniformTypes, typeProp, uniformType);
|
||||||
}
|
}
|
||||||
ref_ptr<Uniform> uniform = new Uniform;
|
ref_ptr<Uniform> uniform = UniformFactory::instance()->
|
||||||
uniform->setName(name);
|
getUniform( effect, name, uniformType, valProp, options );
|
||||||
uniform->setType(uniformType);
|
|
||||||
switch (uniformType) {
|
|
||||||
case Uniform::BOOL:
|
|
||||||
initFromParameters(effect, valProp, uniform.get(),
|
|
||||||
static_cast<bool (Uniform::*)(bool)>(&Uniform::set),
|
|
||||||
options);
|
|
||||||
break;
|
|
||||||
case Uniform::FLOAT:
|
|
||||||
initFromParameters(effect, valProp, uniform.get(),
|
|
||||||
static_cast<bool (Uniform::*)(float)>(&Uniform::set),
|
|
||||||
options);
|
|
||||||
break;
|
|
||||||
case Uniform::FLOAT_VEC3:
|
|
||||||
initFromParameters(effect, valProp, uniform.get(),
|
|
||||||
static_cast<bool (Uniform::*)(const Vec3&)>(&Uniform::set),
|
|
||||||
vec3Names, options);
|
|
||||||
break;
|
|
||||||
case Uniform::FLOAT_VEC4:
|
|
||||||
initFromParameters(effect, valProp, uniform.get(),
|
|
||||||
static_cast<bool (Uniform::*)(const Vec4&)>(&Uniform::set),
|
|
||||||
vec4Names, options);
|
|
||||||
break;
|
|
||||||
case Uniform::INT:
|
|
||||||
case Uniform::SAMPLER_1D:
|
|
||||||
case Uniform::SAMPLER_2D:
|
|
||||||
case Uniform::SAMPLER_3D:
|
|
||||||
case Uniform::SAMPLER_1D_SHADOW:
|
|
||||||
case Uniform::SAMPLER_2D_SHADOW:
|
|
||||||
case Uniform::SAMPLER_CUBE:
|
|
||||||
initFromParameters(effect, valProp, uniform.get(),
|
|
||||||
static_cast<bool (Uniform::*)(int)>(&Uniform::set),
|
|
||||||
options);
|
|
||||||
break;
|
|
||||||
default: // avoid compiler warning
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
// optimize common uniforms
|
// optimize common uniforms
|
||||||
if (uniformType == Uniform::SAMPLER_2D || uniformType == Uniform::INT)
|
if (uniformType == Uniform::SAMPLER_2D || uniformType == Uniform::INT)
|
||||||
{
|
{
|
||||||
@@ -1005,6 +1107,7 @@ InstallAttributeBuilder<UniformBuilder> installUniform("uniform");
|
|||||||
|
|
||||||
// Not sure what to do with "name". At one point I wanted to use it to
|
// Not sure what to do with "name". At one point I wanted to use it to
|
||||||
// order the passes, but I do support render bin and stuff too...
|
// order the passes, but I do support render bin and stuff too...
|
||||||
|
// Clément de l'Hamaide 10/2014: "name" is now used in the UniformCacheKey
|
||||||
|
|
||||||
struct NameBuilder : public PassAttributeBuilder
|
struct NameBuilder : public PassAttributeBuilder
|
||||||
{
|
{
|
||||||
@@ -1336,6 +1439,11 @@ bool Effect::realizeTechniques(const SGReaderWriterOptions* options)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Effect::addDeferredPropertyListener(DeferredPropertyListener* listener)
|
||||||
|
{
|
||||||
|
UniformFactory::instance()->addListener(listener);
|
||||||
|
}
|
||||||
|
|
||||||
void Effect::InitializeCallback::doUpdate(osg::Node* node, osg::NodeVisitor* nv)
|
void Effect::InitializeCallback::doUpdate(osg::Node* node, osg::NodeVisitor* nv)
|
||||||
{
|
{
|
||||||
EffectGeode* eg = dynamic_cast<EffectGeode*>(node);
|
EffectGeode* eg = dynamic_cast<EffectGeode*>(node);
|
||||||
@@ -1345,15 +1453,9 @@ void Effect::InitializeCallback::doUpdate(osg::Node* node, osg::NodeVisitor* nv)
|
|||||||
if (!effect)
|
if (!effect)
|
||||||
return;
|
return;
|
||||||
SGPropertyNode* root = getPropertyRoot();
|
SGPropertyNode* root = getPropertyRoot();
|
||||||
for (vector<SGSharedPtr<Updater> >::iterator itr = effect->_extraData.begin(),
|
|
||||||
end = effect->_extraData.end();
|
// Initialize all queued listeners
|
||||||
itr != end;
|
UniformFactory::instance()->updateListeners(root);
|
||||||
++itr) {
|
|
||||||
InitializeWhenAdded* adder
|
|
||||||
= dynamic_cast<InitializeWhenAdded*>(itr->ptr());
|
|
||||||
if (adder)
|
|
||||||
adder->initOnAdd(effect, root);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Effect::Key::EqualTo::operator()(const Effect::Key& lhs,
|
bool Effect::Key::EqualTo::operator()(const Effect::Key& lhs,
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user