516 lines
16 KiB
C++
516 lines
16 KiB
C++
// This file is part of VSTGUI. It is subject to the license terms
|
|
// in the LICENSE file found in the top-level directory of this
|
|
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE
|
|
|
|
#include "uiviewfactory.h"
|
|
#include "uiattributes.h"
|
|
#include "../lib/cview.h"
|
|
#include "../lib/cstring.h"
|
|
#include "detail/uiviewcreatorattributes.h"
|
|
#include "../lib/platform/std_unorderedmap.h"
|
|
|
|
namespace VSTGUI {
|
|
|
|
/** @class IViewCreator
|
|
|
|
You can register your own custom views with the UIViewFactory by inheriting from this interface and register it
|
|
with UIViewFactory::registerViewCreator().
|
|
|
|
Example for an imaginary view class called MyView which directly inherites from CView:
|
|
@code
|
|
class MyViewCreator : public ViewCreatorAdapter
|
|
{
|
|
public:
|
|
// register this class with the view factory
|
|
MyViewCreator () { UIViewFactory::registerViewCreator (*this); }
|
|
|
|
// return an unique name here
|
|
IdStringPtr getViewName () const { return "MyView"; }
|
|
|
|
// return the name here from where your custom view inherites.
|
|
// Your view automatically supports the attributes from it.
|
|
IdStringPtr getBaseViewName () const { return "CView"; }
|
|
|
|
// create your view here.
|
|
// Note you don't need to apply attributes here as the apply method will be called with this new view
|
|
CView* create (const UIAttributes& attributes, const IUIDescription* description) const { return new MyView (); }
|
|
|
|
// apply custom attributes to your view
|
|
bool apply (CView* view, const UIAttributes& attributes, const IUIDescription* description) const
|
|
{
|
|
MyView* myView = dynamic_cast<MyView*> (view);
|
|
if (myView == 0)
|
|
return false;
|
|
int32_t value;
|
|
if (attributes.getIntegerAttribute ("my-custom-attribute", value))
|
|
myView->setCustomAttribute (value);
|
|
return true;
|
|
}
|
|
|
|
// add your custom attributes to the list
|
|
bool getAttributeNames (StringList& attributeNames) const
|
|
{
|
|
attributeNames.emplace_back ("my-custom-attribute");
|
|
return true;
|
|
}
|
|
|
|
// return the type of your custom attributes
|
|
AttrType getAttributeType (const std::string& attributeName) const
|
|
{
|
|
if (attributeName == "my-custom-attribute")
|
|
return kIntegerType;
|
|
return kUnknownType;
|
|
}
|
|
|
|
// return the string value of the custom attributes of the view
|
|
bool getAttributeValue (CView* view, const string& attributeName, string& stringValue, const IUIDescription* desc) const
|
|
{
|
|
MyView* myView = dynamic_cast<MyView*> (view);
|
|
if (myView == 0)
|
|
return false;
|
|
if (attributeName == "my-custom-attribute")
|
|
{
|
|
stringValue = UIAttributes::integerToString (myView->getCustomAttribute ());
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
};
|
|
// create a static instance so that it registers itself with the view factory
|
|
MyViewCreator __gMyViewCreator;
|
|
|
|
@endcode
|
|
*/
|
|
|
|
using ViewCreatorRegistryMap = std::unordered_map<std::string, const IViewCreator*>;
|
|
|
|
//-----------------------------------------------------------------------------
|
|
class ViewCreatorRegistry : private ViewCreatorRegistryMap
|
|
{
|
|
public:
|
|
using const_iterator = ViewCreatorRegistryMap::const_iterator;
|
|
|
|
const_iterator begin () { return ViewCreatorRegistryMap::begin (); }
|
|
const_iterator end () { return ViewCreatorRegistryMap::end (); }
|
|
|
|
const_iterator find (IdStringPtr name)
|
|
{
|
|
if (name)
|
|
return ViewCreatorRegistryMap::find (name);
|
|
return end ();
|
|
}
|
|
|
|
void add (IdStringPtr name, const IViewCreator* viewCreator)
|
|
{
|
|
#if DEBUG
|
|
if (find (viewCreator->getViewName ()) != end ())
|
|
{
|
|
DebugPrint ("ViewCreateFunction for '%s' already registered\n", viewCreator->getViewName ());
|
|
}
|
|
#endif
|
|
insert (std::make_pair (viewCreator->getViewName (), viewCreator));
|
|
|
|
}
|
|
|
|
void remove (const IViewCreator* viewCreator)
|
|
{
|
|
auto it = find (viewCreator->getViewName ());
|
|
if (it == end ())
|
|
return;
|
|
erase (it);
|
|
}
|
|
};
|
|
|
|
//-----------------------------------------------------------------------------
|
|
static ViewCreatorRegistry& getCreatorRegistry ()
|
|
{
|
|
static ViewCreatorRegistry creatorRegistry;
|
|
return creatorRegistry;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
static CViewAttributeID kViewNameAttribute = 'cvcr';
|
|
|
|
//-----------------------------------------------------------------------------
|
|
UIViewFactory::UIViewFactory ()
|
|
{
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
bool UIViewFactory::viewIsTypeOf (CView* view, const std::string& typeName) const
|
|
{
|
|
auto viewTypeName = getViewName (view);
|
|
if (typeName == viewTypeName)
|
|
return true;
|
|
auto& registry = getCreatorRegistry ();
|
|
auto iter = registry.find (viewTypeName);
|
|
while (iter != registry.end ())
|
|
{
|
|
auto baseViewTypeName = iter->second->getBaseViewName ();
|
|
if (baseViewTypeName == nullptr)
|
|
return false;
|
|
if (typeName == baseViewTypeName)
|
|
return true;
|
|
iter = registry.find (baseViewTypeName);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
CView* UIViewFactory::createViewByName (const std::string* className, const UIAttributes& attributes, const IUIDescription* description) const
|
|
{
|
|
auto& registry = getCreatorRegistry ();
|
|
auto iter = registry.find (className->c_str ());
|
|
if (iter != registry.end ())
|
|
{
|
|
CView* view = (*iter).second->create (attributes, description);
|
|
if (view)
|
|
{
|
|
IdStringPtr viewName = (*iter).second->getViewName ();
|
|
view->setAttribute (kViewNameAttribute, viewName);
|
|
UIAttributes evaluatedAttributes;
|
|
evaluateAttributesAndRemember (view, attributes, evaluatedAttributes, description);
|
|
while (iter != registry.end () && (*iter).second->apply (view, evaluatedAttributes, description))
|
|
{
|
|
if ((*iter).second->getBaseViewName () == nullptr)
|
|
break;
|
|
iter = registry.find ((*iter).second->getBaseViewName ());
|
|
}
|
|
return view;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
#if DEBUG
|
|
DebugPrint ("UIViewFactory::createView(..): Could not find view of class: %s\n", className->c_str ());
|
|
#endif
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
CView* UIViewFactory::createView (const UIAttributes& attributes, const IUIDescription* description) const
|
|
{
|
|
const std::string* className = attributes.getAttributeValue (UIViewCreator::kAttrClass);
|
|
if (className)
|
|
return createViewByName (className, attributes, description);
|
|
std::string viewContainerName ("CViewContainer");
|
|
return createViewByName (&viewContainerName, attributes, description);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
bool UIViewFactory::applyAttributeValues (CView* view, const UIAttributes& attributes, const IUIDescription* desc) const
|
|
{
|
|
bool result = false;
|
|
auto& registry = getCreatorRegistry ();
|
|
auto iter = registry.find (getViewName (view));
|
|
|
|
UIAttributes evaluatedAttributes;
|
|
evaluateAttributesAndRemember (view, attributes, evaluatedAttributes, desc);
|
|
|
|
while (iter != registry.end () && (result = (*iter).second->apply (view, evaluatedAttributes, desc)) && (*iter).second->getBaseViewName ())
|
|
{
|
|
iter = registry.find ((*iter).second->getBaseViewName ());
|
|
}
|
|
return result;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
bool UIViewFactory::applyCustomViewAttributeValues (CView* customView, IdStringPtr baseViewName, const UIAttributes& attributes, const IUIDescription* desc) const
|
|
{
|
|
bool result = false;
|
|
auto& registry = getCreatorRegistry ();
|
|
auto iter = registry.find (baseViewName);
|
|
if (iter != registry.end ())
|
|
{
|
|
IdStringPtr viewName = (*iter).second->getViewName ();
|
|
customView->setAttribute (kViewNameAttribute, viewName);
|
|
}
|
|
UIAttributes evaluatedAttributes;
|
|
evaluateAttributesAndRemember (customView, attributes, evaluatedAttributes, desc);
|
|
while (iter != registry.end () && (result = (*iter).second->apply (customView, evaluatedAttributes, desc)) && (*iter).second->getBaseViewName ())
|
|
{
|
|
iter = registry.find ((*iter).second->getBaseViewName ());
|
|
}
|
|
return result;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
IdStringPtr IViewFactory::getViewName (CView* view)
|
|
{
|
|
IdStringPtr viewName = nullptr;
|
|
uint32_t size = sizeof (IdStringPtr);
|
|
view->getAttribute (kViewNameAttribute, size, &viewName, size);
|
|
return viewName;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void UIViewFactory::evaluateAttributesAndRemember (CView* view, const UIAttributes& attributes, UIAttributes& evaluatedAttributes, const IUIDescription* description) const
|
|
{
|
|
std::string evaluatedValue;
|
|
for (const auto& attr : attributes)
|
|
{
|
|
const std::string& value = attr.second;
|
|
if (description && description->getVariable (value.c_str (), evaluatedValue))
|
|
{
|
|
#if VSTGUI_LIVE_EDITING
|
|
rememberAttribute (view, attr.first.c_str (), value.c_str ());
|
|
#endif
|
|
evaluatedAttributes.setAttribute (attr.first, evaluatedValue);
|
|
}
|
|
else
|
|
{
|
|
#if VSTGUI_LIVE_EDITING
|
|
auto type = getAttributeType (view, attr.first);
|
|
switch (type)
|
|
{
|
|
case IViewCreator::kColorType:
|
|
case IViewCreator::kTagType:
|
|
case IViewCreator::kFontType:
|
|
case IViewCreator::kGradientType:
|
|
rememberAttribute (view, attr.first.c_str (), value.c_str ());
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
#endif
|
|
evaluatedAttributes.setAttribute (attr.first, value);
|
|
}
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
bool UIViewFactory::getAttributeValue (CView* view, const std::string& attributeName, std::string& stringValue, const IUIDescription* desc) const
|
|
{
|
|
#if VSTGUI_LIVE_EDITING
|
|
bool result = getRememberedAttribute (view, attributeName.c_str (), stringValue);
|
|
if (result == false)
|
|
{
|
|
#else
|
|
bool result = false;
|
|
#endif
|
|
auto& registry = getCreatorRegistry ();
|
|
auto iter = registry.find (getViewName (view));
|
|
while (iter != registry.end () && !(result = (*iter).second->getAttributeValue (view, attributeName, stringValue, desc)) && (*iter).second->getBaseViewName ())
|
|
{
|
|
iter = registry.find ((*iter).second->getBaseViewName ());
|
|
}
|
|
#if VSTGUI_LIVE_EDITING
|
|
}
|
|
#endif
|
|
return result;
|
|
}
|
|
|
|
#if VSTGUI_LIVE_EDITING
|
|
//-----------------------------------------------------------------------------
|
|
bool UIViewFactory::getAttributeNamesForView (CView* view, StringList& attributeNames) const
|
|
{
|
|
bool result = false;
|
|
auto& registry = getCreatorRegistry ();
|
|
auto iter = registry.find (getViewName (view));
|
|
while (iter != registry.end () &&
|
|
(result = (*iter).second->getAttributeNames (attributeNames)) &&
|
|
(*iter).second->getBaseViewName ())
|
|
{
|
|
iter = registry.find ((*iter).second->getBaseViewName ());
|
|
}
|
|
return result;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
IViewCreator::AttrType UIViewFactory::getAttributeType (CView* view, const std::string& attributeName) const
|
|
{
|
|
auto& registry = getCreatorRegistry ();
|
|
auto type = IViewCreator::kUnknownType;
|
|
auto iter = registry.find (getViewName (view));
|
|
while (iter != registry.end () && (type = (*iter).second->getAttributeType (attributeName)) == IViewCreator::kUnknownType && (*iter).second->getBaseViewName ())
|
|
{
|
|
iter = registry.find ((*iter).second->getBaseViewName ());
|
|
}
|
|
return type;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
bool UIViewFactory::getPossibleAttributeListValues (CView* view, const std::string& attributeName, StringPtrList& values) const
|
|
{
|
|
auto& registry = getCreatorRegistry ();
|
|
auto iter = registry.find (getViewName (view));
|
|
while (iter != registry.end () && (*iter).second->getPossibleListValues (attributeName, values) == false && (*iter).second->getBaseViewName ())
|
|
{
|
|
iter = registry.find ((*iter).second->getBaseViewName ());
|
|
}
|
|
return !values.empty ();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
bool UIViewFactory::getAttributeValueRange (CView* view, const std::string& attributeName, double& minValue, double& maxValue) const
|
|
{
|
|
minValue = maxValue = -1.;
|
|
auto& registry = getCreatorRegistry ();
|
|
auto iter = registry.find (getViewName (view));
|
|
while (iter != registry.end () && (*iter).second->getAttributeValueRange (attributeName, minValue, maxValue) == false && (*iter).second->getBaseViewName ())
|
|
{
|
|
iter = registry.find ((*iter).second->getBaseViewName ());
|
|
}
|
|
return minValue != maxValue && minValue != -1.;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
bool UIViewFactory::getAttributesForView (CView* view, const IUIDescription* desc, UIAttributes& attr) const
|
|
{
|
|
bool result = false;
|
|
StringList attrNames;
|
|
if (getAttributeNamesForView (view, attrNames))
|
|
{
|
|
auto it = attrNames.begin ();
|
|
while (it != attrNames.end ())
|
|
{
|
|
std::string value;
|
|
if (getAttributeValue (view, *it, value, desc))
|
|
attr.setAttribute (*it, value);
|
|
it++;
|
|
}
|
|
attr.setAttribute (UIViewCreator::kAttrClass, getViewName (view));
|
|
result = true;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void UIViewFactory::collectRegisteredViewNames (StringPtrList& viewNames, IdStringPtr _baseClassNameFilter) const
|
|
{
|
|
UTF8StringView baseClassNameFilter (_baseClassNameFilter);
|
|
auto& registry = getCreatorRegistry ();
|
|
auto iter = registry.begin ();
|
|
while (iter != registry.end ())
|
|
{
|
|
if (baseClassNameFilter)
|
|
{
|
|
bool found = false;
|
|
auto iter2 = iter;
|
|
while (iter2 != registry.end () && (*iter2).second->getBaseViewName ())
|
|
{
|
|
if (baseClassNameFilter == (*iter2).second->getViewName () || baseClassNameFilter == (*iter2).second->getBaseViewName ())
|
|
{
|
|
found = true;
|
|
break;
|
|
}
|
|
iter2 = registry.find ((*iter2).second->getBaseViewName ());
|
|
}
|
|
if (!found)
|
|
{
|
|
iter++;
|
|
continue;
|
|
}
|
|
}
|
|
viewNames.emplace_back (&(*iter).first);
|
|
iter++;
|
|
}
|
|
viewNames.sort ([] (const std::string* lhs, const std::string* rhs) { return *lhs < *rhs; });
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
auto UIViewFactory::collectRegisteredViewAndDisplayNames (IdStringPtr baseClassNameFilter) const -> ViewAndDisplayNameList
|
|
{
|
|
ViewAndDisplayNameList list;
|
|
auto& registry = getCreatorRegistry ();
|
|
auto iter = registry.begin ();
|
|
while (iter != registry.end ())
|
|
{
|
|
if (baseClassNameFilter)
|
|
{
|
|
UTF8StringView baseClassNameStr (baseClassNameFilter);
|
|
bool found = false;
|
|
auto iter2 = iter;
|
|
while (iter2 != registry.end () && (*iter2).second->getBaseViewName ())
|
|
{
|
|
if (baseClassNameStr == (*iter2).second->getViewName () || baseClassNameStr == (*iter2).second->getBaseViewName ())
|
|
{
|
|
found = true;
|
|
break;
|
|
}
|
|
iter2 = registry.find ((*iter2).second->getBaseViewName ());
|
|
}
|
|
if (!found)
|
|
{
|
|
iter++;
|
|
continue;
|
|
}
|
|
}
|
|
list.emplace_back (&(*iter).first, (*iter).second->getDisplayName ());
|
|
iter++;
|
|
}
|
|
return list;
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
UTF8StringPtr UIViewFactory::getViewDisplayName (CView* view) const
|
|
{
|
|
if (auto viewName = getViewName (view))
|
|
{
|
|
UTF8StringView viewNameStr (viewName);
|
|
auto& registry = getCreatorRegistry ();
|
|
for (auto& entry : registry)
|
|
{
|
|
if (viewNameStr == entry.second->getViewName ())
|
|
return entry.second->getDisplayName ();
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
size_t UIViewFactory::createHash (const std::string& str)
|
|
{
|
|
static std::hash<std::string> hashFunc;
|
|
return hashFunc (str);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void UIViewFactory::rememberAttribute (CView* view, IdStringPtr attrName, const std::string& value) const
|
|
{
|
|
#if ENABLE_UNIT_TESTS
|
|
if (disableRememberAttributes)
|
|
return;
|
|
#endif
|
|
auto hash = createHash (attrName);
|
|
view->setAttribute (hash, static_cast<uint32_t> (value.size () + 1), value.c_str ());
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
bool UIViewFactory::getRememberedAttribute (CView* view, IdStringPtr attrName, std::string& value) const
|
|
{
|
|
bool result = false;
|
|
size_t hash = createHash (attrName);
|
|
uint32_t attrSize = 0;
|
|
if (view->getAttributeSize (hash, attrSize))
|
|
{
|
|
char* temp = new char[attrSize];
|
|
if (view->getAttribute (hash, attrSize, temp, attrSize))
|
|
{
|
|
value = temp;
|
|
result = true;
|
|
}
|
|
delete [] temp;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
#endif
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void UIViewFactory::registerViewCreator (const IViewCreator& viewCreator)
|
|
{
|
|
auto& registry = getCreatorRegistry ();
|
|
registry.add (viewCreator.getViewName (), &viewCreator);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void UIViewFactory::unregisterViewCreator (const IViewCreator& viewCreator)
|
|
{
|
|
auto& registry = getCreatorRegistry ();
|
|
registry.remove (&viewCreator);
|
|
}
|
|
|
|
} // VSTGUI
|