Fix issue in Rocket.lua script.
[Cafu-Engine.git] / Libs / GuiSys / GuiImpl.cpp
blob2af54d7d2fcead94d519acbeaf71d42a2326bc50
1 /*
2 Cafu Engine, http://www.cafu.de/
3 Copyright (c) Carsten Fuchs and other contributors.
4 This project is licensed under the terms of the MIT license.
5 */
7 #include "GuiImpl.hpp"
8 #include "AllComponents.hpp"
9 #include "CompBase.hpp"
10 #include "Window.hpp"
11 #include "WindowCreateParams.hpp"
12 #include "ConsoleCommands/Console.hpp"
13 #include "ConsoleCommands/Console_Lua.hpp"
14 #include "ConsoleCommands/ConsoleInterpreter.hpp"
15 #include "MaterialSystem/Material.hpp"
16 #include "MaterialSystem/Mesh.hpp"
17 #include "MaterialSystem/Renderer.hpp"
18 #include "Network/State.hpp"
19 #include "OpenGL/OpenGLWindow.hpp" // Just for the Ca*EventT classes...
20 #include "String.hpp"
21 #include "TypeSys.hpp"
22 #include "UniScriptState.hpp"
24 extern "C"
26 #include <lua.h>
27 #include <lualib.h>
28 #include <lauxlib.h>
31 #include <cassert>
32 #include <cstring>
35 using namespace cf::GuiSys;
38 // Note that we cannot simply replace this method with a global TypeInfoManT instance,
39 // because it is called during global static initialization time. The TIM instance being
40 // embedded in the function guarantees that it is properly initialized before first use.
41 cf::TypeSys::TypeInfoManT& cf::GuiSys::GetGuiTIM()
43 static cf::TypeSys::TypeInfoManT TIM;
45 return TIM;
49 const char* GuiImplT::DocClass =
50 "This class holds the hierarchy of windows that together form a GUI.";
53 GuiImplT::InitErrorT::InitErrorT(const std::string& Message)
54 : std::runtime_error(Message)
59 /*static*/ void GuiImplT::InitScriptState(cf::UniScriptStateT& ScriptState)
61 lua_State* LuaState = ScriptState.GetLuaState();
63 // Load the console library. (Adds a global table with name "Console" to the LuaState with the functions of the ConsoleI interface.)
64 cf::Console_RegisterLua(LuaState);
66 // Load the "ci" (console interpreter) library. (Adds a global table with name "ci" to the LuaState with (some of) the functions of the ConsoleInterpreterI interface.)
67 ConsoleInterpreterI::RegisterLua(LuaState);
69 // For each class that the TypeInfoManTs know about, add a (meta-)table to the registry of the LuaState.
70 // The (meta-)table holds the Lua methods that the respective class implements in C++,
71 // and is to be used as metatable for instances of this class.
72 ScriptBinderT Binder(LuaState);
74 Binder.Init(GetGuiTIM());
75 Binder.Init(GetWindowTIM());
76 Binder.Init(GetComponentTIM());
80 GuiImplT::GuiImplT(cf::UniScriptStateT& ScriptState, GuiResourcesT& GuiRes)
81 : ScriptName(),
82 m_ScriptState(&ScriptState),
83 m_IsOwnScriptSt(false),
84 m_MaterialMan(),
85 m_GuiDefaultRM(NULL),
86 m_GuiPointerRM(NULL),
87 m_GuiFinishZRM(NULL),
88 m_GuiResources(GuiRes),
89 RootWindow(NULL),
90 FocusWindow(NULL),
91 MouseOverWindow(NULL),
92 m_IsInited(false),
93 IsActive(true),
94 IsInteractive(true),
95 IsFullCover(false),
96 MousePosX(VIRTUAL_SCREEN_SIZE_X/2.0f), // 320.0f
97 MousePosY(VIRTUAL_SCREEN_SIZE_Y/2.0f), // 240.0f
98 m_MouseCursorSize(20.0f),
99 MouseIsShown(true)
104 GuiImplT::GuiImplT(GuiResourcesT& GuiRes)
105 : ScriptName(),
106 m_ScriptState(new UniScriptStateT()),
107 m_IsOwnScriptSt(true),
108 m_MaterialMan(),
109 m_GuiDefaultRM(NULL),
110 m_GuiPointerRM(NULL),
111 m_GuiFinishZRM(NULL),
112 m_GuiResources(GuiRes),
113 RootWindow(NULL),
114 FocusWindow(NULL),
115 MouseOverWindow(NULL),
116 m_IsInited(false),
117 IsActive(true),
118 IsInteractive(true),
119 IsFullCover(false),
120 MousePosX(VIRTUAL_SCREEN_SIZE_X/2.0f), // 320.0f
121 MousePosY(VIRTUAL_SCREEN_SIZE_Y/2.0f), // 240.0f
122 m_MouseCursorSize(20.0f),
123 MouseIsShown(true)
125 InitScriptState(*m_ScriptState);
129 void GuiImplT::LoadScript(const std::string& GuiScriptName, int Flags)
131 ScriptName = (Flags & InitFlag_InlineCode) ? "" : GuiScriptName;
133 if ((Flags & InitFlag_InlineCode) == 0)
135 std::string s=cf::String::StripExt(GuiScriptName);
137 if (cf::String::EndsWith(s, "_main") || cf::String::EndsWith(s, "_init"))
138 s=std::string(s, 0, s.length()-5);
140 /*ArrayT<MaterialT*> AllMats=*/m_MaterialMan.RegisterMaterialScript(s+".cmat", cf::String::GetPath(GuiScriptName)+"/");
143 if (!m_MaterialMan.HasMaterial("Gui/Default"))
145 // This material has either not been defined in the .cmat file, or we're dealing with inline code.
146 MaterialT Mat;
148 Mat.Name ="Gui/Default";
149 Mat.UseMeshColors =true;
150 Mat.BlendFactorSrc=MaterialT::SrcAlpha;
151 Mat.BlendFactorDst=MaterialT::OneMinusSrcAlpha;
152 Mat.AmbientMask[4]=false;
154 m_MaterialMan.RegisterMaterial(Mat);
157 if (!m_MaterialMan.HasMaterial("Gui/Cursors/Pointer"))
159 // This material has either not been defined in the .cmat file, or we're dealing with inline code.
160 MaterialT Mat;
162 Mat.Name ="Gui/Cursors/Pointer";
163 // Mat.DiffMapComp =...;
164 Mat.UseMeshColors =true;
165 Mat.BlendFactorSrc=MaterialT::SrcAlpha;
166 Mat.BlendFactorDst=MaterialT::OneMinusSrcAlpha;
168 m_MaterialMan.RegisterMaterial(Mat);
171 if (!m_MaterialMan.HasMaterial("Gui/FinishZ"))
173 // This material has either not been defined in the .cmat file, or we're dealing with inline code.
174 MaterialT Mat;
176 Mat.Name ="Gui/FinishZ";
177 // Mat.DiffMapComp =...;
178 Mat.UseMeshColors =true;
179 Mat.AmbientMask[0]=false;
180 Mat.AmbientMask[1]=false;
181 Mat.AmbientMask[2]=false;
182 Mat.AmbientMask[3]=false;
184 m_MaterialMan.RegisterMaterial(Mat);
187 MatSys::Renderer->FreeMaterial(m_GuiDefaultRM); // It shouldn't happen, but LoadScript() might still be called multiple times.
188 MatSys::Renderer->FreeMaterial(m_GuiPointerRM);
189 MatSys::Renderer->FreeMaterial(m_GuiFinishZRM);
191 m_GuiDefaultRM = MatSys::Renderer->RegisterMaterial(m_MaterialMan.GetMaterial("Gui/Default"));
192 m_GuiPointerRM = MatSys::Renderer->RegisterMaterial(m_MaterialMan.GetMaterial("Gui/Cursors/Pointer"));
193 m_GuiFinishZRM = MatSys::Renderer->RegisterMaterial(m_MaterialMan.GetMaterial("Gui/FinishZ"));
196 const std::string PrintScriptName((Flags & InitFlag_InlineCode) ? "<inline code>" : GuiScriptName);
197 lua_State* LuaState = GetScriptState().GetLuaState();
198 ScriptBinderT Binder(LuaState);
200 // Load the user script!
201 const int LoadResult = (Flags & InitFlag_InlineCode) ? luaL_loadstring(LuaState, GuiScriptName.c_str())
202 : luaL_loadfile (LuaState, GuiScriptName.c_str());
204 if (LoadResult != 0)
206 const std::string Msg = "Could not load \"" + PrintScriptName + "\":\n" + lua_tostring(LuaState, -1);
208 lua_pop(LuaState, 1);
209 Console->Warning(Msg + "\n");
211 // The LuaState will be closed by the m_ScriptState.
212 throw InitErrorT(Msg);
215 // This is the parameter for the lua_pcall().
216 // Script code will fetch it via the "..." ellipsis operator like this:
217 // local gui = ...
218 Binder.Push(IntrusivePtrT<GuiImplT>(this));
220 if (lua_pcall(LuaState, 1, 0, 0) != 0)
222 const std::string Msg = "Could not load \"" + PrintScriptName + "\":\n" + lua_tostring(LuaState, -1);
224 lua_pop(LuaState, 1);
225 Console->Warning(Msg + "\n");
227 // The LuaState will be closed by the m_ScriptState.
228 throw InitErrorT(Msg);
231 if (RootWindow == NULL)
233 const std::string Msg = "No root window set for GUI \"" + PrintScriptName + "\".";
235 Console->Warning(Msg + "\n");
237 // The LuaState will be closed by the m_ScriptState.
238 throw InitErrorT(Msg);
241 // Make sure that everyone dealt properly with the Lua stack so far.
242 assert(lua_gettop(LuaState)==0);
245 // Finally call the Lua OnInit() and OnInit2() methods of each window.
246 ArrayT< IntrusivePtrT<WindowT> > AllChildren;
248 AllChildren.PushBack(RootWindow);
249 RootWindow->GetChildren(AllChildren, true);
251 Init(); // The script has the option to call this itself (via gui:Init()) at an earlier time.
253 for (unsigned long ChildNr=0; ChildNr<AllChildren.Size(); ChildNr++)
255 // The OnInit2() methods contain custom, hand-written code by the user (*_main.cgui files).
256 AllChildren[ChildNr]->CallLuaMethod("OnInit2");
258 // Let each component know that the "static" part of initialization is now complete.
259 const ArrayT< IntrusivePtrT<ComponentBaseT> >& Components = AllChildren[ChildNr]->GetComponents();
261 for (unsigned int CompNr = 0; CompNr < Components.Size(); CompNr++)
262 Components[CompNr]->OnPostLoad((Flags & InitFlag_InGuiEditor) != 0);
266 // Make sure that everyone dealt properly with the Lua stack so far.
267 assert(lua_gettop(LuaState)==0);
271 GuiImplT::~GuiImplT()
273 // Manually "destruct" these references before the Lua state (m_ScriptState).
274 // This is redundant: the normal member destruction sequence achieves the same.
275 RootWindow=NULL;
276 FocusWindow=NULL;
277 MouseOverWindow=NULL;
279 // Free the render materials.
280 MatSys::Renderer->FreeMaterial(m_GuiDefaultRM);
281 MatSys::Renderer->FreeMaterial(m_GuiPointerRM);
282 MatSys::Renderer->FreeMaterial(m_GuiFinishZRM);
284 if (m_IsOwnScriptSt)
286 delete m_ScriptState;
287 m_ScriptState = NULL;
292 void GuiImplT::ObsoleteForceKill()
294 assert(m_IsOwnScriptSt);
296 if (m_IsOwnScriptSt)
298 delete m_ScriptState;
299 m_ScriptState = NULL;
304 void GuiImplT::Init()
306 if (m_IsInited) return;
308 ArrayT< IntrusivePtrT<WindowT> > AllChildren;
310 AllChildren.PushBack(RootWindow);
311 RootWindow->GetChildren(AllChildren, true);
313 for (unsigned long ChildNr = 0; ChildNr < AllChildren.Size(); ChildNr++)
315 // The OnInit() methods are automatically written by the Cafu GUI editor (*_init.cgui files).
316 AllChildren[ChildNr]->CallLuaMethod("OnInit");
319 m_IsInited = true;
323 MatSys::RenderMaterialT* GuiImplT::GetDefaultRM() const
325 return m_GuiDefaultRM;
329 MatSys::RenderMaterialT* GuiImplT::GetPointerRM() const
331 return m_GuiPointerRM;
335 const std::string& GuiImplT::GetScriptName() const
337 return ScriptName;
341 IntrusivePtrT<WindowT> GuiImplT::GetRootWindow() const
343 return RootWindow;
347 IntrusivePtrT<WindowT> GuiImplT::GetFocusWindow() const
349 return FocusWindow;
353 void GuiImplT::Activate(bool doActivate)
355 IsActive=doActivate;
357 // Call the OnActivate() or OnDeactivate() methods of all windows.
358 ArrayT< IntrusivePtrT<WindowT> > AllChildren;
360 AllChildren.PushBack(RootWindow);
361 RootWindow->GetChildren(AllChildren, true);
363 for (unsigned long ChildNr=0; ChildNr<AllChildren.Size(); ChildNr++)
364 AllChildren[ChildNr]->CallLuaMethod(IsActive ? "OnActivate" : "OnDeactivate");
368 void GuiImplT::SetInteractive(bool IsInteractive_)
370 IsInteractive=IsInteractive_;
374 void GuiImplT::GetMousePos(float& MousePosX_, float& MousePosY_) const
376 MousePosX_=MousePosX;
377 MousePosY_=MousePosY;
381 void GuiImplT::SetMousePos(float MousePosX_, float MousePosY_)
383 MousePosX=MousePosX_;
384 MousePosY=MousePosY_;
387 // Clip the mouse position to valid coordinates.
388 if (MousePosX<0.0f) MousePosX=0.0;
389 if (MousePosX>VIRTUAL_SCREEN_SIZE_X) MousePosX=VIRTUAL_SCREEN_SIZE_X;
391 if (MousePosY<0.0f) MousePosY=0.0;
392 if (MousePosY>VIRTUAL_SCREEN_SIZE_Y) MousePosY=VIRTUAL_SCREEN_SIZE_Y;
395 // Determine if the mouse cursor has been moved into (or "over") another window,
396 // that is, see if we have to run any OnMouseLeave() and OnMouseEnter() scripts.
397 IntrusivePtrT<WindowT> Win=RootWindow->Find(Vector2fT(MousePosX, MousePosY));
399 if (Win != MouseOverWindow)
401 if (MouseOverWindow != NULL) MouseOverWindow->CallLuaMethod("OnMouseLeave");
402 MouseOverWindow = Win;
403 if (MouseOverWindow != NULL) MouseOverWindow->CallLuaMethod("OnMouseEnter");
408 void GuiImplT::SetShowMouse(bool ShowMouse_)
410 MouseIsShown=ShowMouse_;
414 // Note that this method is the twin of Deserialize(), whose implementation it must match.
415 void GuiImplT::Serialize(cf::Network::OutStreamT& Stream) const
417 assert(m_IsInited);
419 Stream << MousePosX;
420 Stream << MousePosY;
421 Stream << m_MouseCursorSize;
423 RootWindow->Serialize(Stream, true /*WithChildren*/);
427 // Note that this method is the twin of Serialize(), whose implementation it must match.
428 void GuiImplT::Deserialize(cf::Network::InStreamT& Stream, bool IsIniting)
430 assert(m_IsInited);
432 Stream >> MousePosX;
433 Stream >> MousePosY;
434 Stream >> m_MouseCursorSize;
436 RootWindow->Deserialize(Stream, IsIniting);
440 void GuiImplT::Render(bool zLayerCoating) const
442 RootWindow->Render();
444 static MatSys::MeshT Mesh(MatSys::MeshT::TriangleFan);
446 if (Mesh.Vertices.Size()<4)
448 Mesh.Vertices.PushBackEmpty(4);
450 for (unsigned long VNr=0; VNr<Mesh.Vertices.Size(); VNr++)
452 Mesh.Vertices[VNr].SetColor(1.0f, 1.0f, 1.0f, 1.0f);
453 Mesh.Vertices[VNr].SetTextureCoord(VNr==0 || VNr==3 ? 0.0f : 1.0f, VNr<2 ? 0.0f : 1.0f);
457 if (MouseIsShown)
459 Mesh.Vertices[0].SetOrigin(MousePosX, MousePosY );
460 Mesh.Vertices[1].SetOrigin(MousePosX+m_MouseCursorSize, MousePosY );
461 Mesh.Vertices[2].SetOrigin(MousePosX+m_MouseCursorSize, MousePosY+m_MouseCursorSize);
462 Mesh.Vertices[3].SetOrigin(MousePosX, MousePosY+m_MouseCursorSize);
464 MatSys::Renderer->SetCurrentMaterial(m_GuiPointerRM);
465 MatSys::Renderer->RenderMesh(Mesh);
468 if (zLayerCoating)
470 // Finish by applying a z-layer coating to the GUI screen.
471 // This is important whenever the z-ordering of scene elements can be imperfect, e.g. in the Map Editor.
472 Mesh.Vertices[0].SetOrigin( 0.0f, 0.0f);
473 Mesh.Vertices[1].SetOrigin(640.0f, 0.0f);
474 Mesh.Vertices[2].SetOrigin(640.0f, 480.0f);
475 Mesh.Vertices[3].SetOrigin( 0.0f, 480.0f);
477 MatSys::Renderer->SetCurrentMaterial(m_GuiFinishZRM);
478 MatSys::Renderer->RenderMesh(Mesh);
483 bool GuiImplT::ProcessDeviceEvent(const CaKeyboardEventT& KE)
485 for (IntrusivePtrT<WindowT> Win=FocusWindow; Win!=NULL; Win=Win->GetParent())
487 bool KeyWasProcessed=false;
488 bool ResultOK =false;
490 switch (KE.Type)
492 case CaKeyboardEventT::CKE_KEYDOWN: ResultOK=Win->CallLuaMethod("OnKeyPress", "i>b", KE.Key, &KeyWasProcessed); break;
493 case CaKeyboardEventT::CKE_CHAR: ResultOK=Win->CallLuaMethod("OnChar", "i>b", KE.Key, &KeyWasProcessed); break;
494 case CaKeyboardEventT::CKE_KEYUP: ResultOK=Win->CallLuaMethod("OnKeyRelease", "i>b", KE.Key, &KeyWasProcessed); break;
497 if (ResultOK && KeyWasProcessed) return true;
498 if (Win->OnInputEvent(KE)) return true;
501 return false;
505 bool GuiImplT::ProcessDeviceEvent(const CaMouseEventT& ME)
507 // Note that the processing of the mouse event is orthogonal to (independent of) MouseIsShown.
508 // That is, we may be active and interactive even if the mouse cursor is *not* shown,
509 // as for example with the 3D window of the Cafu engine client, which must receive the
510 // mouse events even if no mouse cursor is shown!
512 bool MEWasProcessed=false; // If the Lua script handler consumed the event.
513 bool ResultOK =false; // If the Lua script handler returned without script error.
515 switch (ME.Type)
517 case CaMouseEventT::CM_BUTTON0:
518 case CaMouseEventT::CM_BUTTON1:
519 case CaMouseEventT::CM_BUTTON2:
520 case CaMouseEventT::CM_BUTTON3:
522 const bool ButtonDown=(ME.Amount>0); // Was it a "button up" or "button down" event?
524 if (MouseOverWindow!=NULL)
526 ResultOK=MouseOverWindow->CallLuaMethod(ButtonDown ? "OnMouseButtonDown" : "OnMouseButtonUp", "i>b", ME.Type, &MEWasProcessed);
529 // Change the keyboard input focus, but only if the mouse button event was not handled by the script
530 // (by handling the event the script signals that the default behaviour (focus change) should not take place).
531 if (!MEWasProcessed && ME.Type==CaMouseEventT::CM_BUTTON0 && ButtonDown && MouseOverWindow!=FocusWindow)
533 // Only "unhandled left mouse button down" events change the keyboard input focus.
534 if (FocusWindow!=NULL) FocusWindow->CallLuaMethod("OnFocusLose");
535 FocusWindow=MouseOverWindow;
536 if (FocusWindow!=NULL) FocusWindow->CallLuaMethod("OnFocusGain");
539 break;
542 case CaMouseEventT::CM_MOVE_X:
544 // Update the mouse cursor position according to the ME.
545 SetMousePos(MousePosX+ME.Amount, MousePosY);
547 // if (MouseOverWindow!=NULL)
548 // {
549 // ResultOK=MouseOverWindow->CallLuaMethod("OnMouseMove", "ii>b", RelMousePosX, RelMousePosY, &MEWasProcessed);
550 // }
551 break;
554 case CaMouseEventT::CM_MOVE_Y:
556 // Update the mouse cursor position according to the ME.
557 SetMousePos(MousePosX, MousePosY+ME.Amount);
559 // if (MouseOverWindow!=NULL)
560 // {
561 // ResultOK=MouseOverWindow->CallLuaMethod("OnMouseMove", "ii>b", RelMousePosX, RelMousePosY, &MEWasProcessed);
562 // }
563 break;
566 default:
567 // Just ignore the other possible ME types.
568 break;
571 if (ResultOK && MEWasProcessed) return true;
572 if (MouseOverWindow==NULL) return false;
574 const Vector2fT AbsWinPos = MouseOverWindow->GetAbsolutePos();
576 return MouseOverWindow->OnInputEvent(ME, MousePosX-AbsWinPos.x, MousePosY-AbsWinPos.y);
580 void GuiImplT::DistributeClockTickEvents(float t)
582 if (GetIsActive()) // Inconsistent and inconsequent, but saves performance: Only distribute clock tick events when this GUI is active.
584 ArrayT< IntrusivePtrT<WindowT> > AllChildren;
586 AllChildren.PushBack(RootWindow);
587 RootWindow->GetChildren(AllChildren, true);
589 for (unsigned long ChildNr=0; ChildNr<AllChildren.Size(); ChildNr++)
591 AllChildren[ChildNr]->OnClockTickEvent(t);
592 AllChildren[ChildNr]->CallLuaMethod("OnFrame");
596 if (m_IsOwnScriptSt)
598 // Run the pending coroutines always, even if this GUI is currently not active.
599 m_ScriptState->RunPendingCoroutines(t);
604 /***********************************************/
605 /*** Implementation of Lua binding functions ***/
606 /***********************************************/
608 static const cf::TypeSys::MethsDocT META_Activate =
610 "activate",
611 "Sets the IsActive flag of this GUI.",
612 "", "(bool IsActive)"
615 int GuiImplT::Activate(lua_State* LuaState)
617 ScriptBinderT Binder(LuaState);
618 IntrusivePtrT<GuiImplT> Gui = Binder.GetCheckedObjectParam< IntrusivePtrT<GuiImplT> >(1);
620 // I also want to treat the number 0 as false, not just "false" and "nil".
621 if (lua_isnumber(LuaState, 2)) Gui->IsActive=lua_tointeger(LuaState, 2)!=0;
622 else Gui->IsActive=lua_toboolean(LuaState, 2)!=0;
624 return 0;
628 static const cf::TypeSys::MethsDocT META_Close =
630 "close",
631 "Same as calling `gui:activate(false);`",
632 "", "()"
635 int GuiImplT::Close(lua_State* LuaState)
637 ScriptBinderT Binder(LuaState);
638 IntrusivePtrT<GuiImplT> Gui = Binder.GetCheckedObjectParam< IntrusivePtrT<GuiImplT> >(1);
640 Gui->IsActive=false;
641 return 0;
645 static const cf::TypeSys::MethsDocT META_SetInteractive =
647 "setInteractive",
648 "Sets the IsInteractive flag of this GUI.",
649 "", "(bool IsInteractive)"
652 int GuiImplT::SetInteractive(lua_State* LuaState)
654 ScriptBinderT Binder(LuaState);
655 IntrusivePtrT<GuiImplT> Gui = Binder.GetCheckedObjectParam< IntrusivePtrT<GuiImplT> >(1);
657 // I also want to treat the number 0 as false, not just "false" and "nil".
658 if (lua_isnumber(LuaState, 2)) Gui->IsInteractive=lua_tointeger(LuaState, 2)!=0;
659 else Gui->IsInteractive=lua_toboolean(LuaState, 2)!=0;
661 return 0;
665 static const cf::TypeSys::MethsDocT META_SetFullCover =
667 "setFullCover",
668 "Sets the IsFullCover flag of this GUI.",
669 "", "(bool IsFullCover)"
672 int GuiImplT::SetFullCover(lua_State* LuaState)
674 ScriptBinderT Binder(LuaState);
675 IntrusivePtrT<GuiImplT> Gui = Binder.GetCheckedObjectParam< IntrusivePtrT<GuiImplT> >(1);
677 // I also want to treat the number 0 as false, not just "false" and "nil".
678 if (lua_isnumber(LuaState, 2)) Gui->IsFullCover=lua_tointeger(LuaState, 2)!=0;
679 else Gui->IsFullCover=lua_toboolean(LuaState, 2)!=0;
681 return 0;
685 static const cf::TypeSys::MethsDocT META_SetMousePos =
687 "setMousePos",
688 "Sets the position of the mouse cursor.",
689 "", "(number x, number y)"
692 int GuiImplT::SetMousePos(lua_State* LuaState)
694 ScriptBinderT Binder(LuaState);
695 IntrusivePtrT<GuiImplT> Gui = Binder.GetCheckedObjectParam< IntrusivePtrT<GuiImplT> >(1);
697 Gui->SetMousePos(float(lua_tonumber(LuaState, 2)),
698 float(lua_tonumber(LuaState, 3)));
700 return 0;
704 static const cf::TypeSys::MethsDocT META_SetMouseCursorSize =
706 "setMouseCursorSize",
707 "Sets the size of the mouse cursor.",
708 "", "(number size)"
711 int GuiImplT::SetMouseCursorSize(lua_State* LuaState)
713 ScriptBinderT Binder(LuaState);
714 IntrusivePtrT<GuiImplT> Gui = Binder.GetCheckedObjectParam< IntrusivePtrT<GuiImplT> >(1);
716 Gui->SetMouseCursorSize(float(lua_tonumber(LuaState, 2)));
718 return 0;
722 static const cf::TypeSys::MethsDocT META_SetMouseMat =
724 "setMouseMat",
725 "Sets the material that is used to render the mouse cursor.\n"
726 "(This method is not yet implemented.)",
727 "", "(string MatName)"
730 int GuiImplT::SetMouseMat(lua_State* LuaState)
732 return 0;
736 static const cf::TypeSys::MethsDocT META_SetMouseIsShown =
738 "showMouse",
739 "Determines whether the mouse cursor is shown at all.",
740 "", "(bool IsShown)"
743 int GuiImplT::SetMouseIsShown(lua_State* LuaState)
745 ScriptBinderT Binder(LuaState);
746 IntrusivePtrT<GuiImplT> Gui = Binder.GetCheckedObjectParam< IntrusivePtrT<GuiImplT> >(1);
748 // I also want to treat the number 0 as false, not just "false" and "nil".
749 if (lua_isnumber(LuaState, 2)) Gui->MouseIsShown=lua_tointeger(LuaState, 2)!=0;
750 else Gui->MouseIsShown=lua_toboolean(LuaState, 2)!=0;
752 return 0;
756 static const cf::TypeSys::MethsDocT META_CreateNew =
758 "new",
759 "This method creates new GUI windows or new GUI components.",
760 "object", "(string ClassName, string InstanceName=\"\")"
763 int GuiImplT::CreateNew(lua_State* LuaState)
765 ScriptBinderT Binder(LuaState);
766 IntrusivePtrT<GuiImplT> Gui = Binder.GetCheckedObjectParam< IntrusivePtrT<GuiImplT> >(1);
768 const std::string TypeName = std::string("GuiSys::") + luaL_checkstring(LuaState, 2);
769 const char* ObjName = lua_tostring(LuaState, 3); // Passing an object name is optional.
771 const cf::TypeSys::TypeInfoT* TI = GetWindowTIM().FindTypeInfoByName(TypeName.c_str());
773 if (TI)
775 IntrusivePtrT<WindowT> Win(static_cast<WindowT*>(TI->CreateInstance(WindowCreateParamsT(*Gui))));
777 // Console->DevPrint(cf::va("Creating window %p.\n", Win));
778 assert(Win->GetType() == TI);
779 assert(strcmp(TI->ClassName, TypeName.c_str()) == 0);
781 if (ObjName) Win->GetBasics()->SetWindowName(ObjName);
783 Binder.Push(Win);
784 return 1;
787 TI = GetComponentTIM().FindTypeInfoByName(TypeName.c_str());
789 if (TI)
791 IntrusivePtrT<ComponentBaseT> Comp(static_cast<ComponentBaseT*>(TI->CreateInstance(cf::TypeSys::CreateParamsT())));
793 Binder.Push(Comp);
794 return 1;
797 return luaL_argerror(LuaState, 2, (std::string("unknown class name \"") + TypeName + "\"").c_str());
801 static const cf::TypeSys::MethsDocT META_SetFocus =
803 "setFocus",
804 "Sets the keyboard input focus to the given window. Does *not* call the OnFocusLose() or OnFocusGain() callbacks!\n"
805 "Instead of a window instance, it is also possible to pass the name of the window (a string).",
806 "", "(WindowT Window)"
809 int GuiImplT::SetFocus(lua_State* LuaState)
811 ScriptBinderT Binder(LuaState);
812 IntrusivePtrT<GuiImplT> Gui = Binder.GetCheckedObjectParam< IntrusivePtrT<GuiImplT> >(1);
814 if (lua_isstring(LuaState, 2))
816 Gui->FocusWindow=Gui->RootWindow->Find(lua_tostring(LuaState, 2));
818 else if (lua_istable(LuaState, 2))
820 Gui->FocusWindow=Binder.GetCheckedObjectParam< IntrusivePtrT<WindowT> >(2);
823 // Note that we intentionally did *not* call the Lua OnFocusLose() or OnFocusGain() scripts,
824 // as is done when the focus changes due to a mouse click:
825 // the Lua code that calls this method should instead call the desired OnFocus*() script functions itself.
826 // This behaviour must be explicitly stated in the user documentation!
827 return 0;
831 static const cf::TypeSys::MethsDocT META_GetRootWindow =
833 "GetRootWindow",
834 "Returns the root window of this GUI as previously set by SetRootWindow().",
835 "WindowT", "()"
838 int GuiImplT::GetRootWindow(lua_State* LuaState)
840 ScriptBinderT Binder(LuaState);
841 IntrusivePtrT<GuiImplT> Gui = Binder.GetCheckedObjectParam< IntrusivePtrT<GuiImplT> >(1);
843 if (Gui->RootWindow.IsNull())
845 lua_pushnil(LuaState);
847 else
849 Binder.Push(Gui->RootWindow);
852 return 1;
856 static const cf::TypeSys::MethsDocT META_SetRootWindow =
858 "SetRootWindow",
859 "Sets the root window for this GUI.",
860 "", "(WindowT Window)"
863 int GuiImplT::SetRootWindow(lua_State* LuaState)
865 ScriptBinderT Binder(LuaState);
866 IntrusivePtrT<GuiImplT> Gui = Binder.GetCheckedObjectParam< IntrusivePtrT<GuiImplT> >(1);
868 Gui->RootWindow = Binder.GetCheckedObjectParam< IntrusivePtrT<WindowT> >(2);
869 return 0;
873 static const cf::TypeSys::MethsDocT META_Init =
875 "Init",
876 "Calls the OnInit() script methods of all windows.",
877 "", "()"
880 int GuiImplT::Init(lua_State* LuaState)
882 ScriptBinderT Binder(LuaState);
883 IntrusivePtrT<GuiImplT> Gui = Binder.GetCheckedObjectParam< IntrusivePtrT<GuiImplT> >(1);
885 Gui->Init();
886 return 0;
890 static const cf::TypeSys::MethsDocT META_toString =
892 "__tostring",
893 "Returns a short string representation of this GUI.",
894 "string", "()"
897 int GuiImplT::toString(lua_State* LuaState)
899 ScriptBinderT Binder(LuaState);
900 IntrusivePtrT<GuiImplT> Gui = Binder.GetCheckedObjectParam< IntrusivePtrT<GuiImplT> >(1);
902 if (Gui->ScriptName=="") lua_pushfstring(LuaState, "A programmatically generated GUI.");
903 else lua_pushfstring(LuaState, "A gui generated from the script \"%s\".", Gui->ScriptName.c_str());
905 return 1;
909 /***********************************/
910 /*** TypeSys-related definitions ***/
911 /***********************************/
913 void* GuiImplT::CreateInstance(const cf::TypeSys::CreateParamsT& Params)
915 // At this time, GuiImplT instances cannot be created "anonymously" via the TypeSys' CreateInstance() method,
916 // as it would require us to derive from cf::TypeSys::CreateParamsT and deal with that.
917 // That's not a problem though, because there is no class hierarchy deriving from GuiImplT, so any code that
918 // instantiates GuiImplTs can do so by using the normal constructor -- no "virtual constructor" is needed.
920 // return new GuiImplT(*static_cast<const cf::GameSys::GuiCreateParamsT*>(&Params));
921 return NULL;
924 const luaL_Reg GuiImplT::MethodsList[] =
926 { "activate", Activate },
927 { "close", Close },
928 { "setInteractive", SetInteractive },
929 { "setFullCover", SetFullCover },
930 { "setMousePos", SetMousePos },
931 { "setMouseCursorSize", SetMouseCursorSize },
932 { "setMouseMat", SetMouseMat },
933 { "showMouse", SetMouseIsShown },
934 { "new", CreateNew },
935 { "setFocus", SetFocus },
936 { "GetRootWindow", GetRootWindow },
937 { "SetRootWindow", SetRootWindow },
938 { "Init", Init },
939 { "__tostring", toString },
940 { NULL, NULL }
943 const cf::TypeSys::MethsDocT GuiImplT::DocMethods[] =
945 META_Activate,
946 META_Close,
947 META_SetInteractive,
948 META_SetFullCover,
949 META_SetMousePos,
950 META_SetMouseCursorSize,
951 META_SetMouseMat,
952 META_SetMouseIsShown,
953 META_CreateNew,
954 META_SetFocus,
955 META_GetRootWindow,
956 META_SetRootWindow,
957 META_Init,
958 META_toString,
959 { NULL, NULL, NULL, NULL }
962 const cf::TypeSys::TypeInfoT GuiImplT::TypeInfo(GetGuiTIM(), "GuiSys::GuiImplT", NULL /*No base class.*/, CreateInstance, MethodsList, DocClass, DocMethods);