Browse Source

Added a word-wrapped multi-line Label component.

David Piuva 5 years ago
parent
commit
2eaaca8fd7

+ 7 - 0
Source/DFPSR/gui/DsrWindow.cpp

@@ -23,9 +23,13 @@
 //    distribution.
 
 #include "DsrWindow.h"
+
 #include "components/Panel.h"
 #include "components/Button.h"
 #include "components/ListBox.h"
+#include "components/Label.h"
+// <<<< Include new components here
+
 #include "../math/scalar.h"
 #include "../math/IVector.h"
 #include "../api/imageAPI.h"
@@ -40,6 +44,9 @@ static void initializeGui() {
 		REGISTER_PERSISTENT_CLASS(Panel)
 		REGISTER_PERSISTENT_CLASS(Button)
 		REGISTER_PERSISTENT_CLASS(ListBox)
+		REGISTER_PERSISTENT_CLASS(Label)
+		// <<<< Register new components here
+
 		initialized = true;
 	}
 }

+ 10 - 6
Source/DFPSR/gui/Font.cpp

@@ -160,13 +160,16 @@ void RasterFont::printMultiLine(ImageRgbaU8& target, const ReadableString& conte
 	int rowStartIndex = 0; // The start of the current row or the unprinted remainder that didn't fit inside the bound.
 	int lastWordBreak = 0; // The last scanned location where the current row could've been broken off.
 	bool wordStarted = false; // True iff the physical line after word wrapping has scanned the beginning of a word.
-	for (int i = 0; i <= content.length(); i++) {
-		// Fake an additional line-break at the end
-		DsrChar code = (i >= content.length()) ? 10 : content[i];
+	if (bound.height() < this->size) {
+		// Not enough height to print anything
+		return;
+	}
+	for (int i = 0; i < content.length(); i++) {
+		DsrChar code = content[i];
 		if (code == 10) {
 			// Print the completed line
 			this->printLine(target, content.exclusiveRange(rowStartIndex, i), IVector2D(bound.left(), y), color);
-			y += this->size; if (y >= bound.bottom()) { return; }
+			y += this->size; if (y + this->size > bound.bottom()) { return; }
 			lineWidth = 0;
 			rowStartIndex = i + 1;
 			lastWordBreak = rowStartIndex;
@@ -187,12 +190,12 @@ void RasterFont::printMultiLine(ImageRgbaU8& target, const ReadableString& conte
 						if (i > rowStartIndex) {
 							splitIndex = i - 1;
 						} else {
-							// Not enough space to print a single character, skipping content to avoid printing outside.
+							// Not enough width to print a single character, skipping content to avoid printing outside.
 							splitIndex = i;
 						}
 					}
 					this->printLine(target, content.exclusiveRange(rowStartIndex, splitIndex), IVector2D(bound.left(), y), color);
-					y += this->size; if (y >= bound.bottom()) { return; }
+					y += this->size; if (y + this->size > bound.bottom()) { return; }
 					lineWidth = 0;
 					// Continue after splitIndex
 					i = splitIndex + 1;
@@ -208,6 +211,7 @@ void RasterFont::printMultiLine(ImageRgbaU8& target, const ReadableString& conte
 			}
 		}
 	}
+	this->printLine(target, content.from(rowStartIndex), IVector2D(bound.left(), y), color);
 }
 
 int32_t RasterFont::getLineWidth(const ReadableString& content) const {

+ 76 - 0
Source/DFPSR/gui/components/Label.cpp

@@ -0,0 +1,76 @@
+// zlib open source license
+//
+// Copyright (c) 2018 to 2019 David Forsgren Piuva
+// 
+// This software is provided 'as-is', without any express or implied
+// warranty. In no event will the authors be held liable for any damages
+// arising from the use of this software.
+// 
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it
+// freely, subject to the following restrictions:
+// 
+//    1. The origin of this software must not be misrepresented; you must not
+//    claim that you wrote the original software. If you use this software
+//    in a product, an acknowledgment in the product documentation would be
+//    appreciated but is not required.
+// 
+//    2. Altered source versions must be plainly marked as such, and must not be
+//    misrepresented as being the original software.
+// 
+//    3. This notice may not be removed or altered from any source
+//    distribution.
+
+#include "Label.h"
+#include <math.h>
+
+using namespace dsr;
+
+PERSISTENT_DEFINITION(Label)
+
+void Label::declareAttributes(StructureDefinition &target) const {
+	VisualComponent::declareAttributes(target);
+	target.declareAttribute(U"Color");
+	target.declareAttribute(U"Opacity");
+	target.declareAttribute(U"Text");
+}
+
+Persistent* Label::findAttribute(const ReadableString &name) {
+	if (string_caseInsensitiveMatch(name, U"Color")) {
+		return &(this->color);
+	} else if (string_caseInsensitiveMatch(name, U"Opacity")) {
+		return &(this->opacity);
+	} else if (string_caseInsensitiveMatch(name, U"Text")) {
+		return &(this->text);
+	} else {
+		return VisualComponent::findAttribute(name);
+	}
+}
+
+Label::Label() {}
+
+bool Label::isContainer() const {
+	return true;
+}
+
+void Label::drawSelf(ImageRgbaU8& targetImage, const IRect &relativeLocation) {
+	completeAssets();
+	if (this->text.value.length() > 0) {
+		// Uncomment to draw a white background for debugging
+		//draw_rectangle(targetImage, relativeLocation, ColorRgbaI32(255, 255, 255, 255));
+		// Print the text directly each time without buffering, because the biggest cost is to fill pixels
+		this->font->printMultiLine(targetImage, this->text.value, relativeLocation, ColorRgbaI32(this->color.value, this->opacity.value));
+	}
+}
+
+bool Label::pointIsInside(const IVector2D& pixelPosition) {
+	// Labels are not clickable, because they have no clearly defined border drawn
+	return false;
+}
+
+void Label::completeAssets() {
+	if (this->font.get() == nullptr) {
+		this->font = font_getDefault();
+	}
+}
+

+ 61 - 0
Source/DFPSR/gui/components/Label.h

@@ -0,0 +1,61 @@
+// zlib open source license
+//
+// Copyright (c) 2018 to 2019 David Forsgren Piuva
+// 
+// This software is provided 'as-is', without any express or implied
+// warranty. In no event will the authors be held liable for any damages
+// arising from the use of this software.
+// 
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it
+// freely, subject to the following restrictions:
+// 
+//    1. The origin of this software must not be misrepresented; you must not
+//    claim that you wrote the original software. If you use this software
+//    in a product, an acknowledgment in the product documentation would be
+//    appreciated but is not required.
+// 
+//    2. Altered source versions must be plainly marked as such, and must not be
+//    misrepresented as being the original software.
+// 
+//    3. This notice may not be removed or altered from any source
+//    distribution.
+
+#ifndef DFPSR_GUI_COMPONENT_LABEL
+#define DFPSR_GUI_COMPONENT_LABEL
+
+#include "../VisualComponent.h"
+#include "../Font.h"
+
+namespace dsr {
+
+class Label : public VisualComponent {
+PERSISTENT_DECLARATION(Label)
+public:
+	// Attributes
+	PersistentColor color;
+	// TODO: Why is "PersistentInteger opacity(255);" not recognizing the constructor?
+	PersistentInteger opacity = PersistentInteger(255); // 0 is fully invisible, 255 is fully opaque
+	PersistentString text;
+	// Attribute access
+	void declareAttributes(StructureDefinition &target) const override;
+	Persistent* findAttribute(const ReadableString &name) override;
+private:
+	// Temporary
+	bool pressed = false;
+	bool inside = false;
+	// Given from the style
+	std::shared_ptr<RasterFont> font;
+	void completeAssets();
+public:
+	Label();
+public:
+	bool isContainer() const;
+	void drawSelf(ImageRgbaU8& targetImage, const IRect &relativeLocation) override;
+	bool pointIsInside(const IVector2D& pixelPosition) override;
+};
+
+}
+
+#endif
+

+ 10 - 0
Source/SDK/guiExample/media/interface.lof

@@ -37,5 +37,15 @@ Begin : Panel
 			List = "Testing", "1", "2", "3", "One Two Three"
 			SelectedIndex = 2
 		End
+		Begin : Label
+			Name = "myLabel"
+			Text = "Testing multi-line label.\nABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz 0123456789\n	indented\n  aligned\n\nEnd of test!"
+			Color = 0,50,0
+			Opacity = 128
+			left = 10%+120
+			right = 100%-20
+			top = 20
+			bottom = 100%-20
+		End
 	End
 End