Merge branch 'master' of git://github.com/AlericInglewood/SingularityViewer

This commit is contained in:
Siana Gearz
2013-02-17 15:27:28 +01:00
30 changed files with 1268 additions and 348 deletions

82
doc/responders.txt Normal file
View File

@@ -0,0 +1,82 @@
All Responders are derived from ResponderBase, however you normally do never derived from that directly yourself.
Instead, Responder classes are derived from one of:
1. Responder base classes
ResponderHeadersOnly -- Derived classes are used with HTTPClient::head or HTTPClient::getHeaderOnly.
ResponderWithCompleted -- Derived classes implement completed(U32, std::string const&, LLSD const&),
or completedRaw(U32, std::string const&, LLChannelDescriptors const&, buffer_ptr_t const&)
if the response is not (always) LLSD.
ResponderWithResult -- Derived classes implement result(LLSD const&) and optionally
errorWithContent(U32, std::string const&, LLSD const&) OR error(U32, std::string const&).
2. Special base classes
ResponderIgnoreBody -- Same as ResponderWithResult but already implements result() that ignored the body.
LLAssetUploadResponder -- Derived from ResponderWithResult. Base class for responders that upload assets via capabilities.
LegacyPolledResponder -- Used for old code that needs polling (do not use).
There is one non-base class Responder with a more general purpose:
3. Special purpose responders:
ResponderIgnore -- Derived from ResponderIgnoreBody. Used for "fire and forget" requests as it ignores any response.
4. Signatures.
Every final (derived) responder class must implement 'getName(void) const' and 'getHTTPTimeoutPolicy(void)',
except the base classes (this is to alert the developer they have to implement getName as it is pure virtual).
For example:
extern AIHTTPTimeoutPolicy myResponder_timeout; // Add 'P(myResponder)' to indra/llmessage/aihttptimeoutpolicy.cpp.
class MyResponder : public LLHTTPClient::SomeResponderBaseClass {
...
/*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return myResponder_timeout; }
/*virtual*/ char const* getName(void) const { return "MyResponder"; }
};
Note the convention that the name of a AIHTTPTimeoutPolicy (what goes between the brackets of P()) is
the class name minus any 'AI' or 'LL' prefix and starting with a lowercase character.
Then, depending on the three main base classes that was derived from, the signatures should be:
class MyResponder1 : public LLHTTPClient::ResponderHeadersOnly {
/*virtual*/ void completedHeaders(U32 status, std::string const& reason, AIHTTPReceivedHeaders const& headers);
// See for example PostImageResponder
...
};
class MyResponder2 : public LLHTTPClient::ResponderWithCompleted {
/*virtual*/ void completedRaw(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer);
// See for example PostImageRedirectResponder
>>>OR<<<
/*virtual*/ void completed(U32 status, const std::string& reason, const LLSD& content); // See for example LLImportPostResponder
};
class MyResponder3 : public LLHTTPClient::ResponderWithResult {
/*virtual*/ void result(const LLSD& content); // See for example LLInventoryModelFetchItemResponder
/*virtual*/ void error(U32 status, const std::string& reason);
>>>OR instead error()<<<
/*virtual*/ void errorWithContent(U32 status, const std::string& reason, const LLSD& content);
// See for example LLSDMessage::EventResponder
};
Finally, if a responder derived from ResponderWithCompleted or ResponderWithResult needs to process
individual headers, you need to override 'needsHeaders':
/*virtual*/ bool needsHeaders(void) const { return true; } // See for example LLWebProfileResponders::PostImageResponder
// which will cause this to be called:
/*virtual*/ void completedHeaders(U32 status, std::string const& reason, AIHTTPReceivedHeaders const& headers);
And if it needs redirection to work (you'll get an assert if you forget this and it is being redirected):
/*virtual*/ bool followRedir(void) const { return true; } // See for example LLWebProfileResponders::ConfigResponder
This is not necessary for ResponderHeadersOnly because that already defines both.

View File

@@ -562,8 +562,10 @@ namespace dc
fake_channel const warning(1, "WARNING ");
fake_channel const curl(1, "CURL ");
fake_channel const curlio(1, "CURLIO ");
fake_channel const curltr(1, "CURLTR ");
fake_channel const statemachine(1, "STATEMACHINE");
fake_channel const notice(1, "NOTICE ");
fake_channel const snapshot(0, "SNAPSHOT ");
} // namespace dc
} // namespace debug

View File

@@ -82,8 +82,10 @@ struct fake_channel {
extern LL_COMMON_API fake_channel const warning;
extern LL_COMMON_API fake_channel const curl;
extern LL_COMMON_API fake_channel const curlio;
extern LL_COMMON_API fake_channel const curltr;
extern LL_COMMON_API fake_channel const statemachine;
extern LL_COMMON_API fake_channel const notice;
extern LL_COMMON_API fake_channel const snapshot;
} // namespace dc
} // namespace debug
@@ -173,8 +175,8 @@ extern LL_COMMON_API fake_channel const notice;
#include <boost/shared_array.hpp>
#if CWDEBUG_LOCATION
#include <execinfo.h> // Needed for 'backtrace'.
#include "llpreprocessor.h"
#endif
#include "llpreprocessor.h" // LL_COMMON_API
#include <set>
#define CWD_API __attribute__ ((visibility("default")))
@@ -387,21 +389,21 @@ void InstanceTracker<T>::dump(void)
// Print "Entering " << \a data to channel \a cntrl and increment
// debugging output indentation until the end of the current scope.
#define DoutEntering(cntrl, data) \
int __slviewer_debug_indentation = 2; \
int __slviewer_debug_indentation = 2; \
{ \
LIBCWD_TSD_DECLARATION; \
if (LIBCWD_DO_TSD_MEMBER_OFF(::libcwd::libcw_do) < 0) \
{ \
::libcwd::channel_set_bootstrap_st __libcwd_channel_set(LIBCWD_DO_TSD(::libcwd::libcw_do) LIBCWD_COMMA_TSD); \
bool on; \
bool __slviewer_debug_on; \
{ \
using namespace LIBCWD_DEBUGCHANNELS; \
on = (__libcwd_channel_set|cntrl).on; \
__slviewer_debug_on = (__libcwd_channel_set|cntrl).on; \
} \
if (on) \
if (__slviewer_debug_on) \
Dout(cntrl, "Entering " << data); \
else \
__slviewer_debug_indentation = 0; \
__slviewer_debug_indentation = 0; \
} \
} \
debug::Indent __slviewer_debug_indent(__slviewer_debug_indentation);

View File

@@ -106,9 +106,9 @@
// on a compiler that doesn't need this hack.
#define AI_NEED_ACCESS_CC (defined(__GNUC__) && (((__GNUC__ == 4) && (__GNUC_MINOR__ < 3)) || (__GNUC__ < 4)))
template<typename T> struct AIReadAccessConst;
template<typename T> struct AIReadAccess;
template<typename T> struct AIWriteAccess;
template<typename T, typename RWLOCK> struct AIReadAccessConst;
template<typename T, typename RWLOCK> struct AIReadAccess;
template<typename T, typename RWLOCK> struct AIWriteAccess;
template<typename T, typename MUTEX> struct AIAccessConst;
template<typename T, typename MUTEX> struct AIAccess;
template<typename T> struct AISTAccessConst;
@@ -225,17 +225,17 @@ protected:
* </code>
*
*/
template<typename T>
template<typename T, typename RWLOCK = AIRWLock>
class AIThreadSafe : public AIThreadSafeBits<T>
{
protected:
// Only these may access the object (through ptr()).
friend struct AIReadAccessConst<T>;
friend struct AIReadAccess<T>;
friend struct AIWriteAccess<T>;
friend struct AIReadAccessConst<T, RWLOCK>;
friend struct AIReadAccess<T, RWLOCK>;
friend struct AIWriteAccess<T, RWLOCK>;
// Locking control.
AIRWLock mRWLock;
RWLOCK mRWLock;
// For use by AIThreadSafeDC
AIThreadSafe(void) { }
@@ -310,20 +310,20 @@ public:
*
* which is not possible with AITHREADSAFE.
*/
template<typename T>
class AIThreadSafeDC : public AIThreadSafe<T>
template<typename T, typename RWLOCK = AIRWLock>
class AIThreadSafeDC : public AIThreadSafe<T, RWLOCK>
{
public:
// Construct a wrapper around a default constructed object.
AIThreadSafeDC(void) { new (AIThreadSafe<T>::ptr()) T; }
AIThreadSafeDC(void) { new (AIThreadSafe<T, RWLOCK>::ptr()) T; }
// Allow an arbitrary parameter to be passed for construction.
template<typename T2> AIThreadSafeDC(T2 const& val) { new (AIThreadSafe<T>::ptr()) T(val); }
template<typename T2> AIThreadSafeDC(T2 const& val) { new (AIThreadSafe<T, RWLOCK>::ptr()) T(val); }
};
/**
* @brief Read lock object and provide read access.
*/
template<typename T>
template<typename T, typename RWLOCK = AIRWLock>
struct AIReadAccessConst
{
//! Internal enum for the lock-type of the AI*Access object.
@@ -336,8 +336,8 @@ struct AIReadAccessConst
};
//! Construct a AIReadAccessConst from a constant AIThreadSafe.
AIReadAccessConst(AIThreadSafe<T> const& wrapper, bool high_priority = false)
: mWrapper(const_cast<AIThreadSafe<T>&>(wrapper)),
AIReadAccessConst(AIThreadSafe<T, RWLOCK> const& wrapper, bool high_priority = false)
: mWrapper(const_cast<AIThreadSafe<T, RWLOCK>&>(wrapper)),
mState(readlocked)
#if AI_NEED_ACCESS_CC
, mIsCopyConstructed(false)
@@ -369,14 +369,14 @@ struct AIReadAccessConst
protected:
//! Constructor used by AIReadAccess.
AIReadAccessConst(AIThreadSafe<T>& wrapper, state_type state)
AIReadAccessConst(AIThreadSafe<T, RWLOCK>& wrapper, state_type state)
: mWrapper(wrapper), mState(state)
#if AI_NEED_ACCESS_CC
, mIsCopyConstructed(false)
#endif
{ }
AIThreadSafe<T>& mWrapper; //!< Reference to the object that we provide access to.
AIThreadSafe<T, RWLOCK>& mWrapper; //!< Reference to the object that we provide access to.
state_type const mState; //!< The lock state that mWrapper is in.
#if AI_NEED_ACCESS_CC
@@ -393,39 +393,39 @@ private:
/**
* @brief Read lock object and provide read access, with possible promotion to write access.
*/
template<typename T>
struct AIReadAccess : public AIReadAccessConst<T>
template<typename T, typename RWLOCK = AIRWLock>
struct AIReadAccess : public AIReadAccessConst<T, RWLOCK>
{
typedef typename AIReadAccessConst<T>::state_type state_type;
using AIReadAccessConst<T>::readlocked;
typedef typename AIReadAccessConst<T, RWLOCK>::state_type state_type;
using AIReadAccessConst<T, RWLOCK>::readlocked;
//! Construct a AIReadAccess from a non-constant AIThreadSafe.
AIReadAccess(AIThreadSafe<T>& wrapper, bool high_priority = false) : AIReadAccessConst<T>(wrapper, readlocked) { this->mWrapper.mRWLock.rdlock(high_priority); }
AIReadAccess(AIThreadSafe<T, RWLOCK>& wrapper, bool high_priority = false) : AIReadAccessConst<T, RWLOCK>(wrapper, readlocked) { this->mWrapper.mRWLock.rdlock(high_priority); }
protected:
//! Constructor used by AIWriteAccess.
AIReadAccess(AIThreadSafe<T>& wrapper, state_type state) : AIReadAccessConst<T>(wrapper, state) { }
AIReadAccess(AIThreadSafe<T, RWLOCK>& wrapper, state_type state) : AIReadAccessConst<T, RWLOCK>(wrapper, state) { }
friend struct AIWriteAccess<T>;
friend struct AIWriteAccess<T, RWLOCK>;
};
/**
* @brief Write lock object and provide read/write access.
*/
template<typename T>
struct AIWriteAccess : public AIReadAccess<T>
template<typename T, typename RWLOCK = AIRWLock>
struct AIWriteAccess : public AIReadAccess<T, RWLOCK>
{
using AIReadAccessConst<T>::readlocked;
using AIReadAccessConst<T>::read2writelocked;
using AIReadAccessConst<T>::writelocked;
using AIReadAccessConst<T>::write2writelocked;
using AIReadAccessConst<T, RWLOCK>::readlocked;
using AIReadAccessConst<T, RWLOCK>::read2writelocked;
using AIReadAccessConst<T, RWLOCK>::writelocked;
using AIReadAccessConst<T, RWLOCK>::write2writelocked;
//! Construct a AIWriteAccess from a non-constant AIThreadSafe.
AIWriteAccess(AIThreadSafe<T>& wrapper) : AIReadAccess<T>(wrapper, writelocked) { this->mWrapper.mRWLock.wrlock();}
AIWriteAccess(AIThreadSafe<T, RWLOCK>& wrapper) : AIReadAccess<T, RWLOCK>(wrapper, writelocked) { this->mWrapper.mRWLock.wrlock();}
//! Promote read access to write access.
explicit AIWriteAccess(AIReadAccess<T>& access)
: AIReadAccess<T>(access.mWrapper, (access.mState == readlocked) ? read2writelocked : write2writelocked)
explicit AIWriteAccess(AIReadAccess<T, RWLOCK>& access)
: AIReadAccess<T, RWLOCK>(access.mWrapper, (access.mState == readlocked) ? read2writelocked : write2writelocked)
{
if (this->mState == read2writelocked)
{

View File

@@ -397,6 +397,43 @@ public:
#endif
};
#if LL_DEBUG
class LL_COMMON_API AINRLock
{
private:
int read_locked;
int write_locked;
mutable bool mAccessed;
mutable AIThreadID mTheadID;
void accessed(void) const
{
if (!mAccessed)
{
mAccessed = true;
mTheadID.reset();
}
else
{
llassert_always(mTheadID.equals_current_thread());
}
}
public:
AINRLock(void) : read_locked(false), write_locked(false), mAccessed(false) { }
bool isLocked() const { return read_locked || write_locked; }
void rdlock(bool high_priority = false) { accessed(); ++read_locked; }
void rdunlock() { --read_locked; }
void wrlock() { llassert(!isLocked()); accessed(); ++write_locked; }
void wrunlock() { --write_locked; }
void wr2rdlock() { llassert(false); }
void rd2wrlock() { llassert(false); }
};
#endif
//============================================================================
void LLThread::lockData()

View File

@@ -152,7 +152,7 @@ void HTTPTimeout::upload_finished(void)
// ^ ^ ^ ^ ^ ^ ^ ^
// | | | | | | | |
bool HTTPTimeout::data_received(size_t n/*,*/
#ifdef CWDEBUG
#if defined(CWDEBUG) || defined(DEBUG_CURLIO)
ASSERT_ONLY_COMMA(bool upload_error_status)
#else
ASSERT_ONLY_COMMA(bool)
@@ -208,8 +208,9 @@ bool HTTPTimeout::lowspeed(size_t bytes)
//
// We do this as follows: we create low_speed_time (in seconds) buckets and fill them with the number
// of bytes received during that second. We also keep track of the sum of all bytes received between 'now'
// and 'now - llmax(starttime, low_speed_time)'. Then if that period reaches at least low_speed_time
// seconds, and the transfer rate (sum / low_speed_time) is less than low_speed_limit, we abort.
// and 'llmax(starttime, now - low_speed_time)'. Then if that period reaches at least low_speed_time
// seconds (when now >= starttime + low_speed_time) and the transfer rate (sum / low_speed_time) is
// less than low_speed_limit, we abort.
// When are we?
S32 second = (sClockCount - mLowSpeedClock) * sClockWidth;
@@ -244,6 +245,7 @@ bool HTTPTimeout::lowspeed(size_t bytes)
if (s == -1)
{
mBucket = 0; // It doesn't really matter where we start.
mOverwriteSecond = second + low_speed_time;
mTotalBytes = bytes;
mBuckets[mBucket] = bytes;
return false;
@@ -257,11 +259,17 @@ bool HTTPTimeout::lowspeed(size_t bytes)
bucket = 0;
if (++s == second)
break;
mTotalBytes -= mBuckets[bucket];
if (s >= mOverwriteSecond)
{
mTotalBytes -= mBuckets[bucket];
}
mBuckets[bucket] = 0;
}
mBucket = bucket;
mTotalBytes -= mBuckets[mBucket];
if (s >= mOverwriteSecond)
{
mTotalBytes -= mBuckets[mBucket];
}
mTotalBytes += bytes;
mBuckets[mBucket] = bytes;
@@ -286,29 +294,40 @@ bool HTTPTimeout::lowspeed(size_t bytes)
}
// Calculate how long the data transfer may stall until we should timeout.
//
// Assume 6 buckets: 0 1 2 3 4 5 (low_speed_time == 6)
// Seconds since start of transfer: 4 5 6 7 8 9 (mOverwriteSecond == 10)
// Current second: ^
// Data in buckets: A B w x y z (mTotalBytes = A + B; w, x, y and z are undefined)
//
// Obviously, we need to stall at LEAST till second low_speed_time before we can "timeout".
// And possibly more if mTotalBytes is already >= mintotalbytes.
//
// The code below finds 'max_stall_time', so that when from now on the buckets
// are filled with 0, then at 'second + max_stall_time' we should time out,
// meaning that the resulting mTotalBytes after writing 0 at that second
// will be less than mintotalbytes and 'second + max_stall_time' >= low_speed_time.
//
llassert_always(mintotalbytes > 0);
S32 max_stall_time = 0;
U32 dropped_bytes = 0;
while(1)
S32 max_stall_time = low_speed_time - second; // Minimum value.
// Note that if max_stall_time <= 0 here, then second >= low_speed_time and
// thus mTotalBytes >= mintotalbytes because we didn't timeout already above.
if (mTotalBytes >= mintotalbytes)
{
if (++bucket == low_speed_time) // The next second the next bucket will be emptied.
bucket = 0;
++max_stall_time;
dropped_bytes += mBuckets[bucket];
// Note how, when max_stall_time == low_speed_time, dropped_bytes has
// to be equal to mTotalBytes, the sum of all vector elements.
llassert(max_stall_time < low_speed_time || dropped_bytes == mTotalBytes);
// AIFIXME: This is a bug and should really be fixed instead of just be a warning.
if (!(max_stall_time < low_speed_time || dropped_bytes == mTotalBytes))
// In this case max_stall_time has a minimum value equal to when we will reach mOverwriteSecond,
// because that is the first second at which mTotalBytes will decrease.
max_stall_time = mOverwriteSecond - second - 1;
U32 total_bytes = mTotalBytes;
int bucket = -1; // Must be one less as the start bucket, which corresponds with mOverwriteSecond (and thus with the current max_stall_time).
do
{
llwarns << "ASSERT max_stall_time < low_speed_time || dropped_bytes == mTotalBytes failed... aborting. "
"max_stall_time = " << max_stall_time << "; low_speed_time = " << low_speed_time <<
"; dropped_bytes = " << dropped_bytes << "; mTotalBytes = " << mTotalBytes << llendl;
break;
++max_stall_time; // Next second (mOverwriteSecond upon entry of the loop).
++bucket; // The next bucket (0 upon entry of the loop).
// Once we reach the end of the vector total_bytes MUST have reached 0 exactly and we should have left this loop.
llassert_always(bucket < low_speed_time);
total_bytes -= mBuckets[bucket]; // Empty this bucket.
}
// And thus the following will certainly abort.
if (second + max_stall_time >= low_speed_time && mTotalBytes - dropped_bytes < mintotalbytes)
break;
while(total_bytes >= 1); // Use 1 here instead of mintotalbytes, to test that total_bytes indeed always reaches zero.
}
// If this function isn't called again within max_stall_time seconds, we stalled.
mStalled = sClockCount + max_stall_time / sClockWidth;

View File

@@ -81,6 +81,7 @@ class HTTPTimeout : public LLRefCount {
bool mLowSpeedOn; // Set while uploading or downloading data.
bool mUploadFinished; // Used to keep track of whether upload_finished was called yet.
S32 mLastSecond; // The time at which lowspeed() was last called, in seconds since mLowSpeedClock.
S32 mOverwriteSecond; // The second at which the first bucket of this transfer will be overwritten.
U32 mTotalBytes; // The sum of all bytes in mBuckets.
U64 mLowSpeedClock; // Clock count at which low speed detection (re)started.
U64 mStalled; // The clock count at which this transaction is considered to be stalling if nothing is transfered anymore.

View File

@@ -7,6 +7,7 @@
#include <stdarg.h>
#include <cstring>
#include <algorithm>
#include <vector>
#include "llpreprocessor.h"
#include <curl/curl.h>
#define COMPILING_DEBUG_LIBCURL_CC

View File

@@ -82,6 +82,7 @@ set(llui_SOURCE_FILES
set(llui_HEADER_FILES
CMakeLists.txt
ailist.h
llalertdialog.h
llbutton.h
llcallbackmap.h

645
indra/llui/ailist.h Normal file
View File

@@ -0,0 +1,645 @@
/**
* @file ailist.h
* @brief A linked list with iterators that advance when their element is deleted.
*
* Copyright (c) 2013, Aleric Inglewood.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution.
*
* CHANGELOG
* and additional copyright holders.
*
* 05/02/2013
* Initial version, written by Aleric Inglewood @ SL
*/
#ifndef AILIST_H
#define AILIST_H
#include <list>
template<typename T>
class AIList;
template<typename T>
class AIConstListIterator;
/*
* AINode<T>
*
* The actual data stored in a std::list when using AIList<T>.
* T is the template parameter used with AIList.
* count are the number of iterators that currently point to this element.
* dead is 0 or 1, where 1 means that the element was erased from the AIList
* (but not yet from the internal std::list, so that any iterators to it
* are NOT invalidated).
*/
template<typename T>
struct AINode {
T mElement; // The user visual data.
mutable unsigned short count; // Number of iterators pointing to this element.
mutable unsigned short dead; // Whether or not the element is "erased".
AINode(void) : count(0), dead(0) { }
explicit AINode(T const& __val) : mElement(__val), count(0), dead(0) { }
// Equivalence operators.
// __node may not be dead. Dead nodes in the list are "skipped" (obviously), meaning that they are never equal or always unequal.
bool operator==(AINode const& __node) const { llassert(!__node.dead); return mElement == __node.mElement && !dead; }
bool operator!=(AINode const& __node) const { llassert(!__node.dead); return mElement != __node.mElement || dead; }
// Default ordering for sort().
bool operator<(AINode const& __node) const { return mElement < __node.mElement; }
};
/*
* AIListIterator<T>
*
* A non-const iterator to an element of AIList<T>.
*/
template<typename T>
class AIListIterator {
private:
typedef AIListIterator<T> _Self;
typedef std::list<AINode<T> > _Container;
typedef typename _Container::iterator _Iterator;
_Container* mContainer; // A pointer to the associated container, or NULL when (still) singular.
// Note that this code does not allow a container to be destructed while
// any non-end iterators still exist (although that could be legal).
// If an iterator points to end() and the container is destructed then
// this pointer is NOT reset to NULL.
_Iterator mIterator; // Internal iterator to element of mContainer (or singular when mContainer is NULL).
// Increment reference counter for mIterator (if not singular and not end()).
void ref(void)
{
if (mContainer && mContainer->end() != mIterator)
{
// It would be bad a new iterator was created that pointed to a dead element.
// Also, as a sanity check, make sure there aren't a ridiculous number of iterators
// pointing to this element.
llassert(!mIterator->dead && mIterator->count < 100);
++(mIterator->count);
}
}
// Decrement reference counter for mIterator (if not singular and not end()).
// If this was the last iterator pointing to a dead element, then really erase it.
void unref(void)
{
if (mContainer && mContainer->end() != mIterator)
{
llassert(mIterator->count > 0);
if (--(mIterator->count) == 0 && mIterator->dead)
{
mContainer->erase(mIterator);
}
}
}
public:
// Some standard typedefs that have to exist for iterators.
typedef typename _Iterator::difference_type difference_type;
typedef typename _Iterator::iterator_category iterator_category;
typedef T value_type;
typedef T* pointer;
typedef T& reference;
// Construct a singular iterator.
AIListIterator(void) : mContainer(NULL) { }
// Construct an iterator to a given element of std::list. Only for internal use by AIList<T>.
AIListIterator(_Container* __c, _Iterator const& __i) : mContainer(__c), mIterator(__i)
{
llassert(mContainer);
ref();
}
// Copy constructor.
AIListIterator(AIListIterator const& __i) : mContainer(__i.mContainer), mIterator(__i.mIterator)
{
ref();
}
// Destructor.
~AIListIterator()
{
unref();
}
// Assignment operator.
_Self& operator=(_Self const& __x)
{
unref(); // We no longer point to whatever we were pointing.
mContainer = __x.mContainer;
mIterator = __x.mIterator;
llassert(mContainer);
ref(); // We now point an(other) element.
return *this;
}
// Dereference operator.
reference operator*() const
{
// Iterator may not be singular or dead.
llassert(mContainer && !mIterator->dead);
return mIterator->mElement;
}
// Dereference operator.
pointer operator->() const
{
// Iterator may not be singular or dead.
llassert(mContainer && !mIterator->dead);
return &mIterator->mElement;
}
// Pre-increment operator (not being singular is implied).
_Self& operator++()
{
_Iterator cur = mIterator; // Make copy of mIterator.
++cur; // Advance it.
unref(); // We will no longer be pointing to this element. This might invalidate mIterator!
while(cur != mContainer->end() && cur->dead) // Advance till the first non-dead element.
{
++cur;
}
mIterator = cur; // Put result back into mIterator.
ref(); // We are now pointing to a valid element again.
return *this;
}
// Post-increment operator (not being singular is implied).
_Self operator++(int)
{
_Self tmp = *this;
this->operator++();
return tmp;
}
// Pre-decrement operator (not being singular is implied).
_Self& operator--()
{
_Iterator cur = mIterator; // See operator++().
--cur;
unref();
while(cur->dead)
{
--cur;
}
mIterator = cur;
ref();
return *this;
}
// Post-decrement operator (not being singular is implied).
_Self operator--(int)
{
_Self tmp = *this;
this->operator--();
return tmp;
}
// Equivalence operators.
// We allow comparing with dead iterators, because if one of them is not-dead
// then the result is "unequal" anyway, which is probably what you want.
bool operator==(_Self const& __x) const { return mIterator == __x.mIterator; }
bool operator!=(_Self const& __x) const { return mIterator != __x.mIterator; }
friend class AIList<T>;
friend class AIConstListIterator<T>;
template<typename T2> friend bool operator==(AIListIterator<T2> const& __x, AIConstListIterator<T2> const& __y);
template<typename T2> friend bool operator!=(AIListIterator<T2> const& __x, AIConstListIterator<T2> const& __y);
// Return the total number of iterators pointing the element that this iterator is pointing to.
// Unless the iterator points to end, a positive number will be returned since this iterator is
// pointing to the element. If it points to end (or is singular) then 0 is returned.
int count(void) const
{
if (mContainer && mIterator != mContainer->end())
{
return mIterator->count;
}
return 0;
}
};
/*
* AIConstListIterator<T>
*
* A const iterator to an element of AIList<T>.
*
* Because this class is very simular to AIListIterator<T>, see above for detailed comments.
*/
template<typename T>
class AIConstListIterator {
private:
typedef AIConstListIterator<T> _Self;
typedef std::list<AINode<T> > _Container;
typedef typename _Container::iterator _Iterator;
typedef typename _Container::const_iterator _ConstIterator;
typedef AIListIterator<T> iterator;
_Container const* mContainer;
_Iterator mConstIterator; // This has to be an _Iterator instead of _ConstIterator, because the compiler doesn't accept a const_iterator for erase yet (C++11 does).
void ref(void)
{
if (mContainer && mContainer->end() != mConstIterator)
{
llassert(mConstIterator->count < 100);
mConstIterator->count++;
}
}
void unref(void)
{
if (mContainer && mContainer->end() != mConstIterator)
{
llassert(mConstIterator->count > 0);
mConstIterator->count--;
if (mConstIterator->count == 0 && mConstIterator->dead)
{
const_cast<_Container*>(mContainer)->erase(mConstIterator);
}
}
}
public:
typedef typename _ConstIterator::difference_type difference_type;
typedef typename _ConstIterator::iterator_category iterator_category;
typedef T value_type;
typedef T const* pointer;
typedef T const& reference;
AIConstListIterator(void) : mContainer(NULL) { }
AIConstListIterator(_Container const* __c, _Iterator const& __i) : mContainer(__c), mConstIterator(__i)
{
llassert(mContainer);
ref();
}
// Allow to construct a const_iterator from an iterator.
AIConstListIterator(iterator const& __x) : mContainer(__x.mContainer), mConstIterator(__x.mIterator)
{
ref();
}
AIConstListIterator(AIConstListIterator const& __i) : mContainer(__i.mContainer), mConstIterator(__i.mConstIterator)
{
ref();
}
~AIConstListIterator()
{
unref();
}
_Self& operator=(_Self const& __x)
{
unref();
mContainer = __x.mContainer;
mConstIterator = __x.mConstIterator;
llassert(mContainer);
ref();
return *this;
}
// Allow to assign from a non-const iterator.
_Self& operator=(iterator const& __x)
{
unref();
mContainer = __x.mContainer;
mConstIterator = __x.mIterator;
llassert(mContainer);
ref();
return *this;
}
reference operator*() const
{
llassert(mContainer && !mConstIterator->dead);
return mConstIterator->mElement;
}
pointer operator->() const
{
llassert(mContainer && !mConstIterator->dead);
return &mConstIterator->mElement;
}
_Self& operator++()
{
_Iterator cur = mConstIterator;
++cur;
unref();
while(cur != mContainer->end() && cur->dead)
{
++cur;
}
mConstIterator = cur;
ref();
return *this;
}
_Self operator++(int)
{
_Self tmp = *this;
this->operator++();
return tmp;
}
_Self& operator--()
{
_Iterator cur = mConstIterator;
--cur;
unref();
while(cur->dead)
{
--cur;
}
mConstIterator = cur;
ref();
return *this;
}
_Self operator--(int)
{
_Self tmp = *this;
this->operator--();
return tmp;
}
bool operator==(_Self const& __x) const { return mConstIterator == __x.mConstIterator; }
bool operator!=(_Self const& __x) const { return mConstIterator != __x.mConstIterator; }
bool operator==(iterator const& __x) const { return mConstIterator == __x.mIterator; }
bool operator!=(iterator const& __x) const { return mConstIterator != __x.mIterator; }
template<typename T2> friend bool operator==(AIListIterator<T2> const& __x, AIConstListIterator<T2> const& __y);
template<typename T2> friend bool operator!=(AIListIterator<T2> const& __x, AIConstListIterator<T2> const& __y);
int count(void) const
{
if (mContainer && mConstIterator != mContainer->end())
{
return mConstIterator->count;
}
return 0;
}
};
template<typename T>
inline bool operator==(AIListIterator<T> const& __x, AIConstListIterator<T> const& __y)
{
return __x.mIterator == __y.mConstIterator;
}
template<typename T>
inline bool operator!=(AIListIterator<T> const& __x, AIConstListIterator<T> const& __y)
{
return __x.mIterator != __y.mConstIterator;
}
/*
* AIList<T>
*
* A linked list that allows elements to be erased while one or more iterators
* are still pointing to that element, after which pre-increment and pre-decrement
* operators still work.
*
* For example:
*
* for (AIList<int>::iterator i = l.begin(); i != l.end(); ++i)
* {
* int x = *i;
* f(i); // Might erase any element of list l.
* // Should not dereference i anymore here (because it might be erased).
* }
*/
template<typename T>
class AIList {
private:
typedef std::list<AINode<T> > _Container;
typedef typename _Container::iterator _Iterator;
typedef typename _Container::const_iterator _ConstIterator;
_Container mContainer;
size_t mSize;
public:
typedef T value_type;
typedef T* pointer;
typedef T const* const_pointer;
typedef T& reference;
typedef T const& const_reference;
typedef AIListIterator<T> iterator;
typedef AIConstListIterator<T> const_iterator;
typedef std::reverse_iterator<iterator> reverse_iterator;
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
typedef size_t size_type;
typedef ptrdiff_t difference_type;
// Default constructor. Create an empty list.
AIList(void) : mSize(0) { }
#ifdef LL_DEBUG
// Destructor calls clear() to check if there are no iterators left pointing to this list. Destructing an empty list is trivial.
~AIList() { clear(); }
#endif
// Construct a list with __n elements of __val.
explicit AIList(size_type __n, value_type const& __val = value_type()) : mContainer(__n, AINode<T>(__val)), mSize(__n) { }
// Copy constructor.
AIList(AIList const& __list) : mSize(0)
{
for (_ConstIterator __i = __list.mContainer.begin(); __i != __list.mContainer.end(); ++__i)
{
if (!__i->dead)
{
mContainer.push_back(AINode<T>(__i->mElement));
++mSize;
}
}
}
// Construct a list from the range [__first, __last>.
template<typename _InputIterator>
AIList(_InputIterator __first, _InputIterator __last) : mSize(0)
{
for (_InputIterator __i = __first; __i != __last; ++__i)
{
mContainer.push_back(AINode<T>(*__i));
++mSize;
}
}
// Assign from another list.
AIList& operator=(AIList const& __list)
{
clear();
for (_ConstIterator __i = __list.mContainer.begin(); __i != __list.mContainer.end(); ++__i)
{
if (!__i->dead)
{
mContainer.push_back(AINode<T>(__i->mElement));
++mSize;
}
}
return *this;
}
iterator begin()
{
_Iterator __i = mContainer.begin();
while(__i != mContainer.end() && __i->dead)
{
++__i;
}
return iterator(&mContainer, __i);
}
const_iterator begin() const
{
_Iterator __i = const_cast<_Container&>(mContainer).begin();
while(__i != mContainer.end() && __i->dead)
{
++__i;
}
return const_iterator(&mContainer, __i);
}
iterator end() { return iterator(&mContainer, mContainer.end()); }
const_iterator end() const { return const_iterator(&mContainer, const_cast<_Container&>(mContainer).end()); }
reverse_iterator rbegin() { return reverse_iterator(end()); }
const_reverse_iterator rbegin() const { return const_reverse_iterator(end()); }
reverse_iterator rend() { return reverse_iterator(begin()); }
const_reverse_iterator rend() const { return const_reverse_iterator(begin()); }
bool empty() const { return mSize == 0; }
size_type size() const { return mSize; }
size_type max_size() const { return mContainer.max_size(); }
reference front() { iterator __i = begin(); return *__i; }
const_reference front() const { const_iterator __i = begin(); return *__i; }
reference back() { iterator __i = end(); --__i; return *__i; }
const_reference back() const { const_iterator __i = end(); --__i; return *__i; }
void push_front(value_type const& __x)
{
mContainer.push_front(AINode<T>(__x));
++mSize;
}
void pop_front()
{
iterator __i = begin();
erase(__i);
}
void push_back(value_type const& __x)
{
mContainer.push_back(AINode<T>(__x));
++mSize;
}
void pop_back()
{
iterator __i = end();
--__i;
erase(__i);
}
iterator insert(iterator __position, value_type const& __x)
{
++mSize;
return iterator(&mContainer, mContainer.insert(__position.mIterator, AINode<T>(__x)));
}
void clear()
{
#ifdef LL_DEBUG
// There should be no iterators left pointing at any element here.
for (_Iterator __i = mContainer.begin(); __i != mContainer.end(); ++__i)
{
llassert(__i->count == 0);
}
#endif
mContainer.clear();
mSize = 0;
}
iterator erase(iterator __position)
{
// Mark the element __position points to as being erased.
// Iterator may not be singular, point to end, or be dead already.
// Obviously count must be larger than zero since __position is still pointing to it.
llassert(__position.mContainer == &mContainer && __position.mIterator != mContainer.end() && __position.mIterator->count > 0 && !__position.mIterator->dead);
__position.mIterator->dead = 1;
--mSize;
return ++__position;
}
// Remove all elements, designated by the iterator where, for which *where == __val.
void remove(value_type const& __val)
{
_Iterator const __e = mContainer.end();
for (_Iterator __i = mContainer.begin(); __i != __e;)
{
if (!__i->dead && __i->mElement == __val)
{
--mSize;
if (__i->count == 0)
{
mContainer.erase(__i++);
continue;
}
// Mark the element as being erased.
__i->dead = 1;
}
++__i;
}
}
void sort()
{
#ifdef LL_DEBUG
// There should be no iterators left pointing at any element here.
for (_Iterator __i = mContainer.begin(); __i != mContainer.end(); ++__i)
{
llassert(__i->count == 0);
}
#endif
mContainer.sort();
}
template<typename _StrictWeakOrdering>
struct PredWrapper
{
_StrictWeakOrdering mPred;
PredWrapper(_StrictWeakOrdering const& pred) : mPred(pred) { }
bool operator()(AINode<T> const& __x, AINode<T> const& __y) const { return mPred(__x.mElement, __y.mElement); }
};
template<typename _StrictWeakOrdering>
void sort(_StrictWeakOrdering const& pred)
{
#ifdef LL_DEBUG
// There should be no iterators left pointing at any element here.
for (_Iterator __i = mContainer.begin(); __i != mContainer.end(); ++__i)
{
llassert(__i->count == 0);
}
#endif
mContainer.sort(PredWrapper<_StrictWeakOrdering>(pred));
}
};
#endif

View File

@@ -911,6 +911,8 @@ void LLFloater::setMinimized(BOOL minimize)
// Lose keyboard focus when minimized
releaseFocus();
// Also reset mLockedView and mLastKeyboardFocus, to avoid that we get focus back somehow.
gFocusMgr.removeKeyboardFocusWithoutCallback(this);
for (S32 i = 0; i < 4; i++)
{

View File

@@ -55,6 +55,8 @@ BOOL LLFocusableElement::handleUnicodeChar(llwchar uni_char, BOOL called_from_pa
// virtual
LLFocusableElement::~LLFocusableElement()
{
// Make sure nothing is pointing to us anymore!
gFocusMgr.removeKeyboardFocusWithoutCallback(this);
delete mFocusLostCallback;
delete mFocusReceivedCallback;
delete mFocusChangedCallback;
@@ -131,6 +133,7 @@ LLFocusMgr::LLFocusMgr()
mKeyboardFocus( NULL ),
mLastKeyboardFocus( NULL ),
mDefaultKeyboardFocus( NULL ),
mLastDefaultKeyboardFocus( NULL ),
mKeystrokesOnly(FALSE),
mTopCtrl( NULL ),
mAppHasFocus(TRUE), // Macs don't seem to notify us that we've gotten focus, so default to true
@@ -171,6 +174,23 @@ void LLFocusMgr::releaseFocusIfNeeded( const LLView* view )
}
}
void LLFocusMgr::restoreDefaultKeyboardFocus(LLFocusableElement* current_default_focus)
{
if (current_default_focus && mDefaultKeyboardFocus == current_default_focus)
{
setDefaultKeyboardFocus(mLastDefaultKeyboardFocus);
mLastDefaultKeyboardFocus = NULL;
}
}
void LLFocusMgr::restoreKeyboardFocus(LLFocusableElement* current_focus)
{
if (current_focus && mKeyboardFocus == current_focus)
{
setKeyboardFocus(mLastKeyboardFocus);
mLastKeyboardFocus = NULL;
}
}
void LLFocusMgr::setKeyboardFocus(LLFocusableElement* new_focus, BOOL lock, BOOL keystrokes_only)
{
@@ -328,11 +348,22 @@ void LLFocusMgr::removeKeyboardFocusWithoutCallback( const LLFocusableElement* f
{
mLockedView = NULL;
}
if( mKeyboardFocus == focus )
if (mKeyboardFocus == focus)
{
mKeyboardFocus = NULL;
}
if (mLastKeyboardFocus == focus)
{
mLastKeyboardFocus = NULL;
}
if (mDefaultKeyboardFocus == focus)
{
mDefaultKeyboardFocus = NULL;
}
if (mLastDefaultKeyboardFocus == focus)
{
mLastDefaultKeyboardFocus = NULL;
}
}

View File

@@ -84,6 +84,7 @@ public:
// Keyboard Focus
void setKeyboardFocus(LLFocusableElement* new_focus, BOOL lock = FALSE, BOOL keystrokes_only = FALSE); // new_focus = NULL to release the focus.
void restoreKeyboardFocus(LLFocusableElement* current_focus);
LLFocusableElement* getKeyboardFocus() const { return mKeyboardFocus; }
LLFocusableElement* getLastKeyboardFocus() const { return mLastKeyboardFocus; }
BOOL childHasKeyboardFocus( const LLView* parent ) const;
@@ -103,7 +104,8 @@ public:
// If setKeyboardFocus(NULL) is called, and there is a non-NULL default
// keyboard focus view, focus goes there. JC
void setDefaultKeyboardFocus(LLFocusableElement* default_focus) { mDefaultKeyboardFocus = default_focus; }
void setDefaultKeyboardFocus(LLFocusableElement* default_focus) { mLastDefaultKeyboardFocus = mDefaultKeyboardFocus; mDefaultKeyboardFocus = default_focus; }
void restoreDefaultKeyboardFocus(LLFocusableElement* current_default_focus);
LLFocusableElement* getDefaultKeyboardFocus() const { return mDefaultKeyboardFocus; }
@@ -132,6 +134,7 @@ private:
LLFocusableElement* mKeyboardFocus; // Keyboard events are preemptively routed to this object
LLFocusableElement* mLastKeyboardFocus; // who last had focus
LLFocusableElement* mDefaultKeyboardFocus;
LLFocusableElement* mLastDefaultKeyboardFocus;
BOOL mKeystrokesOnly;
// Top View

View File

@@ -77,7 +77,8 @@ LLScrollableContainerView::LLScrollableContainerView( const std::string& name,
mReserveScrollCorner( FALSE ),
mMinAutoScrollRate( MIN_AUTO_SCROLL_RATE ),
mMaxAutoScrollRate( MAX_AUTO_SCROLL_RATE ),
mScrolledView( scrolled_view )
mScrolledView( scrolled_view ),
mPassBackToChildren(true)
{
if( mScrolledView )
{
@@ -218,7 +219,7 @@ BOOL LLScrollableContainerView::handleScrollWheel( S32 x, S32 y, S32 clicks )
{
// Give event to my child views - they may have scroll bars
// (Bad UI design, but technically possible.)
if (LLUICtrl::handleScrollWheel(x,y,clicks))
if (mPassBackToChildren && LLUICtrl::handleScrollWheel(x,y,clicks))
return TRUE;
// When the vertical scrollbar is visible, scroll wheel

View File

@@ -70,6 +70,7 @@ public:
virtual void setValue(const LLSD& value) { mInnerRect.setValue(value); }
void setBorderVisible( BOOL b );
void setPassBackToChildren(bool b) { mPassBackToChildren = b; }
void scrollToShowRect( const LLRect& rect, const LLRect& constraint);
void scrollToShowRect( const LLRect& rect) { scrollToShowRect(rect, LLRect(0, mInnerRect.getHeight(), mInnerRect.getWidth(), 0)); }
@@ -128,6 +129,7 @@ private:
F32 mMinAutoScrollRate;
F32 mMaxAutoScrollRate;
bool mHideScrollbar;
bool mPassBackToChildren;
};

View File

@@ -302,8 +302,8 @@ BOOL LLUICtrl::focusFirstItem(BOOL prefer_text_fields, BOOL focus_flash)
LLCtrlQuery query = getTabOrderQuery();
// sort things such that the default tab group is at the front
query.setSorter(DefaultTabGroupFirstSorter::getInstance());
child_list_t result = query(this);
if(result.size() > 0)
viewList_t result = query(this);
if(!result.empty())
{
LLUICtrl * ctrl = static_cast<LLUICtrl*>(result.front());
if(!ctrl->hasFocus())
@@ -322,7 +322,7 @@ BOOL LLUICtrl::focusFirstItem(BOOL prefer_text_fields, BOOL focus_flash)
{
LLCtrlQuery query = getTabOrderQuery();
query.addPreFilter(LLUICtrl::LLTextInputFilter::getInstance());
child_list_t result = query(this);
viewList_t result = query(this);
if(result.size() > 0)
{
LLUICtrl * ctrl = static_cast<LLUICtrl*>(result.front());
@@ -358,7 +358,7 @@ BOOL LLUICtrl::focusLastItem(BOOL prefer_text_fields)
{
LLCtrlQuery query = getTabOrderQuery();
query.addPreFilter(LLUICtrl::LLTextInputFilter::getInstance());
child_list_t result = query(this);
viewList_t result = query(this);
if(result.size() > 0)
{
LLUICtrl * ctrl = static_cast<LLUICtrl*>(result.back());
@@ -372,7 +372,7 @@ BOOL LLUICtrl::focusLastItem(BOOL prefer_text_fields)
}
}
// no text field found, or we don't care about text fields
child_list_t result = getTabOrderQuery().run(this);
viewList_t result = getTabOrderQuery().run(this);
if(result.size() > 0)
{
LLUICtrl * ctrl = static_cast<LLUICtrl*>(result.back());
@@ -395,7 +395,7 @@ BOOL LLUICtrl::focusNextItem(BOOL text_fields_only)
{
query.addPreFilter(LLUICtrl::LLTextInputFilter::getInstance());
}
child_list_t result = query(this);
viewList_t result = query(this);
return focusNext(result);
}
@@ -407,7 +407,7 @@ BOOL LLUICtrl::focusPrevItem(BOOL text_fields_only)
{
query.addPreFilter(LLUICtrl::LLTextInputFilter::getInstance());
}
child_list_t result = query(this);
viewList_t result = query(this);
return focusPrev(result);
}

View File

@@ -518,21 +518,21 @@ LLRect LLView::getRequiredRect()
BOOL LLView::focusNextRoot()
{
LLView::child_list_t result = LLView::getFocusRootsQuery().run(this);
viewList_t result = LLView::getFocusRootsQuery().run(this);
return LLView::focusNext(result);
}
BOOL LLView::focusPrevRoot()
{
LLView::child_list_t result = LLView::getFocusRootsQuery().run(this);
viewList_t result = LLView::getFocusRootsQuery().run(this);
return LLView::focusPrev(result);
}
// static
BOOL LLView::focusNext(LLView::child_list_t & result)
BOOL LLView::focusNext(viewList_t& result)
{
LLView::child_list_iter_t focused = result.end();
for(LLView::child_list_iter_t iter = result.begin();
viewList_t::iterator focused = result.end();
for(viewList_t::iterator iter = result.begin();
iter != result.end();
++iter)
{
@@ -542,7 +542,7 @@ BOOL LLView::focusNext(LLView::child_list_t & result)
break;
}
}
LLView::child_list_iter_t next = focused;
viewList_t::iterator next = focused;
next = (next == result.end()) ? result.begin() : ++next;
while(next != focused)
{
@@ -565,10 +565,10 @@ BOOL LLView::focusNext(LLView::child_list_t & result)
}
// static
BOOL LLView::focusPrev(LLView::child_list_t & result)
BOOL LLView::focusPrev(viewList_t& result)
{
LLView::child_list_reverse_iter_t focused = result.rend();
for(LLView::child_list_reverse_iter_t iter = result.rbegin();
viewList_t::reverse_iterator focused = result.rend();
for(viewList_t::reverse_iterator iter = result.rbegin();
iter != result.rend();
++iter)
{
@@ -578,7 +578,7 @@ BOOL LLView::focusPrev(LLView::child_list_t & result)
break;
}
}
LLView::child_list_reverse_iter_t next = focused;
viewList_t::reverse_iterator next = focused;
next = (next == result.rend()) ? result.rbegin() : ++next;
while(next != focused)
{
@@ -1170,16 +1170,13 @@ void LLView::drawChildren()
LLView* rootp = getRootView();
++sDepth;
for (child_list_reverse_iter_t child_iter = mChildList.rbegin(); child_iter != mChildList.rend();) // ++child_iter)
for (child_list_const_reverse_iter_t child_iter = mChildList.rbegin(); child_iter != mChildList.rend(); ++child_iter)
{
child_list_reverse_iter_t child = child_iter++;
LLView *viewp = *child;
if (viewp == NULL)
{
continue;
}
LLView *viewp = *child_iter;
if (viewp == NULL)
{
continue;
}
if (viewp->getVisible() && /*viewp != focus_view && */viewp->getRect().isValid())
{

View File

@@ -57,6 +57,7 @@
#include "llinitparam.h"
#include "llfocusmgr.h"
#include <boost/unordered_map.hpp>
#include "ailist.h"
const U32 FOLLOWS_NONE = 0x00;
const U32 FOLLOWS_LEFT = 0x01;
@@ -231,7 +232,7 @@ public:
SNAP_BOTTOM
};
typedef std::list<LLView*> child_list_t;
typedef AIList<LLView*> child_list_t;
typedef child_list_t::iterator child_list_iter_t;
typedef child_list_t::const_iterator child_list_const_iter_t;
typedef child_list_t::reverse_iterator child_list_reverse_iter_t;
@@ -582,9 +583,9 @@ public:
static std::string escapeXML(const std::string& xml, std::string& indent);
// focuses the item in the list after the currently-focused item, wrapping if necessary
static BOOL focusNext(LLView::child_list_t & result);
static BOOL focusNext(viewList_t& result);
// focuses the item in the list before the currently-focused item, wrapping if necessary
static BOOL focusPrev(LLView::child_list_t & result);
static BOOL focusPrev(viewList_t& result);
// returns query for iterating over controls in tab order
static const LLCtrlQuery & getTabOrderQuery();

View File

@@ -74,9 +74,10 @@ filterResult_t LLCtrlFilter::operator() (const LLView* const view, const viewLis
viewList_t LLViewQuery::run(LLView* view) const
{
viewList_t result;
viewList_t const child_list(view->getChildList()->begin(), view->getChildList()->end());
// prefilter gets immediate children of view
filterResult_t pre = runFilters(view, *view->getChildList(), mPreFilters);
filterResult_t pre = runFilters(view, child_list, mPreFilters);
if(!pre.first && !pre.second)
{
// not including ourselves or the children
@@ -113,26 +114,26 @@ viewList_t LLViewQuery::run(LLView* view) const
void LLViewQuery::filterChildren(LLView * view, viewList_t & filtered_children) const
{
LLView::child_list_t views(*(view->getChildList()));
viewList_t views(view->getChildList()->begin(), view->getChildList()->end());
if (mSorterp)
{
(*mSorterp)(view, views); // sort the children per the sorter
}
for(LLView::child_list_iter_t iter = views.begin();
for(viewList_t::iterator iter = views.begin();
iter != views.end();
iter++)
++iter)
{
viewList_t indiv_children = this->run(*iter);
filtered_children.splice(filtered_children.end(), indiv_children);
}
}
filterResult_t LLViewQuery::runFilters(LLView * view, const viewList_t children, const filterList_t filters) const
filterResult_t LLViewQuery::runFilters(LLView* view, viewList_t const& children, filterList_t const& filters) const
{
filterResult_t result = filterResult_t(TRUE, TRUE);
for(filterList_const_iter_t iter = filters.begin();
iter != filters.end();
iter++)
++iter)
{
filterResult_t filtered = (**iter)(view, children);
result.first = result.first && filtered.first;
@@ -143,7 +144,7 @@ filterResult_t LLViewQuery::runFilters(LLView * view, const viewList_t children,
class SortByTabOrder : public LLQuerySorter, public LLSingleton<SortByTabOrder>
{
/*virtual*/ void operator() (LLView * parent, LLView::child_list_t &children) const
/*virtual*/ void operator() (LLView* parent, viewList_t& children) const
{
children.sort(LLCompareByTabOrder(parent->getCtrlOrder()));
}

View File

@@ -126,7 +126,7 @@ public:
private:
filterResult_t runFilters(LLView * view, const viewList_t children, const filterList_t filters) const;
filterResult_t runFilters(LLView* view, viewList_t const& children, filterList_t const& filters) const;
filterList_t mPreFilters;
filterList_t mPostFilters;

View File

@@ -8732,7 +8732,7 @@ This should be as low as possible, but too low may break functionality</string>
<key>LastSnapshotType</key>
<map>
<key>Comment</key>
<string>Select this as next type of snapshot to take (0 = postcard, 1 = texture, 2 = local image)</string>
<string>Select this as next type of snapshot to take (0 = feed, 1 = postcard, 2 = texture, 3 = local image)</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
@@ -14185,6 +14185,50 @@ This should be as low as possible, but too low may break functionality</string>
<key>Value</key>
<integer>0</integer>
</map>
<key>SnapshotFeedKeepAspect</key>
<map>
<key>Comment</key>
<string>When adjusting feed resolution keep its aspect ratio constant and equal to the target aspect.</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>0</integer>
</map>
<key>SnapshotPostcardKeepAspect</key>
<map>
<key>Comment</key>
<string>When adjusting postcard resolution keep its aspect ratio constant and equal to the target aspect.</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>0</integer>
</map>
<key>SnapshotTextureKeepAspect</key>
<map>
<key>Comment</key>
<string>When adjusting texture resolution keep its aspect ratio constant and equal to the target aspect.</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>0</integer>
</map>
<key>SnapshotLocalKeepAspect</key>
<map>
<key>Comment</key>
<string>When adjusting local resolution keep its aspect ratio constant and equal to the target aspect.</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>0</integer>
</map>
<key>SnapshotOpenFreezeTime</key>
<map>
<key>Comment</key>

View File

@@ -278,3 +278,10 @@ void LLContainerView::setDisplayChildren(const BOOL displayChildren)
childp->setVisible(mDisplayChildren);
}
}
void LLContainerView::setScrollContainer(LLScrollableContainerView* scroll)
{
mScrollContainer = scroll;
scroll->setPassBackToChildren(false);
}

View File

@@ -61,7 +61,7 @@ public:
void showLabel(BOOL show) { mShowLabel = show; }
void setDisplayChildren(const BOOL displayChildren);
BOOL getDisplayChildren() { return mDisplayChildren; }
void setScrollContainer(LLScrollableContainerView* scroll) {mScrollContainer = scroll;}
void setScrollContainer(LLScrollableContainerView* scroll);
private:
LLScrollableContainerView* mScrollContainer;

View File

@@ -56,9 +56,9 @@ void LLFloaterEditUI::navigateHierarchyButtonPressed(void* data)
const LLView::child_list_t* viewChildren = view->getChildList();
const LLView::child_list_t* parentChildren = parent->getChildList();
//LLView::child_list_t::iterator
std::list<LLView*>::const_iterator itor;
std::list<LLView*>::size_type idx;
std::list<LLView*>::size_type sidx;
LLView::child_list_t::const_iterator itor;
LLView::child_list_t::size_type idx;
LLView::child_list_t::size_type sidx;
for(idx = 0,itor = parentChildren->begin();itor!=parentChildren->end();itor++,idx++){
if((*itor)==view)break;
}

View File

@@ -91,8 +91,8 @@
///----------------------------------------------------------------------------
/// Local function declarations, constants, enums, and typedefs
///----------------------------------------------------------------------------
S32 LLFloaterSnapshot::sUIWinHeightLong = 619 ;
S32 LLFloaterSnapshot::sUIWinHeightShort = LLFloaterSnapshot::sUIWinHeightLong - 260 ;
S32 LLFloaterSnapshot::sUIWinHeightLong = 625 ;
S32 LLFloaterSnapshot::sUIWinHeightShort = LLFloaterSnapshot::sUIWinHeightLong - 266 ;
S32 LLFloaterSnapshot::sUIWinWidth = 219 ;
S32 const THUMBHEIGHT = 159;
@@ -111,6 +111,8 @@ S32 BORDER_WIDTH = 6;
const S32 MAX_POSTCARD_DATASIZE = 1024 * 1024; // one megabyte
const S32 MAX_TEXTURE_SIZE = 512 ; //max upload texture size 512 * 512
static std::string snapshotKeepAspectName();
///----------------------------------------------------------------------------
/// Class LLSnapshotLivePreview
///----------------------------------------------------------------------------
@@ -172,6 +174,7 @@ public:
BOOL getThumbnailUpToDate() const { return mThumbnailUpToDate ;}
bool getShowFreezeFrameSnapshot() const { return mShowFreezeFrameSnapshot; }
LLViewerTexture* getCurrentImage();
char const* resolutionComboName() const;
char const* aspectComboName() const;
void setSnapshotType(ESnapshotType type) { mSnapshotType = type; }
@@ -305,6 +308,7 @@ public:
static void onClickUICheck(LLUICtrl *ctrl, void* data);
static void onClickHUDCheck(LLUICtrl *ctrl, void* data);
static void onClickKeepOpenCheck(LLUICtrl *ctrl, void* data);
static void onClickKeepAspect(LLUICtrl* ctrl, void* data);
static void onCommitQuality(LLUICtrl* ctrl, void* data);
static void onCommitFeedResolution(LLUICtrl* ctrl, void* data);
static void onCommitPostcardResolution(LLUICtrl* ctrl, void* data);
@@ -327,10 +331,14 @@ public:
static LLSnapshotLivePreview* getPreviewView(void);
static void setResolution(LLFloaterSnapshot* floater, const std::string& comboname, bool visible, bool update_controls = true);
static void setAspect(LLFloaterSnapshot* floater, const std::string& comboname, bool update_controls = true);
static void storeAspectSetting(LLComboBox* combo, const std::string& comboname);
static void enforceAspect(LLFloaterSnapshot* floater, F32 new_aspect);
static void enforceResolution(LLFloaterSnapshot* floater, F32 new_aspect);
static void updateControls(LLFloaterSnapshot* floater, bool delayed_formatted = false);
static void resetFeedAndPostcardAspect(LLFloaterSnapshot* floater);
static void updateLayout(LLFloaterSnapshot* floater);
static void freezeTime(bool on);
static void keepAspect(LLFloaterSnapshot* view, bool on, bool force = false);
static LLHandle<LLView> sPreviewHandle;
@@ -345,7 +353,6 @@ public:
LLToolset* mLastToolset;
boost::signals2::connection mQualityMouseUpConnection;
LLFocusableElement* mPrevDefaultKeyboardFocus;
};
//----------------------------------------------------------------------------
@@ -404,7 +411,7 @@ LLSnapshotLivePreview::LLSnapshotLivePreview (const LLRect& rect) :
mNeedsFlash(TRUE),
mSnapshotQuality(gSavedSettings.getS32("SnapshotQuality")),
mFormattedDataSize(0),
mSnapshotType(SNAPSHOT_FEED),
mSnapshotType((ESnapshotType)gSavedSettings.getS32("LastSnapshotType")),
mSnapshotFormat(LLFloaterSnapshot::ESnapshotFormat(gSavedSettings.getS32("SnapshotFormat"))),
mShowFreezeFrameSnapshot(FALSE),
mCameraPos(LLViewerCamera::getInstance()->getOrigin()),
@@ -1716,14 +1723,12 @@ void LLFloaterSnapshot::Impl::freezeTime(bool on)
}
// Make sure the floater keeps focus so that pressing ESC stops Freeze Time mode.
sInstance->impl.mPrevDefaultKeyboardFocus = gFocusMgr.getDefaultKeyboardFocus();
gFocusMgr.setDefaultKeyboardFocus(sInstance);
}
else if (gSavedSettings.getBOOL("FreezeTime")) // turning off freeze frame mode
{
// Restore default keyboard focus.
gFocusMgr.setDefaultKeyboardFocus(sInstance->impl.mPrevDefaultKeyboardFocus);
sInstance->impl.mPrevDefaultKeyboardFocus = NULL;
gFocusMgr.restoreDefaultKeyboardFocus(sInstance);
gSnapshotFloaterView->setMouseOpaque(FALSE);
@@ -1803,7 +1808,6 @@ void LLFloaterSnapshot::Impl::updateControls(LLFloaterSnapshot* floater, bool de
LLSnapshotLivePreview* previewp = getPreviewView();
if (previewp)
{
previewp->setSnapshotType(shot_type);
LLViewerWindow::ESnapshotType layer_type =
(shot_type == LLSnapshotLivePreview::SNAPSHOT_LOCAL) ?
(LLViewerWindow::ESnapshotType)gSavedSettings.getS32("SnapshotLayerType") :
@@ -1844,6 +1848,7 @@ void LLFloaterSnapshot::Impl::updateControls(LLFloaterSnapshot* floater, bool de
floater->childSetVisible("more_btn", !is_advance); // the only item hidden in advanced mode
floater->childSetVisible("less_btn", is_advance);
floater->childSetVisible("type_label2", is_advance);
floater->childSetVisible("keep_aspect", is_advance);
floater->childSetVisible("type_label3", is_advance);
floater->childSetVisible("format_label", is_advance && is_local);
floater->childSetVisible("local_format_combo", is_local);
@@ -1899,6 +1904,8 @@ void LLFloaterSnapshot::Impl::updateControls(LLFloaterSnapshot* floater, bool de
shot_type == LLSnapshotLivePreview::SNAPSHOT_POSTCARD
&& got_bytes
&& previewp->getDataSize() > MAX_POSTCARD_DATASIZE ? LLColor4::red : gColors.getColor( "LabelTextColor" ));
std::string target_size_str = gSavedSettings.getBOOL(snapshotKeepAspectName()) ? floater->getString("sourceAR") : floater->getString("targetAR");
floater->childSetValue("type_label3", target_size_str);
bool up_to_date = previewp && previewp->getSnapshotUpToDate();
bool can_upload = up_to_date && !previewp->isUsedBy(shot_type);
@@ -1987,6 +1994,11 @@ void LLFloaterSnapshot::Impl::onCommitFeedAspect(LLUICtrl* ctrl, void* data)
previewp->addManualOverride(LLSnapshotLivePreview::SNAPSHOT_FEED);
}
updateAspect(ctrl, data);
LLFloaterSnapshot* floater = (LLFloaterSnapshot*)data;
if (floater && previewp && gSavedSettings.getBOOL(snapshotKeepAspectName()))
{
enforceResolution(floater, previewp->getAspect());
}
}
// static
@@ -2000,6 +2012,11 @@ void LLFloaterSnapshot::Impl::onCommitPostcardAspect(LLUICtrl* ctrl, void* data)
previewp->addManualOverride(LLSnapshotLivePreview::SNAPSHOT_POSTCARD);
}
updateAspect(ctrl, data);
LLFloaterSnapshot* floater = (LLFloaterSnapshot*)data;
if (floater && previewp && gSavedSettings.getBOOL(snapshotKeepAspectName()))
{
enforceResolution(floater, previewp->getAspect());
}
}
// static
@@ -2026,6 +2043,11 @@ void LLFloaterSnapshot::Impl::onCommitLocalAspect(LLUICtrl* ctrl, void* data)
previewp->addManualOverride(LLSnapshotLivePreview::SNAPSHOT_LOCAL);
}
updateAspect(ctrl, data);
LLFloaterSnapshot* floater = (LLFloaterSnapshot*)data;
if (floater && previewp && gSavedSettings.getBOOL(snapshotKeepAspectName()))
{
enforceResolution(floater, previewp->getAspect());
}
}
// static
@@ -2252,6 +2274,18 @@ void LLFloaterSnapshot::Impl::onClickKeepOpenCheck(LLUICtrl* ctrl, void* data)
gSavedSettings.setBOOL( "CloseSnapshotOnKeep", !check->get() );
}
// static
void LLFloaterSnapshot::Impl::onClickKeepAspect(LLUICtrl* ctrl, void* data)
{
LLFloaterSnapshot* view = (LLFloaterSnapshot*)data;
if (view)
{
LLCheckBoxCtrl* check = (LLCheckBoxCtrl*)ctrl;
keepAspect(view, check->get());
updateControls(view);
}
}
// static
void LLFloaterSnapshot::Impl::onCommitQuality(LLUICtrl* ctrl, void* data)
{
@@ -2321,6 +2355,46 @@ static std::string lastSnapshotAspectName()
}
}
static std::string snapshotKeepAspectName()
{
switch(gSavedSettings.getS32("LastSnapshotType"))
{
case LLSnapshotLivePreview::SNAPSHOT_FEED: return "SnapshotFeedKeepAspect";
case LLSnapshotLivePreview::SNAPSHOT_POSTCARD: return "SnapshotPostcardKeepAspect";
case LLSnapshotLivePreview::SNAPSHOT_TEXTURE: return "SnapshotTextureKeepAspect";
default: return "SnapshotLocalKeepAspect";
}
}
// static
void LLFloaterSnapshot::Impl::keepAspect(LLFloaterSnapshot* view, bool on, bool force)
{
DoutEntering(dc::snapshot, "LLFloaterSnapshot::Impl::keepAspect(view, " << on << ", " << force << ")");
bool cur_on = gSavedSettings.getBOOL(snapshotKeepAspectName());
if ((!force && cur_on == on) ||
gSavedSettings.getBOOL("RenderUIInSnapshot") ||
gSavedSettings.getBOOL("RenderHUDInSnapshot"))
{
// No change.
return;
}
view->childSetValue("keep_aspect", on);
gSavedSettings.setBOOL(snapshotKeepAspectName(), on);
if (on)
{
LLSnapshotLivePreview* previewp = getPreviewView();
if (previewp)
{
S32 w = llround(view->childGetValue("snapshot_width").asReal(), 1.0);
S32 h = llround(view->childGetValue("snapshot_height").asReal(), 1.0);
gSavedSettings.setS32(lastSnapshotWidthName(), w);
gSavedSettings.setS32(lastSnapshotHeightName(), h);
comboSetCustom(view, previewp->resolutionComboName());
enforceAspect(view, (F32)w / h);
}
}
}
// static
void LLFloaterSnapshot::Impl::updateResolution(LLUICtrl* ctrl, void* data, bool update_controls)
{
@@ -2332,192 +2406,12 @@ void LLFloaterSnapshot::Impl::updateResolution(LLUICtrl* ctrl, void* data, bool
return;
}
S32 new_width = 0;
S32 new_height = 0;
F32 new_aspect = 0;
LLSnapshotLivePreview* previewp = getPreviewView();
#if 0 // Broken -- not doing this for now.
LLSnapshotLivePreview::ESnapshotType shot_type = (LLSnapshotLivePreview::ESnapshotType)gSavedSettings.getS32("LastSnapshotType");
// Is the snapshot was already used (saved or uploaded) and no manual changes
// have been made since to the current destination type, and the raw snapshot
// is still up to date with regard to visibility of UI, HUD and BufferType etc?
if (previewp && previewp->isUsed() && !previewp->isOverriddenBy(shot_type) && previewp->getRawSnapshotUpToDate())
{
previewp->getSize(new_width, new_height);
new_aspect = previewp->getAspect();
S32 const old_width = new_width;
S32 const old_height = new_height;
F32 const old_aspect = new_aspect;
S32 raw_width;
S32 raw_height;
previewp->getRawSize(raw_width, raw_height);
F32 const raw_aspect = (F32)raw_width / raw_height;
bool fixed_crop = false;
bool fixed_size = false;
bool fixed_scale = false;
bool done = false;
bool fail = false;
while (!done)
{
// Attempt to change the size and aspect so the raw snapshot can also be used for this new destination.
S32 w, h, crop_offset;
bool crop_vertically;
previewp->setSize(new_width, new_height);
previewp->setAspect(new_aspect);
LLSnapshotLivePreview::EAspectSizeProblem ret = previewp->getAspectSizeProblem(w, h, crop_vertically, crop_offset);
switch(ret)
{
case LLSnapshotLivePreview::ASPECTSIZE_OK:
done = true; // Don't change anything (else) if the current settings are usable.
break;
case LLSnapshotLivePreview::CANNOT_CROP_HORIZONTALLY:
case LLSnapshotLivePreview::CANNOT_CROP_VERTICALLY:
if (fixed_crop)
{
done = fail = true;
}
else
{
// Set target aspect to aspect of the raw snapshot we have (no reason to crop anything).
new_aspect = raw_aspect;
fixed_crop = true;
}
break;
case LLSnapshotLivePreview::SIZE_TOO_LARGE:
if (fixed_size)
{
done = fail = true;
}
else
{
if (new_width > w)
{
new_width = w;
new_height = llround(new_width / new_aspect);
}
if (new_height > h)
{
new_width = llmin(w, llround(h * new_aspect));
new_height = llmin(h, llround(new_width / new_aspect));
}
fixed_size = true;
}
break;
case LLSnapshotLivePreview::CANNOT_RESIZE:
if (fixed_scale)
{
done = fail = true;
}
else
{
F32 ratio = llmin((F32)w / new_width, (F32)h / new_height);
new_width = llround(new_width * ratio);
new_height = llround(new_height * ratio);
fixed_scale = true;
}
break;
}
}
previewp->setAspect(old_aspect);
previewp->setSize(old_width, old_height);
if (fail)
{
new_aspect = 0;
new_width = new_height = 0;
}
else
{
LLComboBox* size_combo_box = NULL;
LLComboBox* aspect_combo_box = NULL;
switch(shot_type)
{
case LLSnapshotLivePreview::SNAPSHOT_FEED:
size_combo_box = view->getChild<LLComboBox>("feed_size_combo");
aspect_combo_box = view->getChild<LLComboBox>("feed_aspect_combo");
break;
case LLSnapshotLivePreview::SNAPSHOT_POSTCARD:
size_combo_box = view->getChild<LLComboBox>("postcard_size_combo");
aspect_combo_box = view->getChild<LLComboBox>("postcard_aspect_combo");
break;
case LLSnapshotLivePreview::SNAPSHOT_TEXTURE:
size_combo_box = view->getChild<LLComboBox>("texture_size_combo");
aspect_combo_box = view->getChild<LLComboBox>("texture_aspect_combo");
break;
case LLSnapshotLivePreview::SNAPSHOT_LOCAL:
size_combo_box = view->getChild<LLComboBox>("local_size_combo");
aspect_combo_box = view->getChild<LLComboBox>("local_aspect_combo");
break;
}
S32 index = 0;
S32 const size_custom = size_combo_box->getItemCount() - (shot_type == LLSnapshotLivePreview::SNAPSHOT_TEXTURE ? 0 : 1); // Texture does not end on 'Custom'.
while (index < size_custom)
{
size_combo_box->setCurrentByIndex(index);
std::string sdstring = size_combo_box->getSelectedValue();
LLSD sdres;
std::stringstream sstream(sdstring);
LLSDSerialize::fromNotation(sdres, sstream, sdstring.size());
S32 width = sdres[0];
S32 height = sdres[1];
if (width == 0 || height == 0)
{
width = gViewerWindow->getWindowDisplayWidth();
height = gViewerWindow->getWindowDisplayHeight();
}
if (width == new_width && height == new_height)
{
break;
}
++index;
}
if (index == size_custom && shot_type != LLSnapshotLivePreview::SNAPSHOT_TEXTURE)
{
size_combo_box->setCurrentByIndex(index);
}
index = 0;
S32 const aspect_custom = aspect_combo_box->getItemCount() - 1;
while (index < aspect_custom)
{
aspect_combo_box->setCurrentByIndex(index);
std::string sdstring = aspect_combo_box->getSelectedValue();
std::stringstream sstream;
sstream << sdstring;
F32 aspect;
sstream >> aspect;
if (aspect == -2) // Default
{
aspect = (F32)new_width / new_height;
}
if (aspect == 0) // Current window
{
aspect = (F32)gViewerWindow->getWindowDisplayWidth() / gViewerWindow->getWindowDisplayHeight();
}
if (llabs(aspect - new_aspect) < 0.0001)
{
break;
}
++index;
}
if (index == aspect_custom)
{
aspect_combo_box->setCurrentByIndex(index);
setAspect(view, previewp->aspectComboName(), update_controls);
}
}
}
else
#endif
{
view->getChild<LLComboBox>("feed_size_combo")->selectNthItem(gSavedSettings.getS32("SnapshotFeedLastResolution"));
view->getChild<LLComboBox>("feed_aspect_combo")->selectNthItem(gSavedSettings.getS32("SnapshotFeedLastAspect"));
view->getChild<LLComboBox>("postcard_size_combo")->selectNthItem(gSavedSettings.getS32("SnapshotPostcardLastResolution"));
view->getChild<LLComboBox>("postcard_aspect_combo")->selectNthItem(gSavedSettings.getS32("SnapshotPostcardLastAspect"));
view->getChild<LLComboBox>("texture_size_combo")->selectNthItem(gSavedSettings.getS32("SnapshotTextureLastResolution"));
view->getChild<LLComboBox>("texture_aspect_combo")->selectNthItem(gSavedSettings.getS32("SnapshotTextureLastAspect"));
view->getChild<LLComboBox>("local_size_combo")->selectNthItem(gSavedSettings.getS32("SnapshotLocalLastResolution"));
view->getChild<LLComboBox>("local_aspect_combo")->selectNthItem(gSavedSettings.getS32("SnapshotLocalLastAspect"));
}
view->getChild<LLComboBox>("feed_size_combo")->selectNthItem(gSavedSettings.getS32("SnapshotFeedLastResolution"));
view->getChild<LLComboBox>("postcard_size_combo")->selectNthItem(gSavedSettings.getS32("SnapshotPostcardLastResolution"));
view->getChild<LLComboBox>("texture_size_combo")->selectNthItem(gSavedSettings.getS32("SnapshotTextureLastResolution"));
view->getChild<LLComboBox>("local_size_combo")->selectNthItem(gSavedSettings.getS32("SnapshotLocalLastResolution"));
std::string sdstring = combobox->getSelectedValue();
LLSD sdres;
@@ -2526,6 +2420,12 @@ void LLFloaterSnapshot::Impl::updateResolution(LLUICtrl* ctrl, void* data, bool
S32 width = sdres[0];
S32 height = sdres[1];
if (width != -1 && height != -1)
{
// Not "Custom".
keepAspect(view, false);
}
if (previewp && combobox->getCurrentIndex() >= 0)
{
@@ -2538,15 +2438,8 @@ void LLFloaterSnapshot::Impl::updateResolution(LLUICtrl* ctrl, void* data, bool
}
else if (width == -1 || height == -1)
{
if (previewp->isUsed() && new_width != 0 && new_height != 0)
{
previewp->setSize(new_width, new_height);
}
else
{
// load last custom value
previewp->setSize(gSavedSettings.getS32(lastSnapshotWidthName()), gSavedSettings.getS32(lastSnapshotHeightName()));
}
// load last custom value
previewp->setSize(gSavedSettings.getS32(lastSnapshotWidthName()), gSavedSettings.getS32(lastSnapshotHeightName()));
}
else if (height == -2)
{
@@ -2597,17 +2490,8 @@ void LLFloaterSnapshot::Impl::updateResolution(LLUICtrl* ctrl, void* data, bool
if (previewp)
{
if (new_aspect == 0)
{
// In case the aspect is 'Default', need to update aspect (which will call updateControls, if necessary).
setAspect(view, previewp->aspectComboName(), update_controls);
}
else
{
LLSpinCtrl* aspect_spinner = view->getChild<LLSpinCtrl>("aspect_ratio");
aspect_spinner->set(new_aspect);
previewp->setAspect(new_aspect);
}
// In case the aspect is 'Default', need to update aspect (which will call updateControls, if necessary).
setAspect(view, previewp->aspectComboName(), update_controls);
}
}
@@ -2640,6 +2524,8 @@ void LLFloaterSnapshot::Impl::updateAspect(LLUICtrl* ctrl, void* data, bool upda
S32 width, height;
previewp->getSize(width, height);
aspect = (F32)width / height;
// Turn off "Keep aspect" when aspect is set to Default.
keepAspect(view, false);
}
else if (aspect == -1) // Custom
{
@@ -2651,6 +2537,7 @@ void LLFloaterSnapshot::Impl::updateAspect(LLUICtrl* ctrl, void* data, bool upda
}
LLSpinCtrl* aspect_spinner = view->getChild<LLSpinCtrl>("aspect_ratio");
LLCheckBoxCtrl* keep_aspect = view->getChild<LLCheckBoxCtrl>("keep_aspect");
// Set whether or not the spinners can be changed.
if (gSavedSettings.getBOOL("RenderUIInSnapshot") ||
@@ -2660,11 +2547,13 @@ void LLFloaterSnapshot::Impl::updateAspect(LLUICtrl* ctrl, void* data, bool upda
// Disable without making label gray.
aspect_spinner->setAllowEdit(FALSE);
aspect_spinner->setIncrement(0);
keep_aspect->setEnabled(FALSE);
}
else
{
aspect_spinner->setAllowEdit(TRUE);
aspect_spinner->setIncrement(llmax(0.01f, lltrunc(aspect) / 100.0f));
keep_aspect->setEnabled(TRUE);
}
// Sync the spinner and cache value.
@@ -2685,6 +2574,77 @@ void LLFloaterSnapshot::Impl::updateAspect(LLUICtrl* ctrl, void* data, bool upda
}
}
// static
void LLFloaterSnapshot::Impl::enforceAspect(LLFloaterSnapshot* floater, F32 new_aspect)
{
LLSnapshotLivePreview* previewp = getPreviewView();
if (previewp)
{
LLComboBox* combo = floater->getChild<LLComboBox>(previewp->aspectComboName());
S32 const aspect_custom = combo->getItemCount() - 1;
for (S32 index = 0; index <= aspect_custom; ++index)
{
combo->setCurrentByIndex(index);
if (index == aspect_custom)
{
gSavedSettings.setF32(lastSnapshotAspectName(), new_aspect);
break;
}
std::string sdstring = combo->getSelectedValue();
std::stringstream sstream;
sstream << sdstring;
F32 aspect;
sstream >> aspect;
if (aspect == -2) // Default
{
continue;
}
if (aspect == 0) // Current window
{
aspect = (F32)gViewerWindow->getWindowDisplayWidth() / gViewerWindow->getWindowDisplayHeight();
}
if (llabs(aspect - new_aspect) < 0.0001)
{
break;
}
}
storeAspectSetting(combo, previewp->aspectComboName());
updateAspect(combo, floater, true);
}
}
void LLFloaterSnapshot::Impl::enforceResolution(LLFloaterSnapshot* floater, F32 new_aspect)
{
LLSnapshotLivePreview* previewp = getPreviewView();
if (previewp)
{
// Get current size.
S32 w, h;
previewp->getSize(w, h);
// Do all calculation in floating point.
F32 cw = w;
F32 ch = h;
// Get the current raw size.
previewp->getRawSize(w, h);
F32 rw = w;
F32 rh = h;
// Fit rectangle with aspect new_aspect, around current rectangle, but cropped to raw size.
F32 nw = llmin(llmax(cw, ch * new_aspect), rw);
F32 nh = llmin(llmax(ch, cw / new_aspect), rh);
// Fit rectangle with aspect new_aspect inside that rectangle (in case it was cropped).
nw = llmin(nw, nh * new_aspect);
nh = llmin(nh, nw / new_aspect);
// Round off to nearest integer.
S32 new_width = llround(nw);
S32 new_height = llround(nh);
gSavedSettings.setS32(lastSnapshotWidthName(), new_width);
gSavedSettings.setS32(lastSnapshotHeightName(), new_height);
comboSetCustom(floater, previewp->resolutionComboName());
updateResolution(floater->getChild<LLComboBox>(previewp->resolutionComboName()), floater, false);
}
}
// static
void LLFloaterSnapshot::Impl::onCommitLayerTypes(LLUICtrl* ctrl, void*data)
{
@@ -2703,13 +2663,20 @@ void LLFloaterSnapshot::Impl::onCommitSnapshotType(LLUICtrl* ctrl, void* data)
LLFloaterSnapshot *view = (LLFloaterSnapshot *)data;
if (view)
{
gSavedSettings.setS32("LastSnapshotType", getTypeIndex(view));
LLSnapshotLivePreview::ESnapshotType snapshot_type = getTypeIndex(view);
gSavedSettings.setS32("LastSnapshotType", snapshot_type);
LLSnapshotLivePreview* previewp = getPreviewView();
if (previewp)
{
previewp->setSnapshotType(snapshot_type);
}
keepAspect(view, gSavedSettings.getBOOL(snapshotKeepAspectName()), true);
updateControls(view);
}
}
//static
//static
void LLFloaterSnapshot::Impl::onCommitSnapshotFormat(LLUICtrl* ctrl, void* data)
{
LLFloaterSnapshot *view = (LLFloaterSnapshot *)data;
@@ -2729,7 +2696,12 @@ void LLFloaterSnapshot::Impl::comboSetCustom(LLFloaterSnapshot* floater, const s
LLComboBox* combo = floater->getChild<LLComboBox>(comboname);
combo->setCurrentByIndex(combo->getItemCount() - 1); // "custom" is always the last index
storeAspectSetting(combo, comboname);
}
// static
void LLFloaterSnapshot::Impl::storeAspectSetting(LLComboBox* combo, const std::string& comboname)
{
if(comboname == "feed_size_combo")
{
gSavedSettings.setS32("SnapshotFeedLastResolution", combo->getCurrentIndex());
@@ -2766,8 +2738,11 @@ void LLFloaterSnapshot::Impl::onCommitCustomResolution(LLUICtrl *ctrl, void* dat
LLFloaterSnapshot *view = (LLFloaterSnapshot *)data;
if (view)
{
S32 w = llround(view->childGetValue("snapshot_width").asReal(), 1.0);
S32 h = llround(view->childGetValue("snapshot_height").asReal(), 1.0);
LLSpinCtrl* width_spinner = view->getChild<LLSpinCtrl>("snapshot_width");
LLSpinCtrl* height_spinner = view->getChild<LLSpinCtrl>("snapshot_height");
S32 w = llround((F32)width_spinner->getValue().asReal(), 1.0f);
S32 h = llround((F32)height_spinner->getValue().asReal(), 1.0f);
LLSnapshotLivePreview* previewp = getPreviewView();
if (previewp)
@@ -2777,6 +2752,33 @@ void LLFloaterSnapshot::Impl::onCommitCustomResolution(LLUICtrl *ctrl, void* dat
if (w != curw || h != curh)
{
// Enforce multiple of 32 if the step was 32.
Dout(dc::snapshot, "w = " << w << "; curw = " << curw);
if (llabs(w - curw) == 32)
{
w = (w + 16) & -32;
Dout(dc::snapshot, "w = (w + 16) & -32 = " << w);
}
if (llabs(h - curh) == 32)
{
h = (h + 16) & -32;
}
if (gSavedSettings.getBOOL(snapshotKeepAspectName()))
{
F32 aspect = previewp->getAspect();
if (h == curh)
{
// Width was changed. Change height to keep aspect constant.
h = llround(w / aspect);
}
else
{
// Height was changed. Change width to keep aspect constant.
w = llround(h * aspect);
}
}
width_spinner->forceSetValue(LLSD::Real(w));
height_spinner->forceSetValue(LLSD::Real(h));
previewp->setMaxImageSize((S32)((LLSpinCtrl *)ctrl)->getMaxValue()) ;
previewp->setSize(w,h);
checkAutoSnapshot(previewp, FALSE);
@@ -2794,6 +2796,30 @@ void LLFloaterSnapshot::Impl::onCommitCustomResolution(LLUICtrl *ctrl, void* dat
}
}
char const* LLSnapshotLivePreview::resolutionComboName() const
{
char const* result;
switch(mSnapshotType)
{
case SNAPSHOT_FEED:
result = "feed_size_combo";
break;
case SNAPSHOT_POSTCARD:
result = "postcard_size_combo";
break;
case SNAPSHOT_TEXTURE:
result = "texture_size_combo";
break;
case SNAPSHOT_LOCAL:
result = "local_size_combo";
break;
default:
result= "";
break;
}
return result;
}
char const* LLSnapshotLivePreview::aspectComboName() const
{
char const* result;
@@ -2841,6 +2867,11 @@ void LLFloaterSnapshot::Impl::onCommitCustomAspect(LLUICtrl *ctrl, void* data)
gSavedSettings.setF32(lastSnapshotAspectName(), a);
if (gSavedSettings.getBOOL(snapshotKeepAspectName()))
{
enforceResolution(view, a);
}
updateControls(view, true);
}
}
@@ -2902,6 +2933,7 @@ BOOL LLFloaterSnapshot::postBuild()
childSetCommitCallback("snapshot_height", Impl::onCommitCustomResolution, this);
childSetCommitCallback("aspect_ratio", Impl::onCommitCustomAspect, this);
childSetCommitCallback("keep_aspect", Impl::onClickKeepAspect, this);
childSetCommitCallback("ui_check", Impl::onClickUICheck, this);
childSetValue("ui_check", gSavedSettings.getBOOL("RenderUIInSnapshot"));
@@ -2952,8 +2984,9 @@ BOOL LLFloaterSnapshot::postBuild()
Impl::sPreviewHandle = previewp->getHandle();
impl.updateControls(this);
impl.keepAspect(sInstance, gSavedSettings.getBOOL(snapshotKeepAspectName()), true);
impl.freezeTime(gSavedSettings.getBOOL("SnapshotOpenFreezeTime"));
impl.updateControls(this);
return TRUE;
}

View File

@@ -1513,12 +1513,6 @@ BOOL LLFolderView::handleKeyHere( KEY key, MASK mask )
LLMenuGL::sMenuContainer->hideMenus();
}
LLView *item = NULL;
if (getChildCount() > 0)
{
item = *(getChildList()->begin());
}
switch( key )
{
case KEY_F2:
@@ -2074,6 +2068,12 @@ void LLFolderView::scrollToShowItem(LLFolderViewItem* item, const LLRect& constr
}
}
void LLFolderView::setScrollContainer(LLScrollableContainerView* parent)
{
mScrollContainer = parent;
parent->setPassBackToChildren(false);
}
LLRect LLFolderView::getVisibleRect()
{
S32 visible_height = mScrollContainer->getRect().getHeight();

View File

@@ -217,7 +217,7 @@ public:
void scrollToShowSelection();
void scrollToShowItem(LLFolderViewItem* item, const LLRect& constraint_rect);
void setScrollContainer( LLScrollableContainerView* parent ) { mScrollContainer = parent; }
void setScrollContainer(LLScrollableContainerView* parent);
LLRect getVisibleRect();
BOOL search(LLFolderViewItem* first_item, const std::string &search_string, BOOL backward);

View File

@@ -424,8 +424,8 @@ void LLPanelMediaHUD::setAlpha(F32 alpha)
LLViewQuery query;
LLView* query_view = mMediaFocus ? getChildView("media_focused_controls") : getChildView("media_hover_controls");
child_list_t children = query(query_view);
for (child_list_iter_t child_iter = children.begin();
viewList_t children = query(query_view);
for (viewList_t::iterator child_iter = children.begin();
child_iter != children.end(); ++child_iter)
{
LLUICtrl* ctrl = dynamic_cast<LLUICtrl*>(*child_iter);

View File

@@ -101,7 +101,7 @@ public:
// Used for sorting
struct sort
{
bool operator()(const LLView* i1, const LLView* i2)
bool operator()(const LLView* i1, const LLView* i2) const
{
LLTextureBar* bar1p = (LLTextureBar*)i1;
LLTextureBar* bar2p = (LLTextureBar*)i2;
@@ -120,7 +120,7 @@ public:
struct sort_fetch
{
bool operator()(const LLView* i1, const LLView* i2)
bool operator()(const LLView* i1, const LLView* i2) const
{
LLTextureBar* bar1p = (LLTextureBar*)i1;
LLTextureBar* bar2p = (LLTextureBar*)i2;

View File

@@ -53,16 +53,16 @@
<button bottom_delta="-22" follows="left|top" font="SansSerifSmall" halign="center"
height="20" label="Advanced&gt;&gt;" left="10"
mouse_opaque="true" name="more_btn" scale_image="TRUE"
tool_tip="Advanced Options. Default uses current window size (500x375 for profile feed)." width="72" />
tool_tip="Advanced Options. Default uses current window size ((cropped to) 4:3 for profile feed)." width="72" />
<button bottom_delta="0" follows="left|top" font="SansSerifSmall" halign="center"
height="20" label="&lt;&lt;Default" left_delta="0"
mouse_opaque="true" name="less_btn" scale_image="TRUE"
tool_tip="Advanced Options. Default uses current window size (500x375 for profile feed)." width="72" />
tool_tip="Advanced Options. Default uses current window size ((cropped to) 4:3 for profile feed)." width="72" />
<slider bottom_delta="0" decimal_digits="0" follows="left|top" height="15"
increment="1" initial_val="75" left="80"
max_val="100" min_val="0" name="image_quality_slider" width="150" />
<text bottom_delta="-20" follows="top|left" height="15" left="10" name="type_label2" width="115">
Target size
Target Resolution
</text>
<combo_box bottom_delta="-22" follows="left|top" height="20" label="Resolution" left="10"
name="feed_size_combo" width="125">
@@ -176,14 +176,16 @@
</combo_item>
</combo_box>
<spinner bottom_delta="-25" decimal_digits="0" follows="left|top" height="20"
increment="32" label="Width" label_width="30" left="10" max_val="6016"
increment="32" label="Width" label_width="30" left="14" max_val="6016"
min_val="32" name="snapshot_width" width="95" allow_text_entry="false"/>
<spinner bottom_delta="0" decimal_digits="0" follows="left|top" height="20"
increment="32" label="Height" label_width="35" left="110" max_val="6016"
increment="32" label="Height" label_width="35" left="114" max_val="6016"
min_val="32" name="snapshot_height" width="95" allow_text_entry="false"/>
<text bottom_delta="-18" follows="top|left" height="15" left="10" name="type_label3"
width="115">
Target aspect ratio
<check_box bottom_delta="-14" follows="top|left" label="Keep aspect ratio"
left="10" name="keep_aspect" tool_tip="When changing the resolution keep its aspect ratio the same. This also enforces this aspect ratio to be equal to the target aspect (as if the Aspect was set to Default): changing the target aspect will change the aspect of the resolution. Note: setting the resolution to non-Custom, or the Aspect to Default will reset this check box because they are not compatible." />
<text bottom_delta="-20" follows="top|left" height="15" left="10" name="type_label3"
width="200">
place holder, see targetAR / sourceAR
</text>
<combo_box bottom_delta="-22" follows="left|top" height="20" label="Aspect" left="10"
name="feed_aspect_combo" width="115">
@@ -269,8 +271,8 @@
<spinner bottom_delta="0" decimal_digits="5" follows="left|top" height="20"
increment="0.01" label="" left="130" max_val="32"
min_val="0.03125" name="aspect_ratio" width="64" allow_text_entry="false"/>
<text bottom_delta="-10" height="20" left="196" name="aspect_one_label">:1</text>
<text bottom_delta="-20" follows="left|top" height="20" left="15"
<text bottom_delta="-4" height="20" left="196" name="aspect_one_label">:1</text>
<text bottom_delta="-26" follows="left|top" height="20" left="15"
name="layer_type_label" width="50">
Capture:
</text>
@@ -299,5 +301,11 @@
<string name="unknown">
unknown
</string>
<string name="targetAR">
Target Aspect Ratio
</string>
<string name="sourceAR">
Resolution- AND Target- Aspect Ratio
</string>
</floater>