1
0
forked from 0ad/0ad

JS GUI interface

This was SVN commit r666.
This commit is contained in:
Ykkrosh 2004-07-08 15:23:47 +00:00
parent a8f48ff7e0
commit af9c336b43
13 changed files with 1034 additions and 294 deletions

View File

@ -71,22 +71,48 @@ void CButton::HandleMessage(const SGUIMessage &Message)
break;
case GUIM_MOUSE_OVER:
ScriptEvent("MouseOver");
break;
case GUIM_MOUSE_ENTER:
ScriptEvent("MouseEnter");
break;
case GUIM_MOUSE_LEAVE:
ScriptEvent("MouseLeave");
break;
case GUIM_MOUSE_PRESS_LEFT:
ScriptEvent("MouseLeftPress");
break;
case GUIM_MOUSE_RELEASE_LEFT:
ScriptEvent("MouseLeftRelease");
break;
case GUIM_MOUSE_DOWN_LEFT:
ScriptEvent("MouseLeftDown");
break;
case GUIM_MOUSE_PRESS_RIGHT:
ScriptEvent("MouseRightPress");
break;
case GUIM_MOUSE_RELEASE_RIGHT:
ScriptEvent("MouseRightRelease");
break;
case GUIM_MOUSE_DOWN_RIGHT:
ScriptEvent("MouseRightDown");
break;
case GUIM_PRESSED:
GetGUI()->TEMPmessage = "Button " + string((const TCHAR*)m_Name) + " was pressed!";
ScriptEvent("Press");
break;
case GUIM_LOAD:
ScriptEvent("Load");
break;
default:

View File

@ -93,6 +93,8 @@ void CCheckBox::HandleMessage(const SGUIMessage &Message)
GUI<bool>::SetSetting(this, "checked", checked);
//GetGUI()->TEMPmessage = "Check box " + string((const TCHAR*)m_Name) + " was " + (m_Settings.m_Checked?"checked":"unchecked");
ScriptEvent("Press");
} break;
default:

View File

@ -5,7 +5,6 @@ gee@pyro.nu
*/
#include "precompiled.h"
#undef new // if it was redefined for leak detection, since xerces doesn't like it
#include "GUI.h"
@ -15,28 +14,35 @@ gee@pyro.nu
#include "CCheckBox.h"
#include "CRadioButton.h"
#include "XML.h"
//#include <xercesc/dom/DOM.hpp>
//#include <xercesc/parsers/XercesDOMParser.hpp>
//#include <xercesc/framework/LocalFileInputSource.hpp>
//#include <xercesc/util/XMLString.hpp>
//#include <xercesc/util/PlatformUtils.hpp>
#include "ps/Xeromyces.h"
#include "XercesErrorHandler.h"
#include "Prometheus.h"
#include "input.h"
#include "OverlayText.h"
// TODO Gee: Whatever include CRect/CPos/CSize
#include "Overlay.h"
#include "scripting/ScriptingHost.h"
#include <string>
#include <assert.h>
#include <stdarg.h>
// namespaces used
XERCES_CPP_NAMESPACE_USE
//XERCES_CPP_NAMESPACE_USE
using namespace std;
#include "sysdep/ia32.h"
#include "ps/CLogger.h"
#define XERO_TIME
// Class for global JavaScript object
JSClass GUIClass = {
"GUIClass", 0,
JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub,
};
extern int g_xres, g_yres;
@ -74,10 +80,12 @@ int CGUI::HandleEvent(const SDL_Event* ev)
// sprintf(buf, "type = %d", ev->type);
//TEMPmessage = buf;
// Update m_MouseButtons. (BUTTONUP is handled later.)
if (ev->type == SDL_MOUSEBUTTONDOWN)
{
// sprintf(buf, "button = %d", ev->button.button);
//TEMPmessage = buf;
// (0,1,2) = (LMB,RMB,MMB)
if (ev->button.button < 3)
m_MouseButtons |= (1 << ev->button.button);
}
// JW: (pre|post)process omitted; what're they for? why would we need any special button_released handling?
@ -191,17 +199,32 @@ int CGUI::HandleEvent(const SDL_Event* ev)
}
*/
// BUTTONUP's effect on m_MouseButtons is handled after
// everything else, so that e.g. 'press' handlers (activated
// on button up) see which mouse button had been pressed.
if (ev->type == SDL_MOUSEBUTTONUP)
{
// (0,1,2) = (LMB,RMB,MMB)
if (ev->button.button < 3)
m_MouseButtons &= ~(1 << ev->button.button);
}
return EV_PASS;
}
//-------------------------------------------------------------------
// Constructor / Destructor
//-------------------------------------------------------------------
CGUI::CGUI() : m_InternalNameNumber(0)
CGUI::CGUI() : m_InternalNameNumber(0), m_MouseButtons(0)
{
m_BaseObject = new CGUIDummyObject;
m_BaseObject->SetGUI(this);
// Construct the parent object for all GUI JavaScript things
m_ScriptObject = (void*)JS_NewObject(g_ScriptingHost.getContext(), &GUIClass, NULL, NULL);
assert(m_ScriptObject != NULL); // How should it handle errors?
JS_AddRoot(g_ScriptingHost.getContext(), &m_ScriptObject);
// This will make this invisible, not add
//m_BaseObject->SetName(BASE_OBJECT_NAME);
}
@ -210,6 +233,11 @@ CGUI::~CGUI()
{
if (m_BaseObject)
delete m_BaseObject;
if (m_ScriptObject)
// Let it be garbage-collected
JS_RemoveRoot(g_ScriptingHost.getContext(), &m_ScriptObject);
}
//-------------------------------------------------------------------
@ -307,6 +335,10 @@ void CGUI::Process()
void CGUI::Draw()
{
// Clear the depth buffer, so the GUI is
// drawn on top of everything else
glClear(GL_DEPTH_BUFFER_BIT);
glPushMatrix();
glLoadIdentity();
@ -462,6 +494,16 @@ bool CGUI::ObjectExists(const CStr& Name) const
return m_pAllObjects.count(Name) != 0;
}
IGUIObject* CGUI::FindObjectByName(const CStr& Name) const
{
map_pObjects::const_iterator it = m_pAllObjects.find(Name);
if (it == m_pAllObjects.end())
return NULL;
else
return it->second;
}
// private struct used only in GenerateText(...)
struct SGenerateTextImage
{
@ -804,199 +846,158 @@ void CGUI::LoadXMLFile(const string &Filename)
// we can later check if this has increased
m_Errors = 0;
// Initialize XML library
XMLPlatformUtils::Initialize();
CXeromyces XeroFile;
XeroFile.Load(Filename.c_str());
bool ParseFailed = false;
XMBElement node = XeroFile.getRoot();
// Check root element's (node) name so we know what kind of
// data we'll be expecting
std::wstring root_name = XeroFile.getElementString(node.getNodeName());
if (root_name == L"objects")
{
// Create parser instance
XercesDOMParser *parser = new XercesDOMParser();
Xeromyces_ReadRootObjects(node, &XeroFile);
bool ParseFailed = false;
if (parser)
{
// Setup parser
parser->setValidationScheme(XercesDOMParser::Val_Auto);
parser->setDoNamespaces(false);
parser->setDoSchema(false);
parser->setCreateEntityReferenceNodes(false);
// Set cosutomized error handler
CXercesErrorHandler *errorHandler = new CXercesErrorHandler();
parser->setErrorHandler(errorHandler);
/// g_nemLog("*** Xerces XML Parsing Errors");
// Get main node
XMLCh *fname=XMLString::transcode(Filename.c_str());
LocalFileInputSource source(fname);
XMLString::release(&fname);
// parse
parser->parse(source);
// Check how many errors
ParseFailed = parser->getErrorCount() != 0;
// Parse Failed?
if (!ParseFailed)
{
DOMDocument *doc = parser->getDocument();
DOMElement *node = doc->getDocumentElement();
// Check root element's (node) name so we know what kind of
// data we'll be expecting
CStr root_name = XMLTranscode( node->getNodeName() );
if (root_name == CStr("objects"))
{
Xerces_ReadRootObjects(node);
// Re-cache all values so these gets cached too.
//UpdateResolution();
}
else
if (root_name == CStr("sprites"))
{
Xerces_ReadRootSprites(node);
}
else
if (root_name == CStr("styles"))
{
Xerces_ReadRootStyles(node);
}
else
if (root_name == CStr("setup"))
{
Xerces_ReadRootSetup(node);
}
else
{
// TODO Gee: Output in log
}
}
}
// Now report if any other errors occured
if (m_Errors > 0)
{
/// g_console.submit("echo GUI Tree Creation Reports %d errors", m_Errors);
}
delete parser->getErrorHandler();
delete parser;
// Re-cache all values so these gets cached too.
//UpdateResolution();
}
XMLPlatformUtils::Terminate();
else
if (root_name == L"sprites")
{
Xeromyces_ReadRootSprites(node, &XeroFile);
}
else
if (root_name == L"styles")
{
Xeromyces_ReadRootStyles(node, &XeroFile);
}
else
if (root_name == L"setup")
{
Xeromyces_ReadRootSetup(node, &XeroFile);
}
else
{
// TODO Gee: Output in log
}
// Now report if any other errors occured
if (m_Errors > 0)
{
/// g_console.submit("echo GUI Tree Creation Reports %d errors", m_Errors);
}
}
//===================================================================
// XML Reading Xerces Specific Sub-Routines
// XML Reading Xeromyces Specific Sub-Routines
//===================================================================
void CGUI::Xerces_ReadRootObjects(DOMElement *pElement)
void CGUI::Xeromyces_ReadRootObjects(XMBElement Element, CXeromyces* pFile)
{
// Iterate main children
// they should all be <object> elements
DOMNodeList *children = pElement->getChildNodes();
for (u16 i=0; i<children->getLength(); ++i)
XMBElementList children = Element.getChildNodes();
for (int i=0; i<children.Count; ++i)
{
DOMNode *child = children->item(i);
//debug_out("Object %d\n", i);
XMBElement child = children.item(i);
if (child->getNodeType() == DOMNode::ELEMENT_NODE)
{
// Read in this whole object into the GUI
DOMElement *element = (DOMElement*)child;
Xerces_ReadObject(element, m_BaseObject);
}
// Read in this whole object into the GUI
Xeromyces_ReadObject(child, pFile, m_BaseObject);
}
}
void CGUI::Xerces_ReadRootSprites(DOMElement *pElement)
void CGUI::Xeromyces_ReadRootSprites(XMBElement Element, CXeromyces* pFile)
{
// Iterate main children
// they should all be <sprite> elements
DOMNodeList *children = pElement->getChildNodes();
for (u16 i=0; i<children->getLength(); ++i)
XMBElementList children = Element.getChildNodes();
for (int i=0; i<children.Count; ++i)
{
DOMNode *child = children->item(i);
XMBElement child = children.item(i);
if (child->getNodeType() == DOMNode::ELEMENT_NODE)
{
// Read in this whole object into the GUI
DOMElement *element = (DOMElement*)child;
Xerces_ReadSprite(element);
}
// Read in this whole object into the GUI
Xeromyces_ReadSprite(child, pFile);
}
}
void CGUI::Xerces_ReadRootStyles(DOMElement *pElement)
void CGUI::Xeromyces_ReadRootStyles(XMBElement Element, CXeromyces* pFile)
{
// Iterate main children
// they should all be <styles> elements
DOMNodeList *children = pElement->getChildNodes();
for (u16 i=0; i<children->getLength(); ++i)
XMBElementList children = Element.getChildNodes();
for (int i=0; i<children.Count; ++i)
{
DOMNode *child = children->item(i);
XMBElement child = children.item(i);
if (child->getNodeType() == DOMNode::ELEMENT_NODE)
{
// Read in this whole object into the GUI
DOMElement *element = (DOMElement*)child;
Xerces_ReadStyle(element);
}
// Read in this whole object into the GUI
Xeromyces_ReadStyle(child, pFile);
}
}
void CGUI::Xerces_ReadRootSetup(DOMElement *pElement)
void CGUI::Xeromyces_ReadRootSetup(XMBElement Element, CXeromyces* pFile)
{
// Iterate main children
// they should all be <icon>, <scrollbar> or <tooltip>.
DOMNodeList *children = pElement->getChildNodes();
for (u16 i=0; i<children->getLength(); ++i)
XMBElementList children = Element.getChildNodes();
for (int i=0; i<children.Count; ++i)
{
DOMNode *child = children->item(i);
XMBElement child = children.item(i);
if (child->getNodeType() == DOMNode::ELEMENT_NODE)
// Read in this whole object into the GUI
std::wstring name = pFile->getElementString(child.getNodeName());
if (name == L"scrollbar")
{
// Read in this whole object into the GUI
DOMElement *element = (DOMElement*)child;
CStr name = XMLTranscode( element->getNodeName() );
if (name == CStr("scrollbar"))
{
Xerces_ReadScrollBarStyle(element);
}
// No need for else, we're using DTD.
Xeromyces_ReadScrollBarStyle(child, pFile);
}
// No need for else, we're using DTD.
}
}
void CGUI::Xerces_ReadObject(DOMElement *pElement, IGUIObject *pParent)
void CGUI::Xeromyces_ReadObject(XMBElement Element, CXeromyces* pFile, IGUIObject *pParent)
{
assert(pParent && pElement);
u16 i;
assert(pParent);
int i;
// Our object we are going to create
IGUIObject *object = NULL;
XMBAttributeList attributes = Element.getAttributes();
// Well first of all we need to determine the type
CStr type = XMLTranscode( pElement->getAttribute( (XMLCh*)L"type" ) );
std::wstring type = attributes.getNamedItem( pFile->getAttributeID(L"type") );
// Construct object from specified type
// henceforth, we need to do a rollback before aborting.
// i.e. releasing this object
object = ConstructObject(type);
object = ConstructObject(tocstr(type));
if (!object)
{
// Report error that object was unsuccessfully loaded
ReportParseError(CStr("Unrecognized type: ") + type);
ReportParseError(CStr("Unrecognized type: ") + tocstr(type));
delete object;
return;
}
// Cache some IDs for element attribute names, to avoid string comparisons
#define ELMT(x) int elmt_##x = pFile->getElementID(L#x)
#define ATTR(x) int attr_##x = pFile->getAttributeID(L#x)
ELMT(object);
ELMT(action);
ATTR(style);
ATTR(type);
ATTR(name);
ATTR(z);
ATTR(on);
//
// Read Style and set defaults
//
@ -1004,7 +1005,7 @@ void CGUI::Xerces_ReadObject(DOMElement *pElement, IGUIObject *pParent)
//
// Always load default (if it's available) first!
//
CStr argStyle = XMLTranscode( pElement->getAttribute( (XMLCh*)L"style" ) );
CStr argStyle = tocstr(attributes.getNamedItem(attr_style));
if (m_Styles.count(CStr("default")) == 1)
object->LoadStyle(*this, CStr("default"));
@ -1028,41 +1029,38 @@ void CGUI::Xerces_ReadObject(DOMElement *pElement, IGUIObject *pParent)
bool ManuallySetZ = false; // if z has been manually set, this turn true
// Now we can iterate all attributes and store
DOMNamedNodeMap *attributes = pElement->getAttributes();
for (i=0; i<attributes->getLength(); ++i)
for (i=0; i<attributes.Count; ++i)
{
DOMAttr *attr = (DOMAttr*)attributes->item(i);
CStr attr_name = XMLTranscode( attr->getName() );
CStr attr_value = XMLTranscode( attr->getValue() );
XMBAttribute attr = attributes.item(i);
// If value is "null", then it is equivalent as never being entered
if (attr_value == CStr("null"))
if (attr.Value == L"null")
continue;
// Ignore "type" and "style", we've already checked it
if (attr_name == CStr("type") || attr_name == CStr("style") )
if (attr.Name == attr_type || attr.Name == attr_style )
continue;
// Also the name needs some special attention
if (attr_name == CStr("name"))
if (attr.Name == attr_name)
{
object->SetName(attr_value);
object->SetName(tocstr(attr.Value));
NameSet = true;
continue;
}
if (attr_name == CStr("z"))
if (attr.Name == attr_z)
ManuallySetZ = true;
// Try setting the value
try
{
object->SetSetting(attr_name, attr_value);
object->SetSetting(tocstr(pFile->getAttributeString(attr.Name)), tocstr(attr.Value));
}
catch (PS_RESULT e)
{
UNUSED(e);
ReportParseError(CStr("Can't set \"") + attr_name + CStr("\" to \"") + attr_value + CStr("\""));
ReportParseError(CStr("Can't set \"") + tocstr(pFile->getAttributeString(attr.Name)) + CStr("\" to \"") + tocstr(attr.Value) + CStr("\""));
// This is not a fatal error
}
@ -1075,63 +1073,50 @@ void CGUI::Xerces_ReadObject(DOMElement *pElement, IGUIObject *pParent)
++m_InternalNameNumber;
}
CStr caption = tocstr(Element.getText());
caption.Trim(PS_TRIM_BOTH);
if (caption.Length())
{
try
{
// Set the setting caption to this
object->SetSetting("caption", caption);
}
catch (...)
{
// There is no harm if the object didn't have a "caption"
}
}
//
// Read Children
//
// Iterate children
DOMNodeList *children = pElement->getChildNodes();
XMBElementList children = Element.getChildNodes();
for (i=0; i<children->getLength(); ++i)
for (i=0; i<children.Count; ++i)
{
// Get node
DOMNode *child = children->item(i);
XMBElement child = children.item(i);
// Check type (it's probably text or element)
// A child element
if (child->getNodeType() == DOMNode::ELEMENT_NODE)
// Check what name the elements got
int element_name = child.getNodeName();
if (element_name == elmt_object)
{
// Check what name the elements got
CStr element_name = XMLTranscode( child->getNodeName() );
// TODO Gee: REPORT ERROR
if (element_name == CStr("object"))
{
// First get element and not node
DOMElement *element = (DOMElement*)child;
// TODO Gee: REPORT ERROR
// Call this function on the child
Xerces_ReadObject(element, object);
}
// Call this function on the child
Xeromyces_ReadObject(child, pFile, object);
}
else
if (child->getNodeType() == DOMNode::TEXT_NODE)
else if (element_name == elmt_action)
{
CStr caption = XMLTranscode( child->getNodeValue() );
caption = caption.Trim(PS_TRIM_BOTH);
if (caption.Length())
{
// Text is only okay if it's the first element i.e. <object>caption ... </object>
if (i==0)
{
try
{
// Set the setting caption to this
object->SetSetting("caption", caption);
}
catch (...)
{
// There is no harm if the object didn't have a "caption"
}
}
else
debug_warn("Text is only okay if it's the first element i.e. <object>caption ... </object>");
}
CStr action = tocstr(child.getAttributes().getNamedItem(attr_on));
CStr code = tocstr(child.getText());
object->RegisterScriptHandler(action, code, this);
}
}
@ -1182,10 +1167,8 @@ void CGUI::Xerces_ReadObject(DOMElement *pElement, IGUIObject *pParent)
}
}
void CGUI::Xerces_ReadSprite(DOMElement *pElement)
void CGUI::Xeromyces_ReadSprite(XMBElement Element, CXeromyces* pFile)
{
assert(pElement);
// Sprite object we're adding
CGUISprite sprite;
@ -1197,33 +1180,24 @@ void CGUI::Xerces_ReadSprite(DOMElement *pElement)
//
// Get name, we know it exists because of DTD requirements
name = XMLTranscode( pElement->getAttribute( (XMLCh*)L"name" ) );
name = tocstr( Element.getAttributes().getNamedItem( pFile->getAttributeID(L"name") ) );
//
// Read Children (the images)
//
// Iterate children
DOMNodeList *children = pElement->getChildNodes();
XMBElementList children = Element.getChildNodes();
for (u16 i=0; i<children->getLength(); ++i)
for (int i=0; i<children.Count; ++i)
{
// Get node
DOMNode *child = children->item(i);
XMBElement child = children.item(i);
// Check type (it's probably text or element)
// A child element
if (child->getNodeType() == DOMNode::ELEMENT_NODE)
{
// All Elements will be of type "image" by DTD law
// All Elements will be of type "image" by DTD law
// First get element and not node
DOMElement *element = (DOMElement*)child;
// Call this function on the child
Xerces_ReadImage(element, sprite);
}
// Call this function on the child
Xeromyces_ReadImage(child, pFile, sprite);
}
//
@ -1233,9 +1207,8 @@ void CGUI::Xerces_ReadSprite(DOMElement *pElement)
m_Sprites[name] = sprite;
}
void CGUI::Xerces_ReadImage(DOMElement *pElement, CGUISprite &parent)
void CGUI::Xeromyces_ReadImage(XMBElement Element, CXeromyces* pFile, CGUISprite &parent)
{
assert(pElement);
// Image object we're adding
SGUIImage image;
@ -1247,20 +1220,20 @@ void CGUI::Xerces_ReadImage(DOMElement *pElement, CGUISprite &parent)
//
// Now we can iterate all attributes and store
DOMNamedNodeMap *attributes = pElement->getAttributes();
for (u16 i=0; i<attributes->getLength(); ++i)
XMBAttributeList attributes = Element.getAttributes();
for (int i=0; i<attributes.Count; ++i)
{
DOMAttr *attr = (DOMAttr*)attributes->item(i);
CStr attr_name = XMLTranscode( attr->getName() );
CStr attr_value(XMLTranscode( attr->getValue() ));
XMBAttribute attr = attributes.item(i);
std::wstring attr_name = pFile->getAttributeString(attr.Name);
CStr attr_value = tocstr( attr.Value );
// This is the only attribute we want
if (attr_name == CStr("texture"))
if (attr_name == L"texture")
{
image.m_Texture = attr_value;
}
else
if (attr_name == CStr("size"))
if (attr_name == L"size")
{
CClientArea ca;
if (!GUI<CClientArea>::ParseString(attr_value, ca))
@ -1270,7 +1243,7 @@ void CGUI::Xerces_ReadImage(DOMElement *pElement, CGUISprite &parent)
else image.m_Size = ca;
}
else
if (attr_name == CStr("z-level"))
if (attr_name == L"z-level")
{
int z_level;
if (!GUI<int>::ParseString(attr_value, z_level))
@ -1280,7 +1253,7 @@ void CGUI::Xerces_ReadImage(DOMElement *pElement, CGUISprite &parent)
else image.m_DeltaZ = (float)z_level/100.f;
}
else
if (attr_name == CStr("backcolor"))
if (attr_name == L"backcolor")
{
CColor color;
if (!GUI<CColor>::ParseString(attr_value, color))
@ -1304,10 +1277,8 @@ void CGUI::Xerces_ReadImage(DOMElement *pElement, CGUISprite &parent)
parent.AddImage(image);
}
void CGUI::Xerces_ReadStyle(DOMElement *pElement)
void CGUI::Xeromyces_ReadStyle(XMBElement Element, CXeromyces* pFile)
{
assert(pElement);
// style object we're adding
SGUIStyle style;
CStr name;
@ -1317,19 +1288,19 @@ void CGUI::Xerces_ReadStyle(DOMElement *pElement)
//
// Now we can iterate all attributes and store
DOMNamedNodeMap *attributes = pElement->getAttributes();
for (u16 i=0; i<attributes->getLength(); ++i)
XMBAttributeList attributes = Element.getAttributes();
for (int i=0; i<attributes.Count; ++i)
{
DOMAttr *attr = (DOMAttr*)attributes->item(i);
CStr attr_name = XMLTranscode( attr->getName() );
CStr attr_value = XMLTranscode( attr->getValue() );
XMBAttribute attr = attributes.item(i);
std::wstring attr_name = pFile->getAttributeString(attr.Name);
CStr attr_value = tocstr( attr.Value );
// The "name" setting is actually the name of the style
// and not a new default
if (attr_name == CStr("name"))
if (attr_name == L"name")
name = attr_value;
else
style.m_SettingsDefaults[attr_name] = attr_value;
style.m_SettingsDefaults[tocstr(attr_name)] = attr_value;
}
//
@ -1339,10 +1310,8 @@ void CGUI::Xerces_ReadStyle(DOMElement *pElement)
m_Styles[name] = style;
}
void CGUI::Xerces_ReadScrollBarStyle(DOMElement *pElement)
void CGUI::Xeromyces_ReadScrollBarStyle(XMBElement Element, CXeromyces* pFile)
{
assert(pElement);
// style object we're adding
SGUIScrollBarStyle scrollbar;
CStr name;
@ -1352,20 +1321,20 @@ void CGUI::Xerces_ReadScrollBarStyle(DOMElement *pElement)
//
// Now we can iterate all attributes and store
DOMNamedNodeMap *attributes = pElement->getAttributes();
for (u16 i=0; i<attributes->getLength(); ++i)
XMBAttributeList attributes = Element.getAttributes();
for (int i=0; i<attributes.Count; ++i)
{
DOMAttr *attr = (DOMAttr*)attributes->item(i);
CStr attr_name = XMLTranscode( attr->getName() );
CStr attr_value = XMLTranscode( attr->getValue() );
XMBAttribute attr = attributes.item(i);
std::wstring attr_name = pFile->getAttributeString(attr.Name);
CStr attr_value = tocstr( attr.Value );
if (attr_value == CStr("null"))
continue;
if (attr_name == CStr("name"))
if (attr_name == L"name")
name = attr_value;
else
if (attr_name == CStr("width"))
if (attr_name == L"width")
{
int i;
if (!GUI<int>::ParseString(attr_value, i))
@ -1375,7 +1344,7 @@ void CGUI::Xerces_ReadScrollBarStyle(DOMElement *pElement)
scrollbar.m_Width = i;
}
else
if (attr_name == CStr("minimum-bar-size"))
if (attr_name == L"minimum-bar-size")
{
int i;
if (!GUI<int>::ParseString(attr_value, i))
@ -1385,40 +1354,40 @@ void CGUI::Xerces_ReadScrollBarStyle(DOMElement *pElement)
scrollbar.m_MinimumBarSize = i;
}
else
if (attr_name == CStr("sprite-button-top"))
if (attr_name == L"sprite-button-top")
scrollbar.m_SpriteButtonTop = attr_value;
else
if (attr_name == CStr("sprite-button-top-pressed"))
if (attr_name == L"sprite-button-top-pressed")
scrollbar.m_SpriteButtonTopPressed = attr_value;
else
if (attr_name == CStr("sprite-button-top-disabled"))
if (attr_name == L"sprite-button-top-disabled")
scrollbar.m_SpriteButtonTopDisabled = attr_value;
else
if (attr_name == CStr("sprite-button-top-over"))
if (attr_name == L"sprite-button-top-over")
scrollbar.m_SpriteButtonTopOver = attr_value;
else
if (attr_name == CStr("sprite-button-bottom"))
if (attr_name == L"sprite-button-bottom")
scrollbar.m_SpriteButtonBottom = attr_value;
else
if (attr_name == CStr("sprite-button-bottom-pressed"))
if (attr_name == L"sprite-button-bottom-pressed")
scrollbar.m_SpriteButtonBottomPressed = attr_value;
else
if (attr_name == CStr("sprite-button-bottom-disabled"))
if (attr_name == L"sprite-button-bottom-disabled")
scrollbar.m_SpriteButtonBottomDisabled = attr_value;
else
if (attr_name == CStr("sprite-button-bottom-over"))
if (attr_name == L"sprite-button-bottom-over")
scrollbar.m_SpriteButtonBottomOver = attr_value;
else
if (attr_name == CStr("sprite-back-vertical"))
if (attr_name == L"sprite-back-vertical")
scrollbar.m_SpriteBackVertical = attr_value;
else
if (attr_name == CStr("sprite-bar-vertical"))
if (attr_name == L"sprite-bar-vertical")
scrollbar.m_SpriteBarVertical = attr_value;
else
if (attr_name == CStr("sprite-bar-vertical-over"))
if (attr_name == L"sprite-bar-vertical-over")
scrollbar.m_SpriteBarVerticalOver = attr_value;
else
if (attr_name == CStr("sprite-bar-vertical-pressed"))
if (attr_name == L"sprite-bar-vertical-pressed")
scrollbar.m_SpriteBarVerticalPressed = attr_value;
/*

View File

@ -21,15 +21,11 @@ gee@pyro.nu
// Includes / Compiler directives
//--------------------------------------------------------
#include "GUI.h"
#include "XML.h"
//#include <xercesc/dom/DOM.hpp>
//#include <xercesc/util/XMLString.hpp>
//#include <xercesc/util/PlatformUtils.hpp>
#include "Singleton.h"
#include "input.h" // JW: grr, classes suck in this case :P
class XERCES_CPP_NAMESPACE::DOMElement;
#include "Xeromyces.h"
extern int gui_handler(const SDL_Event* ev);
@ -153,6 +149,16 @@ public:
*/
bool ObjectExists(const CStr& Name) const;
/**
* Returns the GUI object with the desired name, or NULL
* if no match is found,
*
* @param Name String name of object
* @return Matching object, or NULL
*/
IGUIObject* FindObjectByName(const CStr& Name) const;
/**
* The GUI needs to have all object types inputted and
* their constructors. Also it needs to associate a type
@ -241,7 +247,7 @@ private:
IGUIObject *ConstructObject(const CStr& str);
//--------------------------------------------------------
/** @name XML Reading Xerces C++ specific subroutines
/** @name XML Reading Xeromyces specific subroutines
*
* These does not throw!
* Because when reading in XML files, it won't be fatal
@ -252,7 +258,7 @@ private:
//--------------------------------------------------------
/**
Xerces_* functions tree
Xeromyces_* functions tree
<code>
\<objects\> (ReadRootObjects)
|
@ -294,42 +300,46 @@ private:
/**
* Reads in the root element \<objects\> (the DOMElement).
*
* @param pElement The Xerces C++ Parser object that represents
* @param Element The Xeromyces object that represents
* the objects-tag.
* @param pFile The Xeromyces object for the file being read
*
* @see LoadXMLFile()
*/
void Xerces_ReadRootObjects(XERCES_CPP_NAMESPACE::DOMElement *pElement);
void Xeromyces_ReadRootObjects(XMBElement Element, CXeromyces* pFile);
/**
* Reads in the root element \<sprites\> (the DOMElement).
*
* @param pElement The Xerces C++ Parser object that represents
* @param Element The Xeromyces object that represents
* the sprites-tag.
* @param pFile The Xeromyces object for the file being read
*
* @see LoadXMLFile()
*/
void Xerces_ReadRootSprites(XERCES_CPP_NAMESPACE::DOMElement *pElement);
void Xeromyces_ReadRootSprites(XMBElement Element, CXeromyces* pFile);
/**
* Reads in the root element \<styles\> (the DOMElement).
*
* @param pElement The Xerces C++ Parser object that represents
* the sprites-tag.
* @param Element The Xeromyces object that represents
* the styles-tag.
* @param pFile The Xeromyces object for the file being read
*
* @see LoadXMLFile()
*/
void Xerces_ReadRootStyles(XERCES_CPP_NAMESPACE::DOMElement *pElement);
void Xeromyces_ReadRootStyles(XMBElement Element, CXeromyces* pFile);
/**
* Reads in the root element \<setup\> (the DOMElement).
*
* @param pElement The Xerces C++ Parser object that represents
* @param Element The Xeromyces object that represents
* the setup-tag.
* @param pFile The Xeromyces object for the file being read
*
* @see LoadXMLFile()
*/
void Xerces_ReadRootSetup(XERCES_CPP_NAMESPACE::DOMElement *pElement);
void Xeromyces_ReadRootSetup(XMBElement Element, CXeromyces* pFile);
// Read Subs
@ -346,61 +356,67 @@ private:
*
* Reads in the root element \<sprites\> (the DOMElement).
*
* @param pElement The Xerces C++ Parser object that represents
* @param Element The Xeromyces object that represents
* the object-tag.
* @param pFile The Xeromyces object for the file being read
* @param pParent Parent to add this object as child in.
*
* @see LoadXMLFile()
*/
void Xerces_ReadObject(XERCES_CPP_NAMESPACE::DOMElement *, IGUIObject *pParent);
void Xeromyces_ReadObject(XMBElement Element, CXeromyces* pFile, IGUIObject *pParent);
/**
* Reads in the element \<sprite\> (the DOMElement) and stores the
* result in a new CGUISprite.
*
* @param pElement The Xerces C++ Parser object that represents
* @param Element The Xeromyces object that represents
* the sprite-tag.
* @param pFile The Xeromyces object for the file being read
*
* @see LoadXMLFile()
*/
void Xerces_ReadSprite(XERCES_CPP_NAMESPACE::DOMElement *pElement);
void Xeromyces_ReadSprite(XMBElement Element, CXeromyces* pFile);
/**
* Reads in the element \<image\> (the DOMElement) and stores the
* result within the CGUISprite.
*
* @param pElement The Xerces C++ Parser object that represents
* @param Element The Xeromyces object that represents
* the image-tag.
* @param pFile The Xeromyces object for the file being read
* @param parent Parent sprite.
*
* @see LoadXMLFile()
*/
void Xerces_ReadImage(XERCES_CPP_NAMESPACE::DOMElement *pElement, CGUISprite &parent);
void Xeromyces_ReadImage(XMBElement Element, CXeromyces* pFile, CGUISprite &parent);
/**
* Reads in the element \<style\> (the DOMElement) and stores the
* result in m_Styles.
*
* @param pElement The Xerces C++ Parser object that represents
* the sprite-tag.
* @param Element The Xeromyces object that represents
* the style-tag.
* @param pFile The Xeromyces object for the file being read
*
* @see LoadXMLFile()
*/
void Xerces_ReadStyle(XERCES_CPP_NAMESPACE::DOMElement *pElement);
void Xeromyces_ReadStyle(XMBElement Element, CXeromyces* pFile);
/**
* Reads in the element \<scrollbar\> (the DOMElement) and stores the
* result in m_ScrollBarStyles.
*
* @param pElement The Xerces C++ Parser object that represents
* @param Element The Xeromyces object that represents
* the scrollbar-tag.
* @param pFile The Xeromyces object for the file being read
*
* @see LoadXMLFile()
*/
void Xerces_ReadScrollBarStyle(XERCES_CPP_NAMESPACE::DOMElement *pElement);
void Xeromyces_ReadScrollBarStyle(XMBElement Element, CXeromyces* pFile);
//@}
private:
// Variables
@ -410,6 +426,14 @@ private:
//--------------------------------------------------------
//@{
/**
* An JSObject* under which all GUI JavaScript things will
* be created, so that they can be garbage-collected
* when the GUI shuts down. (Stored as void* to avoid
* to avoid pulling in all the JS headers)
*/
void* m_ScriptObject;
/**
* don't want to pass this around with the
* ChooseMouseOverAndClosest broadcast -
@ -417,6 +441,12 @@ private:
*/
CPos m_MousePos;
/**
* Indicates which buttons are pressed (bit 0 = LMB,
* bit 1 = RMB, bit 2 = MMB)
*/
unsigned int m_MouseButtons;
/// Used when reading in XML files
// TODO Gee: Used?
int16_t m_Errors;

View File

@ -30,6 +30,8 @@ void CRadioButton::HandleMessage(const SGUIMessage &Message)
GUI<bool>::SetSetting(this, "checked", true);
//GetGUI()->TEMPmessage = "Check box " + string((const TCHAR*)m_Name) + " was " + (m_Settings.m_Checked?"checked":"unchecked");
ScriptEvent("Press");
break;
}

View File

@ -12,6 +12,9 @@ gee@pyro.nu
#include <assert.h>
/////
#include "gui/scripting/JSInterface_IGUIObject.h"
#include "gui/scripting/JSInterface_GUITypes.h"
extern int g_xres, g_yres;
using namespace std;
@ -245,6 +248,20 @@ void IGUIObject::SetSetting(const CStr& Setting, const CStr& Value)
}
}
PS_RESULT IGUIObject::GetSettingType(const CStr& Setting, EGUISettingType &Type) const
{
if (!SettingExists(Setting))
return PS_SETTING_FAIL;
if (m_Settings.find(Setting) == m_Settings.end())
return PS_FAIL;
Type = m_Settings.find(Setting)->second.m_Type;
return PS_OK;
}
void IGUIObject::ChooseMouseOverAndClosest(IGUIObject* &pObject)
{
if (MouseOver())
@ -375,3 +392,56 @@ void IGUIObject::CheckSettingsValidity()
{
}
}
void IGUIObject::RegisterScriptHandler(const CStr& Action, const CStr& Code, CGUI* pGUI)
{
const int paramCount = 1;
const char* paramNames[paramCount] = { "mouse" };
JSFunction* func = JS_CompileFunction(g_ScriptingHost.getContext(), (JSObject*)pGUI->m_ScriptObject, "", paramCount, paramNames, (const char*)Code, Code.Length(), "GUI script", 0);
m_ScriptHandlers[Action] = func;
}
void IGUIObject::ScriptEvent(const CStr& Action)
{
map<CStr, void*>::iterator it = m_ScriptHandlers.find(Action);
if (it == m_ScriptHandlers.end())
return;
// PRIVATE_TO_JSVAL assumes two-byte alignment,
// so make sure that's always true
assert(! ((jsval)this & JSVAL_INT));
// The IGUIObject needs to be stored inside the script's object
jsval guiObject = PRIVATE_TO_JSVAL(this);
// Make a 'this', allowing access to the IGUIObject
JSObject* jsGuiObject = JS_ConstructObjectWithArguments(g_ScriptingHost.getContext(), &JSI_IGUIObject::JSI_class, NULL, (JSObject*)m_pGUI->m_ScriptObject, 1, &guiObject);
// Prevent it from being garbage-collected before
// it's passed into the function
JS_AddRoot(g_ScriptingHost.getContext(), &jsGuiObject);
// Set up the 'mouse' parameter
jsval mouseParams[3];
mouseParams[0] = INT_TO_JSVAL(m_pGUI->m_MousePos.x);
mouseParams[1] = INT_TO_JSVAL(m_pGUI->m_MousePos.y);
mouseParams[2] = INT_TO_JSVAL(m_pGUI->m_MouseButtons);
JSObject* mouseObj = JS_ConstructObjectWithArguments(g_ScriptingHost.getContext(), &JSI_GUIMouse::JSI_class, NULL, (JSObject*)m_pGUI->m_ScriptObject, 3, mouseParams);
assert(mouseObj); // need better error handling
// Don't garbage collect the mouse
JS_AddRoot(g_ScriptingHost.getContext(), &mouseObj);
const int paramCount = 1;
jsval paramData[paramCount];
paramData[0] = OBJECT_TO_JSVAL(mouseObj);
jsval result;
JSBool ok = JS_CallFunction(g_ScriptingHost.getContext(), jsGuiObject, (JSFunction*)((*it).second), 1, paramData, &result);
// Allow the temporary parameters to be collected
JS_RemoveRoot(g_ScriptingHost.getContext(), &mouseObj);
JS_RemoveRoot(g_ScriptingHost.getContext(), &jsGuiObject);
}

View File

@ -35,6 +35,8 @@ gee@pyro.nu
#include <string>
#include <vector>
#include "gui/scripting/JSInterface_IGUIObject.h"
struct SGUISetting;
struct SGUIStyle;
class CGUI;
@ -132,10 +134,13 @@ class IGUIObject
friend class CInternalCGUIAccessorBase;
friend class IGUIScrollBar;
// Allow getProperty to access things like GetParent()
friend JSI_IGUIObject::getProperty(JSContext* cx, JSObject* obj, jsval id, jsval* vp);
public:
IGUIObject();
virtual ~IGUIObject();
/**
* Checks if mouse is hovering this object.
* The mouse position is cached in CGUI.
@ -255,6 +260,24 @@ public:
*/
void SetSetting(const CStr& Setting, const CStr& Value);
/**
* Retrieves the type of a named setting.
*
* @param Setting Setting by name
* @param Type Stores an EGUISettingType
* @return PS_RESULT (PS_OK if successful)
*/
PS_RESULT GetSettingType(const CStr& Setting, EGUISettingType &Type) const;
/**
* Set the script handler for a particular object-specific action
*
* @param Action Name of action
* @param Code Javascript code to execute when the action occurs
* @param pGUI GUI instance to associate the script with
*/
void RegisterScriptHandler(const CStr& Action, const CStr& Code, CGUI* pGUI);
//@}
protected:
//--------------------------------------------------------
@ -374,6 +397,19 @@ protected:
*/
CRect m_CachedActualSize;
/**
* Execute the script for a particular action.
* Does nothing if no script has been registered for that action.
*
* @param Action Name of action
*/
void ScriptEvent(const CStr& Action);
/**
* Internal storage for registered script handlers.
*/
std::map<CStr, void*> m_ScriptHandlers;
//@}
private:
//--------------------------------------------------------

View File

@ -0,0 +1,194 @@
// $Id: JSInterface_GUITypes.cpp,v 1.1 2004/07/08 15:19:45 philip Exp $
#include "precompiled.h"
#include "JSInterface_GUITypes.h"
/**** GUISize ****/
JSClass JSI_GUISize::JSI_class = {
"GUISize", 0,
JS_PropertyStub, JS_PropertyStub,
JS_PropertyStub, JS_PropertyStub,
JS_EnumerateStub, JS_ResolveStub,
JS_ConvertStub, JS_FinalizeStub,
NULL, NULL, NULL, NULL
};
JSPropertySpec JSI_GUISize::JSI_props[] =
{
{ "left", 0, JSPROP_ENUMERATE},
{ "top", 1, JSPROP_ENUMERATE},
{ "right", 2, JSPROP_ENUMERATE},
{ "bottom", 3, JSPROP_ENUMERATE},
{ 0 }
};
JSFunctionSpec JSI_GUISize::JSI_methods[] =
{
{ "toString", JSI_GUISize::toString, 0, 0, 0 },
{ 0 }
};
JSBool JSI_GUISize::construct(JSContext* cx, JSObject* obj, unsigned int argc, jsval* argv, jsval* rval)
{
if (argc == 4)
{
JS_SetProperty(cx, obj, "left", &argv[0]);
JS_SetProperty(cx, obj, "top", &argv[1]);
JS_SetProperty(cx, obj, "right", &argv[2]);
JS_SetProperty(cx, obj, "bottom", &argv[3]);
}
else
{
jsval zero = JSVAL_ZERO;
JS_SetProperty(cx, obj, "left", &zero);
JS_SetProperty(cx, obj, "top", &zero);
JS_SetProperty(cx, obj, "right", &zero);
JS_SetProperty(cx, obj, "bottom", &zero);
}
return JS_TRUE;
}
JSBool JSI_GUISize::toString(JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval)
{
char buffer[256];
snprintf(buffer, 256, "%i %i %i %i",
JSVAL_TO_INT(g_ScriptingHost.GetObjectProperty(obj, "left" )),
JSVAL_TO_INT(g_ScriptingHost.GetObjectProperty(obj, "top" )),
JSVAL_TO_INT(g_ScriptingHost.GetObjectProperty(obj, "right" )),
JSVAL_TO_INT(g_ScriptingHost.GetObjectProperty(obj, "bottom")) );
*rval = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, buffer));
return JS_TRUE;
}
/**** GUIColour ****/
JSClass JSI_GUIColour::JSI_class = {
"GUIColour", 0,
JS_PropertyStub, JS_PropertyStub,
JS_PropertyStub, JS_PropertyStub,
JS_EnumerateStub, JS_ResolveStub,
JS_ConvertStub, JS_FinalizeStub,
NULL, NULL, NULL, NULL
};
JSPropertySpec JSI_GUIColour::JSI_props[] =
{
{ "r", 0, JSPROP_ENUMERATE},
{ "g", 1, JSPROP_ENUMERATE},
{ "b", 2, JSPROP_ENUMERATE},
{ "a", 3, JSPROP_ENUMERATE},
{ 0 }
};
JSFunctionSpec JSI_GUIColour::JSI_methods[] =
{
{ "toString", JSI_GUIColour::toString, 0, 0, 0 },
{ 0 }
};
JSBool JSI_GUIColour::construct(JSContext* cx, JSObject* obj, unsigned int argc, jsval* argv, jsval* rval)
{
if (argc == 4)
{
JS_SetProperty(cx, obj, "r", &argv[0]);
JS_SetProperty(cx, obj, "g", &argv[1]);
JS_SetProperty(cx, obj, "b", &argv[2]);
JS_SetProperty(cx, obj, "a", &argv[3]);
}
else
{
// Nice magenta:
jsval r = DOUBLE_TO_JSVAL(JS_NewDouble(cx, 1.0));
jsval g = DOUBLE_TO_JSVAL(JS_NewDouble(cx, 0.0));
jsval b = DOUBLE_TO_JSVAL(JS_NewDouble(cx, 1.0));
jsval a = DOUBLE_TO_JSVAL(JS_NewDouble(cx, 1.0));
JS_SetProperty(cx, obj, "r", &r);
JS_SetProperty(cx, obj, "g", &g);
JS_SetProperty(cx, obj, "b", &b);
JS_SetProperty(cx, obj, "a", &a);
}
return JS_TRUE;
}
JSBool JSI_GUIColour::toString(JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval)
{
char buffer[256];
// Convert to integers, to be compatible with the GUI's string SetSetting
snprintf(buffer, 256, "%i %i %i %i",
(int)( 255.0 * *JSVAL_TO_DOUBLE(g_ScriptingHost.GetObjectProperty(obj, "r")) ),
(int)( 255.0 * *JSVAL_TO_DOUBLE(g_ScriptingHost.GetObjectProperty(obj, "g")) ),
(int)( 255.0 * *JSVAL_TO_DOUBLE(g_ScriptingHost.GetObjectProperty(obj, "b")) ),
(int)( 255.0 * *JSVAL_TO_DOUBLE(g_ScriptingHost.GetObjectProperty(obj, "a")) ));
*rval = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, buffer));
return JS_TRUE;
}
/**** GUIMouse ****/
JSClass JSI_GUIMouse::JSI_class = {
"GUIMouse", 0,
JS_PropertyStub, JS_PropertyStub,
JS_PropertyStub, JS_PropertyStub,
JS_EnumerateStub, JS_ResolveStub,
JS_ConvertStub, JS_FinalizeStub,
NULL, NULL, NULL, NULL
};
JSPropertySpec JSI_GUIMouse::JSI_props[] =
{
{ "x", 0, JSPROP_ENUMERATE},
{ "y", 1, JSPROP_ENUMERATE},
{ "buttons", 2, JSPROP_ENUMERATE},
{ 0 }
};
JSFunctionSpec JSI_GUIMouse::JSI_methods[] =
{
{ "toString", JSI_GUIMouse::toString, 0, 0, 0 },
{ 0 }
};
JSBool JSI_GUIMouse::construct(JSContext* cx, JSObject* obj, unsigned int argc, jsval* argv, jsval* rval)
{
if (argc == 3)
{
JS_SetProperty(cx, obj, "x", &argv[0]);
JS_SetProperty(cx, obj, "y", &argv[1]);
JS_SetProperty(cx, obj, "buttons", &argv[2]);
}
else
{
jsval zero = JSVAL_ZERO;
JS_SetProperty(cx, obj, "x", &zero);
JS_SetProperty(cx, obj, "y", &zero);
JS_SetProperty(cx, obj, "buttons", &zero);
}
return JS_TRUE;
}
JSBool JSI_GUIMouse::toString(JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval)
{
char buffer[256];
snprintf(buffer, 256, "%i %i %i",
JSVAL_TO_INT(g_ScriptingHost.GetObjectProperty(obj, "x")),
JSVAL_TO_INT(g_ScriptingHost.GetObjectProperty(obj, "y")),
JSVAL_TO_INT(g_ScriptingHost.GetObjectProperty(obj, "buttons")) );
*rval = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, buffer));
return JS_TRUE;
}
// Initialise all the types at once:
void JSI_GUITypes::init()
{
g_ScriptingHost.DefineCustomObjectType(&JSI_GUISize::JSI_class, JSI_GUISize::construct, 1, JSI_GUISize::JSI_props, JSI_GUISize::JSI_methods, NULL, NULL);
g_ScriptingHost.DefineCustomObjectType(&JSI_GUIColour::JSI_class, JSI_GUIColour::construct, 1, JSI_GUIColour::JSI_props, JSI_GUIColour::JSI_methods, NULL, NULL);
g_ScriptingHost.DefineCustomObjectType(&JSI_GUIMouse::JSI_class, JSI_GUIMouse::construct, 1, JSI_GUIMouse::JSI_props, JSI_GUIMouse::JSI_methods, NULL, NULL);
}

View File

@ -0,0 +1,30 @@
// $Id: JSInterface_GUITypes.h,v 1.1 2004/07/08 15:19:45 philip Exp $
#include "scripting/ScriptingHost.h"
#ifndef JSI_GUITYPES_INCLUDED
#define JSI_GUITYPES_INCLUDED
#define GUISTDTYPE(x) \
namespace JSI_GUI##x \
{ \
extern JSClass JSI_class; \
extern JSPropertySpec JSI_props[]; \
extern JSFunctionSpec JSI_methods[]; \
JSBool construct( JSContext* cx, JSObject* obj, unsigned int argc, jsval* argv, jsval* rval ); \
JSBool getByName( JSContext* cx, JSObject* obj, unsigned int argc, jsval* argv, jsval* rval ); \
JSBool toString( JSContext* cx, JSObject* obj, unsigned int argc, jsval* argv, jsval* rval ); \
}
GUISTDTYPE(Size)
GUISTDTYPE(Colour)
GUISTDTYPE(Mouse)
#undef GUISTDTYPE // avoid unnecessary pollution
namespace JSI_GUITypes
{
void init();
}
#endif

View File

@ -0,0 +1,355 @@
// $Id: JSInterface_IGUIObject.cpp,v 1.1 2004/07/08 15:19:45 philip Exp $
#include "precompiled.h"
#include "JSInterface_IGUIObject.h"
#include "JSInterface_GUITypes.h"
JSClass JSI_IGUIObject::JSI_class = {
"GUIObject", JSCLASS_HAS_PRIVATE,
JS_PropertyStub, JS_PropertyStub,
JSI_IGUIObject::getProperty, JSI_IGUIObject::setProperty,
JS_EnumerateStub, JS_ResolveStub,
JS_ConvertStub, JS_FinalizeStub,
NULL, NULL, NULL, NULL
};
JSPropertySpec JSI_IGUIObject::JSI_props[] =
{
{ 0 }
};
JSFunctionSpec JSI_IGUIObject::JSI_methods[] =
{
{ "toString", JSI_IGUIObject::toString, 0, 0, 0 },
{ "getByName", JSI_IGUIObject::getByName, 1, 0, 0 },
{ 0 }
};
JSBool JSI_IGUIObject::getProperty(JSContext* cx, JSObject* obj, jsval id, jsval* vp)
{
CStr propName = JS_GetStringBytes(JS_ValueToString(cx, id));
// Skip some things which are known to be functions rather than properties.
// ("constructor" *must* be here, else it'll try to GetSettingType before
// the private IGUIObject* has been set (and thus crash). The others are
// just for efficiency.)
if (propName == (CStr)"constructor" ||
propName == (CStr)"toString" ||
propName == (CStr)"getByName"
)
return JS_TRUE;
IGUIObject* e = (IGUIObject*)JS_GetPrivate(cx, obj);
// Handle the "parent" property specially
if (propName == (CStr)"parent")
{
IGUIObject* parent = e->GetParent();
if (parent)
{
// If the object isn't parentless, return a new object
JSObject* entity = JS_NewObject(cx, &JSI_IGUIObject::JSI_class, NULL, NULL);
JS_SetPrivate(cx, entity, parent);
*vp = OBJECT_TO_JSVAL(entity);
}
else
{
// Return null if there's no parent
*vp = JSVAL_VOID;
}
return JS_TRUE;
}
// Also handle "name" specially
else if (propName == (CStr)"name")
{
*vp = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, e->GetName()));
return JS_TRUE;
}
else
{
EGUISettingType Type;
if (e->GetSettingType(propName, Type) != PS_OK)
{
// Possibly a function, but they should have been individually
// handled above, so complain about it
JS_ReportError(cx, "Invalid setting '%s'", propName.c_str());
return JS_TRUE;
}
// (All the cases are in {...} to avoid scoping problems)
switch (Type)
{
case GUIST_bool:
{
bool value;
GUI<bool>::GetSetting(e, propName, value);
*vp = value ? JSVAL_TRUE : JSVAL_FALSE;
break;
}
case GUIST_int:
{
int value;
GUI<int>::GetSetting(e, propName, value);
*vp = INT_TO_JSVAL(value);
break;
}
case GUIST_float:
{
float value;
GUI<float>::GetSetting(e, propName, value);
// Create a garbage-collectable double
*vp = DOUBLE_TO_JSVAL(JS_NewDouble(cx, value) );
break;
}
case GUIST_CColor:
{
CColor colour;
GUI<CColor>::GetSetting(e, propName, colour);
JSObject* obj = JS_NewObject(cx, &JSI_GUIColour::JSI_class, NULL, NULL);
jsval r = DOUBLE_TO_JSVAL(JS_NewDouble(cx, colour.r));
jsval g = DOUBLE_TO_JSVAL(JS_NewDouble(cx, colour.g));
jsval b = DOUBLE_TO_JSVAL(JS_NewDouble(cx, colour.b));
jsval a = DOUBLE_TO_JSVAL(JS_NewDouble(cx, colour.a));
JS_SetProperty(cx, obj, "r", &r);
JS_SetProperty(cx, obj, "g", &g);
JS_SetProperty(cx, obj, "b", &b);
JS_SetProperty(cx, obj, "a", &a);
*vp = OBJECT_TO_JSVAL(obj);
break;
}
case GUIST_CClientArea:
{
CClientArea area;
GUI<CClientArea>::GetSetting(e, propName, area);
CRect size = area.pixel;
JSObject* obj = JS_NewObject(cx, &JSI_GUISize::JSI_class, NULL, NULL);
jsval left = INT_TO_JSVAL(size.left);
jsval top = INT_TO_JSVAL(size.top);
jsval right = INT_TO_JSVAL(size.right);
jsval bottom = INT_TO_JSVAL(size.bottom);
JS_SetProperty(cx, obj, "left", &left);
JS_SetProperty(cx, obj, "top", &top);
JS_SetProperty(cx, obj, "right", &right);
JS_SetProperty(cx, obj, "bottom", &bottom);
*vp = OBJECT_TO_JSVAL(obj);
break;
}
case GUIST_CGUIString:
{
CGUIString value;
GUI<CGUIString>::GetSetting(e, propName, value);
// Create a garbage-collectable copy of the string
*vp = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, value.GetRawString().c_str() ));
break;
}
case GUIST_CStr:
{
CStr value;
GUI<CStr>::GetSetting(e, propName, value);
// Create a garbage-collectable copy of the string
*vp = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, value.c_str() ));
break;
}
default:
JS_ReportError(cx, "Setting '%s' uses an unimplemented type", propName.c_str());
*vp = JSVAL_NULL;
break;
}
return JS_TRUE;
}
// Automatically falls through to methods
return JS_TRUE;
}
JSBool JSI_IGUIObject::setProperty(JSContext* cx, JSObject* obj, jsval id, jsval* vp)
{
IGUIObject* e = (IGUIObject*)JS_GetPrivate(cx, obj);
CStr propName = g_ScriptingHost.ValueToString(id);
if (propName == (CStr)"name")
{
CStr propValue = JS_GetStringBytes(JS_ValueToString(cx, *vp));
e->SetName(propValue);
}
else
{
EGUISettingType Type;
if (e->GetSettingType(propName, Type) != PS_OK)
{
JS_ReportError(cx, "Invalid setting '%s'", propName.c_str());
return JS_TRUE;
}
try
{
switch (Type)
{
case GUIST_CStr:
case GUIST_CGUIString:
e->SetSetting(propName, JS_GetStringBytes(JS_ValueToString(cx, *vp)) );
break;
case GUIST_int:
{
int32 value;
if (JS_ValueToInt32(cx, *vp, &value) == JS_TRUE)
GUI<int>::SetSetting(e, propName, value);
else
JS_ReportError(cx, "Cannot convert value to int");
break;
}
case GUIST_float:
{
jsdouble value;
if (JS_ValueToNumber(cx, *vp, &value) == JS_TRUE)
GUI<float>::SetSetting(e, propName, (float)value);
else
JS_ReportError(cx, "Cannot convert value to float");
break;
}
case GUIST_bool:
{
JSBool value;
if (JS_ValueToBoolean(cx, *vp, &value) == JS_TRUE)
GUI<bool>::SetSetting(e, propName, value||0); // ||0 to avoid int-to-bool compiler warnings
else
JS_ReportError(cx, "Cannot convert value to bool");
break;
}
case GUIST_CClientArea:
{
if (JSVAL_IS_STRING(*vp))
{
e->SetSetting(propName, JS_GetStringBytes(JS_ValueToString(cx, *vp)) );
}
else if (JSVAL_IS_OBJECT(*vp) && JS_GetClass(JSVAL_TO_OBJECT(*vp)) == &JSI_GUISize::JSI_class)
{
CClientArea area;
GUI<CClientArea>::GetSetting(e, propName, area);
JSObject* obj = JSVAL_TO_OBJECT(*vp);
jsval t; int32 s;
#define PROP(x) JS_GetProperty(cx, obj, #x, &t); \
JS_ValueToInt32(cx, t, &s); \
area.pixel.##x = s
PROP(left); PROP(top); PROP(right); PROP(bottom);
#undef PROP
GUI<CClientArea>::SetSetting(e, propName, area);
}
else
{
JS_ReportError(cx, "Size only accepts strings or GUISize objects");
}
break;
}
case GUIST_CColor:
{
if (JSVAL_IS_STRING(*vp))
{
e->SetSetting(propName, JS_GetStringBytes(JS_ValueToString(cx, *vp)) );
}
else if (JSVAL_IS_OBJECT(*vp) && JS_GetClass(JSVAL_TO_OBJECT(*vp)) == &JSI_GUIColour::JSI_class)
{
CColor colour;
JSObject* obj = JSVAL_TO_OBJECT(*vp);
jsval t; double s;
#define PROP(x) JS_GetProperty(cx, obj, #x, &t); \
JS_ValueToNumber(cx, t, &s); \
colour.##x = (float)s
PROP(r); PROP(g); PROP(b); PROP(a);
#undef PROP
GUI<CColor>::SetSetting(e, propName, colour);
}
else
{
JS_ReportError(cx, "Color only accepts strings or GUIColour objects");
}
break;
}
default:
JS_ReportError(cx, "Setting '%s' uses an unimplemented type", propName.c_str());
break;
}
}
catch (PS_RESULT)
{
JS_ReportError(cx, "Invalid value for setting '%s'", propName.c_str());
return JS_TRUE;
}
}
return JS_TRUE;
}
JSBool JSI_IGUIObject::construct(JSContext* cx, JSObject* obj, unsigned int argc, jsval* argv, jsval* rval)
{
if (argc == 0)
{
JS_ReportError(cx, "GUIObject has no default constructor");
return JS_FALSE;
}
assert(argc == 1);
// Store the IGUIObject in the JS object's 'private' area
IGUIObject* guiObject = (IGUIObject*)JSVAL_TO_PRIVATE(argv[0]);
JS_SetPrivate(cx, obj, guiObject);
return JS_TRUE;
}
JSBool JSI_IGUIObject::getByName(JSContext* cx, JSObject* obj, unsigned int argc, jsval* argv, jsval* rval)
{
assert(argc == 1);
CStr objectName = JS_GetStringBytes(JS_ValueToString(cx, argv[0]));
IGUIObject* guiObject = g_GUI.FindObjectByName(objectName);
if (!guiObject)
{
// Not found - return null
*rval = JSVAL_NULL;
return JS_TRUE;
}
JSObject* entity = JS_NewObject(cx, &JSI_IGUIObject::JSI_class, NULL, NULL);
JS_SetPrivate(cx, entity, guiObject);
*rval = OBJECT_TO_JSVAL(entity);
return JS_TRUE;
}
void JSI_IGUIObject::init()
{
g_ScriptingHost.DefineCustomObjectType(&JSI_class, construct, 1, JSI_props, JSI_methods, NULL, NULL);
}
JSBool JSI_IGUIObject::toString(JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval)
{
IGUIObject* e = (IGUIObject*)JS_GetPrivate( cx, obj );
char buffer[256];
snprintf(buffer, 256, "[GUIObject: %s]", (const TCHAR*)e->GetName());
buffer[255] = 0;
*rval = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, buffer));
return JS_TRUE;
}

View File

@ -0,0 +1,25 @@
// $Id: JSInterface_IGUIObject.h,v 1.1 2004/07/08 15:19:45 philip Exp $
#include "scripting/ScriptingHost.h"
#include "gui/GUI.h"
#ifndef JSI_IGUIOBJECT_INCLUDED
#define JSI_IGUIOBJECT_INCLUDED
namespace JSI_IGUIObject
{
extern JSClass JSI_class;
extern JSPropertySpec JSI_props[];
extern JSFunctionSpec JSI_methods[];
JSBool addProperty(JSContext* cx, JSObject* obj, jsval id, jsval* vp);
JSBool delProperty(JSContext* cx, JSObject* obj, jsval id, jsval* vp);
JSBool getProperty(JSContext* cx, JSObject* obj, jsval id, jsval* vp);
JSBool setProperty(JSContext* cx, JSObject* obj, jsval id, jsval* vp);
JSBool construct(JSContext* cx, JSObject* obj, unsigned int argc, jsval* argv, jsval* rval);
JSBool getByName(JSContext* cx, JSObject* obj, unsigned int argc, jsval* argv, jsval* rval);
JSBool toString(JSContext* cx, JSObject* obj, unsigned int argc, jsval* argv, jsval* rval);
void init();
void x();
}
#endif

View File

@ -10,7 +10,7 @@
#include "scripting/JSInterface_Entity.h"
#include "scripting/JSInterface_BaseEntity.h"
#include "scripting/JSInterface_Vector3D.h"
//#include "gui/scripting/JSInterface_IGUIObject.h"
#include "gui/scripting/JSInterface_IGUIObject.h"
extern CConsole* g_Console;
@ -28,7 +28,7 @@ JSFunctionSpec ScriptFunctionTable[] =
{"writeConsole", writeConsole, 1, 0, 0 },
{"getEntityByHandle", getEntityByHandle, 1, 0, 0 },
{"getEntityTemplate", getEntityTemplate, 1, 0, 0 },
// {"getGUIObjectByName", JSI_IGUIObject::getByName, 1, 0, 0 },
{"getGUIObjectByName", JSI_IGUIObject::getByName, 1, 0, 0 },
{"getGlobal", getGlobal, 0, 0, 0 },
{0, 0, 0, 0, 0},
};

View File

@ -44,6 +44,7 @@ package.files = {
-- gui/
{ sourcesfromdirs(
"../../gui") },
{ sourcesfromdirs( "../../gui/scripting" ) },
-- terrain/
{ sourcesfromdirs(
"../../terrain") },