Skip to content
greenboxal edited this page Nov 24, 2012 · 7 revisions

This is a work in progress.

FimbulwinterClient GUI is based on Awesomium, a hacked source of Chromium which is the base of the Google Chrome browser. So yes, the GUI is pure HTML5, CSS3 and JavaScript.

In this document, the Controller and Model logic(C++) is referred as 'server-side', View and ViewModel logic(JavaScript, HTML, CSS) is referred as 'client-side'.

How it works?

Like in Chromium, all scripting and rendering logic is done in another process to prevent the GUI to crash the whole game and to provide premium load balancing between CPUs.

Our GUI uses RocketMVVM, a Model-View-ViewModel implementation created specifically to FimbulwinterClient. In this case the controller and the model is written in C++ and the View and the ViewModel in HTML and JavaScript.

Windows

Windows are created using jQuery UI dialog, refer to jQuery UI documentation for more information.

RocketMVVM

RocketMVVM has two basic concepts: observable values and computed values. Observable values are ordinary variables that when changed fires an event notifying the change. Computed values are functions that consumes one or more values from the current ViewModel, it value is computed each time that some of their dependencies notifies that was changed.

The ViewModel object

The core of RocketMVVM is the ViewModel object.

ModelView constructor takes one argument describing it fields.

var exampleViewModel = new mvvm.ViewModel(function() {
    this.name = mvvm.observable('');
    this.level = mvvm.observable(0);

    this.description = mvvm.computed(function() {
        return this.name() + ', level ' + this.level() + '.';
    }, this, ['name', 'level']);

    this.select: function() {
        alert('You choose ' + this.description() + '.');
    }
});

Binding data

The ViewModel object has the applyBindings function.

JavaScript

$(function() {
    $("#testWindow").dialog();
    exampleViewModel.applyBindings($("#testWindow"));
});

HTML

<div id="testWindow">
  <p>Name: <span data-bind="text: name" /></p>
  <p>Level: <span data-bind="text: level" /></p>
  <p>Description: <span data-bind="text: description" /></p>
  <form>
    <p><input data-bind="value: name" /></p>
    <p><input data-bind="value: level" /></p>
    <p><button data-bind="click: select">Select</button></p>
  </form>
</div>

Updating from client-side

To update ViewModel data, you use the update function.

exampleViewModel.update({ name: 'John Doe', level: 33 });

Updating from server-side

This is the most common case, first we need to create a server-side ViewModel matching the client-side one.

#include <Ragnarok/Gui/RocketMVVM.h>

class TestViewModel : public RocketMVVM::ViewModel
{
public:
    MVVM_FIELD_STR(Name, "name");
    MVVM_FIELD(Level, "level", int);
}

Then we need to register a function on a global object that will receive the client-side ViewModel instance.

static TestViewModel TestModel;

void RegisterObjects()
{
    GuiManager *gui = GuiManager::Instance();

    JSObject globalObject = gui->View()->CreateGlobalJavascriptObject("Application.Test").ToObject();
gui->Dispatcher()->BindAsync(globalObject, "SetTestProxy", JSDispatcher::AsyncFunction([&] (const JSArray &args) {
        TestModel.SetProxy(args[0].ToObject());
    }));
}

Then you use TestViewModel::SetX and ViewModel::Update functions.

void UpdateData()
{
    TestModel.SetName("John Doe");
    TestModel.SetLevel(33);
    TestModel.Update();
}

To bind a client-side ViewMode to the server-side one, you call:

Application.Test.SetTestProxy(exampleViewModel);