Browse Source

Letting the virtual assembly code be compiled separatelly, so that it can be reused for multiple themes.

David Piuva 3 năm trước cách đây
mục cha
commit
24de33017f

+ 1 - 1
Source/DFPSR/api/fileAPI.h

@@ -214,7 +214,7 @@ namespace dsr {
 	// A theoretical version of file_getAbsoluteParentFolder for evaluation on a theoretical system without actually calling file_getCurrentPath or running on the given system.
 	// Path-syntax: Depends on pathSyntax argument.
 	// Post-condition: Returns the absolute parent to the given path, or U"?" if trying to leave the root or use a tilde home alias.
-	String file_getTheoreticalAbsoluteParentFolder(const ReadableString &path, const ReadableString &currentPath, PathSyntax pathSyntax);
+	String file_getTheoreticalAbsoluteParentFolder(const ReadableString &path, const ReadableString &currentPath, PathSyntax pathSyntax IMPLICIT_PATH_SYNTAX);
 
 	// Gets the canonical absolute version of the path.
 	// Current directory is expanded, but not user accounts.

+ 16 - 11
Source/DFPSR/gui/VisualTheme.cpp

@@ -23,6 +23,7 @@
 
 #include <stdint.h>
 #include "VisualTheme.h"
+#include "../api/fileAPI.h"
 #include "../api/imageAPI.h"
 #include "../api/drawAPI.h"
 #include "../api/mediaMachineAPI.h"
@@ -215,7 +216,7 @@ struct ClassSettings {
 		FOR_EACH_COLLECTION(this->, RETURN_TRUE_IF_SETTING_EXISTS)
 		return false;
 	}
-	void setVariable(const ReadableString &key, const ReadableString &value) {
+	void setVariable(const ReadableString &key, const ReadableString &value, const ReadableString &fromPath) {
 		if (this->keyExists(key)) { throwError(U"The property ", key, U" was defined multiple times in ", className, U"\n"); }
 		DsrChar firstCharacter = value[0];
 		if (firstCharacter == U'\"') {
@@ -223,11 +224,11 @@ struct ClassSettings {
 			this->strings.pushConstruct(key, string_unmangleQuote(value));
 		} else {
 			int64_t pipeIndex = string_findFirst(value, U'|');
-			if (pipeIndex > -1 && string_caseInsensitiveMatch(string_before(value, pipeIndex), U"RGBA")) {
-				// Key = RGBA|File:Path
-				// Key = RGBA|WxH:Hexadecimals
+			if (pipeIndex > -1 && string_caseInsensitiveMatch(string_before(value, pipeIndex), U"ImageRgbaU8")) {
+				// Key = ImageRgbaU8|File:Path
+				// Key = ImageRgbaU8|WxH:Hexadecimals
 				PersistentImage newImage;
-				newImage.assignValue(string_after(value, pipeIndex));
+				newImage.assignValue(string_after(value, pipeIndex), fromPath);
 				this->colorImages.pushConstruct(key, newImage);
 			} else {
 				// Key = Integer
@@ -259,11 +260,11 @@ public:
 		settings.pushConstruct(className);
 		return settings.length() - 1;
 	}
-	VisualThemeImpl(const ReadableString& mediaCode, const ReadableString &styleSettings) : machine(machine_create(mediaCode)) {
+	VisualThemeImpl(const MediaMachine &machine, const ReadableString &styleSettings, const ReadableString &fromPath) : machine(machine) {
 		this->settings.pushConstruct(U"default");
-		config_parse_ini(styleSettings, [this](const ReadableString& block, const ReadableString& key, const ReadableString& value) {
+		config_parse_ini(styleSettings, [this, fromPath](const ReadableString& block, const ReadableString& key, const ReadableString& value) {
 			int32_t classIndex = (string_length(block) == 0) ? 0 : this->getClassIndex(block);
-			this->settings[classIndex].setVariable(key, value);
+			this->settings[classIndex].setVariable(key, value, fromPath);
 		});
 	}
 	// Destructor
@@ -273,13 +274,17 @@ public:
 static VisualTheme defaultTheme;
 VisualTheme theme_getDefault() {
 	if (!(defaultTheme.get())) {
-		defaultTheme = theme_create(defaultMediaMachineCode, defaultStyleSettings);
+		defaultTheme = theme_createFromText(machine_create(defaultMediaMachineCode), defaultStyleSettings, file_getCurrentPath());
 	}
 	return defaultTheme;
 }
 
-VisualTheme theme_create(const ReadableString &mediaCode, const ReadableString &styleSettings) {
-	return std::make_shared<VisualThemeImpl>(mediaCode, styleSettings);
+VisualTheme theme_createFromText(const MediaMachine &machine, const ReadableString &styleSettings, const ReadableString &fromPath) {
+	return std::make_shared<VisualThemeImpl>(machine, styleSettings, fromPath);
+}
+
+VisualTheme theme_createFromFile(const MediaMachine &machine, const ReadableString &styleFilename) {
+	return theme_createFromText(machine, string_load(styleFilename), file_getRelativeParentFolder(styleFilename));
 }
 
 MediaMethod theme_getScalableImage(const VisualTheme &theme, const ReadableString &className) {

+ 6 - 2
Source/DFPSR/gui/VisualTheme.h

@@ -30,8 +30,12 @@ namespace dsr {
 
 // TODO: Move to the API folder once themes are easy to create.
 
-// Construction
-VisualTheme theme_create(const ReadableString &mediaCode, const ReadableString &themeCode);
+// Create a theme using a virtual machine with functions to call, style settings telling which functions to call with what arguments, and a path to load any non-embedded images from.
+VisualTheme theme_createFromText(const MediaMachine &machine, const ReadableString &styleSettings, const ReadableString &fromPath);
+// Create a theme using a virtual machine with functions to call, and a path to the style settings to load.
+//   Any non-embedded images will be loaded using paths relative to the parent folder of styleFilename;
+VisualTheme theme_createFromFile(const MediaMachine &machine, const ReadableString &styleFilename);
+// Get a handle to the default theme.
 VisualTheme theme_getDefault();
 
 // Get a scalable image by name from the theme.

+ 9 - 2
Source/DFPSR/persistent/atomic/PersistentImage.cpp

@@ -22,6 +22,7 @@
 //    distribution.
 
 #include "PersistentImage.h"
+#include "../../api/fileAPI.h"
 
 using namespace dsr;
 
@@ -43,7 +44,8 @@ static uint8_t readHexaDecimal(const ReadableString &text, int &readFrom) {
 	}
 	return result;
 }
-bool PersistentImage::assignValue(const ReadableString &text) {
+
+bool PersistentImage::assignValue(const ReadableString &text, const ReadableString &fromPath) {
 	if (string_caseInsensitiveMatch(text, U"NONE")) {
 		// Set the handle to null
 		this->value = OrderedImageRgbaU8();
@@ -57,7 +59,8 @@ bool PersistentImage::assignValue(const ReadableString &text) {
 		ReadableString leftSide = string_before(text, colonIndex);
 		if (string_caseInsensitiveMatch(leftSide, U"FILE")) {
 			// Read image from the file path
-			this->value = image_load_RgbaU8(string_after(text, colonIndex));
+			String absolutePath = file_getTheoreticalAbsolutePath(string_after(text, colonIndex), fromPath);
+			this->value = image_load_RgbaU8(absolutePath);
 		} else {
 			// Read dimensions and a sequence of pixels as hexadecimals
 			int xIndex = string_findFirst(text, U'x');
@@ -88,6 +91,10 @@ bool PersistentImage::assignValue(const ReadableString &text) {
 	return true;
 }
 
+bool PersistentImage::assignValue(const ReadableString &text) {
+	return this->assignValue(text, file_getCurrentPath());
+}
+
 static const String hexadecimals = U"0123456789ABCDEF";
 static void writeHexaDecimal(String &out, uint8_t value) {
 	string_appendChar(out, hexadecimals[(value & 0b11110000) >> 4]);

+ 2 - 0
Source/DFPSR/persistent/atomic/PersistentImage.h

@@ -39,6 +39,8 @@ public:
 	PersistentImage() {}
 public:
 	virtual bool assignValue(const ReadableString &text) override;
+	// TODO: Let all persistent types know which directory is being used to load resources.
+	bool assignValue(const ReadableString &text, const ReadableString &fromPath);
 	virtual String& toStreamIndented(String& out, const ReadableString& indentation) const override;
 };
 

+ 24 - 16
Source/tools/wizard/main.cpp

@@ -104,7 +104,7 @@ END:
 static const ReadableString styleSettings =
 UR"QUOTE(
 	border = 2
-	atlas = RGBA|File:media/Style.png
+	atlas = ImageRgbaU8|File:media/Style.png
 	; Image location in the atlas
 	sourceLeft = 0
 	sourceTop = 0
@@ -319,28 +319,36 @@ static void populateInterface(const ReadableString& folderPath) {
 
 DSR_MAIN_CALLER(dsrMain)
 void dsrMain(List<String> args) {
-	// Start sound
+	// Get the application folder.
+	String applicationFolder = file_getApplicationFolder();
+
+	// Start sound.
 	sound_initialize();
-	boomSound = loadSoundFromFile(file_combinePaths(file_getApplicationFolder(), U"Boom.wav"));
+	boomSound = loadSoundFromFile(file_combinePaths(applicationFolder, U"Boom.wav"));
 
-	// Create a window
+	// Create a window.
 	window = window_create(U"DFPSR wizard application", 800, 600);
+
+	// Create components using the layout.
 	window_loadInterfaceFromString(window, interfaceContent);
-	window_applyTheme(window, theme_create(mediaMachineCode, styleSettings));
 
-	// Find components
+	// Create a virtual machine with reusable image generating functions.
+	MediaMachine machine = machine_create(mediaMachineCode);
+	// Use the virtual machine with a specific style referring to the functions in machine.
+	window_applyTheme(window, theme_createFromText(machine, styleSettings, applicationFolder));
+
+	// Find components.
 	projectList = window_findComponentByName(window, U"projectList");
 	launchButton = window_findComponentByName(window, U"launchButton");
 	descriptionLabel = window_findComponentByName(window, U"descriptionLabel");
 	previewPicture = window_findComponentByName(window, U"previewPicture");
 
-	// Find projects to showcase
+	// Find projects to showcase.
 	//   On systems that don't allow getting the application's folder, the program must be started somewhere within the Source folder.
-	String applicationFolder = file_getApplicationFolder();
 	String sourceFolder = findParent(applicationFolder, U"Source");
 	populateInterface(sourceFolder);
 
-	// Bind methods to events
+	// Bind methods to events.
 	window_setKeyboardEvent(window, [](const KeyboardEvent& event) {
 		DsrKey key = event.dsrKey;
 		if (event.keyboardEventType == KeyboardEventType::KeyDown) {
@@ -382,23 +390,23 @@ void dsrMain(List<String> args) {
 		running = false;
 	});
 
-	// Execute
+	// Execute.
 	playSound(boomSound, false, 1.0, 1.0, 0.25);
 	while(running) {
-		// Wait for actions so that we don't render until an action has been recieved
-		// This will save battery on laptops for applications that don't require animation
+		// Wait for actions so that we don't render until an action has been recieved.
+		// This will save battery on laptops for applications that don't require animation.
 		while (!(window_executeEvents(window) || updateInterface(false))) {
 			time_sleepSeconds(0.01);
 		}
-		// Fill the background
+		// Fill the background.
 		AlignedImageRgbaU8 canvas = window_getCanvas(window);
 		image_fill(canvas, ColorRgbaI32(64, 64, 64, 255));
-		// Draw interface
+		// Draw interface.
 		window_drawComponents(window);
-		// Show the final image
+		// Show the final image.
 		window_showCanvas(window);
 	}
 
-	// Close sound
+	// Close sound.
 	sound_terminate();
 }