summaryrefslogtreecommitdiff
path: root/indra/llui/lluictrlfactory.h
diff options
context:
space:
mode:
authorSteven Bennetts <steve@lindenlab.com>2009-06-21 08:04:56 +0000
committerSteven Bennetts <steve@lindenlab.com>2009-06-21 08:04:56 +0000
commit9ec432034dc3c45d7ce763eb02dae4cc7f6b8da8 (patch)
tree4a505c1e0919af52800b3ffb3eaf135e7d6f9ce6 /indra/llui/lluictrlfactory.h
parent351ebe9fcb76f3b99c2957004bb8493a904869ee (diff)
merge -r 122421-124917 viewer-2.0.0-2 -> viewer-2.0.0-3
ignore-dead-branch
Diffstat (limited to 'indra/llui/lluictrlfactory.h')
-rw-r--r--indra/llui/lluictrlfactory.h408
1 files changed, 379 insertions, 29 deletions
diff --git a/indra/llui/lluictrlfactory.h b/indra/llui/lluictrlfactory.h
index 5e7c24efc0..4045022c8e 100644
--- a/indra/llui/lluictrlfactory.h
+++ b/indra/llui/lluictrlfactory.h
@@ -33,68 +33,418 @@
#ifndef LLUICTRLFACTORY_H
#define LLUICTRLFACTORY_H
+#include "llcallbackmap.h"
+#include "llinitparam.h"
+#include "llxmlnode.h"
+#include "llfasttimer.h"
+
+#include <boost/function.hpp>
#include <iosfwd>
#include <stack>
-#include "llcallbackmap.h"
-#include "llfloater.h"
-
-class LLView;
class LLPanel;
+class LLFloater;
+class LLView;
-class LLUICtrlFactory : public LLSingleton<LLUICtrlFactory>
+class LLXUIParser : public LLInitParam::Parser, public LLSingleton<LLXUIParser>
{
+LOG_CLASS(LLXUIParser);
+
+protected:
+ LLXUIParser();
+ friend class LLSingleton<LLXUIParser>;
public:
+ typedef LLInitParam::Parser::name_stack_t name_stack_t;
+
+ /*virtual*/ std::string getCurrentElementName();
+ /*virtual*/ void parserWarning(const std::string& message);
+ /*virtual*/ void parserError(const std::string& message);
+
+ void readXUI(LLXMLNodePtr node, LLInitParam::BaseBlock& block, bool silent=false);
+ void writeXUI(LLXMLNodePtr node, const LLInitParam::BaseBlock& block, const LLInitParam::BaseBlock* diff_block = NULL);
+
+private:
+ typedef std::list<std::pair<std::string, bool> > token_list_t;
+
+ bool readXUIImpl(LLXMLNodePtr node, const std::string& scope, LLInitParam::BaseBlock& block);
+ bool readAttributes(LLXMLNodePtr nodep, LLInitParam::BaseBlock& block);
+
+ //reader helper functions
+ bool readBoolValue(void* val_ptr);
+ bool readStringValue(void* val_ptr);
+ bool readU8Value(void* val_ptr);
+ bool readS8Value(void* val_ptr);
+ bool readU16Value(void* val_ptr);
+ bool readS16Value(void* val_ptr);
+ bool readU32Value(void* val_ptr);
+ bool readS32Value(void* val_ptr);
+ bool readF32Value(void* val_ptr);
+ bool readF64Value(void* val_ptr);
+ bool readColor4Value(void* val_ptr);
+ bool readUIColorValue(void* val_ptr);
+ bool readUUIDValue(void* val_ptr);
+ bool readSDValue(void* val_ptr);
+
+ //writer helper functions
+ bool writeBoolValue(const void* val_ptr, const name_stack_t&);
+ bool writeStringValue(const void* val_ptr, const name_stack_t&);
+ bool writeU8Value(const void* val_ptr, const name_stack_t&);
+ bool writeS8Value(const void* val_ptr, const name_stack_t&);
+ bool writeU16Value(const void* val_ptr, const name_stack_t&);
+ bool writeS16Value(const void* val_ptr, const name_stack_t&);
+ bool writeU32Value(const void* val_ptr, const name_stack_t&);
+ bool writeS32Value(const void* val_ptr, const name_stack_t&);
+ bool writeF32Value(const void* val_ptr, const name_stack_t&);
+ bool writeF64Value(const void* val_ptr, const name_stack_t&);
+ bool writeColor4Value(const void* val_ptr, const name_stack_t&);
+ bool writeUIColorValue(const void* val_ptr, const name_stack_t&);
+ bool writeUUIDValue(const void* val_ptr, const name_stack_t&);
+ bool writeSDValue(const void* val_ptr, const name_stack_t&);
+
+ LLXMLNodePtr getNode(const name_stack_t& stack);
+
+private:
+ Parser::name_stack_t mNameStack;
+ LLXMLNodePtr mCurReadNode;
+ // Root of the widget XML sub-tree, for example, "line_editor"
+ LLXMLNodePtr mWriteRootNode;
+ S32 mLastWriteGeneration;
+ LLXMLNodePtr mLastWrittenChild;
+ S32 mCurReadDepth;
+};
+
+// global static instance for registering all widget types
+typedef boost::function<LLView* (LLXMLNodePtr node, LLView *parent, LLXMLNodePtr output_node)> LLWidgetCreatorFunc;
+
+typedef LLRegistry<std::string, LLWidgetCreatorFunc> widget_registry_t;
+
+template <typename DERIVED_TYPE>
+class LLWidgetRegistry : public LLRegistrySingleton<std::string, LLWidgetCreatorFunc, DERIVED_TYPE>
+{
+public:
+ typedef LLRegistrySingleton<std::string, LLWidgetCreatorFunc, DERIVED_TYPE> super_t;
+ // local static instance for registering a particular widget
+ template<typename T, typename PARAM_BLOCK = typename T::Params>
+ class Register : public super_t::StaticRegistrar
+ {
+ public:
+ // register with either the provided builder, or the generic templated builder
+ Register(const char* tag, LLWidgetCreatorFunc func = NULL);
+ };
+
+protected:
+ LLWidgetRegistry() {}
+};
+
+class LLDefaultWidgetRegistry : public LLWidgetRegistry<LLDefaultWidgetRegistry>
+{
+protected:
+ LLDefaultWidgetRegistry() {}
+ friend class LLSingleton<LLDefaultWidgetRegistry>;
+};
+
+struct LLCompareTypeID
+{
+ bool operator()(const std::type_info* lhs, const std::type_info* rhs) const
+ {
+ return lhs->before(*rhs);
+ }
+};
+
+
+class LLWidgetTemplateRegistry
+: public LLRegistrySingleton<const std::type_info*, std::string, LLWidgetTemplateRegistry, LLCompareTypeID>
+{
+
+};
+
+extern LLFastTimer::DeclareTimer FTM_WIDGET_SETUP;
+extern LLFastTimer::DeclareTimer FTM_WIDGET_CONSTRUCTION;
+extern LLFastTimer::DeclareTimer FTM_INIT_FROM_PARAMS;
+
+class LLUICtrlFactory : public LLSingleton<LLUICtrlFactory>
+{
+private:
+ friend class LLSingleton<LLUICtrlFactory>;
LLUICtrlFactory();
- // do not call! needs to be public so run-time can clean up the singleton
- virtual ~LLUICtrlFactory();
+ ~LLUICtrlFactory();
+
+ // only partial specialization allowed in inner classes, so use extra dummy parameter
+ template <typename T, int DUMMY>
+ class ParamDefaults : public LLSingleton<ParamDefaults<T, DUMMY> >
+ {
+ public:
+ ParamDefaults()
+ {
+ // recursively initialize from base class param block
+ ((typename T::base_block_t&)mPrototype).fillFrom(ParamDefaults<typename T::base_block_t, DUMMY>::instance().get());
+ // after initializing base classes, look up template file for this param block
+ std::string* param_block_tag = LLWidgetTemplateRegistry::instance().getValue(&typeid(T));
+ if (param_block_tag)
+ {
+ LLUICtrlFactory::loadWidgetTemplate(*param_block_tag, mPrototype);
+ }
+ }
+
+ const T& get() { return mPrototype; }
- void setupPaths();
+ private:
+ T mPrototype;
+ };
- void buildFloater(LLFloater* floaterp, const std::string &filename,
- const LLCallbackMap::map_t* factory_map = NULL, BOOL open = TRUE);
- BOOL buildPanel(LLPanel* panelp, const std::string &filename,
- const LLCallbackMap::map_t* factory_map = NULL);
+ // base case for recursion, there are NO base classes of LLInitParam::BaseBlock
+ template<int DUMMY>
+ class ParamDefaults<LLInitParam::BaseBlock, DUMMY> : public LLSingleton<ParamDefaults<LLInitParam::BaseBlock, DUMMY> >
+ {
+ public:
+ const LLInitParam::BaseBlock& get() { return mBaseBlock; }
+ private:
+ LLInitParam::BaseBlock mBaseBlock;
+ };
- void removePanel(LLPanel* panelp) { mBuiltPanels.erase(panelp->getHandle()); }
- void removeFloater(LLFloater* floaterp) { mBuiltFloaters.erase(floaterp->getHandle()); }
+public:
+
+ template<typename T>
+ static const T& getDefaultParams()
+ {
+ //#pragma message("Generating ParamDefaults")
+ return ParamDefaults<T, 0>::instance().get();
+ }
- class LLMenuGL *buildMenu(const std::string &filename, LLView* parentp);
- class LLPieMenu *buildPieMenu(const std::string &filename, LLView* parentp);
+ void buildFloater(LLFloater* floaterp, const std::string &filename, BOOL open_floater = TRUE, LLXMLNodePtr output_node = NULL);
+ LLFloater* buildFloaterFromXML(const std::string& filename, BOOL open_floater = TRUE);
+ BOOL buildPanel(LLPanel* panelp, const std::string &filename, LLXMLNodePtr output_node = NULL);
// Does what you want for LLFloaters and LLPanels
// Returns 0 on success
S32 saveToXML(LLView* viewp, const std::string& filename);
- // Rebuilds all currently built panels.
- void rebuild();
+ std::string getCurFileName() { return mFileNames.empty() ? "" : mFileNames.back(); }
static BOOL getAttributeColor(LLXMLNodePtr node, const std::string& name, LLColor4& color);
LLPanel* createFactoryPanel(const std::string& name);
- virtual LLView* createCtrlWidget(LLPanel *parent, LLXMLNodePtr node);
- virtual LLView* createWidget(LLPanel *parent, LLXMLNodePtr node);
+ void pushFactoryFunctions(const LLCallbackMap::map_t* map);
+ void popFactoryFunctions();
+
+ template<typename T>
+ static T* create(typename T::Params& params, LLView* parent = NULL)
+ {
+ //#pragma message("Generating LLUICtrlFactory::create")
+ params.fillFrom(ParamDefaults<typename T::Params, 0>::instance().get());
+ //S32 foo = "test";
+
+ if (!params.validateBlock())
+ {
+ llwarns << getInstance()->getCurFileName() << ": Invalid parameter block for " << typeid(T).name() << llendl;
+ }
+ T* widget = new T(params);
+ widget->initFromParams(params);
+ if (parent)
+ widget->setParent(parent);
+ return widget;
+ }
+
+ LLView* createFromXML(LLXMLNodePtr node, LLView* parent, const std::string& filename, LLXMLNodePtr output_node, const widget_registry_t& );
+
+ static const widget_registry_t& getWidgetRegistry(LLView*);
+
+ template<typename T>
+ static T* createFromFile(const std::string &filename, LLView *parent, LLXMLNodePtr output_node = NULL)
+ {
+ //#pragma message("Generating LLUICtrlFactory::createFromFile")
+ T* widget = NULL;
+
+ std::string skinned_filename = findSkinnedFilename(filename);
+ getInstance()->mFileNames.push_back(skinned_filename);
+ {
+ LLXMLNodePtr root_node;
+
+ //if exporting, only load the language being exported,
+ //instead of layering localized version on top of english
+ if (output_node)
+ {
+ if (!LLUICtrlFactory::getLocalizedXMLNode(filename, root_node))
+ {
+ llwarns << "Couldn't parse XUI file: " << filename << llendl;
+ goto fail;
+ }
+ }
+ else if (!LLUICtrlFactory::getLayeredXMLNode(filename, root_node))
+ {
+ llwarns << "Couldn't parse XUI file: " << skinned_filename << llendl;
+ goto fail;
+ }
+
+ LLView* view = getInstance()->createFromXML(root_node, parent, filename, output_node, getWidgetRegistry(parent));
+ if (view)
+ {
+ widget = dynamic_cast<T*>(view);
+ // not of right type, so delete it
+ if (!widget)
+ {
+ delete view;
+ view = NULL;
+ }
+
+ }
+ }
+fail:
+ getInstance()->mFileNames.pop_back();
+ return widget;
+ }
+
+ template <class T>
+ static T* createDummyWidget(const std::string& name)
+ {
+ //#pragma message("Generating LLUICtrlFactory::createDummyWidget")
+ typename T::Params params;
+ params.name(name);
+
+ return create<T>(params);
+ }
+
+ template<typename T, typename PARAM_BLOCK>
+ static T* defaultBuilder(LLXMLNodePtr node, LLView *parent, LLXMLNodePtr output_node)
+ {
+ LLFastTimer timer(FTM_WIDGET_SETUP);
+
+ //#pragma message("Generating LLUICtrlFactory::defaultBuilder")
+ PARAM_BLOCK params(getDefaultParams<PARAM_BLOCK>());
+
+ LLXUIParser::instance().readXUI(node, params);
+
+ if (output_node)
+ {
+ // We always want to output top-left coordinates
+ PARAM_BLOCK output_params(params);
+ T::setupParamsForExport(output_params, parent);
+ // Export only the differences between this any default params
+ PARAM_BLOCK default_params(getDefaultParams<PARAM_BLOCK>());
+ output_node->setName(node->getName()->mString);
+ LLXUIParser::instance().writeXUI(
+ output_node, output_params, &default_params);
+ }
+
+ // Apply layout transformations, usually munging rect
+ T::setupParams(params, parent);
+
+ if (!params.validateBlock())
+ {
+ llwarns << getInstance()->getCurFileName() << ": Invalid parameter block for " << typeid(T).name() << llendl;
+ }
+ T* widget;
+ {
+ LLFastTimer timer(FTM_WIDGET_CONSTRUCTION);
+ widget = new T(params);
+ }
+ {
+ LLFastTimer timer(FTM_INIT_FROM_PARAMS);
+ widget->initFromParams(params);
+ }
+
+ if (parent)
+ {
+ S32 tab_group = params.tab_group.isProvided() ? params.tab_group() : -1;
+ setCtrlParent(widget, parent, tab_group);
+ }
+
+ createChildren(widget, node, output_node);
+
+ if (!widget->postBuild())
+ {
+ delete widget;
+ return NULL;
+ }
+
+ return widget;
+ }
+
+ static void createChildren(LLView* viewp, LLXMLNodePtr node, LLXMLNodePtr output_node = NULL);
static bool getLayeredXMLNode(const std::string &filename, LLXMLNodePtr& root);
+
+ static bool getLocalizedXMLNode(const std::string &xui_filename, LLXMLNodePtr& root);
- static const std::vector<std::string>& getXUIPaths();
+ static void loadWidgetTemplate(const std::string& widget_tag, LLInitParam::BaseBlock& block);
private:
- bool getLayeredXMLNodeImpl(const std::string &filename, LLXMLNodePtr& root);
+ //static void setCtrlValue(LLView* view, LLXMLNodePtr node);
+ static void setCtrlParent(LLView* view, LLView* parent, S32 tab_group);
+
+ // Avoid directly using LLUI and LLDir in the template code
+ static std::string findSkinnedFilename(const std::string& filename);
+
+ typedef std::deque<const LLCallbackMap::map_t*> factory_stack_t;
+ factory_stack_t mFactoryStack;
+
+ LLPanel* mDummyPanel;
+ std::vector<std::string> mFileNames;
+};
+
+// this is here to make gcc happy with reference to LLUICtrlFactory
+template<typename DERIVED>
+template<typename T, typename PARAM_BLOCK>
+LLWidgetRegistry<DERIVED>::Register<T, PARAM_BLOCK>::Register(const char* tag, LLWidgetCreatorFunc func)
+: LLWidgetRegistry<DERIVED>::StaticRegistrar(tag, func.empty() ? (LLWidgetCreatorFunc)&LLUICtrlFactory::defaultBuilder<T, PARAM_BLOCK> : func)
+{
+ //FIXME: inventory_panel will register itself with LLPanel::Params but it does have its own params...:(
+ LLWidgetTemplateRegistry::instance().defaultRegistrar().add(&typeid(PARAM_BLOCK), tag);
+}
+
+
+typedef boost::function<LLPanel* (void)> LLPannelClassCreatorFunc;
- typedef std::map<LLHandle<LLPanel>, std::string> built_panel_t;
- built_panel_t mBuiltPanels;
+// local static instance for registering a particular panel class
- typedef std::map<LLHandle<LLFloater>, std::string> built_floater_t;
- built_floater_t mBuiltFloaters;
+class LLRegisterPanelClass
+: public LLSingleton< LLRegisterPanelClass >
+{
+public:
+ // reigister with either the provided builder, or the generic templated builder
+ void addPanelClass(const std::string& tag,LLPannelClassCreatorFunc func)
+ {
+ mPannelClassesNames[tag] = func;
+ }
+
+ LLPanel* createPanelClass(const std::string& tag)
+ {
+ param_name_map_t::iterator iT = mPannelClassesNames.find(tag);
+ if(iT == mPannelClassesNames.end())
+ return 0;
+ return iT->second();
+ }
+ template<typename T>
+ static T* defaultPanelClassBuilder()
+ {
+ T* pT = new T();
+ return pT;
+ }
- std::deque<const LLCallbackMap::map_t*> mFactoryStack;
+private:
+ typedef std::map< std::string, LLPannelClassCreatorFunc> param_name_map_t;
+
+ param_name_map_t mPannelClassesNames;
+};
- static std::vector<std::string> sXUIPaths;
- LLPanel* mDummyPanel;
+// local static instance for registering a particular panel class
+template<typename T>
+class LLRegisterPanelClassWrapper
+: public LLRegisterPanelClass
+{
+public:
+ // reigister with either the provided builder, or the generic templated builder
+ LLRegisterPanelClassWrapper(const std::string& tag);
};
+template<typename T>
+LLRegisterPanelClassWrapper<T>::LLRegisterPanelClassWrapper(const std::string& tag)
+{
+ LLRegisterPanelClass::instance().addPanelClass(tag,&LLRegisterPanelClass::defaultPanelClassBuilder<T>);
+}
+
+
#endif //LLUICTRLFACTORY_H