diff options
Diffstat (limited to 'indra/llui/lluictrlfactory.h')
-rw-r--r-- | indra/llui/lluictrlfactory.h | 320 |
1 files changed, 289 insertions, 31 deletions
diff --git a/indra/llui/lluictrlfactory.h b/indra/llui/lluictrlfactory.h index 5e7c24efc0..5b04557368 100644 --- a/indra/llui/lluictrlfactory.h +++ b/indra/llui/lluictrlfactory.h @@ -33,68 +33,326 @@ #ifndef LLUICTRLFACTORY_H #define LLUICTRLFACTORY_H +#include "llcallbackmap.h" +#include "llinitparam.h" +#include "llxmlnode.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; +}; + +// global static instance for registering all widget types +typedef boost::function<LLView* (LLXMLNodePtr node, LLView *parent, LLXMLNodePtr output_node)> LLWidgetCreatorFunc; + +class LLWidgetCreatorRegistry : public LLRegistrySingleton<std::string, LLWidgetCreatorFunc, LLWidgetCreatorRegistry> +{ +protected: + LLWidgetCreatorRegistry() {} + +private: + friend class LLSingleton<LLWidgetCreatorRegistry>; +}; + +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> +{ + +}; + +// local static instance for registering a particular widget +template<typename T, typename PARAM_BLOCK = typename T::Params> +class LLRegisterWidget +: public LLWidgetCreatorRegistry::StaticRegistrar +{ +public: + // register with either the provided builder, or the generic templated builder + LLRegisterWidget(const char* tag, LLWidgetCreatorFunc func = NULL); +}; + +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); + } + } - void setupPaths(); + const T& get() { return 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); + private: + T mPrototype; + }; - void removePanel(LLPanel* panelp) { mBuiltPanels.erase(panelp->getHandle()); } - void removeFloater(LLFloater* floaterp) { mBuiltFloaters.erase(floaterp->getHandle()); } + // 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; + }; - class LLMenuGL *buildMenu(const std::string &filename, LLView* parentp); - class LLPieMenu *buildPieMenu(const std::string &filename, LLView* parentp); +public: + + template<typename T> + static const T& getDefaultParams() + { + //#pragma message("Generating ParamDefaults") + return ParamDefaults<T, 0>::instance().get(); + } + + 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(); - static bool getLayeredXMLNode(const std::string &filename, LLXMLNodePtr& root); + 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"; - static const std::vector<std::string>& getXUIPaths(); + 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; + } -private: - bool getLayeredXMLNodeImpl(const std::string &filename, LLXMLNodePtr& root); + LLView* createFromXML(LLXMLNodePtr node, LLView* parent, const std::string& filename = LLStringUtil::null, LLXMLNodePtr output_node = NULL); + + template<typename T> + static T* createFromFile(const std::string &filename, LLView *parent) + { + //#pragma message("Generating LLUICtrlFactory::createFromFile") + T* widget = NULL; + + std::string skinned_filename = findSkinnedFilename(filename); + getInstance()->mFileNames.push_back(skinned_filename); + { + LLXMLNodePtr root_node; + + if (LLUICtrlFactory::getLayeredXMLNode(filename, root_node)) + { + LLView* view = getInstance()->createFromXML(root_node, parent, filename); + if (view) + { + widget = dynamic_cast<T*>(view); + // not of right type, so delete it + if (!widget) + { + delete view; + view = NULL; + } + + } + } + else + { + llwarns << "Couldn't parse XUI file: " << skinned_filename << llendl; + } + } + getInstance()->mFileNames.pop_back(); - typedef std::map<LLHandle<LLPanel>, std::string> built_panel_t; - built_panel_t mBuiltPanels; + return widget; + } - typedef std::map<LLHandle<LLFloater>, std::string> built_floater_t; - built_floater_t mBuiltFloaters; + 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); + } - std::deque<const LLCallbackMap::map_t*> mFactoryStack; + template<typename T, typename PARAM_BLOCK> + static T* defaultBuilder(LLXMLNodePtr node, LLView *parent, LLXMLNodePtr output_node) + { + //#pragma message("Generating LLUICtrlFactory::defaultBuilder") + PARAM_BLOCK params(getDefaultParams<PARAM_BLOCK>()); - static std::vector<std::string> sXUIPaths; + LLXUIParser::instance().readXUI(node, params); - LLPanel* mDummyPanel; + 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 = new T(params); + widget->initFromParams(params); + + if (parent) + { + S32 tab_group = params.tab_group.isProvided() ? params.tab_group() : -1; + setCtrlParent(widget, parent, tab_group); + } + + widget->addChildren(node, output_node); + + if (!widget->postBuild()) + { + delete widget; + return NULL; + } + + return widget; + } + + static bool getLayeredXMLNode(const std::string &filename, LLXMLNodePtr& root); + + static void loadWidgetTemplate(const std::string& widget_tag, LLInitParam::BaseBlock& block); + +private: + //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 T, typename PARAM_BLOCK> +LLRegisterWidget<T, PARAM_BLOCK>::LLRegisterWidget(const char* tag, LLWidgetCreatorFunc func) +: LLWidgetCreatorRegistry::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); +} + #endif //LLUICTRLFACTORY_H |