# Converted Atlas's object-settings UI into JavaScript.
(Note: This breaks the Actor Viewer, hopefully temporarily.) This was SVN commit r6932.
This commit is contained in:
parent
9a977c9962
commit
34d0f012e8
114
binaries/data/tools/atlas/scripts/editorstate.js
Normal file
114
binaries/data/tools/atlas/scripts/editorstate.js
Normal file
@ -0,0 +1,114 @@
|
||||
// Define the default state settings.
|
||||
// (It's done this way so that this script can be dynamically reloaded,
|
||||
// and won't overwrite the previous runtime state but will still pick
|
||||
// up any new properties)
|
||||
var defaults = {
|
||||
objectSettings: {
|
||||
view: undefined,
|
||||
selectedObjects: [],
|
||||
playerID: 1,
|
||||
actorSelections: [],
|
||||
variantGroups: []
|
||||
}
|
||||
};
|
||||
|
||||
defaults.objectSettings.toSObjectSettings = function () {
|
||||
return {
|
||||
player: this.playerID,
|
||||
selections: this.actorSelections
|
||||
};
|
||||
}
|
||||
|
||||
defaults.objectSettings.onSelectionChange = function () {
|
||||
if (! this.selectedObjects.length)
|
||||
return; // TODO: do something sensible here
|
||||
|
||||
// TODO: Support multiple selections
|
||||
var selection = this.selectedObjects[0];
|
||||
|
||||
var settings = Atlas.Message.GetObjectSettings(this.view, selection).settings;
|
||||
|
||||
this.playerID = settings.player;
|
||||
this.actorSelections = settings.selections;
|
||||
this.variantGroups = settings.variantgroups;
|
||||
|
||||
this.notifyObservers();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current actor variation (as a list of chosen variants), based
|
||||
* on its variant groups and the selection strings. This is equivalent to the
|
||||
* variation rendered by the game.
|
||||
*/
|
||||
defaults.objectSettings.getActorVariation = function ()
|
||||
{
|
||||
var selectionMap = {};
|
||||
for each (var s in this.actorSelections)
|
||||
selectionMap[s] = 1;
|
||||
|
||||
var variation = [];
|
||||
GROUP: for each (var group in this.variantGroups) {
|
||||
for each (var variant in group) {
|
||||
if (variant in selectionMap) {
|
||||
variation.push(variant);
|
||||
continue GROUP;
|
||||
}
|
||||
}
|
||||
// None selected; default to first
|
||||
variation.push(group[0]);
|
||||
}
|
||||
return variation;
|
||||
}
|
||||
|
||||
// Merges the 'defs' tree into 'obj', overwriting any old values with
|
||||
// the same keys
|
||||
function setDefaults(defs, obj)
|
||||
{
|
||||
for (var k in defs) {
|
||||
if (k in obj)
|
||||
setDefaults(defs[k], obj[k]);
|
||||
else
|
||||
obj[k] = defaults[k];
|
||||
}
|
||||
}
|
||||
|
||||
function makeObservable(obj)
|
||||
{
|
||||
// If the object has already been set up as observable, don't do any more work.
|
||||
// (In particular, don't delete any old observers, so they don't get lost when
|
||||
// this script is reloaded.)
|
||||
if (typeof obj._observers != 'undefined')
|
||||
return;
|
||||
|
||||
obj._observers = [];
|
||||
obj.registerObserver = function (callback) {
|
||||
this._observers.push(callback);
|
||||
}
|
||||
obj.unregisterObserver = function (callback) {
|
||||
this._observers = this._observers.filter(function (o) { return o !== callback });
|
||||
}
|
||||
obj.notifyObservers = function () {
|
||||
for each (var o in this._observers)
|
||||
o(this);
|
||||
};
|
||||
}
|
||||
|
||||
function postObjectSettingsToGame(objectSettings)
|
||||
{
|
||||
if (objectSettings.selectedObjects.length)
|
||||
Atlas.Message.SetObjectSettings(objectSettings.view,
|
||||
objectSettings.selectedObjects[0], objectSettings.toSObjectSettings());
|
||||
}
|
||||
|
||||
function init()
|
||||
{
|
||||
setDefaults(defaults, Atlas.State);
|
||||
|
||||
makeObservable(Atlas.State.objectSettings);
|
||||
Atlas.State.objectSettings.registerObserver(postObjectSettingsToGame);
|
||||
}
|
||||
|
||||
function deinit() {
|
||||
Atlas.State.objectSettings.unregisterObserver(postObjectSettingsToGame);
|
||||
}
|
||||
|
@ -18,24 +18,56 @@ function loadScript(name /*, ...*/)
|
||||
var script = file.readAll(); // TODO: handle errors
|
||||
file.close();
|
||||
|
||||
var args = [];
|
||||
for (var i = 1; i < arguments.length; ++i)
|
||||
args.push(arguments[i])
|
||||
|
||||
var script = Atlas.LoadScript(name+'.js', script);
|
||||
scriptReloader.add(name, args, filename);
|
||||
|
||||
script.init.apply(null, args);
|
||||
|
||||
// Extract the arguments which the function will actually use
|
||||
// (Can't use Array.slice since arguments isn't an Array)
|
||||
// (Have to do this rather than use arguments.length, since we sometimes
|
||||
// pass unused bottomWindows into init and then destroy the window when realising
|
||||
// it wasn't used, and then we mustn't send the destroyed window again later)
|
||||
var args = [];
|
||||
if (script.init)
|
||||
for (var i = 1; i < 1+script.init.length; ++i)
|
||||
args.push(arguments[i]);
|
||||
|
||||
scriptReloader.add(name, args, filename, script);
|
||||
|
||||
if (script.init)
|
||||
script.init.apply(null, args);
|
||||
|
||||
return script;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function for C++ to easily set dot-separated names
|
||||
*/
|
||||
function setValue(name, value)
|
||||
{
|
||||
var obj = global;
|
||||
var props = name.split(".");
|
||||
for (var i = 0; i < props.length-1; ++i)
|
||||
obj = obj[props[i]];
|
||||
obj[props[props.length-1]] = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function for C++ to easily get dot-separated names
|
||||
*/
|
||||
function getValue(name)
|
||||
{
|
||||
var obj = global;
|
||||
var props = name.split(".");
|
||||
for (var i = 0; i < props.length; ++i)
|
||||
obj = obj[props[i]];
|
||||
return obj;
|
||||
}
|
||||
|
||||
function loadXML(name)
|
||||
{
|
||||
var relativePath = 'tools/atlas/' + name + '.xml';
|
||||
var filename = new wxFileName(relativePath, wxPathFormat.UNIX);
|
||||
filename.normalize(wxPathNormalize.DOTS | wxPathNormalize.ABSOLUTE | wxPathNormalize.TILDE,
|
||||
Atlas.GetDataDirectory()); // equivalent to MakeAbsolute(dir);
|
||||
Atlas.GetDataDirectory()); // equivalent to MakeAbsolute(dir);
|
||||
|
||||
var file = new wxFFile(filename.fullPath);
|
||||
var xml = file.readAll(); // TODO: handle errors
|
||||
@ -46,11 +78,10 @@ function loadXML(name)
|
||||
return new XML(xml);
|
||||
}
|
||||
|
||||
function init() { /* dummy function to make the script reloader happy */ }
|
||||
|
||||
// Automatically reload scripts from disk when they have been modified
|
||||
var scriptReloader = {
|
||||
timer: new wxTimer(),
|
||||
scripts: [], // [ [filename,window], ... ]
|
||||
scripts: [], // [ {name, args, filename, mtime, window, script}, ... ]
|
||||
notify: function ()
|
||||
{
|
||||
for each (var script in scriptReloader.scripts)
|
||||
@ -59,13 +90,18 @@ var scriptReloader = {
|
||||
if (mtime - script.mtime != 0)
|
||||
{
|
||||
print('*** Modifications detected - reloading "' + script.name + '"...\n');
|
||||
|
||||
script.mtime = mtime;
|
||||
|
||||
if (script.script && script.script.deinit)
|
||||
script.script.deinit();
|
||||
|
||||
if (script.name == 'main')
|
||||
{
|
||||
// Special case for this file to reload itself
|
||||
var obj = loadScript(script.name, null);
|
||||
script.script = loadScript(script.name, null);
|
||||
// Copy the important state into the new version of this file
|
||||
obj.scriptReloader.scripts = scriptReloader.scripts;
|
||||
script.script.scriptReloader.scripts = scriptReloader.scripts;
|
||||
// Stop this one
|
||||
scriptReloader.timer.stop();
|
||||
}
|
||||
@ -74,25 +110,30 @@ var scriptReloader = {
|
||||
// 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));
|
||||
script.script = loadScript.apply(null, [script.name].concat(script.args));
|
||||
for each (var window in script.args)
|
||||
window.layout();
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
add: function (name, args, filename)
|
||||
add: function (name, args, filename, script)
|
||||
{
|
||||
for each (var script in this.scripts)
|
||||
if (script.name == name)
|
||||
for each (var s in this.scripts)
|
||||
if (s.name == name)
|
||||
return; // stop if this is already loaded
|
||||
this.scripts.push({ name:name, args:args, filename:filename, mtime:filename.modificationTime });
|
||||
|
||||
this.scripts.push({ name:name, args:args, filename:filename, mtime:filename.modificationTime, script:script });
|
||||
}
|
||||
};
|
||||
scriptReloader.timer.onNotify = scriptReloader.notify;
|
||||
scriptReloader.timer.start(1000);
|
||||
scriptReloader.add('main', null, getScriptFilename('main'));
|
||||
|
||||
loadScript('editorstate');
|
||||
|
||||
// Export global functions:
|
||||
global.loadScript = loadScript;
|
||||
global.loadXML = loadXML;
|
||||
global.setValue = setValue;
|
||||
global.getValue = getValue;
|
||||
|
120
binaries/data/tools/atlas/scripts/section/object.js
Normal file
120
binaries/data/tools/atlas/scripts/section/object.js
Normal file
@ -0,0 +1,120 @@
|
||||
function setObjectFilter(objectList, objects, type)
|
||||
{
|
||||
objectList.freeze();
|
||||
objectList.clear();
|
||||
var ids = [];
|
||||
for each (var object in objects) {
|
||||
if (object.type == type) {
|
||||
ids.push(object.id);
|
||||
objectList.append(object.name);
|
||||
}
|
||||
}
|
||||
objectList.objectIDs = ids;
|
||||
objectList.thaw();
|
||||
}
|
||||
|
||||
var g_observer;
|
||||
|
||||
function init(window, bottomWindow)
|
||||
{
|
||||
window.sizer = new wxBoxSizer(wxOrientation.VERTICAL);
|
||||
|
||||
var objects = Atlas.Message.GetObjectsList().objects;
|
||||
|
||||
var objectList = new wxListBox(window, -1, wxDefaultPosition, wxDefaultSize, [],
|
||||
wxListBox.SINGLE | wxListBox.HSCROLL);
|
||||
objectList.onListBox = function (evt) {
|
||||
if (evt.selection == -1)
|
||||
return;
|
||||
var id = objectList.objectIDs[evt.selection];
|
||||
Atlas.SetCurrentToolWith('PlaceObject', id);
|
||||
};
|
||||
setObjectFilter(objectList, objects, 0);
|
||||
|
||||
var groupSelector = new wxChoice(window, -1, wxDefaultPosition, wxDefaultSize,
|
||||
["Entities", "Actors (all)"]
|
||||
);
|
||||
groupSelector.onChoice = function (evt) {
|
||||
setObjectFilter(objectList, objects, evt.selection);
|
||||
};
|
||||
|
||||
window.sizer.add(groupSelector, 0, wxStretch.EXPAND);
|
||||
window.sizer.add(objectList, 1, wxStretch.EXPAND);
|
||||
|
||||
|
||||
bottomWindow.sizer = new wxBoxSizer(wxOrientation.VERTICAL);
|
||||
var playerSelector = new wxChoice(bottomWindow, -1, wxDefaultPosition, wxDefaultSize,
|
||||
["Gaia", "Player 1", "Player 2", "Player 3", "Player 4", "Player 5", "Player 6", "Player 7", "Player 8"]
|
||||
);
|
||||
bottomWindow.sizer.add(playerSelector);
|
||||
|
||||
playerSelector.selection = Atlas.State.objectSettings.playerID;
|
||||
playerSelector.onChoice = function (evt) {
|
||||
Atlas.State.objectSettings.playerID = evt.selection;
|
||||
Atlas.State.objectSettings.notifyObservers();
|
||||
};
|
||||
function updatePlayerSelector() {
|
||||
playerSelector.selection = Atlas.State.objectSettings.playerID;
|
||||
}
|
||||
|
||||
|
||||
var variationControl = new wxScrolledWindow(bottomWindow, -1);
|
||||
variationControl.setScrollRate(0, 5);
|
||||
variationControl.sizer = new wxBoxSizer(wxOrientation.VERTICAL);
|
||||
var variationControlBox = new wxStaticBoxSizer(new wxStaticBox(bottomWindow, -1, "Actor Variation"), wxOrientation.VERTICAL);
|
||||
variationControl.sizer.minSize = new wxSize(160, -1);
|
||||
variationControlBox.add(variationControl, 1);
|
||||
bottomWindow.sizer.add(variationControlBox, 1);
|
||||
|
||||
function onVariationSelect() {
|
||||
// It's possible for a variant name to appear in multiple groups.
|
||||
// If so, assume that all the names in each group are the same, so
|
||||
// we don't have to worry about some impossible combinations (e.g.
|
||||
// one group "a,b", a second "b,c", and a third "c,a", where's there's
|
||||
// no set of selections that matches one (and only one) of each group).
|
||||
//
|
||||
// So... When a combo box is changed from 'a' to 'b', add 'b' to the new
|
||||
// selections and make sure any other combo boxes containing both 'a' and
|
||||
// 'b' no longer contain 'a'.
|
||||
|
||||
var sel = this.stringSelection;
|
||||
var selections = [ sel ];
|
||||
for each (var c in variationControl.children)
|
||||
if (c.findString(sel) == wxNOT_FOUND)
|
||||
selections.push(c.stringSelection);
|
||||
|
||||
Atlas.State.objectSettings.actorSelections = selections;
|
||||
Atlas.State.objectSettings.notifyObservers();
|
||||
}
|
||||
|
||||
function updateVariationControl() {
|
||||
variationControl.sizer.clear(true);
|
||||
var settings = Atlas.State.objectSettings;
|
||||
var variation = settings.getActorVariation();
|
||||
for (var i = 0; i < settings.variantGroups.length; ++i) {
|
||||
var choice = new wxChoice(variationControl, -1, wxDefaultPosition, new wxSize(80, -1),
|
||||
settings.variantGroups[i]);
|
||||
choice.onChoice = onVariationSelect;
|
||||
choice.stringSelection = variation[i];
|
||||
variationControl.sizer.add(choice, 0, wxStretch.EXPAND);
|
||||
}
|
||||
variationControlBox.layout();
|
||||
variationControl.sizer.layout();
|
||||
bottomWindow.sizer.layout();
|
||||
}
|
||||
|
||||
g_observer = function() {
|
||||
updatePlayerSelector();
|
||||
updateVariationControl();
|
||||
};
|
||||
Atlas.State.objectSettings.registerObserver(g_observer);
|
||||
|
||||
// Initialise the controls
|
||||
g_observer();
|
||||
}
|
||||
|
||||
function deinit()
|
||||
{
|
||||
Atlas.State.objectSettings.unregisterObserver(g_observer);
|
||||
}
|
||||
|
@ -94,6 +94,8 @@ TerrainPreviewPage.prototype = {
|
||||
itemSizer.cols = numCols;
|
||||
};
|
||||
|
||||
// TODO: Do something clever like load the preview images asynchronously,
|
||||
// to avoid the annoying freeze when switching tabs
|
||||
var previews = Atlas.Message.GetTerrainGroupPreviews(this.name, w, h).previews;
|
||||
var i = 0;
|
||||
var names = [];
|
||||
@ -113,6 +115,8 @@ TerrainPreviewPage.prototype = {
|
||||
itemSizer.add(imgSizer, 0, wxAlignment.CENTRE | wxStretch.EXPAND);
|
||||
}
|
||||
|
||||
// TODO: fix keyboard navigation of the terrain previews
|
||||
|
||||
this.panel.layout();
|
||||
|
||||
this.loaded = true;
|
||||
@ -124,10 +128,9 @@ function init(window, bottomWindow)
|
||||
window.sizer = new wxBoxSizer(wxOrientation.VERTICAL);
|
||||
|
||||
var tools = [
|
||||
/* text label; internal tool name; button */
|
||||
[ 'Modify', 'AlterElevation', undefined ],
|
||||
[ 'Flatten', 'FlattenElevation', undefined ],
|
||||
[ 'Paint', 'PaintTerrain', undefined ]
|
||||
{ label: 'Modify', name: 'AlterElevation' },
|
||||
{ label: 'Flatten', name: 'FlattenElevation' },
|
||||
{ label: 'Paint', name: 'PaintTerrain' },
|
||||
];
|
||||
var selectedTool = null; // null if none selected, else an element of 'tools'
|
||||
|
||||
@ -135,9 +138,9 @@ function init(window, bottomWindow)
|
||||
window.sizer.add(toolSizer, 0, wxStretch.EXPAND);
|
||||
for each (var tool in tools)
|
||||
{
|
||||
var button = new wxButton(window, -1, tool[0]);
|
||||
var button = new wxButton(window, -1, tool.label);
|
||||
toolSizer.add(button, 1);
|
||||
tool[2] = button;
|
||||
tool.button = button;
|
||||
|
||||
// Explicitly set the background to the default colour, so that the button
|
||||
// is always owner-drawn (by the wxButton code), rather than initially using the
|
||||
@ -157,15 +160,16 @@ function init(window, bottomWindow)
|
||||
{
|
||||
// Disable the old tool
|
||||
if (selectedTool)
|
||||
selectedTool[2].backgroundColour = wxSystemSettings.getColour(wxSystemSettings.COLOUR_BTNFACE);
|
||||
selectedTool.button.backgroundColour = wxSystemSettings.getColour(wxSystemSettings.COLOUR_BTNFACE);
|
||||
// Enable the new one
|
||||
selectedTool = tool;
|
||||
this.backgroundColour = new wxColour(0xEE, 0xCC, 0x55);
|
||||
Atlas.SetCurrentTool(tool[1]);
|
||||
Atlas.SetCurrentTool(tool.name);
|
||||
brush.send();
|
||||
}
|
||||
};
|
||||
})(tool);
|
||||
// TODO: Need to make this interact properly with Tools.cpp/RegisterToolButton so all the buttons are in sync
|
||||
}
|
||||
|
||||
var brushSizer = new wxStaticBoxSizer(new wxStaticBox(window, -1, 'Brush'), wxOrientation.VERTICAL);
|
||||
|
@ -18,6 +18,10 @@
|
||||
#include "ScriptInterface.h"
|
||||
|
||||
#include <cassert>
|
||||
#ifndef _WIN32
|
||||
# include <typeinfo>
|
||||
# include <cxxabi.h>
|
||||
#endif
|
||||
|
||||
#include "js/jsapi.h"
|
||||
|
||||
@ -37,30 +41,49 @@
|
||||
#include "GameInterface/Shareable.h"
|
||||
#include "GameInterface/Messages.h"
|
||||
|
||||
|
||||
#include <boost/preprocessor/punctuation/comma_if.hpp>
|
||||
#include <boost/preprocessor/repetition/repeat.hpp>
|
||||
|
||||
#include <valgrind/valgrind.h>
|
||||
|
||||
#define FAIL(msg) do { JS_ReportError(cx, msg); return false; } while (false)
|
||||
|
||||
const int RUNTIME_SIZE = 1024*1024; // TODO: how much memory is needed?
|
||||
const int RUNTIME_SIZE = 4*1024*1024; // TODO: how much memory is needed?
|
||||
const int STACK_CHUNK_SIZE = 8192;
|
||||
|
||||
SubmitCommand g_SubmitCommand; // TODO: globals are ugly
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace
|
||||
{
|
||||
template<typename T>
|
||||
void ReportError(JSContext* cx, const char* title)
|
||||
{
|
||||
// TODO: SetPendingException turns the error into a JS-catchable exception,
|
||||
// but the error report doesn't say anything useful like the line number,
|
||||
// so I'm just using ReportError instead for now (and failures are uncatchable
|
||||
// and will terminate the whole script)
|
||||
//JS_SetPendingException(cx, STRING_TO_JSVAL(JS_NewStringCopyZ(cx, "%s: Unhandled type", title)));
|
||||
#ifdef _WIN32
|
||||
JS_ReportError(cx, "%s: Unhandled type", title);
|
||||
#else
|
||||
// Give a more informative message on GCC
|
||||
int status;
|
||||
char* name = abi::__cxa_demangle(typeid(T).name(), 0, 0, &status);
|
||||
JS_ReportError(cx, "%s: Unhandled type '%s'", title, name);
|
||||
free(name);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Use templated structs instead of functions, so that we can use partial specialisation:
|
||||
|
||||
template<typename T> struct FromJSVal
|
||||
{
|
||||
static bool Convert(JSContext* cx, jsval WXUNUSED(v), T& WXUNUSED(out))
|
||||
{
|
||||
JS_ReportError(cx, "Unrecognised argument type");
|
||||
// TODO: SetPendingException turns the error into a JS-catchable exception,
|
||||
// but the error report doesn't say anything useful like the line number,
|
||||
// so I'm just using ReportError instead for now (and failures are uncatchable
|
||||
// and will terminate the whole script)
|
||||
//JS_SetPendingException(cx, STRING_TO_JSVAL(JS_NewStringCopyZ(cx, "Unrecognised argument type")));
|
||||
ReportError<T>(cx, "FromJSVal");
|
||||
return false;
|
||||
}
|
||||
};
|
||||
@ -92,7 +115,18 @@ namespace
|
||||
static bool Convert(JSContext* cx, jsval v, int& out)
|
||||
{
|
||||
int32 ret;
|
||||
if (! JS_ValueToInt32(cx, v, &ret)) return false;
|
||||
if (! JS_ValueToECMAInt32(cx, v, &ret)) return false;
|
||||
out = ret;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template<> struct FromJSVal<size_t>
|
||||
{
|
||||
static bool Convert(JSContext* cx, jsval v, size_t& out)
|
||||
{
|
||||
uint32 ret;
|
||||
if (! JS_ValueToECMAUint32(cx, v, &ret)) return false;
|
||||
out = ret;
|
||||
return true;
|
||||
}
|
||||
@ -163,12 +197,13 @@ namespace
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
// Primitive types:
|
||||
|
||||
template<typename T> struct ToJSVal
|
||||
{
|
||||
static jsval Convert(JSContext* cx, const T& WXUNUSED(val))
|
||||
{
|
||||
JS_ReportError(cx, "Unrecognised query return type");
|
||||
ReportError<T>(cx, "ToJSVal");
|
||||
return JSVAL_VOID;
|
||||
}
|
||||
};
|
||||
@ -191,6 +226,14 @@ namespace
|
||||
}
|
||||
};
|
||||
|
||||
template<> struct ToJSVal<size_t>
|
||||
{
|
||||
static jsval Convert(JSContext* WXUNUSED(cx), const size_t& val)
|
||||
{
|
||||
return INT_TO_JSVAL(val);
|
||||
}
|
||||
};
|
||||
|
||||
template<> struct ToJSVal<wxString>
|
||||
{
|
||||
static jsval Convert(JSContext* cx, const wxString& val)
|
||||
@ -221,6 +264,9 @@ namespace
|
||||
}
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
// Compound types:
|
||||
|
||||
template<typename T> struct ToJSVal<std::vector<T> >
|
||||
{
|
||||
static jsval Convert(JSContext* cx, const std::vector<T>& val)
|
||||
@ -247,6 +293,7 @@ namespace
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
// AtlasMessage structures:
|
||||
|
||||
template<> struct ToJSVal<AtlasMessage::sTerrainGroupPreview>
|
||||
{
|
||||
@ -269,6 +316,65 @@ namespace
|
||||
}
|
||||
};
|
||||
|
||||
template<> struct ToJSVal<AtlasMessage::sObjectsListItem>
|
||||
{
|
||||
static jsval Convert(JSContext* cx, const AtlasMessage::sObjectsListItem& val)
|
||||
{
|
||||
JSObject* obj = JS_NewObject(cx, NULL, NULL, NULL);
|
||||
if (! obj) return JSVAL_VOID;
|
||||
JS_AddRoot(cx, &obj);
|
||||
JS_DefineProperty(cx, obj, "id", ToJSVal<std::wstring>::Convert(cx, *val.id), NULL, NULL, JSPROP_ENUMERATE);
|
||||
JS_DefineProperty(cx, obj, "name", ToJSVal<std::wstring>::Convert(cx, *val.name), NULL, NULL, JSPROP_ENUMERATE);
|
||||
JS_DefineProperty(cx, obj, "type", ToJSVal<int>::Convert(cx, val.type), NULL, NULL, JSPROP_ENUMERATE);
|
||||
JS_RemoveRoot(cx, &obj);
|
||||
return OBJECT_TO_JSVAL(obj);
|
||||
}
|
||||
};
|
||||
|
||||
template<> struct ToJSVal<AtlasMessage::sObjectSettings>
|
||||
{
|
||||
static jsval Convert(JSContext* cx, const AtlasMessage::sObjectSettings& val)
|
||||
{
|
||||
JSObject* obj = JS_NewObject(cx, NULL, NULL, NULL);
|
||||
if (! obj) return JSVAL_VOID;
|
||||
JS_AddRoot(cx, &obj);
|
||||
JS_DefineProperty(cx, obj, "player", ToJSVal<size_t>::Convert(cx, val.player), NULL, NULL, JSPROP_ENUMERATE);
|
||||
JS_DefineProperty(cx, obj, "selections", ToJSVal<std::vector<std::wstring> >::Convert(cx, *val.selections), NULL, NULL, JSPROP_ENUMERATE);
|
||||
JS_DefineProperty(cx, obj, "variantgroups", ToJSVal<std::vector<std::vector<std::wstring> > >::Convert(cx, *val.variantgroups), NULL, NULL, JSPROP_ENUMERATE);
|
||||
JS_RemoveRoot(cx, &obj);
|
||||
return OBJECT_TO_JSVAL(obj);
|
||||
}
|
||||
};
|
||||
|
||||
template<> struct FromJSVal<AtlasMessage::sObjectSettings>
|
||||
{
|
||||
static bool Convert(JSContext* cx, jsval v, AtlasMessage::sObjectSettings& out)
|
||||
{
|
||||
JSObject* obj;
|
||||
if (! JS_ValueToObject(cx, v, &obj) || obj == NULL)
|
||||
FAIL("Argument must be an array");
|
||||
jsval val;
|
||||
|
||||
int player;
|
||||
if (! JS_GetProperty(cx, obj, "player", &val))
|
||||
FAIL("Failed to get 'player'");
|
||||
if (! ScriptInterface::FromJSVal(cx, val, player))
|
||||
FAIL("Failed to convert 'player'");
|
||||
out.player = player;
|
||||
|
||||
std::vector<std::wstring> selections;
|
||||
if (! JS_GetProperty(cx, obj, "selections", &val))
|
||||
FAIL("Failed to get 'selections'");
|
||||
if (! ScriptInterface::FromJSVal(cx, val, selections))
|
||||
FAIL("Failed to convert 'selections'");
|
||||
out.selections = selections;
|
||||
|
||||
// variantgroups is only used in engine-to-editor, so we don't
|
||||
// bother converting it here
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
template<typename T> bool ScriptInterface::FromJSVal(JSContext* cx, jsval v, T& out)
|
||||
@ -284,10 +390,10 @@ template<typename T> jsval ScriptInterface::ToJSVal(JSContext* cx, const T& 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&);
|
||||
|
||||
template bool ScriptInterface::FromJSVal<float>(JSContext*, jsval, float&);
|
||||
|
||||
template jsval ScriptInterface::ToJSVal<wxString>(JSContext*, wxString const&);
|
||||
template jsval ScriptInterface::ToJSVal<int>(JSContext*, int const&);
|
||||
template jsval ScriptInterface::ToJSVal<std::vector<int> >(JSContext*, std::vector<int> const&);
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
@ -327,6 +433,7 @@ namespace
|
||||
wxLogWarning(_T("%s"), logMessage.c_str());
|
||||
else
|
||||
wxLogError(_T("%s"), logMessage.c_str());
|
||||
VALGRIND_PRINTF_BACKTRACE("->");
|
||||
wxPrintf(_T("wxJS %s: %s\n--------\n"), isWarning ? _T("warning") : _T("error"), logMessage.c_str());
|
||||
}
|
||||
|
||||
@ -377,7 +484,8 @@ ScriptInterface_impl::ScriptInterface_impl()
|
||||
m_cx = JS_NewContext(m_rt, STACK_CHUNK_SIZE);
|
||||
assert(m_cx);
|
||||
|
||||
JS_BeginRequest(m_cx); // if you get linker errors, see the comment in the .h about JS_THREADSAFE
|
||||
JS_BeginRequest(m_cx); // if you get linker errors, see the comment in ScriptInterface.h about JS_THREADSAFE
|
||||
// (TODO: are we using requests correctly? (Probably not; how much does it matter?))
|
||||
|
||||
JS_SetContextPrivate(m_cx, NULL);
|
||||
|
||||
@ -400,9 +508,10 @@ ScriptInterface_impl::ScriptInterface_impl()
|
||||
|
||||
JS_DefineFunction(m_cx, m_glob, "print", ::print, 0, JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT);
|
||||
|
||||
m_atlas = JS_DefineObject(m_cx, m_glob, "Atlas", NULL, NULL, JSPROP_READONLY|JSPROP_PERMANENT);
|
||||
m_atlas = JS_DefineObject(m_cx, m_glob, "Atlas", NULL, NULL, JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT);
|
||||
JS_DefineFunction(m_cx, m_atlas, "ForceGC", ::ForceGC, 0, JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT);
|
||||
JS_DefineFunction(m_cx, m_atlas, "LoadScript", ::LoadScript, 2, JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT);
|
||||
JS_DefineObject(m_cx, m_atlas, "State", NULL, NULL, JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT);
|
||||
|
||||
RegisterMessages(m_atlas);
|
||||
}
|
||||
@ -435,9 +544,10 @@ void ScriptInterface_impl::Register(const char* name, JSNative fptr, uintN nargs
|
||||
}
|
||||
|
||||
|
||||
ScriptInterface::ScriptInterface()
|
||||
: m(new ScriptInterface_impl)
|
||||
ScriptInterface::ScriptInterface(SubmitCommand submitCommand)
|
||||
: m(new ScriptInterface_impl())
|
||||
{
|
||||
g_SubmitCommand = submitCommand;
|
||||
}
|
||||
|
||||
ScriptInterface::~ScriptInterface()
|
||||
@ -459,6 +569,55 @@ void ScriptInterface::Register(const char* name, JSNative fptr, size_t nargs)
|
||||
m->Register(name, fptr, (uintN)nargs);
|
||||
}
|
||||
|
||||
JSContext* ScriptInterface::GetContext()
|
||||
{
|
||||
return m->m_cx;
|
||||
}
|
||||
|
||||
void ScriptInterface::AddRoot(void* ptr)
|
||||
{
|
||||
JS_AddRoot(m->m_cx, ptr);
|
||||
}
|
||||
|
||||
void ScriptInterface::RemoveRoot(void* ptr)
|
||||
{
|
||||
JS_RemoveRoot(m->m_cx, ptr);
|
||||
}
|
||||
|
||||
void ScriptInterface::SetValue_(const wxString& name, jsval val)
|
||||
{
|
||||
jsval jsName = ToJSVal(m->m_cx, name);
|
||||
|
||||
const uintN argc = 2;
|
||||
jsval argv[argc] = { jsName, val };
|
||||
jsval rval;
|
||||
JSBool ok = JS_CallFunctionName(m->m_cx, m->m_glob, "setValue", argc, argv, &rval); // TODO: error checking
|
||||
}
|
||||
|
||||
bool ScriptInterface::GetValue_(const wxString& name, jsval& ret)
|
||||
{
|
||||
jsval jsName = ToJSVal(m->m_cx, name);
|
||||
|
||||
const uintN argc = 1;
|
||||
jsval argv[argc] = { jsName };
|
||||
return JS_CallFunctionName(m->m_cx, m->m_glob, "getValue", argc, argv, &ret);
|
||||
}
|
||||
|
||||
void ScriptInterface::Eval(const wxString& script)
|
||||
{
|
||||
jsval rval;
|
||||
JSBool ok = JS_EvaluateScript(m->m_cx, m->m_glob,
|
||||
script.mb_str(), script.length(), NULL, 0, &rval);
|
||||
// TODO: error checking
|
||||
}
|
||||
|
||||
bool ScriptInterface::Eval_(const wxString& script, jsval& rval)
|
||||
{
|
||||
JSBool ok = JS_EvaluateScript(m->m_cx, m->m_glob,
|
||||
script.mb_str(), script.length(), NULL, 0, &rval);
|
||||
return ok;
|
||||
}
|
||||
|
||||
void ScriptInterface::LoadScript(const wxString& filename, const wxString& code)
|
||||
{
|
||||
size_t codeLength;
|
||||
@ -540,6 +699,15 @@ std::pair<wxPanel*, wxPanel*> ScriptInterface::LoadScriptAsSidebar(const wxStrin
|
||||
return JS_TRUE; \
|
||||
}
|
||||
|
||||
#define COMMAND(name, merge, vals) \
|
||||
JSBool call_##name(JSContext* cx, JSObject* WXUNUSED(obj), uintN WXUNUSED(argc), jsval* argv, jsval* WXUNUSED(rval)) \
|
||||
{ \
|
||||
(void)cx; (void)argv; /* avoid 'unused parameter' warnings */ \
|
||||
BOOST_PP_SEQ_FOR_EACH_I(CONVERT_ARGS, ~, vals) \
|
||||
g_SubmitCommand(new AtlasMessage::m##name (AtlasMessage::d##name ( BOOST_PP_SEQ_FOR_EACH_I(ARG_LIST, ~, vals) ))); \
|
||||
return JS_TRUE; \
|
||||
}
|
||||
|
||||
#define QUERY(name, in_vals, out_vals) \
|
||||
JSBool call_##name(JSContext* cx, JSObject* WXUNUSED(obj), uintN WXUNUSED(argc), jsval* argv, jsval* rval) \
|
||||
{ \
|
||||
@ -554,8 +722,6 @@ std::pair<wxPanel*, wxPanel*> ScriptInterface::LoadScriptAsSidebar(const wxStrin
|
||||
return JS_TRUE; \
|
||||
}
|
||||
|
||||
#define COMMAND(name, merge, vals)
|
||||
|
||||
#define MESSAGES_SKIP_SETUP
|
||||
#define MESSAGES_SKIP_STRUCTS
|
||||
|
||||
@ -570,6 +736,7 @@ namespace
|
||||
}
|
||||
|
||||
#undef MESSAGE
|
||||
#undef COMMAND
|
||||
#undef QUERY
|
||||
|
||||
void ScriptInterface_impl::RegisterMessages(JSObject* parent)
|
||||
@ -583,13 +750,20 @@ void ScriptInterface_impl::RegisterMessages(JSObject* parent)
|
||||
ret = JS_DefineFunction(m_cx, obj, #name, call_##name, BOOST_PP_SEQ_SIZE((~)vals)-1, \
|
||||
JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT);
|
||||
|
||||
#define COMMAND(name, merge, 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) \
|
||||
ret = JS_DefineFunction(m_cx, obj, #name, call_##name, BOOST_PP_SEQ_SIZE((~)in_vals)-1, \
|
||||
JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT);
|
||||
|
||||
// TODO: #define COMMAND(name, merge, vals) ...
|
||||
|
||||
#undef INCLUDED_MESSAGES
|
||||
|
||||
|
||||
#include "GameInterface/Messages.h"
|
||||
|
||||
#undef MESSAGE
|
||||
#undef COMMAND
|
||||
#undef QUERY
|
||||
}
|
||||
|
||||
|
@ -37,15 +37,23 @@ class wxWindow;
|
||||
class wxString;
|
||||
class wxPanel;
|
||||
|
||||
namespace AtlasMessage { struct mWorldCommand; }
|
||||
typedef void (*SubmitCommand)(AtlasMessage::mWorldCommand* command);
|
||||
|
||||
struct ScriptInterface_impl;
|
||||
class ScriptInterface
|
||||
{
|
||||
public:
|
||||
ScriptInterface();
|
||||
ScriptInterface(SubmitCommand submitCommand);
|
||||
~ScriptInterface();
|
||||
void SetCallbackData(void* cbdata);
|
||||
static void* GetCallbackData(JSContext* cx);
|
||||
|
||||
template <typename T> void SetValue(const wxString& name, const T& val);
|
||||
template <typename T> bool GetValue(const wxString& name, T& ret);
|
||||
void Eval(const wxString& script);
|
||||
template <typename T> bool Eval(const wxString& script, T& ret);
|
||||
|
||||
// Defined elsewhere:
|
||||
// template <TR, T0..., TR (*fptr) (void* cbdata, T0...)>
|
||||
// void RegisterFunction(const char* functionName);
|
||||
@ -59,8 +67,43 @@ public:
|
||||
template <typename T> static bool FromJSVal(JSContext* cx, jsval val, T& ret);
|
||||
template <typename T> static jsval ToJSVal(JSContext* cx, const T& val);
|
||||
private:
|
||||
JSContext* GetContext();
|
||||
void AddRoot(void* ptr);
|
||||
void RemoveRoot(void* ptr);
|
||||
void SetValue_(const wxString& name, jsval val);
|
||||
bool GetValue_(const wxString& name, jsval& ret);
|
||||
bool Eval_(const wxString& name, jsval& ret);
|
||||
|
||||
void Register(const char* name, JSNative fptr, size_t nargs);
|
||||
std::auto_ptr<ScriptInterface_impl> m;
|
||||
|
||||
// The nasty macro/template bits are split into a separate file so you don't have to look at them
|
||||
#include "NativeWrapper.inl"
|
||||
|
||||
template <typename T>
|
||||
void ScriptInterface::SetValue(const wxString& name, const T& val)
|
||||
{
|
||||
return SetValue_(name, ToJSVal(GetContext(), val));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool ScriptInterface::GetValue(const wxString& name, T& ret)
|
||||
{
|
||||
jsval jsRet;
|
||||
if (! GetValue_(name, jsRet)) return false;
|
||||
AddRoot(&jsRet); // root it while we do some more work (TODO: is this really necessary?)
|
||||
bool ok = FromJSVal(GetContext(), jsRet, ret);
|
||||
RemoveRoot(&jsRet);
|
||||
return ok;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool ScriptInterface::Eval(const wxString& script, T& ret)
|
||||
{
|
||||
jsval jsRet;
|
||||
if (! Eval_(script, jsRet)) return false;
|
||||
AddRoot(&jsRet); // root it while we do some more work
|
||||
bool ok = FromJSVal(GetContext(), jsRet, ret);
|
||||
RemoveRoot(&jsRet);
|
||||
return ok;
|
||||
}
|
||||
|
@ -27,7 +27,7 @@
|
||||
#include "ScenarioEditor/Tools/Common/Tools.h"
|
||||
#include "ScenarioEditor/ScenarioEditor.h"
|
||||
#include "ScenarioEditor/Sections/Environment/LightControl.h"
|
||||
#include "ScenarioEditor/Sections/Object/VariationControl.h"
|
||||
//#include "ScenarioEditor/Sections/Object/VariationControl.h"
|
||||
|
||||
#include "GameInterface/Messages.h"
|
||||
|
||||
@ -182,15 +182,20 @@ static void SendToGame(const AtlasMessage::sEnvironmentSettings& settings)
|
||||
POST_COMMAND(SetEnvironmentSettings, (settings));
|
||||
}
|
||||
|
||||
ActorViewer::ActorViewer(wxWindow* parent)
|
||||
ActorViewer::ActorViewer(wxWindow* parent, ScriptInterface& scriptInterface)
|
||||
: wxFrame(parent, wxID_ANY, _("Actor Viewer"), wxDefaultPosition, wxSize(800, 600)),
|
||||
m_CurrentSpeed(0.f), m_BackgroundColour(wxColour(255, 255, 255)),
|
||||
m_ToggledWalking(false), m_ToggledWireframe(false), m_ToggledGround(true),
|
||||
m_ToggledShadows(true), m_ToggledStats(false),
|
||||
m_ObjectSettings(m_ObjectSelection, AtlasMessage::eRenderView::ACTOR)
|
||||
m_ScriptInterface(scriptInterface),
|
||||
m_ObjectSettings(m_ObjectSelection, m_ScriptInterface)
|
||||
{
|
||||
SetIcon(wxIcon(_T("ICON_ActorEditor")));
|
||||
|
||||
// XXX: need to init m_ScriptInterface
|
||||
|
||||
m_ObjectSettings.Init(AtlasMessage::eRenderView::ACTOR);
|
||||
|
||||
SnapSplitterWindow* splitter = new SnapSplitterWindow(this, 0);
|
||||
splitter->SetDefaultSashPosition(250);
|
||||
|
||||
@ -301,7 +306,7 @@ ActorViewer::ActorViewer(wxWindow* parent)
|
||||
wxSizer* bottomRightSizer = new wxBoxSizer(wxVERTICAL);
|
||||
wxSizer* playButtonSizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
wxSizer* optionButtonSizer = new wxBoxSizer(wxVERTICAL);
|
||||
wxSizer* variationSizer = new wxStaticBoxSizer(wxVERTICAL, sidePanel, _("Variation"));
|
||||
// wxSizer* variationSizer = new wxStaticBoxSizer(wxVERTICAL, sidePanel, _("Variation"));
|
||||
|
||||
playButtonSizer->Add(new wxButton(sidePanel, ID_Play, _("Play")), wxSizerFlags().Proportion(1));
|
||||
playButtonSizer->Add(new wxButton(sidePanel, ID_Pause, _("Pause")), wxSizerFlags().Proportion(1));
|
||||
@ -315,7 +320,7 @@ ActorViewer::ActorViewer(wxWindow* parent)
|
||||
optionButtonSizer->Add(Tooltipped(new wxButton(sidePanel, ID_ToggleShadows, _("Shadows")), _("Toggle shadow rendering")), wxSizerFlags().Expand());
|
||||
optionButtonSizer->Add(Tooltipped(new wxButton(sidePanel, ID_ToggleStats, _("Poly count")), _("Toggle polygon-count statistics - turn off ground and shadows for more useful data")), wxSizerFlags().Expand());
|
||||
|
||||
variationSizer->Add(new VariationControl(sidePanel, m_ObjectSettings), wxSizerFlags().Expand().Proportion(1));
|
||||
// variationSizer->Add(new VariationControl(sidePanel, m_ObjectSettings), wxSizerFlags().Expand().Proportion(1));
|
||||
|
||||
mainSizer->Add(m_TreeCtrl, wxSizerFlags().Expand().Proportion(1));
|
||||
mainSizer->Add(bottomSizer, wxSizerFlags().Expand());
|
||||
@ -328,7 +333,7 @@ ActorViewer::ActorViewer(wxWindow* parent)
|
||||
|
||||
bottomRightSizer->Add(m_AnimationBox, wxSizerFlags().Expand());
|
||||
bottomRightSizer->Add(playButtonSizer, wxSizerFlags().Expand());
|
||||
bottomRightSizer->Add(variationSizer, wxSizerFlags().Expand().Proportion(1));
|
||||
// bottomRightSizer->Add(variationSizer, wxSizerFlags().Expand().Proportion(1));
|
||||
|
||||
sidePanel->SetSizer(mainSizer);
|
||||
|
||||
|
@ -25,11 +25,12 @@
|
||||
|
||||
class wxTreeCtrl;
|
||||
class wxTreeEvent;
|
||||
class ScriptInterface;
|
||||
|
||||
class ActorViewer : public wxFrame
|
||||
{
|
||||
public:
|
||||
ActorViewer(wxWindow* parent);
|
||||
ActorViewer(wxWindow* parent, ScriptInterface& scriptInterface);
|
||||
|
||||
private:
|
||||
void SetActorView(bool flushCache = false);
|
||||
@ -49,8 +50,10 @@ private:
|
||||
wxString m_CurrentActor;
|
||||
float m_CurrentSpeed;
|
||||
|
||||
ScriptInterface& m_ScriptInterface;
|
||||
|
||||
Observable<std::vector<AtlasMessage::ObjectID> > m_ObjectSelection;
|
||||
Observable<ObjectSettings> m_ObjectSettings;
|
||||
ObjectSettings m_ObjectSettings;
|
||||
wxColour m_BackgroundColour;
|
||||
bool m_ToggledWireframe, m_ToggledWalking, m_ToggledGround, m_ToggledShadows, m_ToggledStats;
|
||||
|
||||
|
@ -53,7 +53,7 @@ public:
|
||||
template <typename T1>
|
||||
explicit Observable(const T1& a1) : T(a1) {}
|
||||
template <typename T1, typename T2>
|
||||
explicit Observable(T1& a1, T2 a2) : T(a1, a2) {}
|
||||
explicit Observable(T1& a1, T2& a2) : T(a1, a2) {}
|
||||
|
||||
template<typename C> ObservableConnection RegisterObserver(int order, void (C::*callback) (const T&), C* obj)
|
||||
{
|
||||
|
@ -155,6 +155,10 @@ ATLASDLLIMPEXP void Atlas_ReportError()
|
||||
///ReportError(); // janwas: disabled until ErrorReporter.cpp compiles
|
||||
}
|
||||
|
||||
void ScenarioEditorSubmitCommand(AtlasMessage::mWorldCommand* command)
|
||||
{
|
||||
ScenarioEditor::GetCommandProc().Submit(new WorldCommand(command));
|
||||
}
|
||||
|
||||
class AtlasDLLApp : public wxApp
|
||||
{
|
||||
@ -188,7 +192,6 @@ public:
|
||||
wxFrame* frame;
|
||||
#define MAYBE(t) if (g_InitialWindowType == _T(#t)) frame = new t(NULL); else
|
||||
MAYBE(ActorEditor)
|
||||
MAYBE(ActorViewer)
|
||||
MAYBE(ColourTester)
|
||||
#ifdef USE_AOE3ED
|
||||
MAYBE(ArchiveViewer)
|
||||
@ -198,9 +201,14 @@ public:
|
||||
// else
|
||||
if (g_InitialWindowType == _T("ScenarioEditor"))
|
||||
{
|
||||
m_ScriptInterface = new ScriptInterface();
|
||||
m_ScriptInterface = new ScriptInterface(&ScenarioEditorSubmitCommand);
|
||||
frame = new ScenarioEditor(NULL, *m_ScriptInterface);
|
||||
}
|
||||
else if (g_InitialWindowType == _T("ActorViewer"))
|
||||
{
|
||||
m_ScriptInterface = new ScriptInterface(&ScenarioEditorSubmitCommand);
|
||||
frame = new ActorViewer(NULL, *m_ScriptInterface);
|
||||
}
|
||||
else
|
||||
{
|
||||
wxFAIL_MSG(_("Internal error: invalid window type"));
|
||||
|
@ -30,8 +30,8 @@
|
||||
#include "General/AtlasEventLoop.h"
|
||||
#include "General/Datafile.h"
|
||||
|
||||
#include "HighResTimer/HighResTimer.h"
|
||||
#include "Buttons/ToolButton.h"
|
||||
#include "CustomControls/HighResTimer/HighResTimer.h"
|
||||
#include "CustomControls/Buttons/ToolButton.h"
|
||||
#include "CustomControls/Canvas/Canvas.h"
|
||||
|
||||
#include "GameInterface/MessagePasser.h"
|
||||
@ -295,11 +295,18 @@ AtlasWindowCommandProc& ScenarioEditor::GetCommandProc() { return g_CommandProc;
|
||||
|
||||
namespace
|
||||
{
|
||||
// Wrapper function because SetCurrentTool takes an optional argument, which JS doesn't like
|
||||
void SetCurrentTool_script(void* cbdata, wxString name)
|
||||
// Wrapper functions for scripts
|
||||
|
||||
void SetCurrentTool_(void* cbdata, wxString name)
|
||||
{
|
||||
static_cast<ScenarioEditor*>(cbdata)->GetToolManager().SetCurrentTool(name);
|
||||
}
|
||||
|
||||
void SetCurrentToolWith(void* cbdata, wxString name, wxString arg)
|
||||
{
|
||||
static_cast<ScenarioEditor*>(cbdata)->GetToolManager().SetCurrentTool(name, &arg);
|
||||
}
|
||||
|
||||
wxString GetDataDirectory(void*)
|
||||
{
|
||||
return Datafile::GetDataDirectory();
|
||||
@ -319,7 +326,7 @@ namespace
|
||||
ScenarioEditor::ScenarioEditor(wxWindow* parent, ScriptInterface& scriptInterface)
|
||||
: wxFrame(parent, wxID_ANY, _T(""), wxDefaultPosition, wxSize(1024, 768))
|
||||
, m_FileHistory(_T("Scenario Editor")), m_ScriptInterface(scriptInterface)
|
||||
, m_ObjectSettings(g_SelectedObjects, AtlasMessage::eRenderView::GAME)
|
||||
, m_ObjectSettings(g_SelectedObjects, m_ScriptInterface)
|
||||
, m_ToolManager(this)
|
||||
{
|
||||
// Global application initialisation:
|
||||
@ -338,7 +345,8 @@ ScenarioEditor::ScenarioEditor(wxWindow* parent, ScriptInterface& scriptInterfac
|
||||
// Script interface functions
|
||||
GetScriptInterface().SetCallbackData(static_cast<void*>(this));
|
||||
GetScriptInterface().RegisterFunction<wxString, GetDataDirectory>("GetDataDirectory");
|
||||
GetScriptInterface().RegisterFunction<void, wxString, SetCurrentTool_script>("SetCurrentTool");
|
||||
GetScriptInterface().RegisterFunction<void, wxString, SetCurrentTool_>("SetCurrentTool");
|
||||
GetScriptInterface().RegisterFunction<void, wxString, wxString, SetCurrentToolWith>("SetCurrentToolWith");
|
||||
GetScriptInterface().RegisterFunction<void, float, SetBrushStrength>("SetBrushStrength");
|
||||
GetScriptInterface().RegisterFunction<void, wxString, SetSelectedTexture>("SetSelectedTexture");
|
||||
|
||||
@ -353,6 +361,9 @@ ScenarioEditor::ScenarioEditor(wxWindow* parent, ScriptInterface& scriptInterfac
|
||||
GetScriptInterface().LoadScript(filename.GetFullName(), script);
|
||||
}
|
||||
|
||||
// Initialise things that rely on scripts
|
||||
m_ObjectSettings.Init(AtlasMessage::eRenderView::GAME);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Menu
|
||||
|
||||
|
@ -58,7 +58,7 @@ public:
|
||||
static float GetSpeedModifier();
|
||||
|
||||
ScriptInterface& GetScriptInterface() const { return m_ScriptInterface; }
|
||||
Observable<ObjectSettings>& GetObjectSettings() { return m_ObjectSettings; }
|
||||
ObjectSettings& GetObjectSettings() { return m_ObjectSettings; }
|
||||
|
||||
ToolManager& GetToolManager() { return m_ToolManager; }
|
||||
|
||||
|
@ -22,13 +22,12 @@
|
||||
|
||||
#include "SectionLayout.h"
|
||||
|
||||
#include "SnapSplitterWindow/SnapSplitterWindow.h"
|
||||
#include "CustomControls/SnapSplitterWindow/SnapSplitterWindow.h"
|
||||
|
||||
#include "ScenarioEditor.h"
|
||||
#include "AtlasScript/ScriptInterface.h"
|
||||
|
||||
#include "Sections/Terrain/Terrain.h"
|
||||
#include "Sections/Object/Object.h"
|
||||
#include "Sections/Environment/Environment.h"
|
||||
#include "Sections/Cinematic/Cinematic.h"
|
||||
#include "Sections/Trigger/Trigger.h"
|
||||
@ -317,7 +316,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(ObjectSidebar, _T("object.png"), _("Object"));
|
||||
ADD_SIDEBAR_SCRIPT(_T("object"), _T("object.png"), _("Object"));
|
||||
ADD_SIDEBAR(EnvironmentSidebar, _T("environment.png"), _("Environment"));
|
||||
|
||||
#ifndef ATLAS_PUBLIC_RELEASE
|
||||
|
@ -1,208 +0,0 @@
|
||||
/* Copyright (C) 2009 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "precompiled.h"
|
||||
|
||||
#include "Object.h"
|
||||
|
||||
#include "Buttons/ToolButton.h"
|
||||
#include "ScenarioEditor/ScenarioEditor.h"
|
||||
#include "ScenarioEditor/Tools/Common/ObjectSettings.h"
|
||||
#include "ScenarioEditor/Tools/Common/MiscState.h"
|
||||
#include "VariationControl.h"
|
||||
|
||||
#include "GameInterface/Messages.h"
|
||||
|
||||
#include "wx/busyinfo.h"
|
||||
|
||||
class ObjectSelectListBox : public wxListBox
|
||||
{
|
||||
public:
|
||||
ObjectSelectListBox(wxWindow* parent, ToolManager& toolManager)
|
||||
: wxListBox(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0, NULL, wxLB_SINGLE|wxLB_HSCROLL)
|
||||
, m_ToolManager(toolManager)
|
||||
{
|
||||
}
|
||||
|
||||
void OnSelect(wxCommandEvent& evt)
|
||||
{
|
||||
// On selecting an object, enable the PlaceObject tool with this object
|
||||
wxString id = static_cast<wxStringClientData*>(evt.GetClientObject())->GetData();
|
||||
m_ToolManager.SetCurrentTool(_T("PlaceObject"), &id);
|
||||
}
|
||||
|
||||
private:
|
||||
ToolManager& m_ToolManager;
|
||||
DECLARE_EVENT_TABLE();
|
||||
};
|
||||
BEGIN_EVENT_TABLE(ObjectSelectListBox, wxListBox)
|
||||
EVT_LISTBOX(wxID_ANY, ObjectSelectListBox::OnSelect)
|
||||
END_EVENT_TABLE();
|
||||
|
||||
|
||||
class ObjectChoiceCtrl : public wxChoice
|
||||
{
|
||||
public:
|
||||
ObjectChoiceCtrl(wxWindow* parent, const wxArrayString& strings, ObjectSidebar& sidebar)
|
||||
: wxChoice(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, strings),
|
||||
m_Sidebar(sidebar)
|
||||
{
|
||||
SetSelection(0);
|
||||
}
|
||||
|
||||
void OnSelect(wxCommandEvent& evt)
|
||||
{
|
||||
// Switch between displayed lists of objects (e.g. entities vs actors)
|
||||
m_Sidebar.SetObjectFilter(evt.GetSelection());
|
||||
}
|
||||
|
||||
private:
|
||||
ObjectSidebar& m_Sidebar;
|
||||
|
||||
DECLARE_EVENT_TABLE();
|
||||
};
|
||||
BEGIN_EVENT_TABLE(ObjectChoiceCtrl, wxChoice)
|
||||
EVT_CHOICE(wxID_ANY, ObjectChoiceCtrl::OnSelect)
|
||||
END_EVENT_TABLE();
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
class ObjectBottomBar : public wxPanel
|
||||
{
|
||||
public:
|
||||
ObjectBottomBar(wxWindow* parent, Observable<ObjectSettings>& objectSettings);
|
||||
};
|
||||
|
||||
struct ObjectSidebarImpl
|
||||
{
|
||||
ObjectSidebarImpl() : m_BottomBar(NULL), m_ObjectListBox(NULL) { }
|
||||
wxWindow* m_BottomBar;
|
||||
wxListBox* m_ObjectListBox;
|
||||
std::vector<AtlasMessage::sObjectsListItem> m_Objects;
|
||||
};
|
||||
|
||||
ObjectSidebar::ObjectSidebar(ScenarioEditor& scenarioEditor, wxWindow* sidebarContainer, wxWindow* bottomBarContainer)
|
||||
: Sidebar(scenarioEditor, sidebarContainer, bottomBarContainer), p(new ObjectSidebarImpl())
|
||||
{
|
||||
wxArrayString strings;
|
||||
strings.Add(_("Entities"));
|
||||
strings.Add(_("Actors (all)"));
|
||||
m_MainSizer->Add(new ObjectChoiceCtrl(this, strings, *this), wxSizerFlags().Expand());
|
||||
|
||||
p->m_ObjectListBox = new ObjectSelectListBox(this, scenarioEditor.GetToolManager());
|
||||
m_MainSizer->Add(p->m_ObjectListBox, wxSizerFlags().Proportion(1).Expand());
|
||||
|
||||
m_BottomBar = new ObjectBottomBar(bottomBarContainer, scenarioEditor.GetObjectSettings());
|
||||
}
|
||||
|
||||
ObjectSidebar::~ObjectSidebar()
|
||||
{
|
||||
delete p;
|
||||
}
|
||||
|
||||
void ObjectSidebar::OnFirstDisplay()
|
||||
{
|
||||
wxBusyInfo busy (_("Loading list of objects"));
|
||||
|
||||
// Get the list of objects from the game
|
||||
AtlasMessage::qGetObjectsList qry;
|
||||
qry.Post();
|
||||
p->m_Objects = *qry.objects;
|
||||
// Display first group of objects
|
||||
SetObjectFilter(0);
|
||||
}
|
||||
|
||||
void ObjectSidebar::SetObjectFilter(int type)
|
||||
{
|
||||
p->m_ObjectListBox->Freeze();
|
||||
p->m_ObjectListBox->Clear();
|
||||
for (std::vector<AtlasMessage::sObjectsListItem>::iterator it = p->m_Objects.begin(); it != p->m_Objects.end(); ++it)
|
||||
{
|
||||
if (it->type == type)
|
||||
{
|
||||
wxString id = it->id.c_str();
|
||||
wxString name = it->name.c_str();
|
||||
p->m_ObjectListBox->Append(name, new wxStringClientData(id));
|
||||
}
|
||||
}
|
||||
p->m_ObjectListBox->Thaw();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class PlayerComboBox : public wxComboBox
|
||||
{
|
||||
public:
|
||||
PlayerComboBox(wxWindow* parent, wxArrayString& choices, Observable<ObjectSettings>& objectSettings)
|
||||
: wxComboBox(parent, -1, choices[objectSettings.GetPlayerID()], wxDefaultPosition, wxDefaultSize, choices, wxCB_READONLY)
|
||||
, m_ObjectSettings(objectSettings)
|
||||
{
|
||||
m_Conn = m_ObjectSettings.RegisterObserver(1, &PlayerComboBox::OnObjectSettingsChange, this);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
ObservableScopedConnection m_Conn;
|
||||
Observable<ObjectSettings>& m_ObjectSettings;
|
||||
|
||||
void OnObjectSettingsChange(const ObjectSettings& settings)
|
||||
{
|
||||
SetSelection((long)settings.GetPlayerID());
|
||||
}
|
||||
|
||||
void OnSelect(wxCommandEvent& evt)
|
||||
{
|
||||
m_ObjectSettings.SetPlayerID(evt.GetInt());
|
||||
m_ObjectSettings.NotifyObserversExcept(m_Conn);
|
||||
}
|
||||
|
||||
DECLARE_EVENT_TABLE();
|
||||
};
|
||||
BEGIN_EVENT_TABLE(PlayerComboBox, wxComboBox)
|
||||
EVT_COMBOBOX(wxID_ANY, PlayerComboBox::OnSelect)
|
||||
END_EVENT_TABLE();
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
ObjectBottomBar::ObjectBottomBar(wxWindow* parent, Observable<ObjectSettings>& objectSettings)
|
||||
: wxPanel(parent, wxID_ANY)
|
||||
{
|
||||
wxSizer* sizer = new wxBoxSizer(wxVERTICAL);
|
||||
|
||||
wxArrayString players;
|
||||
// TODO: get proper player names
|
||||
players.Add(_("Gaia"));
|
||||
players.Add(_("Player 1"));
|
||||
players.Add(_("Player 2"));
|
||||
players.Add(_("Player 3"));
|
||||
players.Add(_("Player 4"));
|
||||
players.Add(_("Player 5"));
|
||||
players.Add(_("Player 6"));
|
||||
players.Add(_("Player 7"));
|
||||
players.Add(_("Player 8"));
|
||||
wxComboBox* playerSelect = new PlayerComboBox(this, players, objectSettings);
|
||||
sizer->Add(playerSelect);
|
||||
|
||||
wxWindow* variationSelect = new VariationControl(this, objectSettings);
|
||||
variationSelect->SetMinSize(wxSize(160, -1));
|
||||
wxSizer* variationSizer = new wxStaticBoxSizer(wxVERTICAL, this, _("Variation"));
|
||||
variationSizer->Add(variationSelect, wxSizerFlags().Proportion(1).Expand());
|
||||
sizer->Add(variationSizer, wxSizerFlags().Proportion(1));
|
||||
|
||||
SetSizer(sizer);
|
||||
}
|
@ -1,33 +0,0 @@
|
||||
/* Copyright (C) 2009 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "../Common/Sidebar.h"
|
||||
|
||||
struct ObjectSidebarImpl;
|
||||
class ObjectSidebar : public Sidebar
|
||||
{
|
||||
public:
|
||||
ObjectSidebar(ScenarioEditor& scenarioEditor, wxWindow* sidebarContainer, wxWindow* bottomBarContainer);
|
||||
~ObjectSidebar();
|
||||
void SetObjectFilter(int type);
|
||||
|
||||
protected:
|
||||
virtual void OnFirstDisplay();
|
||||
|
||||
private:
|
||||
ObjectSidebarImpl* p;
|
||||
};
|
@ -1,146 +0,0 @@
|
||||
/* Copyright (C) 2009 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "precompiled.h"
|
||||
|
||||
#include "VariationControl.h"
|
||||
|
||||
#include "ScenarioEditor/Tools/Common/ObjectSettings.h"
|
||||
|
||||
VariationControl::VariationControl(wxWindow* parent, Observable<ObjectSettings>& objectSettings)
|
||||
: wxScrolledWindow(parent, -1),
|
||||
m_ObjectSettings(objectSettings)
|
||||
{
|
||||
m_Conn = m_ObjectSettings.RegisterObserver(1, &VariationControl::OnObjectSettingsChange, this);
|
||||
|
||||
SetScrollRate(0, 5);
|
||||
|
||||
m_Sizer = new wxBoxSizer(wxVERTICAL);
|
||||
SetSizer(m_Sizer);
|
||||
}
|
||||
|
||||
// Event handler shared by all the combo boxes created by this window
|
||||
void VariationControl::OnSelect(wxCommandEvent& evt)
|
||||
{
|
||||
std::set<wxString> selections;
|
||||
|
||||
// It's possible for a variant name to appear in multiple groups.
|
||||
// If so, assume that all the names in each group are the same, so
|
||||
// we don't have to worry about some impossible combinations (e.g.
|
||||
// one group "a,b", a second "b,c", and a third "c,a", where's there's
|
||||
// no set of selections that matches one (and only one) of each group).
|
||||
//
|
||||
// So... When a combo box is changed from 'a' to 'b', add 'b' to the new
|
||||
// selections and make sure any other combo boxes containing both 'a' and
|
||||
// 'b' no longer contain 'a'.
|
||||
|
||||
wxComboBox* thisComboBox = wxDynamicCast(evt.GetEventObject(), wxComboBox);
|
||||
wxCHECK(thisComboBox != NULL, );
|
||||
wxString newValue = thisComboBox->GetValue();
|
||||
|
||||
selections.insert(newValue);
|
||||
|
||||
for (size_t i = 0; i < m_ComboBoxes.size(); ++i)
|
||||
{
|
||||
wxComboBox* comboBox = m_ComboBoxes[i];
|
||||
// If our newly selected value is used in another combobox, we want
|
||||
// that combobox to use the new value, so don't add its old value
|
||||
// to the list of selections
|
||||
if (comboBox->FindString(newValue) == wxNOT_FOUND)
|
||||
selections.insert(comboBox->GetValue());
|
||||
}
|
||||
|
||||
m_ObjectSettings.SetActorSelections(selections);
|
||||
m_ObjectSettings.NotifyObserversExcept(m_Conn);
|
||||
RefreshObjectSettings();
|
||||
}
|
||||
|
||||
void VariationControl::OnObjectSettingsChange(const ObjectSettings& settings)
|
||||
{
|
||||
Freeze();
|
||||
|
||||
const std::vector<ObjectSettings::Group>& variation = settings.GetActorVariation();
|
||||
|
||||
// Creating combo boxes seems to be pretty expensive - so we create as
|
||||
// few as possible, by never deleting any.
|
||||
|
||||
size_t oldCount = m_ComboBoxes.size();
|
||||
size_t newCount = variation.size();
|
||||
|
||||
// If we have too many combo boxes, hide the excess ones
|
||||
for (size_t i = newCount; i < oldCount; ++i)
|
||||
{
|
||||
m_ComboBoxes[i]->Show(false);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < variation.size(); ++i)
|
||||
{
|
||||
const ObjectSettings::Group& group = variation[i];
|
||||
|
||||
if (i < oldCount)
|
||||
{
|
||||
// Already got enough boxes available, so use an old one
|
||||
wxComboBox* comboBox = m_ComboBoxes[i];
|
||||
// Replace the contents of the old combobox with the new data
|
||||
comboBox->Freeze();
|
||||
comboBox->Clear();
|
||||
comboBox->Append(group.variants);
|
||||
comboBox->SetValue(group.chosen);
|
||||
comboBox->Show(true);
|
||||
comboBox->Thaw();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Create an initially empty combobox, because we can fill it
|
||||
// quicker than the default constructor can
|
||||
wxComboBox* combo = new wxComboBox(this, -1, wxEmptyString, wxDefaultPosition,
|
||||
wxSize(80, wxDefaultCoord), wxArrayString(), wxCB_READONLY);
|
||||
// Freeze it before adding all the values
|
||||
combo->Freeze();
|
||||
combo->Append(group.variants);
|
||||
combo->SetValue(group.chosen);
|
||||
combo->Thaw();
|
||||
// Add the on-select event handler
|
||||
combo->Connect(wxID_ANY, wxEVT_COMMAND_COMBOBOX_SELECTED,
|
||||
wxCommandEventHandler(VariationControl::OnSelect), NULL, this);
|
||||
// Add box to sizer and list
|
||||
m_Sizer->Add(combo, wxSizerFlags().Expand());
|
||||
m_ComboBoxes.push_back(combo);
|
||||
}
|
||||
}
|
||||
|
||||
Layout();
|
||||
|
||||
Thaw();
|
||||
|
||||
// Make the scrollbars appear when appropriate
|
||||
FitInside();
|
||||
}
|
||||
|
||||
void VariationControl::RefreshObjectSettings()
|
||||
{
|
||||
const std::vector<ObjectSettings::Group>& variation = m_ObjectSettings.GetActorVariation();
|
||||
|
||||
// For each group, set the corresponding combobox's value to the chosen one
|
||||
size_t i = 0;
|
||||
for (std::vector<ObjectSettings::Group>::const_iterator group = variation.begin();
|
||||
group != variation.end() && i < m_ComboBoxes.size();
|
||||
++group, ++i)
|
||||
{
|
||||
m_ComboBoxes[i]->SetValue(group->chosen);
|
||||
}
|
||||
}
|
@ -1,42 +0,0 @@
|
||||
/* Copyright (C) 2009 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 0 A.D. is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef INCLUDED_VARIATIONCONTROL
|
||||
#define INCLUDED_VARIATIONCONTROL
|
||||
|
||||
#include "General/Observable.h"
|
||||
|
||||
class ObjectSettings;
|
||||
|
||||
class VariationControl : public wxScrolledWindow
|
||||
{
|
||||
public:
|
||||
VariationControl(wxWindow* parent, Observable<ObjectSettings>& objectSettings);
|
||||
|
||||
private:
|
||||
void OnSelect(wxCommandEvent& evt);
|
||||
void OnObjectSettingsChange(const ObjectSettings& settings);
|
||||
void RefreshObjectSettings();
|
||||
|
||||
ObservableScopedConnection m_Conn;
|
||||
|
||||
Observable<ObjectSettings>& m_ObjectSettings;
|
||||
std::vector<wxComboBox*> m_ComboBoxes;
|
||||
wxSizer* m_Sizer;
|
||||
};
|
||||
|
||||
#endif // INCLUDED_VARIATIONCONTROL
|
@ -21,133 +21,42 @@
|
||||
|
||||
#include "GameInterface/Messages.h"
|
||||
#include "ScenarioEditor/ScenarioEditor.h"
|
||||
#include "AtlasScript/ScriptInterface.h"
|
||||
|
||||
ObjectSettings::ObjectSettings(Observable<std::vector<AtlasMessage::ObjectID> >& selectedObjects, int view)
|
||||
: m_PlayerID(0), m_SelectedObjects(selectedObjects), m_View(view)
|
||||
ObjectSettings::ObjectSettings(Observable<std::vector<AtlasMessage::ObjectID> >& selectedObjects, ScriptInterface& scriptInterface)
|
||||
: m_ScriptInterface(scriptInterface)
|
||||
{
|
||||
m_Conn = m_SelectedObjects.RegisterObserver(0, &ObjectSettings::OnSelectionChange, this);
|
||||
m_Conn = selectedObjects.RegisterObserver(0, &ObjectSettings::OnSelectionChange, this);
|
||||
}
|
||||
|
||||
size_t ObjectSettings::GetPlayerID() const
|
||||
void ObjectSettings::Init(int view)
|
||||
{
|
||||
return m_PlayerID;
|
||||
m_ScriptInterface.SetValue(_T("Atlas.State.objectSettings.view"), view);
|
||||
}
|
||||
|
||||
void ObjectSettings::SetPlayerID(int playerID)
|
||||
{
|
||||
m_PlayerID = playerID;
|
||||
PostToGame();
|
||||
}
|
||||
|
||||
const std::set<wxString>& ObjectSettings::GetActorSelections() const
|
||||
{
|
||||
return m_ActorSelections;
|
||||
}
|
||||
|
||||
void ObjectSettings::SetActorSelections(const std::set<wxString>& selections)
|
||||
{
|
||||
m_ActorSelections = selections;
|
||||
PostToGame();
|
||||
}
|
||||
|
||||
const std::vector<ObjectSettings::Group> ObjectSettings::GetActorVariation() const
|
||||
{
|
||||
std::vector<Group> variation;
|
||||
|
||||
for (std::vector<wxArrayString>::const_iterator grp = m_VariantGroups.begin();
|
||||
grp != m_VariantGroups.end();
|
||||
++grp)
|
||||
{
|
||||
Group group;
|
||||
group.variants = *grp;
|
||||
|
||||
// Variant choice method, as used by the game: Choose the first variant
|
||||
// which matches any of the selections
|
||||
|
||||
size_t chosen = 0; // default to first
|
||||
for (size_t i = 0; i < grp->GetCount(); ++i)
|
||||
{
|
||||
if (m_ActorSelections.find(grp->Item(i)) != m_ActorSelections.end())
|
||||
{
|
||||
chosen = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
group.chosen = grp->Item(chosen);
|
||||
|
||||
variation.push_back(group);
|
||||
}
|
||||
|
||||
return variation;
|
||||
m_ScriptInterface.SetValue(_T("Atlas.State.objectSettings.playerID"), playerID);
|
||||
}
|
||||
|
||||
AtlasMessage::sObjectSettings ObjectSettings::GetSettings() const
|
||||
{
|
||||
AtlasMessage::sObjectSettings settings;
|
||||
|
||||
settings.player = m_PlayerID;
|
||||
|
||||
// Copy selections from set into vector
|
||||
std::vector<std::wstring> selections;
|
||||
for (std::set<wxString>::const_iterator it = m_ActorSelections.begin();
|
||||
it != m_ActorSelections.end();
|
||||
++it)
|
||||
{
|
||||
selections.push_back(it->c_str());
|
||||
}
|
||||
settings.selections = selections;
|
||||
|
||||
bool ok = m_ScriptInterface.Eval(_T("Atlas.State.objectSettings.toSObjectSettings()"), settings);
|
||||
wxASSERT(ok);
|
||||
return settings;
|
||||
}
|
||||
|
||||
void ObjectSettings::OnSelectionChange(const std::vector<AtlasMessage::ObjectID>& selection)
|
||||
{
|
||||
// TODO: what would be the sensible action if nothing's selected?
|
||||
// and if multiple objects are selected?
|
||||
// Convert to ints so they can be passed to JS
|
||||
std::vector<int> objs (selection.begin(), selection.end());
|
||||
|
||||
if (selection.empty())
|
||||
return;
|
||||
|
||||
AtlasMessage::qGetObjectSettings qry (m_View, selection[0]);
|
||||
qry.Post();
|
||||
|
||||
m_PlayerID = qry.settings->player;
|
||||
|
||||
m_ActorSelections.clear();
|
||||
m_VariantGroups.clear();
|
||||
|
||||
std::vector<std::vector<std::wstring> > variation = *qry.settings->variantgroups;
|
||||
for (std::vector<std::vector<std::wstring> >::iterator grp = variation.begin();
|
||||
grp != variation.end();
|
||||
++grp)
|
||||
{
|
||||
wxArrayString variants;
|
||||
|
||||
for (std::vector<std::wstring>::iterator it = grp->begin();
|
||||
it != grp->end();
|
||||
++it)
|
||||
{
|
||||
variants.Add(it->c_str());
|
||||
}
|
||||
|
||||
m_VariantGroups.push_back(variants);
|
||||
}
|
||||
|
||||
std::vector<std::wstring> selections = *qry.settings->selections;
|
||||
for (std::vector<std::wstring>::iterator sel = selections.begin();
|
||||
sel != selections.end();
|
||||
++sel)
|
||||
{
|
||||
m_ActorSelections.insert(sel->c_str());
|
||||
}
|
||||
|
||||
static_cast<Observable<ObjectSettings>*>(this)->NotifyObservers();
|
||||
m_ScriptInterface.SetValue(_T("Atlas.State.objectSettings.selectedObjects"), objs);
|
||||
m_ScriptInterface.Eval(_T("Atlas.State.objectSettings.onSelectionChange()"));
|
||||
}
|
||||
|
||||
void ObjectSettings::PostToGame()
|
||||
void ObjectSettings::NotifyObservers()
|
||||
{
|
||||
if (m_SelectedObjects.empty())
|
||||
return;
|
||||
|
||||
POST_COMMAND(SetObjectSettings, (m_View, m_SelectedObjects[0], GetSettings()));
|
||||
m_ScriptInterface.Eval(_T("Atlas.State.objectSettings.notifyObservers()"));
|
||||
}
|
||||
|
@ -19,62 +19,37 @@
|
||||
#define INCLUDED_OBJECTSETTINGS
|
||||
|
||||
#include <vector>
|
||||
#include <set>
|
||||
|
||||
#include "ScenarioEditor/Tools/Common/MiscState.h"
|
||||
|
||||
class ScriptInterface;
|
||||
|
||||
namespace AtlasMessage
|
||||
{
|
||||
struct sObjectSettings;
|
||||
}
|
||||
|
||||
// Various settings to be applied to newly created units, or to the currently
|
||||
// selected unit. If a unit is selected or being previewed, it should match
|
||||
// these settings.
|
||||
// This class is now just an interface to the JS Atlas.State.objectSettings,
|
||||
// for old C++ code that hasn't been ported to JS yet.
|
||||
class ObjectSettings
|
||||
{
|
||||
public:
|
||||
ObjectSettings(Observable<std::vector<AtlasMessage::ObjectID> >& selectedObjects, int view);
|
||||
ObjectSettings(Observable<std::vector<AtlasMessage::ObjectID> >& selectedObjects, ScriptInterface& scriptInterface);
|
||||
void Init(int view);
|
||||
|
||||
size_t GetPlayerID() const;
|
||||
void SetPlayerID(int playerID);
|
||||
|
||||
struct Group
|
||||
{
|
||||
wxArrayString variants;
|
||||
wxString chosen;
|
||||
};
|
||||
|
||||
const std::vector<Group> GetActorVariation() const;
|
||||
|
||||
const std::set<wxString>& GetActorSelections() const;
|
||||
void SetActorSelections(const std::set<wxString>& selections);
|
||||
|
||||
// Constructs new sObjectSettings object from settings
|
||||
AtlasMessage::sObjectSettings GetSettings() const;
|
||||
|
||||
void NotifyObservers();
|
||||
|
||||
private:
|
||||
Observable<std::vector<AtlasMessage::ObjectID> >& m_SelectedObjects;
|
||||
|
||||
int m_View;
|
||||
|
||||
// 0 = gaia, 1..inf = normal players
|
||||
size_t m_PlayerID;
|
||||
|
||||
// Set of user-chosen actor selections, potentially a superset of any single
|
||||
// actor's possible variants (since it doesn't get reset if you select
|
||||
// a new actor, and will accumulate variant names)
|
||||
std::set<wxString> m_ActorSelections;
|
||||
|
||||
// List of actor variant groups (each a list of variant names)
|
||||
std::vector<wxArrayString> m_VariantGroups;
|
||||
ScriptInterface& m_ScriptInterface;
|
||||
|
||||
// Observe changes to unit selection
|
||||
ObservableScopedConnection m_Conn;
|
||||
void OnSelectionChange(const std::vector<AtlasMessage::ObjectID>& selection);
|
||||
|
||||
// Transfer current settings to the currently selected unit (if any)
|
||||
void PostToGame();
|
||||
};
|
||||
|
||||
#endif // INCLUDED_OBJECTSETTINGS
|
||||
|
Loading…
Reference in New Issue
Block a user