1
1
forked from 0ad/0ad

Atlas: Ported terrain texture selection panel to JS. Removed textual labels on each texture.

wxJS: Added incomplete wxNotebook. Added wxWindow.toolTip.

This was SVN commit r5174.
This commit is contained in:
Ykkrosh 2007-06-14 12:11:22 +00:00
parent e0884bb539
commit 047b1ca21d
21 changed files with 967 additions and 84 deletions

View File

@ -11,17 +11,21 @@ function getScriptFilename(name)
* Loads and executes a script from disk. The script runs in a separate scope,
* so variables and functions declared in it will not be visible outside that file.
*/
function loadScript(name, window)
function loadScript(name /*, ...*/)
{
var filename = getScriptFilename(name);
var file = new wxFFile(filename.fullPath);
var script = file.readAll(); // TODO: handle errors
file.close();
var script = Atlas.LoadScript(name+'.js', script);
scriptReloader.add(name, window, filename);
var args = [];
for (var i = 1; i < arguments.length; ++i)
args.push(arguments[i])
script.init(window); // TODO: use a variable list of arguments
var script = Atlas.LoadScript(name+'.js', script);
scriptReloader.add(name, args, filename);
script.init.apply(null, args);
return script;
}
@ -67,19 +71,22 @@ var scriptReloader = {
}
else
{
script.window.destroyChildren();
loadScript(script.name, script.window);
script.window.layout();
// TODO: know which arguments are really windows that should be regenerated
for each (var window in script.args)
window.destroyChildren();
loadScript.apply(null, [script.name].concat(script.args));
for each (var window in script.args)
window.layout();
}
}
}
},
add: function (name, window, filename)
add: function (name, args, filename)
{
for each (var script in this.scripts)
if (script.name == name)
return; // stop if this is already loaded
this.scripts.push({ name:name, window:window, filename:filename, mtime:filename.modificationTime });
this.scripts.push({ name:name, args:args, filename:filename, mtime:filename.modificationTime });
}
};
scriptReloader.timer.onNotify = scriptReloader.notify;

View File

@ -55,7 +55,53 @@ var brush = {
}
};
function init(window)
function TerrainPreviewPage(panel, name)
{
this.panel = panel;
this.name = name;
}
TerrainPreviewPage.prototype = {
display: function() {
if (this.loaded)
return;
this.panel.sizer = new wxBoxSizer(wxOrientation.VERTICAL);
var list = new wxListCtrl(this.panel, -1, wxDefaultPosition, wxDefaultSize, wxListCtrl.ICON | wxListCtrl.SINGLE_SEL);
this.panel.sizer.add(list, 1, wxStretch.EXPAND);
var w = 80, h = 40;
var imglist = new wxImageList(w, h, false, 0);
var previews = Atlas.Message.GetTerrainGroupPreviews(this.name, w, h).previews;
var i = 0;
var names = [];
for each (var p in previews)
{
imglist.add(p.imagedata);
list.insertItem(i, '', i);
names.push(p.name);
++i;
}
list.onMotion = function(evt) {
var hit = list.hitTest(evt.position);
var tip = undefined;
if (hit.item != -1 && (hit.flags & wxListHitTest.ONITEMICON))
tip = names[hit.item]
if (list.toolTip !== tip)
list.toolTip = tip;
};
list.onItemSelected = function(evt) {
Atlas.SetSelectedTexture(names[evt.index]);
};
list.setImageList(imglist, wxListCtrl.NORMAL);
this.loaded = true;
}
};
function init(window, bottomWindow)
{
window.sizer = new wxBoxSizer(wxOrientation.VERTICAL);
@ -91,8 +137,10 @@ function init(window)
}
else
{
// Disable the old tool
if (selectedTool)
selectedTool[2].backgroundColour = wxSystemSettings.getColour(wxSystemSettings.COLOUR_BTNFACE);
// Enable the new one
selectedTool = tool;
this.backgroundColour = new wxColour(0xEE, 0xCC, 0x55);
Atlas.SetCurrentTool(tool[1]);
@ -139,4 +187,22 @@ function init(window)
brush.strength = evt.position / 10;
brush.send();
};
var terrainGroups = Atlas.Message.GetTerrainGroups();
var nb = new wxNotebook(bottomWindow, -1);
bottomWindow.sizer = new wxBoxSizer(wxOrientation.VERTICAL);
bottomWindow.sizer.add(nb, 1, wxStretch.EXPAND);
var pages = [];
nb.onPageChanged = function (evt) {
pages[evt.selection].display()
}
for each (var groupname in terrainGroups.groupnames)
{
var panel = new wxPanel(nb, -1);
var page = new TerrainPreviewPage(panel, groupname);
pages.push(page);
nb.addPage(panel, groupname); // TODO: use Titlecase letters
}
}

View File

@ -15,14 +15,11 @@
#include "wxJS/io/init.h"
#include "wxJS/gui/init.h"
#include "wxJS/gui/control/panel.h"
#include "wxJS/gui/misc/bitmap.h"
#include "GameInterface/Shareable.h"
#include "GameInterface/Messages.h"
// We want to include Messages.h again below, with some different definitions,
// so cheat and undefine its include-guard
#undef INCLUDED_MESSAGES
#include <boost/preprocessor/punctuation/comma_if.hpp>
#include <boost/preprocessor/repetition/repeat.hpp>
@ -88,7 +85,9 @@ namespace
{
static bool Convert(JSContext* cx, jsval v, std::wstring& out)
{
JSString* ret = JS_ValueToString(cx, v); // never returns NULL
JSString* ret = JS_ValueToString(cx, v);
if (! ret)
FAIL("Argument must be convertible to a string");
jschar* ch = JS_GetStringChars(ret);
out = std::wstring(ch, ch+JS_GetStringLength(ret));
return true;
@ -99,7 +98,9 @@ namespace
{
static bool Convert(JSContext* cx, jsval v, std::string& out)
{
JSString* ret = JS_ValueToString(cx, v); // never returns NULL
JSString* ret = JS_ValueToString(cx, v);
if (! ret)
FAIL("Argument must be convertible to a string");
char* ch = JS_GetStringBytes(ret);
out = std::string(ch);
return true;
@ -110,7 +111,9 @@ namespace
{
static bool Convert(JSContext* cx, jsval v, wxString& out)
{
JSString* ret = JS_ValueToString(cx, v); // never returns NULL
JSString* ret = JS_ValueToString(cx, v);
if (! ret)
FAIL("Argument must be convertible to a string");
jschar* ch = JS_GetStringChars(ret);
out = wxString((const char*)ch, wxMBConvUTF16(), JS_GetStringLength(ret)*2);
return true;
@ -127,6 +130,7 @@ namespace
jsuint length;
if (! JS_GetArrayLength(cx, obj, &length))
FAIL("Failed to get array length");
out.reserve(length);
for (jsint i = 0; i < length; ++i)
{
jsval el;
@ -140,32 +144,40 @@ namespace
return true;
}
};
}
template<typename T> bool ScriptInterface::FromJSVal(JSContext* cx, jsval v, T& out)
{
return ::FromJSVal<T>::Convert(cx, v, out);
}
////////////////////////////////////////////////////////////////
// Explicit instantiation of functions that would otherwise be unused in this file
// but are required for linking with other files
template bool ScriptInterface::FromJSVal<wxString>(JSContext*, jsval, wxString&);
template<typename T> struct ToJSVal
{
static jsval Convert(JSContext* cx, const T& val)
{
JS_ReportError(cx, "Unrecognised query return type");
return JSVAL_VOID;
}
};
template<> jsval ScriptInterface::ToJSVal<float>(JSContext* cx, const float& val)
{
/*template<> struct ToJSVal<float>
{
static jsval Convert(JSContext* cx, const float& val)
{
jsval rval = JSVAL_VOID;
JS_NewDoubleValue(cx, val, &rval); // ignore return value
return rval;
}
}
};*/
template<> jsval ScriptInterface::ToJSVal<int>(JSContext* WXUNUSED(cx), const int& val)
{
template<> struct ToJSVal<int>
{
static jsval Convert(JSContext* WXUNUSED(cx), const int& val)
{
return INT_TO_JSVAL(val);
}
}
};
template<> jsval ScriptInterface::ToJSVal<wxString>(JSContext* cx, const wxString& val)
{
template<> struct ToJSVal<wxString>
{
static jsval Convert(JSContext* cx, const wxString& val)
{
wxMBConvUTF16 conv;
size_t length;
wxCharBuffer utf16 = conv.cWC2MB(val.c_str(), val.length()+1, &length);
@ -174,8 +186,89 @@ template<> jsval ScriptInterface::ToJSVal<wxString>(JSContext* cx, const wxStrin
return STRING_TO_JSVAL(str);
else
return JSVAL_VOID;
}
};
template<> struct ToJSVal<std::wstring>
{
static jsval Convert(JSContext* cx, const std::wstring& val)
{
wxMBConvUTF16 conv;
size_t length;
wxCharBuffer utf16 = conv.cWC2MB(val.c_str(), val.length()+1, &length);
JSString* str = JS_NewUCStringCopyN(cx, reinterpret_cast<jschar*>(utf16.data()), length/2);
if (str)
return STRING_TO_JSVAL(str);
else
return JSVAL_VOID;
}
};
template<typename T> struct ToJSVal<std::vector<T> >
{
static jsval Convert(JSContext* cx, const std::vector<T>& val)
{
JSObject* obj = JS_NewArrayObject(cx, 0, NULL);
if (! obj) return JSVAL_VOID;
JS_AddRoot(cx, &obj);
for (size_t i = 0; i < val.size(); ++i)
{
jsval el = ToJSVal<T>::Convert(cx, val[i]);
JS_SetElement(cx, obj, i, &el);
}
JS_RemoveRoot(cx, &obj);
return OBJECT_TO_JSVAL(obj);
}
};
template<typename T> struct ToJSVal<AtlasMessage::Shareable<T> >
{
static jsval Convert(JSContext* cx, const AtlasMessage::Shareable<T>& val)
{
return ToJSVal<T>::Convert(cx, val._Unwrap());
}
};
////////////////////////////////////////////////////////////////
template<> struct ToJSVal<AtlasMessage::sTerrainGroupPreview>
{
static jsval Convert(JSContext* cx, const AtlasMessage::sTerrainGroupPreview& val)
{
JSObject* obj = JS_NewObject(cx, NULL, NULL, NULL);
if (! obj) return JSVAL_VOID;
JS_AddRoot(cx, &obj);
JS_DefineProperty(cx, obj, "name", ToJSVal<std::wstring>::Convert(cx, *val.name), NULL, NULL, JSPROP_ENUMERATE);
unsigned char* buf = (unsigned char*)(malloc(val.imagedata.GetSize()));
memcpy(buf, val.imagedata.GetBuffer(), val.imagedata.GetSize());
jsval bmp = wxjs::gui::Bitmap::CreateObject(cx, new wxBitmap (wxImage(val.imagewidth, val.imageheight, buf)));
JS_DefineProperty(cx, obj, "imagedata", bmp, NULL, NULL, JSPROP_ENUMERATE);
JS_RemoveRoot(cx, &obj);
return OBJECT_TO_JSVAL(obj);
}
};
}
template<typename T> bool ScriptInterface::FromJSVal(JSContext* cx, jsval v, T& out)
{
return ::FromJSVal<T>::Convert(cx, v, out);
}
template<typename T> jsval ScriptInterface::ToJSVal(JSContext* cx, const T& v)
{
return ::ToJSVal<T>::Convert(cx, v);
}
// Explicit instantiation of functions that would otherwise be unused in this file
// but are required for linking with other files
template bool ScriptInterface::FromJSVal<wxString>(JSContext*, jsval, wxString&);
////////////////////////////////////////////////////////////////
struct ScriptInterface_impl
@ -358,32 +451,91 @@ wxPanel* ScriptInterface::LoadScriptAsPanel(const wxString& name, wxWindow* pare
return panel;
}
// TODO: this is an ugly function to provide
std::pair<wxPanel*, wxPanel*> ScriptInterface::LoadScriptAsSidebar(const wxString& name, wxWindow* side, wxWindow* bottom)
{
wxPanel* sidePanel = new wxPanel(side, -1);
JSObject* jsSideWindow = JSVAL_TO_OBJECT(wxjs::gui::Panel::CreateObject(m->m_cx, sidePanel));
sidePanel->SetClientObject(new wxjs::JavaScriptClientData(m->m_cx, jsSideWindow, true, false));
wxPanel* bottomPanel = new wxPanel(bottom, -1);
JSObject* jsBottomWindow = JSVAL_TO_OBJECT(wxjs::gui::Panel::CreateObject(m->m_cx, bottomPanel));
bottomPanel->SetClientObject(new wxjs::JavaScriptClientData(m->m_cx, jsBottomWindow, true, false));
jsval jsName = ToJSVal(m->m_cx, name);
const uintN argc = 3;
jsval argv[argc] = { jsName, OBJECT_TO_JSVAL(jsSideWindow), OBJECT_TO_JSVAL(jsBottomWindow) };
jsval rval;
JS_CallFunctionName(m->m_cx, m->m_glob, "loadScript", argc, argv, &rval); // TODO: error checking
// TODO: This really need a better way to handle these two windows (of which one is optional)...
if (bottomPanel->GetChildren().size() != 0)
return std::make_pair(sidePanel, bottomPanel);
else
{
bottomPanel->Destroy();
return std::make_pair(sidePanel, static_cast<wxPanel*>(NULL));
}
}
////////////////////////////////////////////////////////////////
struct MessageWrapper
{
#define NUMBERED_LIST(z, i, data) , data##i
#define NUMBERED_LIST2(z, i, data) BOOST_PP_COMMA_IF(i) data##i
#define CONVERT_ARGS(z, i, data) T##i a##i; if (! ScriptInterface::FromJSVal<T##i>(cx, argv[i], a##i)) return JS_FALSE;
#define OVERLOADS(z, i, data) \
template <typename Message BOOST_PP_REPEAT_##z (i, NUMBERED_LIST, typename T) > \
static JSNative call(Message* (*WXUNUSED(fptr)) ( BOOST_PP_REPEAT_##z(i, NUMBERED_LIST2, T) )) { \
return &_call<Message BOOST_PP_REPEAT_##z(i, NUMBERED_LIST, T) >; \
} \
template <typename Message BOOST_PP_REPEAT_##z (i, NUMBERED_LIST, typename T) > \
static uintN nargs(Message* (*WXUNUSED(fptr)) ( BOOST_PP_REPEAT_##z(i, NUMBERED_LIST2, T) )) { \
return i; \
} \
template <typename Message BOOST_PP_REPEAT_##z (i, NUMBERED_LIST, typename T) > \
static JSBool _call(JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* WXUNUSED(rval)) \
#define TYPE(elem) BOOST_PP_TUPLE_ELEM(2, 0, elem)
#define NAME(elem) BOOST_PP_TUPLE_ELEM(2, 1, elem)
#define MAKE_STR_(s) #s
#define MAKE_STR(s) MAKE_STR_(s)
#define CONVERT_ARGS(r, data, i, elem) \
TYPE(elem) a##i; \
if (! ScriptInterface::FromJSVal< TYPE(elem) >(cx, argv[i], a##i)) \
return JS_FALSE;
#define CONVERT_OUTPUTS(r, data, i, elem) \
JS_DefineProperty(cx, ret, MAKE_STR(NAME(elem)), ScriptInterface::ToJSVal(cx, q.NAME(elem)), \
NULL, NULL, JSPROP_ENUMERATE);
#define ARG_LIST(r, data, i, elem) BOOST_PP_COMMA_IF(i) a##i
#define MESSAGE(name, vals) \
JSBool call_##name(JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* WXUNUSED(rval)) \
{ \
(void)cx; (void)obj; (void)argc; (void)argv; /* avoid 'unused parameter' warnings */ \
BOOST_PP_REPEAT_##z (i, CONVERT_ARGS, ~) \
AtlasMessage::g_MessagePasser->Add(SHAREABLE_NEW(Message, ( BOOST_PP_REPEAT_##z(i, NUMBERED_LIST2, a) ))); \
BOOST_PP_SEQ_FOR_EACH_I(CONVERT_ARGS, ~, vals) \
g_MessagePasser->Add(SHAREABLE_NEW(m##name, ( BOOST_PP_SEQ_FOR_EACH_I(ARG_LIST, ~, vals) ))); \
return JS_TRUE; \
}
BOOST_PP_REPEAT(7, OVERLOADS, ~)
};
#define QUERY(name, in_vals, out_vals) \
JSBool call_##name(JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval) \
{ \
BOOST_PP_SEQ_FOR_EACH_I(CONVERT_ARGS, ~, in_vals) \
q##name q = q##name( BOOST_PP_SEQ_FOR_EACH_I(ARG_LIST, ~, in_vals) ); \
q.Post(); \
JSObject* ret = JS_NewObject(cx, NULL, NULL, NULL); \
if (! ret) return JS_FALSE; \
*rval = OBJECT_TO_JSVAL(ret); \
BOOST_PP_SEQ_FOR_EACH_I(CONVERT_OUTPUTS, ~, out_vals) \
return JS_TRUE; \
}
#define COMMAND(name, merge, vals)
#define MESSAGES_SKIP_SETUP
#define MESSAGES_SKIP_STRUCTS
// We want to include Messages.h again, with some different definitions,
// so cheat and undefine its include-guard
#undef INCLUDED_MESSAGES
namespace
{
using namespace AtlasMessage;
#include "GameInterface/Messages.h"
}
#undef MESSAGE
#undef QUERY
void ScriptInterface_impl::RegisterMessages(JSObject* parent)
{
@ -392,20 +544,17 @@ void ScriptInterface_impl::RegisterMessages(JSObject* parent)
JSFunction* ret;
JSObject* obj = JS_DefineObject(m_cx, parent, "Message", NULL, NULL, JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT);
#define MESSAGE(name, vals) \
ret = JS_DefineFunction(m_cx, obj, #name, MessageWrapper::call(&m##name::CtorType), MessageWrapper::nargs(&m##name::CtorType), JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT);
#define MESSAGE(name, vals) \
ret = JS_DefineFunction(m_cx, obj, #name, call_##name, BOOST_PP_SEQ_SIZE((~)vals)-1, \
JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT);
#define QUERY(name, in_vals, out_vals) /* TODO \
extern void f##name##_wrapper(AtlasMessage::IMessage*); \
AtlasMessage::GetMsgHandlers().insert(std::pair<std::string, AtlasMessage::msgHandler>(#name, &f##name##_wrapper));*/
#define QUERY(name, in_vals, out_vals) \
ret = JS_DefineFunction(m_cx, obj, #name, call_##name, BOOST_PP_SEQ_SIZE((~)in_vals)-1, \
JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT);
#define COMMAND(name, merge, vals) /* TODO \
extern cmdHandler c##name##_create(); \
GetCmdHandlers().insert(std::pair<std::string, cmdHandler>("c"#name, c##name##_create()));*/
// TODO: #define COMMAND(name, merge, vals) ...
#undef SHAREABLE_STRUCT
#define SHAREABLE_STRUCT(name)
#undef INCLUDED_MESSAGES
#define MESSAGES_SKIP_SETUP
#include "GameInterface/Messages.h"
}

View File

@ -35,6 +35,7 @@ public:
void LoadScript(const wxString& filename, const wxString& code);
wxPanel* LoadScriptAsPanel(const wxString& name, wxWindow* parent);
std::pair<wxPanel*, wxPanel*> LoadScriptAsSidebar(const wxString& name, wxWindow* side, wxWindow* bottom);
template <typename T> static bool FromJSVal(JSContext* cx, jsval val, T& ret);
template <typename T> static jsval ToJSVal(JSContext* cx, const T& val);

View File

@ -24,6 +24,7 @@
#include "Tools/Common/Tools.h"
#include "Tools/Common/Brushes.h"
#include "Tools/Common/MiscState.h"
static HighResTimer g_Timer;
@ -276,6 +277,10 @@ namespace
{
g_Brush_Elevation.SetStrength(strength);
}
void SetSelectedTexture(wxString name)
{
g_SelectedTexture = name;
}
}
ScenarioEditor::ScenarioEditor(wxWindow* parent, ScriptInterface& scriptInterface)
@ -299,6 +304,7 @@ ScenarioEditor::ScenarioEditor(wxWindow* parent, ScriptInterface& scriptInterfac
GetScriptInterface().RegisterFunction<wxString, Datafile::GetDataDirectory>("GetDataDirectory");
GetScriptInterface().RegisterFunction<void, wxString, SetCurrentTool_script>("SetCurrentTool");
GetScriptInterface().RegisterFunction<void, float, SetBrushStrength>("SetBrushStrength");
GetScriptInterface().RegisterFunction<void, wxString, SetSelectedTexture>("SetSelectedTexture");
{
const wxString relativePath (_T("tools/atlas/scripts/main.js"));

View File

@ -232,11 +232,19 @@ class ScriptedSidebar : public Sidebar
{
public:
ScriptedSidebar(const wxString& name, ScenarioEditor& scenarioEditor, wxWindow* sidebarContainer, wxWindow* bottomBarContainer)
: Sidebar(scenarioEditor, sidebarContainer, bottomBarContainer)
: Sidebar(scenarioEditor, sidebarContainer, bottomBarContainer), m_BottomBarContainer(bottomBarContainer), m_Name(name)
{
wxPanel* panel = m_ScenarioEditor.GetScriptInterface().LoadScriptAsPanel(_T("section/") + name, this);
m_MainSizer->Add(panel, wxSizerFlags(1).Expand());
}
virtual void OnFirstDisplay()
{
std::pair<wxPanel*, wxPanel*> panels = m_ScenarioEditor.GetScriptInterface().LoadScriptAsSidebar(_T("section/") + m_Name, this, m_BottomBarContainer);
m_MainSizer->Add(panels.first, wxSizerFlags(1).Expand());
m_BottomBar = panels.second;
}
private:
wxString m_Name;
wxWindow* m_BottomBarContainer;
};
@ -288,7 +296,7 @@ void SectionLayout::Build(ScenarioEditor& scenarioEditor)
ADD_SIDEBAR_SCRIPT(_T("map"), _T("map.png"), _("Map"));
ADD_SIDEBAR_SCRIPT(_T("terrain"), _T("terrain.png"), _("Terrain"));
ADD_SIDEBAR(TerrainSidebar, _T("terrain.png"), _("Terrain"));
//ADD_SIDEBAR(TerrainSidebar, _T("terrain.png"), _("Terrain"));
ADD_SIDEBAR(ObjectSidebar, _T("object.png"), _("Object"));
ADD_SIDEBAR(EnvironmentSidebar, _T("environment.png"), _("Environment"));

View File

@ -66,7 +66,7 @@ void Brush::SetData(int w, int h, const std::vector<float>& data)
m_Data = data;
debug_assert(data.size() == w*h);
debug_assert(data.size() == (size_t)(w*h));
}
void Brush::GetCentre(int& x, int& y) const

View File

@ -88,6 +88,8 @@ QUERYHANDLER(GetTerrainGroupPreviews)
delete[] texdata;
}
previews.back().imagewidth = msg->imagewidth;
previews.back().imageheight = msg->imageheight;
previews.back().imagedata = buf;
}

View File

@ -99,11 +99,13 @@ MESSAGE(Screenshot,
((int, tiles)) // the final image will be (640*tiles)x(480*tiles)
);
#ifndef MESSAGES_SKIP_STRUCTS
struct sCinemaRecordCB
{
unsigned char* buffer;
};
SHAREABLE_STRUCT(sCinemaRecordCB);
#endif
QUERY(CinemaRecord,
((std::wstring, path))
@ -136,12 +138,16 @@ QUERY(GetTerrainGroups,
((std::vector<std::wstring>, groupnames))
);
#ifndef MESSAGES_SKIP_STRUCTS
struct sTerrainGroupPreview
{
Shareable<std::wstring> name;
Shareable<std::vector<unsigned char> > imagedata; // RGB*size*size
Shareable<int> imagewidth;
Shareable<int> imageheight;
Shareable<std::vector<unsigned char> > imagedata; // RGB*width*height
};
SHAREABLE_STRUCT(sTerrainGroupPreview);
#endif
QUERY(GetTerrainGroupPreviews,
((std::wstring, groupname))
@ -154,6 +160,7 @@ QUERY(GetTerrainGroupPreviews,
//////////////////////////////////////////////////////////////////////////
#ifndef MESSAGES_SKIP_STRUCTS
struct sObjectsListItem
{
Shareable<std::wstring> id;
@ -161,12 +168,14 @@ struct sObjectsListItem
Shareable<int> type; // 0 = entity, 1 = actor
};
SHAREABLE_STRUCT(sObjectsListItem);
#endif
QUERY(GetObjectsList,
, // no inputs
((std::vector<sObjectsListItem>, objects)) // sorted by .name
);
#ifndef MESSAGES_SKIP_STRUCTS
struct sObjectSettings
{
Shareable<int> player;
@ -178,6 +187,7 @@ struct sObjectSettings
Shareable<std::vector<std::vector<std::wstring> > > variantgroups;
};
SHAREABLE_STRUCT(sObjectSettings);
#endif
// Preview object in the game world - creates a temporary unit at the given
// position, and removes it when the preview is next changed
@ -249,6 +259,7 @@ MESSAGE(LookAt,
//////////////////////////////////////////////////////////////////////////
#ifndef MESSAGES_SKIP_STRUCTS
struct sEnvironmentSettings
{
Shareable<float> waterheight; // range 0..1 corresponds to min..max terrain height; out-of-bounds values allowed
@ -276,6 +287,7 @@ struct sEnvironmentSettings
Shareable<Colour> unitcolour;
};
SHAREABLE_STRUCT(sEnvironmentSettings);
#endif
QUERY(GetEnvironmentSettings,
// no inputs

View File

@ -151,6 +151,7 @@ const bool NOMERGE = false;
#define QUERY_WITHOUT_INPUTS(name, in_vals, out_vals) \
QUERYSTRUCT(name) \
q##name() {} \
static q##name* CtorType() { return NULL; } \
BOOST_PP_SEQ_FOR_EACH_I(B_MEMBERS, ~, out_vals) /* other members */ \
}
@ -158,6 +159,7 @@ const bool NOMERGE = false;
QUERYSTRUCT(name) \
q##name( BOOST_PP_SEQ_FOR_EACH_I(B_CONSTRUCTORARGS, ~, in_vals) ) \
: BOOST_PP_SEQ_FOR_EACH_I(B_CONSTRUCTORINIT, ~, in_vals) {} \
static q##name* CtorType( BOOST_PP_SEQ_FOR_EACH_I(B_CONSTRUCTORTYPES, ~, in_vals) ) { return NULL; } \
BOOST_PP_SEQ_FOR_EACH_I(B_CONSTMEMBERS, ~, in_vals) \
BOOST_PP_SEQ_FOR_EACH_I(B_MEMBERS, ~, out_vals) \
}

View File

@ -273,6 +273,7 @@ public:
// (TODO - this is probably not really safely shareable, due to unspecified calling conventions)
template<typename T> struct Callback
{
Callback() : cb(NULL), cbdata(NULL) {}
Callback(void (*cb) (const T*, void*), void* cbdata) : cb(cb), cbdata(cbdata) {}
void (*cb) (const T*, void*);
void* cbdata;

View File

@ -0,0 +1,119 @@
#include "precompiled.h"
#ifndef WX_PRECOMP
#include <wx/wx.h>
#endif
#include "../../common/main.h"
#include "bookctrl.h"
#include "window.h"
using namespace wxjs;
using namespace wxjs::gui;
WXJS_INIT_CLASS(BookCtrlBase, "wxBookCtrlBase", 0)
WXJS_BEGIN_CONSTANT_MAP(BookCtrlBase)
WXJS_CONSTANT(wxBK_, HITTEST_NOWHERE)
WXJS_CONSTANT(wxBK_, HITTEST_ONICON)
WXJS_CONSTANT(wxBK_, HITTEST_ONLABEL)
WXJS_CONSTANT(wxBK_, HITTEST_ONITEM)
WXJS_CONSTANT(wxBK_, HITTEST_ONPAGE)
WXJS_CONSTANT(wxBK_, DEFAULT)
WXJS_CONSTANT(wxBK_, TOP)
WXJS_CONSTANT(wxBK_, BOTTOM)
WXJS_CONSTANT(wxBK_, LEFT)
WXJS_CONSTANT(wxBK_, RIGHT)
WXJS_END_CONSTANT_MAP()
WXJS_BEGIN_PROPERTY_MAP(BookCtrlBase)
WXJS_READONLY_PROPERTY(P_PAGE_COUNT, "pageCount")
WXJS_END_PROPERTY_MAP()
bool BookCtrlBase::GetProperty(wxBookCtrlBase *p, JSContext *cx, JSObject *obj, int id, jsval *vp)
{
switch (id)
{
case P_PAGE_COUNT:
*vp = ToJS(cx, p->GetPageCount());
break;
}
return true;
}
bool BookCtrlBase::SetProperty(wxBookCtrlBase *p, JSContext *cx, JSObject *obj, int id, jsval *vp)
{
return true;
}
WXJS_BEGIN_METHOD_MAP(BookCtrlBase)
WXJS_METHOD("addPage", addPage, 2)
WXJS_METHOD("deleteAllPages", deleteAllPages, 0)
WXJS_METHOD("getPage", getPage, 1)
WXJS_END_METHOD_MAP()
JSBool BookCtrlBase::addPage(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
wxBookCtrlBase *p = GetPrivate(cx, obj);
if ( p == NULL )
return JS_FALSE;
wxWindow *win;
wxString text;
bool select = false;
int imageId = -1;
if ( argc >= 4 )
{
if ( ! FromJS(cx, argv[3], imageId) )
return JS_FALSE;
}
if ( argc >= 3 )
{
if ( ! FromJS(cx, argv[2], select) )
return JS_FALSE;
}
FromJS(cx, argv[1], text);
win = Window::GetPrivate(cx, argv[0]);
if ( win == NULL )
return JS_FALSE;
p->AddPage(win, text, select, imageId);
return JS_TRUE;
}
JSBool BookCtrlBase::deleteAllPages(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
wxBookCtrlBase *p = GetPrivate(cx, obj);
if ( p == NULL )
return JS_FALSE;
p->DeleteAllPages();
return JS_TRUE;
}
JSBool BookCtrlBase::getPage(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
wxBookCtrlBase *p = GetPrivate(cx, obj);
if ( p == NULL )
return JS_FALSE;
size_t page;
if ( ! FromJS(cx, argv[0], page) )
return JS_FALSE;
wxWindow *win = p->GetPage(page);
JavaScriptClientData *data
= dynamic_cast<JavaScriptClientData*>(win->GetClientObject());
if ( data == NULL )
return JS_FALSE;
*rval = OBJECT_TO_JSVAL(data->GetObject());
return JS_TRUE;
}

View File

@ -0,0 +1,42 @@
#ifndef _WXJSBOOKCTRL_H
#define _WXJSBOOKCTRL_H
#include "../../common/evtconn.h"
#include <wx/bookctrl.h>
namespace wxjs
{
namespace gui
{
class BookCtrlBase : public ApiWrapper<BookCtrlBase, wxBookCtrlBase>
{
public:
static bool GetProperty(wxBookCtrlBase *p,
JSContext *cx,
JSObject *obj,
int id,
jsval *vp);
static bool SetProperty(wxBookCtrlBase *p,
JSContext *cx,
JSObject *obj,
int id,
jsval *vp);
WXJS_DECLARE_METHOD_MAP()
WXJS_DECLARE_METHOD(addPage)
WXJS_DECLARE_METHOD(deleteAllPages)
WXJS_DECLARE_METHOD(getPage)
WXJS_DECLARE_CONSTANT_MAP()
WXJS_DECLARE_PROPERTY_MAP()
enum
{
P_PAGE_COUNT
};
};
}; // namespace gui
}; // namespace wxjs
#endif //_WXJSBOOKCTRL_H

View File

@ -0,0 +1,257 @@
#include "precompiled.h"
#ifndef WX_PRECOMP
#include <wx/wx.h>
#endif
#include "../../common/main.h"
#include "../event/jsevent.h"
#include "../event/notebookevt.h"
#include "notebook.h"
#include "bookctrl.h"
#include "window.h"
#include "../misc/point.h"
#include "../misc/size.h"
#include "../errors.h"
using namespace wxjs;
using namespace wxjs::gui;
WXJS_INIT_CLASS(Notebook, "wxNotebook", 2)
void Notebook::InitClass(JSContext* WXUNUSED(cx),
JSObject* WXUNUSED(obj),
JSObject* WXUNUSED(proto))
{
NotebookEventHandler::InitConnectEventMap();
}
WXJS_BEGIN_CONSTANT_MAP(Notebook)
WXJS_CONSTANT(wxNB_, HITTEST_NOWHERE)
WXJS_CONSTANT(wxNB_, HITTEST_ONICON)
WXJS_CONSTANT(wxNB_, HITTEST_ONLABEL)
WXJS_CONSTANT(wxNB_, HITTEST_ONITEM)
WXJS_CONSTANT(wxNB_, HITTEST_ONPAGE)
WXJS_CONSTANT(wxNB_, DEFAULT)
WXJS_CONSTANT(wxNB_, TOP)
WXJS_CONSTANT(wxNB_, BOTTOM)
WXJS_CONSTANT(wxNB_, LEFT)
WXJS_CONSTANT(wxNB_, RIGHT)
WXJS_CONSTANT(wxNB_, FIXEDWIDTH)
WXJS_CONSTANT(wxNB_, MULTILINE)
WXJS_CONSTANT(wxNB_, NOPAGETHEME)
WXJS_CONSTANT(wxNB_, FLAT)
WXJS_END_CONSTANT_MAP()
WXJS_BEGIN_PROPERTY_MAP(Notebook)
WXJS_READONLY_PROPERTY(P_ROW_COUNT, "rowCount")
WXJS_END_PROPERTY_MAP()
bool Notebook::GetProperty(wxNotebook *p, JSContext *cx, JSObject *obj, int id, jsval *vp)
{
switch (id)
{
case P_ROW_COUNT:
*vp = ToJS(cx, p->GetRowCount());
break;
}
return true;
}
bool Notebook::SetProperty(wxNotebook *p, JSContext *cx, JSObject *obj, int id, jsval *vp)
{
switch (id)
{
}
return true;
}
bool Notebook::AddProperty(wxNotebook *p,
JSContext* WXUNUSED(cx),
JSObject* WXUNUSED(obj),
const wxString &prop,
jsval* WXUNUSED(vp))
{
if ( WindowEventHandler::ConnectEvent(p, prop, true) )
return true;
NotebookEventHandler::ConnectEvent(p, prop, true);
return true;
}
bool Notebook::DeleteProperty(wxNotebook *p,
JSContext* WXUNUSED(cx),
JSObject* WXUNUSED(obj),
const wxString &prop)
{
if ( WindowEventHandler::ConnectEvent(p, prop, false) )
return true;
NotebookEventHandler::ConnectEvent(p, prop, false);
return true;
}
// HACK: so I don't get PAGE_CHANGED events when ~wxNotebook is calling DeleteAllPages
struct Wrapper_wxNotebook : public wxNotebook
{
~Wrapper_wxNotebook()
{
wxList* d = GetDynamicEventTable();
for (wxList::iterator it = d->begin(), end = d->end(); it != end; ++it)
{
wxDynamicEventTableEntry *entry = (wxDynamicEventTableEntry*)*it;
delete entry->m_callbackUserData;
delete entry;
}
d->Clear();
}
};
wxNotebook* Notebook::Construct(JSContext *cx,
JSObject *obj,
uintN argc,
jsval *argv,
bool WXUNUSED(constructing))
{
wxNotebook *p = new Wrapper_wxNotebook();
SetPrivate(cx, obj, p);
if ( argc > 0 )
{
jsval rval;
if ( ! create(cx, obj, argc, argv, &rval) )
return NULL;
}
return p;
}
WXJS_BEGIN_METHOD_MAP(Notebook)
WXJS_METHOD("create", create, 2)
WXJS_END_METHOD_MAP()
JSBool Notebook::create(JSContext *cx,
JSObject *obj,
uintN argc,
jsval *argv,
jsval *rval)
{
wxNotebook *p = GetPrivate(cx, obj);
*rval = JSVAL_FALSE;
if ( argc > 5 )
argc = 5;
wxWindowID id = -1;
const wxPoint *pt = &wxDefaultPosition;
const wxSize *size = &wxDefaultSize;
int style = 0;
switch(argc)
{
case 5:
if ( ! FromJS(cx, argv[4], style) )
{
JS_ReportError(cx, WXJS_INVALID_ARG_TYPE, 4, "Integer");
return JS_FALSE;
}
// Fall through
case 4:
size = Size::GetPrivate(cx, argv[3]);
if ( size == NULL )
{
JS_ReportError(cx, WXJS_INVALID_ARG_TYPE, 3, "wxSize");
return JS_FALSE;
}
// Fall through
case 3:
pt = Point::GetPrivate(cx, argv[2]);
if ( pt == NULL )
{
JS_ReportError(cx, WXJS_INVALID_ARG_TYPE, 3, "wxPoint");
return JS_FALSE;
}
// Fall through
default:
if ( ! FromJS(cx, argv[1], id) )
{
JS_ReportError(cx, WXJS_INVALID_ARG_TYPE, 2, "Integer");
return JS_FALSE;
}
wxWindow *parent = Window::GetPrivate(cx, argv[0]);
if ( parent == NULL )
{
JS_ReportError(cx, WXJS_NO_PARENT_ERROR, GetClass()->name);
return JS_FALSE;
}
JavaScriptClientData *clntParent =
dynamic_cast<JavaScriptClientData *>(parent->GetClientObject());
if ( clntParent == NULL )
{
JS_ReportError(cx, WXJS_NO_PARENT_ERROR, GetClass()->name);
return JS_FALSE;
}
JS_SetParent(cx, obj, clntParent->GetObject());
if ( p->Create(parent, id, *pt, *size, style) )
{
*rval = JSVAL_TRUE;
p->SetClientObject(new JavaScriptClientData(cx, obj, true, false));
}
}
return JS_TRUE;
}
WXJS_INIT_EVENT_MAP(wxNotebook)
const wxString WXJS_PAGE_CHANGED_EVENT = wxT("onPageChanged");
const wxString WXJS_PAGE_CHANGING_EVENT = wxT("onPageChanging");
void NotebookEventHandler::OnPageChanged(wxNotebookEvent &event)
{
PrivNotebookEvent::Fire<NotebookEvent>(event, WXJS_PAGE_CHANGED_EVENT);
}
void NotebookEventHandler::OnPageChanging(wxNotebookEvent &event)
{
PrivNotebookEvent::Fire<NotebookEvent>(event, WXJS_PAGE_CHANGING_EVENT);
}
void NotebookEventHandler::ConnectPageChanged(wxNotebook *p, bool connect)
{
if ( connect )
{
p->Connect(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED,
wxNotebookEventHandler(OnPageChanged));
}
else
{
p->Disconnect(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED,
wxNotebookEventHandler(OnPageChanged));
}
}
void NotebookEventHandler::ConnectPageChanging(wxNotebook *p, bool connect)
{
if ( connect )
{
p->Connect(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING,
wxNotebookEventHandler(OnPageChanging));
}
else
{
p->Disconnect(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING,
wxNotebookEventHandler(OnPageChanging));
}
}
void NotebookEventHandler::InitConnectEventMap()
{
AddConnector(WXJS_PAGE_CHANGED_EVENT, ConnectPageChanged);
AddConnector(WXJS_PAGE_CHANGING_EVENT, ConnectPageChanging);
}

View File

@ -0,0 +1,69 @@
#ifndef _WXJSNOTEBOOK_H
#define _WXJSNOTEBOOK_H
#include "../../common/evtconn.h"
#include <wx/notebook.h>
namespace wxjs
{
namespace gui
{
class Notebook : public ApiWrapper<Notebook, wxNotebook>
{
public:
static void InitClass(JSContext *cx,
JSObject *obj,
JSObject *proto);
static bool AddProperty(wxNotebook *p,
JSContext *cx,
JSObject *obj,
const wxString &prop,
jsval *vp);
static bool DeleteProperty(wxNotebook *p,
JSContext *cx,
JSObject *obj,
const wxString &prop);
static bool GetProperty(wxNotebook *p,
JSContext *cx,
JSObject *obj,
int id,
jsval *vp);
static bool SetProperty(wxNotebook *p,
JSContext *cx,
JSObject *obj,
int id,
jsval *vp);
static wxNotebook* Construct(JSContext *cx,
JSObject *obj,
uintN argc,
jsval *argv,
bool constructing);
WXJS_DECLARE_METHOD_MAP()
WXJS_DECLARE_METHOD(create)
WXJS_DECLARE_CONSTANT_MAP()
WXJS_DECLARE_PROPERTY_MAP()
enum
{
P_ROW_COUNT
};
};
class NotebookEventHandler : public EventConnector<wxNotebook>
, public wxEvtHandler
{
public:
void OnPageChanged(wxNotebookEvent &event);
void OnPageChanging(wxNotebookEvent &event);
static void InitConnectEventMap();
private:
static void ConnectPageChanged(wxNotebook *p, bool connect);
static void ConnectPageChanging(wxNotebook *p, bool connect);
};
}; // namespace gui
}; // namespace wxjs
#endif //_WXJSNOTEBOOK_H

View File

@ -32,6 +32,8 @@
#include "../../common/main.h"
#include <wx/tooltip.h>
#include "window.h"
#include "../misc/point.h"
#include "../misc/size.h"
@ -198,6 +200,7 @@ WXJS_BEGIN_PROPERTY_MAP(Window)
WXJS_PROPERTY(P_BACKGROUND_COLOUR, "backgroundColour")
WXJS_PROPERTY(P_FOREGROUND_COLOUR, "foregroundColour")
WXJS_PROPERTY(P_FONT, "font")
WXJS_PROPERTY(P_TOOL_TIP, "toolTip")
WXJS_END_PROPERTY_MAP()
bool Window::GetProperty(wxWindow *p, JSContext *cx, JSObject *obj, int id, jsval *vp)
@ -347,6 +350,15 @@ bool Window::GetProperty(wxWindow *p, JSContext *cx, JSObject *obj, int id, jsva
case P_FONT:
*vp = Font::CreateObject(cx, new wxFont(p->GetFont()), obj);
break;
case P_TOOL_TIP:
if ( p->GetToolTip() == NULL )
*vp = JSVAL_VOID;
else
{
wxString tip = p->GetToolTip()->GetTip();
*vp = ToJS(cx, tip);
}
break;
}
return true;
}
@ -528,6 +540,17 @@ bool Window::SetProperty(wxWindow *p, JSContext *cx, JSObject *obj, int id, jsva
p->SetFont(*font);
break;
}
case P_TOOL_TIP:
if ( JSVAL_IS_VOID(*vp) )
{
p->SetToolTip(NULL);
}
else
{
wxString tip;
FromJS(cx, *vp, tip);
p->SetToolTip(tip);
}
}
return true;
}

View File

@ -129,6 +129,7 @@ namespace wxjs
, P_BACKGROUND_COLOUR
, P_FOREGROUND_COLOUR
, P_FONT
, P_TOOL_TIP
};
};

View File

@ -48,6 +48,7 @@
#include "htmllink.h"
#include "split.h"
#include "spinevt.h"
#include "notebookevt.h"
#include "notify.h"
#include "listevt.h"
@ -178,5 +179,10 @@ bool wxjs::gui::InitEventClasses(JSContext *cx, JSObject *global)
if (! obj )
return false;
obj = NotebookEvent::JSInit(cx, global, NotifyEvent::GetClassPrototype());
wxASSERT_MSG(obj != NULL, wxT("wxNotebookEvent prototype creation failed"));
if (! obj )
return false;
return true;
}

View File

@ -0,0 +1,72 @@
#include "precompiled.h"
#ifndef WX_PRECOMP
#include <wx/wx.h>
#endif
#include "../../common/main.h"
#include "../../common/apiwrap.h"
#include <wx/notebook.h>
#include "jsevent.h"
#include "../misc/size.h"
#include "notebookevt.h"
using namespace wxjs;
using namespace wxjs::gui;
WXJS_INIT_CLASS(NotebookEvent, "wxNotebookEvent", 0)
WXJS_BEGIN_PROPERTY_MAP(NotebookEvent)
WXJS_PROPERTY(P_OLD_SELECTION, "oldSelection")
WXJS_PROPERTY(P_SELECTION, "selection")
WXJS_END_PROPERTY_MAP()
bool NotebookEvent::GetProperty(PrivNotebookEvent *p,
JSContext *cx,
JSObject* WXUNUSED(obj),
int id,
jsval *vp)
{
wxNotebookEvent *event = (wxNotebookEvent*) p->GetEvent();
switch ( id )
{
case P_OLD_SELECTION:
*vp = ToJS(cx, event->GetOldSelection());
break;
case P_SELECTION:
*vp = ToJS(cx, event->GetSelection());
break;
}
return true;
}
bool NotebookEvent::SetProperty(PrivNotebookEvent *p,
JSContext *cx,
JSObject* WXUNUSED(obj),
int id,
jsval *vp)
{
wxNotebookEvent *event = (wxNotebookEvent*) p->GetEvent();
switch ( id )
{
case P_OLD_SELECTION:
{
int sel;
if ( FromJS(cx, *vp, sel) )
event->SetOldSelection(sel);
break;
}
case P_SELECTION:
{
int sel;
if ( FromJS(cx, *vp, sel) )
event->SetSelection(sel);
break;
}
}
return true;
}

View File

@ -0,0 +1,28 @@
#ifndef _WXJSNotebookEvent_H
#define _WXJSNotebookEvent_H
class wxNotebookEvent;
namespace wxjs
{
namespace gui
{
typedef JSEvent<wxNotebookEvent> PrivNotebookEvent;
class NotebookEvent : public ApiWrapper<NotebookEvent, PrivNotebookEvent>
{
public:
static bool GetProperty(PrivNotebookEvent *p, JSContext *cx, JSObject *obj, int id, jsval *vp);
static bool SetProperty(PrivNotebookEvent *p, JSContext *cx, JSObject *obj, int id, jsval *vp);
enum
{
P_OLD_SELECTION
, P_SELECTION
};
WXJS_DECLARE_PROPERTY_MAP()
};
}; // namespace gui
}; // namespace wxjs
#endif //_WXJSNotebookEvent_H

View File

@ -90,6 +90,8 @@
#include "control/htmlwin.h"
#include "control/spinctrl.h"
#include "control/spinbtn.h"
#include "control/bookctrl.h"
#include "control/notebook.h"
// Validators
#include "misc/validate.h"
@ -638,6 +640,16 @@ bool wxjs::gui::InitClass(JSContext *cx, JSObject *global)
if (! obj )
return false;
obj = BookCtrlBase::JSInit(cx, global, Control::GetClassPrototype());
wxASSERT_MSG(obj != NULL, wxT("wxBookCtrlBase prototype creation failed"));
if (! obj )
return false;
obj = Notebook::JSInit(cx, global, BookCtrlBase::GetClassPrototype());
wxASSERT_MSG(obj != NULL, wxT("wxNotebook prototype creation failed"));
if (! obj )
return false;
// Define the global functions
InitFunctions(cx, global);