2015-02-12 23:16:25 +08:00
|
|
|
// Aseprite
|
2018-06-07 02:44:52 +08:00
|
|
|
// Copyright (C) 2001-2018 David Capello
|
2015-02-12 23:16:25 +08:00
|
|
|
//
|
2016-08-27 04:02:58 +08:00
|
|
|
// This program is distributed under the terms of
|
|
|
|
// the End-User License Agreement for Aseprite.
|
2012-06-16 10:37:59 +08:00
|
|
|
|
2013-08-06 08:20:19 +08:00
|
|
|
#ifdef HAVE_CONFIG_H
|
2012-06-16 10:37:59 +08:00
|
|
|
#include "config.h"
|
2013-08-06 08:20:19 +08:00
|
|
|
#endif
|
2012-06-16 10:37:59 +08:00
|
|
|
|
2018-06-07 02:44:52 +08:00
|
|
|
#include "app/ui/pref_widget.h"
|
|
|
|
|
2012-06-16 10:37:59 +08:00
|
|
|
#include "app/widget_loader.h"
|
|
|
|
|
2013-08-06 08:20:19 +08:00
|
|
|
#include "app/app.h"
|
2016-12-17 12:01:57 +08:00
|
|
|
#include "app/i18n/strings.h"
|
2013-08-06 08:20:19 +08:00
|
|
|
#include "app/modules/gui.h"
|
|
|
|
#include "app/resource_finder.h"
|
2014-09-08 13:27:41 +08:00
|
|
|
#include "app/ui/button_set.h"
|
2013-08-06 08:20:19 +08:00
|
|
|
#include "app/ui/color_button.h"
|
2015-03-20 02:21:28 +08:00
|
|
|
#include "app/ui/drop_down_button.h"
|
2015-12-11 03:52:43 +08:00
|
|
|
#include "app/ui/icon_button.h"
|
2015-12-01 02:08:18 +08:00
|
|
|
#include "app/ui/search_entry.h"
|
2014-09-08 13:27:41 +08:00
|
|
|
#include "app/ui/skin/skin_theme.h"
|
2012-06-16 10:37:59 +08:00
|
|
|
#include "app/widget_not_found.h"
|
2014-09-08 13:27:41 +08:00
|
|
|
#include "app/xml_document.h"
|
2013-08-06 08:20:19 +08:00
|
|
|
#include "app/xml_exception.h"
|
2012-06-16 10:37:59 +08:00
|
|
|
#include "base/bind.h"
|
2017-02-15 01:55:45 +08:00
|
|
|
#include "base/exception.h"
|
2013-10-15 06:58:11 +08:00
|
|
|
#include "base/fs.h"
|
2012-06-16 10:37:59 +08:00
|
|
|
#include "base/memory.h"
|
2015-02-26 20:53:19 +08:00
|
|
|
#include "she/system.h"
|
2013-08-06 08:20:19 +08:00
|
|
|
#include "ui/ui.h"
|
2012-06-16 10:37:59 +08:00
|
|
|
|
|
|
|
#include "tinyxml.h"
|
|
|
|
|
|
|
|
#include <cstdio>
|
|
|
|
#include <cstdlib>
|
|
|
|
#include <cstring>
|
2017-08-15 22:25:23 +08:00
|
|
|
#include <limits>
|
2012-06-16 10:37:59 +08:00
|
|
|
|
2013-08-06 08:20:19 +08:00
|
|
|
namespace app {
|
|
|
|
|
2012-06-18 09:02:54 +08:00
|
|
|
using namespace ui;
|
2014-09-08 13:27:41 +08:00
|
|
|
using namespace app::skin;
|
2012-06-18 09:02:54 +08:00
|
|
|
|
2012-06-16 10:37:59 +08:00
|
|
|
static int convert_align_value_to_flags(const char *value);
|
2014-09-08 13:27:41 +08:00
|
|
|
static int int_attr(const TiXmlElement* elem, const char* attribute_name, int default_value);
|
2012-06-16 10:37:59 +08:00
|
|
|
|
|
|
|
WidgetLoader::WidgetLoader()
|
|
|
|
: m_tooltipManager(NULL)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
WidgetLoader::~WidgetLoader()
|
|
|
|
{
|
|
|
|
for (TypeCreatorsMap::iterator
|
|
|
|
it=m_typeCreators.begin(), end=m_typeCreators.end(); it != end; ++it)
|
|
|
|
it->second->dispose();
|
|
|
|
}
|
|
|
|
|
|
|
|
void WidgetLoader::addWidgetType(const char* tagName, IWidgetTypeCreator* creator)
|
|
|
|
{
|
|
|
|
m_typeCreators[tagName] = creator;
|
|
|
|
}
|
|
|
|
|
2014-07-14 00:24:57 +08:00
|
|
|
Widget* WidgetLoader::loadWidget(const char* fileName, const char* widgetId, ui::Widget* widget)
|
2012-06-16 10:37:59 +08:00
|
|
|
{
|
|
|
|
std::string buf;
|
|
|
|
|
|
|
|
ResourceFinder rf;
|
|
|
|
rf.addPath(fileName);
|
|
|
|
|
2013-10-15 06:58:11 +08:00
|
|
|
buf = "widgets/";
|
2012-06-16 10:37:59 +08:00
|
|
|
buf += fileName;
|
2014-04-13 00:35:55 +08:00
|
|
|
rf.includeDataDir(buf.c_str());
|
2012-06-16 10:37:59 +08:00
|
|
|
|
2014-04-13 00:35:55 +08:00
|
|
|
if (!rf.findFirst())
|
2012-06-16 10:37:59 +08:00
|
|
|
throw WidgetNotFound(widgetId);
|
|
|
|
|
2014-07-14 00:24:57 +08:00
|
|
|
widget = loadWidgetFromXmlFile(rf.filename(), widgetId, widget);
|
2012-06-16 10:37:59 +08:00
|
|
|
if (!widget)
|
|
|
|
throw WidgetNotFound(widgetId);
|
|
|
|
|
|
|
|
return widget;
|
|
|
|
}
|
|
|
|
|
2014-07-14 00:24:57 +08:00
|
|
|
Widget* WidgetLoader::loadWidgetFromXmlFile(
|
|
|
|
const std::string& xmlFilename,
|
|
|
|
const std::string& widgetId,
|
|
|
|
ui::Widget* widget)
|
2012-06-16 10:37:59 +08:00
|
|
|
{
|
|
|
|
m_tooltipManager = NULL;
|
2017-10-12 05:02:38 +08:00
|
|
|
m_xmlTranslator.setStringIdPrefix(widgetId.c_str());
|
2012-06-16 10:37:59 +08:00
|
|
|
|
2013-10-15 06:58:11 +08:00
|
|
|
XmlDocumentRef doc(open_xml(xmlFilename));
|
2015-04-03 07:42:43 +08:00
|
|
|
TiXmlHandle handle(doc.get());
|
2012-06-16 10:37:59 +08:00
|
|
|
|
|
|
|
// Search the requested widget.
|
|
|
|
TiXmlElement* xmlElement = handle
|
|
|
|
.FirstChild("gui")
|
|
|
|
.FirstChildElement().ToElement();
|
|
|
|
|
|
|
|
while (xmlElement) {
|
|
|
|
const char* nodename = xmlElement->Attribute("id");
|
|
|
|
|
2013-10-15 06:58:11 +08:00
|
|
|
if (nodename && nodename == widgetId) {
|
2014-09-08 13:27:41 +08:00
|
|
|
widget = convertXmlElementToWidget(xmlElement, NULL, NULL, widget);
|
2012-06-16 10:37:59 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
xmlElement = xmlElement->NextSiblingElement();
|
|
|
|
}
|
|
|
|
|
|
|
|
return widget;
|
|
|
|
}
|
|
|
|
|
2014-09-08 13:27:41 +08:00
|
|
|
Widget* WidgetLoader::convertXmlElementToWidget(const TiXmlElement* elem, Widget* root, Widget* parent, Widget* widget)
|
2012-06-16 10:37:59 +08:00
|
|
|
{
|
2013-10-15 06:58:11 +08:00
|
|
|
const std::string elem_name = elem->Value();
|
2012-06-16 10:37:59 +08:00
|
|
|
|
|
|
|
// TODO error handling: add a message if the widget is bad specified
|
|
|
|
|
|
|
|
// Try to use one of the creators.
|
|
|
|
TypeCreatorsMap::iterator it = m_typeCreators.find(elem_name);
|
|
|
|
|
|
|
|
if (it != m_typeCreators.end()) {
|
2014-07-14 00:24:57 +08:00
|
|
|
if (!widget)
|
|
|
|
widget = it->second->createWidgetFromXml(elem);
|
2012-06-16 10:37:59 +08:00
|
|
|
}
|
2014-06-23 08:56:04 +08:00
|
|
|
else if (elem_name == "panel") {
|
2014-07-14 00:24:57 +08:00
|
|
|
if (!widget)
|
|
|
|
widget = new Panel();
|
2014-06-23 08:56:04 +08:00
|
|
|
}
|
2013-10-15 06:58:11 +08:00
|
|
|
else if (elem_name == "box") {
|
2012-06-16 10:37:59 +08:00
|
|
|
bool horizontal = bool_attr_is_true(elem, "horizontal");
|
|
|
|
bool vertical = bool_attr_is_true(elem, "vertical");
|
2015-06-24 01:00:00 +08:00
|
|
|
int align = (horizontal ? HORIZONTAL: vertical ? VERTICAL: 0);
|
2012-06-16 10:37:59 +08:00
|
|
|
|
2014-07-14 00:24:57 +08:00
|
|
|
if (!widget)
|
|
|
|
widget = new Box(align);
|
|
|
|
else
|
Refactor several "getNoun()" getters to "noun()"
This is a work-in-progress to create a consistent API and finally
separate the whole Aseprite base/gfx/ui libs into a reusable C++ library.
Classes:
app::IFileItem, app::AppMenuItem, app::skin::SkinPart,
gfx::Rect, gfx::Border, she::FileDialog,
ui::IButtonIcon, ui::Graphics, ui::Overlay, ui::Widget,
ui::ScrollableViewDelegate, and UI events
2015-12-05 01:39:04 +08:00
|
|
|
widget->setAlign(widget->align() | align);
|
2012-06-16 10:37:59 +08:00
|
|
|
}
|
2013-10-15 06:58:11 +08:00
|
|
|
else if (elem_name == "vbox") {
|
2014-07-14 00:24:57 +08:00
|
|
|
if (!widget)
|
|
|
|
widget = new VBox();
|
2012-06-16 10:37:59 +08:00
|
|
|
}
|
2013-10-15 06:58:11 +08:00
|
|
|
else if (elem_name == "hbox") {
|
2014-07-14 00:24:57 +08:00
|
|
|
if (!widget)
|
|
|
|
widget = new HBox();
|
2012-06-16 10:37:59 +08:00
|
|
|
}
|
2013-10-15 06:58:11 +08:00
|
|
|
else if (elem_name == "boxfiller") {
|
2014-07-14 00:24:57 +08:00
|
|
|
if (!widget)
|
|
|
|
widget = new BoxFiller();
|
2012-06-16 10:37:59 +08:00
|
|
|
}
|
2013-10-15 06:58:11 +08:00
|
|
|
else if (elem_name == "button") {
|
2015-12-11 03:52:43 +08:00
|
|
|
const char* icon_name = elem->Attribute("icon");
|
|
|
|
|
|
|
|
if (!widget) {
|
|
|
|
if (icon_name) {
|
|
|
|
SkinPartPtr part = SkinTheme::instance()->getPartById(icon_name);
|
|
|
|
if (!part)
|
|
|
|
throw base::Exception("<button> element found with invalid 'icon' attribute '%s'",
|
|
|
|
icon_name);
|
|
|
|
|
2017-08-15 21:39:06 +08:00
|
|
|
widget = new IconButton(part);
|
2015-12-11 03:52:43 +08:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
widget = new Button("");
|
|
|
|
}
|
|
|
|
}
|
2014-07-14 00:24:57 +08:00
|
|
|
|
|
|
|
bool left = bool_attr_is_true(elem, "left");
|
|
|
|
bool right = bool_attr_is_true(elem, "right");
|
|
|
|
bool top = bool_attr_is_true(elem, "top");
|
|
|
|
bool bottom = bool_attr_is_true(elem, "bottom");
|
|
|
|
bool closewindow = bool_attr_is_true(elem, "closewindow");
|
|
|
|
|
2015-06-24 01:00:00 +08:00
|
|
|
widget->setAlign((left ? LEFT: (right ? RIGHT: CENTER)) |
|
|
|
|
(top ? TOP: (bottom ? BOTTOM: MIDDLE)));
|
2014-07-14 00:24:57 +08:00
|
|
|
|
|
|
|
if (closewindow) {
|
|
|
|
static_cast<Button*>(widget)
|
2015-12-05 02:17:42 +08:00
|
|
|
->Click.connect(base::Bind<void>(&Widget::closeWindow, widget));
|
2012-06-16 10:37:59 +08:00
|
|
|
}
|
|
|
|
}
|
2013-10-15 06:58:11 +08:00
|
|
|
else if (elem_name == "check") {
|
2018-06-07 02:44:52 +08:00
|
|
|
const char* looklike = elem->Attribute("looklike");
|
|
|
|
const char* pref = elem->Attribute("pref");
|
|
|
|
|
|
|
|
ASSERT(!widget || !pref); // widget && pref is not supported
|
2012-06-16 10:37:59 +08:00
|
|
|
|
|
|
|
if (looklike != NULL && strcmp(looklike, "button") == 0) {
|
2018-06-07 02:44:52 +08:00
|
|
|
ASSERT(!pref); // not supported yet
|
|
|
|
|
2014-07-14 00:24:57 +08:00
|
|
|
if (!widget)
|
|
|
|
widget = new CheckBox("", kButtonWidget);
|
2012-06-16 10:37:59 +08:00
|
|
|
}
|
|
|
|
else {
|
2018-06-07 02:44:52 +08:00
|
|
|
if (!widget) {
|
|
|
|
// Automatic bind <check> widget with bool preference option
|
|
|
|
if (pref) {
|
|
|
|
auto prefWidget = new BoolPrefWidget<CheckBox>("");
|
|
|
|
prefWidget->setPref(pref);
|
|
|
|
widget = prefWidget;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
widget = new CheckBox("");
|
|
|
|
}
|
|
|
|
}
|
2012-06-16 10:37:59 +08:00
|
|
|
}
|
|
|
|
|
2014-07-14 00:24:57 +08:00
|
|
|
bool center = bool_attr_is_true(elem, "center");
|
|
|
|
bool right = bool_attr_is_true(elem, "right");
|
|
|
|
bool top = bool_attr_is_true(elem, "top");
|
|
|
|
bool bottom = bool_attr_is_true(elem, "bottom");
|
2012-06-16 10:37:59 +08:00
|
|
|
|
2015-06-24 01:00:00 +08:00
|
|
|
widget->setAlign((center ? CENTER:
|
|
|
|
(right ? RIGHT: LEFT)) |
|
|
|
|
(top ? TOP:
|
|
|
|
(bottom ? BOTTOM: MIDDLE)));
|
2012-06-16 10:37:59 +08:00
|
|
|
}
|
2013-10-15 06:58:11 +08:00
|
|
|
else if (elem_name == "combobox") {
|
2014-07-14 00:24:57 +08:00
|
|
|
if (!widget)
|
|
|
|
widget = new ComboBox();
|
2014-08-11 22:33:17 +08:00
|
|
|
|
|
|
|
bool editable = bool_attr_is_true(elem, "editable");
|
|
|
|
if (editable)
|
|
|
|
((ComboBox*)widget)->setEditable(true);
|
2012-06-16 10:37:59 +08:00
|
|
|
}
|
2013-10-15 06:58:11 +08:00
|
|
|
else if (elem_name == "entry") {
|
2013-03-31 07:10:54 +08:00
|
|
|
const char* maxsize = elem->Attribute("maxsize");
|
|
|
|
const char* suffix = elem->Attribute("suffix");
|
2012-06-16 10:37:59 +08:00
|
|
|
|
|
|
|
if (maxsize != NULL) {
|
|
|
|
bool readonly = bool_attr_is_true(elem, "readonly");
|
|
|
|
|
2014-07-14 00:24:57 +08:00
|
|
|
widget = new Entry(strtol(maxsize, NULL, 10), "");
|
2012-06-16 10:37:59 +08:00
|
|
|
|
|
|
|
if (readonly)
|
|
|
|
((Entry*)widget)->setReadOnly(true);
|
2013-03-31 07:10:54 +08:00
|
|
|
|
|
|
|
if (suffix)
|
|
|
|
((Entry*)widget)->setSuffix(suffix);
|
2012-06-16 10:37:59 +08:00
|
|
|
}
|
2013-03-31 07:10:54 +08:00
|
|
|
else
|
|
|
|
throw std::runtime_error("<entry> element found without 'maxsize' attribute");
|
2012-06-16 10:37:59 +08:00
|
|
|
}
|
2013-10-15 06:58:11 +08:00
|
|
|
else if (elem_name == "grid") {
|
2012-06-16 10:37:59 +08:00
|
|
|
const char *columns = elem->Attribute("columns");
|
|
|
|
bool same_width_columns = bool_attr_is_true(elem, "same_width_columns");
|
|
|
|
|
|
|
|
if (columns != NULL) {
|
2014-05-03 07:21:57 +08:00
|
|
|
widget = new Grid(strtol(columns, NULL, 10),
|
2012-06-16 10:37:59 +08:00
|
|
|
same_width_columns);
|
|
|
|
}
|
|
|
|
}
|
2013-10-15 06:58:11 +08:00
|
|
|
else if (elem_name == "label") {
|
2014-07-14 00:24:57 +08:00
|
|
|
if (!widget)
|
|
|
|
widget = new Label("");
|
|
|
|
|
|
|
|
bool center = bool_attr_is_true(elem, "center");
|
|
|
|
bool right = bool_attr_is_true(elem, "right");
|
|
|
|
bool top = bool_attr_is_true(elem, "top");
|
|
|
|
bool bottom = bool_attr_is_true(elem, "bottom");
|
|
|
|
|
2015-06-24 01:00:00 +08:00
|
|
|
widget->setAlign((center ? CENTER:
|
|
|
|
(right ? RIGHT: LEFT)) |
|
|
|
|
(top ? TOP:
|
|
|
|
(bottom ? BOTTOM: MIDDLE)));
|
2012-06-16 10:37:59 +08:00
|
|
|
}
|
2014-06-14 10:00:49 +08:00
|
|
|
else if (elem_name == "link") {
|
|
|
|
const char* url = elem->Attribute("url");
|
|
|
|
|
2014-07-14 00:24:57 +08:00
|
|
|
if (!widget)
|
|
|
|
widget = new LinkLabel(url ? url: "", "");
|
|
|
|
else {
|
|
|
|
LinkLabel* link = dynamic_cast<LinkLabel*>(widget);
|
|
|
|
ASSERT(link != NULL);
|
|
|
|
if (link)
|
|
|
|
link->setUrl(url);
|
2014-06-14 10:00:49 +08:00
|
|
|
}
|
2014-07-14 00:24:57 +08:00
|
|
|
|
|
|
|
bool center = bool_attr_is_true(elem, "center");
|
|
|
|
bool right = bool_attr_is_true(elem, "right");
|
|
|
|
bool top = bool_attr_is_true(elem, "top");
|
|
|
|
bool bottom = bool_attr_is_true(elem, "bottom");
|
|
|
|
|
|
|
|
widget->setAlign(
|
2015-06-24 01:00:00 +08:00
|
|
|
(center ? CENTER: (right ? RIGHT: LEFT)) |
|
|
|
|
(top ? TOP: (bottom ? BOTTOM: MIDDLE)));
|
2014-06-14 10:00:49 +08:00
|
|
|
}
|
2013-10-15 06:58:11 +08:00
|
|
|
else if (elem_name == "listbox") {
|
2014-07-14 00:24:57 +08:00
|
|
|
if (!widget)
|
|
|
|
widget = new ListBox();
|
2016-11-16 05:11:47 +08:00
|
|
|
|
|
|
|
bool multiselect = bool_attr_is_true(elem, "multiselect");
|
|
|
|
if (multiselect)
|
|
|
|
static_cast<ListBox*>(widget)->setMultiselect(multiselect);
|
2012-06-16 10:37:59 +08:00
|
|
|
}
|
2013-10-15 06:58:11 +08:00
|
|
|
else if (elem_name == "listitem") {
|
2014-07-14 00:24:57 +08:00
|
|
|
ListItem* listitem;
|
|
|
|
if (!widget) {
|
|
|
|
listitem = new ListItem("");
|
|
|
|
widget = listitem;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
listitem = dynamic_cast<ListItem*>(widget);
|
|
|
|
ASSERT(listitem != NULL);
|
|
|
|
}
|
2012-06-16 10:37:59 +08:00
|
|
|
|
2014-07-14 00:24:57 +08:00
|
|
|
const char* value = elem->Attribute("value");
|
|
|
|
if (value)
|
2014-06-23 08:56:04 +08:00
|
|
|
listitem->setValue(value);
|
2012-06-16 10:37:59 +08:00
|
|
|
}
|
2013-10-15 06:58:11 +08:00
|
|
|
else if (elem_name == "splitter") {
|
2012-06-16 10:37:59 +08:00
|
|
|
bool horizontal = bool_attr_is_true(elem, "horizontal");
|
|
|
|
bool vertical = bool_attr_is_true(elem, "vertical");
|
2012-07-18 12:10:43 +08:00
|
|
|
const char* by = elem->Attribute("by");
|
|
|
|
const char* position = elem->Attribute("position");
|
|
|
|
Splitter::Type type = (by && strcmp(by, "pixel") == 0 ?
|
|
|
|
Splitter::ByPixel:
|
|
|
|
Splitter::ByPercentage);
|
|
|
|
|
|
|
|
Splitter* splitter = new Splitter(type,
|
2015-06-24 01:00:00 +08:00
|
|
|
horizontal ? HORIZONTAL:
|
|
|
|
vertical ? VERTICAL: 0);
|
2012-07-18 12:10:43 +08:00
|
|
|
if (position) {
|
|
|
|
splitter->setPosition(strtod(position, NULL)
|
2014-11-26 09:33:45 +08:00
|
|
|
* (type == Splitter::ByPixel ? guiscale(): 1));
|
2012-07-18 12:10:43 +08:00
|
|
|
}
|
|
|
|
widget = splitter;
|
2012-06-16 10:37:59 +08:00
|
|
|
}
|
2013-10-15 06:58:11 +08:00
|
|
|
else if (elem_name == "radio") {
|
2012-06-16 10:37:59 +08:00
|
|
|
const char* group = elem->Attribute("group");
|
2014-07-14 00:24:57 +08:00
|
|
|
const char* looklike = elem->Attribute("looklike");
|
2012-06-16 10:37:59 +08:00
|
|
|
|
2014-05-03 07:21:57 +08:00
|
|
|
int radio_group = (group ? strtol(group, NULL, 10): 1);
|
2012-06-16 10:37:59 +08:00
|
|
|
|
2014-07-14 00:24:57 +08:00
|
|
|
if (!widget) {
|
|
|
|
if (looklike != NULL && strcmp(looklike, "button") == 0) {
|
|
|
|
widget = new RadioButton("", radio_group, kButtonWidget);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
widget = new RadioButton("", radio_group);
|
|
|
|
}
|
2012-06-16 10:37:59 +08:00
|
|
|
}
|
|
|
|
else {
|
2014-07-14 00:24:57 +08:00
|
|
|
RadioButton* radio = dynamic_cast<RadioButton*>(widget);
|
|
|
|
ASSERT(radio != NULL);
|
|
|
|
if (radio)
|
|
|
|
radio->setRadioGroup(radio_group);
|
2012-06-16 10:37:59 +08:00
|
|
|
}
|
|
|
|
|
2014-07-14 00:24:57 +08:00
|
|
|
bool center = bool_attr_is_true(elem, "center");
|
|
|
|
bool right = bool_attr_is_true(elem, "right");
|
|
|
|
bool top = bool_attr_is_true(elem, "top");
|
|
|
|
bool bottom = bool_attr_is_true(elem, "bottom");
|
2012-06-16 10:37:59 +08:00
|
|
|
|
2014-07-14 00:24:57 +08:00
|
|
|
widget->setAlign(
|
2015-06-24 01:00:00 +08:00
|
|
|
(center ? CENTER:
|
|
|
|
(right ? RIGHT: LEFT)) |
|
|
|
|
(top ? TOP:
|
|
|
|
(bottom ? BOTTOM: MIDDLE)));
|
2012-06-16 10:37:59 +08:00
|
|
|
}
|
2013-10-15 06:58:11 +08:00
|
|
|
else if (elem_name == "separator") {
|
2012-06-16 10:37:59 +08:00
|
|
|
bool center = bool_attr_is_true(elem, "center");
|
|
|
|
bool right = bool_attr_is_true(elem, "right");
|
|
|
|
bool middle = bool_attr_is_true(elem, "middle");
|
|
|
|
bool bottom = bool_attr_is_true(elem, "bottom");
|
|
|
|
bool horizontal = bool_attr_is_true(elem, "horizontal");
|
|
|
|
bool vertical = bool_attr_is_true(elem, "vertical");
|
2014-07-14 00:24:57 +08:00
|
|
|
int align =
|
2015-06-24 01:00:00 +08:00
|
|
|
(horizontal ? HORIZONTAL: 0) |
|
|
|
|
(vertical ? VERTICAL: 0) |
|
|
|
|
(center ? CENTER: (right ? RIGHT: LEFT)) |
|
|
|
|
(middle ? MIDDLE: (bottom ? BOTTOM: TOP));
|
2014-07-14 00:24:57 +08:00
|
|
|
|
|
|
|
if (!widget) {
|
2017-10-12 05:02:38 +08:00
|
|
|
widget = new Separator(m_xmlTranslator(elem, "text"), align);
|
2014-07-14 00:24:57 +08:00
|
|
|
}
|
|
|
|
else
|
Refactor several "getNoun()" getters to "noun()"
This is a work-in-progress to create a consistent API and finally
separate the whole Aseprite base/gfx/ui libs into a reusable C++ library.
Classes:
app::IFileItem, app::AppMenuItem, app::skin::SkinPart,
gfx::Rect, gfx::Border, she::FileDialog,
ui::IButtonIcon, ui::Graphics, ui::Overlay, ui::Widget,
ui::ScrollableViewDelegate, and UI events
2015-12-05 01:39:04 +08:00
|
|
|
widget->setAlign(widget->align() | align);
|
2012-06-16 10:37:59 +08:00
|
|
|
}
|
2013-10-15 06:58:11 +08:00
|
|
|
else if (elem_name == "slider") {
|
2012-06-16 10:37:59 +08:00
|
|
|
const char *min = elem->Attribute("min");
|
|
|
|
const char *max = elem->Attribute("max");
|
2014-05-03 07:21:57 +08:00
|
|
|
int min_value = min != NULL ? strtol(min, NULL, 10): 0;
|
|
|
|
int max_value = max != NULL ? strtol(max, NULL, 10): 0;
|
2012-06-16 10:37:59 +08:00
|
|
|
|
|
|
|
widget = new Slider(min_value, max_value, min_value);
|
|
|
|
}
|
2013-10-15 06:58:11 +08:00
|
|
|
else if (elem_name == "textbox") {
|
2012-06-16 11:03:27 +08:00
|
|
|
bool wordwrap = bool_attr_is_true(elem, "wordwrap");
|
2012-06-16 10:37:59 +08:00
|
|
|
|
2014-07-14 00:24:57 +08:00
|
|
|
if (!widget)
|
|
|
|
widget = new TextBox(elem->GetText(), 0);
|
|
|
|
else
|
|
|
|
widget->setText(elem->GetText());
|
|
|
|
|
|
|
|
if (wordwrap)
|
Refactor several "getNoun()" getters to "noun()"
This is a work-in-progress to create a consistent API and finally
separate the whole Aseprite base/gfx/ui libs into a reusable C++ library.
Classes:
app::IFileItem, app::AppMenuItem, app::skin::SkinPart,
gfx::Rect, gfx::Border, she::FileDialog,
ui::IButtonIcon, ui::Graphics, ui::Overlay, ui::Widget,
ui::ScrollableViewDelegate, and UI events
2015-12-05 01:39:04 +08:00
|
|
|
widget->setAlign(widget->align() | WORDWRAP);
|
2012-06-16 10:37:59 +08:00
|
|
|
}
|
2013-10-15 06:58:11 +08:00
|
|
|
else if (elem_name == "view") {
|
2014-07-14 00:24:57 +08:00
|
|
|
if (!widget)
|
|
|
|
widget = new View();
|
2012-06-16 10:37:59 +08:00
|
|
|
}
|
2013-10-15 06:58:11 +08:00
|
|
|
else if (elem_name == "window") {
|
2014-07-14 00:24:57 +08:00
|
|
|
if (!widget) {
|
|
|
|
bool desktop = bool_attr_is_true(elem, "desktop");
|
|
|
|
|
|
|
|
if (desktop)
|
|
|
|
widget = new Window(Window::DesktopWindow);
|
2016-12-17 12:01:57 +08:00
|
|
|
else if (elem->Attribute("text"))
|
2017-10-12 05:02:38 +08:00
|
|
|
widget = new Window(Window::WithTitleBar, m_xmlTranslator(elem, "text"));
|
2014-07-14 00:24:57 +08:00
|
|
|
else
|
|
|
|
widget = new Window(Window::WithoutTitleBar);
|
|
|
|
}
|
2012-06-16 10:37:59 +08:00
|
|
|
}
|
2013-10-15 06:58:11 +08:00
|
|
|
else if (elem_name == "colorpicker") {
|
2017-04-05 07:02:29 +08:00
|
|
|
const bool rgba = bool_attr_is_true(elem, "rgba");
|
|
|
|
const bool simple = bool_attr_is_true(elem, "simple");
|
2017-03-25 12:01:59 +08:00
|
|
|
|
2017-06-23 05:39:28 +08:00
|
|
|
if (!widget) {
|
|
|
|
ColorButtonOptions options;
|
|
|
|
options.canPinSelector = false;
|
|
|
|
options.showSimpleColors = simple;
|
|
|
|
options.showIndexTab = true;
|
2017-03-25 12:01:59 +08:00
|
|
|
widget = new ColorButton(Color::fromMask(),
|
2017-06-23 05:39:28 +08:00
|
|
|
(rgba ? IMAGE_RGB:
|
|
|
|
app_get_current_pixel_format()),
|
|
|
|
options);
|
|
|
|
}
|
2012-06-16 10:37:59 +08:00
|
|
|
}
|
2015-03-20 02:21:28 +08:00
|
|
|
else if (elem_name == "dropdownbutton") {
|
|
|
|
if (!widget) {
|
2017-10-12 05:02:38 +08:00
|
|
|
widget = new DropDownButton(m_xmlTranslator(elem, "text").c_str());
|
2015-03-20 02:21:28 +08:00
|
|
|
}
|
|
|
|
}
|
2014-09-08 13:27:41 +08:00
|
|
|
else if (elem_name == "buttonset") {
|
|
|
|
const char* columns = elem->Attribute("columns");
|
|
|
|
|
|
|
|
if (!widget && columns)
|
|
|
|
widget = new ButtonSet(strtol(columns, NULL, 10));
|
2015-12-17 05:14:04 +08:00
|
|
|
|
|
|
|
if (ButtonSet* buttonset = dynamic_cast<ButtonSet*>(widget)) {
|
|
|
|
bool multiple = bool_attr_is_true(elem, "multiple");
|
|
|
|
if (multiple)
|
|
|
|
buttonset->setMultipleSelection(multiple);
|
|
|
|
}
|
2014-09-08 13:27:41 +08:00
|
|
|
}
|
|
|
|
else if (elem_name == "item") {
|
|
|
|
if (!parent)
|
|
|
|
throw std::runtime_error("<item> without parent");
|
|
|
|
|
|
|
|
if (ButtonSet* buttonset = dynamic_cast<ButtonSet*>(parent)) {
|
|
|
|
const char* icon = elem->Attribute("icon");
|
2015-08-12 23:38:07 +08:00
|
|
|
const char* text = elem->Attribute("text");
|
|
|
|
int hspan = int_attr(elem, "hspan", 1);
|
|
|
|
int vspan = int_attr(elem, "vspan", 1);
|
2014-09-08 13:27:41 +08:00
|
|
|
|
2015-08-12 23:38:07 +08:00
|
|
|
ButtonSet::Item* item = new ButtonSet::Item();
|
|
|
|
|
|
|
|
if (icon) {
|
|
|
|
SkinPartPtr part = SkinTheme::instance()->getPartById(std::string(icon));
|
2015-08-05 06:38:52 +08:00
|
|
|
if (part)
|
2015-08-12 23:38:07 +08:00
|
|
|
item->setIcon(part);
|
2014-09-08 13:27:41 +08:00
|
|
|
}
|
2015-08-12 23:38:07 +08:00
|
|
|
|
|
|
|
if (text)
|
2017-10-12 05:02:38 +08:00
|
|
|
item->setText(m_xmlTranslator(elem, "text"));
|
2015-08-12 23:38:07 +08:00
|
|
|
|
|
|
|
buttonset->addItem(item, hspan, vspan);
|
|
|
|
fillWidgetWithXmlElementAttributes(elem, root, item);
|
2014-09-08 13:27:41 +08:00
|
|
|
}
|
|
|
|
}
|
2015-02-26 20:53:19 +08:00
|
|
|
else if (elem_name == "image") {
|
|
|
|
if (!widget) {
|
|
|
|
const char* file = elem->Attribute("file");
|
|
|
|
|
|
|
|
// Load image
|
|
|
|
std::string icon(file);
|
|
|
|
|
|
|
|
ResourceFinder rf;
|
|
|
|
rf.includeDataDir(file);
|
|
|
|
if (!rf.findFirst())
|
|
|
|
throw base::Exception("File %s not found", file);
|
|
|
|
|
|
|
|
try {
|
|
|
|
she::Surface* sur = she::instance()->loadRgbaSurface(rf.filename().c_str());
|
2016-05-11 23:58:27 +08:00
|
|
|
widget = new ImageView(sur, 0, true);
|
2015-02-26 20:53:19 +08:00
|
|
|
}
|
|
|
|
catch (...) {
|
|
|
|
throw base::Exception("Error loading %s file", file);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-12-01 02:08:18 +08:00
|
|
|
else if (elem_name == "search") {
|
|
|
|
if (!widget)
|
|
|
|
widget = new SearchEntry;
|
|
|
|
}
|
2012-06-16 10:37:59 +08:00
|
|
|
|
|
|
|
// Was the widget created?
|
2017-02-15 01:16:37 +08:00
|
|
|
if (widget) {
|
2015-08-12 23:38:07 +08:00
|
|
|
fillWidgetWithXmlElementAttributesWithChildren(elem, root, widget);
|
2017-02-15 01:16:37 +08:00
|
|
|
}
|
2014-05-03 07:19:43 +08:00
|
|
|
|
2014-07-14 00:24:57 +08:00
|
|
|
return widget;
|
|
|
|
}
|
2012-06-16 10:37:59 +08:00
|
|
|
|
2014-09-08 13:27:41 +08:00
|
|
|
void WidgetLoader::fillWidgetWithXmlElementAttributes(const TiXmlElement* elem, Widget* root, Widget* widget)
|
2014-07-14 00:24:57 +08:00
|
|
|
{
|
|
|
|
const char* id = elem->Attribute("id");
|
2015-08-01 02:55:06 +08:00
|
|
|
const char* tooltip_dir = elem->Attribute("tooltip_dir");
|
2014-07-14 00:24:57 +08:00
|
|
|
bool selected = bool_attr_is_true(elem, "selected");
|
|
|
|
bool disabled = bool_attr_is_true(elem, "disabled");
|
|
|
|
bool expansive = bool_attr_is_true(elem, "expansive");
|
|
|
|
bool homogeneous = bool_attr_is_true(elem, "homogeneous");
|
|
|
|
bool magnet = bool_attr_is_true(elem, "magnet");
|
|
|
|
bool noborders = bool_attr_is_true(elem, "noborders");
|
|
|
|
const char* width = elem->Attribute("width");
|
|
|
|
const char* height = elem->Attribute("height");
|
|
|
|
const char* minwidth = elem->Attribute("minwidth");
|
|
|
|
const char* minheight = elem->Attribute("minheight");
|
|
|
|
const char* maxwidth = elem->Attribute("maxwidth");
|
|
|
|
const char* maxheight = elem->Attribute("maxheight");
|
2015-02-26 20:53:19 +08:00
|
|
|
const char* border = elem->Attribute("border");
|
|
|
|
const char* styleid = elem->Attribute("style");
|
2014-07-14 00:24:57 +08:00
|
|
|
const char* childspacing = elem->Attribute("childspacing");
|
|
|
|
|
|
|
|
if (width) {
|
|
|
|
if (!minwidth) minwidth = width;
|
|
|
|
if (!maxwidth) maxwidth = width;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (height) {
|
|
|
|
if (!minheight) minheight = height;
|
|
|
|
if (!maxheight) maxheight = height;
|
|
|
|
}
|
|
|
|
|
2016-12-17 12:01:57 +08:00
|
|
|
if (id)
|
2014-07-14 00:24:57 +08:00
|
|
|
widget->setId(id);
|
|
|
|
|
2016-12-17 12:01:57 +08:00
|
|
|
if (elem->Attribute("text"))
|
2017-10-12 05:02:38 +08:00
|
|
|
widget->setText(m_xmlTranslator(elem, "text"));
|
2014-07-14 00:24:57 +08:00
|
|
|
|
2016-12-17 12:01:57 +08:00
|
|
|
if (elem->Attribute("tooltip") && root) {
|
2014-07-14 00:24:57 +08:00
|
|
|
if (!m_tooltipManager) {
|
|
|
|
m_tooltipManager = new ui::TooltipManager();
|
|
|
|
root->addChild(m_tooltipManager);
|
2012-06-16 10:37:59 +08:00
|
|
|
}
|
2015-08-01 02:55:06 +08:00
|
|
|
|
|
|
|
int dir = LEFT;
|
|
|
|
if (tooltip_dir) {
|
|
|
|
if (strcmp(tooltip_dir, "top") == 0) dir = TOP;
|
|
|
|
else if (strcmp(tooltip_dir, "bottom") == 0) dir = BOTTOM;
|
|
|
|
else if (strcmp(tooltip_dir, "left") == 0) dir = LEFT;
|
|
|
|
else if (strcmp(tooltip_dir, "right") == 0) dir = RIGHT;
|
|
|
|
}
|
2016-12-17 12:01:57 +08:00
|
|
|
|
2017-10-12 05:02:38 +08:00
|
|
|
m_tooltipManager->addTooltipFor(widget, m_xmlTranslator(elem, "tooltip"), dir);
|
2014-07-14 00:24:57 +08:00
|
|
|
}
|
2012-06-16 10:37:59 +08:00
|
|
|
|
2014-07-14 00:24:57 +08:00
|
|
|
if (selected)
|
|
|
|
widget->setSelected(selected);
|
2012-06-16 10:37:59 +08:00
|
|
|
|
2014-07-14 00:24:57 +08:00
|
|
|
if (disabled)
|
|
|
|
widget->setEnabled(false);
|
2012-06-16 10:37:59 +08:00
|
|
|
|
2014-07-14 00:24:57 +08:00
|
|
|
if (expansive)
|
|
|
|
widget->setExpansive(true);
|
2012-06-16 10:37:59 +08:00
|
|
|
|
2014-07-14 00:24:57 +08:00
|
|
|
if (homogeneous)
|
Refactor several "getNoun()" getters to "noun()"
This is a work-in-progress to create a consistent API and finally
separate the whole Aseprite base/gfx/ui libs into a reusable C++ library.
Classes:
app::IFileItem, app::AppMenuItem, app::skin::SkinPart,
gfx::Rect, gfx::Border, she::FileDialog,
ui::IButtonIcon, ui::Graphics, ui::Overlay, ui::Widget,
ui::ScrollableViewDelegate, and UI events
2015-12-05 01:39:04 +08:00
|
|
|
widget->setAlign(widget->align() | HOMOGENEOUS);
|
2012-06-16 10:37:59 +08:00
|
|
|
|
2014-07-14 00:24:57 +08:00
|
|
|
if (magnet)
|
|
|
|
widget->setFocusMagnet(true);
|
2012-06-16 10:37:59 +08:00
|
|
|
|
2017-08-15 21:39:06 +08:00
|
|
|
if (noborders) {
|
|
|
|
widget->InitTheme.connect(
|
|
|
|
[widget]{
|
|
|
|
widget->noBorderNoChildSpacing();
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
if (border) {
|
|
|
|
int v = strtol(border, nullptr, 10);
|
|
|
|
widget->InitTheme.connect(
|
|
|
|
[widget, v]{
|
|
|
|
widget->setBorder(gfx::Border(v*guiscale()));
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
if (childspacing) {
|
|
|
|
int v = strtol(childspacing, nullptr, 10);
|
|
|
|
widget->InitTheme.connect(
|
|
|
|
[widget, v]{
|
|
|
|
widget->setChildSpacing(v*guiscale());
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
if (minwidth || minheight ||
|
|
|
|
maxwidth || maxheight) {
|
|
|
|
const int minw = (minwidth ? strtol(minwidth, NULL, 10): 0);
|
|
|
|
const int minh = (minheight ? strtol(minheight, NULL, 10): 0);
|
|
|
|
const int maxw = (maxwidth ? strtol(maxwidth, NULL, 10): 0);
|
|
|
|
const int maxh = (maxheight ? strtol(maxheight, NULL, 10): 0);
|
|
|
|
widget->InitTheme.connect(
|
|
|
|
[widget, minw, minh, maxw, maxh]{
|
|
|
|
widget->setMinSize(gfx::Size(0, 0));
|
2017-08-15 22:25:23 +08:00
|
|
|
widget->setMaxSize(gfx::Size(std::numeric_limits<int>::max(),
|
|
|
|
std::numeric_limits<int>::max()));
|
2017-08-15 21:39:06 +08:00
|
|
|
const gfx::Size reqSize = widget->sizeHint();
|
|
|
|
widget->setMinSize(
|
|
|
|
gfx::Size((minw > 0 ? guiscale()*minw: reqSize.w),
|
|
|
|
(minh > 0 ? guiscale()*minh: reqSize.h)));
|
|
|
|
widget->setMaxSize(
|
2017-08-15 22:25:23 +08:00
|
|
|
gfx::Size((maxw > 0 ? guiscale()*maxw: std::numeric_limits<int>::max()),
|
|
|
|
(maxh > 0 ? guiscale()*maxh: std::numeric_limits<int>::max())));
|
2017-08-15 21:39:06 +08:00
|
|
|
});
|
2014-07-14 00:24:57 +08:00
|
|
|
}
|
2012-06-16 10:37:59 +08:00
|
|
|
|
2015-02-26 20:53:19 +08:00
|
|
|
if (styleid) {
|
2017-08-15 21:39:06 +08:00
|
|
|
std::string styleIdStr = styleid;
|
|
|
|
widget->InitTheme.connect(
|
|
|
|
[widget, styleIdStr]{
|
|
|
|
SkinTheme* theme = static_cast<SkinTheme*>(widget->theme());
|
|
|
|
ui::Style* style = theme->getStyleById(styleIdStr);
|
|
|
|
if (style)
|
|
|
|
widget->setStyle(style);
|
|
|
|
else
|
|
|
|
throw base::Exception("Style %s not found", styleIdStr.c_str());
|
|
|
|
});
|
2015-02-26 20:53:19 +08:00
|
|
|
}
|
2017-02-15 01:16:37 +08:00
|
|
|
|
|
|
|
// Assign widget mnemonic from the character preceded by a '&'
|
|
|
|
widget->processMnemonicFromText();
|
2017-08-15 21:39:06 +08:00
|
|
|
widget->initTheme();
|
2015-08-12 23:38:07 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void WidgetLoader::fillWidgetWithXmlElementAttributesWithChildren(const TiXmlElement* elem, ui::Widget* root, ui::Widget* widget)
|
|
|
|
{
|
|
|
|
fillWidgetWithXmlElementAttributes(elem, root, widget);
|
2015-02-26 20:53:19 +08:00
|
|
|
|
2014-07-14 00:24:57 +08:00
|
|
|
if (!root)
|
|
|
|
root = widget;
|
|
|
|
|
|
|
|
// Children
|
|
|
|
const TiXmlElement* childElem = elem->FirstChildElement();
|
|
|
|
while (childElem) {
|
2014-09-08 13:27:41 +08:00
|
|
|
Widget* child = convertXmlElementToWidget(childElem, root, widget, NULL);
|
2014-07-14 00:24:57 +08:00
|
|
|
if (child) {
|
|
|
|
// Attach the child in the view
|
2015-06-24 01:37:22 +08:00
|
|
|
if (widget->type() == kViewWidget) {
|
2014-07-14 00:24:57 +08:00
|
|
|
static_cast<View*>(widget)->attachToView(child);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
// Add the child in the grid
|
2015-06-24 01:37:22 +08:00
|
|
|
else if (widget->type() == kGridWidget) {
|
2014-07-14 00:24:57 +08:00
|
|
|
const char* cell_hspan = childElem->Attribute("cell_hspan");
|
|
|
|
const char* cell_vspan = childElem->Attribute("cell_vspan");
|
|
|
|
const char* cell_align = childElem->Attribute("cell_align");
|
|
|
|
int hspan = cell_hspan ? strtol(cell_hspan, NULL, 10): 1;
|
|
|
|
int vspan = cell_vspan ? strtol(cell_vspan, NULL, 10): 1;
|
|
|
|
int align = cell_align ? convert_align_value_to_flags(cell_align): 0;
|
|
|
|
Grid* grid = dynamic_cast<Grid*>(widget);
|
|
|
|
ASSERT(grid != NULL);
|
|
|
|
|
|
|
|
grid->addChildInCell(child, hspan, vspan, align);
|
|
|
|
}
|
2015-04-09 18:46:55 +08:00
|
|
|
// Attach the child in the view
|
2015-06-24 01:37:22 +08:00
|
|
|
else if (widget->type() == kComboBoxWidget &&
|
|
|
|
child->type() == kListItemWidget) {
|
2015-04-09 18:46:55 +08:00
|
|
|
ComboBox* combo = dynamic_cast<ComboBox*>(widget);
|
|
|
|
ASSERT(combo != NULL);
|
|
|
|
|
|
|
|
combo->addItem(dynamic_cast<ListItem*>(child));
|
|
|
|
}
|
2014-07-14 00:24:57 +08:00
|
|
|
// Just add the child in any other kind of widget
|
|
|
|
else
|
|
|
|
widget->addChild(child);
|
2012-06-16 10:37:59 +08:00
|
|
|
}
|
2014-07-14 00:24:57 +08:00
|
|
|
childElem = childElem->NextSiblingElement();
|
2012-06-16 10:37:59 +08:00
|
|
|
}
|
|
|
|
|
2015-06-24 01:37:22 +08:00
|
|
|
if (widget->type() == kViewWidget) {
|
2014-07-14 00:24:57 +08:00
|
|
|
bool maxsize = bool_attr_is_true(elem, "maxsize");
|
|
|
|
if (maxsize)
|
|
|
|
static_cast<View*>(widget)->makeVisibleAllScrollableArea();
|
|
|
|
}
|
2012-06-16 10:37:59 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static int convert_align_value_to_flags(const char *value)
|
|
|
|
{
|
|
|
|
char *tok, *ptr = base_strdup(value);
|
|
|
|
int flags = 0;
|
|
|
|
|
2014-08-22 12:32:13 +08:00
|
|
|
for (tok=strtok(ptr, " ");
|
2012-06-16 10:37:59 +08:00
|
|
|
tok != NULL;
|
2014-08-22 12:32:13 +08:00
|
|
|
tok=strtok(NULL, " ")) {
|
|
|
|
if (strcmp(tok, "horizontal") == 0) {
|
2015-06-24 01:00:00 +08:00
|
|
|
flags |= HORIZONTAL;
|
2012-06-16 10:37:59 +08:00
|
|
|
}
|
2014-08-22 12:32:13 +08:00
|
|
|
else if (strcmp(tok, "vertical") == 0) {
|
2015-06-24 01:00:00 +08:00
|
|
|
flags |= VERTICAL;
|
2012-06-16 10:37:59 +08:00
|
|
|
}
|
2014-08-22 12:32:13 +08:00
|
|
|
else if (strcmp(tok, "left") == 0) {
|
2015-06-24 01:00:00 +08:00
|
|
|
flags |= LEFT;
|
2012-06-16 10:37:59 +08:00
|
|
|
}
|
2014-08-22 12:32:13 +08:00
|
|
|
else if (strcmp(tok, "center") == 0) {
|
2015-06-24 01:00:00 +08:00
|
|
|
flags |= CENTER;
|
2012-06-16 10:37:59 +08:00
|
|
|
}
|
2014-08-22 12:32:13 +08:00
|
|
|
else if (strcmp(tok, "right") == 0) {
|
2015-06-24 01:00:00 +08:00
|
|
|
flags |= RIGHT;
|
2012-06-16 10:37:59 +08:00
|
|
|
}
|
2014-08-22 12:32:13 +08:00
|
|
|
else if (strcmp(tok, "top") == 0) {
|
2015-06-24 01:00:00 +08:00
|
|
|
flags |= TOP;
|
2012-06-16 10:37:59 +08:00
|
|
|
}
|
2014-08-22 12:32:13 +08:00
|
|
|
else if (strcmp(tok, "middle") == 0) {
|
2015-06-24 01:00:00 +08:00
|
|
|
flags |= MIDDLE;
|
2012-06-16 10:37:59 +08:00
|
|
|
}
|
2014-08-22 12:32:13 +08:00
|
|
|
else if (strcmp(tok, "bottom") == 0) {
|
2015-06-24 01:00:00 +08:00
|
|
|
flags |= BOTTOM;
|
2012-06-16 10:37:59 +08:00
|
|
|
}
|
2014-08-22 12:32:13 +08:00
|
|
|
else if (strcmp(tok, "homogeneous") == 0) {
|
2015-06-24 01:00:00 +08:00
|
|
|
flags |= HOMOGENEOUS;
|
2012-06-16 10:37:59 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
base_free(ptr);
|
|
|
|
return flags;
|
|
|
|
}
|
|
|
|
|
2014-09-08 13:27:41 +08:00
|
|
|
static int int_attr(const TiXmlElement* elem, const char* attribute_name, int default_value)
|
|
|
|
{
|
|
|
|
const char* value = elem->Attribute(attribute_name);
|
|
|
|
|
|
|
|
return (value ? strtol(value, NULL, 10): default_value);
|
|
|
|
}
|
|
|
|
|
2013-08-06 08:20:19 +08:00
|
|
|
} // namespace app
|