You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
openmw-tes3mp/gui/gui.d

322 lines
7.3 KiB
D

/*
OpenMW - The completely unofficial reimplementation of Morrowind
Copyright (C) 2008-2009 Nicolay Korslund
Email: < korslund@gmail.com >
WWW: http://openmw.snaptoad.com/
This file (gui.d) is part of the OpenMW package.
OpenMW is distributed as free software: you can redistribute it
and/or modify it under the terms of the GNU General Public License
version 3, as published by the Free Software Foundation.
This program 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
version 3 along with this program. If not, see
http://www.gnu.org/licenses/ .
*/
module gui.gui;
import monster.monster;
import monster.vm.mclass;
import monster.modules.console;
import gui.bindings;
import bullet.bindings;
import std.string;
import std.stdio;
// Widget class and gui module
MonsterClass
gmc, // GUI module
wid_mc, // Widget
but_mc, // Button
tex_mc, // StaticText
img_mc, // StaticImage
pro_mc, // Progress
win_mc; // Window
MWidget[WidgetPtr] gui_store;
class MWidget
{
WidgetPtr widget;
MonsterObject *mo;
// Used for layouts
bool isLayout;
char[] prefix;
// For layouts
this(char[] layout, WidgetPtr parent = null)
{
assert(layout.length);
isLayout = true;
prefix = format("%s", cast(void*)this);
widget = gui_loadLayout(layout.toStringz(), prefix.toStringz(), parent);
if(widget is null)
fail("Layout " ~ layout ~ " is empty");
this();
}
// For normal widgets
this(WidgetPtr w)
{
isLayout = false;
widget = w;
assert(widget !is null);
this();
}
private this()
{
assert(widget !is null);
// Create the object from the right class
mo = toClass(widget).createObject();
// But store the pointer in the Widget's pointer slot
mo.getExtra(wid_mc).obj = this;
// Also store a lookup for later
gui_store[widget] = this;
}
MWidget getChild(char[] name)
{
if(prefix.length)
name = prefix ~ name;
// Get the child widget
auto pt = gui_getChild(widget, name.toStringz());
if(pt is null)
fail("Widget has no child named " ~ name);
// Return the MWidget
return get(pt);
}
// Return the MonsterClass corresponding to a given widget.
private static MonsterClass toClass(WidgetPtr p)
{
switch(widgetType(p))
{
/*
case "Button": return but_mc;
case "StaticText": return tex_mc;
case "StaticImage": return img_mc;
case "Progress": return pro_mc;
case "Window": return win_mc;
*/
default:
// Use "Widget" for all unimplemented types
case "Widget": return wid_mc;
}
}
// Get the MWidget (and associatied MonsterObject) corresponding to
// a given Widget.
static MWidget get(WidgetPtr wid)
{
// First, check if the instance exists
auto p = wid in gui_store;
if(p) return *p;
// No MWidget exists. We have to create one.
return new MWidget(wid);
}
};
char[] widgetType(WidgetPtr p)
{
return toString(gui_widgetType(p));
}
MWidget getMWOwner(MonsterObject *mo)
{
return (cast(MWidget)mo.getExtra(wid_mc).obj);
}
MWidget getMWOwner()
{
return getMWOwner(params.obj());
}
WidgetPtr getOwner(MonsterObject *mo)
{
return getMWOwner(mo).widget;
}
WidgetPtr getOwner()
{
return getMWOwner().widget;
}
// Widget functions
void setCaption()
{
AIndex[] args = stack.popAArray();
char[] res;
foreach(AIndex ind; args)
res ~= format("%s", arrays.getRef(ind).carr);
gui_setCaption(getOwner(), toStringz(res));
}
void setNeedMouseFocus()
{ gui_setNeedMouseFocus(getOwner(), stack.popBool); }
void setTextColor()
{
float b = stack.popFloat();
float g = stack.popFloat();
float r = stack.popFloat();
gui_setTextColor(getOwner(), r,g,b);
}
void setCoord()
{
int h = stack.popInt();
int w = stack.popInt();
int y = stack.popInt();
int x = stack.popInt();
gui_setCoord(getOwner(), x,y,w,h);
}
void get()
{
// Get the owner MWidget
auto mw = getMWOwner();
// Get the child
mw = mw.getChild(stack.popString8());
// Push the object
stack.pushObject(mw.mo);
}
// TODO: These are all written to be used with the 'gui' module. Later
// they should be part of Widget, and create child widgets. When used
// with 'gui' they create root widgets.
void loadLayout()
{
MWidget mw = new MWidget(stack.popString8());
stack.pushObject(mw.mo);
}
void text()
{
char[] layer = stack.popString8();
int h = stack.popInt();
int w = stack.popInt();
int y = stack.popInt();
int x = stack.popInt();
char[] skin = stack.popString8();
WidgetPtr ptr = gui_createText(skin.toStringz(),
x,y,w,h,
layer.toStringz());
assert(widgetType(ptr) == "StaticText");
MWidget mw = new MWidget(ptr);
stack.pushObject(mw.mo);
}
void getWidth()
{
stack.pushInt(gui_getWidth(null));
}
void getHeight()
{
stack.pushInt(gui_getHeight(null));
}
void initGUI(bool debugOut)
{
// Load the GUI system
gui_setupGUI(debugOut);
}
void startGUI()
{
gui_showHUD();
// Run GUI scripts
// Create the HUD and windows
vm.run("makegui.mn");
// Run the fps ticker
vm.run("fpsticker.mn");
}
void setupGUIScripts()
{
vm.addPath("mscripts/guiscripts/");
vm.addPath("mscripts/guiscripts/module/");
gmc = vm.load("gui", "gui.mn");
wid_mc = vm.load("Widget", "widget.mn");
/*
but_mc = new MonsterClass("Button", "button.mn");
tex_mc = new MonsterClass("Text", "text.mn");
img_mc = new MonsterClass("Image", "image.mn");
pro_mc = new MonsterClass("Progress", "progress.mn");
win_mc = new MonsterClass("Window", "window.mn");
*/
wid_mc.bind("setCaption", &setCaption);
wid_mc.bind("setNeedMouseFocus", &setNeedMouseFocus);
wid_mc.bind("setTextColor", &setTextColor);
wid_mc.bind("setCoord", &setCoord);
wid_mc.bind("get", &get);
gmc.bind("text", &text);
gmc.bind("loadLayout", &loadLayout);
gmc.bind("getWidth", &getWidth);
gmc.bind("getHeight", &getHeight);
// Set up the console
auto cmc = vm.load("Console");
auto cmo = cmc.createObject;
cons = new Console(cmo);
// Bind native functions
cmc.bind("walk", { bullet_walk(); cons.putln("Walk mode enabled");});
cmc.bind("fly", { bullet_fly(); cons.putln("Fly mode enabled");});
cmc.bind("ghost", { bullet_ghost(); cons.putln("Ghost mode enabled");});
cmc.bind("setfont",
{
char[] fnt = stack.popString8();
gui_setConsoleFont(toStringz(fnt));
cons.putln("Setting font " ~ fnt);
});
cmc.bind("clear", { gui_clearConsole(); });
cmc.bind("exit", { exitProgram(); });
cmc.bind("wireframe", { cons.putln("Wireframe mode not implemented yet"); });
}
Console cons;
// Checked from input/events.d. Shouldn't really be here, but it's a
// workaround for a DMD import issue.
bool doExit = false;
void exitProgram()
{
doExit = true;
}
// Some glue code that will go away later when we use the C++
// interface to Monster directly.
extern(C):
int console_input(char* str)
{
char[] dstr = toString(str);
return cons.input(dstr);
}
char* console_output()
{
char[] dstr = cons.output();
return toStringz(dstr);
}