/* * This source file is part of RmlUi, the HTML/CSS Interface Middleware * * For the latest information, see http://github.com/mikke89/RmlUi * * Copyright (c) 2018 Michael R. P. Ragazzon * Copyright (c) 2019 The RmlUi Team, and contributors * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. * */ #include #include #include #include #include #include #include #include class DemoWindow : public Rml::Core::EventListener { public: DemoWindow(const Rml::Core::String &title, const Rml::Core::Vector2f &position, Rml::Core::Context *context) { using namespace Rml::Core; document = context->LoadDocument("basic/demo/data/demo.rml"); if (document != nullptr) { { document->GetElementById("title")->SetInnerRML(title); document->SetProperty(PropertyId::Left, Property(position.x, Property::PX)); document->SetProperty(PropertyId::Top, Property(position.y, Property::PX)); } document->Show(); } } void Shutdown() { if (document) { document->Close(); document = nullptr; } } void ProcessEvent(Rml::Core::Event& event) override { using namespace Rml::Core; switch (event.GetId()) { case EventId::Keydown: { Rml::Core::Input::KeyIdentifier key_identifier = (Rml::Core::Input::KeyIdentifier) event.GetParameter< int >("key_identifier", 0); bool ctrl_key = event.GetParameter< bool >("ctrl_key", false); if (key_identifier == Rml::Core::Input::KI_ESCAPE) { Shell::RequestExit(); } else if (key_identifier == Rml::Core::Input::KI_F8) { Rml::Debugger::SetVisible(!Rml::Debugger::IsVisible()); } } break; default: break; } } Rml::Core::ElementDocument * GetDocument() { return document; } private: Rml::Core::ElementDocument *document; }; Rml::Core::Context* context = nullptr; ShellRenderInterfaceExtensions *shell_renderer; void GameLoop() { context->Update(); shell_renderer->PrepareRenderBuffer(); context->Render(); shell_renderer->PresentRenderBuffer(); } class DemoEventListener : public Rml::Core::EventListener { public: DemoEventListener(const Rml::Core::String& value, Rml::Core::Element* element) : value(value), element(element) {} void ProcessEvent(Rml::Core::Event& event) override { using namespace Rml::Core; if (value == "exit") { // Test replacing the current element. // Need to be careful with regard to lifetime issues. The event's current element will be destroyed, so we cannot // use it after SetInnerRml(). The library should handle this case safely internally when propagating the event further. auto parent = element->GetParentNode(); parent->SetInnerRML(""); if (auto child = parent->GetChild(0)) child->Focus(); } else if (value == "confirm_exit") { Shell::RequestExit(); } else if (value == "cancel_exit") { if(auto parent = element->GetParentNode()) parent->SetInnerRML(""); } } void OnDetach(Rml::Core::Element* element) override { delete this; } private: Rml::Core::String value; Rml::Core::Element* element; }; class DemoEventListenerInstancer : public Rml::Core::EventListenerInstancer { public: Rml::Core::EventListener* InstanceEventListener(const Rml::Core::String& value, Rml::Core::Element* element) override { return new DemoEventListener(value, element); } }; #if defined RMLUI_PLATFORM_WIN32 #include int APIENTRY WinMain(HINSTANCE RMLUI_UNUSED_PARAMETER(instance_handle), HINSTANCE RMLUI_UNUSED_PARAMETER(previous_instance_handle), char* RMLUI_UNUSED_PARAMETER(command_line), int RMLUI_UNUSED_PARAMETER(command_show)) #else int main(int RMLUI_UNUSED_PARAMETER(argc), char** RMLUI_UNUSED_PARAMETER(argv)) #endif { #ifdef RMLUI_PLATFORM_WIN32 RMLUI_UNUSED(instance_handle); RMLUI_UNUSED(previous_instance_handle); RMLUI_UNUSED(command_line); RMLUI_UNUSED(command_show); #else RMLUI_UNUSED(argc); RMLUI_UNUSED(argv); #endif const int width = 1600; const int height = 950; ShellRenderInterfaceOpenGL opengl_renderer; shell_renderer = &opengl_renderer; // Generic OS initialisation, creates a window and attaches OpenGL. if (!Shell::Initialise() || !Shell::OpenWindow("Demo Sample", shell_renderer, width, height, true)) { Shell::Shutdown(); return -1; } // RmlUi initialisation. Rml::Core::SetRenderInterface(&opengl_renderer); opengl_renderer.SetViewport(width, height); ShellSystemInterface system_interface; Rml::Core::SetSystemInterface(&system_interface); Rml::Core::Initialise(); // Create the main RmlUi context and set it on the shell's input layer. context = Rml::Core::CreateContext("main", Rml::Core::Vector2i(width, height)); if (context == nullptr) { Rml::Core::Shutdown(); Shell::Shutdown(); return -1; } Rml::Controls::Initialise(); Rml::Debugger::Initialise(context); Input::SetContext(context); shell_renderer->SetContext(context); context->SetDensityIndependentPixelRatio(1.0f); DemoEventListenerInstancer event_listener_instancer; Rml::Core::Factory::RegisterEventListenerInstancer(&event_listener_instancer); Shell::LoadFonts("assets/"); auto window = std::make_unique("Demo sample", Rml::Core::Vector2f(150, 80), context); window->GetDocument()->AddEventListener(Rml::Core::EventId::Keydown, window.get()); window->GetDocument()->AddEventListener(Rml::Core::EventId::Keyup, window.get()); window->GetDocument()->AddEventListener(Rml::Core::EventId::Animationend, window.get()); Shell::EventLoop(GameLoop); window->Shutdown(); // Shutdown RmlUi. Rml::Core::Shutdown(); Shell::CloseWindow(); Shell::Shutdown(); window.reset(); return 0; }