mirror of
https://github.com/aseprite/aseprite.git
synced 2025-03-28 16:20:50 +00:00
Add "gen" utility to generate UI widget wrappers from XML files
This commit is contained in:
parent
958d8f922f
commit
31e565a2b0
@ -1,15 +1,18 @@
|
||||
# ASEPRITE
|
||||
# Copyright (C) 2001-2013 David Capello
|
||||
# Aseprite
|
||||
# Copyright (C) 2001-2014 David Capello
|
||||
#
|
||||
# Parts of this file come from the Allegro 4.4 CMakeLists.txt
|
||||
|
||||
# CMake setup
|
||||
cmake_minimum_required(VERSION 2.6 FATAL_ERROR)
|
||||
|
||||
# CMP0003: Libraries linked via full path no longer produce linker search paths.
|
||||
#if(COMMAND cmake_policy)
|
||||
# cmake_policy(SET CMP0003 NEW)
|
||||
#endif(COMMAND cmake_policy)
|
||||
if(COMMAND cmake_policy)
|
||||
# CMP0003: Libraries linked via full path no longer produce linker search paths.
|
||||
#cmake_policy(SET CMP0003 NEW)
|
||||
|
||||
# CMP0046: Old behavior to silently ignore non-existent dependencies.
|
||||
cmake_policy(SET CMP0046 OLD)
|
||||
endif(COMMAND cmake_policy)
|
||||
|
||||
if(NOT CMAKE_BUILD_TYPE)
|
||||
set(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING
|
||||
|
@ -1,5 +1,5 @@
|
||||
# Aseprite
|
||||
# Copyright (C) 2001-2013 David Capello
|
||||
# Copyright (C) 2001-2014 David Capello
|
||||
|
||||
add_definitions(-DHAVE_CONFIG_H)
|
||||
|
||||
@ -20,6 +20,9 @@ set(aseprite_libraries app-lib css-lib doc-lib raster-lib
|
||||
# Directories where .h files can be found
|
||||
include_directories(. .. ../third_party)
|
||||
|
||||
# Directory where generated files by "gen" utility will stay.
|
||||
include_directories(${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
# Third-party libraries
|
||||
|
||||
if(USE_SHARED_JPEGLIB)
|
||||
@ -161,10 +164,11 @@ endif()
|
||||
# Aseprite Libraries (in preferred order to be built)
|
||||
|
||||
add_subdirectory(base)
|
||||
add_subdirectory(css)
|
||||
add_subdirectory(doc)
|
||||
add_subdirectory(filters)
|
||||
add_subdirectory(gen)
|
||||
add_subdirectory(gfx)
|
||||
add_subdirectory(css)
|
||||
add_subdirectory(raster)
|
||||
add_subdirectory(scripting)
|
||||
add_subdirectory(she)
|
||||
@ -209,6 +213,29 @@ if(EXISTS ../docs/quickref.pdf)
|
||||
DESTINATION share/aseprite/docs/quickref.pdf)
|
||||
endif()
|
||||
|
||||
######################################################################
|
||||
# Generate source files from widget XML files
|
||||
|
||||
file(GLOB widget_files ${CMAKE_SOURCE_DIR}/data/widgets/*.xml)
|
||||
foreach(widget_file ${widget_files})
|
||||
get_filename_component(widget_name ${widget_file} NAME_WE)
|
||||
set(target_name generated_${widget_name})
|
||||
set(output_fn ${CMAKE_CURRENT_BINARY_DIR}/generated_${widget_name}.h)
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${output_fn}
|
||||
COMMAND gen/gen --input ${widget_file} --widgetid ${widget_name} > ${output_fn}
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
|
||||
MAIN_DEPENDENCY ${widget_file}
|
||||
DEPENDS gen)
|
||||
|
||||
add_custom_target(${target_name} DEPENDS ${output_fn})
|
||||
|
||||
set_source_files_properties(${target_name} PROPERTIES GENERATED TRUE)
|
||||
|
||||
add_dependencies(app-lib ${target_name})
|
||||
endforeach()
|
||||
|
||||
######################################################################
|
||||
# Tests
|
||||
|
||||
|
@ -24,6 +24,7 @@ because they don't depend on any other component.
|
||||
|
||||
* [cfg](cfg/) (base, allegro): Library to handle configuration/settings/user preferences.
|
||||
* [doc](doc/) (base, gfx): Document model library (business layer, replacement of `raster` library).
|
||||
* [gen](gen/) (base): Helper utility to generate C++ files from different XMLs.
|
||||
* [net](net/) (base): Networking library to send HTTP requests.
|
||||
* [raster](raster/) (base, gfx): Library to handle graphics entities like sprites, images, frames.
|
||||
* [she](she/) (base, gfx, allegro): A wrapper for the Allegro library.
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* Aseprite
|
||||
* Copyright (C) 2001-2013 David Capello
|
||||
* Copyright (C) 2001-2014 David Capello
|
||||
*
|
||||
* 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
|
||||
@ -26,9 +26,9 @@
|
||||
namespace app {
|
||||
|
||||
template<class T>
|
||||
inline T* load_widget(const char* fileName, const char* widgetId) {
|
||||
inline T* load_widget(const char* fileName, const char* widgetId, T* widget = NULL) {
|
||||
WidgetLoader loader;
|
||||
return loader.loadWidgetT<T>(fileName, widgetId);
|
||||
return loader.loadWidgetT<T>(fileName, widgetId, widget);
|
||||
}
|
||||
|
||||
} // namespace app
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* Aseprite
|
||||
* Copyright (C) 2001-2013 David Capello
|
||||
* Copyright (C) 2001-2014 David Capello
|
||||
*
|
||||
* 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
|
||||
@ -42,8 +42,6 @@
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
|
||||
#define TRANSLATE_ATTR(a) a
|
||||
|
||||
namespace app {
|
||||
|
||||
using namespace ui;
|
||||
@ -68,9 +66,8 @@ void WidgetLoader::addWidgetType(const char* tagName, IWidgetTypeCreator* creato
|
||||
m_typeCreators[tagName] = creator;
|
||||
}
|
||||
|
||||
Widget* WidgetLoader::loadWidget(const char* fileName, const char* widgetId)
|
||||
Widget* WidgetLoader::loadWidget(const char* fileName, const char* widgetId, ui::Widget* widget)
|
||||
{
|
||||
Widget* widget;
|
||||
std::string buf;
|
||||
|
||||
ResourceFinder rf;
|
||||
@ -83,17 +80,18 @@ Widget* WidgetLoader::loadWidget(const char* fileName, const char* widgetId)
|
||||
if (!rf.findFirst())
|
||||
throw WidgetNotFound(widgetId);
|
||||
|
||||
widget = loadWidgetFromXmlFile(rf.filename(), widgetId);
|
||||
widget = loadWidgetFromXmlFile(rf.filename(), widgetId, widget);
|
||||
if (!widget)
|
||||
throw WidgetNotFound(widgetId);
|
||||
|
||||
return widget;
|
||||
}
|
||||
|
||||
Widget* WidgetLoader::loadWidgetFromXmlFile(const std::string& xmlFilename,
|
||||
const std::string& widgetId)
|
||||
Widget* WidgetLoader::loadWidgetFromXmlFile(
|
||||
const std::string& xmlFilename,
|
||||
const std::string& widgetId,
|
||||
ui::Widget* widget)
|
||||
{
|
||||
Widget* widget = NULL;
|
||||
m_tooltipManager = NULL;
|
||||
|
||||
XmlDocumentRef doc(open_xml(xmlFilename));
|
||||
@ -108,7 +106,7 @@ Widget* WidgetLoader::loadWidgetFromXmlFile(const std::string& xmlFilename,
|
||||
const char* nodename = xmlElement->Attribute("id");
|
||||
|
||||
if (nodename && nodename == widgetId) {
|
||||
widget = convertXmlElementToWidget(xmlElement, NULL);
|
||||
widget = convertXmlElementToWidget(xmlElement, NULL, widget);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -118,11 +116,9 @@ Widget* WidgetLoader::loadWidgetFromXmlFile(const std::string& xmlFilename,
|
||||
return widget;
|
||||
}
|
||||
|
||||
Widget* WidgetLoader::convertXmlElementToWidget(const TiXmlElement* elem, Widget* root)
|
||||
Widget* WidgetLoader::convertXmlElementToWidget(const TiXmlElement* elem, Widget* root, Widget* widget)
|
||||
{
|
||||
const std::string elem_name = elem->Value();
|
||||
Widget* widget = NULL;
|
||||
Widget* child;
|
||||
|
||||
// TODO error handling: add a message if the widget is bad specified
|
||||
|
||||
@ -130,121 +126,107 @@ Widget* WidgetLoader::convertXmlElementToWidget(const TiXmlElement* elem, Widget
|
||||
TypeCreatorsMap::iterator it = m_typeCreators.find(elem_name);
|
||||
|
||||
if (it != m_typeCreators.end()) {
|
||||
widget = it->second->createWidgetFromXml(elem);
|
||||
if (!widget)
|
||||
widget = it->second->createWidgetFromXml(elem);
|
||||
}
|
||||
// Oneof
|
||||
else if (elem_name == "panel") {
|
||||
widget = new Panel();
|
||||
if (!widget)
|
||||
widget = new Panel();
|
||||
}
|
||||
// Boxes
|
||||
else if (elem_name == "box") {
|
||||
bool horizontal = bool_attr_is_true(elem, "horizontal");
|
||||
bool vertical = bool_attr_is_true(elem, "vertical");
|
||||
bool homogeneous = bool_attr_is_true(elem, "homogeneous");
|
||||
int align = (horizontal ? JI_HORIZONTAL: vertical ? JI_VERTICAL: 0);
|
||||
|
||||
widget = new Box((horizontal ? JI_HORIZONTAL:
|
||||
vertical ? JI_VERTICAL: 0) |
|
||||
(homogeneous ? JI_HOMOGENEOUS: 0));
|
||||
if (!widget)
|
||||
widget = new Box(align);
|
||||
else
|
||||
widget->setAlign(widget->getAlign() | align);
|
||||
}
|
||||
else if (elem_name == "vbox") {
|
||||
bool homogeneous = bool_attr_is_true(elem, "homogeneous");
|
||||
|
||||
widget = new VBox();
|
||||
if (homogeneous)
|
||||
widget->setAlign(widget->getAlign() | JI_HOMOGENEOUS);
|
||||
if (!widget)
|
||||
widget = new VBox();
|
||||
}
|
||||
else if (elem_name == "hbox") {
|
||||
bool homogeneous = bool_attr_is_true(elem, "homogeneous");
|
||||
|
||||
widget = new HBox();
|
||||
if (homogeneous)
|
||||
widget->setAlign(widget->getAlign() | JI_HOMOGENEOUS);
|
||||
if (!widget)
|
||||
widget = new HBox();
|
||||
}
|
||||
else if (elem_name == "boxfiller") {
|
||||
widget = new BoxFiller();
|
||||
if (!widget)
|
||||
widget = new BoxFiller();
|
||||
}
|
||||
// Button
|
||||
else if (elem_name == "button") {
|
||||
const char *text = elem->Attribute("text");
|
||||
if (!widget)
|
||||
widget = new Button("");
|
||||
|
||||
widget = new Button(text ? TRANSLATE_ATTR(text): "");
|
||||
if (widget) {
|
||||
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");
|
||||
const char *_bevel = elem->Attribute("bevel");
|
||||
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");
|
||||
const char *_bevel = elem->Attribute("bevel");
|
||||
|
||||
widget->setAlign((left ? JI_LEFT: (right ? JI_RIGHT: JI_CENTER)) |
|
||||
(top ? JI_TOP: (bottom ? JI_BOTTOM: JI_MIDDLE)));
|
||||
widget->setAlign((left ? JI_LEFT: (right ? JI_RIGHT: JI_CENTER)) |
|
||||
(top ? JI_TOP: (bottom ? JI_BOTTOM: JI_MIDDLE)));
|
||||
|
||||
if (_bevel != NULL) {
|
||||
char* bevel = base_strdup(_bevel);
|
||||
int c, b[4];
|
||||
char *tok;
|
||||
if (_bevel != NULL) {
|
||||
char* bevel = base_strdup(_bevel);
|
||||
int c, b[4];
|
||||
char *tok;
|
||||
|
||||
for (c=0; c<4; ++c)
|
||||
b[c] = 0;
|
||||
for (c=0; c<4; ++c)
|
||||
b[c] = 0;
|
||||
|
||||
for (tok=ustrtok(bevel, " "), c=0;
|
||||
tok;
|
||||
tok=ustrtok(NULL, " "), ++c) {
|
||||
if (c < 4)
|
||||
b[c] = ustrtol(tok, NULL, 10);
|
||||
}
|
||||
base_free(bevel);
|
||||
|
||||
setup_bevels(widget, b[0], b[1], b[2], b[3]);
|
||||
for (tok=ustrtok(bevel, " "), c=0;
|
||||
tok;
|
||||
tok=ustrtok(NULL, " "), ++c) {
|
||||
if (c < 4)
|
||||
b[c] = ustrtol(tok, NULL, 10);
|
||||
}
|
||||
base_free(bevel);
|
||||
|
||||
if (closewindow) {
|
||||
static_cast<Button*>(widget)
|
||||
->Click.connect(Bind<void>(&Widget::closeWindow, widget));
|
||||
}
|
||||
setup_bevels(widget, b[0], b[1], b[2], b[3]);
|
||||
}
|
||||
|
||||
if (closewindow) {
|
||||
static_cast<Button*>(widget)
|
||||
->Click.connect(Bind<void>(&Widget::closeWindow, widget));
|
||||
}
|
||||
}
|
||||
// Check
|
||||
else if (elem_name == "check") {
|
||||
const char *text = elem->Attribute("text");
|
||||
const char *looklike = elem->Attribute("looklike");
|
||||
|
||||
text = (text ? TRANSLATE_ATTR(text): "");
|
||||
|
||||
if (looklike != NULL && strcmp(looklike, "button") == 0) {
|
||||
widget = new CheckBox(text, kButtonWidget);
|
||||
if (!widget)
|
||||
widget = new CheckBox("", kButtonWidget);
|
||||
}
|
||||
else {
|
||||
widget = new CheckBox(text);
|
||||
if (!widget)
|
||||
widget = new CheckBox("");
|
||||
}
|
||||
|
||||
if (widget) {
|
||||
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");
|
||||
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((center ? JI_CENTER:
|
||||
(right ? JI_RIGHT: JI_LEFT)) |
|
||||
(top ? JI_TOP:
|
||||
(bottom ? JI_BOTTOM: JI_MIDDLE)));
|
||||
}
|
||||
widget->setAlign((center ? JI_CENTER:
|
||||
(right ? JI_RIGHT: JI_LEFT)) |
|
||||
(top ? JI_TOP:
|
||||
(bottom ? JI_BOTTOM: JI_MIDDLE)));
|
||||
}
|
||||
/* combobox */
|
||||
else if (elem_name == "combobox") {
|
||||
widget = new ComboBox();
|
||||
if (!widget)
|
||||
widget = new ComboBox();
|
||||
}
|
||||
/* entry */
|
||||
else if (elem_name == "entry") {
|
||||
const char* maxsize = elem->Attribute("maxsize");
|
||||
const char* text = elem->Attribute("text");
|
||||
const char* suffix = elem->Attribute("suffix");
|
||||
|
||||
if (maxsize != NULL) {
|
||||
bool readonly = bool_attr_is_true(elem, "readonly");
|
||||
|
||||
widget = new Entry(strtol(maxsize, NULL, 10),
|
||||
text ? TRANSLATE_ATTR(text): "");
|
||||
widget = new Entry(strtol(maxsize, NULL, 10), "");
|
||||
|
||||
if (readonly)
|
||||
((Entry*)widget)->setReadOnly(true);
|
||||
@ -255,7 +237,6 @@ Widget* WidgetLoader::convertXmlElementToWidget(const TiXmlElement* elem, Widget
|
||||
else
|
||||
throw std::runtime_error("<entry> element found without 'maxsize' attribute");
|
||||
}
|
||||
/* grid */
|
||||
else if (elem_name == "grid") {
|
||||
const char *columns = elem->Attribute("columns");
|
||||
bool same_width_columns = bool_attr_is_true(elem, "same_width_columns");
|
||||
@ -265,56 +246,60 @@ Widget* WidgetLoader::convertXmlElementToWidget(const TiXmlElement* elem, Widget
|
||||
same_width_columns);
|
||||
}
|
||||
}
|
||||
/* label */
|
||||
else if (elem_name == "label") {
|
||||
const char *text = elem->Attribute("text");
|
||||
if (!widget)
|
||||
widget = new Label("");
|
||||
|
||||
widget = new Label(text ? TRANSLATE_ATTR(text): "");
|
||||
if (widget) {
|
||||
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");
|
||||
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((center ? JI_CENTER:
|
||||
(right ? JI_RIGHT: JI_LEFT)) |
|
||||
(top ? JI_TOP:
|
||||
(bottom ? JI_BOTTOM: JI_MIDDLE)));
|
||||
}
|
||||
widget->setAlign((center ? JI_CENTER:
|
||||
(right ? JI_RIGHT: JI_LEFT)) |
|
||||
(top ? JI_TOP:
|
||||
(bottom ? JI_BOTTOM: JI_MIDDLE)));
|
||||
}
|
||||
/* link */
|
||||
else if (elem_name == "link") {
|
||||
const char* text = elem->Attribute("text");
|
||||
const char* url = elem->Attribute("url");
|
||||
|
||||
widget = new LinkLabel(url ? url: "", text ? TRANSLATE_ATTR(text): "");
|
||||
if (widget) {
|
||||
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(
|
||||
(center ? JI_CENTER: (right ? JI_RIGHT: JI_LEFT)) |
|
||||
(top ? JI_TOP: (bottom ? JI_BOTTOM: JI_MIDDLE)));
|
||||
if (!widget)
|
||||
widget = new LinkLabel(url ? url: "", "");
|
||||
else {
|
||||
LinkLabel* link = dynamic_cast<LinkLabel*>(widget);
|
||||
ASSERT(link != NULL);
|
||||
if (link)
|
||||
link->setUrl(url);
|
||||
}
|
||||
|
||||
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(
|
||||
(center ? JI_CENTER: (right ? JI_RIGHT: JI_LEFT)) |
|
||||
(top ? JI_TOP: (bottom ? JI_BOTTOM: JI_MIDDLE)));
|
||||
}
|
||||
/* listbox */
|
||||
else if (elem_name == "listbox") {
|
||||
widget = new ListBox();
|
||||
if (!widget)
|
||||
widget = new ListBox();
|
||||
}
|
||||
/* listitem */
|
||||
else if (elem_name == "listitem") {
|
||||
const char* text = elem->Attribute("text");
|
||||
const char* value = elem->Attribute("value");
|
||||
|
||||
ListItem* listitem = new ListItem(text ? TRANSLATE_ATTR(text): "");
|
||||
if (value) {
|
||||
listitem->setValue(value);
|
||||
ListItem* listitem;
|
||||
if (!widget) {
|
||||
listitem = new ListItem("");
|
||||
widget = listitem;
|
||||
}
|
||||
widget = listitem;
|
||||
else {
|
||||
listitem = dynamic_cast<ListItem*>(widget);
|
||||
ASSERT(listitem != NULL);
|
||||
}
|
||||
|
||||
const char* value = elem->Attribute("value");
|
||||
if (value)
|
||||
listitem->setValue(value);
|
||||
}
|
||||
/* splitter */
|
||||
else if (elem_name == "splitter") {
|
||||
bool horizontal = bool_attr_is_true(elem, "horizontal");
|
||||
bool vertical = bool_attr_is_true(elem, "vertical");
|
||||
@ -333,53 +318,58 @@ Widget* WidgetLoader::convertXmlElementToWidget(const TiXmlElement* elem, Widget
|
||||
}
|
||||
widget = splitter;
|
||||
}
|
||||
/* radio */
|
||||
else if (elem_name == "radio") {
|
||||
const char* text = elem->Attribute("text");
|
||||
const char* group = elem->Attribute("group");
|
||||
const char *looklike = elem->Attribute("looklike");
|
||||
const char* looklike = elem->Attribute("looklike");
|
||||
|
||||
text = (text ? TRANSLATE_ATTR(text): "");
|
||||
int radio_group = (group ? strtol(group, NULL, 10): 1);
|
||||
|
||||
if (looklike != NULL && strcmp(looklike, "button") == 0) {
|
||||
widget = new RadioButton(text, radio_group, kButtonWidget);
|
||||
if (!widget) {
|
||||
if (looklike != NULL && strcmp(looklike, "button") == 0) {
|
||||
widget = new RadioButton("", radio_group, kButtonWidget);
|
||||
}
|
||||
else {
|
||||
widget = new RadioButton("", radio_group);
|
||||
}
|
||||
}
|
||||
else {
|
||||
widget = new RadioButton(text, radio_group);
|
||||
RadioButton* radio = dynamic_cast<RadioButton*>(widget);
|
||||
ASSERT(radio != NULL);
|
||||
if (radio)
|
||||
radio->setRadioGroup(radio_group);
|
||||
}
|
||||
|
||||
if (widget) {
|
||||
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");
|
||||
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((center ? JI_CENTER:
|
||||
(right ? JI_RIGHT: JI_LEFT)) |
|
||||
(top ? JI_TOP:
|
||||
(bottom ? JI_BOTTOM: JI_MIDDLE)));
|
||||
}
|
||||
widget->setAlign(
|
||||
(center ? JI_CENTER:
|
||||
(right ? JI_RIGHT: JI_LEFT)) |
|
||||
(top ? JI_TOP:
|
||||
(bottom ? JI_BOTTOM: JI_MIDDLE)));
|
||||
}
|
||||
/* separator */
|
||||
else if (elem_name == "separator") {
|
||||
const char *text = elem->Attribute("text");
|
||||
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");
|
||||
int align =
|
||||
(horizontal ? JI_HORIZONTAL: 0) |
|
||||
(vertical ? JI_VERTICAL: 0) |
|
||||
(center ? JI_CENTER: (right ? JI_RIGHT: JI_LEFT)) |
|
||||
(middle ? JI_MIDDLE: (bottom ? JI_BOTTOM: JI_TOP));
|
||||
|
||||
widget = new Separator(text ? TRANSLATE_ATTR(text): "",
|
||||
(horizontal ? JI_HORIZONTAL: 0) |
|
||||
(vertical ? JI_VERTICAL: 0) |
|
||||
(center ? JI_CENTER:
|
||||
(right ? JI_RIGHT: JI_LEFT)) |
|
||||
(middle ? JI_MIDDLE:
|
||||
(bottom ? JI_BOTTOM: JI_TOP)));
|
||||
if (!widget) {
|
||||
const char* text = elem->Attribute("text");
|
||||
widget = new Separator(text ? text: "", align);
|
||||
}
|
||||
else
|
||||
widget->setAlign(widget->getAlign() | align);
|
||||
}
|
||||
/* slider */
|
||||
else if (elem_name == "slider") {
|
||||
const char *min = elem->Attribute("min");
|
||||
const char *max = elem->Attribute("max");
|
||||
@ -388,145 +378,164 @@ Widget* WidgetLoader::convertXmlElementToWidget(const TiXmlElement* elem, Widget
|
||||
|
||||
widget = new Slider(min_value, max_value, min_value);
|
||||
}
|
||||
/* textbox */
|
||||
else if (elem_name == "textbox") {
|
||||
bool wordwrap = bool_attr_is_true(elem, "wordwrap");
|
||||
|
||||
widget = new TextBox(elem->GetText(), wordwrap ? JI_WORDWRAP: 0);
|
||||
}
|
||||
/* view */
|
||||
else if (elem_name == "view") {
|
||||
widget = new View();
|
||||
}
|
||||
/* window */
|
||||
else if (elem_name == "window") {
|
||||
const char *text = elem->Attribute("text");
|
||||
bool desktop = bool_attr_is_true(elem, "desktop");
|
||||
|
||||
if (desktop)
|
||||
widget = new Window(Window::DesktopWindow);
|
||||
else if (text)
|
||||
widget = new Window(Window::WithTitleBar, TRANSLATE_ATTR(text));
|
||||
if (!widget)
|
||||
widget = new TextBox(elem->GetText(), 0);
|
||||
else
|
||||
widget = new Window(Window::WithoutTitleBar);
|
||||
widget->setText(elem->GetText());
|
||||
|
||||
if (wordwrap)
|
||||
widget->setAlign(widget->getAlign() | JI_WORDWRAP);
|
||||
}
|
||||
else if (elem_name == "view") {
|
||||
if (!widget)
|
||||
widget = new View();
|
||||
}
|
||||
else if (elem_name == "window") {
|
||||
if (!widget) {
|
||||
const char* text = elem->Attribute("text");
|
||||
bool desktop = bool_attr_is_true(elem, "desktop");
|
||||
|
||||
if (desktop)
|
||||
widget = new Window(Window::DesktopWindow);
|
||||
else if (text)
|
||||
widget = new Window(Window::WithTitleBar, text);
|
||||
else
|
||||
widget = new Window(Window::WithoutTitleBar);
|
||||
}
|
||||
}
|
||||
/* colorpicker */
|
||||
else if (elem_name == "colorpicker") {
|
||||
widget = new ColorButton(Color::fromMask(), app_get_current_pixel_format());
|
||||
if (!widget)
|
||||
widget = new ColorButton(Color::fromMask(), app_get_current_pixel_format());
|
||||
}
|
||||
|
||||
// Was the widget created?
|
||||
if (widget) {
|
||||
const char* id = elem->Attribute("id");
|
||||
const char* tooltip = elem->Attribute("tooltip");
|
||||
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 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");
|
||||
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;
|
||||
}
|
||||
|
||||
if (id != NULL)
|
||||
widget->setId(id);
|
||||
|
||||
if (tooltip != NULL && root != NULL) {
|
||||
if (!m_tooltipManager) {
|
||||
m_tooltipManager = new ui::TooltipManager();
|
||||
root->addChild(m_tooltipManager);
|
||||
}
|
||||
m_tooltipManager->addTooltipFor(widget, tooltip, JI_LEFT);
|
||||
}
|
||||
|
||||
if (selected)
|
||||
widget->setSelected(selected);
|
||||
|
||||
if (disabled)
|
||||
widget->setEnabled(false);
|
||||
|
||||
if (expansive)
|
||||
widget->setExpansive(true);
|
||||
|
||||
if (magnet)
|
||||
widget->setFocusMagnet(true);
|
||||
|
||||
if (noborders)
|
||||
widget->noBorderNoChildSpacing();
|
||||
|
||||
if (childspacing)
|
||||
widget->child_spacing = strtol(childspacing, NULL, 10);
|
||||
|
||||
gfx::Size reqSize = widget->getPreferredSize();
|
||||
|
||||
if (minwidth || minheight) {
|
||||
int w = (minwidth ? jguiscale()*strtol(minwidth, NULL, 10): reqSize.w);
|
||||
int h = (minheight ? jguiscale()*strtol(minheight, NULL, 10): reqSize.h);
|
||||
widget->setMinSize(gfx::Size(w, h));
|
||||
}
|
||||
|
||||
if (maxwidth || maxheight) {
|
||||
int w = (maxwidth ? jguiscale()*strtol(maxwidth, NULL, 10): INT_MAX);
|
||||
int h = (maxheight ? jguiscale()*strtol(maxheight, NULL, 10): INT_MAX);
|
||||
widget->setMaxSize(gfx::Size(w, h));
|
||||
}
|
||||
|
||||
if (!root)
|
||||
root = widget;
|
||||
|
||||
// Children
|
||||
const TiXmlElement* childElem = elem->FirstChildElement();
|
||||
while (childElem) {
|
||||
child = convertXmlElementToWidget(childElem, root);
|
||||
if (child) {
|
||||
// Attach the child in the view
|
||||
if (widget->type == kViewWidget) {
|
||||
static_cast<View*>(widget)->attachToView(child);
|
||||
break;
|
||||
}
|
||||
// Add the child in the grid
|
||||
else if (widget->type == kGridWidget) {
|
||||
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);
|
||||
}
|
||||
// Just add the child in any other kind of widget
|
||||
else
|
||||
widget->addChild(child);
|
||||
}
|
||||
childElem = childElem->NextSiblingElement();
|
||||
}
|
||||
|
||||
if (widget->type == kViewWidget) {
|
||||
bool maxsize = bool_attr_is_true(elem, "maxsize");
|
||||
if (maxsize)
|
||||
static_cast<View*>(widget)->makeVisibleAllScrollableArea();
|
||||
}
|
||||
}
|
||||
if (widget)
|
||||
fillWidgetWithXmlElementAttributes(elem, root, widget);
|
||||
|
||||
return widget;
|
||||
}
|
||||
|
||||
void WidgetLoader::fillWidgetWithXmlElementAttributes(const TiXmlElement* elem, ui::Widget* root, ui::Widget* widget)
|
||||
{
|
||||
const char* id = elem->Attribute("id");
|
||||
const char* text = elem->Attribute("text");
|
||||
const char* tooltip = elem->Attribute("tooltip");
|
||||
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");
|
||||
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;
|
||||
}
|
||||
|
||||
if (id != NULL)
|
||||
widget->setId(id);
|
||||
|
||||
if (text)
|
||||
widget->setText(text);
|
||||
|
||||
if (tooltip != NULL && root != NULL) {
|
||||
if (!m_tooltipManager) {
|
||||
m_tooltipManager = new ui::TooltipManager();
|
||||
root->addChild(m_tooltipManager);
|
||||
}
|
||||
m_tooltipManager->addTooltipFor(widget, tooltip, JI_LEFT);
|
||||
}
|
||||
|
||||
if (selected)
|
||||
widget->setSelected(selected);
|
||||
|
||||
if (disabled)
|
||||
widget->setEnabled(false);
|
||||
|
||||
if (expansive)
|
||||
widget->setExpansive(true);
|
||||
|
||||
if (homogeneous)
|
||||
widget->setAlign(widget->getAlign() | JI_HOMOGENEOUS);
|
||||
|
||||
if (magnet)
|
||||
widget->setFocusMagnet(true);
|
||||
|
||||
if (noborders)
|
||||
widget->noBorderNoChildSpacing();
|
||||
|
||||
if (childspacing)
|
||||
widget->child_spacing = strtol(childspacing, NULL, 10);
|
||||
|
||||
gfx::Size reqSize = widget->getPreferredSize();
|
||||
|
||||
if (minwidth || minheight) {
|
||||
int w = (minwidth ? jguiscale()*strtol(minwidth, NULL, 10): reqSize.w);
|
||||
int h = (minheight ? jguiscale()*strtol(minheight, NULL, 10): reqSize.h);
|
||||
widget->setMinSize(gfx::Size(w, h));
|
||||
}
|
||||
|
||||
if (maxwidth || maxheight) {
|
||||
int w = (maxwidth ? jguiscale()*strtol(maxwidth, NULL, 10): INT_MAX);
|
||||
int h = (maxheight ? jguiscale()*strtol(maxheight, NULL, 10): INT_MAX);
|
||||
widget->setMaxSize(gfx::Size(w, h));
|
||||
}
|
||||
|
||||
if (!root)
|
||||
root = widget;
|
||||
|
||||
// Children
|
||||
const TiXmlElement* childElem = elem->FirstChildElement();
|
||||
while (childElem) {
|
||||
Widget* child = convertXmlElementToWidget(childElem, root, NULL);
|
||||
if (child) {
|
||||
// Attach the child in the view
|
||||
if (widget->type == kViewWidget) {
|
||||
static_cast<View*>(widget)->attachToView(child);
|
||||
break;
|
||||
}
|
||||
// Add the child in the grid
|
||||
else if (widget->type == kGridWidget) {
|
||||
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);
|
||||
}
|
||||
// Just add the child in any other kind of widget
|
||||
else
|
||||
widget->addChild(child);
|
||||
}
|
||||
childElem = childElem->NextSiblingElement();
|
||||
}
|
||||
|
||||
if (widget->type == kViewWidget) {
|
||||
bool maxsize = bool_attr_is_true(elem, "maxsize");
|
||||
if (maxsize)
|
||||
static_cast<View*>(widget)->makeVisibleAllScrollableArea();
|
||||
}
|
||||
}
|
||||
|
||||
static int convert_align_value_to_flags(const char *value)
|
||||
{
|
||||
char *tok, *ptr = base_strdup(value);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* Aseprite
|
||||
* Copyright (C) 2001-2013 David Capello
|
||||
* Copyright (C) 2001-2014 David Capello
|
||||
*
|
||||
* 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
|
||||
@ -56,13 +56,11 @@ namespace app {
|
||||
void addWidgetType(const char* tagName, IWidgetTypeCreator* creator);
|
||||
|
||||
// Loads the specified widget from an .xml file.
|
||||
ui::Widget* loadWidget(const char* fileName, const char* widgetId);
|
||||
ui::Widget* loadWidget(const char* fileName, const char* widgetId, ui::Widget* widget = NULL);
|
||||
|
||||
template<class T>
|
||||
T* loadWidgetT(const char* fileName, const char* widgetId) {
|
||||
ui::Widget* widget = loadWidget(fileName, widgetId);
|
||||
|
||||
T* specificWidget = dynamic_cast<T*>(widget);
|
||||
T* loadWidgetT(const char* fileName, const char* widgetId, T* widget = NULL) {
|
||||
T* specificWidget = dynamic_cast<T*>(loadWidget(fileName, widgetId, widget));
|
||||
if (!specificWidget)
|
||||
throw WidgetTypeMismatch(widgetId);
|
||||
|
||||
@ -70,9 +68,13 @@ namespace app {
|
||||
}
|
||||
|
||||
private:
|
||||
ui::Widget* loadWidgetFromXmlFile(const std::string& xmlFilename,
|
||||
const std::string& widgetId);
|
||||
ui::Widget* convertXmlElementToWidget(const TiXmlElement* elem, ui::Widget* root);
|
||||
ui::Widget* loadWidgetFromXmlFile(
|
||||
const std::string& xmlFilename,
|
||||
const std::string& widgetId,
|
||||
ui::Widget* widget);
|
||||
|
||||
ui::Widget* convertXmlElementToWidget(const TiXmlElement* elem, ui::Widget* root, ui::Widget* widget);
|
||||
void fillWidgetWithXmlElementAttributes(const TiXmlElement* elem, ui::Widget* root, ui::Widget* widget);
|
||||
|
||||
typedef std::map<std::string, IWidgetTypeCreator*> TypeCreatorsMap;
|
||||
|
||||
|
14
src/gen/CMakeLists.txt
Normal file
14
src/gen/CMakeLists.txt
Normal file
@ -0,0 +1,14 @@
|
||||
# Aseprite Code Generator
|
||||
# Copyright (C) 2014 David Capello
|
||||
|
||||
add_executable(gen
|
||||
gen.cpp
|
||||
ui_class.cpp)
|
||||
|
||||
target_link_libraries(gen base-lib)
|
||||
if(USE_SHARED_TINYXML)
|
||||
target_link_libraries(gen ${LIBTINYXML_LIBRARY})
|
||||
else()
|
||||
target_link_libraries(gen tinyxml)
|
||||
endif()
|
||||
|
20
src/gen/LICENSE.txt
Normal file
20
src/gen/LICENSE.txt
Normal file
@ -0,0 +1,20 @@
|
||||
Copyright (c) 2014 David Capello
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
23
src/gen/README.md
Normal file
23
src/gen/README.md
Normal file
@ -0,0 +1,23 @@
|
||||
# Aseprite Code Generator
|
||||
*Copyright (C) 2014 David Capello*
|
||||
|
||||
> Distributed under [MIT license](LICENSE.txt)
|
||||
|
||||
This utility generates source code from XML files. Its aim is to
|
||||
convert XML files (dynamic data) to C++ files (static structures) that
|
||||
can be checked in compile-time. There are three areas of interest:
|
||||
|
||||
1. To create `ui::Widget`s subclasses from
|
||||
[data/widgets/*.xml](../../data/widgets/)
|
||||
files. In this way we can create wrappers that can access to each
|
||||
XML file directly in a easier way (e.g. one member for each widget
|
||||
with an `id` parameter on it).
|
||||
2. To create configuration wrappers from a special
|
||||
`config-metadata.xml` file (so we can replace
|
||||
`get/set_config_int/bool/string()` function calls). There is an
|
||||
ongoing `cfg` module to replace the whole reading/writing
|
||||
operations of user's settings/preferences.
|
||||
3. To create a wrapper class for theme data access. From
|
||||
[data/skins/default/](../../data/skins/default/)
|
||||
we can create a C++ class with a member function to access
|
||||
each theme slice, color, style, etc.
|
50
src/gen/gen.cpp
Normal file
50
src/gen/gen.cpp
Normal file
@ -0,0 +1,50 @@
|
||||
// Aseprite Code Generator
|
||||
// Copyright (c) 2014 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
// Read LICENSE.txt for more information.
|
||||
|
||||
#include "base/file_handle.h"
|
||||
#include "base/path.h"
|
||||
#include "base/program_options.h"
|
||||
#include "base/string.h"
|
||||
#include "gen/ui_class.h"
|
||||
#include "tinyxml.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
typedef base::ProgramOptions PO;
|
||||
|
||||
static void run(int argc, const char* argv[])
|
||||
{
|
||||
PO po;
|
||||
PO::Option& inputFn = po.add("input").requiresValue("<filename>");
|
||||
PO::Option& widgetId = po.add("widgetid").requiresValue("<filename>");
|
||||
po.parse(argc, argv);
|
||||
|
||||
// Try to load the XML file
|
||||
TiXmlDocument* doc = NULL;
|
||||
|
||||
if (inputFn.enabled()) {
|
||||
base::FileHandle inputFile(base::open_file(inputFn.value(), "rb"));
|
||||
doc = new TiXmlDocument();
|
||||
doc->SetValue(inputFn.value().c_str());
|
||||
if (!doc->LoadFile(inputFile))
|
||||
throw std::runtime_error("invalid input file");
|
||||
}
|
||||
|
||||
if (doc && widgetId.enabled())
|
||||
gen_ui_class(doc, inputFn.value(), widgetId.value());
|
||||
}
|
||||
|
||||
int main(int argc, const char* argv[])
|
||||
{
|
||||
try {
|
||||
run(argc, argv);
|
||||
return 0;
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
std::cerr << e.what() << "\n";
|
||||
return 1;
|
||||
}
|
||||
}
|
176
src/gen/ui_class.cpp
Normal file
176
src/gen/ui_class.cpp
Normal file
@ -0,0 +1,176 @@
|
||||
// Aseprite Code Generator
|
||||
// Copyright (c) 2014 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
// Read LICENSE.txt for more information.
|
||||
|
||||
#include "base/exception.h"
|
||||
#include "base/file_handle.h"
|
||||
#include "base/path.h"
|
||||
#include "base/program_options.h"
|
||||
#include "base/string.h"
|
||||
#include "gen/ui_class.h"
|
||||
|
||||
#include <cctype>
|
||||
#include <iostream>
|
||||
|
||||
typedef base::ProgramOptions PO;
|
||||
typedef std::vector<TiXmlElement*> XmlElements;
|
||||
|
||||
static std::string convert_xmlid_to_cppid(const std::string& xmlid, bool firstLetterUpperCase)
|
||||
{
|
||||
bool firstLetter = firstLetterUpperCase;
|
||||
std::string cppid;
|
||||
for (size_t i=0; i<xmlid.size(); ++i) {
|
||||
if (xmlid[i] == '_') {
|
||||
firstLetter = true;
|
||||
}
|
||||
else if (firstLetter) {
|
||||
firstLetter = false;
|
||||
cppid += std::toupper(xmlid[i]);
|
||||
}
|
||||
else
|
||||
cppid += xmlid[i];
|
||||
}
|
||||
return cppid;
|
||||
}
|
||||
|
||||
static TiXmlElement* find_element_by_id(TiXmlElement* elem, const std::string& thisId)
|
||||
{
|
||||
const char* id = elem->Attribute("id");
|
||||
if (id && id == thisId)
|
||||
return elem;
|
||||
|
||||
TiXmlElement* child = elem->FirstChildElement();
|
||||
while (child) {
|
||||
TiXmlElement* match = find_element_by_id(child, thisId);
|
||||
if (match)
|
||||
return match;
|
||||
|
||||
child = child->NextSiblingElement();
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void collect_widgets_with_ids(TiXmlElement* elem, XmlElements& widgets)
|
||||
{
|
||||
TiXmlElement* child = elem->FirstChildElement();
|
||||
while (child) {
|
||||
const char* id = child->Attribute("id");
|
||||
if (id)
|
||||
widgets.push_back(child);
|
||||
collect_widgets_with_ids(child, widgets);
|
||||
child = child->NextSiblingElement();
|
||||
}
|
||||
}
|
||||
|
||||
static std::string convert_type(const std::string& name)
|
||||
{
|
||||
if (name == "box") return "ui::Box";
|
||||
if (name == "button") return "ui::Button";
|
||||
if (name == "check") return "ui::CheckBox";
|
||||
if (name == "combobox") return "ui::ComboBox";
|
||||
if (name == "entry") return "ui::Entry";
|
||||
if (name == "hbox") return "ui::HBox";
|
||||
if (name == "label") return "ui::Label";
|
||||
if (name == "listbox") return "ui::ListBox";
|
||||
if (name == "radio") return "ui::RadioButton";
|
||||
if (name == "slider") return "ui::Slider";
|
||||
if (name == "vbox") return "ui::VBox";
|
||||
if (name == "view") return "ui::View";
|
||||
if (name == "window") return "ui::Window";
|
||||
throw base::Exception("unknown widget name: " + name);
|
||||
}
|
||||
|
||||
void gen_ui_class(TiXmlDocument* doc, const std::string& inputFn, const std::string& widgetId)
|
||||
{
|
||||
std::cout
|
||||
<< "// Don't modify, generated file from " << inputFn << "\n"
|
||||
<< "\n";
|
||||
|
||||
TiXmlHandle handle(doc);
|
||||
TiXmlElement* elem = handle.FirstChild("gui").ToElement();
|
||||
elem = find_element_by_id(elem, widgetId);
|
||||
if (!elem) {
|
||||
std::cout << "#error Widget not found: " << widgetId << "\n";
|
||||
return;
|
||||
}
|
||||
|
||||
XmlElements widgets;
|
||||
collect_widgets_with_ids(elem, widgets);
|
||||
|
||||
std::string className = convert_xmlid_to_cppid(widgetId, true);
|
||||
std::string fnUpper = base::string_to_upper(base::get_file_title(inputFn));
|
||||
std::string widgetType = convert_type(elem->Value());
|
||||
|
||||
std::cout
|
||||
<< "#ifndef GENERATED_" << fnUpper << "_H_INCLUDED\n"
|
||||
<< "#define GENERATED_" << fnUpper << "_H_INCLUDED\n"
|
||||
<< "#pragma once\n"
|
||||
<< "\n"
|
||||
<< "#include \"app/find_widget.h\"\n"
|
||||
<< "#include \"app/load_widget.h\"\n"
|
||||
<< "#include \"ui/ui.h\"\n"
|
||||
<< "\n"
|
||||
<< "namespace app {\n"
|
||||
<< "namespace gen {\n"
|
||||
<< "\n"
|
||||
<< " class " << className << " : public " << widgetType << " {\n"
|
||||
<< " public:\n"
|
||||
<< " " << className << "()";
|
||||
|
||||
// Special ctor for base class
|
||||
if (widgetType == "ui::Window") {
|
||||
std::cout
|
||||
<< " : ui::Window(ui::Window::WithTitleBar)";
|
||||
}
|
||||
|
||||
std::cout
|
||||
<< " {\n"
|
||||
<< " app::load_widget(\"" << base::get_file_name(inputFn) << "\", \"" << widgetId << "\", this);\n"
|
||||
<< " app::finder(this)\n";
|
||||
|
||||
for (XmlElements::iterator it=widgets.begin(), end=widgets.end();
|
||||
it != end; ++it) {
|
||||
const char* id = (*it)->Attribute("id");
|
||||
std::string cppid = convert_xmlid_to_cppid(id, false);
|
||||
std::cout
|
||||
<< " >> \"" << id << "\" >> m_" << cppid << "\n";
|
||||
}
|
||||
|
||||
std::cout
|
||||
<< " ;\n"
|
||||
<< " }\n"
|
||||
<< "\n";
|
||||
|
||||
for (XmlElements::iterator it=widgets.begin(), end=widgets.end();
|
||||
it != end; ++it) {
|
||||
std::string childType = convert_type((*it)->Value());
|
||||
const char* id = (*it)->Attribute("id");
|
||||
std::string cppid = convert_xmlid_to_cppid(id, false);
|
||||
std::cout
|
||||
<< " " << childType << "* " << cppid << "() { return m_" << cppid << "; }\n";
|
||||
}
|
||||
|
||||
std::cout
|
||||
<< "\n"
|
||||
<< " private:\n";
|
||||
|
||||
for (XmlElements::iterator it=widgets.begin(), end=widgets.end();
|
||||
it != end; ++it) {
|
||||
std::string childType = convert_type((*it)->Value());
|
||||
const char* id = (*it)->Attribute("id");
|
||||
std::string cppid = convert_xmlid_to_cppid(id, false);
|
||||
std::cout
|
||||
<< " " << childType << "* m_" << cppid << ";\n";
|
||||
}
|
||||
|
||||
std::cout
|
||||
<< " };\n"
|
||||
<< "\n"
|
||||
<< "} // namespace gen\n"
|
||||
<< "} // namespace app\n"
|
||||
<< "\n"
|
||||
<< "#endif\n";
|
||||
}
|
16
src/gen/ui_class.h
Normal file
16
src/gen/ui_class.h
Normal file
@ -0,0 +1,16 @@
|
||||
// Aseprite Code Generator
|
||||
// Copyright (c) 2014 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
// Read LICENSE.txt for more information.
|
||||
|
||||
#ifndef GEN_UI_CLASS_H_INCLUDED
|
||||
#define GEN_UI_CLASS_H_INCLUDED
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include "tinyxml.h"
|
||||
|
||||
void gen_ui_class(TiXmlDocument* doc, const std::string& inputFn, const std::string& widgetId);
|
||||
|
||||
#endif
|
Loading…
x
Reference in New Issue
Block a user