Browse Source

Add RML/RCSS sandbox to demo sample

Michael Ragazzon 6 years ago
parent
commit
4760a33388

+ 22 - 0
Samples/assets/invader.rcss

@@ -605,6 +605,7 @@ scrollbarhorizontal
 
 textarea scrollbarvertical
 {
+	cursor: arrow;
 	margin: 10px 0px 4px 0;
 	width: 12px;
 }
@@ -624,3 +625,24 @@ textarea scrollbarvertical sliderarrowinc
 	width: 0px;
 	height: 0px;
 }
+
+textarea scrollbarhorizontal
+{
+	cursor: arrow;
+	margin-left: 7px;
+	height: 12px;
+}
+textarea scrollbarhorizontal sliderbar
+{
+	background-color: #BC0000CC;
+	height: 8px;
+	min-width: 10px;
+}
+textarea scrollbarhorizontal sliderbar:hover
+{
+	background-color: #B82500CC;
+}
+textarea scrollbarhorizontal sliderbar:active
+{
+	background-color: #770000CC;
+}

+ 23 - 3
Samples/basic/demo/data/demo.rml

@@ -150,11 +150,25 @@ p.emojis
 	color: #b33;
 }
 
-textarea {
+#controls textarea {
 	font-size: 18px;
 	font-effect: outline(2px #006600);
 	color: #ddd;
-	
+}
+#sandbox textarea {
+	font-size: 16px;
+	color: #222;
+}
+#sandbox_rml_source { margin-left: -5px; }
+#sandbox_rcss_source { margin-left: 5px; }
+#sandbox_target {
+	background-color: #fff;
+	border: 1px #000;
+	height: 400px;
+	margin: 30px 15px 0;
+	color: #000;
+	text-align: left;
+	position: relative;
 }
 </style>
 </head>
@@ -231,10 +245,16 @@ textarea {
 	<p>Img elements can take both sprites and images. For images it also supports a 'coords' attribute for specifying a sub-rectangle.</p>
 </panel>
 <tab>Controls</tab>
-<panel>
+<panel id="controls">
 	<div>Type something here: <input style="vertical-align: -7px;" size="10" type="text" maxlength="12" value="Sample text"/></div>
 	<textarea cols="30" rows="5" wrap="nowrap">😍 Hello 🌐 World! 😎</textarea>
 </panel>
+<tab>Sandbox</tab>
+<panel id="sandbox">
+	<textarea id="sandbox_rml_source" cols="35" rows="8" wrap="nowrap" onchange="set_sandbox_body"></textarea>
+	<textarea id="sandbox_rcss_source" cols="35" rows="8" wrap="nowrap" onchange="set_sandbox_style"></textarea>
+	<div id="sandbox_target"></div>
+</panel>
 </tabset>
 </body>
 </rml>

+ 115 - 9
Samples/basic/demo/src/main.cpp

@@ -33,8 +33,18 @@
 #include <Shell.h>
 #include <ShellRenderInterfaceOpenGL.h>
 #include <RmlUi/Core/TransformPrimitive.h>
+#include <RmlUi/Core/StreamMemory.h>
+
+static const Rml::Core::String sandbox_default_rcss = R"(
+body { width: 100%; height: 100%; overflow: hidden auto; }
+scrollbarvertical { width: 15px; }
+scrollbarvertical slidertrack { background: #eee; }
+scrollbarvertical slidertrack:active { background: #ddd; }
+scrollbarvertical sliderbar { width: 15px; min-height: 30px; background: #aaa; }
+scrollbarvertical sliderbar:hover { background: #888; }
+scrollbarvertical sliderbar:active { background: #666; }
+)";
 
-#include <sstream>
 
 class DemoWindow : public Rml::Core::EventListener
 {
@@ -50,11 +60,66 @@ public:
 				document->SetProperty(PropertyId::Left, Property(position.x, Property::PX));
 				document->SetProperty(PropertyId::Top, Property(position.y, Property::PX));
 			}
+
+			// Add sandbox default text.
+			if (auto source = static_cast<Rml::Controls::ElementFormControl*>(document->GetElementById("sandbox_rml_source")))
+			{
+				auto value = source->GetValue();
+				value += "<p>Write your RML here</p>\n\n<!-- <img src=\"assets/high_scores_alien_1.tga\"/> -->";
+				source->SetValue(value);
+			}
+
+			// Prepare sandbox document.
+			if (auto target = document->GetElementById("sandbox_target"))
+			{
+				iframe = context->CreateDocument();
+				auto iframe_ptr = iframe->GetParentNode()->RemoveChild(iframe);
+				target->AppendChild(std::move(iframe_ptr));
+				iframe->SetProperty(PropertyId::Position, Property(Style::Position::Relative));
+				iframe->SetProperty(PropertyId::Display, Property(Style::Display::Block));
+				iframe->SetInnerRML("<p>Rendered output goes here.</p>");
+
+				// Load basic RML style sheet
+				Rml::Core::String style_sheet_content;
+				{
+					// Load file into string
+					auto file_interface = Rml::Core::GetFileInterface();
+					Rml::Core::FileHandle handle = file_interface->Open("assets/rml.rcss");
+					
+					size_t length = file_interface->Length(handle);
+					style_sheet_content.resize(length);
+					file_interface->Read((void*)style_sheet_content.data(), length, handle);
+					file_interface->Close(handle);
+
+					style_sheet_content += sandbox_default_rcss;
+				}
+
+				Rml::Core::StreamMemory stream((Rml::Core::byte*)style_sheet_content.data(), style_sheet_content.size());
+				stream.SetSourceURL("sandbox://default_rcss");
+
+				rml_basic_style_sheet = std::make_shared<Rml::Core::StyleSheet>();
+				rml_basic_style_sheet->LoadStyleSheet(&stream);
+			}
+
+			// Add sandbox style sheet text.
+			if (auto source = static_cast<Rml::Controls::ElementFormControl*>(document->GetElementById("sandbox_rcss_source")))
+			{
+				Rml::Core::String value = "/* Write your RCSS here */\n\n/* body { color: #fea; background: #224; } */";
+				source->SetValue(value);
+				SetSandboxStylesheet(value);
+			}
 			
 			document->Show();
 		}
 	}
 
+	void Update() {
+		if (iframe)
+		{
+			iframe->UpdateDocument();
+		}
+	}
+
 	void Shutdown() {
 		if (document)
 		{
@@ -94,18 +159,43 @@ public:
 		return document;
 	}
 
+	void SetSandboxStylesheet(const Rml::Core::String& string)
+	{
+		if (iframe && rml_basic_style_sheet)
+		{
+			auto style = std::make_shared<Rml::Core::StyleSheet>();
+			Rml::Core::StreamMemory stream((const Rml::Core::byte*)string.data(), string.size());
+			stream.SetSourceURL("sandbox://rcss");
+
+			style->LoadStyleSheet(&stream);
+			style = rml_basic_style_sheet->CombineStyleSheet(*style);
+			iframe->SetStyleSheet(style);
+		}
+	}
+
+	void SetSandboxBody(const Rml::Core::String& string)
+	{
+		if (iframe)
+		{
+			iframe->SetInnerRML(string);
+		}
+	}
+
 private:
-	Rml::Core::ElementDocument *document;
+	Rml::Core::ElementDocument *document = nullptr;
+	Rml::Core::ElementDocument *iframe = nullptr;
+	Rml::Core::SharedPtr<Rml::Core::StyleSheet> rml_basic_style_sheet;
 };
 
 
 Rml::Core::Context* context = nullptr;
 ShellRenderInterfaceExtensions *shell_renderer;
-
+std::unique_ptr<DemoWindow> demo_window;
 
 void GameLoop()
 {
 	context->Update();
+	demo_window->Update();
 
 	shell_renderer->PrepareRenderBuffer();
 	context->Render();
@@ -143,6 +233,22 @@ public:
 			if(auto parent = element->GetParentNode())
 				parent->SetInnerRML("<button id='exit' onclick='exit'>Exit</button>");
 		}
+		else if (value == "set_sandbox_body")
+		{
+			if (auto source = static_cast<Rml::Controls::ElementFormControl*>(element->GetElementById("sandbox_rml_source")))
+			{
+				auto value = source->GetValue();
+				demo_window->SetSandboxBody(value);
+			}
+		}
+		else if (value == "set_sandbox_style")
+		{
+			if (auto source = static_cast<Rml::Controls::ElementFormControl*>(element->GetElementById("sandbox_rcss_source")))
+			{
+				auto value = source->GetValue();
+				demo_window->SetSandboxStylesheet(value);
+			}
+		}
 	}
 
 	void OnDetach(Rml::Core::Element* element) override { delete this; }
@@ -225,14 +331,14 @@ int main(int RMLUI_UNUSED_PARAMETER(argc), char** RMLUI_UNUSED_PARAMETER(argv))
 
 	Shell::LoadFonts("assets/");
 
-	auto window = std::make_unique<DemoWindow>("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());
+	demo_window = std::make_unique<DemoWindow>("Demo sample", Rml::Core::Vector2f(150, 80), context);
+	demo_window->GetDocument()->AddEventListener(Rml::Core::EventId::Keydown, demo_window.get());
+	demo_window->GetDocument()->AddEventListener(Rml::Core::EventId::Keyup, demo_window.get());
+	demo_window->GetDocument()->AddEventListener(Rml::Core::EventId::Animationend, demo_window.get());
 
 	Shell::EventLoop(GameLoop);
 
-	window->Shutdown();
+	demo_window->Shutdown();
 
 	// Shutdown RmlUi.
 	Rml::Core::Shutdown();
@@ -240,7 +346,7 @@ int main(int RMLUI_UNUSED_PARAMETER(argc), char** RMLUI_UNUSED_PARAMETER(argv))
 	Shell::CloseWindow();
 	Shell::Shutdown();
 
-	window.reset();
+	demo_window.reset();
 
 	return 0;
 }

+ 1 - 1
Samples/shell/src/win32/ShellWin32.cpp

@@ -280,7 +280,7 @@ void Shell::SetMouseCursor(const Rml::Core::String& cursor_name)
 	if (window_handle)
 	{
 		HCURSOR cursor_handle = nullptr;
-		if (cursor_name.empty())
+		if (cursor_name.empty() || cursor_name == "arrow")
 			cursor_handle = cursor_default;
 		else if(cursor_name == "move")
 			cursor_handle = cursor_move;

+ 4 - 4
Source/Controls/WidgetTextInput.cpp

@@ -40,7 +40,7 @@ namespace Controls {
 static constexpr float CURSOR_BLINK_TIME = 0.7f;
 
 static bool IsWordCharacter(char c) {
-	return !Core::StringUtilities::IsWhitespace(c) && !(c >= '!' && c <= '@');
+	return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_' || (c < 0 || c >= 128);
 }
 
 WidgetTextInput::WidgetTextInput(ElementFormControl* _parent) : internal_dimensions(0, 0), scroll_offset(0, 0), selection_geometry(_parent), cursor_position(0, 0), cursor_size(0, 0), cursor_geometry(_parent)
@@ -521,7 +521,7 @@ bool WidgetTextInput::AddCharacters(Rml::Core::String string)
 
 	Core::String value = GetElement()->GetAttribute< Rml::Core::String >("value", "");
 	
-	value.insert(GetCursorIndex(), string);
+	value.insert(std::min(size_t(GetCursorIndex()), value.size()), string);
 
 	edit_index += (int)string.size();
 
@@ -558,7 +558,7 @@ bool WidgetTextInput::DeleteCharacters(CursorMovement direction)
 void WidgetTextInput::CopySelection()
 {
 	const Core::String& value = GetElement()->GetAttribute< Rml::Core::String >("value", "");
-	const Core::String snippet = value.substr(selection_begin_index, selection_length);
+	const Core::String snippet = value.substr(std::min(size_t(selection_begin_index), value.size()), selection_length);
 	Core::GetSystemInterface()->SetClipboardText(snippet);
 }
 
@@ -1185,7 +1185,7 @@ void WidgetTextInput::DeleteSelection()
 	{
 		const Core::String& value = GetElement()->GetAttribute< Rml::Core::String >("value", "");
 
-		Rml::Core::String new_value = value.substr(0, selection_begin_index) + value.substr(selection_begin_index + selection_length);
+		Rml::Core::String new_value = value.substr(0, selection_begin_index) + value.substr(std::min(size_t(selection_begin_index + selection_length), value.size()));
 		GetElement()->SetAttribute("value", new_value);
 
 		// Move the cursor to the beginning of the old selection.