Merge branch 'master' of https://github.com/singularity-viewer/SingularityViewer.git
This commit is contained in:
@@ -21,6 +21,7 @@ set(aistatemachine_SOURCE_FILES
|
||||
aistatemachine.cpp
|
||||
aistatemachinethread.cpp
|
||||
aitimer.cpp
|
||||
aicondition.cpp
|
||||
)
|
||||
|
||||
set(aistatemachine_HEADER_FILES
|
||||
@@ -29,6 +30,7 @@ set(aistatemachine_HEADER_FILES
|
||||
aistatemachine.h
|
||||
aistatemachinethread.h
|
||||
aitimer.h
|
||||
aicondition.h
|
||||
)
|
||||
|
||||
set_source_files_properties(${aistatemachine_HEADER_FILES}
|
||||
|
||||
89
indra/aistatemachine/aicondition.cpp
Normal file
89
indra/aistatemachine/aicondition.cpp
Normal file
@@ -0,0 +1,89 @@
|
||||
/**
|
||||
* @file aicondition.cpp
|
||||
* @brief Implementation of AICondition
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 14/10/2013
|
||||
* Initial version, written by Aleric Inglewood @ SL
|
||||
*/
|
||||
|
||||
#include "sys.h"
|
||||
#include "aicondition.h"
|
||||
#include "aistatemachine.h"
|
||||
|
||||
void AIConditionBase::wait(AIStateMachine* state_machine)
|
||||
{
|
||||
// The condition must be locked before calling AIStateMachine::wait().
|
||||
llassert(mutex().isSelfLocked());
|
||||
// Add the new state machine at the end.
|
||||
mWaitingStateMachines.push_back(state_machine);
|
||||
}
|
||||
|
||||
void AIConditionBase::remove(AIStateMachine* state_machine)
|
||||
{
|
||||
mutex().lock();
|
||||
// Remove all occurances of state_machine from the queue.
|
||||
queue_t::iterator const end = mWaitingStateMachines.end();
|
||||
queue_t::iterator last = end;
|
||||
for (queue_t::iterator iter = mWaitingStateMachines.begin(); iter != last; ++iter)
|
||||
{
|
||||
if (iter->get() == state_machine)
|
||||
{
|
||||
if (--last == iter)
|
||||
{
|
||||
break;
|
||||
}
|
||||
queue_t::value_type::swap(*iter, *last);
|
||||
}
|
||||
}
|
||||
// This invalidates all iterators involved, including end, but not any iterators to the remaining elements.
|
||||
mWaitingStateMachines.erase(last, end);
|
||||
mutex().unlock();
|
||||
}
|
||||
|
||||
void AIConditionBase::signal(int n)
|
||||
{
|
||||
// The condition must be locked before calling AICondition::signal or AICondition::broadcast.
|
||||
llassert(mutex().isSelfLocked());
|
||||
// Signal n state machines.
|
||||
while (n > 0 && !mWaitingStateMachines.empty())
|
||||
{
|
||||
LLPointer<AIStateMachine> state_machine = mWaitingStateMachines.front();
|
||||
bool success = state_machine->signalled();
|
||||
// Only state machines that are actually still blocked should be in the queue:
|
||||
// they are removed from the queue by calling AICondition::remove whenever
|
||||
// they are unblocked for whatever reason...
|
||||
llassert(success);
|
||||
if (success)
|
||||
{
|
||||
++n;
|
||||
}
|
||||
else
|
||||
{
|
||||
// We never get here...
|
||||
remove(state_machine.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
110
indra/aistatemachine/aicondition.h
Normal file
110
indra/aistatemachine/aicondition.h
Normal file
@@ -0,0 +1,110 @@
|
||||
/**
|
||||
* @file aicondition.h
|
||||
* @brief Condition variable for statemachines.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 14/10/2013
|
||||
* Initial version, written by Aleric Inglewood @ SL
|
||||
*/
|
||||
|
||||
#ifndef AICONDITION_H
|
||||
#define AICONDITION_H
|
||||
|
||||
#include <deque>
|
||||
#include <llpointer.h>
|
||||
#include "aithreadsafe.h"
|
||||
|
||||
class AIStateMachine;
|
||||
class LLMutex;
|
||||
|
||||
// class AICondition
|
||||
//
|
||||
// Call AIStateMachine::wait(AICondition&) in the multiplex_impl of a state machine to
|
||||
// make the state machine go idle until some thread calls AICondition::signal().
|
||||
//
|
||||
// If the state machine is no longer running or wasn't waiting anymore because
|
||||
// something else woke it up, then AICondition::signal() will wake up another
|
||||
// state machine (if any).
|
||||
//
|
||||
// Usage:
|
||||
//
|
||||
// struct Foo { bool met(); }; // Returns true when the condition is met.
|
||||
// AICondition<Foo> Condition_t;
|
||||
// AIAccess<Foo> Condition_wat;
|
||||
//
|
||||
// // Some thread-safe condition variable.
|
||||
// Condition_t condition;
|
||||
//
|
||||
// // Inside the state machine:
|
||||
// {
|
||||
// ...
|
||||
// state WAIT_FOR_CONDITION:
|
||||
// {
|
||||
// // Lock condition and check it. Wait if condition is not met yet.
|
||||
// {
|
||||
// Condition_wat condition_w(condition);
|
||||
// if (!condition_w->met())
|
||||
// {
|
||||
// wait(condition);
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// set_state(CONDITION_MET);
|
||||
// break;
|
||||
// }
|
||||
// CONDITION_MET:
|
||||
// {
|
||||
//
|
||||
|
||||
class AIConditionBase
|
||||
{
|
||||
public:
|
||||
virtual ~AIConditionBase() { }
|
||||
|
||||
void signal(int n = 1); // Call this when the condition was met to release n state machines.
|
||||
void broadcast(void) { signal(mWaitingStateMachines.size()); } // Release all blocked state machines.
|
||||
|
||||
private:
|
||||
// These functions are called by AIStateMachine.
|
||||
friend class AIStateMachine;
|
||||
void wait(AIStateMachine* state_machine);
|
||||
void remove(AIStateMachine* state_machine);
|
||||
|
||||
protected:
|
||||
virtual LLMutex& mutex(void) = 0;
|
||||
|
||||
protected:
|
||||
typedef std::deque<LLPointer<AIStateMachine> > queue_t;
|
||||
queue_t mWaitingStateMachines;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class AICondition : public AIThreadSafeSimpleDC<T>, public AIConditionBase
|
||||
{
|
||||
protected:
|
||||
/*virtual*/ LLMutex& mutex(void) { return this->mMutex; }
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
|
||||
#include "linden_common.h"
|
||||
#include "aistatemachine.h"
|
||||
#include "aicondition.h"
|
||||
#include "lltimer.h"
|
||||
|
||||
//==================================================================
|
||||
@@ -283,7 +284,7 @@ char const* HelloWorld::state_str_impl(state_type run_state) const
|
||||
|
||||
void AIEngine::add(AIStateMachine* state_machine)
|
||||
{
|
||||
Dout(dc::statemachine, "Adding state machine [" << (void*)state_machine << "] to " << mName);
|
||||
Dout(dc::statemachine(state_machine->mSMDebug), "Adding state machine [" << (void*)state_machine << "] to " << mName);
|
||||
engine_state_type_wat engine_state_w(mEngineState);
|
||||
engine_state_w->list.push_back(QueueElement(state_machine));
|
||||
if (engine_state_w->waiting)
|
||||
@@ -330,7 +331,7 @@ void AIEngine::mainloop(void)
|
||||
engine_state_type_wat engine_state_w(mEngineState);
|
||||
if (!active)
|
||||
{
|
||||
Dout(dc::statemachine, "Erasing state machine [" << (void*)&state_machine << "] from " << mName);
|
||||
Dout(dc::statemachine(state_machine.mSMDebug), "Erasing state machine [" << (void*)&state_machine << "] from " << mName);
|
||||
engine_state_w->list.erase(queued_element++);
|
||||
}
|
||||
else
|
||||
@@ -392,7 +393,7 @@ void AIStateMachine::multiplex(event_type event)
|
||||
// If this fails then you are using a pointer to a state machine instead of an LLPointer.
|
||||
llassert(event == initial_run || getNumRefs() > 0);
|
||||
|
||||
DoutEntering(dc::statemachine, "AIStateMachine::multiplex(" << event_str(event) << ") [" << (void*)this << "]");
|
||||
DoutEntering(dc::statemachine(mSMDebug), "AIStateMachine::multiplex(" << event_str(event) << ") [" << (void*)this << "]");
|
||||
|
||||
base_state_type state;
|
||||
state_type run_state;
|
||||
@@ -407,7 +408,7 @@ void AIStateMachine::multiplex(event_type event)
|
||||
llassert(!mMultiplexMutex.isSelfLocked()); // We may never enter recursively!
|
||||
if (!mMultiplexMutex.tryLock())
|
||||
{
|
||||
Dout(dc::statemachine, "Leaving because it is already being run [" << (void*)this << "]");
|
||||
Dout(dc::statemachine(mSMDebug), "Leaving because it is already being run [" << (void*)this << "]");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -421,7 +422,7 @@ void AIStateMachine::multiplex(event_type event)
|
||||
// we should indeed run, again.
|
||||
if (event == schedule_run && !sub_state_type_rat(mSubState)->need_run)
|
||||
{
|
||||
Dout(dc::statemachine, "Leaving because it was already being run [" << (void*)this << "]");
|
||||
Dout(dc::statemachine(mSMDebug), "Leaving because it was already being run [" << (void*)this << "]");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -440,9 +441,9 @@ void AIStateMachine::multiplex(event_type event)
|
||||
{
|
||||
#ifdef CWDEBUG
|
||||
if (state == bs_multiplex)
|
||||
Dout(dc::statemachine, "Running state bs_multiplex / " << state_str_impl(run_state) << " [" << (void*)this << "]");
|
||||
Dout(dc::statemachine(mSMDebug), "Running state bs_multiplex / " << state_str_impl(run_state) << " [" << (void*)this << "]");
|
||||
else
|
||||
Dout(dc::statemachine, "Running state " << state_str(state) << " [" << (void*)this << "]");
|
||||
Dout(dc::statemachine(mSMDebug), "Running state " << state_str(state) << " [" << (void*)this << "]");
|
||||
#endif
|
||||
|
||||
#ifdef SHOW_ASSERT
|
||||
@@ -503,7 +504,7 @@ void AIStateMachine::multiplex(event_type event)
|
||||
// run of bs_reset is not a problem because it happens to be a NoOp.
|
||||
state = (state == bs_initialize) ? bs_reset : bs_abort;
|
||||
#ifdef CWDEBUG
|
||||
Dout(dc::statemachine, "Late abort detected! Running state " << state_str(state) << " instead [" << (void*)this << "]");
|
||||
Dout(dc::statemachine(mSMDebug), "Late abort detected! Running state " << state_str(state) << " instead [" << (void*)this << "]");
|
||||
#endif
|
||||
}
|
||||
#ifdef SHOW_ASSERT
|
||||
@@ -665,7 +666,7 @@ void AIStateMachine::multiplex(event_type event)
|
||||
|
||||
#ifdef CWDEBUG
|
||||
if (state != state_w->base_state)
|
||||
Dout(dc::statemachine, "Base state changed from " << state_str(state) << " to " << state_str(state_w->base_state) <<
|
||||
Dout(dc::statemachine(mSMDebug), "Base state changed from " << state_str(state) << " to " << state_str(state_w->base_state) <<
|
||||
"; need_new_run = " << (need_new_run ? "true" : "false") << " [" << (void*)this << "]");
|
||||
#endif
|
||||
}
|
||||
@@ -699,11 +700,15 @@ void AIStateMachine::multiplex(event_type event)
|
||||
// Mark that we're added to this engine, and at the same time, that we're not added to the previous one.
|
||||
state_w->current_engine = engine;
|
||||
}
|
||||
#ifdef SHOW_ASSERT
|
||||
// We are leaving the loop, but we're not idle. The statemachine should re-enter the loop again.
|
||||
mDebugShouldRun = true;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
// Remove this state machine from any engine.
|
||||
// Cause the engine to remove us.
|
||||
// Remove this state machine from any engine,
|
||||
// causing the engine to remove us.
|
||||
state_w->current_engine = NULL;
|
||||
}
|
||||
|
||||
@@ -749,7 +754,7 @@ void AIStateMachine::multiplex(event_type event)
|
||||
|
||||
AIStateMachine::state_type AIStateMachine::begin_loop(base_state_type base_state)
|
||||
{
|
||||
DoutEntering(dc::statemachine, "AIStateMachine::begin_loop(" << state_str(base_state) << ") [" << (void*)this << "]");
|
||||
DoutEntering(dc::statemachine(mSMDebug), "AIStateMachine::begin_loop(" << state_str(base_state) << ") [" << (void*)this << "]");
|
||||
|
||||
sub_state_type_wat sub_state_w(mSubState);
|
||||
// Honor a subsequent call to idle() (only necessary in bs_multiplex, but it doesn't hurt to reset this flag in other states too).
|
||||
@@ -759,7 +764,7 @@ AIStateMachine::state_type AIStateMachine::begin_loop(base_state_type base_state
|
||||
// Honor previous calls to advance_state() (once run_state is initialized).
|
||||
if (base_state == bs_multiplex && sub_state_w->advance_state > sub_state_w->run_state)
|
||||
{
|
||||
Dout(dc::statemachine, "Copying advance_state to run_state, because it is larger [" << state_str_impl(sub_state_w->advance_state) << " > " << state_str_impl(sub_state_w->run_state) << "]");
|
||||
Dout(dc::statemachine(mSMDebug), "Copying advance_state to run_state, because it is larger [" << state_str_impl(sub_state_w->advance_state) << " > " << state_str_impl(sub_state_w->run_state) << "]");
|
||||
sub_state_w->run_state = sub_state_w->advance_state;
|
||||
}
|
||||
#ifdef SHOW_ASSERT
|
||||
@@ -789,7 +794,7 @@ AIStateMachine::state_type AIStateMachine::begin_loop(base_state_type base_state
|
||||
|
||||
void AIStateMachine::run(AIStateMachine* parent, state_type new_parent_state, bool abort_parent, bool on_abort_signal_parent, AIEngine* default_engine)
|
||||
{
|
||||
DoutEntering(dc::statemachine, "AIStateMachine::run(" <<
|
||||
DoutEntering(dc::statemachine(mSMDebug), "AIStateMachine::run(" <<
|
||||
(void*)parent << ", " <<
|
||||
(parent ? parent->state_str_impl(new_parent_state) : "NA") <<
|
||||
", abort_parent = " << (abort_parent ? "true" : "false") <<
|
||||
@@ -839,7 +844,7 @@ void AIStateMachine::run(AIStateMachine* parent, state_type new_parent_state, bo
|
||||
|
||||
void AIStateMachine::run(callback_type::signal_type::slot_type const& slot, AIEngine* default_engine)
|
||||
{
|
||||
DoutEntering(dc::statemachine, "AIStateMachine::run(<slot>, default_engine = " << default_engine->name() << ") [" << (void*)this << "]");
|
||||
DoutEntering(dc::statemachine(mSMDebug), "AIStateMachine::run(<slot>, default_engine = " << default_engine->name() << ") [" << (void*)this << "]");
|
||||
|
||||
#ifdef SHOW_ASSERT
|
||||
{
|
||||
@@ -874,7 +879,7 @@ void AIStateMachine::run(callback_type::signal_type::slot_type const& slot, AIEn
|
||||
|
||||
void AIStateMachine::callback(void)
|
||||
{
|
||||
DoutEntering(dc::statemachine, "AIStateMachine::callback() [" << (void*)this << "]");
|
||||
DoutEntering(dc::statemachine(mSMDebug), "AIStateMachine::callback() [" << (void*)this << "]");
|
||||
|
||||
bool aborted = sub_state_type_rat(mSubState)->aborted;
|
||||
if (mParent)
|
||||
@@ -920,7 +925,7 @@ void AIStateMachine::force_killed(void)
|
||||
|
||||
void AIStateMachine::kill(void)
|
||||
{
|
||||
DoutEntering(dc::statemachine, "AIStateMachine::kill() [" << (void*)this << "]");
|
||||
DoutEntering(dc::statemachine(mSMDebug), "AIStateMachine::kill() [" << (void*)this << "]");
|
||||
#ifdef SHOW_ASSERT
|
||||
{
|
||||
multiplex_state_type_rat state_r(mState);
|
||||
@@ -937,7 +942,7 @@ void AIStateMachine::kill(void)
|
||||
|
||||
void AIStateMachine::reset()
|
||||
{
|
||||
DoutEntering(dc::statemachine, "AIStateMachine::reset() [" << (void*)this << "]");
|
||||
DoutEntering(dc::statemachine(mSMDebug), "AIStateMachine::reset() [" << (void*)this << "]");
|
||||
#ifdef SHOW_ASSERT
|
||||
mDebugAborted = false;
|
||||
mDebugContPending = false;
|
||||
@@ -960,6 +965,8 @@ void AIStateMachine::reset()
|
||||
sub_state_w->reset = true;
|
||||
// Start running.
|
||||
sub_state_w->idle = false;
|
||||
// We're not waiting for a condition.
|
||||
sub_state_w->blocked = NULL;
|
||||
// Keep running till we reach at least bs_multiplex.
|
||||
sub_state_w->need_run = true;
|
||||
}
|
||||
@@ -972,7 +979,7 @@ void AIStateMachine::reset()
|
||||
|
||||
void AIStateMachine::set_state(state_type new_state)
|
||||
{
|
||||
DoutEntering(dc::statemachine, "AIStateMachine::set_state(" << state_str_impl(new_state) << ") [" << (void*)this << "]");
|
||||
DoutEntering(dc::statemachine(mSMDebug), "AIStateMachine::set_state(" << state_str_impl(new_state) << ") [" << (void*)this << "]");
|
||||
#ifdef SHOW_ASSERT
|
||||
{
|
||||
multiplex_state_type_rat state_r(mState);
|
||||
@@ -983,6 +990,8 @@ void AIStateMachine::set_state(state_type new_state)
|
||||
}
|
||||
#endif
|
||||
sub_state_type_wat sub_state_w(mSubState);
|
||||
// It should never happen that set_state() is called while we're blocked.
|
||||
llassert(!sub_state_w->blocked);
|
||||
// Force current state to the requested state.
|
||||
sub_state_w->run_state = new_state;
|
||||
// Void last call to advance_state.
|
||||
@@ -999,13 +1008,13 @@ void AIStateMachine::set_state(state_type new_state)
|
||||
|
||||
void AIStateMachine::advance_state(state_type new_state)
|
||||
{
|
||||
DoutEntering(dc::statemachine, "AIStateMachine::advance_state(" << state_str_impl(new_state) << ") [" << (void*)this << "]");
|
||||
DoutEntering(dc::statemachine(mSMDebug), "AIStateMachine::advance_state(" << state_str_impl(new_state) << ") [" << (void*)this << "]");
|
||||
{
|
||||
sub_state_type_wat sub_state_w(mSubState);
|
||||
// Ignore call to advance_state when the currently queued state is already greater or equal to the requested state.
|
||||
if (sub_state_w->advance_state >= new_state)
|
||||
{
|
||||
Dout(dc::statemachine, "Ignored, because " << state_str_impl(sub_state_w->advance_state) << " >= " << state_str_impl(new_state) << ".");
|
||||
Dout(dc::statemachine(mSMDebug), "Ignored, because " << state_str_impl(sub_state_w->advance_state) << " >= " << state_str_impl(new_state) << ".");
|
||||
return;
|
||||
}
|
||||
// Ignore call to advance_state when the current state is greater than the requested state: the new state would be
|
||||
@@ -1014,7 +1023,7 @@ void AIStateMachine::advance_state(state_type new_state)
|
||||
// the state change is and should be being ignored: the statemachine would start running it's current state (again).
|
||||
if (sub_state_w->run_state > new_state)
|
||||
{
|
||||
Dout(dc::statemachine, "Ignored, because " << state_str_impl(sub_state_w->run_state) << " > " << state_str_impl(new_state) << " (current state).");
|
||||
Dout(dc::statemachine(mSMDebug), "Ignored, because " << state_str_impl(sub_state_w->run_state) << " > " << state_str_impl(new_state) << " (current state).");
|
||||
return;
|
||||
}
|
||||
// Increment state.
|
||||
@@ -1023,6 +1032,13 @@ void AIStateMachine::advance_state(state_type new_state)
|
||||
sub_state_w->idle = false;
|
||||
// Ignore a call to idle if it occurs before we leave multiplex_impl().
|
||||
sub_state_w->skip_idle = true;
|
||||
// No longer say we woke up when signalled() is called.
|
||||
if (sub_state_w->blocked)
|
||||
{
|
||||
Dout(dc::statemachine(mSMDebug), "Removing statemachine from condition " << (void*)sub_state_w->blocked);
|
||||
sub_state_w->blocked->remove(this);
|
||||
sub_state_w->blocked = NULL;
|
||||
}
|
||||
// Mark that a re-entry of multiplex() is necessary.
|
||||
sub_state_w->need_run = true;
|
||||
#ifdef SHOW_ASSERT
|
||||
@@ -1048,7 +1064,7 @@ void AIStateMachine::advance_state(state_type new_state)
|
||||
|
||||
void AIStateMachine::idle(void)
|
||||
{
|
||||
DoutEntering(dc::statemachine, "AIStateMachine::idle() [" << (void*)this << "]");
|
||||
DoutEntering(dc::statemachine(mSMDebug), "AIStateMachine::idle() [" << (void*)this << "]");
|
||||
#ifdef SHOW_ASSERT
|
||||
{
|
||||
multiplex_state_type_rat state_r(mState);
|
||||
@@ -1066,7 +1082,7 @@ void AIStateMachine::idle(void)
|
||||
// Ignore call to idle() when advance_state() was called since last call to set_state().
|
||||
if (sub_state_w->skip_idle)
|
||||
{
|
||||
Dout(dc::statemachine, "Ignored, because skip_idle is true (advance_state() was called last).");
|
||||
Dout(dc::statemachine(mSMDebug), "Ignored, because skip_idle is true (advance_state() was called last).");
|
||||
return;
|
||||
}
|
||||
// Mark that we are idle.
|
||||
@@ -1075,13 +1091,54 @@ void AIStateMachine::idle(void)
|
||||
mSleep = 0;
|
||||
}
|
||||
|
||||
// This function is very much like idle().
|
||||
void AIStateMachine::wait(AIConditionBase& condition)
|
||||
{
|
||||
DoutEntering(dc::statemachine(mSMDebug), "AIStateMachine::wait(" << (void*)&condition << ") [" << (void*)this << "]");
|
||||
#ifdef SHOW_ASSERT
|
||||
{
|
||||
multiplex_state_type_rat state_r(mState);
|
||||
// wait() may only be called multiplex_impl().
|
||||
llassert(state_r->base_state == bs_multiplex);
|
||||
// May only be called by the thread that is holding mMultiplexMutex.
|
||||
llassert(mThreadId.equals_current_thread());
|
||||
}
|
||||
// wait() following set_state() cancels the reason to run because of the call to set_state.
|
||||
mDebugSetStatePending = false;
|
||||
#endif
|
||||
sub_state_type_wat sub_state_w(mSubState);
|
||||
// As wait() may only be called from within the state machine, it should never happen that the state machine is already idle.
|
||||
llassert(!sub_state_w->idle);
|
||||
// Ignore call to wait() when advance_state() was called since last call to set_state().
|
||||
if (sub_state_w->skip_idle)
|
||||
{
|
||||
Dout(dc::statemachine(mSMDebug), "Ignored, because skip_idle is true (advance_state() was called last).");
|
||||
return;
|
||||
}
|
||||
// Register ourselves with the condition object.
|
||||
condition.wait(this);
|
||||
// Mark that we are idle.
|
||||
sub_state_w->idle = true;
|
||||
// Mark that we are waiting for a condition.
|
||||
sub_state_w->blocked = &condition;
|
||||
// Not sleeping (anymore).
|
||||
mSleep = 0;
|
||||
}
|
||||
|
||||
void AIStateMachine::cont(void)
|
||||
{
|
||||
DoutEntering(dc::statemachine, "AIStateMachine::cont() [" << (void*)this << "]");
|
||||
DoutEntering(dc::statemachine(mSMDebug), "AIStateMachine::cont() [" << (void*)this << "]");
|
||||
{
|
||||
sub_state_type_wat sub_state_w(mSubState);
|
||||
// Void last call to idle(), if any.
|
||||
sub_state_w->idle = false;
|
||||
// No longer say we woke up when signalled() is called.
|
||||
if (sub_state_w->blocked)
|
||||
{
|
||||
Dout(dc::statemachine(mSMDebug), "Removing statemachine from condition " << (void*)sub_state_w->blocked);
|
||||
sub_state_w->blocked->remove(this);
|
||||
sub_state_w->blocked = NULL;
|
||||
}
|
||||
// Mark that a re-entry of multiplex() is necessary.
|
||||
sub_state_w->need_run = true;
|
||||
#ifdef SHOW_ASSERT
|
||||
@@ -1095,15 +1152,56 @@ void AIStateMachine::cont(void)
|
||||
}
|
||||
}
|
||||
|
||||
// This function is very much like cont(), except that it has no effect when we are not in a blocked state.
|
||||
// Returns true if the state machine was unblocked, false if it was already unblocked.
|
||||
bool AIStateMachine::signalled(void)
|
||||
{
|
||||
DoutEntering(dc::statemachine(mSMDebug), "AIStateMachine::signalled() [" << (void*)this << "]");
|
||||
{
|
||||
sub_state_type_wat sub_state_w(mSubState);
|
||||
// Test if we are blocked or not.
|
||||
if (sub_state_w->blocked)
|
||||
{
|
||||
Dout(dc::statemachine(mSMDebug), "Removing statemachine from condition " << (void*)sub_state_w->blocked);
|
||||
sub_state_w->blocked->remove(this);
|
||||
sub_state_w->blocked = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// Void last call to wait().
|
||||
sub_state_w->idle = false;
|
||||
// Mark that a re-entry of multiplex() is necessary.
|
||||
sub_state_w->need_run = true;
|
||||
#ifdef SHOW_ASSERT
|
||||
// From this moment.
|
||||
mDebugContPending = true;
|
||||
#endif
|
||||
}
|
||||
if (!mMultiplexMutex.isSelfLocked())
|
||||
{
|
||||
multiplex(schedule_run);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void AIStateMachine::abort(void)
|
||||
{
|
||||
DoutEntering(dc::statemachine, "AIStateMachine::abort() [" << (void*)this << "]");
|
||||
DoutEntering(dc::statemachine(mSMDebug), "AIStateMachine::abort() [" << (void*)this << "]");
|
||||
bool is_waiting = false;
|
||||
{
|
||||
multiplex_state_type_rat state_r(mState);
|
||||
sub_state_type_wat sub_state_w(mSubState);
|
||||
// Mark that we are aborted, iff we didn't already finish.
|
||||
sub_state_w->aborted = !sub_state_w->finished;
|
||||
// No longer say we woke up when signalled() is called.
|
||||
if (sub_state_w->blocked)
|
||||
{
|
||||
Dout(dc::statemachine(mSMDebug), "Removing statemachine from condition " << (void*)sub_state_w->blocked);
|
||||
sub_state_w->blocked->remove(this);
|
||||
sub_state_w->blocked = NULL;
|
||||
}
|
||||
// Mark that a re-entry of multiplex() is necessary.
|
||||
sub_state_w->need_run = true;
|
||||
// Schedule a new run when this state machine is waiting.
|
||||
@@ -1128,7 +1226,7 @@ void AIStateMachine::abort(void)
|
||||
|
||||
void AIStateMachine::finish(void)
|
||||
{
|
||||
DoutEntering(dc::statemachine, "AIStateMachine::finish() [" << (void*)this << "]");
|
||||
DoutEntering(dc::statemachine(mSMDebug), "AIStateMachine::finish() [" << (void*)this << "]");
|
||||
#ifdef SHOW_ASSERT
|
||||
{
|
||||
multiplex_state_type_rat state_r(mState);
|
||||
@@ -1147,7 +1245,7 @@ void AIStateMachine::finish(void)
|
||||
|
||||
void AIStateMachine::yield(void)
|
||||
{
|
||||
DoutEntering(dc::statemachine, "AIStateMachine::yield() [" << (void*)this << "]");
|
||||
DoutEntering(dc::statemachine(mSMDebug), "AIStateMachine::yield() [" << (void*)this << "]");
|
||||
multiplex_state_type_rat state_r(mState);
|
||||
// yield() may only be called from multiplex_impl().
|
||||
llassert(state_r->base_state == bs_multiplex);
|
||||
@@ -1160,7 +1258,7 @@ void AIStateMachine::yield(void)
|
||||
void AIStateMachine::yield(AIEngine* engine)
|
||||
{
|
||||
llassert(engine);
|
||||
DoutEntering(dc::statemachine, "AIStateMachine::yield(" << engine->name() << ") [" << (void*)this << "]");
|
||||
DoutEntering(dc::statemachine(mSMDebug), "AIStateMachine::yield(" << engine->name() << ") [" << (void*)this << "]");
|
||||
#ifdef SHOW_ASSERT
|
||||
{
|
||||
multiplex_state_type_rat state_r(mState);
|
||||
@@ -1173,9 +1271,19 @@ void AIStateMachine::yield(AIEngine* engine)
|
||||
mYieldEngine = engine;
|
||||
}
|
||||
|
||||
bool AIStateMachine::yield_if_not(AIEngine* engine)
|
||||
{
|
||||
if (engine && multiplex_state_type_rat(mState)->current_engine != engine)
|
||||
{
|
||||
yield(engine);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void AIStateMachine::yield_frame(unsigned int frames)
|
||||
{
|
||||
DoutEntering(dc::statemachine, "AIStateMachine::yield_frame(" << frames << ") [" << (void*)this << "]");
|
||||
DoutEntering(dc::statemachine(mSMDebug), "AIStateMachine::yield_frame(" << frames << ") [" << (void*)this << "]");
|
||||
mSleep = -(S64)frames;
|
||||
// Sleeping is always done from the main thread.
|
||||
yield(&gMainThreadEngine);
|
||||
@@ -1183,7 +1291,7 @@ void AIStateMachine::yield_frame(unsigned int frames)
|
||||
|
||||
void AIStateMachine::yield_ms(unsigned int ms)
|
||||
{
|
||||
DoutEntering(dc::statemachine, "AIStateMachine::yield_ms(" << ms << ") [" << (void*)this << "]");
|
||||
DoutEntering(dc::statemachine(mSMDebug), "AIStateMachine::yield_ms(" << ms << ") [" << (void*)this << "]");
|
||||
mSleep = get_clock_count() + calc_clock_frequency() * ms / 1000;
|
||||
// Sleeping is always done from the main thread.
|
||||
yield(&gMainThreadEngine);
|
||||
@@ -1233,7 +1341,7 @@ void AIEngine::threadloop(void)
|
||||
engine_state_type_wat engine_state_w(mEngineState);
|
||||
if (!active)
|
||||
{
|
||||
Dout(dc::statemachine, "Erasing state machine [" << (void*)&state_machine << "] from " << mName);
|
||||
Dout(dc::statemachine(state_machine.mSMDebug), "Erasing state machine [" << (void*)&state_machine << "] from " << mName);
|
||||
engine_state_w->list.erase(queued_element++);
|
||||
}
|
||||
else
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
#include <list>
|
||||
#include <boost/signals2.hpp>
|
||||
|
||||
class AIConditionBase;
|
||||
class AIStateMachine;
|
||||
|
||||
class AIEngine
|
||||
@@ -132,6 +133,7 @@ class AIStateMachine : public LLThreadSafeRefCount
|
||||
struct sub_state_type {
|
||||
state_type run_state;
|
||||
state_type advance_state;
|
||||
AIConditionBase* blocked;
|
||||
bool reset;
|
||||
bool need_run;
|
||||
bool idle;
|
||||
@@ -195,20 +197,36 @@ class AIStateMachine : public LLThreadSafeRefCount
|
||||
bool mDebugAdvanceStatePending; // True while advance_state() was called by not handled yet.
|
||||
bool mDebugRefCalled; // True when ref() is called (or will be called within the critial area of mMultiplexMutex).
|
||||
#endif
|
||||
#ifdef CWDEBUG
|
||||
protected:
|
||||
bool mSMDebug; // Print debug output only when true.
|
||||
#endif
|
||||
private:
|
||||
U64 mRuntime; // Total time spent running in the main thread (in clocks).
|
||||
|
||||
public:
|
||||
AIStateMachine(void) : mCallback(NULL), mDefaultEngine(NULL), mYieldEngine(NULL),
|
||||
AIStateMachine(CWD_ONLY(bool debug)) : mCallback(NULL), mDefaultEngine(NULL), mYieldEngine(NULL),
|
||||
#ifdef SHOW_ASSERT
|
||||
mThreadId(AIThreadID::none), mDebugLastState(bs_killed), mDebugShouldRun(false), mDebugAborted(false), mDebugContPending(false),
|
||||
mDebugSetStatePending(false), mDebugAdvanceStatePending(false), mDebugRefCalled(false),
|
||||
#endif
|
||||
#ifdef CWDEBUG
|
||||
mSMDebug(debug),
|
||||
#endif
|
||||
mRuntime(0)
|
||||
{ }
|
||||
|
||||
protected:
|
||||
// The user should call finish() (or abort(), or kill() from the call back when finish_impl() calls run()), not delete a class derived from AIStateMachine directly.
|
||||
virtual ~AIStateMachine() { llassert(multiplex_state_type_rat(mState)->base_state == bs_killed); }
|
||||
// The user should call finish() (or abort(), or kill() from the call back when finish_impl() calls run()),
|
||||
// not delete a class derived from AIStateMachine directly. Deleting it directly before calling run() is
|
||||
// ok however.
|
||||
virtual ~AIStateMachine()
|
||||
{
|
||||
#ifdef SHOW_ASSERT
|
||||
base_state_type state = multiplex_state_type_rat(mState)->base_state;
|
||||
llassert(state == bs_killed || state == bs_reset);
|
||||
#endif
|
||||
}
|
||||
|
||||
public:
|
||||
// These functions may be called directly after creation, or from within finish_impl(), or from the call back function.
|
||||
@@ -224,11 +242,13 @@ class AIStateMachine : public LLThreadSafeRefCount
|
||||
void set_state(state_type new_state); // Run this state the NEXT loop.
|
||||
// These functions can only be called from within multiplex_impl().
|
||||
void idle(void); // Go idle unless cont() or advance_state() were called since the start of the current loop, or until they are called.
|
||||
void wait(AIConditionBase& condition); // The same as idle(), but wake up when AICondition<T>::signal() is called.
|
||||
void finish(void); // Mark that the state machine finished and schedule the call back.
|
||||
void yield(void); // Yield to give CPU to other state machines, but do not go idle.
|
||||
void yield(AIEngine* engine); // Yield to give CPU to other state machines, but do not go idle. Continue running from engine 'engine'.
|
||||
void yield_frame(unsigned int frames); // Run from the main-thread engine after at least 'frames' frames have passed.
|
||||
void yield_ms(unsigned int ms); // Run from the main-thread engine after roughly 'ms' miliseconds have passed.
|
||||
bool yield_if_not(AIEngine* engine); // Do not really yield, unless the current engine is not 'engine'. Returns true if it switched engine.
|
||||
|
||||
public:
|
||||
// This function can be called from multiplex_imp(), but also by a child state machine and
|
||||
@@ -236,11 +256,12 @@ class AIStateMachine : public LLThreadSafeRefCount
|
||||
// to access this state machine.
|
||||
void abort(void); // Abort the state machine (unsuccessful finish).
|
||||
|
||||
// These are the only two functions that can be called by any thread at any moment.
|
||||
// These are the only three functions that can be called by any thread at any moment.
|
||||
// Those threads should use an LLPointer<AIStateMachine> to access this state machine.
|
||||
void cont(void); // Guarantee at least one full run of multiplex() after this function is called. Cancels the last call to idle().
|
||||
void advance_state(state_type new_state); // Guarantee at least one full run of multiplex() after this function is called
|
||||
// iff new_state is larger than the last state that was processed.
|
||||
bool signalled(void); // Call cont() iff this state machine is still blocked after a call to wait(). Returns false if it already unblocked.
|
||||
|
||||
public:
|
||||
// Accessors.
|
||||
|
||||
@@ -181,7 +181,11 @@ class AIStateMachineThreadBase : public AIStateMachine {
|
||||
static state_type const max_state = wait_stopped + 1;
|
||||
|
||||
protected:
|
||||
AIStateMachineThreadBase(void) { }
|
||||
AIStateMachineThreadBase(CWD_ONLY(bool debug))
|
||||
#ifdef CWDEBUG
|
||||
: AIStateMachine(debug)
|
||||
#endif
|
||||
{ }
|
||||
|
||||
private:
|
||||
// Handle initializing the object.
|
||||
@@ -217,7 +221,10 @@ class AIStateMachineThread : public AIStateMachineThreadBase {
|
||||
|
||||
public:
|
||||
// Constructor.
|
||||
AIStateMachineThread(void)
|
||||
AIStateMachineThread(CWD_ONLY(bool debug))
|
||||
#ifdef CWDEBUG
|
||||
: AIStateMachineThreadBase(debug)
|
||||
#endif
|
||||
{
|
||||
*AIThreadImpl::StateMachineThread_wat(mThreadImpl.mStateMachineThread) = this;
|
||||
}
|
||||
|
||||
@@ -76,7 +76,11 @@ class AITimer : public AIStateMachine {
|
||||
F64 mInterval; //!< Input variable: interval after which the event will be generated, in seconds.
|
||||
|
||||
public:
|
||||
AITimer(void) : mInterval(0) { DoutEntering(dc::statemachine, "AITimer(void) [" << (void*)this << "]"); }
|
||||
AITimer(CWD_ONLY(bool debug = false)) :
|
||||
#ifdef CWDEBUG
|
||||
AIStateMachine(debug),
|
||||
#endif
|
||||
mInterval(0) { DoutEntering(dc::statemachine(mSMDebug), "AITimer(void) [" << (void*)this << "]"); }
|
||||
|
||||
/**
|
||||
* @brief Set the interval after which the timer should expire.
|
||||
@@ -96,7 +100,7 @@ class AITimer : public AIStateMachine {
|
||||
|
||||
protected:
|
||||
// Call finish() (or abort()), not delete.
|
||||
/*virtual*/ ~AITimer() { DoutEntering(dc::statemachine, "~AITimer() [" << (void*)this << "]"); mFrameTimer.cancel(); }
|
||||
/*virtual*/ ~AITimer() { DoutEntering(dc::statemachine(mSMDebug), "~AITimer() [" << (void*)this << "]"); mFrameTimer.cancel(); }
|
||||
|
||||
// Handle initializing the object.
|
||||
/*virtual*/ void initialize_impl(void);
|
||||
|
||||
@@ -46,6 +46,10 @@ if (WINDOWS)
|
||||
set(MSVC_DIR 10.0)
|
||||
set(MSVC_SUFFIX 100)
|
||||
endif (MSVC10)
|
||||
if (MSVC11)
|
||||
set(MSVC_DIR 11.0)
|
||||
set(MSVC_SUFFIX 110)
|
||||
endif (MSVC11)
|
||||
|
||||
# Remove default /Zm1000 flag that cmake inserts
|
||||
string (REPLACE "/Zm1000" " " CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
|
||||
@@ -78,11 +82,17 @@ if (WINDOWS)
|
||||
/W3
|
||||
/c
|
||||
/Zc:forScope
|
||||
/Zc:wchar_t-
|
||||
/Zc:wchar_t-
|
||||
/nologo
|
||||
/Oy-
|
||||
/arch:SSE2
|
||||
)
|
||||
|
||||
# SSE2 is implied on win64
|
||||
if(WORD_SIZE EQUAL 32)
|
||||
add_definitions(/arch:SSE2)
|
||||
else(WORD_SIZE EQUAL 32)
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /wd4267 /wd4250 /wd4244")
|
||||
endif(WORD_SIZE EQUAL 32)
|
||||
|
||||
# configure win32 API for windows XP+ compatibility
|
||||
set(WINVER "0x0501" CACHE STRING "Win32 API Target version (see http://msdn.microsoft.com/en-us/library/aa383745%28v=VS.85%29.aspx)")
|
||||
|
||||
@@ -81,6 +81,7 @@ set(cmake_SOURCE_FILES
|
||||
Linking.cmake
|
||||
MediaPluginBase.cmake
|
||||
NDOF.cmake
|
||||
NVAPI.cmake
|
||||
OPENAL.cmake
|
||||
OpenGL.cmake
|
||||
OpenJPEG.cmake
|
||||
|
||||
@@ -6,6 +6,14 @@
|
||||
|
||||
include(CMakeCopyIfDifferent)
|
||||
|
||||
if(WORD_SIZE EQUAL 32)
|
||||
set(debug_libs_dir "${CMAKE_SOURCE_DIR}/../libraries/i686-win32/lib/debug")
|
||||
set(release_libs_dir "${CMAKE_SOURCE_DIR}/../libraries/i686-win32/lib/release")
|
||||
else(WORD_SIZE EQUAL 32)
|
||||
set(debug_libs_dir "${CMAKE_SOURCE_DIR}/../libraries/x86_64-win/lib/debug")
|
||||
set(release_libs_dir "${CMAKE_SOURCE_DIR}/../libraries/x86_64-win/lib/release")
|
||||
endif(WORD_SIZE EQUAL 32)
|
||||
|
||||
set(vivox_src_dir "${CMAKE_SOURCE_DIR}/newview/vivox-runtime/i686-win32")
|
||||
set(vivox_files
|
||||
SLVoice.exe
|
||||
@@ -23,7 +31,7 @@ copy_if_different(
|
||||
set(all_targets ${all_targets} ${out_targets})
|
||||
|
||||
|
||||
set(debug_src_dir "${CMAKE_SOURCE_DIR}/../libraries/i686-win32/lib/debug")
|
||||
set(debug_src_dir "${debug_libs_dir}")
|
||||
set(debug_files
|
||||
libhunspell.dll
|
||||
libapr-1.dll
|
||||
@@ -44,7 +52,7 @@ copy_if_different(
|
||||
set(all_targets ${all_targets} ${out_targets})
|
||||
|
||||
# Debug config runtime files required for the plugin test mule
|
||||
set(plugintest_debug_src_dir "${CMAKE_SOURCE_DIR}/../libraries/i686-win32/lib/debug")
|
||||
set(plugintest_debug_src_dir "${debug_libs_dir}")
|
||||
set(plugintest_debug_files
|
||||
libeay32.dll
|
||||
qtcored4.dll
|
||||
@@ -63,7 +71,7 @@ copy_if_different(
|
||||
set(all_targets ${all_targets} ${out_targets})
|
||||
|
||||
# Debug config runtime files required for the plugin test mule (Qt image format plugins)
|
||||
set(plugintest_debug_src_dir "${CMAKE_SOURCE_DIR}/../libraries/i686-win32/lib/debug/imageformats")
|
||||
set(plugintest_debug_src_dir "${debug_libs_dir}/imageformats")
|
||||
set(plugintest_debug_files
|
||||
qgifd4.dll
|
||||
qicod4.dll
|
||||
@@ -89,7 +97,7 @@ copy_if_different(
|
||||
set(all_targets ${all_targets} ${out_targets})
|
||||
|
||||
# Release & ReleaseDebInfo config runtime files required for the plugin test mule
|
||||
set(plugintest_release_src_dir "${CMAKE_SOURCE_DIR}/../libraries/i686-win32/lib/release")
|
||||
set(plugintest_release_src_dir "${release_libs_dir}")
|
||||
set(plugintest_release_files
|
||||
libeay32.dll
|
||||
qtcore4.dll
|
||||
@@ -116,7 +124,7 @@ copy_if_different(
|
||||
set(all_targets ${all_targets} ${out_targets})
|
||||
|
||||
# Release & ReleaseDebInfo config runtime files required for the plugin test mule (Qt image format plugins)
|
||||
set(plugintest_release_src_dir "${CMAKE_SOURCE_DIR}/../libraries/i686-win32/lib/release/imageformats")
|
||||
set(plugintest_release_src_dir "${release_libs_dir}/imageformats")
|
||||
set(plugintest_release_files
|
||||
qgif4.dll
|
||||
qico4.dll
|
||||
@@ -158,7 +166,7 @@ copy_if_different(
|
||||
set(all_targets ${all_targets} ${out_targets})
|
||||
|
||||
# Debug config runtime files required for the plugins
|
||||
set(plugins_debug_src_dir "${CMAKE_SOURCE_DIR}/../libraries/i686-win32/lib/debug")
|
||||
set(plugins_debug_src_dir "${debug_libs_dir}")
|
||||
set(plugins_debug_files
|
||||
libeay32.dll
|
||||
qtcored4.dll
|
||||
@@ -177,7 +185,7 @@ copy_if_different(
|
||||
set(all_targets ${all_targets} ${out_targets})
|
||||
|
||||
# Release & ReleaseDebInfo config runtime files required for the plugins
|
||||
set(plugins_release_src_dir "${CMAKE_SOURCE_DIR}/../libraries/i686-win32/lib/release")
|
||||
set(plugins_release_src_dir "${release_libs_dir}")
|
||||
set(plugins_release_files
|
||||
libeay32.dll
|
||||
qtcore4.dll
|
||||
@@ -203,9 +211,9 @@ copy_if_different(
|
||||
)
|
||||
set(all_targets ${all_targets} ${out_targets})
|
||||
|
||||
set(release_src_dir "${CMAKE_SOURCE_DIR}/../libraries/i686-win32/lib/release")
|
||||
|
||||
set(release_src_dir "${release_libs_dir}")
|
||||
set(release_files
|
||||
libtcmalloc_minimal.dll
|
||||
libhunspell.dll
|
||||
libapr-1.dll
|
||||
libaprutil-1.dll
|
||||
@@ -216,8 +224,21 @@ set(release_files
|
||||
glod.dll
|
||||
)
|
||||
|
||||
if(WORD_SIZE EQUAL 32)
|
||||
set(release_files ${release_files}
|
||||
libtcmalloc_minimal.dll
|
||||
)
|
||||
endif(WORD_SIZE EQUAL 32)
|
||||
|
||||
|
||||
if(FMODEX)
|
||||
find_path(FMODEX_BINARY_DIR fmodex.dll
|
||||
if (WORD_SIZE EQUAL 32)
|
||||
set(fmodex_dll_file "fmodex.dll")
|
||||
else (WORD_SIZE EQUAL 32)
|
||||
set(fmodex_dll_file "fmodex64.dll")
|
||||
endif (WORD_SIZE EQUAL 32)
|
||||
|
||||
find_path(FMODEX_BINARY_DIR "${fmodex_dll_file}"
|
||||
"${release_src_dir}"
|
||||
"${FMODEX_SDK_DIR}/api"
|
||||
"${FMODEX_SDK_DIR}"
|
||||
@@ -225,11 +246,11 @@ if(FMODEX)
|
||||
)
|
||||
|
||||
if(FMODEX_BINARY_DIR)
|
||||
copy_if_different("${FMODEX_BINARY_DIR}" "${CMAKE_CURRENT_BINARY_DIR}/Release" out_targets fmodex.dll)
|
||||
copy_if_different("${FMODEX_BINARY_DIR}" "${CMAKE_CURRENT_BINARY_DIR}/Release" out_targets "${fmodex_dll_file}")
|
||||
set(all_targets ${all_targets} ${out_targets})
|
||||
copy_if_different("${FMODEX_BINARY_DIR}" "${CMAKE_CURRENT_BINARY_DIR}/RelWithDebInfo" out_targets fmodex.dll)
|
||||
copy_if_different("${FMODEX_BINARY_DIR}" "${CMAKE_CURRENT_BINARY_DIR}/RelWithDebInfo" out_targets "${fmodex_dll_file}")
|
||||
set(all_targets ${all_targets} ${out_targets})
|
||||
copy_if_different("${FMODEX_BINARY_DIR}" "${CMAKE_CURRENT_BINARY_DIR}/Debug" out_targets fmodex.dll)
|
||||
copy_if_different("${FMODEX_BINARY_DIR}" "${CMAKE_CURRENT_BINARY_DIR}/Debug" out_targets "${fmodex_dll_file}")
|
||||
set(all_targets ${all_targets} ${out_targets})
|
||||
endif(FMODEX_BINARY_DIR)
|
||||
endif(FMODEX)
|
||||
@@ -285,105 +306,6 @@ copy_if_different(
|
||||
)
|
||||
set(all_targets ${all_targets} ${out_targets})
|
||||
|
||||
# Copy MS C runtime dlls, required for packaging.
|
||||
# *TODO - Adapt this to support VC9
|
||||
if (MSVC80)
|
||||
FIND_PATH(debug_msvc8_redist_path msvcr80d.dll
|
||||
PATHS
|
||||
[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\8.0\\Setup\\VC;ProductDir]/redist/Debug_NonRedist/x86/Microsoft.VC80.DebugCRT
|
||||
NO_DEFAULT_PATH
|
||||
NO_DEFAULT_PATH
|
||||
)
|
||||
|
||||
if(EXISTS ${debug_msvc8_redist_path})
|
||||
set(debug_msvc8_files
|
||||
msvcr80d.dll
|
||||
msvcp80d.dll
|
||||
Microsoft.VC80.DebugCRT.manifest
|
||||
)
|
||||
|
||||
copy_if_different(
|
||||
${debug_msvc8_redist_path}
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/Debug"
|
||||
out_targets
|
||||
${debug_msvc8_files}
|
||||
)
|
||||
set(all_targets ${all_targets} ${out_targets})
|
||||
|
||||
set(debug_appconfig_file ${CMAKE_CURRENT_BINARY_DIR}/Debug/${VIEWER_BINARY_NAME}.exe.config)
|
||||
add_custom_command(
|
||||
OUTPUT ${debug_appconfig_file}
|
||||
COMMAND ${PYTHON_EXECUTABLE}
|
||||
ARGS
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/build_win32_appConfig.py
|
||||
${CMAKE_CURRENT_BINARY_DIR}/Debug/Microsoft.VC80.DebugCRT.manifest
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/SecondLifeDebug.exe.config
|
||||
${debug_appconfig_file}
|
||||
DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/Debug/Microsoft.VC80.DebugCRT.manifest
|
||||
COMMENT "Creating debug app config file"
|
||||
)
|
||||
|
||||
endif (EXISTS ${debug_msvc8_redist_path})
|
||||
|
||||
FIND_PATH(release_msvc8_redist_path msvcr80.dll
|
||||
PATHS
|
||||
[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\8.0\\Setup\\VC;ProductDir]/redist/x86/Microsoft.VC80.CRT
|
||||
NO_DEFAULT_PATH
|
||||
NO_DEFAULT_PATH
|
||||
)
|
||||
|
||||
if(EXISTS ${release_msvc8_redist_path})
|
||||
set(release_msvc8_files
|
||||
msvcr80.dll
|
||||
msvcp80.dll
|
||||
Microsoft.VC80.CRT.manifest
|
||||
)
|
||||
|
||||
copy_if_different(
|
||||
${release_msvc8_redist_path}
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/Release"
|
||||
out_targets
|
||||
${release_msvc8_files}
|
||||
)
|
||||
set(all_targets ${all_targets} ${out_targets})
|
||||
|
||||
copy_if_different(
|
||||
${release_msvc8_redist_path}
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/RelWithDebInfo"
|
||||
out_targets
|
||||
${release_msvc8_files}
|
||||
)
|
||||
set(all_targets ${all_targets} ${out_targets})
|
||||
|
||||
set(release_appconfig_file ${CMAKE_CURRENT_BINARY_DIR}/Release/${VIEWER_BINARY_NAME}.exe.config)
|
||||
add_custom_command(
|
||||
OUTPUT ${release_appconfig_file}
|
||||
COMMAND ${PYTHON_EXECUTABLE}
|
||||
ARGS
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/build_win32_appConfig.py
|
||||
${CMAKE_CURRENT_BINARY_DIR}/Release/Microsoft.VC80.CRT.manifest
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/SecondLife.exe.config
|
||||
${release_appconfig_file}
|
||||
DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/Release/Microsoft.VC80.CRT.manifest
|
||||
COMMENT "Creating release app config file"
|
||||
)
|
||||
|
||||
set(relwithdebinfo_appconfig_file ${CMAKE_CURRENT_BINARY_DIR}/RelWithDebInfo/${VIEWER_BINARY_NAME}.exe.config)
|
||||
add_custom_command(
|
||||
OUTPUT ${relwithdebinfo_appconfig_file}
|
||||
COMMAND ${PYTHON_EXECUTABLE}
|
||||
ARGS
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/build_win32_appConfig.py
|
||||
${CMAKE_CURRENT_BINARY_DIR}/RelWithDebInfo/Microsoft.VC80.CRT.manifest
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/SecondLife.exe.config
|
||||
${relwithdebinfo_appconfig_file}
|
||||
DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/RelWithDebInfo/Microsoft.VC80.CRT.manifest
|
||||
COMMENT "Creating relwithdebinfo app config file"
|
||||
)
|
||||
|
||||
endif (EXISTS ${release_msvc8_redist_path})
|
||||
endif (MSVC80)
|
||||
|
||||
add_custom_target(copy_win_libs ALL
|
||||
DEPENDS
|
||||
${all_targets}
|
||||
|
||||
@@ -44,10 +44,15 @@ if (WINDOWS)
|
||||
"$ENV{ProgramFiles(x86)}/Windows Kits/8.0"
|
||||
)
|
||||
|
||||
if (WIN_KIT_ROOT_DIR)
|
||||
find_path (WIN_KIT_LIB_DIR dxguid.lib
|
||||
"${WIN_KIT_ROOT_DIR}/Lib/winv6.3/um/${DIRECTX_ARCHITECTURE}"
|
||||
"${WIN_KIT_ROOT_DIR}/Lib/Win8/um/${DIRECTX_ARCHITECTURE}"
|
||||
)
|
||||
|
||||
if (WIN_KIT_ROOT_DIR AND WIN_KIT_LIB_DIR)
|
||||
set (DIRECTX_INCLUDE_DIR "${WIN_KIT_ROOT_DIR}/Include/um" "${WIN_KIT_ROOT_DIR}/Include/shared")
|
||||
set (DIRECTX_LIBRARY_DIR "${WIN_KIT_ROOT_DIR}/Lib/Win8/um/${DIRECTX_ARCHITECTURE}")
|
||||
endif (WIN_KIT_ROOT_DIR)
|
||||
set (DIRECTX_LIBRARY_DIR "${WIN_KIT_LIB_DIR}")
|
||||
endif (WIN_KIT_ROOT_DIR AND WIN_KIT_LIB_DIR)
|
||||
endif (DIRECTX_ROOT_DIR)
|
||||
|
||||
if (DIRECTX_INCLUDE_DIR)
|
||||
|
||||
@@ -16,7 +16,7 @@ if (NOT FMODEX_LIBRARY)
|
||||
)
|
||||
elseif(WORD_SIZE EQUAL 64)
|
||||
find_library(FMODEX_LIBRARY
|
||||
fmodex64 fmodexL64
|
||||
fmodex64_vc fmodexL64_vc fmodex64 fmodexL64
|
||||
PATHS
|
||||
"${FMODEX_SDK_DIR}/api/lib"
|
||||
"${FMODEX_SDK_DIR}/api"
|
||||
@@ -25,21 +25,31 @@ if (NOT FMODEX_LIBRARY)
|
||||
)
|
||||
endif(WORD_SIZE EQUAL 32)
|
||||
endif(FMODEX_SDK_DIR)
|
||||
if(WINDOWS AND NOT FMODEX_LIBRARY)
|
||||
set(FMODEX_PROG_DIR "$ENV{PROGRAMFILES}/FMOD SoundSystem/FMOD Programmers API Windows")
|
||||
find_library(FMODEX_LIBRARY
|
||||
fmodex_vc fmodexL_vc
|
||||
PATHS
|
||||
"${FMODEX_PROG_DIR}/api/lib"
|
||||
"${FMODEX_PROG_DIR}/api"
|
||||
"${FMODEX_PROG_DIR}"
|
||||
)
|
||||
if(WINDOWS AND NOT FMODEX_SDK_DIR)
|
||||
GET_FILENAME_COMPONENT(FMODEX_PROG_DIR [HKEY_CURRENT_USER\\Software\\FMOD\ Programmers\ API\ Windows] ABSOLUTE CACHE)
|
||||
if(WORD_SIZE EQUAL 32)
|
||||
find_library(FMODEX_LIBRARY
|
||||
fmodex_vc fmodexL_vc
|
||||
PATHS
|
||||
"${FMODEX_PROG_DIR}/api/lib"
|
||||
"${FMODEX_PROG_DIR}/api"
|
||||
"${FMODEX_PROG_DIR}"
|
||||
)
|
||||
else(WORD_SIZE EQUAL 32)
|
||||
find_library(FMODEX_LIBRARY
|
||||
fmodex64_vc fmodexL64_vc
|
||||
PATHS
|
||||
"${FMODEX_PROG_DIR}/api/lib"
|
||||
"${FMODEX_PROG_DIR}/api"
|
||||
"${FMODEX_PROG_DIR}"
|
||||
)
|
||||
endif(WORD_SIZE EQUAL 32)
|
||||
if(FMODEX_LIBRARY)
|
||||
message(STATUS "Found fmodex in ${FMODEX_PROG_DIR}")
|
||||
set(FMODEX_SDK_DIR "${FMODEX_PROG_DIR}")
|
||||
set(FMODEX_SDK_DIR "${FMODEX_PROG_DIR}" CACHE PATH "Path to the FMOD Ex SDK." FORCE)
|
||||
endif(FMODEX_LIBRARY)
|
||||
endif(WINDOWS AND NOT FMODEX_LIBRARY)
|
||||
endif(WINDOWS AND NOT FMODEX_SDK_DIR)
|
||||
endif (NOT FMODEX_LIBRARY)
|
||||
|
||||
find_path(FMODEX_INCLUDE_DIR fmod.hpp
|
||||
|
||||
@@ -5,22 +5,29 @@ set(${CMAKE_CURRENT_LIST_FILE}_INCLUDED "YES")
|
||||
include(Variables)
|
||||
|
||||
if (NOT STANDALONE)
|
||||
if (WINDOWS)
|
||||
set(ARCH_PREBUILT_DIRS ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/lib)
|
||||
set(ARCH_PREBUILT_DIRS_RELEASE ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/lib/release)
|
||||
set(ARCH_PREBUILT_DIRS_DEBUG ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/lib/debug)
|
||||
elseif (LINUX)
|
||||
set(ARCH_PREBUILT_DIRS ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/lib/release)
|
||||
set(ARCH_PREBUILT_DIRS_RELEASE ${ARCH_PREBUILT_DIRS})
|
||||
set(ARCH_PREBUILT_DIRS_DEBUG ${ARCH_PREBUILT_DIRS})
|
||||
elseif (DARWIN)
|
||||
set(ARCH_PREBUILT_DIRS ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/lib)
|
||||
set(ARCH_PREBUILT_DIRS_RELEASE ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/lib/release)
|
||||
set(ARCH_PREBUILT_DIRS_DEBUG ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/lib/debug)
|
||||
endif (WINDOWS)
|
||||
set(ARCH_PREBUILT_DIRS ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/lib)
|
||||
set(ARCH_PREBUILT_DIRS_RELEASE ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/lib/release)
|
||||
set(ARCH_PREBUILT_DIRS_DEBUG ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/lib/debug)
|
||||
|
||||
if(WINDOWS OR ${CMAKE_GENERATOR} MATCHES "Xcode")
|
||||
# the cmake xcode and VS generators implicitly append ${CMAKE_CFG_INTDIR} to the library paths for us
|
||||
# fortunately both windows and darwin are case insensitive filesystems so this works.
|
||||
set(ARCH_PREBUILT_LINK_DIRS "${ARCH_PREBUILT_DIRS}")
|
||||
else(WINDOWS OR ${CMAKE_GENERATOR} MATCHES "Xcode")
|
||||
# else block is for linux and any other makefile based generators
|
||||
string(TOLOWER ${CMAKE_BUILD_TYPE} CMAKE_BUILD_TYPE_LOWER)
|
||||
set(ARCH_PREBUILT_LINK_DIRS ${ARCH_PREBUILT_DIRS}/${CMAKE_BUILD_TYPE_LOWER})
|
||||
endif(WINDOWS OR ${CMAKE_GENERATOR} MATCHES "Xcode")
|
||||
|
||||
if (NOT "${CMAKE_BUILD_TYPE}" STREQUAL "Release")
|
||||
# When we're building something other than Release, append the
|
||||
# packages/lib/release directory to deal with autobuild packages that don't
|
||||
# provide (e.g.) lib/debug libraries.
|
||||
list(APPEND ARCH_PREBUILT_LINK_DIRS ${ARCH_PREBUILT_DIRS_RELEASE})
|
||||
endif (NOT "${CMAKE_BUILD_TYPE}" STREQUAL "Release")
|
||||
endif (NOT STANDALONE)
|
||||
|
||||
link_directories(${ARCH_PREBUILT_DIRS})
|
||||
link_directories(${ARCH_PREBUILT_LINK_DIRS})
|
||||
|
||||
if (LINUX)
|
||||
set(DL_LIBRARY dl)
|
||||
|
||||
21
indra/cmake/NVAPI.cmake
Normal file
21
indra/cmake/NVAPI.cmake
Normal file
@@ -0,0 +1,21 @@
|
||||
# -*- cmake -*-
|
||||
include(Prebuilt)
|
||||
include(Variables)
|
||||
|
||||
set(NVAPI ON CACHE BOOL "Use NVAPI.")
|
||||
|
||||
if (NVAPI)
|
||||
if (WINDOWS)
|
||||
use_prebuilt_binary(nvapi)
|
||||
if (WORD_SIZE EQUAL 32)
|
||||
set(NVAPI_LIBRARY nvapi)
|
||||
elseif (WORD_SIZE EQUAL 64)
|
||||
set(NVAPI_LIBRARY nvapi64)
|
||||
endif (WORD_SIZE EQUAL 32)
|
||||
else (WINDOWS)
|
||||
set(NVAPI_LIBRARY "")
|
||||
endif (WINDOWS)
|
||||
else (NVAPI)
|
||||
set(NVAPI_LIBRARY "")
|
||||
endif (NVAPI)
|
||||
|
||||
@@ -8,7 +8,7 @@ endif(INSTALL_PROPRIETARY)
|
||||
if (DARWIN)
|
||||
include(CMakeFindFrameworks)
|
||||
find_library(QUICKTIME_LIBRARY QuickTime)
|
||||
elseif (WINDOWS)
|
||||
elseif (WINDOWS AND WORD_SIZE EQUAL 32)
|
||||
set(QUICKTIME_SDK_DIR "$ENV{PROGRAMFILES}/QuickTime SDK"
|
||||
CACHE PATH "Location of the QuickTime SDK.")
|
||||
|
||||
|
||||
@@ -37,10 +37,15 @@ set(LIBS_PREBUILT_DIR ${CMAKE_SOURCE_DIR}/../libraries CACHE PATH
|
||||
|
||||
if (${CMAKE_SYSTEM_NAME} MATCHES "Windows")
|
||||
set(WINDOWS ON BOOL FORCE)
|
||||
set(ARCH i686)
|
||||
set(LL_ARCH ${ARCH}_win32)
|
||||
set(LL_ARCH_DIR ${ARCH}-win32)
|
||||
set(WORD_SIZE 32)
|
||||
if (WORD_SIZE EQUAL 32)
|
||||
set(ARCH i686)
|
||||
set(LL_ARCH ${ARCH}_win32)
|
||||
set(LL_ARCH_DIR ${ARCH}-win32)
|
||||
elseif (WORD_SIZE EQUAL 64)
|
||||
set(ARCH x86_64)
|
||||
set(LL_ARCH ${ARCH}_win)
|
||||
set(LL_ARCH_DIR ${ARCH}-win)
|
||||
endif (WORD_SIZE EQUAL 32)
|
||||
endif (${CMAKE_SYSTEM_NAME} MATCHES "Windows")
|
||||
|
||||
if (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
|
||||
@@ -92,7 +97,7 @@ endif (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
|
||||
if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
||||
set(DARWIN 1)
|
||||
|
||||
if(${CMAKE_GENERATOR} MATCHES Xcode)
|
||||
if(${CMAKE_GENERATOR} MATCHES "Xcode")
|
||||
#SDK Compiler and Deployment targets for XCode
|
||||
if (${XCODE_VERSION} VERSION_LESS 4.0.0)
|
||||
set(CMAKE_OSX_SYSROOT /Developer/SDKs/MacOSX10.5.sdk)
|
||||
@@ -101,10 +106,10 @@ if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
||||
set(CMAKE_OSX_SYSROOT /Developer/SDKs/MacOSX10.6.sdk)
|
||||
set(CMAKE_OSX_DEPLOYMENT_TARGET 10.6)
|
||||
endif (${XCODE_VERSION} VERSION_LESS 4.0.0)
|
||||
else(${CMAKE_GENERATOR} MATCHES Xcode)
|
||||
else(${CMAKE_GENERATOR} MATCHES "Xcode")
|
||||
set(CMAKE_OSX_SYSROOT /Developer/SDKs/MacOSX10.6.sdk)
|
||||
set(CMAKE_OSX_DEPLOYMENT_TARGET 10.6)
|
||||
endif(${CMAKE_GENERATOR} MATCHES Xcode)
|
||||
endif(${CMAKE_GENERATOR} MATCHES "Xcode")
|
||||
|
||||
set(CMAKE_XCODE_ATTRIBUTE_GCC_VERSION "com.apple.compilers.llvmgcc42")
|
||||
|
||||
@@ -119,15 +124,17 @@ if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
||||
set(LL_ARCH_DIR universal-darwin)
|
||||
endif (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
||||
|
||||
if (WINDOWS)
|
||||
if (WINDOWS AND WORD_SIZE EQUAL 32)
|
||||
set(PREBUILT_TYPE windows)
|
||||
elseif (WINDOWS AND WORD_SIZE EQUAL 64)
|
||||
set(PREBUILT_TYPE windows64)
|
||||
elseif(DARWIN)
|
||||
set(PREBUILT_TYPE darwin)
|
||||
elseif(LINUX AND WORD_SIZE EQUAL 32)
|
||||
set(PREBUILT_TYPE linux)
|
||||
elseif(LINUX AND WORD_SIZE EQUAL 64)
|
||||
set(PREBUILT_TYPE linux64)
|
||||
endif(WINDOWS)
|
||||
endif(WINDOWS AND WORD_SIZE EQUAL 32)
|
||||
|
||||
# Default deploy grid
|
||||
set(GRID agni CACHE STRING "Target Grid")
|
||||
|
||||
@@ -144,6 +144,7 @@ extern LL_COMMON_API fake_channel const snapshot;
|
||||
#define CWDEBUG_MARKER 0
|
||||
|
||||
#define BACKTRACE do { } while(0)
|
||||
#define CWD_ONLY(...)
|
||||
|
||||
#endif // !DOXYGEN
|
||||
|
||||
@@ -180,6 +181,7 @@ extern LL_COMMON_API fake_channel const snapshot;
|
||||
#include <set>
|
||||
|
||||
#define CWD_API __attribute__ ((visibility("default")))
|
||||
#define CWD_ONLY(...) __VA_ARGS__
|
||||
|
||||
//! Debug specific code.
|
||||
namespace debug {
|
||||
|
||||
@@ -443,9 +443,15 @@ class WindowsSetup(PlatformSetup):
|
||||
'vc100' : {
|
||||
'gen' : r'Visual Studio 10',
|
||||
'ver' : r'10.0'
|
||||
},
|
||||
'vc110' : {
|
||||
'gen' : r'Visual Studio 11',
|
||||
'ver' : r'11.0'
|
||||
}
|
||||
}
|
||||
|
||||
gens['vs2010'] = gens['vc100']
|
||||
gens['vs2012'] = gens['vc110']
|
||||
|
||||
search_path = r'C:\windows'
|
||||
exe_suffixes = ('.exe', '.bat', '.com')
|
||||
@@ -503,6 +509,9 @@ class WindowsSetup(PlatformSetup):
|
||||
project_name=self.project_name,
|
||||
word_size=self.word_size,
|
||||
)
|
||||
if self.word_size == 64:
|
||||
args["generator"] += r' Win64'
|
||||
|
||||
#if simple:
|
||||
# return 'cmake %(opts)s "%(dir)s"' % args
|
||||
return ('cmake -G "%(generator)s" '
|
||||
|
||||
@@ -192,6 +192,8 @@ def usage(srctree=""):
|
||||
arg['description'] % nd)
|
||||
|
||||
def main():
|
||||
print "cwd:", os.getcwd()
|
||||
print " ".join(sys.argv)
|
||||
option_names = [arg['name'] + '=' for arg in ARGUMENTS]
|
||||
option_names.append('help')
|
||||
options, remainder = getopt.getopt(sys.argv[1:], "", option_names)
|
||||
@@ -266,7 +268,7 @@ class LLManifest(object):
|
||||
__metaclass__ = LLManifestRegistry
|
||||
manifests = {}
|
||||
def for_platform(self, platform, arch = None):
|
||||
if arch:
|
||||
if arch and platform != "windows":
|
||||
platform = platform + '_' + arch
|
||||
return self.manifests[platform.lower()]
|
||||
for_platform = classmethod(for_platform)
|
||||
|
||||
@@ -138,7 +138,7 @@ namespace HACD
|
||||
if (m_callBack)
|
||||
{
|
||||
char msg[1024];
|
||||
sprintf(msg, "nCC %lu\n", m_graph.m_nCCs);
|
||||
sprintf(msg, "nCC %zu\n", m_graph.m_nCCs);
|
||||
(*m_callBack)(msg, 0.0, 0.0, m_graph.GetNVertices());
|
||||
|
||||
}
|
||||
@@ -879,7 +879,7 @@ namespace HACD
|
||||
if (m_callBack)
|
||||
{
|
||||
char msg[1024];
|
||||
sprintf(msg, "\t CH(%zu) \t %zu \t %lf \t %zu \t %f \t %zu\n", v, static_cast<unsigned long>(p), m_graph.m_vertices[v].m_concavity, m_graph.m_vertices[v].m_distPoints.Size(), m_graph.m_vertices[v].m_surf*100.0/m_area, m_graph.m_vertices[v].m_ancestors.size());
|
||||
sprintf(msg, "\t CH(%zu) \t %zu \t %lf \t %zu \t %f \t %zu\n", v, p, m_graph.m_vertices[v].m_concavity, m_graph.m_vertices[v].m_distPoints.Size(), m_graph.m_vertices[v].m_surf*100.0/m_area, m_graph.m_vertices[v].m_ancestors.size());
|
||||
(*m_callBack)(msg, 0.0, 0.0, m_nClusters);
|
||||
p++;
|
||||
}
|
||||
|
||||
@@ -22,7 +22,9 @@
|
||||
#include <set>
|
||||
#include <vector>
|
||||
#include <queue>
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER >= 1700
|
||||
#include <functional>
|
||||
#endif
|
||||
namespace HACD
|
||||
{
|
||||
const double sc_pi = 3.14159265;
|
||||
|
||||
@@ -106,7 +106,7 @@ namespace HACD
|
||||
m_nMaxNodes = 0;
|
||||
for(size_t k = 0; k < maxDepth; k++)
|
||||
{
|
||||
m_nMaxNodes += (1 << maxDepth);
|
||||
m_nMaxNodes += (static_cast<size_t>(1) << maxDepth);
|
||||
}
|
||||
m_nodes = new RMNode[m_nMaxNodes];
|
||||
RMNode & root = m_nodes[AddNode()];
|
||||
|
||||
@@ -117,7 +117,8 @@ public:
|
||||
/*virtual*/ void stopAnimating(BOOL upload_bake);
|
||||
/*virtual*/ BOOL linkDrivenParams(visual_param_mapper mapper, BOOL only_cross_params);
|
||||
/*virtual*/ void resetDrivenParams();
|
||||
|
||||
/*virtual*/ char const* getTypeString(void) const { return "param_driver"; }
|
||||
|
||||
// LLViewerVisualParam Virtual functions
|
||||
/*virtual*/ F32 getTotalDistortion();
|
||||
/*virtual*/ const LLVector4a& getAvgDistortion();
|
||||
|
||||
@@ -173,6 +173,7 @@ public:
|
||||
// LLVisualParam Virtual functions
|
||||
///*virtual*/ BOOL parseData(LLXmlTreeNode* node);
|
||||
/*virtual*/ void apply( ESex sex );
|
||||
/*virtual*/ char const* getTypeString(void) const { return "param_morph"; }
|
||||
|
||||
// LLViewerVisualParam Virtual functions
|
||||
/*virtual*/ F32 getTotalDistortion();
|
||||
|
||||
@@ -109,7 +109,8 @@ public:
|
||||
// LLVisualParam Virtual functions
|
||||
///*virtual*/ BOOL parseData(LLXmlTreeNode* node);
|
||||
/*virtual*/ void apply( ESex sex );
|
||||
|
||||
/*virtual*/ char const* getTypeString(void) const { return "param_skeleton"; }
|
||||
|
||||
// LLViewerVisualParam Virtual functions
|
||||
/*virtual*/ F32 getTotalDistortion() { return 0.1f; }
|
||||
/*virtual*/ const LLVector4a& getAvgDistortion() { return mDefaultVec; }
|
||||
|
||||
@@ -86,6 +86,7 @@ public:
|
||||
/*virtual*/ void setWeight(F32 weight, BOOL upload_bake);
|
||||
/*virtual*/ void setAnimationTarget(F32 target_value, BOOL upload_bake);
|
||||
/*virtual*/ void animate(F32 delta, BOOL upload_bake);
|
||||
/*virtual*/ char const* getTypeString(void) const { return "param_alpha"; }
|
||||
|
||||
// LLViewerVisualParam Virtual functions
|
||||
/*virtual*/ F32 getTotalDistortion() { return 1.f; }
|
||||
@@ -177,7 +178,7 @@ public:
|
||||
/*virtual*/ void setWeight(F32 weight, BOOL upload_bake);
|
||||
/*virtual*/ void setAnimationTarget(F32 target_value, BOOL upload_bake);
|
||||
/*virtual*/ void animate(F32 delta, BOOL upload_bake);
|
||||
|
||||
/*virtual*/ char const* getTypeString(void) const { return "param_color"; }
|
||||
|
||||
// LLViewerVisualParam Virtual functions
|
||||
/*virtual*/ F32 getTotalDistortion() { return 1.f; }
|
||||
|
||||
@@ -143,6 +143,12 @@ BOOL LLViewerVisualParam::setInfo(LLViewerVisualParamInfo *info)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
//virtual
|
||||
std::string LLViewerVisualParam::getDumpWearableTypeName(void) const
|
||||
{
|
||||
return LLWearableType::getTypeName(LLWearableType::EType(getInfo()->mWearableType));
|
||||
}
|
||||
|
||||
/*
|
||||
//=============================================================================
|
||||
// These virtual functions should always be overridden,
|
||||
|
||||
@@ -82,6 +82,7 @@ public:
|
||||
|
||||
// LLVisualParam Virtual functions
|
||||
///*virtual*/ BOOL parseData(LLXmlTreeNode* node);
|
||||
/*virtual*/ std::string getDumpWearableTypeName(void) const;
|
||||
|
||||
// New Virtual functions
|
||||
virtual F32 getTotalDistortion() = 0;
|
||||
|
||||
@@ -41,6 +41,7 @@ class LLVisualParam;
|
||||
class LLTexGlobalColorInfo;
|
||||
class LLTexGlobalColor;
|
||||
class LLAvatarAppearance;
|
||||
class AIArchetype;
|
||||
|
||||
// Abstract class.
|
||||
class LLWearable
|
||||
|
||||
@@ -59,8 +59,13 @@ bool attemptDelayLoad()
|
||||
{
|
||||
__try
|
||||
{
|
||||
#if defined(_WIN64)
|
||||
if( FAILED( __HrLoadAllImportsForDll( "fmodex64.dll" ) ) )
|
||||
return false;
|
||||
#else
|
||||
if( FAILED( __HrLoadAllImportsForDll( "fmodex.dll" ) ) )
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
__except( EXCEPTION_EXECUTE_HANDLER )
|
||||
{
|
||||
|
||||
@@ -162,6 +162,10 @@ public:
|
||||
void setParamLocation(EParamLocation loc);
|
||||
EParamLocation getParamLocation() const { return mParamLocation; }
|
||||
|
||||
// Singu extensions. Used for dumping the archtype.
|
||||
virtual char const* getTypeString(void) const = 0;
|
||||
virtual std::string getDumpWearableTypeName(void) const = 0;
|
||||
|
||||
protected:
|
||||
F32 mCurWeight; // current weight
|
||||
F32 mLastWeight; // last weight
|
||||
|
||||
@@ -17,6 +17,8 @@ include_directories(
|
||||
)
|
||||
|
||||
set(llcommon_SOURCE_FILES
|
||||
aialert.cpp
|
||||
aifile.cpp
|
||||
aiframetimer.cpp
|
||||
aithreadid.cpp
|
||||
imageids.cpp
|
||||
@@ -106,6 +108,8 @@ set(llcommon_SOURCE_FILES
|
||||
set(llcommon_HEADER_FILES
|
||||
CMakeLists.txt
|
||||
|
||||
aialert.h
|
||||
aifile.h
|
||||
aiframetimer.h
|
||||
airecursive.h
|
||||
aithreadid.h
|
||||
|
||||
82
indra/llcommon/aialert.cpp
Normal file
82
indra/llcommon/aialert.cpp
Normal file
@@ -0,0 +1,82 @@
|
||||
/**
|
||||
* @file aialert.cpp
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 02/11/2013
|
||||
* - Initial version, written by Aleric Inglewood @ SL
|
||||
*
|
||||
* 05/11/2013
|
||||
* Moved everything in namespace AIAlert, except AIArgs.
|
||||
*/
|
||||
|
||||
#include "aialert.h"
|
||||
|
||||
namespace AIAlert
|
||||
{
|
||||
|
||||
Error::Error(Prefix const& prefix, modal_nt type,
|
||||
Error const& alert) : mLines(alert.mLines), mModal(type)
|
||||
{
|
||||
if (alert.mModal == modal) mModal = modal;
|
||||
if (prefix) mLines.push_front(Line(prefix));
|
||||
}
|
||||
|
||||
Error::Error(Prefix const& prefix, modal_nt type,
|
||||
std::string const& xml_desc, AIArgs const& args) : mModal(type)
|
||||
{
|
||||
if (prefix) mLines.push_back(Line(prefix));
|
||||
mLines.push_back(Line(xml_desc, args));
|
||||
}
|
||||
|
||||
Error::Error(Prefix const& prefix, modal_nt type,
|
||||
Error const& alert,
|
||||
std::string const& xml_desc, AIArgs const& args) : mLines(alert.mLines), mModal(type)
|
||||
{
|
||||
if (alert.mModal == modal) mModal = modal;
|
||||
if (prefix) mLines.push_back(Line(prefix, !mLines.empty()));
|
||||
mLines.push_back(Line(xml_desc, args));
|
||||
}
|
||||
|
||||
Error::Error(Prefix const& prefix, modal_nt type,
|
||||
std::string const& xml_desc,
|
||||
Error const& alert) : mLines(alert.mLines), mModal(type)
|
||||
{
|
||||
if (alert.mModal == modal) mModal = modal;
|
||||
if (!mLines.empty()) { mLines.front().set_newline(); }
|
||||
mLines.push_front(Line(xml_desc));
|
||||
if (prefix) mLines.push_front(Line(prefix));
|
||||
}
|
||||
|
||||
Error::Error(Prefix const& prefix, modal_nt type,
|
||||
std::string const& xml_desc, AIArgs const& args,
|
||||
Error const& alert) : mLines(alert.mLines), mModal(type)
|
||||
{
|
||||
if (alert.mModal == modal) mModal = modal;
|
||||
if (!mLines.empty()) { mLines.front().set_newline(); }
|
||||
mLines.push_front(Line(xml_desc, args));
|
||||
if (prefix) mLines.push_front(Line(prefix));
|
||||
}
|
||||
|
||||
} // namespace AIAlert
|
||||
|
||||
306
indra/llcommon/aialert.h
Normal file
306
indra/llcommon/aialert.h
Normal file
@@ -0,0 +1,306 @@
|
||||
/**
|
||||
* @file aialert.h
|
||||
* @brief Declaration of AIArgs and AIAlert classes.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 02/11/2013
|
||||
* Initial version, written by Aleric Inglewood @ SL
|
||||
*
|
||||
* 05/11/2013
|
||||
* Moved everything in namespace AIAlert, except AIArgs.
|
||||
*/
|
||||
|
||||
#ifndef AI_ALERT
|
||||
#define AI_ALERT
|
||||
|
||||
#include "llpreprocessor.h"
|
||||
#include "llstring.h"
|
||||
#include <deque>
|
||||
#include <exception>
|
||||
|
||||
//===================================================================================================================================
|
||||
// Facility to throw errors that can easily be converted to an informative pop-up floater for the user.
|
||||
|
||||
// Throw arbitrary class.
|
||||
#define THROW_ALERT_CLASS(Alert, ...) throw Alert(AIAlert::Prefix(), AIAlert::not_modal, __VA_ARGS__)
|
||||
#define THROW_MALERT_CLASS(Alert, ...) throw Alert(AIAlert::Prefix(), AIAlert::modal, __VA_ARGS__)
|
||||
#ifdef __GNUC__
|
||||
#define THROW_FALERT_CLASS(Alert, ...) throw Alert(AIAlert::Prefix(__PRETTY_FUNCTION__, AIAlert::pretty_function_prefix), AIAlert::not_modal, __VA_ARGS__)
|
||||
#define THROW_FMALERT_CLASS(Alert, ...) throw Alert(AIAlert::Prefix(__PRETTY_FUNCTION__, AIAlert::pretty_function_prefix), AIAlert::modal, __VA_ARGS__)
|
||||
#else
|
||||
#define THROW_FALERT_CLASS(Alert, ...) throw Alert(AIAlert::Prefix(__FUNCTION__, AIAlert::pretty_function_prefix), AIAlert::not_modal, __VA_ARGS__)
|
||||
#define THROW_FMALERT_CLASS(Alert, ...) throw Alert(AIAlert::Prefix(__FUNCTION__, AIAlert::pretty_function_prefix), AIAlert::modal, __VA_ARGS__)
|
||||
#endif
|
||||
|
||||
// Shortcut to throw AIAlert::Error.
|
||||
#define THROW_ALERT(...) THROW_ALERT_CLASS(AIAlert::Error, __VA_ARGS__)
|
||||
#define THROW_MALERT(...) THROW_MALERT_CLASS(AIAlert::Error, __VA_ARGS__)
|
||||
#define THROW_FALERT(...) THROW_FALERT_CLASS(AIAlert::Error, __VA_ARGS__)
|
||||
#define THROW_FMALERT(...) THROW_FMALERT_CLASS(AIAlert::Error, __VA_ARGS__)
|
||||
|
||||
// Shortcut to throw AIAlert::ErrorCode.
|
||||
#define THROW_ALERTC(...) THROW_ALERT_CLASS(AIAlert::ErrorCode, __VA_ARGS__)
|
||||
#define THROW_MALERTC(...) THROW_MALERT_CLASS(AIAlert::ErrorCode, __VA_ARGS__)
|
||||
#define THROW_FALERTC(...) THROW_FALERT_CLASS(AIAlert::ErrorCode, __VA_ARGS__)
|
||||
#define THROW_FMALERTC(...) THROW_FMALERT_CLASS(AIAlert::ErrorCode, __VA_ARGS__)
|
||||
|
||||
// Shortcut to throw AIAlert::ErrorCode with errno as code.
|
||||
#define THROW_ALERTE(...) do { int errn = errno; THROW_ALERT_CLASS(AIAlert::ErrorCode, errn, __VA_ARGS__); } while(0)
|
||||
#define THROW_MALERTE(...) do { int errn = errno; THROW_MALERT_CLASS(AIAlert::ErrorCode, errn, __VA_ARGS__); } while(0)
|
||||
#define THROW_FALERTE(...) do { int errn = errno; THROW_FALERT_CLASS(AIAlert::ErrorCode, errn, __VA_ARGS__); } while(0)
|
||||
#define THROW_FMALERTE(...) do { int errn = errno; THROW_FMALERT_CLASS(AIAlert::ErrorCode, errn, __VA_ARGS__); } while(0)
|
||||
|
||||
// Examples
|
||||
|
||||
#ifdef EXAMPLE_CODE
|
||||
|
||||
//----------------------------------------------------------
|
||||
// To show the alert box:
|
||||
|
||||
catch (AIAlert::Error const& error)
|
||||
{
|
||||
AIAlert::add(error); // Optionally pass pretty_function_prefix as second parameter to *suppress* that output.
|
||||
}
|
||||
|
||||
// or, for example
|
||||
|
||||
catch (AIAlert::ErrorCode const& error)
|
||||
{
|
||||
if (error.getCode() != EEXIST)
|
||||
{
|
||||
AIAlert::add(alert, AIAlert::pretty_function_prefix);
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------
|
||||
// To throw alerts:
|
||||
|
||||
THROW_ALERT("ExampleKey"); // A) Lookup "ExampleKey" in strings.xml and show translation.
|
||||
THROW_ALERT("ExampleKey", AIArgs("[FIRST]", first)("[SECOND]", second)(...etc...)); // B) Same as A, but replace [FIRST] with first, [SECOND] with second, etc.
|
||||
THROW_ALERT("ExampleKey", error); // C) As A, but followed by a colon and a newline, and then the text of 'error'.
|
||||
THROW_ALERT(error, "ExampleKey"); // D) The text of 'error', followed by a colon and a newline and then as A.
|
||||
THROW_ALERT("ExampleKey", AIArgs("[FIRST]", first)("[SECOND]", second), error); // E) As B, but followed by a colon and a newline, and then the text of 'error'.
|
||||
THROW_ALERT(error, "ExampleKey", AIArgs("[FIRST]", first)("[SECOND]", second)); // F) The text of 'error', followed by a colon and a newline and then as B.
|
||||
// where 'error' is a caught Error object (as above) in a rethrow.
|
||||
// Prepend ALERT with M and/or F to make the alert box Modal and/or prepend the text with the current function name.
|
||||
// For example,
|
||||
THROW_MFALERT("ExampleKey", AIArgs("[FIRST]", first)); // Throw a Modal alert box that is prefixed with the current Function name.
|
||||
// Append E after ALERT to throw an ErrorCode class that contains the current errno.
|
||||
// For example,
|
||||
THROW_FALERTE("ExampleKey", AIArgs("[FIRST]", first)); // Throw an alert box that is prefixed with the current Function name and pass errno to the catcher.
|
||||
|
||||
#endif // EXAMPLE_CODE
|
||||
|
||||
//
|
||||
//===================================================================================================================================
|
||||
|
||||
// A wrapper around LLStringUtil::format_map_t to allow constructing a dictionary
|
||||
// on one line by doing:
|
||||
//
|
||||
// AIArgs("[ARG1]", arg1)("[ARG2]", arg2)("[ARG3]", arg3)...
|
||||
|
||||
class LL_COMMON_API AIArgs
|
||||
{
|
||||
private:
|
||||
LLStringUtil::format_map_t mArgs; // The underlying replacement map.
|
||||
|
||||
public:
|
||||
// Construct an empty map.
|
||||
AIArgs(void) { }
|
||||
// Construct a map with a single replacement.
|
||||
AIArgs(char const* key, std::string const& replacement) { mArgs[key] = replacement; }
|
||||
// Add another replacement.
|
||||
AIArgs& operator()(char const* key, std::string const& replacement) { mArgs[key] = replacement; return *this; }
|
||||
// The destructor may not throw.
|
||||
~AIArgs() throw() { }
|
||||
|
||||
// Accessor.
|
||||
LLStringUtil::format_map_t const& operator*() const { return mArgs; }
|
||||
};
|
||||
|
||||
namespace AIAlert
|
||||
{
|
||||
|
||||
enum modal_nt
|
||||
{
|
||||
not_modal,
|
||||
modal
|
||||
};
|
||||
|
||||
enum alert_line_type_nt
|
||||
{
|
||||
normal = 0,
|
||||
empty_prefix = 1,
|
||||
pretty_function_prefix = 2
|
||||
// These must exist of single bits (a mask).
|
||||
};
|
||||
|
||||
// An Prefix currently comes only in two flavors:
|
||||
//
|
||||
// empty_prefix : An empty prefix.
|
||||
// pretty_function_prefix : A function name prefix, this is the function from which the alert was thrown.
|
||||
|
||||
class LL_COMMON_API Prefix
|
||||
{
|
||||
public:
|
||||
Prefix(void) : mType(empty_prefix) { }
|
||||
Prefix(char const* str, alert_line_type_nt type) : mStr(str), mType(type) { }
|
||||
|
||||
operator bool(void) const { return mType != empty_prefix; }
|
||||
alert_line_type_nt type(void) const { return mType; }
|
||||
std::string const& str(void) const { return mStr; }
|
||||
|
||||
private:
|
||||
std::string mStr; // Literal text. For example a C++ function name.
|
||||
alert_line_type_nt mType; // The type of this prefix.
|
||||
};
|
||||
|
||||
// A class that represents one line with its replacements.
|
||||
// The string mXmlDesc shall be looked up in strings.xml.
|
||||
// This is not done as part of this class because LLTrans::getString
|
||||
// is not part of llcommon.
|
||||
|
||||
class LL_COMMON_API Line
|
||||
{
|
||||
private:
|
||||
bool mNewline; // Prepend this line with a newline if set.
|
||||
std::string mXmlDesc; // The keyword to look up in string.xml.
|
||||
AIArgs mArgs; // Replacement map.
|
||||
alert_line_type_nt mType; // The type of this line: normal for normal lines, other for prefixes.
|
||||
|
||||
public:
|
||||
Line(std::string const& xml_desc, bool newline = false) : mNewline(newline), mXmlDesc(xml_desc), mType(normal) { }
|
||||
Line(std::string const& xml_desc, AIArgs const& args, bool newline = false) : mNewline(newline), mXmlDesc(xml_desc), mArgs(args), mType(normal) { }
|
||||
Line(Prefix const& prefix, bool newline = false) : mNewline(newline), mXmlDesc("AIPrefix"), mArgs("[PREFIX]", prefix.str()), mType(prefix.type()) { }
|
||||
// The destructor may not throw.
|
||||
~Line() throw() { }
|
||||
|
||||
// Prepend a newline before this line.
|
||||
void set_newline(void) { mNewline = true; }
|
||||
|
||||
// These are to be used like: LLTrans::getString(line.getXmlDesc(), line.args()) and prepend with a \n if prepend_newline() returns true.
|
||||
std::string getXmlDesc(void) const { return mXmlDesc; }
|
||||
LLStringUtil::format_map_t const& args(void) const { return *mArgs; }
|
||||
bool prepend_newline(void) const { return mNewline; }
|
||||
|
||||
// Accessors.
|
||||
bool suppressed(unsigned int suppress_mask) const { return (suppress_mask & mType) != 0; }
|
||||
bool is_prefix(void) const { return mType != normal; }
|
||||
};
|
||||
|
||||
// This class is used to throw an error that will cause
|
||||
// an alert box to pop up for the user.
|
||||
//
|
||||
// An alert box only has text and an OK button.
|
||||
// The alert box does not give feed back to the program; it is purely informational.
|
||||
|
||||
// The class represents multiple lines, each line is to be translated and catenated,
|
||||
// separated by newlines, and then written to an alert box. This is not done as part
|
||||
// of this class because LLTrans::getString and LLNotification is not part of llcommon.
|
||||
// Instead call LLNotificationUtil::add(Error const&).
|
||||
|
||||
class LL_COMMON_API Error : public std::exception
|
||||
{
|
||||
public:
|
||||
typedef std::deque<Line> lines_type;
|
||||
|
||||
// The destructor may not throw.
|
||||
~Error() throw() { }
|
||||
|
||||
// Accessors.
|
||||
lines_type const& lines(void) const { return mLines; }
|
||||
bool is_modal(void) const { return mModal == modal; }
|
||||
|
||||
// Existing alert, just add a prefix and turn alert into modal if appropriate.
|
||||
Error(Prefix const& prefix, modal_nt type, Error const& alert);
|
||||
|
||||
// A string with zero or more replacements.
|
||||
Error(Prefix const& prefix, modal_nt type,
|
||||
std::string const& xml_desc, AIArgs const& args = AIArgs());
|
||||
|
||||
// Same as above bit prepending the message with the text of another alert.
|
||||
Error(Prefix const& prefix, modal_nt type,
|
||||
Error const& alert,
|
||||
std::string const& xml_desc, AIArgs const& args = AIArgs());
|
||||
|
||||
// Same as above but appending the message with the text of another alert.
|
||||
// (no args)
|
||||
Error(Prefix const& prefix, modal_nt type,
|
||||
std::string const& xml_desc,
|
||||
Error const& alert);
|
||||
// (with args)
|
||||
Error(Prefix const& prefix, modal_nt type,
|
||||
std::string const& xml_desc, AIArgs const& args,
|
||||
Error const& alert);
|
||||
|
||||
private:
|
||||
lines_type mLines; // The lines (or prefixes) of text to be displayed, each consisting on a keyword (to be looked up in strings.xml) and a replacement map.
|
||||
modal_nt mModal; // If true, make the alert box a modal floater.
|
||||
};
|
||||
|
||||
// Same as Error but allows to pass an additional error code.
|
||||
|
||||
class LL_COMMON_API ErrorCode : public Error
|
||||
{
|
||||
private:
|
||||
int mCode;
|
||||
|
||||
public:
|
||||
// The destructor may not throw.
|
||||
~ErrorCode() throw() { }
|
||||
|
||||
// Accessor.
|
||||
int getCode(void) const { return mCode; }
|
||||
|
||||
// Just an Error with a code.
|
||||
ErrorCode(Prefix const& prefix, modal_nt type, int code,
|
||||
Error const& alert) :
|
||||
Error(prefix, type, alert), mCode(code) { }
|
||||
|
||||
// A string with zero or more replacements.
|
||||
ErrorCode(Prefix const& prefix, modal_nt type, int code,
|
||||
std::string const& xml_desc, AIArgs const& args = AIArgs()) :
|
||||
Error(prefix, type, xml_desc, args), mCode(code) { }
|
||||
|
||||
// Same as above bit prepending the message with the text of another alert.
|
||||
ErrorCode(Prefix const& prefix, modal_nt type, int code,
|
||||
Error const& alert,
|
||||
std::string const& xml_desc, AIArgs const& args = AIArgs()) :
|
||||
Error(prefix, type, alert, xml_desc, args), mCode(code) { }
|
||||
|
||||
// Same as above but appending the message with the text of another alert.
|
||||
// (no args)
|
||||
ErrorCode(Prefix const& prefix, modal_nt type, int code,
|
||||
std::string const& xml_desc,
|
||||
Error const& alert) :
|
||||
Error(prefix, type, xml_desc, alert), mCode(code) { }
|
||||
// (with args)
|
||||
ErrorCode(Prefix const& prefix, modal_nt type, int code,
|
||||
std::string const& xml_desc, AIArgs const& args,
|
||||
Error const& alert) :
|
||||
Error(prefix, type, xml_desc, args, alert), mCode(code) { }
|
||||
};
|
||||
|
||||
} // namespace AIAlert
|
||||
|
||||
#endif // AI_ALERT
|
||||
119
indra/llcommon/aifile.cpp
Normal file
119
indra/llcommon/aifile.cpp
Normal file
@@ -0,0 +1,119 @@
|
||||
/**
|
||||
* @file aifile.cpp
|
||||
* @brief POSIX file operations that throw on error.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 03/11/2013
|
||||
* Initial version, written by Aleric Inglewood @ SL
|
||||
*/
|
||||
|
||||
#include "linden_common.h"
|
||||
#include "aifile.h"
|
||||
#include "aialert.h"
|
||||
|
||||
#if LL_WINDOWS
|
||||
#include <windows.h>
|
||||
#include <stdlib.h> // Windows errno
|
||||
#else
|
||||
#include <errno.h>
|
||||
#endif
|
||||
|
||||
AIFile::AIFile(std::string const& filename, char const* accessmode)
|
||||
{
|
||||
mFp = AIFile::fopen(filename, accessmode);
|
||||
}
|
||||
|
||||
AIFile::~AIFile()
|
||||
{
|
||||
AIFile::close(mFp);
|
||||
}
|
||||
|
||||
// Like THROW_MALERTE but appends "LLFile::strerr(errn) << " (" << errn << ')'" as argument to replace [ERROR].
|
||||
#define THROW_ERROR(...) \
|
||||
do { \
|
||||
int errn = errno; \
|
||||
std::ostringstream error; \
|
||||
error << LLFile::strerr(errn) << " (" << errn << ')'; \
|
||||
THROW_MALERT_CLASS(AIAlert::ErrorCode, errn, __VA_ARGS__ ("[ERROR]", error.str())); \
|
||||
} while(0)
|
||||
|
||||
//static
|
||||
void AIFile::mkdir(std::string const& dirname, int perms)
|
||||
{
|
||||
int rc = LLFile::mkdir_nowarn(dirname, perms);
|
||||
if (rc < 0 && errno != EEXIST)
|
||||
{
|
||||
THROW_ERROR("AIFile_mkdir_Failed_to_create_DIRNAME", AIArgs("[DIRNAME]", dirname));
|
||||
}
|
||||
}
|
||||
|
||||
//static
|
||||
void AIFile::rmdir(std::string const& dirname)
|
||||
{
|
||||
int rc = LLFile::rmdir_nowarn(dirname);
|
||||
if (rc < 0 && errno != ENOENT)
|
||||
{
|
||||
THROW_ERROR("AIFile_rmdir_Failed_to_remove_DIRNAME", AIArgs("[DIRNAME]", dirname));
|
||||
}
|
||||
}
|
||||
|
||||
//static
|
||||
LLFILE* AIFile::fopen(std::string const& filename, const char* mode)
|
||||
{
|
||||
LLFILE* fp = LLFile::fopen(filename, mode);
|
||||
if (!fp)
|
||||
{
|
||||
THROW_ERROR("AIFile_fopen_Failed_to_open_FILENAME", AIArgs("[FILENAME]", filename));
|
||||
}
|
||||
return fp;
|
||||
}
|
||||
|
||||
//static
|
||||
void AIFile::close(LLFILE* file)
|
||||
{
|
||||
if (LLFile::close(file) < 0)
|
||||
{
|
||||
THROW_ERROR("AIFile_close_Failed_to_close_file", AIArgs);
|
||||
}
|
||||
}
|
||||
|
||||
//static
|
||||
void AIFile::remove(std::string const& filename)
|
||||
{
|
||||
int rc = LLFile::remove_nowarn(filename);
|
||||
if (rc < 0 && errno != ENOENT)
|
||||
{
|
||||
THROW_ERROR("AIFile_remove_Failed_to_remove_FILENAME", AIArgs("[FILENAME]", filename));
|
||||
}
|
||||
}
|
||||
|
||||
//static
|
||||
void AIFile::rename(std::string const& filename, std::string const& newname)
|
||||
{
|
||||
if (LLFile::rename_nowarn(filename, newname) < 0)
|
||||
{
|
||||
THROW_ERROR("AIFile_rename_Failed_to_rename_FILE_to_NEWFILE", AIArgs("[FILE]", filename)("[NEWFILE]", newname));
|
||||
}
|
||||
}
|
||||
|
||||
59
indra/llcommon/aifile.h
Normal file
59
indra/llcommon/aifile.h
Normal file
@@ -0,0 +1,59 @@
|
||||
/**
|
||||
* @file aifile.h
|
||||
* @brief Declaration of AIFile.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 02/11/2013
|
||||
* Initial version, written by Aleric Inglewood @ SL
|
||||
*/
|
||||
|
||||
#ifndef AIFILE_H
|
||||
#define AIFILE_H
|
||||
|
||||
#include "llfile.h"
|
||||
|
||||
// As LLFile, but throws AIAlert instead of printing a warning.
|
||||
class LL_COMMON_API AIFile
|
||||
{
|
||||
private:
|
||||
LLFILE* mFp;
|
||||
|
||||
public:
|
||||
// Scoped file (exception safe). Throws AIAlertCode with errno on failure.
|
||||
AIFile(std::string const& filename, char const* accessmode);
|
||||
~AIFile();
|
||||
|
||||
operator LLFILE* () const { return mFp; }
|
||||
|
||||
// All these functions take UTF8 path/filenames.
|
||||
static LLFILE* fopen(std::string const& filename, char const* accessmode);
|
||||
static void close(LLFILE* file);
|
||||
|
||||
static void mkdir(std::string const& dirname, int perms = 0700); // Does NOT throw when dirname already exists.
|
||||
static void rmdir(std::string const& dirname); // Does NOT throw when dirname does not exist.
|
||||
static void remove(std::string const& filename); // Does NOT throw when filename does not exist.
|
||||
static void rename(std::string const& filename, std::string const& newname);
|
||||
};
|
||||
|
||||
#endif // AIFILE_H
|
||||
@@ -123,6 +123,8 @@ LLApp::LLApp() : mThreadErrorp(NULL)
|
||||
commonCtor();
|
||||
}
|
||||
|
||||
static void* sCrashLoggerReserve = NULL;
|
||||
|
||||
void LLApp::commonCtor()
|
||||
{
|
||||
// Set our status to running
|
||||
@@ -148,6 +150,12 @@ void LLApp::commonCtor()
|
||||
sApplication = this;
|
||||
|
||||
mExceptionHandler = 0;
|
||||
|
||||
#if LL_WINDOWS
|
||||
sCrashLoggerReserve = VirtualAlloc(NULL, 512*1024, MEM_COMMIT|MEM_RESERVE, PAGE_NOACCESS);
|
||||
#else
|
||||
sCrashLoggerReserve = malloc(512*1024);
|
||||
#endif
|
||||
|
||||
// initialize the buffer to write the minidump filename to
|
||||
// (this is used to avoid allocating memory in the crash handler)
|
||||
@@ -155,6 +163,20 @@ void LLApp::commonCtor()
|
||||
mCrashReportPipeStr = L"\\\\.\\pipe\\LLCrashReporterPipe";
|
||||
}
|
||||
|
||||
#if LL_WINDOWS
|
||||
static bool clear_CrashLoggerReserve_callback(void* context, EXCEPTION_POINTERS* exinfo, MDRawAssertionInfo* assertion)
|
||||
{
|
||||
VirtualFree(sCrashLoggerReserve, 0, MEM_RELEASE);
|
||||
return true;
|
||||
}
|
||||
#else
|
||||
static bool clear_CrashLoggerReserve_callback(void* context)
|
||||
{
|
||||
free(sCrashLoggerReserve);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
LLApp::LLApp(LLErrorThread *error_thread) :
|
||||
mThreadErrorp(error_thread)
|
||||
{
|
||||
@@ -307,46 +329,12 @@ void LLApp::setupErrorHandling()
|
||||
// Install the Google Breakpad crash handler for Windows
|
||||
if(mExceptionHandler == 0)
|
||||
{
|
||||
llwarns << "adding breakpad exception handler" << llendl;
|
||||
|
||||
std::wostringstream ws;
|
||||
ws << mCrashReportPipeStr << getPid();
|
||||
std::wstring wpipe_name = ws.str();
|
||||
std::string ptmp = std::string(wpipe_name.begin(), wpipe_name.end());
|
||||
|
||||
::Sleep(2000); //HACK hopefully a static wait won't blow up in my face before google fixes their implementation.
|
||||
|
||||
//HACK this for loop is ueless. Breakpad dumbly returns success when the OOP handler isn't initialized.
|
||||
for (int retries=0;retries<5;++retries)
|
||||
{
|
||||
mExceptionHandler = new google_breakpad::ExceptionHandler(
|
||||
L"",
|
||||
NULL, //No filter
|
||||
windows_post_minidump_callback,
|
||||
0,
|
||||
google_breakpad::ExceptionHandler::HANDLER_ALL,
|
||||
MiniDumpNormal, //Generate a 'normal' minidump.
|
||||
(WCHAR *)wpipe_name.c_str(),
|
||||
NULL); //No custom client info.
|
||||
if (mExceptionHandler)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
::Sleep(100); //Wait a tick and try again.
|
||||
}
|
||||
}
|
||||
if (!mExceptionHandler)
|
||||
{
|
||||
llwarns << "Failed to initialize OOP exception handler. Defaulting to In Process handling" << llendl;
|
||||
mExceptionHandler = new google_breakpad::ExceptionHandler(
|
||||
std::wstring(mDumpPath.begin(),mDumpPath.end()), //Dump path
|
||||
0, //dump filename
|
||||
windows_post_minidump_callback,
|
||||
0,
|
||||
google_breakpad::ExceptionHandler::HANDLER_ALL);
|
||||
}
|
||||
mExceptionHandler = new google_breakpad::ExceptionHandler(
|
||||
std::wstring(mDumpPath.begin(),mDumpPath.end()), //Dump path
|
||||
clear_CrashLoggerReserve_callback,
|
||||
windows_post_minidump_callback,
|
||||
0,
|
||||
google_breakpad::ExceptionHandler::HANDLER_ALL);
|
||||
if (mExceptionHandler)
|
||||
{
|
||||
mExceptionHandler->set_handle_debug_exceptions(true);
|
||||
@@ -401,7 +389,7 @@ void LLApp::setupErrorHandling()
|
||||
|
||||
if(installHandler && (mExceptionHandler == 0))
|
||||
{
|
||||
mExceptionHandler = new google_breakpad::ExceptionHandler(mDumpPath, 0, &unix_post_minidump_callback, 0, true, 0);
|
||||
mExceptionHandler = new google_breakpad::ExceptionHandler(mDumpPath, clear_CrashLoggerReserve_callback, &unix_post_minidump_callback, 0, true, 0);
|
||||
}
|
||||
#elif LL_LINUX
|
||||
if(installHandler && (mExceptionHandler == 0))
|
||||
@@ -411,8 +399,7 @@ void LLApp::setupErrorHandling()
|
||||
mDumpPath = "/tmp";
|
||||
}
|
||||
google_breakpad::MinidumpDescriptor desc(mDumpPath);
|
||||
//mExceptionHandler = new google_breakpad::ExceptionHandler(desc, 0, unix_minidump_callback, 0, true, 0);
|
||||
mExceptionHandler = new google_breakpad::ExceptionHandler(desc, NULL, unix_minidump_callback, NULL, true, -1);
|
||||
mExceptionHandler = new google_breakpad::ExceptionHandler(desc, clear_CrashLoggerReserve_callback, unix_minidump_callback, NULL, true, -1);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -184,7 +184,7 @@ LLMutex* LLFastTimer::sLogLock = NULL;
|
||||
std::queue<LLSD> LLFastTimer::sLogQueue;
|
||||
const int LLFastTimer::NamedTimer::HISTORY_NUM = 300;
|
||||
|
||||
#if LL_WINDOWS
|
||||
#if defined(LL_WINDOWS) && !defined(_WIN64)
|
||||
#define USE_RDTSC 1
|
||||
#endif
|
||||
|
||||
|
||||
@@ -49,7 +49,8 @@ static std::string empty;
|
||||
|
||||
#if LL_WINDOWS
|
||||
// On Windows, use strerror_s().
|
||||
std::string strerr(int errn)
|
||||
//static
|
||||
std::string LLFile::strerr(int errn)
|
||||
{
|
||||
char buffer[256];
|
||||
strerror_s(buffer, errn); // infers sizeof(buffer) -- love it!
|
||||
@@ -98,7 +99,8 @@ std::string message_from(int orig_errno, const char* buffer, size_t bufflen,
|
||||
<< " (error " << stre_errno << ')');
|
||||
}
|
||||
|
||||
std::string strerr(int errn)
|
||||
//static
|
||||
std::string LLFile::strerr(int errn)
|
||||
{
|
||||
char buffer[256];
|
||||
// Select message_from() function matching the strerror_r() we have on hand.
|
||||
@@ -108,7 +110,8 @@ std::string strerr(int errn)
|
||||
#endif // ! LL_WINDOWS
|
||||
|
||||
// On either system, shorthand call just infers global 'errno'.
|
||||
std::string strerr()
|
||||
//static
|
||||
std::string LLFile::strerr()
|
||||
{
|
||||
return strerr(errno);
|
||||
}
|
||||
@@ -125,7 +128,7 @@ int warnif(const std::string& desc, const std::string& filename, int rc, int acc
|
||||
if (errn != accept)
|
||||
{
|
||||
LL_WARNS("LLFile") << "Couldn't " << desc << " '" << filename
|
||||
<< "' (errno " << errn << "): " << strerr(errn) << LL_ENDL;
|
||||
<< "' (errno " << errn << "): " << LLFile::strerr(errn) << LL_ENDL;
|
||||
}
|
||||
#if 0 && LL_WINDOWS // turn on to debug file-locking problems
|
||||
// If the problem is "Permission denied," maybe it's because another
|
||||
@@ -171,7 +174,7 @@ int warnif(const std::string& desc, const std::string& filename, int rc, int acc
|
||||
}
|
||||
|
||||
// static
|
||||
int LLFile::mkdir(const std::string& dirname, int perms)
|
||||
int LLFile::mkdir_nowarn(const std::string& dirname, int perms)
|
||||
{
|
||||
#if LL_WINDOWS
|
||||
// permissions are ignored on Windows
|
||||
@@ -181,13 +184,19 @@ int LLFile::mkdir(const std::string& dirname, int perms)
|
||||
#else
|
||||
int rc = ::mkdir(dirname.c_str(), (mode_t)perms);
|
||||
#endif
|
||||
return rc;
|
||||
}
|
||||
|
||||
int LLFile::mkdir(const std::string& dirname, int perms)
|
||||
{
|
||||
int rc = LLFile::mkdir_nowarn(dirname, perms);
|
||||
// We often use mkdir() to ensure the existence of a directory that might
|
||||
// already exist. Don't spam the log if it does.
|
||||
return warnif("mkdir", dirname, rc, EEXIST);
|
||||
}
|
||||
|
||||
// static
|
||||
int LLFile::rmdir(const std::string& dirname)
|
||||
int LLFile::rmdir_nowarn(const std::string& dirname)
|
||||
{
|
||||
#if LL_WINDOWS
|
||||
// permissions are ignored on Windows
|
||||
@@ -197,6 +206,12 @@ int LLFile::rmdir(const std::string& dirname)
|
||||
#else
|
||||
int rc = ::rmdir(dirname.c_str());
|
||||
#endif
|
||||
return rc;
|
||||
}
|
||||
|
||||
int LLFile::rmdir(const std::string& dirname)
|
||||
{
|
||||
int rc = LLFile::rmdir_nowarn(dirname);
|
||||
return warnif("rmdir", dirname, rc);
|
||||
}
|
||||
|
||||
@@ -238,8 +253,7 @@ int LLFile::close(LLFILE * file)
|
||||
return ret_value;
|
||||
}
|
||||
|
||||
|
||||
int LLFile::remove(const std::string& filename)
|
||||
int LLFile::remove_nowarn(const std::string& filename)
|
||||
{
|
||||
#if LL_WINDOWS
|
||||
std::string utf8filename = filename;
|
||||
@@ -248,10 +262,16 @@ int LLFile::remove(const std::string& filename)
|
||||
#else
|
||||
int rc = ::remove(filename.c_str());
|
||||
#endif
|
||||
return rc;
|
||||
}
|
||||
|
||||
int LLFile::remove(const std::string& filename)
|
||||
{
|
||||
int rc = LLFile::remove_nowarn(filename);
|
||||
return warnif("remove", filename, rc);
|
||||
}
|
||||
|
||||
int LLFile::rename(const std::string& filename, const std::string& newname)
|
||||
int LLFile::rename_nowarn(const std::string& filename, const std::string& newname)
|
||||
{
|
||||
#if LL_WINDOWS
|
||||
std::string utf8filename = filename;
|
||||
@@ -262,6 +282,12 @@ int LLFile::rename(const std::string& filename, const std::string& newname)
|
||||
#else
|
||||
int rc = ::rename(filename.c_str(),newname.c_str());
|
||||
#endif
|
||||
return rc;
|
||||
}
|
||||
|
||||
int LLFile::rename(const std::string& filename, const std::string& newname)
|
||||
{
|
||||
int rc = LLFile::rename_nowarn(filename, newname);
|
||||
return warnif(STRINGIZE("rename to '" << newname << "' from"), filename, rc);
|
||||
}
|
||||
|
||||
|
||||
@@ -30,6 +30,9 @@
|
||||
#ifndef LL_LLFILE_H
|
||||
#define LL_LLFILE_H
|
||||
|
||||
#include <fstream>
|
||||
#include <sys/stat.h>
|
||||
|
||||
/**
|
||||
* This class provides a cross platform interface to the filesystem.
|
||||
* Attempts to mostly mirror the POSIX style IO functions.
|
||||
@@ -37,9 +40,6 @@
|
||||
|
||||
typedef FILE LLFILE;
|
||||
|
||||
#include <fstream>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#if LL_WINDOWS
|
||||
// windows version of stat function and stat data structure are called _stat
|
||||
typedef struct _stat llstat;
|
||||
@@ -68,6 +68,12 @@ public:
|
||||
|
||||
static int close(LLFILE * file);
|
||||
|
||||
// Singu extension: the same as below, but doesn't print a warning as to leave errno alone.
|
||||
static int mkdir_nowarn(const std::string& filename, int perms);
|
||||
static int rmdir_nowarn(const std::string& filename);
|
||||
static int remove_nowarn(const std::string& filename);
|
||||
static int rename_nowarn(const std::string& filename, const std::string& newname);
|
||||
|
||||
// perms is a permissions mask like 0777 or 0700. In most cases it will
|
||||
// be overridden by the user's umask. It is ignored on Windows.
|
||||
static int mkdir(const std::string& filename, int perms = 0700);
|
||||
@@ -82,6 +88,9 @@ public:
|
||||
std::ios::openmode mode);
|
||||
|
||||
static const char * tmpdir();
|
||||
|
||||
static std::string strerr(int errn);
|
||||
static std::string strerr();
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#include <typeinfo>
|
||||
|
||||
#include "string_table.h"
|
||||
#include "llerror.h" // llassert_always
|
||||
#include <boost/utility.hpp>
|
||||
#include <boost/function.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
|
||||
@@ -281,7 +281,12 @@ void LLMD5::raw_digest(unsigned char *s) const
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
//Singu extension: the inverse of LLMD5::raw_digest.
|
||||
void LLMD5::clone(unsigned char const* s)
|
||||
{
|
||||
memcpy(digest, s, 16);
|
||||
finalized = 1;
|
||||
}
|
||||
|
||||
void LLMD5::hex_digest(char *s) const
|
||||
{
|
||||
@@ -305,12 +310,26 @@ void LLMD5::hex_digest(char *s) const
|
||||
return;
|
||||
}
|
||||
|
||||
//Singu extension: the inverse of LLMD5::hex_digest.
|
||||
void LLMD5::clone(std::string const& hash_str)
|
||||
{
|
||||
for (int i = 0; i < 16; ++i)
|
||||
{
|
||||
unsigned char byte = 0;
|
||||
for (int j = 0; j < 2; ++j)
|
||||
{
|
||||
char c = hash_str[i * 2 + j];
|
||||
unsigned char nibble = (c >= '0' && c <= '9') ? c - '0' : c - 'a' + 10;
|
||||
byte += nibble << ((1 - j) << 2);
|
||||
}
|
||||
digest[i] = byte;
|
||||
}
|
||||
finalized = 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
std::ostream& operator<<(std::ostream &stream, LLMD5 context)
|
||||
std::ostream& operator<<(std::ostream &stream, LLMD5 const& context)
|
||||
{
|
||||
char s[33]; /* Flawfinder: ignore */
|
||||
context.hex_digest(s);
|
||||
@@ -318,23 +337,6 @@ std::ostream& operator<<(std::ostream &stream, LLMD5 context)
|
||||
return stream;
|
||||
}
|
||||
|
||||
bool operator==(const LLMD5& a, const LLMD5& b)
|
||||
{
|
||||
unsigned char a_guts[16];
|
||||
unsigned char b_guts[16];
|
||||
a.raw_digest(a_guts);
|
||||
b.raw_digest(b_guts);
|
||||
if (memcmp(a_guts,b_guts,16)==0)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
bool operator!=(const LLMD5& a, const LLMD5& b)
|
||||
{
|
||||
return !(a==b);
|
||||
}
|
||||
|
||||
// PRIVATE METHODS:
|
||||
|
||||
void LLMD5::init(){
|
||||
|
||||
@@ -32,6 +32,10 @@
|
||||
#ifndef LL_LLMD5_H
|
||||
#define LL_LLMD5_H
|
||||
|
||||
#include "llpreprocessor.h"
|
||||
#include <iosfwd>
|
||||
#include <cstring> // memcmp
|
||||
|
||||
// LLMD5.CC - source code for the C++/object oriented translation and
|
||||
// modification of MD5.
|
||||
|
||||
@@ -98,18 +102,27 @@ public:
|
||||
void update (const std::string& str);
|
||||
void finalize ();
|
||||
|
||||
bool isFinalized() const { return finalized; }
|
||||
|
||||
// constructors for special circumstances. All these constructors finalize
|
||||
// the MD5 context.
|
||||
LLMD5 (const unsigned char *string); // digest string, finalize
|
||||
LLMD5 (std::istream& stream); // digest stream, finalize
|
||||
LLMD5 (FILE *file); // digest file, close, finalize
|
||||
LLMD5 (const unsigned char *string, const unsigned int number);
|
||||
|
||||
// Singu extension: set digest directly, finalize.
|
||||
void clone(unsigned char const* digest); // Inverse of raw_digest.
|
||||
void clone(std::string const& hash_str); // Inverse of hex_digest.
|
||||
|
||||
// methods to acquire finalized result
|
||||
void raw_digest(unsigned char *array) const; // provide 16-byte array for binary data
|
||||
void hex_digest(char *string) const; // provide 33-byte array for ascii-hex string
|
||||
|
||||
friend LL_COMMON_API std::ostream& operator<< (std::ostream&, LLMD5 context);
|
||||
friend LL_COMMON_API std::ostream& operator<< (std::ostream&, LLMD5 const& context);
|
||||
friend LL_COMMON_API bool operator==(const LLMD5& a, const LLMD5& b) { return std::memcmp(a.digest ,b.digest, 16) == 0; }
|
||||
friend LL_COMMON_API bool operator!=(const LLMD5& a, const LLMD5& b) { return std::memcmp(a.digest ,b.digest, 16) != 0; }
|
||||
friend LL_COMMON_API bool operator<(const LLMD5& a, const LLMD5& b) { return std::memcmp(a.digest ,b.digest, 16) < 0; }
|
||||
|
||||
private:
|
||||
|
||||
@@ -131,7 +144,4 @@ private:
|
||||
|
||||
};
|
||||
|
||||
LL_COMMON_API bool operator==(const LLMD5& a, const LLMD5& b);
|
||||
LL_COMMON_API bool operator!=(const LLMD5& a, const LLMD5& b);
|
||||
|
||||
#endif // LL_LLMD5_H
|
||||
|
||||
@@ -200,7 +200,7 @@ inline void ll_memcpy_nonaliased_aligned_16(char* __restrict dst, const char* __
|
||||
assert((bytes % sizeof(F32))== 0);
|
||||
ll_assert_aligned(src,16);
|
||||
ll_assert_aligned(dst,16);
|
||||
assert((src < dst) ? ((src + bytes) < dst) : ((dst + bytes) < src));
|
||||
assert((src < dst) ? ((src + bytes) <= dst) : ((dst + bytes) <= src));
|
||||
assert(bytes%16==0);
|
||||
|
||||
char* end = dst + bytes;
|
||||
|
||||
@@ -416,7 +416,7 @@ static F64 calculate_cpu_frequency(U32 measure_msecs)
|
||||
unsigned long dwCurPriorityClass = GetPriorityClass(hProcess);
|
||||
int iCurThreadPriority = GetThreadPriority(hThread);
|
||||
unsigned long dwProcessMask, dwSystemMask, dwNewMask = 1;
|
||||
GetProcessAffinityMask(hProcess, &dwProcessMask, &dwSystemMask);
|
||||
GetProcessAffinityMask(hProcess, (PDWORD_PTR)&dwProcessMask, (PDWORD_PTR)&dwSystemMask);
|
||||
|
||||
SetPriorityClass(hProcess, REALTIME_PRIORITY_CLASS);
|
||||
SetThreadPriority(hThread, THREAD_PRIORITY_TIME_CRITICAL);
|
||||
|
||||
@@ -27,6 +27,9 @@
|
||||
#define LLREFCOUNT_H
|
||||
|
||||
#include <boost/noncopyable.hpp>
|
||||
#include "llpreprocessor.h" // LL_COMMON_API
|
||||
#include "stdtypes.h" // S32
|
||||
#include "llerror.h" // llassert
|
||||
|
||||
#define LL_REF_COUNT_DEBUG 0
|
||||
#if LL_REF_COUNT_DEBUG
|
||||
|
||||
@@ -37,6 +37,8 @@
|
||||
|
||||
#include <vector>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include "llpreprocessor.h"
|
||||
#include "stdtypes.h"
|
||||
|
||||
class LLRunnable;
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
|
||||
#include "llerror.h" // *TODO: eliminate this
|
||||
|
||||
#include <map>
|
||||
#include <typeinfo>
|
||||
#include <boost/noncopyable.hpp>
|
||||
|
||||
|
||||
@@ -231,7 +231,9 @@ public:
|
||||
operator std::string() const { return mString; }
|
||||
bool operator<(const LLFormatMapString& rhs) const { return mString < rhs.mString; }
|
||||
std::size_t length() const { return mString.length(); }
|
||||
|
||||
// The destructor may not throw.
|
||||
~LLFormatMapString() throw() { }
|
||||
|
||||
private:
|
||||
std::string mString;
|
||||
};
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
|
||||
#include <iostream>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
#include "stdtypes.h"
|
||||
#include "llpreprocessor.h"
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
|
||||
const S32 LL_VERSION_MAJOR = 1;
|
||||
const S32 LL_VERSION_MINOR = 8;
|
||||
const S32 LL_VERSION_PATCH = 3;
|
||||
const S32 LL_VERSION_PATCH = 4;
|
||||
const S32 LL_VERSION_BUILD = ${vBUILD};
|
||||
|
||||
const char * const LL_CHANNEL = "${VIEWER_CHANNEL}";
|
||||
|
||||
@@ -140,7 +140,7 @@ inline F64 llabs(const F64 a)
|
||||
|
||||
inline S32 lltrunc( F32 f )
|
||||
{
|
||||
#if LL_WINDOWS && !defined( __INTEL_COMPILER )
|
||||
#if LL_WINDOWS && !defined( __INTEL_COMPILER ) && !defined(_WIN64)
|
||||
// Avoids changing the floating point control word.
|
||||
// Add or subtract 0.5 - epsilon and then round
|
||||
const static U32 zpfp[] = { 0xBEFFFFFF, 0x3EFFFFFF };
|
||||
@@ -166,7 +166,7 @@ inline S32 lltrunc( F64 f )
|
||||
|
||||
inline S32 llfloor( F32 f )
|
||||
{
|
||||
#if LL_WINDOWS && !defined( __INTEL_COMPILER )
|
||||
#if LL_WINDOWS && !defined( __INTEL_COMPILER ) && !defined(_WIN64)
|
||||
// Avoids changing the floating point control word.
|
||||
// Accurate (unlike Stereopsis version) for all values between S32_MIN and S32_MAX and slightly faster than Stereopsis version.
|
||||
// Add -(0.5 - epsilon) and then round
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
#error "Please include llmath.h before this file."
|
||||
#endif
|
||||
|
||||
#if ( ( LL_DARWIN || LL_LINUX ) && !(__SSE2__) ) || ( LL_WINDOWS && ( _M_IX86_FP < 2 ) )
|
||||
#if ( ( LL_DARWIN || LL_LINUX ) && !(__SSE2__) ) || ( LL_WINDOWS && ( _M_IX86_FP < 2 ) && !defined(_WIN64) )
|
||||
#error SSE2 not enabled. LLVector4a and related class will not compile.
|
||||
#endif
|
||||
|
||||
|
||||
@@ -250,10 +250,13 @@ void AICurlEasyRequestStateMachine::finish_impl(void)
|
||||
}
|
||||
}
|
||||
|
||||
AICurlEasyRequestStateMachine::AICurlEasyRequestStateMachine(void) :
|
||||
AICurlEasyRequestStateMachine::AICurlEasyRequestStateMachine(CWD_ONLY(bool debug)) :
|
||||
#ifdef CWDEBUG
|
||||
AIStateMachine(debug),
|
||||
#endif
|
||||
mTotalDelayTimeout(AIHTTPTimeoutPolicy::getDebugSettingsCurlTimeout().getTotalDelay())
|
||||
{
|
||||
Dout(dc::statemachine, "Calling AICurlEasyRequestStateMachine(void) [" << (void*)this << "] [" << (void*)mCurlEasyRequest.get() << "]");
|
||||
Dout(dc::statemachine(mSMDebug), "Calling AICurlEasyRequestStateMachine(void) [" << (void*)this << "] [" << (void*)mCurlEasyRequest.get() << "]");
|
||||
AICurlInterface::Stats::AICurlEasyRequestStateMachine_count++;
|
||||
}
|
||||
|
||||
@@ -264,7 +267,7 @@ void AICurlEasyRequestStateMachine::setTotalDelayTimeout(F32 totalDelayTimeout)
|
||||
|
||||
AICurlEasyRequestStateMachine::~AICurlEasyRequestStateMachine()
|
||||
{
|
||||
Dout(dc::statemachine, "Calling ~AICurlEasyRequestStateMachine() [" << (void*)this << "] [" << (void*)mCurlEasyRequest.get() << "]");
|
||||
Dout(dc::statemachine(mSMDebug), "Calling ~AICurlEasyRequestStateMachine() [" << (void*)this << "] [" << (void*)mCurlEasyRequest.get() << "]");
|
||||
--AICurlInterface::Stats::AICurlEasyRequestStateMachine_count;
|
||||
}
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@
|
||||
// Construction of a AICurlEasyRequestStateMachine might throw AICurlNoEasyHandle.
|
||||
class AICurlEasyRequestStateMachine : public AIStateMachine, public AICurlEasyHandleEvents {
|
||||
public:
|
||||
AICurlEasyRequestStateMachine(void);
|
||||
AICurlEasyRequestStateMachine(CWD_ONLY(bool debug = false));
|
||||
|
||||
// Transparent access.
|
||||
AICurlEasyRequest mCurlEasyRequest;
|
||||
|
||||
@@ -343,6 +343,7 @@ void LLHTTPClient::ResponderBase::decode_llsd_body(U32 status, std::string const
|
||||
strncmp(str, "cap not found:", 14) && // Most of the other 3%.
|
||||
str[0] && // Empty happens too and aint LLSD either.
|
||||
strncmp(str, "Not Found", 9) &&
|
||||
strncmp(str, "Upstream error: ", 16) && // Received by LLEventPollResponder every 50 seconds (see http://wiki.secondlife.com/wiki/EventQueueGet).
|
||||
LLSDSerialize::fromXML(dummy, ss) > 0;
|
||||
if (server_sent_llsd_with_http_error)
|
||||
{
|
||||
|
||||
@@ -294,14 +294,14 @@ BOOL LLPartSysData::unpack(LLDataPacker &dp)
|
||||
//skip to LLPartData block
|
||||
U8 feh = 0;
|
||||
|
||||
for (U32 i = 0; i < size; ++i)
|
||||
for (S32 i = 0; i < size; ++i)
|
||||
{
|
||||
dp.unpackU8(feh, "whippang");
|
||||
}
|
||||
|
||||
dp.unpackS32(size, "partsize");
|
||||
//skip LLPartData block
|
||||
for (U32 i = 0; i < size; ++i)
|
||||
for (S32 i = 0; i < size; ++i)
|
||||
{
|
||||
dp.unpackU8(feh, "whippang");
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ set_source_files_properties(${llplugin_HEADER_FILES}
|
||||
|
||||
if(NOT WORD_SIZE EQUAL 32)
|
||||
if(WINDOWS)
|
||||
add_definitions(/FIXED:NO)
|
||||
# add_definitions(/FIXED:NO)
|
||||
else(WINDOWS) # not windows therefore gcc LINUX and DARWIN
|
||||
add_definitions(-fPIC)
|
||||
endif(WINDOWS)
|
||||
|
||||
@@ -545,7 +545,7 @@ S32 LLTextureEntry::setMaterialID(const LLMaterialID& pMaterialID)
|
||||
{
|
||||
mMaterialUpdatePending = true;
|
||||
mMaterialID = pMaterialID;
|
||||
return TEM_CHANGE_NONE;
|
||||
return TEM_CHANGE_TEXTURE;
|
||||
}
|
||||
|
||||
mMaterialUpdatePending = false;
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
const S32 TEM_CHANGE_NONE = 0x0;
|
||||
const S32 TEM_CHANGE_COLOR = 0x1;
|
||||
const S32 TEM_CHANGE_TEXTURE = 0x2;
|
||||
const S32 TEM_CHANGE_MEDIA = 0x4; //Currently doesn't do anything, (not that TEM_CHANGE_TEXTURE either)
|
||||
const S32 TEM_CHANGE_MEDIA = 0x4;
|
||||
const S32 TEM_INVALID = 0x8;
|
||||
|
||||
const S32 TEM_BUMPMAP_COUNT = 32;
|
||||
@@ -133,7 +133,13 @@ public:
|
||||
virtual const LLUUID &getID() const { return mID; }
|
||||
const LLColor4 &getColor() const { return mColor; }
|
||||
void getScale(F32 *s, F32 *t) const { *s = mScaleS; *t = mScaleT; }
|
||||
F32 getScaleS() const { return mScaleS; }
|
||||
F32 getScaleT() const { return mScaleT; }
|
||||
|
||||
void getOffset(F32 *s, F32 *t) const { *s = mOffsetS; *t = mOffsetT; }
|
||||
F32 getOffsetS() const { return mOffsetS; }
|
||||
F32 getOffsetT() const { return mOffsetT; }
|
||||
|
||||
F32 getRotation() const { return mRotation; }
|
||||
void getRotation(F32 *theta) const { *theta = mRotation; }
|
||||
|
||||
@@ -144,7 +150,7 @@ public:
|
||||
U8 getBumpShinyFullbright() const { return mBump; }
|
||||
|
||||
U8 getMediaFlags() const { return mMediaFlags & TEM_MEDIA_MASK; }
|
||||
U8 getTexGen() const { return mMediaFlags & TEM_TEX_GEN_MASK; }
|
||||
LLTextureEntry::e_texgen getTexGen() const { return LLTextureEntry::e_texgen(mMediaFlags & TEM_TEX_GEN_MASK); }
|
||||
U8 getMediaTexGen() const { return mMediaFlags; }
|
||||
F32 getGlow() const { return mGlow; }
|
||||
const LLMaterialID& getMaterialID() const { return mMaterialID; };
|
||||
|
||||
@@ -755,10 +755,12 @@ bool LLGLManager::initGL()
|
||||
#endif
|
||||
stop_glerror();
|
||||
|
||||
#if LL_WINDOWS
|
||||
if (mIsIntel && mGLVersion <= 3.f)
|
||||
{ //never try to use framebuffer objects on older intel drivers (crashy)
|
||||
mHasFramebufferObject = FALSE;
|
||||
}
|
||||
#endif
|
||||
|
||||
stop_glerror();
|
||||
|
||||
|
||||
@@ -550,7 +550,7 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade
|
||||
LL_WARNS("ShaderLoading") << "GL ERROR entering loadShaderFile(): " << error << LL_ENDL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
LL_DEBUGS("ShaderLoading") << "Loading shader file: " << filename << " class " << shader_level << LL_ENDL;
|
||||
|
||||
if (filename.empty())
|
||||
@@ -610,6 +610,10 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade
|
||||
text[count++] = strdup("#define ATTRIBUTE attribute\n");
|
||||
text[count++] = strdup("#define VARYING varying\n");
|
||||
text[count++] = strdup("#define VARYING_FLAT varying\n");
|
||||
// Need to enable extensions here instead of in the shader files,
|
||||
// before any non-preprocessor directives (per spec)
|
||||
text[count++] = strdup("#extension GL_ARB_texture_rectangle : enable\n");
|
||||
text[count++] = strdup("#extension GL_ARB_shader_texture_lod : enable\n");
|
||||
}
|
||||
else if (minor_version <= 29)
|
||||
{
|
||||
@@ -620,6 +624,10 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade
|
||||
text[count++] = strdup("#define ATTRIBUTE attribute\n");
|
||||
text[count++] = strdup("#define VARYING varying\n");
|
||||
text[count++] = strdup("#define VARYING_FLAT varying\n");
|
||||
// Need to enable extensions here instead of in the shader files,
|
||||
// before any non-preprocessor directives (per spec)
|
||||
text[count++] = strdup("#extension GL_ARB_texture_rectangle : enable\n");
|
||||
text[count++] = strdup("#extension GL_ARB_shader_texture_lod : enable\n");
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -628,6 +636,11 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade
|
||||
{
|
||||
//set version to 1.30
|
||||
text[count++] = strdup("#version 130\n");
|
||||
// Need to enable extensions here instead of in the shader files,
|
||||
// before any non-preprocessor directives (per spec)
|
||||
text[count++] = strdup("#extension GL_ARB_texture_rectangle : enable\n");
|
||||
text[count++] = strdup("#extension GL_ARB_shader_texture_lod : enable\n");
|
||||
|
||||
|
||||
//some implementations of GLSL 1.30 require integer precision be explicitly declared
|
||||
text[count++] = strdup("precision mediump int;\n");
|
||||
@@ -636,7 +649,12 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade
|
||||
else
|
||||
{ //set version to 400
|
||||
text[count++] = strdup("#version 400\n");
|
||||
// Need to enable extensions here instead of in the shader files,
|
||||
// before any non-preprocessor directives (per spec)
|
||||
text[count++] = strdup("#extension GL_ARB_texture_rectangle : enable\n");
|
||||
text[count++] = strdup("#extension GL_ARB_shader_texture_lod : enable\n");
|
||||
}
|
||||
|
||||
|
||||
text[count++] = strdup("#define DEFINE_GL_FRAGCOLOR 1\n");
|
||||
text[count++] = strdup("#define FXAA_GLSL_130 1\n");
|
||||
|
||||
@@ -171,9 +171,10 @@ LLView* LLComboBox::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *
|
||||
LLXMLNodePtr child;
|
||||
for (child = node->getFirstChild(); child.notNull(); child = child->getNextSibling())
|
||||
{
|
||||
if (child->hasName("combo_item"))
|
||||
if (child->hasName("combo_item") || child->hasName("combo_box.item"))
|
||||
{
|
||||
std::string label = child->getTextContents();
|
||||
child->getAttributeString("label", label);
|
||||
|
||||
std::string value = label;
|
||||
child->getAttributeString("value", value);
|
||||
|
||||
@@ -366,6 +366,20 @@ void LLFocusMgr::removeKeyboardFocusWithoutCallback( const LLFocusableElement* f
|
||||
}
|
||||
}
|
||||
|
||||
bool LLFocusMgr::keyboardFocusHasAccelerators() const
|
||||
{
|
||||
LLView* focus_view = dynamic_cast<LLView*>(mKeyboardFocus);
|
||||
while(focus_view)
|
||||
{
|
||||
if (focus_view->hasAccelerators())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
focus_view = focus_view->getParent();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void LLFocusMgr::setMouseCapture( LLMouseHandler* new_captor )
|
||||
{
|
||||
|
||||
@@ -121,6 +121,7 @@ public:
|
||||
void unlockFocus();
|
||||
BOOL focusLocked() const { return mLockedView != NULL; }
|
||||
|
||||
bool keyboardFocusHasAccelerators() const;
|
||||
|
||||
struct Impl;
|
||||
|
||||
|
||||
@@ -626,12 +626,12 @@ BOOL LLMenuItemSeparatorGL::handleMouseDown(S32 x, S32 y, MASK mask)
|
||||
{
|
||||
// the menu items are in the child list in bottom up order
|
||||
LLView* prev_menu_item = parent_menu->findNextSibling(this);
|
||||
return prev_menu_item ? prev_menu_item->handleMouseDown(x, prev_menu_item->getRect().getHeight(), mask) : FALSE;
|
||||
return (prev_menu_item && prev_menu_item->getVisible() && prev_menu_item->getEnabled()) ? prev_menu_item->handleMouseDown(x, prev_menu_item->getRect().getHeight(), mask) : FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
LLView* next_menu_item = parent_menu->findPrevSibling(this);
|
||||
return next_menu_item ? next_menu_item->handleMouseDown(x, 0, mask) : FALSE;
|
||||
return (next_menu_item && next_menu_item->getVisible() && next_menu_item->getEnabled()) ? next_menu_item->handleMouseDown(x, 0, mask) : FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -641,12 +641,12 @@ BOOL LLMenuItemSeparatorGL::handleMouseUp(S32 x, S32 y, MASK mask)
|
||||
if (y > getRect().getHeight() / 2)
|
||||
{
|
||||
LLView* prev_menu_item = parent_menu->findNextSibling(this);
|
||||
return prev_menu_item ? prev_menu_item->handleMouseUp(x, prev_menu_item->getRect().getHeight(), mask) : FALSE;
|
||||
return (prev_menu_item && prev_menu_item->getVisible() && prev_menu_item->getEnabled()) ? prev_menu_item->handleMouseUp(x, prev_menu_item->getRect().getHeight(), mask) : FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
LLView* next_menu_item = parent_menu->findPrevSibling(this);
|
||||
return next_menu_item ? next_menu_item->handleMouseUp(x, 0, mask) : FALSE;
|
||||
return (next_menu_item && next_menu_item->getVisible() && next_menu_item->getEnabled()) ? next_menu_item->handleMouseUp(x, 0, mask) : FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3306,50 +3306,16 @@ void LLMenuGL::showPopup(LLView* spawning_view, LLMenuGL* menu, S32 x, S32 y)
|
||||
menu->getParent()->sendChildToFront(menu);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// class LLPieMenuBranch
|
||||
// A branch to another pie menu
|
||||
//-----------------------------------------------------------------------------
|
||||
class LLPieMenuBranch : public LLMenuItemGL
|
||||
{
|
||||
public:
|
||||
LLPieMenuBranch(const std::string& name, const std::string& label, LLPieMenu* branch);
|
||||
|
||||
virtual LLXMLNodePtr getXML(bool save_children = true) const;
|
||||
|
||||
// called to rebuild the draw label
|
||||
virtual void buildDrawLabel( void );
|
||||
|
||||
virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask)
|
||||
{
|
||||
LLMenuItemGL::handleMouseUp(x,y,mask);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// doIt() - do the primary funcationality of the menu item.
|
||||
virtual void doIt( void );
|
||||
|
||||
LLPieMenu* getBranch() { return mBranch; }
|
||||
|
||||
protected:
|
||||
LLPieMenu* mBranch;
|
||||
};
|
||||
|
||||
const F32 PIE_MENU_WIDTH = 190;
|
||||
const F32 PIE_MENU_HEIGHT = 190;
|
||||
|
||||
LLPieMenuBranch::LLPieMenuBranch(const std::string& name,
|
||||
const std::string& label,
|
||||
LLPieMenu* branch)
|
||||
LLContextMenuBranch::LLContextMenuBranch(const std::string& name, const std::string& label, LLContextMenu* branch)
|
||||
: LLMenuItemGL( name, label, KEY_NONE, MASK_NONE ),
|
||||
mBranch( branch )
|
||||
{
|
||||
mBranch->hide(FALSE);
|
||||
mBranch->hide();
|
||||
mBranch->setParentMenuItem(this);
|
||||
}
|
||||
|
||||
// virtual
|
||||
LLXMLNodePtr LLPieMenuBranch::getXML(bool save_children) const
|
||||
LLXMLNodePtr LLContextMenuBranch::getXML(bool save_children) const
|
||||
{
|
||||
if (mBranch)
|
||||
{
|
||||
@@ -3360,7 +3326,7 @@ LLXMLNodePtr LLPieMenuBranch::getXML(bool save_children) const
|
||||
}
|
||||
|
||||
// called to rebuild the draw label
|
||||
void LLPieMenuBranch::buildDrawLabel( void )
|
||||
void LLContextMenuBranch::buildDrawLabel( void )
|
||||
{
|
||||
{
|
||||
// default enablement is this -- if any of the subitems are
|
||||
@@ -3386,62 +3352,72 @@ void LLPieMenuBranch::buildDrawLabel( void )
|
||||
std::string st = mDrawAccelLabel;
|
||||
appendAcceleratorString( st );
|
||||
mDrawAccelLabel = st;
|
||||
|
||||
// No special branch suffix
|
||||
mDrawBranchLabel.clear();
|
||||
|
||||
// Singu Note: This is meaningless to pies
|
||||
mDrawBranchLabel = LLMenuGL::BRANCH_SUFFIX;
|
||||
}
|
||||
|
||||
void LLContextMenuBranch::showSubMenu()
|
||||
{
|
||||
if (getDrawTextDisabled()) return; // Singu Note: Don't open disabled submenus!
|
||||
S32 center_x;
|
||||
S32 center_y;
|
||||
static LLUICachedControl<bool> context("LiruUseContextMenus", false);
|
||||
if (context) // Use the edge of this item
|
||||
{
|
||||
localPointToScreen(getRect().getWidth(), getRect().getHeight(), ¢er_x, ¢er_y);
|
||||
}
|
||||
else // Use the center of the parent pie menu, and hide it
|
||||
{
|
||||
LLContextMenu* parent = static_cast<LLContextMenu*>(getParent());
|
||||
const LLRect& rect = parent->getRect();
|
||||
parent->localPointToScreen(rect.getWidth() / 2, rect.getHeight() / 2, ¢er_x, ¢er_y);
|
||||
parent->hide();
|
||||
}
|
||||
mBranch->show(center_x, center_y, context);
|
||||
}
|
||||
|
||||
// doIt() - do the primary funcationality of the menu item.
|
||||
void LLPieMenuBranch::doIt( void )
|
||||
void LLContextMenuBranch::doIt( void )
|
||||
{
|
||||
LLPieMenu *parent = (LLPieMenu *)getParent();
|
||||
|
||||
LLRect rect = parent->getRect();
|
||||
S32 center_x;
|
||||
S32 center_y;
|
||||
parent->localPointToScreen(rect.getWidth() / 2, rect.getHeight() / 2, ¢er_x, ¢er_y);
|
||||
|
||||
parent->hide(FALSE);
|
||||
mBranch->show( center_x, center_y, FALSE );
|
||||
showSubMenu();
|
||||
}
|
||||
|
||||
void LLContextMenuBranch::setHighlight( BOOL highlight )
|
||||
{
|
||||
if (highlight == getHighlight()) return;
|
||||
LLMenuItemGL::setHighlight(highlight);
|
||||
|
||||
// Singu Note: Pie menus show subs only on click
|
||||
static LLUICachedControl<bool> context("LiruUseContextMenus", false);
|
||||
if (!context) return;
|
||||
|
||||
if (highlight)
|
||||
{
|
||||
showSubMenu();
|
||||
}
|
||||
else
|
||||
{
|
||||
mBranch->hide();
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//-----------------------------------------------------------------------------
|
||||
// class LLPieMenu
|
||||
// A circular menu of items, icons, etc.
|
||||
// class LLContextMenu
|
||||
// A context menu
|
||||
//-----------------------------------------------------------------------------
|
||||
LLPieMenu::LLPieMenu(const std::string& name, const std::string& label)
|
||||
: LLMenuGL(name, label),
|
||||
mFirstMouseDown(FALSE),
|
||||
mUseInfiniteRadius(FALSE),
|
||||
mHoverItem(NULL),
|
||||
mHoverThisFrame(FALSE),
|
||||
LLContextMenu::LLContextMenu(const std::string& name, const std::string& label)
|
||||
: LLMenuGL(name, label.empty() ? name : label),
|
||||
mHoveredAnyItem(FALSE),
|
||||
mOuterRingAlpha(1.f),
|
||||
mCurRadius(0.f),
|
||||
mRightMouseDown(FALSE)
|
||||
{
|
||||
setRect(LLRect(0,PIE_MENU_HEIGHT,PIE_MENU_WIDTH,0));
|
||||
mHoverItem(NULL)
|
||||
{
|
||||
//setBackgroundVisible(TRUE);
|
||||
LLMenuGL::setVisible(FALSE);
|
||||
}
|
||||
|
||||
LLPieMenu::LLPieMenu(const std::string& name)
|
||||
: LLMenuGL(name, name),
|
||||
mFirstMouseDown(FALSE),
|
||||
mUseInfiniteRadius(FALSE),
|
||||
mHoverItem(NULL),
|
||||
mHoverThisFrame(FALSE),
|
||||
mHoveredAnyItem(FALSE),
|
||||
mOuterRingAlpha(1.f),
|
||||
mCurRadius(0.f),
|
||||
mRightMouseDown(FALSE)
|
||||
{
|
||||
setRect(LLRect(0,PIE_MENU_HEIGHT,PIE_MENU_WIDTH,0));
|
||||
LLMenuGL::setVisible(FALSE);
|
||||
}
|
||||
|
||||
|
||||
// virtual
|
||||
LLXMLNodePtr LLPieMenu::getXML(bool save_children) const
|
||||
LLXMLNodePtr LLContextMenu::getXML(bool save_children) const
|
||||
{
|
||||
LLXMLNodePtr node = LLMenuGL::getXML();
|
||||
|
||||
@@ -3450,22 +3426,34 @@ LLXMLNodePtr LLPieMenu::getXML(bool save_children) const
|
||||
return node;
|
||||
}
|
||||
|
||||
void LLPieMenu::initXML(LLXMLNodePtr node, LLView *context, LLUICtrlFactory *factory)
|
||||
void LLContextMenu::initXML(LLXMLNodePtr node, LLView *context, LLUICtrlFactory *factory, bool is_context)
|
||||
{
|
||||
LLXMLNodePtr child;
|
||||
for (child = node->getFirstChild(); child.notNull(); child = child->getNextSibling())
|
||||
{
|
||||
if (child->hasName(LL_PIE_MENU_TAG))
|
||||
{
|
||||
// SUBMENU
|
||||
std::string name("menu");
|
||||
child->getAttributeString("name", name);
|
||||
std::string label(name);
|
||||
child->getAttributeString("label", label);
|
||||
// In context menus, more submenu is just an extension of the parent
|
||||
bool more(false);
|
||||
if (is_context && child->getAttribute_bool("more", more) && more)
|
||||
{
|
||||
//addSeparator(); // Singu Note: perhaps a separator (above) is in order, too?
|
||||
initXML(child, context, factory, true);
|
||||
//addSeparator(); // Singu Note: perhaps a separator (below) is in order, too?
|
||||
}
|
||||
else
|
||||
{
|
||||
// SUBMENU
|
||||
std::string name("menu");
|
||||
child->getAttributeString("name", name);
|
||||
std::string label(name);
|
||||
child->getAttributeString("label", label);
|
||||
|
||||
LLPieMenu *submenu = new LLPieMenu(name, label);
|
||||
appendPieMenu(submenu);
|
||||
submenu->initXML(child, context, factory);
|
||||
// Singu Note: Pie Submenus are denoted with >, while context submenus have an obvious arrow at the end
|
||||
LLContextMenu* submenu = is_context ? new LLContextMenu(name, label) : new LLPieMenu(name, label + " >");
|
||||
appendContextSubMenu(submenu);
|
||||
submenu->initXML(child, context, factory, is_context);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -3474,51 +3462,132 @@ void LLPieMenu::initXML(LLXMLNodePtr node, LLView *context, LLUICtrlFactory *fac
|
||||
}
|
||||
}
|
||||
|
||||
bool LLPieMenu::addChild(LLView* view, S32 tab_group)
|
||||
{
|
||||
if(LLMenuGL::addChild(view, tab_group))
|
||||
{
|
||||
LLMenuItemSeparatorGL* sep = dynamic_cast<LLMenuItemSeparatorGL*>(view);
|
||||
if(sep)
|
||||
sep->setVisible(false);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// virtual
|
||||
void LLPieMenu::setVisible(BOOL visible)
|
||||
void LLContextMenu::setVisible(BOOL visible)
|
||||
{
|
||||
if (!visible)
|
||||
{
|
||||
hide(FALSE);
|
||||
hide();
|
||||
}
|
||||
}
|
||||
|
||||
BOOL LLPieMenu::handleHover( S32 x, S32 y, MASK mask )
|
||||
void LLContextMenu::show(S32 x, S32 y, bool context)
|
||||
{
|
||||
// This is mostly copied from the llview class, but it continues
|
||||
// the hover handle code after a hover handler has been found.
|
||||
BOOL handled = FALSE;
|
||||
|
||||
// If we got a hover event, we've already moved the cursor
|
||||
// for any menu shifts, so subsequent mouseup messages will be in the
|
||||
// correct position. No need to correct them.
|
||||
//mShiftHoriz = 0;
|
||||
//mShiftVert = 0;
|
||||
|
||||
// release mouse capture after short period of visibility if we're using a finite boundary
|
||||
// so that right click outside of boundary will trigger new pie menu
|
||||
if (hasMouseCapture() &&
|
||||
!mRightMouseDown &&
|
||||
mShrinkBorderTimer.getStarted() &&
|
||||
mShrinkBorderTimer.getElapsedTimeF32() >= PIE_SHRINK_TIME)
|
||||
if (getChildList()->empty())
|
||||
{
|
||||
gFocusMgr.setMouseCapture(NULL);
|
||||
mUseInfiniteRadius = FALSE;
|
||||
// nothing to show, so abort
|
||||
return;
|
||||
}
|
||||
// Save click point for detecting cursor moves before mouse-up.
|
||||
// Must be in local coords to compare with mouseUp events.
|
||||
// If the mouse doesn't move, the menu will stay open ala the Mac.
|
||||
// See also LLMenuGL::showPopup()
|
||||
LLMenuHolderGL::sContextMenuSpawnPos.set(x,y);
|
||||
|
||||
arrangeAndClear();
|
||||
|
||||
S32 width = getRect().getWidth();
|
||||
S32 height = getRect().getHeight();
|
||||
const LLRect menu_region_rect = LLMenuGL::sMenuContainer->getMenuRect();
|
||||
LLView* parent_view = getParent();
|
||||
|
||||
// Singu TODO: These could probably be combined a bit more.
|
||||
if (context) // Singu Note: Determine menu repositioning behavior based on menu type
|
||||
{
|
||||
// Open upwards if menu extends past bottom
|
||||
if (y - height < menu_region_rect.mBottom)
|
||||
{
|
||||
if (getParentMenuItem())
|
||||
{
|
||||
y += height - getParentMenuItem()->getNominalHeight();
|
||||
}
|
||||
else
|
||||
{
|
||||
y += height;
|
||||
}
|
||||
}
|
||||
|
||||
// Open out to the left if menu extends past right edge
|
||||
if (x + width > menu_region_rect.mRight)
|
||||
{
|
||||
if (getParentMenuItem())
|
||||
{
|
||||
x -= getParentMenuItem()->getRect().getWidth() + width;
|
||||
}
|
||||
else
|
||||
{
|
||||
x -= width;
|
||||
}
|
||||
}
|
||||
|
||||
S32 local_x, local_y;
|
||||
parent_view->screenPointToLocal(x, y, &local_x, &local_y);
|
||||
|
||||
LLRect rect;
|
||||
rect.setLeftTopAndSize(local_x, local_y, width, height);
|
||||
setRect(rect);
|
||||
}
|
||||
else
|
||||
{
|
||||
S32 local_x, local_y;
|
||||
parent_view->screenPointToLocal(x, y, &local_x, &local_y);
|
||||
|
||||
LLRect rect;
|
||||
rect.setCenterAndSize(local_x, local_y, width, height);
|
||||
setRect(rect);
|
||||
if (!menu_region_rect.contains(rect)) // Adjust the pie rectangle to keep it on screen
|
||||
{
|
||||
S32 trans[2]={0,0};
|
||||
if (rect.mLeft < menu_region_rect.mLeft)
|
||||
{
|
||||
trans[0] = menu_region_rect.mLeft - rect.mLeft;
|
||||
}
|
||||
else if (rect.mRight > menu_region_rect.mRight)
|
||||
{
|
||||
trans[0] = menu_region_rect.mRight - rect.mRight;
|
||||
}
|
||||
if (rect.mBottom < menu_region_rect.mBottom)
|
||||
{
|
||||
trans[1] = menu_region_rect.mBottom - rect.mBottom;
|
||||
}
|
||||
else if (rect.mTop > menu_region_rect.mTop)
|
||||
{
|
||||
trans[1] = menu_region_rect.mTop - rect.mTop;
|
||||
}
|
||||
setRect(rect.translate(trans[0],trans[1]));
|
||||
LLUI::setMousePositionLocal(getParent(),rect.getCenterX(), rect.getCenterY());
|
||||
}
|
||||
}
|
||||
|
||||
LLMenuItemGL *item = pieItemFromXY( x, y );
|
||||
arrange();
|
||||
LLView::setVisible(TRUE);
|
||||
}
|
||||
|
||||
void LLContextMenu::hide()
|
||||
{
|
||||
if (!getVisible()) return;
|
||||
|
||||
LLView::setVisible(FALSE);
|
||||
|
||||
if (mHoverItem)
|
||||
{
|
||||
mHoverItem->setHighlight( FALSE );
|
||||
mHoverItem = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
BOOL LLContextMenu::handleHover( S32 x, S32 y, MASK mask )
|
||||
{
|
||||
LLMenuGL::handleHover(x, y, mask);
|
||||
|
||||
LLMenuItemGL* item = getHighlightedItem();
|
||||
|
||||
return handleHoverOver(item, x, y);
|
||||
}
|
||||
|
||||
BOOL LLContextMenu::handleHoverOver(LLMenuItemGL* item, S32 x, S32 y)
|
||||
{
|
||||
BOOL handled = FALSE;
|
||||
|
||||
if (item && item->getEnabled())
|
||||
{
|
||||
@@ -3534,37 +3603,6 @@ BOOL LLPieMenu::handleHover( S32 x, S32 y, MASK mask )
|
||||
}
|
||||
mHoverItem = item;
|
||||
mHoverItem->setHighlight( TRUE );
|
||||
|
||||
switch(pieItemIndexFromXY(x, y))
|
||||
{
|
||||
case 0:
|
||||
make_ui_sound("UISndPieMenuSliceHighlight0");
|
||||
break;
|
||||
case 1:
|
||||
make_ui_sound("UISndPieMenuSliceHighlight1");
|
||||
break;
|
||||
case 2:
|
||||
make_ui_sound("UISndPieMenuSliceHighlight2");
|
||||
break;
|
||||
case 3:
|
||||
make_ui_sound("UISndPieMenuSliceHighlight3");
|
||||
break;
|
||||
case 4:
|
||||
make_ui_sound("UISndPieMenuSliceHighlight4");
|
||||
break;
|
||||
case 5:
|
||||
make_ui_sound("UISndPieMenuSliceHighlight5");
|
||||
break;
|
||||
case 6:
|
||||
make_ui_sound("UISndPieMenuSliceHighlight6");
|
||||
break;
|
||||
case 7:
|
||||
make_ui_sound("UISndPieMenuSliceHighlight7");
|
||||
break;
|
||||
default:
|
||||
make_ui_sound("UISndPieMenuSliceHighlight0");
|
||||
break;
|
||||
}
|
||||
}
|
||||
mHoveredAnyItem = TRUE;
|
||||
}
|
||||
@@ -3585,8 +3623,170 @@ BOOL LLPieMenu::handleHover( S32 x, S32 y, MASK mask )
|
||||
handled = TRUE;
|
||||
}
|
||||
|
||||
return handled;
|
||||
}
|
||||
|
||||
// handleMouseUp and handleMouseDown are handled by LLMenuGL
|
||||
|
||||
|
||||
BOOL LLContextMenu::handleRightMouseDown(S32 x, S32 y, MASK mask)
|
||||
{
|
||||
BOOL handled = FALSE;
|
||||
|
||||
// The click was somewhere within our rectangle
|
||||
LLMenuItemGL* item = getHighlightedItem();
|
||||
|
||||
S32 local_x = x - getRect().mLeft;
|
||||
S32 local_y = y - getRect().mBottom;
|
||||
|
||||
BOOL clicked_in_menu = pointInView(local_x, local_y);
|
||||
|
||||
// grab mouse if right clicking anywhere within pie (even deadzone in middle), to detect drag outside of pie
|
||||
if (clicked_in_menu)
|
||||
{
|
||||
// capture mouse cursor as if on initial menu show
|
||||
handled = TRUE;
|
||||
}
|
||||
|
||||
if (item)
|
||||
{
|
||||
// lie to the item about where the click happened
|
||||
// to make sure it's within the item's rectangle
|
||||
if (item->handleMouseDown( 0, 0, mask ))
|
||||
{
|
||||
handled = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return handled;
|
||||
}
|
||||
|
||||
BOOL LLContextMenu::handleRightMouseUp( S32 x, S32 y, MASK mask )
|
||||
{
|
||||
S32 local_x = x - getRect().mLeft;
|
||||
S32 local_y = y - getRect().mBottom;
|
||||
|
||||
if (!mHoveredAnyItem && !pointInView(local_x, local_y))
|
||||
{
|
||||
sMenuContainer->hideMenus();
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
BOOL result = handleMouseUp( x, y, mask );
|
||||
mHoveredAnyItem = FALSE;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool LLContextMenu::addChild(LLView* view, S32 tab_group)
|
||||
{
|
||||
if (LLContextMenu* context = dynamic_cast<LLContextMenu*>(view))
|
||||
return appendContextSubMenu(context);
|
||||
if (LLMenuItemGL* item = dynamic_cast<LLMenuItemGL*>(view))
|
||||
return append(item);
|
||||
if (LLMenuGL* menu = dynamic_cast<LLMenuGL*>(view))
|
||||
return appendMenu(menu);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
BOOL LLContextMenu::appendContextSubMenu(LLContextMenu* menu)
|
||||
{
|
||||
if (menu == this)
|
||||
{
|
||||
llerrs << "Can't attach a context menu to itself" << llendl;
|
||||
}
|
||||
LLContextMenuBranch* item = new LLContextMenuBranch(menu->getName(), menu->getLabel(), menu);
|
||||
getParent()->addChild(item->getBranch());
|
||||
return append(item);
|
||||
}
|
||||
|
||||
const S32 PIE_MENU_HEIGHT = 190;
|
||||
const S32 PIE_MENU_WIDTH = 190;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// class LLPieMenu
|
||||
// A circular menu of items, icons, etc.
|
||||
//-----------------------------------------------------------------------------
|
||||
LLPieMenu::LLPieMenu(const std::string& name, const std::string& label)
|
||||
: LLContextMenu(name, label),
|
||||
mFirstMouseDown(FALSE),
|
||||
mUseInfiniteRadius(FALSE),
|
||||
mHoverIndex(-1),
|
||||
mHoverThisFrame(FALSE),
|
||||
mOuterRingAlpha(1.f),
|
||||
mCurRadius(0.f),
|
||||
mRightMouseDown(FALSE)
|
||||
{
|
||||
setRect(LLRect(0,PIE_MENU_HEIGHT,PIE_MENU_WIDTH,0));
|
||||
}
|
||||
|
||||
// Separators on pie menus are invisible
|
||||
bool LLPieMenu::addChild(LLView* view, S32 tab_group)
|
||||
{
|
||||
if (LLContextMenu::addChild(view, tab_group))
|
||||
{
|
||||
LLMenuItemSeparatorGL* sep = dynamic_cast<LLMenuItemSeparatorGL*>(view);
|
||||
if(sep)
|
||||
sep->setVisible(false);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
BOOL LLPieMenu::handleHover( S32 x, S32 y, MASK mask )
|
||||
{
|
||||
// release mouse capture after short period of visibility if we're using a finite boundary
|
||||
// so that right click outside of boundary will trigger new pie menu
|
||||
if (hasMouseCapture() &&
|
||||
!mRightMouseDown &&
|
||||
mShrinkBorderTimer.getStarted() &&
|
||||
mShrinkBorderTimer.getElapsedTimeF32() >= PIE_SHRINK_TIME)
|
||||
{
|
||||
gFocusMgr.setMouseCapture(NULL);
|
||||
mUseInfiniteRadius = FALSE;
|
||||
}
|
||||
|
||||
mHoverThisFrame = TRUE;
|
||||
|
||||
S32 index = mHoverIndex;
|
||||
mHoverIndex = pieItemIndexFromXY(x, y);
|
||||
BOOL handled = handleHoverOver(pieItemFromIndex(mHoverIndex), x, y);
|
||||
|
||||
if (mHoverItem && mHoverIndex != index)
|
||||
{
|
||||
switch(mHoverIndex)
|
||||
{
|
||||
case 0:
|
||||
make_ui_sound("UISndPieMenuSliceHighlight0");
|
||||
break;
|
||||
case 1:
|
||||
make_ui_sound("UISndPieMenuSliceHighlight1");
|
||||
break;
|
||||
case 2:
|
||||
make_ui_sound("UISndPieMenuSliceHighlight2");
|
||||
break;
|
||||
case 3:
|
||||
make_ui_sound("UISndPieMenuSliceHighlight3");
|
||||
break;
|
||||
case 4:
|
||||
make_ui_sound("UISndPieMenuSliceHighlight4");
|
||||
break;
|
||||
case 5:
|
||||
make_ui_sound("UISndPieMenuSliceHighlight5");
|
||||
break;
|
||||
case 6:
|
||||
make_ui_sound("UISndPieMenuSliceHighlight6");
|
||||
break;
|
||||
case 7:
|
||||
make_ui_sound("UISndPieMenuSliceHighlight7");
|
||||
break;
|
||||
default:
|
||||
make_ui_sound("UISndPieMenuSliceHighlight0");
|
||||
break;
|
||||
}
|
||||
}
|
||||
return handled;
|
||||
}
|
||||
|
||||
@@ -3602,11 +3802,6 @@ BOOL LLPieMenu::handleMouseDown( S32 x, S32 y, MASK mask )
|
||||
// to make sure it's within the item's rectangle
|
||||
handled = item->handleMouseDown( 0, 0, mask );
|
||||
}
|
||||
else if (!mRightMouseDown)
|
||||
{
|
||||
// call hidemenus to make sure transient selections get cleared
|
||||
((LLMenuHolderGL*)getParent())->hideMenus();
|
||||
}
|
||||
|
||||
// always handle mouse down as mouse up will close open menus
|
||||
return TRUE;
|
||||
@@ -3688,13 +3883,26 @@ BOOL LLPieMenu::handleMouseUp( S32 x, S32 y, MASK mask )
|
||||
if (item->getEnabled())
|
||||
{
|
||||
handled = item->handleMouseUp( 0, 0, mask );
|
||||
hide(TRUE);
|
||||
hide();
|
||||
}
|
||||
}
|
||||
else if (!mRightMouseDown)
|
||||
{
|
||||
// if shift is held, click is in the view, and a parent menu exists, go back up
|
||||
if (mask & MASK_SHIFT && pointInView(x, y))
|
||||
{
|
||||
if (LLMenuItemGL* branch = getParentMenuItem())
|
||||
{
|
||||
if (LLContextMenu* parent = dynamic_cast<LLContextMenu*>(branch->getParent()))
|
||||
{
|
||||
hide();
|
||||
parent->show(LLMenuHolderGL::sContextMenuSpawnPos.mX, LLMenuHolderGL::sContextMenuSpawnPos.mY, false);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
// call hidemenus to make sure transient selections get cleared
|
||||
((LLMenuHolderGL*)getParent())->hideMenus();
|
||||
sMenuContainer->hideMenus();
|
||||
}
|
||||
|
||||
if (handled)
|
||||
@@ -3732,6 +3940,7 @@ void LLPieMenu::draw()
|
||||
{
|
||||
mHoverItem->setHighlight(FALSE);
|
||||
mHoverItem = NULL;
|
||||
mHoverIndex = -1;
|
||||
}
|
||||
|
||||
F32 width = (F32) getRect().getWidth();
|
||||
@@ -3765,22 +3974,16 @@ void LLPieMenu::draw()
|
||||
gl_washer_2d( mCurRadius, (F32) PIE_CENTER_SIZE, steps, bg_color, outer_color );
|
||||
|
||||
// selected wedge
|
||||
item_list_t::iterator item_iter;
|
||||
S32 i = 0;
|
||||
for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter)
|
||||
if (mHoverItem)
|
||||
{
|
||||
if ((*item_iter)->getHighlight())
|
||||
{
|
||||
F32 arc_size = F_PI * 0.25f;
|
||||
F32 arc_size = F_PI * 0.25f;
|
||||
|
||||
F32 start_radians = (i * arc_size) - (arc_size * 0.5f);
|
||||
F32 end_radians = start_radians + arc_size;
|
||||
F32 start_radians = (mHoverIndex * arc_size) - (arc_size * 0.5f);
|
||||
F32 end_radians = start_radians + arc_size;
|
||||
|
||||
LLColor4 outer_color = selected_color;
|
||||
outer_color.mV[VALPHA] *= mOuterRingAlpha;
|
||||
gl_washer_segment_2d( mCurRadius, (F32)PIE_CENTER_SIZE, start_radians, end_radians, steps / 8, selected_color, outer_color );
|
||||
}
|
||||
i++;
|
||||
LLColor4 outer_color = selected_color;
|
||||
outer_color.mV[VALPHA] *= mOuterRingAlpha;
|
||||
gl_washer_segment_2d( mCurRadius, (F32)PIE_CENTER_SIZE, start_radians, end_radians, steps / 8, selected_color, outer_color );
|
||||
}
|
||||
|
||||
LLUI::setLineWidth( line_width );
|
||||
@@ -3807,38 +4010,10 @@ void LLPieMenu::draw()
|
||||
LLView::draw();
|
||||
}
|
||||
|
||||
void LLPieMenu::drawBackground(LLMenuItemGL* itemp, LLColor4& color)
|
||||
// virtual
|
||||
void LLPieMenu::drawBackground(LLMenuItemGL*, LLColor4&)
|
||||
{
|
||||
F32 width = (F32) getRect().getWidth();
|
||||
F32 height = (F32) getRect().getHeight();
|
||||
F32 center_x = width/2;
|
||||
F32 center_y = height/2;
|
||||
S32 steps = 100;
|
||||
|
||||
gGL.color4fv( color.mV );
|
||||
gGL.pushUIMatrix();
|
||||
{
|
||||
gGL.translateUI(center_x - itemp->getRect().mLeft, center_y - itemp->getRect().mBottom, 0.f);
|
||||
|
||||
item_list_t::iterator item_iter;
|
||||
S32 i = 0;
|
||||
for (item_iter = mItems.begin(); item_iter != mItems.end(); ++item_iter)
|
||||
{
|
||||
if ((*item_iter) == itemp)
|
||||
{
|
||||
F32 arc_size = F_PI * 0.25f;
|
||||
|
||||
F32 start_radians = (i * arc_size) - (arc_size * 0.5f);
|
||||
F32 end_radians = start_radians + arc_size;
|
||||
|
||||
LLColor4 outer_color = color;
|
||||
outer_color.mV[VALPHA] *= mOuterRingAlpha;
|
||||
gl_washer_segment_2d( mCurRadius, (F32)PIE_CENTER_SIZE, start_radians, end_radians, steps / 8, color, outer_color );
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
gGL.popUIMatrix();
|
||||
// Selection is drawn in our draw call, do nothing here and override base drawing rectangles.
|
||||
}
|
||||
|
||||
// virtual
|
||||
@@ -3853,24 +4028,9 @@ BOOL LLPieMenu::append(LLMenuItemGL *item)
|
||||
BOOL LLPieMenu::addSeparator()
|
||||
{
|
||||
LLMenuItemGL* separator = new LLMenuItemBlankGL();
|
||||
separator->setFont( LLFontGL::getFontSansSerifSmall() );
|
||||
return append( separator );
|
||||
}
|
||||
|
||||
|
||||
BOOL LLPieMenu::appendPieMenu(LLPieMenu *menu)
|
||||
{
|
||||
if (menu == this)
|
||||
{
|
||||
llerrs << "Can't attach a pie menu to itself" << llendl;
|
||||
}
|
||||
LLPieMenuBranch *item;
|
||||
item = new LLPieMenuBranch(menu->getName(), menu->getLabel(), menu);
|
||||
getParent()->addChild(item->getBranch());
|
||||
item->setFont( LLFontGL::getFontSansSerifSmall() );
|
||||
return append( item );
|
||||
}
|
||||
|
||||
// virtual
|
||||
void LLPieMenu::arrange()
|
||||
{
|
||||
@@ -3925,13 +4085,15 @@ void LLPieMenu::arrange()
|
||||
|
||||
LLMenuItemGL *LLPieMenu::pieItemFromXY(S32 x, S32 y)
|
||||
{
|
||||
// We might have shifted this menu on draw. If so, we need
|
||||
// to shift over mouseup events until we get a hover event.
|
||||
//x += mShiftHoriz;
|
||||
//y += mShiftVert;
|
||||
return pieItemFromIndex(pieItemIndexFromXY(x, y));
|
||||
}
|
||||
|
||||
S32 LLPieMenu::pieItemIndexFromXY(S32 x, S32 y)
|
||||
{
|
||||
// An arc of the pie menu is 45 degrees
|
||||
const F32 ARC_DEG = 45.f;
|
||||
|
||||
// correct for non-square pixels
|
||||
S32 delta_x = x - getRect().getWidth() / 2;
|
||||
S32 delta_y = y - getRect().getHeight() / 2;
|
||||
|
||||
@@ -3939,14 +4101,14 @@ LLMenuItemGL *LLPieMenu::pieItemFromXY(S32 x, S32 y)
|
||||
S32 dist_squared = delta_x*delta_x + delta_y*delta_y;
|
||||
if (dist_squared < PIE_CENTER_SIZE*PIE_CENTER_SIZE)
|
||||
{
|
||||
return NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// infinite radius is only used with right clicks
|
||||
S32 radius = llmax( getRect().getWidth()/2, getRect().getHeight()/2 );
|
||||
if (!(mUseInfiniteRadius && mRightMouseDown) && dist_squared > radius * radius)
|
||||
{
|
||||
return NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
F32 angle = RAD_TO_DEG * (F32) atan2((F32)delta_y, (F32)delta_x);
|
||||
@@ -3958,8 +4120,11 @@ LLMenuItemGL *LLPieMenu::pieItemFromXY(S32 x, S32 y)
|
||||
// make sure we're only using positive angles
|
||||
if (angle < 0.f) angle += 360.f;
|
||||
|
||||
S32 which = S32( angle / ARC_DEG );
|
||||
return S32( angle / ARC_DEG );
|
||||
}
|
||||
|
||||
LLMenuItemGL* LLPieMenu::pieItemFromIndex(S32 which)
|
||||
{
|
||||
if (0 <= which && which < (S32)mItems.size() )
|
||||
{
|
||||
item_list_t::iterator item_iter;
|
||||
@@ -3979,74 +4144,11 @@ LLMenuItemGL *LLPieMenu::pieItemFromXY(S32 x, S32 y)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
S32 LLPieMenu::pieItemIndexFromXY(S32 x, S32 y)
|
||||
|
||||
// virtual
|
||||
void LLPieMenu::show(S32 x, S32 y, bool mouse_down)
|
||||
{
|
||||
// An arc of the pie menu is 45 degrees
|
||||
const F32 ARC_DEG = 45.f;
|
||||
// correct for non-square pixels
|
||||
S32 delta_x = x - getRect().getWidth() / 2;
|
||||
S32 delta_y = y - getRect().getHeight() / 2;
|
||||
|
||||
// circle safe zone in the center
|
||||
if (delta_x*delta_x + delta_y*delta_y < PIE_CENTER_SIZE*PIE_CENTER_SIZE)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
F32 angle = RAD_TO_DEG * (F32) atan2((F32)delta_y, (F32)delta_x);
|
||||
|
||||
// rotate marks CCW so that east = [0, ARC_DEG) instead of
|
||||
// [-ARC_DEG/2, ARC_DEG/2)
|
||||
angle += ARC_DEG / 2.f;
|
||||
|
||||
// make sure we're only using positive angles
|
||||
if (angle < 0.f) angle += 360.f;
|
||||
|
||||
S32 which = S32( angle / ARC_DEG );
|
||||
return which;
|
||||
}
|
||||
|
||||
void LLPieMenu::show(S32 x, S32 y, BOOL mouse_down)
|
||||
{
|
||||
S32 width = getRect().getWidth();
|
||||
S32 height = getRect().getHeight();
|
||||
|
||||
const LLRect menu_region_rect = LLMenuGL::sMenuContainer->getMenuRect();
|
||||
|
||||
LLView* parent_view = getParent();
|
||||
|
||||
S32 local_x, local_y;
|
||||
parent_view->screenPointToLocal(x, y, &local_x, &local_y);
|
||||
|
||||
LLRect rect;
|
||||
rect.setCenterAndSize(local_x, local_y, width, height);
|
||||
setRect(rect);
|
||||
|
||||
arrange();
|
||||
|
||||
// Adjust the pie rectangle to keep it on screen
|
||||
if(!menu_region_rect.contains(rect))
|
||||
{
|
||||
S32 trans[2]={0,0};
|
||||
if (rect.mLeft < menu_region_rect.mLeft)
|
||||
{
|
||||
trans[0] = menu_region_rect.mLeft - rect.mLeft;
|
||||
}
|
||||
else if (rect.mRight > menu_region_rect.mRight)
|
||||
{
|
||||
trans[0] = menu_region_rect.mRight - rect.mRight;
|
||||
}
|
||||
if (rect.mBottom < menu_region_rect.mBottom)
|
||||
{
|
||||
trans[1] = menu_region_rect.mBottom - rect.mBottom;
|
||||
}
|
||||
else if (rect.mTop > menu_region_rect.mTop)
|
||||
{
|
||||
trans[1] = menu_region_rect.mTop - rect.mTop;
|
||||
}
|
||||
setRect(rect.translate(trans[0],trans[1]));
|
||||
LLUI::setMousePositionLocal(getParent(),rect.getCenterX(), rect.getCenterY());
|
||||
}
|
||||
LLContextMenu::show(x, y, false);
|
||||
|
||||
// *FIX: what happens when mouse buttons reversed?
|
||||
mRightMouseDown = mouse_down;
|
||||
@@ -4059,8 +4161,6 @@ void LLPieMenu::show(S32 x, S32 y, BOOL mouse_down)
|
||||
make_ui_sound("UISndPieMenuAppear");
|
||||
}
|
||||
|
||||
LLView::setVisible(TRUE);
|
||||
|
||||
// we want all mouse events in case user does quick right click again off of pie menu
|
||||
// rectangle, to support gestural menu traversal
|
||||
gFocusMgr.setMouseCapture(this);
|
||||
@@ -4075,16 +4175,10 @@ void LLPieMenu::show(S32 x, S32 y, BOOL mouse_down)
|
||||
}
|
||||
}
|
||||
|
||||
void LLPieMenu::hide(BOOL item_selected)
|
||||
// virtual
|
||||
void LLPieMenu::hide()
|
||||
{
|
||||
if (!getVisible()) return;
|
||||
|
||||
if (mHoverItem)
|
||||
{
|
||||
mHoverItem->setHighlight( FALSE );
|
||||
mHoverItem = NULL;
|
||||
}
|
||||
|
||||
LLContextMenu::hide();
|
||||
make_ui_sound("UISndPieMenuHide");
|
||||
|
||||
mFirstMouseDown = FALSE;
|
||||
@@ -4092,8 +4186,6 @@ void LLPieMenu::hide(BOOL item_selected)
|
||||
mUseInfiniteRadius = FALSE;
|
||||
mHoveredAnyItem = FALSE;
|
||||
|
||||
LLView::setVisible(FALSE);
|
||||
|
||||
gFocusMgr.setMouseCapture(NULL);
|
||||
}
|
||||
|
||||
@@ -4630,10 +4722,13 @@ BOOL LLMenuHolderGL::handleKey(KEY key, MASK mask, BOOL called_from_parent)
|
||||
}
|
||||
else
|
||||
{
|
||||
//highlight first enabled one
|
||||
if(pMenu->highlightNextItem(NULL))
|
||||
if (key == KEY_UP || key == KEY_DOWN) // Singu Note: Only highlight if the user actually meant to navigate through the menu
|
||||
{
|
||||
handled = true;
|
||||
//highlight first enabled one
|
||||
if (pMenu->highlightNextItem(NULL))
|
||||
{
|
||||
handled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -685,29 +685,59 @@ private:
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// class LLContextMenu
|
||||
// A context menu
|
||||
//-----------------------------------------------------------------------------
|
||||
class LLContextMenu
|
||||
: public LLMenuGL
|
||||
{
|
||||
public:
|
||||
LLContextMenu(const std::string& name, const std::string& label = "");
|
||||
|
||||
virtual LLXMLNodePtr getXML(bool save_children = true) const;
|
||||
void initXML(LLXMLNodePtr node, LLView* context, LLUICtrlFactory* factory, bool is_context);
|
||||
|
||||
public:
|
||||
virtual ~LLContextMenu() {}
|
||||
|
||||
// LLView Functionality
|
||||
// can't set visibility directly, must call show or hide
|
||||
virtual void setVisible(BOOL visible);
|
||||
|
||||
virtual void show(S32 x, S32 y, bool context = true);
|
||||
virtual void hide();
|
||||
|
||||
virtual BOOL handleHover( S32 x, S32 y, MASK mask );
|
||||
BOOL handleHoverOver(LLMenuItemGL* item, S32 x, S32 y); // Singu Note: Unify common functionality between Pie and Context hover behaviors
|
||||
virtual BOOL handleRightMouseDown( S32 x, S32 y, MASK mask );
|
||||
virtual BOOL handleRightMouseUp( S32 x, S32 y, MASK mask );
|
||||
|
||||
virtual bool addChild(LLView* view, S32 tab_group = 0);
|
||||
|
||||
BOOL appendContextSubMenu(LLContextMenu* menu);
|
||||
|
||||
protected:
|
||||
BOOL mHoveredAnyItem;
|
||||
LLMenuItemGL* mHoverItem;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// class LLPieMenu
|
||||
// A circular menu of items, icons, etc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
class LLPieMenu
|
||||
: public LLMenuGL
|
||||
: public LLContextMenu
|
||||
{
|
||||
public:
|
||||
LLPieMenu(const std::string& name, const std::string& label);
|
||||
LLPieMenu(const std::string& name);
|
||||
LLPieMenu(const std::string& name, const std::string& label = "");
|
||||
virtual ~LLPieMenu() {}
|
||||
|
||||
virtual LLXMLNodePtr getXML(bool save_children = true) const;
|
||||
void initXML(LLXMLNodePtr node, LLView *context, LLUICtrlFactory *factory);
|
||||
|
||||
// LLView Functionality
|
||||
// hide separators. they are added to 'pad' in empty cells.
|
||||
virtual bool addChild(LLView* view, S32 tab_group = 0);
|
||||
|
||||
// can't set visibility directly, must call show or hide
|
||||
virtual void setVisible(BOOL visible);
|
||||
|
||||
virtual BOOL handleHover( S32 x, S32 y, MASK mask );
|
||||
virtual BOOL handleMouseDown( S32 x, S32 y, MASK mask );
|
||||
virtual BOOL handleRightMouseDown(S32 x, S32 y, MASK mask);
|
||||
@@ -721,34 +751,59 @@ private:
|
||||
public:
|
||||
virtual BOOL addSeparator();
|
||||
|
||||
BOOL appendPieMenu(LLPieMenu *menu);
|
||||
|
||||
virtual void arrange( void );
|
||||
|
||||
// Display the menu centered on this point on the screen.
|
||||
void show(S32 x, S32 y, BOOL mouse_down);
|
||||
void hide(BOOL item_selected);
|
||||
/*virtual*/ void show(S32 x, S32 y, bool mouse_down = true);
|
||||
/*virtual*/ void hide();
|
||||
|
||||
private:
|
||||
LLMenuItemGL *pieItemFromXY(S32 x, S32 y);
|
||||
LLMenuItemGL* pieItemFromIndex(S32 which);
|
||||
S32 pieItemIndexFromXY(S32 x, S32 y);
|
||||
|
||||
// These cause menu items to be spuriously selected by right-clicks
|
||||
// near the window edge at low frame rates. I don't think they are
|
||||
// needed unless you shift the menu position in the draw() function. JC
|
||||
//S32 mShiftHoriz; // non-zero if menu had to shift this frame
|
||||
//S32 mShiftVert; // non-zero if menu had to shift this frame
|
||||
BOOL mFirstMouseDown; // true from show until mouse up
|
||||
BOOL mUseInfiniteRadius; // allow picking pie menu items anywhere outside of center circle
|
||||
LLMenuItemGL* mHoverItem;
|
||||
S32 mHoverIndex;
|
||||
BOOL mHoverThisFrame;
|
||||
BOOL mHoveredAnyItem;
|
||||
LLFrameTimer mShrinkBorderTimer;
|
||||
F32 mOuterRingAlpha; // for rendering pie menus as both bounded and unbounded
|
||||
F32 mCurRadius;
|
||||
BOOL mRightMouseDown;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// class LLContextMenuBranch
|
||||
// A branch to another context menu
|
||||
//-----------------------------------------------------------------------------
|
||||
class LLContextMenuBranch : public LLMenuItemGL
|
||||
{
|
||||
public:
|
||||
LLContextMenuBranch(const std::string& name, const std::string& label, LLContextMenu* branch);
|
||||
|
||||
virtual LLXMLNodePtr getXML(bool save_children = true) const;
|
||||
|
||||
// called to rebuild the draw label
|
||||
virtual void buildDrawLabel( void );
|
||||
|
||||
virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask)
|
||||
{
|
||||
LLMenuItemGL::handleMouseUp(x,y,mask);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// doIt() - do the primary funcationality of the menu item.
|
||||
virtual void doIt( void );
|
||||
|
||||
LLContextMenu* getBranch() { return mBranch; }
|
||||
void setHighlight( BOOL highlight );
|
||||
|
||||
protected:
|
||||
void showSubMenu();
|
||||
|
||||
LLContextMenu* mBranch;
|
||||
};
|
||||
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Class LLMenuBarGL
|
||||
|
||||
@@ -187,7 +187,8 @@ BOOL LLMultiFloater::closeAllFloaters()
|
||||
//Tab did not actually close, possibly due to a pending Save Confirmation dialog..
|
||||
//so try and close the next one in the list...
|
||||
tabToClose++;
|
||||
}else
|
||||
}
|
||||
else
|
||||
{
|
||||
//Tab closed ok.
|
||||
lastTabCount = mTabContainer->getTabCount();
|
||||
@@ -252,7 +253,7 @@ void LLMultiFloater::addFloater(LLFloater* floaterp, BOOL select_added_floater,
|
||||
else if (floaterp->getHost())
|
||||
{
|
||||
// floaterp is hosted by somebody else and
|
||||
// this is adding it, so remove it from it's old host
|
||||
// this is adding it, so remove it from its old host
|
||||
floaterp->getHost()->removeFloater(floaterp);
|
||||
}
|
||||
else if (floaterp->getParent() == gFloaterView)
|
||||
@@ -302,8 +303,21 @@ void LLMultiFloater::addFloater(LLFloater* floaterp, BOOL select_added_floater,
|
||||
{
|
||||
floaterp->setVisible(FALSE);
|
||||
}
|
||||
|
||||
// Tabs sometimes overlap resize handle
|
||||
moveResizeHandlesToFront();
|
||||
}
|
||||
|
||||
void LLMultiFloater::updateFloaterTitle(LLFloater* floaterp)
|
||||
{
|
||||
S32 index = mTabContainer->getIndexForPanel(floaterp);
|
||||
if (index != -1)
|
||||
{
|
||||
mTabContainer->setPanelTitle(index, floaterp->getShortTitle());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
BOOL selectFloater(LLFloater* floaterp)
|
||||
|
||||
@@ -329,8 +343,9 @@ void LLMultiFloater::selectPrevFloater()
|
||||
mTabContainer->selectPrevTab();
|
||||
}
|
||||
|
||||
void LLMultiFloater::showFloater(LLFloater* floaterp)
|
||||
void LLMultiFloater::showFloater(LLFloater* floaterp, LLTabContainer::eInsertionPoint insertion_point)
|
||||
{
|
||||
if(!floaterp) return;
|
||||
// we won't select a panel that already is selected
|
||||
// it is hard to do this internally to tab container
|
||||
// as tab selection is handled via index and the tab at a given
|
||||
@@ -338,7 +353,7 @@ void LLMultiFloater::showFloater(LLFloater* floaterp)
|
||||
if (floaterp != mTabContainer->getCurrentPanel() &&
|
||||
!mTabContainer->selectTabPanel(floaterp))
|
||||
{
|
||||
addFloater(floaterp, TRUE);
|
||||
addFloater(floaterp, TRUE, insertion_point);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -417,6 +432,13 @@ BOOL LLMultiFloater::handleKeyHere(KEY key, MASK mask)
|
||||
if (floater && floater->canClose() && floater->isCloseable())
|
||||
{
|
||||
floater->close();
|
||||
|
||||
// EXT-5695 (Tabbed IM window loses focus if close any tabs by Ctrl+W)
|
||||
// bring back focus on tab container if there are any tab left
|
||||
if(mTabContainer->getTabCount() > 0)
|
||||
{
|
||||
mTabContainer->setFocus(TRUE);
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
@@ -468,12 +490,17 @@ void LLMultiFloater::setFloaterFlashing(LLFloater* floaterp, BOOL flashing)
|
||||
|
||||
void LLMultiFloater::onTabSelected()
|
||||
{
|
||||
tabOpen((LLFloater*)mTabContainer->getCurrentPanel());
|
||||
LLFloater* floaterp = dynamic_cast<LLFloater*>(mTabContainer->getCurrentPanel());
|
||||
if (floaterp)
|
||||
{
|
||||
tabOpen(floaterp);
|
||||
}
|
||||
}
|
||||
|
||||
void LLMultiFloater::setCanResize(BOOL can_resize)
|
||||
{
|
||||
LLFloater::setCanResize(can_resize);
|
||||
if (!mTabContainer) return;
|
||||
if (isResizable() && mTabContainer->getTabPosition() == LLTabContainer::BOTTOM)
|
||||
{
|
||||
mTabContainer->setRightTabBtnOffset(RESIZE_HANDLE_WIDTH);
|
||||
@@ -510,16 +537,9 @@ void LLMultiFloater::updateResizeLimits()
|
||||
// initialize minimum size constraint to the original xml values.
|
||||
S32 new_min_width = mOrigMinWidth;
|
||||
S32 new_min_height = mOrigMinHeight;
|
||||
// possibly increase minimum size constraint due to children's minimums.
|
||||
for (S32 tab_idx = 0; tab_idx < mTabContainer->getTabCount(); ++tab_idx)
|
||||
{
|
||||
LLFloater* floaterp = (LLFloater*)mTabContainer->getPanelByIndex(tab_idx);
|
||||
if (floaterp)
|
||||
{
|
||||
new_min_width = llmax(new_min_width, floaterp->getMinWidth() + LLPANEL_BORDER_WIDTH * 2);
|
||||
new_min_height = llmax(new_min_height, floaterp->getMinHeight() + LLFLOATER_HEADER_SIZE + TABCNTR_HEADER_HEIGHT);
|
||||
}
|
||||
}
|
||||
|
||||
computeResizeLimits(new_min_width, new_min_height);
|
||||
|
||||
setResizeLimits(new_min_width, new_min_height);
|
||||
|
||||
S32 cur_height = getRect().getHeight();
|
||||
@@ -545,3 +565,17 @@ void LLMultiFloater::updateResizeLimits()
|
||||
gFloaterView->adjustToFitScreen(this, TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
void LLMultiFloater::computeResizeLimits(S32& new_min_width, S32& new_min_height)
|
||||
{
|
||||
// possibly increase minimum size constraint due to children's minimums.
|
||||
for (S32 tab_idx = 0; tab_idx < mTabContainer->getTabCount(); ++tab_idx)
|
||||
{
|
||||
LLFloater* floaterp = (LLFloater*)mTabContainer->getPanelByIndex(tab_idx);
|
||||
if (floaterp)
|
||||
{
|
||||
new_min_width = llmax(new_min_width, floaterp->getMinWidth() + LLPANEL_BORDER_WIDTH * 2);
|
||||
new_min_height = llmax(new_min_height, floaterp->getMinHeight() + LLFLOATER_HEADER_SIZE + TABCNTR_HEADER_HEIGHT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ public:
|
||||
virtual void growToFit(S32 content_width, S32 content_height);
|
||||
virtual void addFloater(LLFloater* floaterp, BOOL select_added_floater, LLTabContainer::eInsertionPoint insertion_point = LLTabContainer::END);
|
||||
|
||||
virtual void showFloater(LLFloater* floaterp);
|
||||
virtual void showFloater(LLFloater* floaterp, LLTabContainer::eInsertionPoint insertion_point = LLTabContainer::END);
|
||||
virtual void removeFloater(LLFloater* floaterp);
|
||||
|
||||
virtual void tabOpen(LLFloater* opened_floater);
|
||||
@@ -76,6 +76,7 @@ public:
|
||||
void onTabSelected();
|
||||
|
||||
virtual void updateResizeLimits();
|
||||
virtual void updateFloaterTitle(LLFloater* floaterp);
|
||||
|
||||
protected:
|
||||
struct LLFloaterData
|
||||
@@ -94,6 +95,9 @@ protected:
|
||||
LLTabContainer::TabPosition mTabPos;
|
||||
BOOL mAutoResize;
|
||||
S32 mOrigMinWidth, mOrigMinHeight; // logically const but initialized late
|
||||
|
||||
private:
|
||||
virtual void computeResizeLimits(S32& new_min_width, S32& new_min_height);
|
||||
};
|
||||
|
||||
#endif // LL_MULTI_FLOATER_H
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
#include "lltrans.h"
|
||||
|
||||
#include "llnotifications.h"
|
||||
#include "aialert.h"
|
||||
|
||||
#include "../newview/hippogridmanager.h"
|
||||
|
||||
@@ -1479,6 +1480,14 @@ LLNotificationPtr LLNotifications::add(const LLNotification::Params& p)
|
||||
return pNotif;
|
||||
}
|
||||
|
||||
namespace AIAlert { std::string text(Error const& error, int suppress_mask = 0); }
|
||||
LLNotificationPtr LLNotifications::add(AIAlert::Error const& error, int type, unsigned int suppress_mask)
|
||||
{
|
||||
LLSD substitutions = LLSD::emptyMap();
|
||||
substitutions["[PAYLOAD]"] = AIAlert::text(error, suppress_mask);
|
||||
return add(LLNotification::Params((type == AIAlert::modal || error.is_modal()) ? "AIAlertModal" : "AIAlert").substitutions(substitutions));
|
||||
}
|
||||
|
||||
|
||||
void LLNotifications::add(const LLNotificationPtr pNotif)
|
||||
{
|
||||
|
||||
@@ -108,6 +108,8 @@
|
||||
#include "llnotificationptr.h"
|
||||
#include "llnotificationcontext.h"
|
||||
|
||||
namespace AIAlert { class Error; }
|
||||
|
||||
typedef enum e_notification_priority
|
||||
{
|
||||
NOTIFICATION_PRIORITY_UNSPECIFIED,
|
||||
@@ -737,6 +739,7 @@ public:
|
||||
const LLSD& substitutions,
|
||||
const LLSD& payload,
|
||||
LLNotificationFunctorRegistry::ResponseFunctor functor);
|
||||
LLNotificationPtr add(AIAlert::Error const& error, int type, unsigned int suppress_mask);
|
||||
LLNotificationPtr add(const LLNotification::Params& p);
|
||||
|
||||
void forceResponse(const LLNotification::Params& params, S32 option);
|
||||
|
||||
@@ -25,11 +25,76 @@
|
||||
#include "linden_common.h"
|
||||
|
||||
#include "llnotificationsutil.h"
|
||||
#include "lltrans.h"
|
||||
|
||||
#include "llnotifications.h"
|
||||
#include "llsd.h"
|
||||
#include "llxmlnode.h" // apparently needed to call LLNotifications::instance()
|
||||
|
||||
namespace AIAlert
|
||||
{
|
||||
|
||||
LLNotificationPtr add(Error const& error, unsigned int suppress_mask, modal_nt type)
|
||||
{
|
||||
return LLNotifications::instance().add(error, type, suppress_mask);
|
||||
}
|
||||
|
||||
LLNotificationPtr add(std::string const& xml_desc, modal_nt type)
|
||||
{
|
||||
return LLNotifications::instance().add(Error(Prefix(), type, xml_desc, AIArgs()), type, 0);
|
||||
}
|
||||
|
||||
LLNotificationPtr add(std::string const& xml_desc, AIArgs const& args, modal_nt type)
|
||||
{
|
||||
return LLNotifications::instance().add(Error(Prefix(), type, xml_desc, args), type, 0);
|
||||
}
|
||||
|
||||
LLNotificationPtr add(Error const& error, std::string const& xml_desc, unsigned int suppress_mask, modal_nt type)
|
||||
{
|
||||
return LLNotifications::instance().add(Error(Prefix(), type, error, xml_desc, AIArgs()), type, suppress_mask);
|
||||
}
|
||||
|
||||
LLNotificationPtr add(Error const& error, std::string const& xml_desc, AIArgs const& args, unsigned int suppress_mask, modal_nt type)
|
||||
{
|
||||
return LLNotifications::instance().add(Error(Prefix(), type, error, xml_desc, args), type, suppress_mask);
|
||||
}
|
||||
|
||||
LLNotificationPtr add(std::string const& xml_desc, Error const& error, unsigned int suppress_mask, modal_nt type)
|
||||
{
|
||||
return LLNotifications::instance().add(Error(Prefix(), type, xml_desc, AIArgs(), error), type, suppress_mask);
|
||||
}
|
||||
|
||||
LLNotificationPtr add(std::string const& xml_desc, AIArgs const& args, Error const& error, unsigned int suppress_mask, modal_nt type)
|
||||
{
|
||||
return LLNotifications::instance().add(Error(Prefix(), type, xml_desc, args, error), type, suppress_mask);
|
||||
}
|
||||
|
||||
std::string text(Error const& error, int suppress_mask)
|
||||
{
|
||||
std::string alert_text;
|
||||
bool suppress_newlines = false;
|
||||
bool last_was_prefix = false;
|
||||
for (Error::lines_type::const_iterator line = error.lines().begin(); line != error.lines().end(); ++line)
|
||||
{
|
||||
// Even if a line is suppressed, we print its leading newline if requested, but never more than one.
|
||||
if (!suppress_newlines && line->prepend_newline())
|
||||
{
|
||||
alert_text += '\n';
|
||||
suppress_newlines = true;
|
||||
}
|
||||
if (!line->suppressed(suppress_mask))
|
||||
{
|
||||
if (last_was_prefix) alert_text += ' '; // The translation system strips off spaces... add them back.
|
||||
alert_text += LLTrans::getString(line->getXmlDesc(), line->args());
|
||||
suppress_newlines = false;
|
||||
last_was_prefix = line->is_prefix();
|
||||
}
|
||||
}
|
||||
return alert_text;
|
||||
}
|
||||
|
||||
} // namespace AIAlert
|
||||
|
||||
LLNotificationPtr LLNotificationsUtil::add(const std::string& name)
|
||||
{
|
||||
return LLNotifications::instance().add(
|
||||
|
||||
@@ -30,11 +30,55 @@
|
||||
// to avoid including the heavyweight llnotifications.h
|
||||
|
||||
#include "llnotificationptr.h"
|
||||
#include "aialert.h"
|
||||
|
||||
#include <boost/function.hpp>
|
||||
|
||||
class LLSD;
|
||||
|
||||
namespace AIAlert
|
||||
{
|
||||
// Add an alert directly to LLNotifications.
|
||||
|
||||
// Look up xml_desc in strings.xml.
|
||||
LLNotificationPtr add(std::string const& xml_desc,
|
||||
modal_nt type = not_modal);
|
||||
// ... with replacement args.
|
||||
LLNotificationPtr add(std::string const& xml_desc, AIArgs const& args,
|
||||
modal_nt type = not_modal);
|
||||
|
||||
// Append it to an existing alert error.
|
||||
LLNotificationPtr add(Error const& error,
|
||||
std::string const& xml_desc,
|
||||
unsigned int suppress_mask = 0, modal_nt type = not_modal);
|
||||
LLNotificationPtr add(Error const& error,
|
||||
std::string const& xml_desc, AIArgs const& args,
|
||||
unsigned int suppress_mask = 0, modal_nt type = not_modal);
|
||||
// Prepend it to an existing alert error.
|
||||
LLNotificationPtr add(std::string const& xml_desc,
|
||||
Error const& error,
|
||||
unsigned int suppress_mask = 0, modal_nt type = not_modal);
|
||||
LLNotificationPtr add(std::string const& xml_desc, AIArgs const& args,
|
||||
Error const& error,
|
||||
unsigned int suppress_mask = 0, modal_nt type = not_modal);
|
||||
|
||||
// Just show the caught alert error.
|
||||
LLNotificationPtr add(Error const& error,
|
||||
unsigned int suppress_mask = 0, modal_nt type = not_modal);
|
||||
|
||||
// Short cuts for enforcing modal alerts.
|
||||
inline LLNotificationPtr add_modal(std::string const& xml_desc) { return add(xml_desc, modal); }
|
||||
inline LLNotificationPtr add_modal(std::string const& xml_desc, AIArgs const& args) { return add(xml_desc, args, modal); }
|
||||
inline LLNotificationPtr add_modal(Error const& error, std::string const& xml_desc, unsigned int suppress_mask = 0) { return add(error, xml_desc, suppress_mask, modal); }
|
||||
inline LLNotificationPtr add_modal(Error const& error, std::string const& xml_desc, AIArgs const& args, unsigned int suppress_mask = 0) { return add(error, xml_desc, args, suppress_mask, modal); }
|
||||
inline LLNotificationPtr add_modal(std::string const& xml_desc, Error const& error, unsigned int suppress_mask = 0) { return add(xml_desc, error, suppress_mask, modal); }
|
||||
inline LLNotificationPtr add_modal(std::string const& xml_desc, AIArgs const& args, Error const& error, unsigned int suppress_mask = 0) { return add(xml_desc, args, error, suppress_mask, modal); }
|
||||
inline LLNotificationPtr add_modal(Error const& error, unsigned int suppress_mask = 0) { return add(error, suppress_mask, modal); }
|
||||
|
||||
// Return the full, translated, texted of the alert (possibly suppressing certain output).
|
||||
std::string text(Error const& error, int suppress_mask = 0);
|
||||
}
|
||||
|
||||
namespace LLNotificationsUtil
|
||||
{
|
||||
LLNotificationPtr add(const std::string& name);
|
||||
|
||||
@@ -530,11 +530,13 @@ BOOL LLPanel::initPanelXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *f
|
||||
|
||||
void LLPanel::initChildrenXML(LLXMLNodePtr node, LLUICtrlFactory* factory)
|
||||
{
|
||||
std::string kidstring(node->getName()->mString);
|
||||
kidstring += ".string";
|
||||
LLXMLNodePtr child;
|
||||
for (child = node->getFirstChild(); child.notNull(); child = child->getNextSibling())
|
||||
{
|
||||
// look for string declarations for programmatic text
|
||||
if (child->hasName("string"))
|
||||
if (child->hasName("string") || child->hasName(kidstring))
|
||||
{
|
||||
std::string string_name;
|
||||
child->getAttributeString("name", string_name);
|
||||
|
||||
@@ -40,9 +40,10 @@ const S32 MIN_COLUMN_WIDTH = 20;
|
||||
//---------------------------------------------------------------------------
|
||||
// LLScrollColumnHeader
|
||||
//---------------------------------------------------------------------------
|
||||
LLScrollColumnHeader::LLScrollColumnHeader(const std::string& name, const LLRect& rect, LLScrollListColumn* column)
|
||||
: LLButton(name, rect, "square_btn_32x128.tga", "square_btn_selected_32x128.tga", LLStringUtil::null, NULL, LLFontGL::getFontSansSerifSmall()),
|
||||
LLScrollColumnHeader::LLScrollColumnHeader(const std::string& name, const LLRect& rect, LLScrollListColumn* column, const std::string& unselected_image_name, const std::string& selected_image_name)
|
||||
: LLButton(name, rect, unselected_image_name, selected_image_name, LLStringUtil::null, NULL, LLFontGL::getFontSansSerifSmall()),
|
||||
mColumn(column),
|
||||
mDrawArrow(true),
|
||||
mHasResizableElement(FALSE)
|
||||
{
|
||||
setClickedCallback(boost::bind(&LLScrollColumnHeader::onClick, this, _2));
|
||||
@@ -65,20 +66,23 @@ LLScrollColumnHeader::~LLScrollColumnHeader()
|
||||
|
||||
void LLScrollColumnHeader::draw()
|
||||
{
|
||||
std::string sort_column = mColumn->mParentCtrl->getSortColumnName();
|
||||
BOOL draw_arrow = !mColumn->mLabel.empty()
|
||||
&& mColumn->mParentCtrl->isSorted()
|
||||
// check for indirect sorting column as well as column's sorting name
|
||||
&& (sort_column == mColumn->mSortingColumn || sort_column == mColumn->mName);
|
||||
if (mDrawArrow)
|
||||
{
|
||||
std::string sort_column = mColumn->mParentCtrl->getSortColumnName();
|
||||
BOOL draw_arrow = !mColumn->mLabel.empty()
|
||||
&& mColumn->mParentCtrl->isSorted()
|
||||
// check for indirect sorting column as well as column's sorting name
|
||||
&& (sort_column == mColumn->mSortingColumn || sort_column == mColumn->mName);
|
||||
|
||||
BOOL is_ascending = mColumn->mParentCtrl->getSortAscending();
|
||||
if (draw_arrow)
|
||||
{
|
||||
setImageOverlay(is_ascending ? "up_arrow.tga" : "down_arrow.tga", LLFontGL::RIGHT, LLColor4::white);
|
||||
}
|
||||
else
|
||||
{
|
||||
setImageOverlay(LLUUID::null);
|
||||
BOOL is_ascending = mColumn->mParentCtrl->getSortAscending();
|
||||
if (draw_arrow)
|
||||
{
|
||||
setImageOverlay(is_ascending ? "up_arrow.tga" : "down_arrow.tga", LLFontGL::RIGHT, LLColor4::white);
|
||||
}
|
||||
else
|
||||
{
|
||||
setImageOverlay(LLUUID::null);
|
||||
}
|
||||
}
|
||||
|
||||
// Draw children
|
||||
|
||||
@@ -40,7 +40,7 @@ class LLScrollListCtrl;
|
||||
class LLScrollColumnHeader : public LLButton
|
||||
{
|
||||
public:
|
||||
LLScrollColumnHeader(const std::string& name, const LLRect& rect, LLScrollListColumn* column);
|
||||
LLScrollColumnHeader(const std::string& name, const LLRect& rect, LLScrollListColumn* column, const std::string& unselected_image_name = "square_btn_32x128.tga", const std::string& selected_image_name = "square_btn_selected_32x128.tga");
|
||||
~LLScrollColumnHeader();
|
||||
|
||||
/*virtual*/ void draw();
|
||||
@@ -51,6 +51,8 @@ public:
|
||||
/*virtual*/ void handleReshape(const LLRect& new_rect, bool by_user = false);
|
||||
|
||||
LLScrollListColumn* getColumn() { return mColumn; }
|
||||
// Singu Note: Toggles drawing the sort arrow altogether
|
||||
void setDrawArrow(bool draw_arrow) { mDrawArrow = draw_arrow; }
|
||||
void setHasResizableElement(BOOL resizable);
|
||||
void updateResizeBars();
|
||||
BOOL canResize();
|
||||
@@ -60,6 +62,7 @@ public:
|
||||
|
||||
private:
|
||||
LLScrollListColumn* mColumn;
|
||||
bool mDrawArrow;
|
||||
LLResizeBar* mResizeBar;
|
||||
BOOL mHasResizableElement;
|
||||
};
|
||||
|
||||
@@ -2848,24 +2848,29 @@ void LLScrollListCtrl::addColumn(const LLScrollListColumn::Params& column_params
|
||||
|
||||
LLRect temp_rect = LLRect(left,top+mHeadingHeight,right,top);
|
||||
|
||||
new_column->mHeader = new LLScrollColumnHeader("btn_" + name, temp_rect, new_column);
|
||||
new_column->mHeader->setToolTip(column_params.tool_tip());
|
||||
new_column->mHeader->setTabStop(false);
|
||||
new_column->mHeader->setVisible(mDisplayColumnHeaders);
|
||||
|
||||
if(column_params.header.image.isProvided())
|
||||
if (column_params.header.image.isProvided())
|
||||
{
|
||||
new_column->mHeader->setImages(column_params.header.image, column_params.header.image);
|
||||
}
|
||||
else if(column_params.header.image_overlay.isProvided())
|
||||
{
|
||||
new_column->mHeader->setImageOverlay(column_params.header.image_overlay);
|
||||
new_column->mHeader = new LLScrollColumnHeader("btn_" + name, temp_rect, new_column, column_params.header.image, column_params.header.image);
|
||||
new_column->mHeader->setDrawArrow(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
new_column->mHeader->setLabel(column_params.header.label());
|
||||
new_column->mHeader = new LLScrollColumnHeader("btn_" + name, temp_rect, new_column);
|
||||
if (column_params.header.image_overlay.isProvided())
|
||||
{
|
||||
new_column->mHeader->setImageOverlay(column_params.header.image_overlay);
|
||||
new_column->mHeader->setDrawArrow(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
new_column->mHeader->setLabel(column_params.header.label());
|
||||
}
|
||||
}
|
||||
|
||||
new_column->mHeader->setToolTip(column_params.tool_tip());
|
||||
new_column->mHeader->setTabStop(false);
|
||||
new_column->mHeader->setVisible(mDisplayColumnHeaders);
|
||||
|
||||
addChild(new_column->mHeader);
|
||||
|
||||
sendChildToFront(mScrollbar);
|
||||
|
||||
@@ -446,7 +446,7 @@ LLMenuGL *LLUICtrlFactory::buildMenu(const std::string &filename, LLView* parent
|
||||
//-----------------------------------------------------------------------------
|
||||
// buildMenu()
|
||||
//-----------------------------------------------------------------------------
|
||||
LLPieMenu *LLUICtrlFactory::buildPieMenu(const std::string &filename, LLView* parentp)
|
||||
LLContextMenu* LLUICtrlFactory::buildContextMenu(const std::string& filename, LLView* parentp)
|
||||
{
|
||||
LLXMLNodePtr root;
|
||||
|
||||
@@ -465,9 +465,10 @@ LLPieMenu *LLUICtrlFactory::buildPieMenu(const std::string &filename, LLView* pa
|
||||
std::string name("menu");
|
||||
root->getAttributeString("name", name);
|
||||
|
||||
LLPieMenu *menu = new LLPieMenu(name);
|
||||
static LLUICachedControl<bool> context("LiruUseContextMenus", false);
|
||||
LLContextMenu* menu = context ? new LLContextMenu(name) : new LLPieMenu(name);
|
||||
parentp->addChild(menu);
|
||||
menu->initXML(root, parentp, this);
|
||||
menu->initXML(root, parentp, this, context);
|
||||
|
||||
if (LLUI::sShowXUINames)
|
||||
{
|
||||
|
||||
@@ -106,7 +106,7 @@ public:
|
||||
bool builtPanel(LLPanel* panelp) {return mBuiltPanels.find(panelp->getHandle()) != mBuiltPanels.end();}
|
||||
|
||||
class LLMenuGL *buildMenu(const std::string &filename, LLView* parentp);
|
||||
class LLPieMenu *buildPieMenu(const std::string &filename, LLView* parentp);
|
||||
class LLContextMenu* buildContextMenu(const std::string& filename, LLView* parentp);
|
||||
|
||||
// Does what you want for LLFloaters and LLPanels
|
||||
// Returns 0 on success
|
||||
|
||||
@@ -357,6 +357,11 @@ public:
|
||||
BOOL focusNextRoot();
|
||||
BOOL focusPrevRoot();
|
||||
|
||||
// Normally we want the app menus to get priority on accelerated keys
|
||||
// However, sometimes we want to give specific views a first chance
|
||||
// at handling them. (eg. the script editor)
|
||||
virtual bool hasAccelerators() const { return false; }
|
||||
|
||||
virtual void deleteAllChildren();
|
||||
|
||||
virtual void setTentative(BOOL b);
|
||||
|
||||
@@ -363,7 +363,11 @@ std::string LLDir::buildSLOSCacheDir() const
|
||||
}
|
||||
else
|
||||
{
|
||||
#if defined(_WIN64)
|
||||
res = add(getOSCacheDir(), "SingularityViewer64");
|
||||
#else
|
||||
res = add(getOSCacheDir(), "SingularityViewer");
|
||||
#endif
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -749,7 +749,7 @@ void LLWindowWin32::close()
|
||||
LL_DEBUGS("Window") << "Destroying Window" << LL_ENDL;
|
||||
|
||||
// Don't process events in our mainWindowProc any longer.
|
||||
SetWindowLong(mWindowHandle, GWL_USERDATA, NULL);
|
||||
SetWindowLongPtr(mWindowHandle, GWLP_USERDATA, NULL);
|
||||
|
||||
// Make sure we don't leave a blank toolbar button.
|
||||
ShowWindow(mWindowHandle, SW_HIDE);
|
||||
@@ -1660,7 +1660,7 @@ BOOL LLWindowWin32::switchContext(BOOL fullscreen, const LLCoordScreen &size, BO
|
||||
LL_DEBUGS("Window") << "Keeping vertical sync" << LL_ENDL;
|
||||
}
|
||||
|
||||
SetWindowLong(mWindowHandle, GWL_USERDATA, (U32)this);
|
||||
SetWindowLongPtr(mWindowHandle, GWLP_USERDATA, (LONG_PTR)this);
|
||||
|
||||
// register this window as handling drag/drop events from the OS
|
||||
DragAcceptFiles( mWindowHandle, TRUE );
|
||||
@@ -1983,7 +1983,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_
|
||||
// This helps prevent avatar walking after maximizing the window by double-clicking the title bar.
|
||||
static bool sHandleLeftMouseUp = true;
|
||||
|
||||
LLWindowWin32 *window_imp = (LLWindowWin32 *)GetWindowLong(h_wnd, GWL_USERDATA);
|
||||
LLWindowWin32 *window_imp = (LLWindowWin32 *)GetWindowLongPtr(h_wnd, GWLP_USERDATA);
|
||||
|
||||
|
||||
if (NULL != window_imp)
|
||||
|
||||
@@ -13,6 +13,7 @@ include_directories(
|
||||
)
|
||||
|
||||
set(llxml_SOURCE_FILES
|
||||
aixml.cpp
|
||||
llcontrol.cpp
|
||||
llxmlnode.cpp
|
||||
llxmlparser.cpp
|
||||
@@ -22,6 +23,7 @@ set(llxml_SOURCE_FILES
|
||||
set(llxml_HEADER_FILES
|
||||
CMakeLists.txt
|
||||
|
||||
aixml.h
|
||||
llcontrol.h
|
||||
llcontrolgroupreader.h
|
||||
llxmlnode.h
|
||||
|
||||
609
indra/llxml/aixml.cpp
Normal file
609
indra/llxml/aixml.cpp
Normal file
@@ -0,0 +1,609 @@
|
||||
/**
|
||||
* @file aixml.cpp
|
||||
* @brief XML serialization support.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 30/07/2013
|
||||
* Initial version, written by Aleric Inglewood @ SL
|
||||
*/
|
||||
|
||||
#include "sys.h"
|
||||
#include "aixml.h"
|
||||
#include "llmd5.h"
|
||||
#include <boost/tokenizer.hpp>
|
||||
#include "aifile.h"
|
||||
|
||||
//=============================================================================
|
||||
// Overview
|
||||
|
||||
// The AIXML* classes provide an Object Oriented way to serialize objects
|
||||
// to and from an XML file.
|
||||
//
|
||||
// The following classes are provided:
|
||||
//
|
||||
// AIXMLRootElement - Write an object to a file (including XML declaration at the top).
|
||||
// AIXMLElement - Write an ojbect to an ostream (just one XML element).
|
||||
//
|
||||
// AIXMLParser - Read and deserialize an XML file written with AIXMLRootElement.
|
||||
// AIXMLElementParser - Read and deserialize an XML stream written with AIXMLElement.
|
||||
//
|
||||
// Classes that need to be written to and from XML would typically
|
||||
// supply two member functions. For example,
|
||||
|
||||
#ifdef EXAMPLE_CODE // undefined
|
||||
|
||||
class HelloWorld {
|
||||
public:
|
||||
// Write object to XML.
|
||||
void toXML(std::ostream& os, int indentation) const;
|
||||
// Read object from XML.
|
||||
HelloWorld(AIXMLElementParser const& parser);
|
||||
|
||||
private:
|
||||
// Example member variables...
|
||||
Attribute1 mAttribute1;
|
||||
Attribute2 mAttribute2;
|
||||
// etc.
|
||||
Custom1 mCustom;
|
||||
std::vector<Custom2> mContainer;
|
||||
LLDate mDate;
|
||||
LLMD5 mMd5;
|
||||
LLUUID mUUID;
|
||||
};
|
||||
|
||||
// Typical serialization member function.
|
||||
void HelloWorld::toXML(std::ostream& os, int indentation) const
|
||||
{
|
||||
AIXMLElement tag(os, "helloworld", indentation);
|
||||
|
||||
// Zero or more attributes:
|
||||
tag.attribute("attributename1", mAttribute1); // Uses operator<<(std::ostream&, Attribute1 const&) to write mAttribute1.
|
||||
tag.attribute("attributename2", mAttribute2); // Uses operator<<(std::ostream&, Attribute2 const&) to write mAttribute2.
|
||||
// etc.
|
||||
|
||||
// Zero or more child elements:
|
||||
tag.child("tagname", mChild1);
|
||||
tag.child(mCustom); // Calls mCustom.toXML() to insert the object.
|
||||
tag.child(mContainer.begin(), mContainer.end()); // Calls tag.child(element) for each element of the container.
|
||||
// Special allowed cases:
|
||||
tag.child(mDate); // Uses "date" as tag name.
|
||||
tag.child(mMd5); // Uses "md5" as tag name.
|
||||
tag.child(mUUID); // Uses "uuid" as tag name.
|
||||
}
|
||||
|
||||
// Typical deserialization member function.
|
||||
HelloWorld::HelloWorld(AIXMLElementParser const& parser)
|
||||
{
|
||||
// Zero or more attributes:
|
||||
parser.attribute("attributename1", "foobar"); // Throws std::runtime_error is attributename1 is missing or does not have the value "foobar".
|
||||
if (!parser.attribute("attributename2", mAttribute2)) // Reads value of attributename2 into mAttribute2 (throws if it could not be parsed).
|
||||
{
|
||||
throw std::runtime_error("..."); // Attribute was missing.
|
||||
}
|
||||
|
||||
// Zero or more child elements:
|
||||
parser.child("tagname", mChild1);
|
||||
parser.child("custom1", mCustom);
|
||||
parser.insert_children("custom2", mContainer);
|
||||
// Special allowed cases:
|
||||
parser.child(mDate);
|
||||
parser.child(mMd5);
|
||||
parser.child(mUUID);
|
||||
}
|
||||
|
||||
// To actually write to an XML file one would do, for example:
|
||||
|
||||
LLFILE* fp = fopen(...);
|
||||
AIXMLRootElement tag(fp, "rootname");
|
||||
tag.attribute("version", "1.0");
|
||||
tag.child(LLDate::now());
|
||||
tag.child(mHelloWorld);
|
||||
|
||||
// And to read it again,
|
||||
|
||||
AIXMLParser helloworld(filename, "description of file used for error reporting", "rootname", 1);
|
||||
helloworld.attribute("version", "1.0");
|
||||
helloworld.child("helloworld", mHelloWorld);
|
||||
|
||||
// Of course, both would need to be in a try { } catch block.
|
||||
|
||||
#endif // EXAMPLE_CODE
|
||||
|
||||
// Do NOT change these - it would break old databases.
|
||||
char const* const DEFAULT_LLUUID_NAME = "uuid";
|
||||
char const* const DEFAULT_MD5STR_NAME = "md5";
|
||||
char const* const DEFAULT_LLDATE_NAME = "date";
|
||||
|
||||
std::string const DEFAULT_MD5STR_ATTRIBUTE_NAME = DEFAULT_MD5STR_NAME;
|
||||
std::string const DEFAULT_LLUUID_ATTRIBUTE_NAME = DEFAULT_LLUUID_NAME;
|
||||
std::string const DEFAULT_LLDATE_ATTRIBUTE_NAME = DEFAULT_LLDATE_NAME;
|
||||
std::string const DEFAULT_VERSION_ATTRIBUTE_NAME = "version";
|
||||
|
||||
struct xdigit {
|
||||
bool isxdigit;
|
||||
xdigit(void) : isxdigit(true) { }
|
||||
void operator()(char c) { isxdigit = isxdigit && std::isxdigit(c); }
|
||||
operator bool() const { return isxdigit; }
|
||||
};
|
||||
|
||||
static bool is_valid_md5str(std::string const& str)
|
||||
{
|
||||
return str.length() == MD5HEX_STR_BYTES && std::for_each(str.begin(), str.end(), xdigit());
|
||||
}
|
||||
|
||||
// Conversion routine that is a lot more strict then LLStringUtil::convertToU32.
|
||||
// This version does not allow leading or trailing spaces, nor does it allow a leading minus sign.
|
||||
// Leading zeroes are not allowed except a 0 by itself.
|
||||
bool convertToU32strict(std::string const& str, U32& value)
|
||||
{
|
||||
bool first = true;
|
||||
value = 0;
|
||||
for (std::string::const_iterator i = str.begin(); i != str.end(); ++i)
|
||||
{
|
||||
if (value == 0 && !first || !std::isdigit(*i)) // Reject leading zeroes and non-digits.
|
||||
return false;
|
||||
value = value * 10 + *i - '0';
|
||||
first = false;
|
||||
}
|
||||
return !first; // Reject empty string.
|
||||
}
|
||||
|
||||
typedef boost::tokenizer<boost::char_separator<char> > boost_tokenizer;
|
||||
|
||||
bool decode_version(std::string const& version, U32& major, U32& minor)
|
||||
{
|
||||
boost_tokenizer tokens(version, boost::char_separator<char>("", "."));
|
||||
boost_tokenizer::const_iterator itTok = tokens.begin();
|
||||
return itTok != tokens.end() && convertToU32strict(*itTok++, major) &&
|
||||
itTok != tokens.end() && *itTok++ == "." &&
|
||||
itTok != tokens.end() && convertToU32strict(*itTok, minor);
|
||||
}
|
||||
|
||||
bool md5strFromXML(LLXmlTreeNode* node, std::string& md5str_out)
|
||||
{
|
||||
static LLStdStringHandle const DEFAULT_MD5STR_ATTRIBUTE_NAME_HANDLE = LLXmlTree::addAttributeString(DEFAULT_MD5STR_ATTRIBUTE_NAME);
|
||||
return node->getFastAttributeString(DEFAULT_MD5STR_ATTRIBUTE_NAME_HANDLE, md5str_out) && is_valid_md5str(md5str_out);
|
||||
}
|
||||
|
||||
bool md5strFromXML(LLXmlTreeNode* node, std::string& md5str_out, std::string const& attribute_name)
|
||||
{
|
||||
return node->getAttributeString(attribute_name, md5str_out) && is_valid_md5str(md5str_out);
|
||||
}
|
||||
|
||||
bool UUIDFromXML(LLXmlTreeNode* node, LLUUID& uuid_out)
|
||||
{
|
||||
static LLStdStringHandle const DEFAULT_LLUUID_ATTRIBUTE_NAME_HANDLE = LLXmlTree::addAttributeString(DEFAULT_LLUUID_ATTRIBUTE_NAME);
|
||||
return node->getFastAttributeUUID(DEFAULT_LLUUID_ATTRIBUTE_NAME_HANDLE, uuid_out);
|
||||
}
|
||||
|
||||
bool UUIDFromXML(LLXmlTreeNode* node, LLUUID& uuid_out, std::string const& attribute_name)
|
||||
{
|
||||
return node->getAttributeUUID(attribute_name, uuid_out);
|
||||
}
|
||||
|
||||
bool dateFromXML(LLXmlTreeNode* node, LLDate& date_out)
|
||||
{
|
||||
static LLStdStringHandle const DEFAULT_LLDATE_ATTRIBUTE_NAME_HANDLE = LLXmlTree::addAttributeString(DEFAULT_LLDATE_ATTRIBUTE_NAME);
|
||||
std::string date_s;
|
||||
return node->getFastAttributeString(DEFAULT_LLDATE_ATTRIBUTE_NAME_HANDLE, date_s) && date_out.fromString(date_s);
|
||||
}
|
||||
|
||||
bool dateFromXML(LLXmlTreeNode* node, LLDate& date_out, std::string const& attribute_name)
|
||||
{
|
||||
std::string date_s;
|
||||
return node->getAttributeString(attribute_name, date_s) && date_out.fromString(date_s);
|
||||
}
|
||||
|
||||
bool versionFromXML(LLXmlTreeNode* node, U32& major_out, U32& minor_out)
|
||||
{
|
||||
static LLStdStringHandle const DEFAULT_VERSION_ATTRIBUTE_NAME_HANDLE = LLXmlTree::addAttributeString(DEFAULT_VERSION_ATTRIBUTE_NAME);
|
||||
major_out = minor_out = 0;
|
||||
std::string version_s;
|
||||
return node->getFastAttributeString(DEFAULT_VERSION_ATTRIBUTE_NAME_HANDLE, version_s) && decode_version(version_s, major_out, minor_out);
|
||||
}
|
||||
|
||||
bool versionFromXML(LLXmlTreeNode* node, U32& major_out, U32& minor_out, std::string const& attribute_name)
|
||||
{
|
||||
major_out = minor_out = 0;
|
||||
std::string version_s;
|
||||
return node->getAttributeString(attribute_name, version_s) && decode_version(version_s, major_out, minor_out);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// AIXMLElement
|
||||
|
||||
AIXMLElement::AIXMLElement(std::ostream& os, char const* name, int indentation) :
|
||||
mOs(os), mName(name), mIndentation(indentation), mHasChildren(false)
|
||||
{
|
||||
mOs << std::string(mIndentation, ' ') << '<' << mName;
|
||||
if (!mOs.good())
|
||||
{
|
||||
THROW_ALERT("AIXMLElement_Failed_to_write_DATA", AIArgs("[DATA]", "<" + mName));
|
||||
}
|
||||
}
|
||||
|
||||
int AIXMLElement::open_child(void)
|
||||
{
|
||||
if (!mHasChildren)
|
||||
{
|
||||
mOs << ">\n";
|
||||
if (!mOs.good())
|
||||
{
|
||||
THROW_ALERT("AIXMLElement_closing_child_Failed_to_write_DATA", AIArgs("[DATA]", ">\\n"));
|
||||
}
|
||||
mHasChildren = true;
|
||||
}
|
||||
mIndentation += 2;
|
||||
return mIndentation;
|
||||
}
|
||||
|
||||
void AIXMLElement::close_child(void)
|
||||
{
|
||||
mIndentation -= 2;
|
||||
}
|
||||
|
||||
AIXMLElement::~AIXMLElement()
|
||||
{
|
||||
if (mHasChildren)
|
||||
{
|
||||
mOs << std::string(mIndentation, ' ') << "</" << mName << ">\n";
|
||||
if (!mOs.good())
|
||||
{
|
||||
THROW_ALERT("AIXMLElement_closing_child_Failed_to_write_DATA",
|
||||
AIArgs("[DATA]", "\\n" + std::string(mIndentation, ' ') + "</" + mName + ">\\n"));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mOs << " />\n";
|
||||
if (!mOs.good())
|
||||
{
|
||||
THROW_ALERT("AIXMLElement_closing_child_Failed_to_write_DATA", AIArgs("[DATA]", " />\\n"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<>
|
||||
void AIXMLElement::child(LLUUID const& element)
|
||||
{
|
||||
open_child();
|
||||
write_child(DEFAULT_LLUUID_NAME, element);
|
||||
close_child();
|
||||
}
|
||||
|
||||
template<>
|
||||
void AIXMLElement::child(LLMD5 const& element)
|
||||
{
|
||||
open_child();
|
||||
write_child(DEFAULT_MD5STR_NAME, element);
|
||||
close_child();
|
||||
}
|
||||
|
||||
template<>
|
||||
void AIXMLElement::child(LLDate const& element)
|
||||
{
|
||||
open_child();
|
||||
write_child(DEFAULT_LLDATE_NAME, element);
|
||||
close_child();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// AIXMLStream
|
||||
|
||||
AIXMLStream::AIXMLStream(LLFILE* fp, bool standalone) : mOfs(fp)
|
||||
{
|
||||
char const* sp = standalone ? " standalone=\"yes\"" : "";
|
||||
int rc = fprintf(fp, "<?xml version=\"1.0\" encoding=\"utf-8\"%s ?>\n", sp);
|
||||
if (rc < 0 || ferror(fp))
|
||||
{
|
||||
// I don't think that errno is set to anything else but EBADF here,
|
||||
// so there is not really any informative message to add here.
|
||||
THROW_MALERT("AIXMLStream_fprintf_failed_to_write_xml_header");
|
||||
}
|
||||
}
|
||||
|
||||
AIXMLStream::~AIXMLStream()
|
||||
{
|
||||
if (mOfs.is_open())
|
||||
{
|
||||
mOfs.close();
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// AIXMLParser
|
||||
|
||||
AIXMLParser::AIXMLParser(std::string const& filename, char const* file_desc, std::string const& name, U32 major_version) :
|
||||
AIXMLElementParser(mFilename, mFileDesc, major_version),
|
||||
mFilename(filename), mFileDesc(file_desc)
|
||||
{
|
||||
char const* error = NULL;
|
||||
AIArgs args;
|
||||
if (!mXmlTree.parseFile(filename, TRUE))
|
||||
{
|
||||
AIFile dummy(filename, "rb"); // Check if the file can be opened at all (throws with a more descriptive error if not).
|
||||
error = "AIXMLParser_Cannot_parse_FILEDESC_FILENAME";
|
||||
}
|
||||
else
|
||||
{
|
||||
mNode = mXmlTree.getRoot();
|
||||
if (!mNode)
|
||||
{
|
||||
error = "AIXMLParser_No_root_node_found_in_FILEDESC_FILENAME";
|
||||
}
|
||||
else if (!mNode->hasName(name))
|
||||
{
|
||||
error = "AIXMLParser_Missing_header_NAME_invalid_FILEDESC_FILENAME";
|
||||
args("[NAME]", name);
|
||||
}
|
||||
else if (!versionFromXML(mNode, mVersionMajor, mVersionMinor))
|
||||
{
|
||||
error = "AIXMLParser_Invalid_or_missing_NAME_version_attribute_in_FILEDESC_FILENAME";
|
||||
args("[NAME]", name);
|
||||
}
|
||||
else if (mVersionMajor != major_version)
|
||||
{
|
||||
error = "AIXMLParser_Incompatible_NAME_version_MAJOR_MINOR_in";
|
||||
args("[NAME]", name)("[MAJOR]", llformat("%u", mVersionMajor))("[MINOR]", llformat("%u", mVersionMinor));
|
||||
}
|
||||
}
|
||||
if (error)
|
||||
{
|
||||
THROW_MALERT(error, args("[FILEDESC]", mFileDesc)("[FILENAME]", mFilename));
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// AIXMLElementParser
|
||||
|
||||
template<>
|
||||
LLMD5 AIXMLElementParser::read_string(std::string const& value) const
|
||||
{
|
||||
if (!is_valid_md5str(value))
|
||||
{
|
||||
THROW_MALERT("AIXMLElementParser_read_string_Invalid_MD5_VALUE_in_FILEDESC_FILENAME",
|
||||
AIArgs("[VALUE]", value)("[FILEDESC]", mFileDesc)("[FILENAME]", mFilename));
|
||||
}
|
||||
unsigned char digest[16];
|
||||
std::memset(digest, 0, sizeof(digest));
|
||||
for (int i = 0; i < 32; ++i)
|
||||
{
|
||||
int x = value[i];
|
||||
digest[i >> 1] += (x - (x & 0xf0) + (x >> 6) * 9) << ((~i & 1) << 2);
|
||||
}
|
||||
LLMD5 result;
|
||||
result.clone(digest);
|
||||
return result;
|
||||
}
|
||||
|
||||
template<>
|
||||
LLDate AIXMLElementParser::read_string(std::string const& value) const
|
||||
{
|
||||
LLDate result;
|
||||
result.fromString(value);
|
||||
return result;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T AIXMLElementParser::read_integer(char const* type, std::string const& value) const
|
||||
{
|
||||
long long int result;
|
||||
sscanf(value.c_str(),"%lld", &result);
|
||||
if (result < (std::numeric_limits<T>::min)() || result > (std::numeric_limits<T>::max)())
|
||||
{
|
||||
THROW_MALERT("AIXMLElementParser_read_integer_Invalid_TYPE_VALUE_in_FILEDESC_FILENAME",
|
||||
AIArgs("[TYPE]", type)("[VALUE]", value)("FILEDESC", mFileDesc)("[FILENAME]", mFilename));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template<>
|
||||
U8 AIXMLElementParser::read_string(std::string const& value) const
|
||||
{
|
||||
return read_integer<U8>("U8", value);
|
||||
}
|
||||
|
||||
template<>
|
||||
S8 AIXMLElementParser::read_string(std::string const& value) const
|
||||
{
|
||||
return read_integer<S8>("S8", value);
|
||||
}
|
||||
|
||||
template<>
|
||||
U16 AIXMLElementParser::read_string(std::string const& value) const
|
||||
{
|
||||
return read_integer<U16>("U16", value);
|
||||
}
|
||||
|
||||
template<>
|
||||
S16 AIXMLElementParser::read_string(std::string const& value) const
|
||||
{
|
||||
return read_integer<S16>("S16", value);
|
||||
}
|
||||
|
||||
template<>
|
||||
U32 AIXMLElementParser::read_string(std::string const& value) const
|
||||
{
|
||||
return read_integer<U32>("U32", value);
|
||||
}
|
||||
|
||||
template<>
|
||||
S32 AIXMLElementParser::read_string(std::string const& value) const
|
||||
{
|
||||
return read_integer<S32>("S32", value);
|
||||
}
|
||||
|
||||
double read_float(std::string const& value)
|
||||
{
|
||||
double result;
|
||||
sscanf(value.c_str(),"%lf", &result);
|
||||
return result;
|
||||
}
|
||||
|
||||
template<>
|
||||
F32 AIXMLElementParser::read_string(std::string const& value) const
|
||||
{
|
||||
return read_float(value);
|
||||
}
|
||||
|
||||
template<>
|
||||
F64 AIXMLElementParser::read_string(std::string const& value) const
|
||||
{
|
||||
return read_float(value);
|
||||
}
|
||||
|
||||
template<>
|
||||
bool AIXMLElementParser::read_string(std::string const& value) const
|
||||
{
|
||||
if (value == "true")
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if (value != "false")
|
||||
{
|
||||
THROW_MALERT("AIXMLElementParser_read_string_Invalid_boolean_VALUE_in_FILEDESC_FILENAME",
|
||||
AIArgs("[VALUE]", value)("FILEDESC]", mFileDesc)("[FILENAME]", mFilename));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void AIXMLElementParser::attribute(char const* name, char const* required_value) const
|
||||
{
|
||||
char const* error = NULL;
|
||||
AIArgs args;
|
||||
std::string value;
|
||||
if (!mNode->getAttributeString(name, value))
|
||||
{
|
||||
error = "AIXMLElementParser_attribute_Missing_NAME_attribute_in_NODENAME_of_FILEDESC_FILENAME";
|
||||
}
|
||||
else if (value != required_value)
|
||||
{
|
||||
error = "AIXMLElementParser_attribute_Invalid_NAME_attribute_should_be_REQUIRED_in_NODENAME_of_FILEDESC_FILENAME";
|
||||
args("[REQUIRED]", required_value);
|
||||
}
|
||||
if (error)
|
||||
{
|
||||
THROW_MALERT(error, args("[NAME]", name)("[NODENAME]", node_name())("[FILEDESC]", mFileDesc)("[FILENAME]", mFilename));
|
||||
}
|
||||
}
|
||||
|
||||
template<>
|
||||
LLUUID AIXMLElementParser::read_child(LLXmlTreeNode* node) const
|
||||
{
|
||||
LLUUID result;
|
||||
if (!LLUUID::parseUUID(node->getContents(), &result))
|
||||
{
|
||||
THROW_MALERT("AIXMLElementParser_read_child_Invalid_uuid_in_FILEDESC_FILENAME",
|
||||
AIArgs("[FILEDESC]", mFileDesc)("[FILENAME]", mFilename));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template<>
|
||||
LLMD5 AIXMLElementParser::read_child(LLXmlTreeNode* node) const
|
||||
{
|
||||
return read_string<LLMD5>(node->getContents());
|
||||
}
|
||||
|
||||
template<>
|
||||
LLDate AIXMLElementParser::read_child(LLXmlTreeNode* node) const
|
||||
{
|
||||
LLDate result;
|
||||
if (!result.fromString(node->getContents()))
|
||||
{
|
||||
THROW_MALERT("AIXMLElementParser_read_child_Invalid_date_DATE_in_FILEDESC_FILENAME",
|
||||
AIArgs("[DATE]", node->getContents())("[FILEDESC]", mFileDesc)("[FILENAME]", mFilename));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template<>
|
||||
S8 AIXMLElementParser::read_child(LLXmlTreeNode* node) const
|
||||
{
|
||||
return read_integer<S8>("S8", node->getContents());
|
||||
}
|
||||
|
||||
template<>
|
||||
U8 AIXMLElementParser::read_child(LLXmlTreeNode* node) const
|
||||
{
|
||||
return read_integer<U8>("U8", node->getContents());
|
||||
}
|
||||
|
||||
template<>
|
||||
S16 AIXMLElementParser::read_child(LLXmlTreeNode* node) const
|
||||
{
|
||||
return read_integer<S16>("S16", node->getContents());
|
||||
}
|
||||
|
||||
template<>
|
||||
U16 AIXMLElementParser::read_child(LLXmlTreeNode* node) const
|
||||
{
|
||||
return read_integer<U16>("U16", node->getContents());
|
||||
}
|
||||
|
||||
template<>
|
||||
S32 AIXMLElementParser::read_child(LLXmlTreeNode* node) const
|
||||
{
|
||||
return read_integer<S32>("S32", node->getContents());
|
||||
}
|
||||
|
||||
template<>
|
||||
U32 AIXMLElementParser::read_child(LLXmlTreeNode* node) const
|
||||
{
|
||||
return read_integer<U32>("U32", node->getContents());
|
||||
}
|
||||
|
||||
template<>
|
||||
F32 AIXMLElementParser::read_child(LLXmlTreeNode* node) const
|
||||
{
|
||||
return read_string<F32>(node->getContents());
|
||||
}
|
||||
|
||||
template<>
|
||||
F64 AIXMLElementParser::read_child(LLXmlTreeNode* node) const
|
||||
{
|
||||
return read_string<F64>(node->getContents());
|
||||
}
|
||||
|
||||
template<>
|
||||
bool AIXMLElementParser::read_child(LLXmlTreeNode* node) const
|
||||
{
|
||||
return read_string<bool>(node->getContents());
|
||||
}
|
||||
|
||||
bool AIXMLElementParser::child(LLUUID& uuid) const
|
||||
{
|
||||
return child(DEFAULT_LLUUID_NAME, uuid);
|
||||
}
|
||||
|
||||
bool AIXMLElementParser::child(LLMD5& md5) const
|
||||
{
|
||||
return child(DEFAULT_MD5STR_NAME, md5);
|
||||
}
|
||||
|
||||
bool AIXMLElementParser::child(LLDate& date) const
|
||||
{
|
||||
return child(DEFAULT_LLDATE_NAME, date);
|
||||
}
|
||||
|
||||
375
indra/llxml/aixml.h
Normal file
375
indra/llxml/aixml.h
Normal file
@@ -0,0 +1,375 @@
|
||||
/**
|
||||
* @file aixml.h
|
||||
* @brief XML serialization support.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 30/07/2013
|
||||
* Initial version, written by Aleric Inglewood @ SL
|
||||
*/
|
||||
|
||||
#ifndef AIXML_H
|
||||
#define AIXML_H
|
||||
|
||||
#include "llxmltree.h"
|
||||
#include "llxmlnode.h"
|
||||
#include "llfile.h"
|
||||
#include <sstream>
|
||||
#include "aialert.h"
|
||||
|
||||
extern char const* const DEFAULT_LLUUID_NAME;
|
||||
extern char const* const DEFAULT_MD5STR_NAME;
|
||||
extern char const* const DEFAULT_LLDATE_NAME;
|
||||
|
||||
class LLUUID;
|
||||
class LLMD5;
|
||||
class LLDate;
|
||||
|
||||
bool md5strFromXML(LLXmlTreeNode* node, std::string& md5str_out);
|
||||
bool md5strFromXML(LLXmlTreeNode* node, std::string& md5str_out, std::string const& attribute_name);
|
||||
bool UUIDFromXML(LLXmlTreeNode* node, LLUUID& uuid_out);
|
||||
bool UUIDFromXML(LLXmlTreeNode* node, LLUUID& uuid_out, std::string const& attribute_name);
|
||||
bool dateFromXML(LLXmlTreeNode* node, LLDate& date_out);
|
||||
bool dateFromXML(LLXmlTreeNode* node, LLDate& date_out, std::string const& attribute_name);
|
||||
bool versionFromXML(LLXmlTreeNode* node, U32& major_out, U32& minor_out);
|
||||
bool versionFromXML(LLXmlTreeNode* node, U32& major_out, U32& minor_out, std::string const& attribute_name);
|
||||
|
||||
class AIXMLElement
|
||||
{
|
||||
private:
|
||||
std::ostream& mOs;
|
||||
std::string mName;
|
||||
int mIndentation;
|
||||
bool mHasChildren;
|
||||
|
||||
public:
|
||||
AIXMLElement(std::ostream& os, char const* name, int indentation);
|
||||
~AIXMLElement();
|
||||
|
||||
template<typename T>
|
||||
void attribute(char const* name, T const& attribute);
|
||||
template<typename T>
|
||||
void child(T const& element);
|
||||
template<typename T>
|
||||
void child(char const* name, T const& element);
|
||||
template<typename FWD_ITERATOR>
|
||||
void child(FWD_ITERATOR i1, FWD_ITERATOR const& i2);
|
||||
|
||||
private:
|
||||
template<typename T>
|
||||
void write_child(char const* name, T const& element);
|
||||
|
||||
int open_child(void);
|
||||
void close_child(void);
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
void AIXMLElement::attribute(char const* name, T const& attribute)
|
||||
{
|
||||
std::ostringstream raw_attribute;
|
||||
raw_attribute << attribute;
|
||||
mOs << ' ' << name << "=\"" << LLXMLNode::escapeXML(raw_attribute.str()) << '"';
|
||||
if (!mOs.good())
|
||||
{
|
||||
std::ostringstream ss;
|
||||
ss << ' ' << name << "=\"" << LLXMLNode::escapeXML(raw_attribute.str()) << '"';
|
||||
THROW_FALERT("AIXMLElement_attribute_Failed_to_write_DATA", AIArgs("[DATA]", ss.str()));
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void AIXMLElement::child(T const& element)
|
||||
{
|
||||
open_child();
|
||||
element.toXML(mOs, mIndentation);
|
||||
if (!mOs.good()) // Normally toXML will already have thrown.
|
||||
{
|
||||
THROW_FALERT("AIXMLElement_child_Bad_ostream");
|
||||
}
|
||||
close_child();
|
||||
}
|
||||
|
||||
template<>
|
||||
void AIXMLElement::child(LLUUID const& element);
|
||||
|
||||
template<>
|
||||
void AIXMLElement::child(LLMD5 const& element);
|
||||
|
||||
template<>
|
||||
void AIXMLElement::child(LLDate const& element);
|
||||
|
||||
template<typename T>
|
||||
void AIXMLElement::write_child(char const* name, T const& element)
|
||||
{
|
||||
mOs << std::string(mIndentation, ' ') << '<' << name << '>' << element << "</" << name << ">\n";
|
||||
if (!mOs.good())
|
||||
{
|
||||
std::ostringstream ss;
|
||||
ss << std::string(mIndentation, ' ') << '<' << name << '>' << element << "</" << name << ">\\n";
|
||||
THROW_FALERT("AIXMLElement_write_child_Failed_to_write_DATA", AIArgs("[DATA]", ss.str()));
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void AIXMLElement::child(char const* name, T const& element)
|
||||
{
|
||||
open_child();
|
||||
write_child(name, element);
|
||||
close_child();
|
||||
}
|
||||
|
||||
template<typename FWD_ITERATOR>
|
||||
void AIXMLElement::child(FWD_ITERATOR i1, FWD_ITERATOR const& i2)
|
||||
{
|
||||
while (i1 != i2)
|
||||
{
|
||||
child(*i1++);
|
||||
}
|
||||
}
|
||||
|
||||
// Helper class for AIXMLRootElement.
|
||||
class AIXMLStream {
|
||||
protected:
|
||||
llofstream mOfs;
|
||||
AIXMLStream(LLFILE* fp, bool standalone);
|
||||
~AIXMLStream();
|
||||
};
|
||||
|
||||
// Class to write XML files.
|
||||
class AIXMLRootElement : public AIXMLStream, public AIXMLElement
|
||||
{
|
||||
public:
|
||||
AIXMLRootElement(LLFILE* fp, char const* name, bool standalone = true) : AIXMLStream(fp, standalone), AIXMLElement(mOfs, name, 0) { }
|
||||
};
|
||||
|
||||
class AIXMLElementParser
|
||||
{
|
||||
private:
|
||||
U32 mVersion;
|
||||
std::string const& mFilename;
|
||||
std::string const& mFileDesc;
|
||||
|
||||
protected:
|
||||
LLXmlTreeNode* mNode;
|
||||
|
||||
protected:
|
||||
// Used by AIXMLParser, which initializes mNode directly.
|
||||
AIXMLElementParser(std::string const& filename, std::string const& file_desc, U32 version) : mVersion(version), mFilename(filename), mFileDesc(file_desc) { }
|
||||
virtual ~AIXMLElementParser() { }
|
||||
|
||||
// Used for error reporting.
|
||||
virtual std::string node_name(void) const { return "node '" + mNode->getName() + "'"; }
|
||||
|
||||
// Parse the integer given as string 'value' and return it as type T (U8, S8, U16, S16, U32 or S32).
|
||||
template<typename T>
|
||||
T read_integer(char const* type, std::string const& value) const;
|
||||
|
||||
// Parse the string 'value' and return it as type T.
|
||||
template<typename T>
|
||||
T read_string(std::string const& value) const;
|
||||
|
||||
// Parse a child node and return it as type T.
|
||||
template<typename T>
|
||||
T read_child(LLXmlTreeNode* node) const;
|
||||
|
||||
public:
|
||||
// Constructor for child member functions.
|
||||
AIXMLElementParser(std::string const& filename, std::string const& file_desc, U32 version, LLXmlTreeNode* node) : mVersion(version), mFilename(filename), mFileDesc(file_desc), mNode(node) { }
|
||||
|
||||
// Require the existence of some attribute with given value.
|
||||
void attribute(char const* name, char const* required_value) const;
|
||||
|
||||
// Read attribute. Returns true if attribute was found.
|
||||
template<typename T>
|
||||
bool attribute(char const* name, T& attribute) const;
|
||||
|
||||
// Read child element. Returns true if child was found.
|
||||
template<typename T>
|
||||
bool child(char const* name, T& child) const;
|
||||
// Read Linden types. Return true if the child was found.
|
||||
bool child(LLUUID& uuid) const;
|
||||
bool child(LLMD5& md5) const;
|
||||
bool child(LLDate& date) const;
|
||||
|
||||
// Append all elements with name 'name' to container.
|
||||
template<typename CONTAINER>
|
||||
void push_back_children(char const* name, CONTAINER& container) const;
|
||||
|
||||
// Insert all elements with name 'name' into container.
|
||||
template<typename CONTAINER>
|
||||
void insert_children(char const* name, CONTAINER& container) const;
|
||||
|
||||
// Set version of this particular element (if not set mVersion will be the version of the parent, all the way up to the xml header with a version of 1).
|
||||
void setVersion(U32 version) { mVersion = version; }
|
||||
|
||||
// Accessors.
|
||||
std::string const& filename(void) const { return mFilename; }
|
||||
std::string const& filedesc(void) const { return mFileDesc; }
|
||||
U32 version(void) const { return mVersion; }
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
inline T AIXMLElementParser::read_string(std::string const& value) const
|
||||
{
|
||||
// Construct from string.
|
||||
return T(value);
|
||||
}
|
||||
|
||||
// Specializations.
|
||||
|
||||
template<>
|
||||
LLMD5 AIXMLElementParser::read_string(std::string const& value) const;
|
||||
|
||||
template<>
|
||||
LLDate AIXMLElementParser::read_string(std::string const& value) const;
|
||||
|
||||
template<>
|
||||
U8 AIXMLElementParser::read_string(std::string const& value) const;
|
||||
|
||||
template<>
|
||||
S8 AIXMLElementParser::read_string(std::string const& value) const;
|
||||
|
||||
template<>
|
||||
U16 AIXMLElementParser::read_string(std::string const& value) const;
|
||||
|
||||
template<>
|
||||
S16 AIXMLElementParser::read_string(std::string const& value) const;
|
||||
|
||||
template<>
|
||||
U32 AIXMLElementParser::read_string(std::string const& value) const;
|
||||
|
||||
template<>
|
||||
S32 AIXMLElementParser::read_string(std::string const& value) const;
|
||||
|
||||
template<>
|
||||
F32 AIXMLElementParser::read_string(std::string const& value) const;
|
||||
|
||||
template<>
|
||||
F64 AIXMLElementParser::read_string(std::string const& value) const;
|
||||
|
||||
template<>
|
||||
bool AIXMLElementParser::read_string(std::string const& value) const;
|
||||
|
||||
|
||||
template<typename T>
|
||||
bool AIXMLElementParser::attribute(char const* name, T& attribute) const
|
||||
{
|
||||
std::string value;
|
||||
if (!mNode->getAttributeString(name, value))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
attribute = read_string<T>(value);
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline T AIXMLElementParser::read_child(LLXmlTreeNode* node) const
|
||||
{
|
||||
return AIXMLElementParser(mFilename, mFileDesc, mVersion, node);
|
||||
}
|
||||
|
||||
// Specializations.
|
||||
|
||||
template<>
|
||||
inline std::string AIXMLElementParser::read_child(LLXmlTreeNode* node) const
|
||||
{
|
||||
return node->getContents();
|
||||
}
|
||||
|
||||
template<>
|
||||
LLMD5 AIXMLElementParser::read_child(LLXmlTreeNode* node) const;
|
||||
|
||||
template<>
|
||||
LLUUID AIXMLElementParser::read_child(LLXmlTreeNode* node) const;
|
||||
|
||||
template<>
|
||||
LLDate AIXMLElementParser::read_child(LLXmlTreeNode* node) const;
|
||||
|
||||
template<>
|
||||
S32 AIXMLElementParser::read_child(LLXmlTreeNode* node) const;
|
||||
|
||||
template<>
|
||||
F32 AIXMLElementParser::read_child(LLXmlTreeNode* node) const;
|
||||
|
||||
template<>
|
||||
bool AIXMLElementParser::read_child(LLXmlTreeNode* node) const;
|
||||
|
||||
|
||||
template<typename T>
|
||||
bool AIXMLElementParser::child(char const* name, T& child) const
|
||||
{
|
||||
LLXmlTreeNode* node = mNode->getChildByName(name);
|
||||
if (!node)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
child = read_child<T>(node);
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename CONTAINER>
|
||||
void AIXMLElementParser::insert_children(char const* name, CONTAINER& container) const
|
||||
{
|
||||
for (LLXmlTreeNode* node = mNode->getFirstChild(); node; node = mNode->getNextChild())
|
||||
{
|
||||
if (!node->hasName(name))
|
||||
continue;
|
||||
container.insert(read_child<typename CONTAINER::value_type>(node));
|
||||
}
|
||||
}
|
||||
|
||||
template<typename CONTAINER>
|
||||
void AIXMLElementParser::push_back_children(char const* name, CONTAINER& container) const
|
||||
{
|
||||
for (LLXmlTreeNode* node = mNode->getFirstChild(); node; node = mNode->getNextChild())
|
||||
{
|
||||
if (!node->hasName(name))
|
||||
continue;
|
||||
container.push_back(read_child<typename CONTAINER::value_type>(node));
|
||||
}
|
||||
}
|
||||
|
||||
// Class to read XML files.
|
||||
class AIXMLParser : public AIXMLElementParser
|
||||
{
|
||||
private:
|
||||
std::string mFilename;
|
||||
std::string mFileDesc;
|
||||
|
||||
LLXmlTree mXmlTree;
|
||||
U32 mVersionMajor;
|
||||
U32 mVersionMinor;
|
||||
|
||||
public:
|
||||
AIXMLParser(std::string const& filename, char const* file_desc, std::string const& name, U32 major_version);
|
||||
|
||||
U32 version_major(void) const { return mVersionMajor; }
|
||||
U32 version_minor(void) const { return mVersionMinor; }
|
||||
|
||||
protected:
|
||||
/*virtual*/ std::string node_name(void) const { return "root node"; }
|
||||
};
|
||||
|
||||
#endif // AIXML_H
|
||||
|
||||
@@ -555,6 +555,36 @@ void XMLCALL EndXMLNode(void *userData,
|
||||
node->setValue(value);
|
||||
}
|
||||
}
|
||||
// Singu note: moved here from XMLData.
|
||||
if (LLXMLNode::sStripEscapedStrings)
|
||||
{
|
||||
std::string value = node->getValue();
|
||||
int len = value.length();
|
||||
if (len > 1 && value[0] == '"' && value[len - 1] == '"')
|
||||
{
|
||||
// Special-case: Escaped string.
|
||||
std::string unescaped_string;
|
||||
for (S32 pos = 1; pos < len - 1; ++pos)
|
||||
{
|
||||
if (value[pos] == '\\' && value[pos + 1] == '\\')
|
||||
{
|
||||
unescaped_string += '\\';
|
||||
++pos;
|
||||
}
|
||||
else if (value[pos] == '\\' && value[pos + 1] == '"')
|
||||
{
|
||||
unescaped_string += '"';
|
||||
++pos;
|
||||
}
|
||||
else
|
||||
{
|
||||
unescaped_string += value[pos];
|
||||
}
|
||||
}
|
||||
value += unescaped_string;
|
||||
node->setValue(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void XMLCALL XMLData(void *userData,
|
||||
@@ -563,6 +593,15 @@ void XMLCALL XMLData(void *userData,
|
||||
{
|
||||
LLXMLNode* current_node = (LLXMLNode *)userData;
|
||||
std::string value = current_node->getValue();
|
||||
#if 0
|
||||
// Apparently also Lindens who write XML parsers can't read documentation.
|
||||
// "A single block of contiguous text free of markup may still result in a sequence
|
||||
// of calls to this handler. In other words, if you're searching for a pattern in
|
||||
// the text, it may be split across calls to this handler."
|
||||
// (http://sepp.oetiker.ch/expat-1.95.6-rs.SEPP/expat-1.95.6/doc/reference.html#XML_SetCharacterDataHandler)
|
||||
//
|
||||
// In other words, this is not guaranteed to work at all -- Aleric.
|
||||
|
||||
if (LLXMLNode::sStripEscapedStrings)
|
||||
{
|
||||
if (s[0] == '\"' && s[len-1] == '\"')
|
||||
@@ -591,6 +630,7 @@ void XMLCALL XMLData(void *userData,
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
value.append(std::string(s, len));
|
||||
current_node->setValue(value);
|
||||
}
|
||||
@@ -928,12 +968,6 @@ bool LLXMLNode::getLayeredXMLNode(LLXMLNodePtr& root,
|
||||
return true;
|
||||
}
|
||||
|
||||
// static
|
||||
void LLXMLNode::writeHeaderToFile(LLFILE *out_file)
|
||||
{
|
||||
fprintf(out_file, "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\" ?>\n");
|
||||
}
|
||||
|
||||
void LLXMLNode::writeToFile(LLFILE *out_file, const std::string& indent, bool use_type_decorations)
|
||||
{
|
||||
if (isFullyDefault())
|
||||
|
||||
@@ -157,11 +157,6 @@ public:
|
||||
|
||||
static bool getLayeredXMLNode(LLXMLNodePtr& root, const std::vector<std::string>& paths);
|
||||
|
||||
|
||||
// Write standard XML file header:
|
||||
// <?xml version="1.0" encoding="utf-8" standalone="yes" ?>
|
||||
static void writeHeaderToFile(LLFILE *out_file);
|
||||
|
||||
// Write XML to file with one attribute per line.
|
||||
// XML escapes values as they are written.
|
||||
void writeToFile(LLFILE *out_file, const std::string& indent = std::string(), bool use_type_decorations=true);
|
||||
|
||||
@@ -38,6 +38,7 @@ include(LLXML)
|
||||
#include(LScript)
|
||||
include(Linking)
|
||||
include(NDOF)
|
||||
include(NVAPI)
|
||||
include(StateMachine)
|
||||
include(TemplateCheck)
|
||||
include(UI)
|
||||
@@ -47,6 +48,8 @@ include(LLAppearance)
|
||||
|
||||
if (WINDOWS)
|
||||
include(CopyWinLibs)
|
||||
set(CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_SKIP)
|
||||
include(InstallRequiredSystemLibraries)
|
||||
endif (WINDOWS)
|
||||
|
||||
include_directories(
|
||||
@@ -80,6 +83,7 @@ include_directories(
|
||||
set(viewer_SOURCE_FILES
|
||||
NACLantispam.cpp
|
||||
aihttpview.cpp
|
||||
aixmllindengenepool.cpp
|
||||
aoremotectrl.cpp
|
||||
ascentfloatercontactgroups.cpp
|
||||
ascentkeyword.cpp
|
||||
@@ -597,6 +601,7 @@ set(viewer_HEADER_FILES
|
||||
|
||||
NACLantispam.h
|
||||
aihttpview.h
|
||||
aixmllindengenepool.h
|
||||
aoremotectrl.h
|
||||
ascentfloatercontactgroups.h
|
||||
ascentkeyword.h
|
||||
@@ -1429,21 +1434,11 @@ if (!DISABLE_TEMPLATE_CHECK)
|
||||
check_message_template(${VIEWER_BINARY_NAME})
|
||||
endif (!DISABLE_TEMPLATE_CHECK)
|
||||
|
||||
# We package by default on Linux so we can run from newview/packaged.
|
||||
if (LINUX)
|
||||
set(PACKAGE_DEFAULT ON)
|
||||
else (LINUX)
|
||||
set(PACKAGE_DEFAULT OFF)
|
||||
endif (LINUX)
|
||||
set(PACKAGE ${PACKAGE_DEFAULT} CACHE BOOL
|
||||
set(PACKAGE OFF CACHE BOOL
|
||||
"Add a package target that builds an installer package.")
|
||||
|
||||
if (WINDOWS)
|
||||
if(MSVC10)
|
||||
set(release_flags "/MAPRelease/${VIEWER_BINARY_NAME}.map")
|
||||
else(MSVC10)
|
||||
set(release_flags "/MAP:Release/${VIEWER_BINARY_NAME}.map")
|
||||
endif(MSVC10)
|
||||
set(release_flags "/MAPRelease/${VIEWER_BINARY_NAME}.map")
|
||||
|
||||
if (FMOD)
|
||||
if(MANIFEST_LIBRARIES)
|
||||
@@ -1453,12 +1448,18 @@ if (WINDOWS)
|
||||
endif(MANIFEST_LIBRARIES)
|
||||
endif (FMOD)
|
||||
if (FMODEX)
|
||||
if (WORD_SIZE EQUAL 32)
|
||||
set(fmodex_dll_file "fmodex.dll")
|
||||
else (WORD_SIZE EQUAL 32)
|
||||
set(fmodex_dll_file "fmodex64.dll")
|
||||
endif (WORD_SIZE EQUAL 32)
|
||||
|
||||
if(MANIFEST_LIBRARIES)
|
||||
set(MANIFEST_LIBRARIES "${MANIFEST_LIBRARIES}|${FMODEX_BINARY_DIR}/fmodex.dll")
|
||||
set(MANIFEST_LIBRARIES "${MANIFEST_LIBRARIES}|${FMODEX_BINARY_DIR}/${fmodex_dll_file}")
|
||||
else(MANIFEST_LIBRARIES)
|
||||
set(MANIFEST_LIBRARIES "--extra_libraries=${FMODEX_BINARY_DIR}/fmodex.dll")
|
||||
set(MANIFEST_LIBRARIES "--extra_libraries=${FMODEX_BINARY_DIR}/${fmodex_dll_file}")
|
||||
endif(MANIFEST_LIBRARIES)
|
||||
set(EXTRA_LINKER_FLAGS "/DELAYLOAD:fmodex.dll")
|
||||
set(EXTRA_LINKER_FLAGS "/DELAYLOAD:${fmodex_dll_file}")
|
||||
endif (FMODEX)
|
||||
|
||||
set_target_properties(${VIEWER_BINARY_NAME}
|
||||
@@ -1516,6 +1517,7 @@ if (WINDOWS)
|
||||
COMMAND ${PYTHON_EXECUTABLE}
|
||||
ARGS
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py
|
||||
--arch=${ARCH}
|
||||
--artwork=${ARTWORK_DIR}
|
||||
--branding_id=${VIEWER_BRANDING_ID}
|
||||
--build=${CMAKE_CURRENT_BINARY_DIR}
|
||||
@@ -1537,6 +1539,7 @@ if (WINDOWS)
|
||||
COMMAND ${PYTHON_EXECUTABLE}
|
||||
ARGS
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py
|
||||
--arch=${ARCH}
|
||||
--artwork=${ARTWORK_DIR}
|
||||
--actions=copy
|
||||
--branding_id=${VIEWER_BRANDING_ID}
|
||||
@@ -1590,6 +1593,7 @@ target_link_libraries(${VIEWER_BINARY_NAME}
|
||||
${LLMATH_LIBRARIES}
|
||||
${LLCOMMON_LIBRARIES}
|
||||
${NDOF_LIBRARY}
|
||||
${NVAPI_LIBRARY}
|
||||
${viewer_LIBRARIES}
|
||||
${Boost_CONTEXT_LIBRARY}
|
||||
${Boost_FILESYSTEM_LIBRARY}
|
||||
@@ -1857,6 +1861,21 @@ endif (LL_TESTS)
|
||||
# Don't do these for DARWIN or LINUX here -- they're taken care of by viewer_manifest.py
|
||||
if (WINDOWS)
|
||||
|
||||
IF(CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS)
|
||||
FOREACH(RUNTIME_LIB ${CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS})
|
||||
add_custom_command(
|
||||
TARGET ${VIEWER_BINARY_NAME} POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND}
|
||||
ARGS
|
||||
-E
|
||||
copy_if_different
|
||||
${RUNTIME_LIB}
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
COMMENT "Copying ${RUNTIME_LIB} to the runtime folder."
|
||||
)
|
||||
ENDFOREACH(RUNTIME_LIB ${CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS})
|
||||
ENDIF(CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS)
|
||||
|
||||
get_target_property(BUILT_LLCOMMON llcommon LOCATION)
|
||||
|
||||
set_target_properties(llcommon
|
||||
@@ -1912,7 +1931,7 @@ if (WINDOWS)
|
||||
COMMENT "Copying Quicktime Plugin to the runtime folder."
|
||||
)
|
||||
|
||||
get_target_property(BUILT_FILEPICKER_PLUGIN basic_plugin_filepicker LOCATION)
|
||||
get_target_property(BUILT_FILEPICKER_PLUGIN basic_plugin_filepicker LOCATION)
|
||||
add_custom_command(
|
||||
TARGET ${VIEWER_BINARY_NAME} POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND}
|
||||
@@ -1924,7 +1943,9 @@ if (WINDOWS)
|
||||
COMMENT "Copying filepicker Plugin to the runtime folder."
|
||||
)
|
||||
|
||||
get_target_property(BUILT_WINMM_SHIM_PLUGIN winmm_shim LOCATION)
|
||||
# winmm doesn't build on windows 64
|
||||
if(WORD_SIZE EQUAL 32)
|
||||
get_target_property(BUILT_WINMM_SHIM_PLUGIN winmm_shim LOCATION)
|
||||
add_custom_command(
|
||||
TARGET ${VIEWER_BINARY_NAME} POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND}
|
||||
@@ -1935,6 +1956,8 @@ if (WINDOWS)
|
||||
${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}
|
||||
COMMENT "Copying winmm.dll to the runtime folder."
|
||||
)
|
||||
endif(WORD_SIZE EQUAL 32)
|
||||
|
||||
# Copying the mime_types.xml file to app_settings
|
||||
set(mime_types_source "${CMAKE_SOURCE_DIR}/newview/skins/default/xui/en-us")
|
||||
set(mime_types_dest "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/app_settings")
|
||||
|
||||
205
indra/newview/aixmllindengenepool.cpp
Normal file
205
indra/newview/aixmllindengenepool.cpp
Normal file
@@ -0,0 +1,205 @@
|
||||
/**
|
||||
* @file aixmllindengenepool.cpp
|
||||
* @brief XML linden_genepool serialization support.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 01/11/2013
|
||||
* Initial version, written by Aleric Inglewood @ SL
|
||||
*/
|
||||
|
||||
// metaversion 1.0
|
||||
// ===============
|
||||
//
|
||||
// Added as child of <linden_genepool>:
|
||||
//
|
||||
// <meta gridnick="secondlife" date="2013-07-16T16:49:00.40Z" />
|
||||
//
|
||||
// Optionally, as child of <archetype>, the following node may appear:
|
||||
//
|
||||
// <meta path="clothing/jackets" name="Purple jacket" description="A jacket with mainly the color purple" />
|
||||
//
|
||||
// Furthermore, metaversion 1.0 and higher allow the occurance of one or more <archetype> blocks.
|
||||
// If this is used then it is strongly advised to use one <archetype> per wearable, so that
|
||||
// the the <meta> node makes sense (it then refers to the wearable of that <archetype>).
|
||||
//
|
||||
// The reason for this clumsy way to link wearable to extra meta data is to stay
|
||||
// compatible with the older format (no metaversion).
|
||||
|
||||
#include "llviewerprecompiledheaders.h"
|
||||
#include "aixmllindengenepool.h"
|
||||
#include "hippogridmanager.h"
|
||||
#include "llvisualparam.h"
|
||||
#include "llviewerwearable.h"
|
||||
#include "llquantize.h"
|
||||
|
||||
extern void append_path_short(LLUUID const& id, std::string& path);
|
||||
|
||||
void AIXMLLindenGenepool::MetaData::toXML(std::ostream& os, int indentation) const
|
||||
{
|
||||
AIXMLElement tag(os, "meta", indentation);
|
||||
tag.attribute("gridnick", mGridNick);
|
||||
tag.attribute(DEFAULT_LLDATE_NAME, mDate);
|
||||
}
|
||||
|
||||
AIXMLLindenGenepool::MetaData::MetaData(AIXMLElementParser const& parser)
|
||||
{
|
||||
parser.attribute("gridnick", mGridNick);
|
||||
parser.attribute(DEFAULT_LLDATE_NAME, mDate);
|
||||
}
|
||||
|
||||
AIXMLLindenGenepool::AIXMLLindenGenepool(LLFILE* fp) : AIXMLRootElement(fp, "linden_genepool")
|
||||
{
|
||||
attribute("version", "1.0");
|
||||
attribute("metaversion", "1.0");
|
||||
child(MetaData(gHippoGridManager->getConnectedGrid()->getGridNick(), LLDate::now()));
|
||||
}
|
||||
|
||||
void AIVisualParamIDValuePair::toXML(std::ostream& os, int indentation) const
|
||||
{
|
||||
LLVisualParam const* visual_param = mVisualParam;
|
||||
if (!visual_param && mWearable)
|
||||
{
|
||||
visual_param = mWearable->getVisualParam(mID);
|
||||
}
|
||||
if (visual_param)
|
||||
{
|
||||
AIXMLElement tag(os, "param", indentation);
|
||||
tag.attribute("id", mID);
|
||||
tag.attribute("name", visual_param->getName());
|
||||
tag.attribute("value", mValue);
|
||||
tag.attribute("u8", (U32)F32_to_U8(mValue, visual_param->getMinWeight(), visual_param->getMaxWeight()));
|
||||
tag.attribute("type", visual_param->getTypeString());
|
||||
tag.attribute("wearable", visual_param->getDumpWearableTypeName());
|
||||
}
|
||||
}
|
||||
|
||||
AIVisualParamIDValuePair::AIVisualParamIDValuePair(AIXMLElementParser const& parser)
|
||||
{
|
||||
// Only id and value are relevant. Ignore all other attributes.
|
||||
parser.attribute("id", mID);
|
||||
parser.attribute("value", mValue);
|
||||
}
|
||||
|
||||
void AITextureIDUUIDPair::toXML(std::ostream& os, int indentation) const
|
||||
{
|
||||
AIXMLElement tag(os, "texture", indentation);
|
||||
tag.attribute("te", mID);
|
||||
tag.attribute(DEFAULT_LLUUID_NAME, mUUID);
|
||||
}
|
||||
|
||||
AITextureIDUUIDPair::AITextureIDUUIDPair(AIXMLElementParser const& parser)
|
||||
{
|
||||
parser.attribute("te", mID);
|
||||
parser.attribute(DEFAULT_LLUUID_NAME, mUUID);
|
||||
}
|
||||
|
||||
void AIArchetype::MetaData::toXML(std::ostream& os, int indentation) const
|
||||
{
|
||||
AIXMLElement tag(os, "meta", indentation);
|
||||
tag.attribute("path", mPath);
|
||||
tag.attribute("name", mName);
|
||||
tag.attribute("description", mDescription);
|
||||
}
|
||||
|
||||
AIArchetype::MetaData::MetaData(AIXMLElementParser const& parser)
|
||||
{
|
||||
char const* missing = NULL;
|
||||
if (!parser.attribute("path", mPath))
|
||||
{
|
||||
missing = "path";
|
||||
}
|
||||
if (!parser.attribute("name", mName))
|
||||
{
|
||||
missing = "name";
|
||||
}
|
||||
if (!parser.attribute("description", mDescription))
|
||||
{
|
||||
missing = "description";
|
||||
}
|
||||
if (missing)
|
||||
{
|
||||
THROW_ALERT("AIArchetype_MetaData_archetype_meta_has_no_ATTRIBUTE", AIArgs("[ATTRIBUTE]", missing));
|
||||
}
|
||||
}
|
||||
|
||||
AIArchetype::MetaData::MetaData(LLViewerWearable const* wearable) : mName(wearable->getName()), mDescription(wearable->getDescription())
|
||||
{
|
||||
append_path_short(wearable->getItemID(), mPath);
|
||||
}
|
||||
|
||||
AIArchetype::AIArchetype(void) : mType(LLWearableType::WT_NONE)
|
||||
{
|
||||
}
|
||||
|
||||
AIArchetype::AIArchetype(LLWearableType::EType type) : mType(type)
|
||||
{
|
||||
}
|
||||
|
||||
AIArchetype::AIArchetype(LLViewerWearable const* wearable) : mType(wearable->getType()), mMetaData(wearable)
|
||||
{
|
||||
}
|
||||
|
||||
void AIArchetype::toXML(std::ostream& os, int indentation) const
|
||||
{
|
||||
AIXMLElement tag(os, "archetype", indentation);
|
||||
if (mType == LLWearableType::WT_NONE)
|
||||
{
|
||||
tag.attribute("name", "???");
|
||||
}
|
||||
else
|
||||
{
|
||||
tag.attribute("name", LLWearableType::getTypeName(mType));
|
||||
}
|
||||
if (!mMetaData.mPath.empty())
|
||||
{
|
||||
tag.child(mMetaData);
|
||||
}
|
||||
tag.child(mParams.begin(), mParams.end());
|
||||
tag.child(mTextures.begin(), mTextures.end());
|
||||
}
|
||||
|
||||
AIArchetype::AIArchetype(AIXMLElementParser const& parser)
|
||||
{
|
||||
std::string name;
|
||||
mType = LLWearableType::WT_NONE;
|
||||
|
||||
if (!parser.attribute("name", name))
|
||||
{
|
||||
llwarns << "The <archetype> tag in file \"" << parser.filename() << "\" is missing the 'name' parameter." << llendl;
|
||||
}
|
||||
else if (name != "???")
|
||||
{
|
||||
mType = LLWearableType::typeNameToType(name);
|
||||
}
|
||||
if (parser.version() >= 1)
|
||||
{
|
||||
if (!parser.child("meta", mMetaData))
|
||||
{
|
||||
THROW_ALERT("AIArchetype_archetype_has_no_meta");
|
||||
}
|
||||
}
|
||||
parser.push_back_children("param", mParams);
|
||||
parser.push_back_children("texture", mTextures);
|
||||
}
|
||||
|
||||
150
indra/newview/aixmllindengenepool.h
Normal file
150
indra/newview/aixmllindengenepool.h
Normal file
@@ -0,0 +1,150 @@
|
||||
/**
|
||||
* @file aixmllindengenepool.h
|
||||
* @brief XML linden_genepool serialization support.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 01/11/2013
|
||||
* Initial version, written by Aleric Inglewood @ SL
|
||||
*/
|
||||
|
||||
#ifndef AIXMLLINDENGENEPOOL_H
|
||||
#define AIXMLLINDENGENEPOOL_H
|
||||
|
||||
#include "aixml.h"
|
||||
#include "llwearabletype.h"
|
||||
#include "llviewervisualparam.h"
|
||||
#include <vector>
|
||||
|
||||
class LLViewerWearable;
|
||||
|
||||
class AIXMLLindenGenepool : public AIXMLRootElement
|
||||
{
|
||||
public:
|
||||
struct MetaData
|
||||
{
|
||||
std::string mGridNick;
|
||||
LLDate mDate;
|
||||
|
||||
MetaData(void) { }
|
||||
MetaData(std::string const& grid_nick, LLDate const& date) : mGridNick(grid_nick), mDate(date) { }
|
||||
|
||||
void toXML(std::ostream& os, int indentation) const;
|
||||
MetaData(AIXMLElementParser const& parser);
|
||||
};
|
||||
|
||||
AIXMLLindenGenepool(LLFILE* fp);
|
||||
};
|
||||
|
||||
class AIVisualParamIDValuePair
|
||||
{
|
||||
private:
|
||||
// A wearable + ID define the LLVisualParam, but it also possible to specify the LLVisualParam directly.
|
||||
LLVisualParam const* mVisualParam; // Specific LLVisualParam, given at construction, or ...
|
||||
LLViewerWearable const* mWearable; // Underlaying wearable, if any.
|
||||
|
||||
U32 mID; // The visual parameter id.
|
||||
F32 mValue; // The value of the visual parameter.
|
||||
|
||||
public:
|
||||
AIVisualParamIDValuePair(LLVisualParam const* visual_param) :
|
||||
mVisualParam(visual_param), mWearable(NULL), mID(visual_param->getID()), mValue(visual_param->getWeight()) { }
|
||||
|
||||
AIVisualParamIDValuePair(LLVisualParam const* visual_param, F32 value) :
|
||||
mVisualParam(visual_param), mWearable(NULL), mID(visual_param->getID()), mValue(value) { }
|
||||
|
||||
AIVisualParamIDValuePair(LLViewerWearable const* wearable, U32 id, F32 value) :
|
||||
mVisualParam(NULL), mWearable(wearable), mID(id), mValue(value) { }
|
||||
|
||||
void toXML(std::ostream& os, int indentation) const;
|
||||
AIVisualParamIDValuePair(AIXMLElementParser const& parser);
|
||||
|
||||
// Accessors.
|
||||
U32 getID(void) const { return mID; }
|
||||
F32 getValue(void) const { return mValue; }
|
||||
};
|
||||
|
||||
class AITextureIDUUIDPair
|
||||
{
|
||||
private:
|
||||
U32 mID;
|
||||
LLUUID mUUID;
|
||||
|
||||
public:
|
||||
AITextureIDUUIDPair(U32 id, LLUUID const& uuid) : mID(id), mUUID(uuid) { }
|
||||
|
||||
void toXML(std::ostream& os, int indentation) const;
|
||||
AITextureIDUUIDPair(AIXMLElementParser const& parser);
|
||||
|
||||
// Accessors.
|
||||
U32 getID(void) const { return mID; }
|
||||
LLUUID const& getUUID(void) const { return mUUID; }
|
||||
};
|
||||
|
||||
class AIArchetype
|
||||
{
|
||||
public:
|
||||
struct MetaData
|
||||
{
|
||||
std::string mPath; // The wearable location in the inventory.
|
||||
std::string mName; // The wearable name.
|
||||
std::string mDescription; // The wearable description.
|
||||
|
||||
MetaData(void) { }
|
||||
MetaData(LLViewerWearable const* wearable);
|
||||
|
||||
void toXML(std::ostream& os, int indentation) const;
|
||||
MetaData(AIXMLElementParser const& parser);
|
||||
};
|
||||
|
||||
typedef std::vector<AIVisualParamIDValuePair> params_type;
|
||||
typedef std::vector<AITextureIDUUIDPair> textures_type;
|
||||
|
||||
private:
|
||||
LLWearableType::EType mType; // The type of the wearable.
|
||||
MetaData mMetaData;
|
||||
params_type mParams;
|
||||
textures_type mTextures;
|
||||
|
||||
public:
|
||||
// Accessors.
|
||||
LLWearableType::EType getType(void) const { return mType; }
|
||||
MetaData const& getMetaData(void) const { return mMetaData; }
|
||||
params_type const& getParams(void) const { return mParams; }
|
||||
textures_type const& getTextures(void) const { return mTextures; }
|
||||
|
||||
public:
|
||||
// An archtype without wearable has no (known) metadata. This is recognized because mPath will be empty.
|
||||
// An archtype without type with get the attribute name="???".
|
||||
AIArchetype(void); // <archetype name="???">
|
||||
AIArchetype(LLWearableType::EType type); // <archetype name="shirt">
|
||||
AIArchetype(LLViewerWearable const* wearable); // <archetype name="shirt"> <meta path="myclothes" name="blue shirt" description="Awesome blue shirt">
|
||||
|
||||
void add(AIVisualParamIDValuePair const& visual_param_id_value_pair) { mParams.push_back(visual_param_id_value_pair); }
|
||||
void add(AITextureIDUUIDPair const& texture_id_uuid_pair) { mTextures.push_back(texture_id_uuid_pair); }
|
||||
|
||||
void toXML(std::ostream& os, int indentation) const;
|
||||
AIArchetype(AIXMLElementParser const& parser);
|
||||
};
|
||||
|
||||
#endif // AIXMLLINDENGENEPOOL_H
|
||||
@@ -40,7 +40,7 @@
|
||||
</array>
|
||||
<key>tags</key>
|
||||
<array>
|
||||
<string>ShaderLoading</string>
|
||||
<!--string>ShaderLoading</string-->
|
||||
<string>Openjpeg</string>
|
||||
<!-- Debug output about messages received from plugins: -->
|
||||
<string>Plugin</string> <!-- Everything except what is listed below -->
|
||||
|
||||
@@ -8,7 +8,17 @@
|
||||
<string>settings_sh.xml</string>
|
||||
<string>settings_rlv.xml</string>
|
||||
</array>
|
||||
|
||||
<key>SinguOffsetScrollKeys</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Enable keys to modify camera and focus offsets</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>1</integer>
|
||||
</map>
|
||||
<key>PhoenixIMAnnounceStealFocus</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
@@ -210,17 +220,6 @@
|
||||
<integer>100</integer>
|
||||
</map>
|
||||
|
||||
<key>zmm_deffov</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Default field of viewer for right click mouse zoom.</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>F32</string>
|
||||
<key>Value</key>
|
||||
<real>1.0</real>
|
||||
</map>
|
||||
<key>zmm_mlfov</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
@@ -232,28 +231,6 @@
|
||||
<key>Value</key>
|
||||
<real>1</real>
|
||||
</map>
|
||||
<key>zmm_isinml</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>mouselook</string>
|
||||
<key>Persist</key>
|
||||
<integer>0</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
<key>zmm_rightmousedown</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>insert rude comment here</string>
|
||||
<key>Persist</key>
|
||||
<integer>0</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
|
||||
<key>AllowLargeSounds</key>
|
||||
<map>
|
||||
@@ -786,6 +763,17 @@
|
||||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
<key>LiruMouselookMenu</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Controls if holding Alt and right clicking in mouselook will bring up a menu</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<boolean>1</boolean>
|
||||
</map>
|
||||
<key>LiruNewARCLimit</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
@@ -868,6 +856,17 @@ Found in Advanced->Rendering->Info Displays</string>
|
||||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
<key>LiruUseContextMenus</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Use context menus instead of the default pie menus we all know and love.</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<boolean>0</boolean>
|
||||
</map>
|
||||
<key>SLBShowFPS</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
@@ -936,6 +935,17 @@ Found in Advanced->Rendering->Info Displays</string>
|
||||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
<key>FSSynchronizeTextureMaps</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Align texture maps (texture, bumpy, shiny) across the faces of a prim</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<boolean>1</boolean>
|
||||
</map>
|
||||
<key>InstantMessageLogPathAnyAccount</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
@@ -5703,6 +5713,39 @@ This should be as low as possible, but too low may break functionality</string>
|
||||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
<key>DefaultBlankNormalTexture</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Texture used as 'Blank' in texture picker for normal map. (UUID texture reference)</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>String</string>
|
||||
<key>Value</key>
|
||||
<string>5b53359e-59dd-d8a2-04c3-9e65134da47a</string>
|
||||
</map>
|
||||
<key>DefaultObjectNormalTexture</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Texture used as 'Default' in texture picker for normal map. (UUID texture reference)</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>String</string>
|
||||
<key>Value</key>
|
||||
<string>85f28839-7a1c-b4e3-d71d-967792970a7b</string>
|
||||
</map>
|
||||
<key>DefaultObjectSpecularTexture</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Texture used as 'Default' in texture picker for specular map. (UUID texture reference)</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>String</string>
|
||||
<key>Value</key>
|
||||
<string>87e0e8f7-8729-1ea8-cfc9-8915773009db</string>
|
||||
</map>
|
||||
<key>DefaultObjectTexture</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
@@ -13742,6 +13785,17 @@ This should be as low as possible, but too low may break functionality</string>
|
||||
<key>Value</key>
|
||||
<integer>1</integer>
|
||||
</map>
|
||||
<key>RevokePermsOnStopAnimation</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Clear animation permssions when choosing "Stop Animating Me"</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>1</integer>
|
||||
</map>
|
||||
<key>RotateRight</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
@@ -17735,7 +17789,7 @@ This should be as low as possible, but too low may break functionality</string>
|
||||
<key>Type</key>
|
||||
<string>S32</string>
|
||||
<key>Value</key>
|
||||
<integer>1</integer>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
</map>
|
||||
</llsd>
|
||||
|
||||
@@ -277,7 +277,7 @@
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>1</integer>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
<key>AscentShowOthersTagColor</key>
|
||||
<map>
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#extension GL_ARB_texture_rectangle : enable
|
||||
//#extension GL_ARB_texture_rectangle : enable
|
||||
|
||||
#define INDEXED 1
|
||||
#define NON_INDEXED 2
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#extension GL_ARB_texture_rectangle : enable
|
||||
//#extension GL_ARB_texture_rectangle : enable
|
||||
|
||||
#ifdef DEFINE_GL_FRAGCOLOR
|
||||
out vec4 frag_color;
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#extension GL_ARB_texture_rectangle : enable
|
||||
//#extension GL_ARB_texture_rectangle : enable
|
||||
|
||||
#ifdef DEFINE_GL_FRAGCOLOR
|
||||
out vec4 frag_color;
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#extension GL_ARB_texture_rectangle : enable
|
||||
//#extension GL_ARB_texture_rectangle : enable
|
||||
|
||||
#ifdef DEFINE_GL_FRAGCOLOR
|
||||
out vec4 frag_color;
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#extension GL_ARB_texture_rectangle : enable
|
||||
//#extension GL_ARB_texture_rectangle : enable
|
||||
|
||||
#ifdef DEFINE_GL_FRAGCOLOR
|
||||
out vec4 frag_color;
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#extension GL_ARB_texture_rectangle : enable
|
||||
//#extension GL_ARB_texture_rectangle : enable
|
||||
|
||||
#ifdef DEFINE_GL_FRAGCOLOR
|
||||
out vec4 frag_color;
|
||||
|
||||
@@ -22,8 +22,6 @@
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#ifdef DEFINE_GL_FRAGCOLOR
|
||||
out vec4 frag_color;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user