Browse Source

Extended the GUI API.

David Piuva 3 years ago
parent
commit
e9274ed98c

+ 44 - 2
Source/DFPSR/api/guiAPI.cpp

@@ -80,12 +80,54 @@ Component dsr::window_getRoot(const Window& window) {
 
 Component dsr::window_findComponentByName(const Window& window, const ReadableString& name, bool mustExist) {
 	MUST_EXIST(window, window_findComponentByName);
-	return window->findComponentByName(name);
+	Component result = window->findComponentByName(name);
+	if (mustExist && result.get() == nullptr) {
+		throwError(U"window_findComponentByName: No child component named ", name, " found!");
+	}
+	return result;
 }
 
 Component dsr::window_findComponentByNameAndIndex(const Window& window, const ReadableString& name, int index, bool mustExist) {
 	MUST_EXIST(window, window_findComponentByNameAndIndex);
-	return window->findComponentByNameAndIndex(name, index);
+	Component result = window->findComponentByNameAndIndex(name, index);
+	if (mustExist && result.get() == nullptr) {
+		throwError(U"window_findComponentByName: No child component named ", name, " with index ", index, " found!");
+	}
+	return result;
+}
+
+int dsr::component_getChildCount(const Component& parent) {
+	if (parent.get()) {
+		return parent->getChildCount();
+	} else {
+		return -1;
+	}
+}
+
+Component dsr::component_getChild(const Component& parent, int childIndex) {
+	if (parent.get()) {
+		return std::dynamic_pointer_cast<VisualComponent>(parent->getChild(childIndex));
+	} else {
+		return std::shared_ptr<VisualComponent>(); // Null handle
+	}
+}
+
+static void findAllComponentsByName(const Component& component, const ReadableString& name, std::function<void(Component, int)> callback) {
+	if (component_exists(component)) {
+		// Check if the current component matches
+		if (string_match(component->getName(), name)) {
+			callback(component, component->getIndex());
+		}
+		// Search among child components
+		int childCount = component_getChildCount(component);
+		for (int childIndex = childCount - 1; childIndex >= 0; childIndex--) {
+			findAllComponentsByName(component_getChild(component, childIndex), name, callback);
+		}
+	}
+}
+void dsr::window_findAllComponentsByName(const Window& window, const ReadableString& name, std::function<void(Component, int)> callback) {
+	MUST_EXIST(window, window_findAllComponentsByName);
+	findAllComponentsByName(window->getRootComponent(), name, callback);
 }
 
 bool dsr::window_executeEvents(const Window& window) {

+ 30 - 8
Source/DFPSR/api/guiAPI.h

@@ -65,12 +65,25 @@ namespace dsr {
 	//   Raises an exception if window doesn't exist.
 	//   There should always exist a root component where more components can be added recursively
 	Component window_getRoot(const Window& window);
-	// TODO: Document
-	//   Raises an exception if window doesn't exist.
+	// Returns a handle to the first matching component of the name in window.
+	//                 For consistent behavior, make sure that only one component has the name, or use window_findComponentByNameAndIndex after giving each a unique index.
+	// If mustExist is true, not finding any component with the name throws an exception.
+	// Raises an exception if window doesn't exist.
+	// Component names are case sensitive to reduce the risk of accidental naming conflicts among many components.
 	Component window_findComponentByName(const Window& window, const ReadableString& name, bool mustExist = true);
-	// TODO: Document
-	//   Raises an exception if window doesn't exist.
+	// Returns a handle to the first matching component of the name and index in window.
+	// If mustExist is true, not finding any component with the name throws an exception.
+	// Raises an exception if window doesn't exist.
+	// Component names are case sensitive to reduce the risk of accidental naming conflicts among many components.
 	Component window_findComponentByNameAndIndex(const Window& window, const ReadableString& name, int index, bool mustExist = true);
+	// Calls back with the component handle and index for each match of the name.
+	//   Can be used to count the number of components by incrementing a counter for each match.
+	//   Can be used to detach all the matching components and have them automatically garbage collected by reference counting.
+	//   The index can be used as a filter or to look up information.
+	// To allow detaching components while iterating over the list of children, order is reversed for child components.
+	// Raises an exception if window doesn't exist.
+	// Component names are case sensitive to reduce the risk of accidental naming conflicts among many components.
+	void window_findAllComponentsByName(const Window& window, const ReadableString& name, std::function<void(Component, int)> callback);
 
 // The three main events to run in a loop at the end of the main function
 	// If the window's event queue contained any resize of the window, the canvas and the depth buffer will be replaced during this call.
@@ -170,13 +183,21 @@ namespace dsr {
 	bool component_exists(const Component& component);
 	// Removed the component from the parent.
 	//   Does nothing if used against the root component.
-	//   Make sure to erase any other references to the component if you want it erased.
+	//   Make sure to erase any other references to the component if you want it erased, including parent pointers in any child components that may still be attached unless you detach them first.
+	//   There is currently no attach function, because such a function would need runtime checks against cyclic dependencies from attaching a parent to its own child, and still be hard to debug once it happens.
 	void component_detachFromParent(const Component& component);
+	// Returns the number of direct (non-recursive) child components attached to parent, or -1 if parent is a null handle.
+	int component_getChildCount(const Component& parent);
+	// Returns the child at childIndex from parent, or an empty handle if parent does not exist or childIndex is out of bound.
+	//   Child indices go from 0 to count - 1.
+	//   The child index refers to the parent's list of children, not the child's index attribute.
+	Component component_getChild(const Component& parent, int childIndex);
 	// Returns true iff propertyName exists in component.
+	//   Property names are case insensitive, to give more flexibility for the few property names.
 	bool component_hasProperty(const Component& component, const ReadableString& propertyName);
 	// Sets a property found using propertyName in component to the value serialized in value.
 	//   Raises an exception if component doesn't exist.
-	//   Matching of propertyName is case insensitive.
+	//   Matching of propertyName is case insensitive, to give more flexibility for the few property names.
 	//   Returns ReturnCode::Good if assigned.
 	//   Unless mustAssign forces an exception.
 	//     Returns ReturnCode::KeyNotFound if propertyName wasn't found in component.
@@ -198,7 +219,7 @@ namespace dsr {
 	ReturnCode component_setProperty_string(const Component& component, const ReadableString& propertyName, const ReadableString& value, bool mustAssign = true);
 	// Returns a property found using propertyName in component.
 	//   Raises an exception if component doesn't exist.
-	//   Matching of propertyName is case insensitive.
+	//   Matching of propertyName is case insensitive, to give more flexibility for the few property names.
 	//   If mustExist is true
 	//     Raises an exception when propertyName isn't found.
 	//   If mustExist is false
@@ -213,7 +234,8 @@ namespace dsr {
 	//   Returns the result without adding any quote signs or escape characters.
 	String component_getProperty_string(const Component& component, const ReadableString& propertyName, bool mustExist = true);
 
-	// Call a named method in the component using optional text arguments
+	// Call a named method in the component using optional text arguments.
+	//   Matching of methodName is case insensitive, to give more flexibility for the few method names.
 	String component_call(const Component& component, const ReadableString& methodName);
 	String component_call(const Component& component, const ReadableString& methodName, const ReadableString& arguments);
 

+ 4 - 4
Source/DFPSR/gui/DsrWindow.cpp

@@ -90,19 +90,19 @@ void DsrWindow::applyLayout() {
 	this->mainPanel->applyLayout(IVector2D(this->getCanvasWidth(), this->getCanvasHeight()));
 }
 
-std::shared_ptr<VisualComponent> DsrWindow::findComponentByName(ReadableString name, bool mustExist) const {
+std::shared_ptr<VisualComponent> DsrWindow::findComponentByName(ReadableString name) const {
 	if (string_match(this->mainPanel->getName(), name)) {
 		return this->mainPanel;
 	} else {
-		return this->mainPanel->findChildByName(name, mustExist);
+		return this->mainPanel->findChildByName(name);
 	}
 }
 
-std::shared_ptr<VisualComponent> DsrWindow::findComponentByNameAndIndex(ReadableString name, int index, bool mustExist) const {
+std::shared_ptr<VisualComponent> DsrWindow::findComponentByNameAndIndex(ReadableString name, int index) const {
 	if (string_match(this->mainPanel->getName(), name) && this->mainPanel->getIndex() == index) {
 		return this->mainPanel;
 	} else {
-		return this->mainPanel->findChildByNameAndIndex(name, index, mustExist);
+		return this->mainPanel->findChildByNameAndIndex(name, index);
 	}
 }
 

+ 6 - 6
Source/DFPSR/gui/DsrWindow.h

@@ -62,15 +62,15 @@ public:
 		void applyLayout();
 
 		// Component getters
-		std::shared_ptr<VisualComponent> findComponentByName(ReadableString name, bool mustExist = true) const;
+		std::shared_ptr<VisualComponent> findComponentByName(ReadableString name) const;
 		template <typename T>
-		std::shared_ptr<T> findComponentByName(ReadableString name, bool mustExist = true) const {
-			return std::dynamic_pointer_cast<T>(this->findComponentByName(name, mustExist));
+		std::shared_ptr<T> findComponentByName(ReadableString name) const {
+			return std::dynamic_pointer_cast<T>(this->findComponentByName(name));
 		}
-		std::shared_ptr<VisualComponent> findComponentByNameAndIndex(ReadableString name, int index, bool mustExist = true) const;
+		std::shared_ptr<VisualComponent> findComponentByNameAndIndex(ReadableString name, int index) const;
 		template <typename T>
-		std::shared_ptr<T> findComponentByNameAndIndex(ReadableString name, int index, bool mustExist = true) const {
-			return std::dynamic_pointer_cast<T>(this->findComponentByNameAndIndex(name, index, mustExist));
+		std::shared_ptr<T> findComponentByNameAndIndex(ReadableString name, int index) const {
+			return std::dynamic_pointer_cast<T>(this->findComponentByNameAndIndex(name, index));
 		}
 
 		// Get the root component that contains all other components in the window

+ 9 - 5
Source/DFPSR/gui/VisualComponent.cpp

@@ -176,7 +176,11 @@ int VisualComponent::getChildCount() const {
 }
 
 std::shared_ptr<Persistent> VisualComponent::getChild(int index) const {
-	return this->children[index];
+	if (index >= 0 && index < this->children.length()) {
+		return this->children[index];
+	} else {
+		return std::shared_ptr<Persistent>(); // Null handle for out of bound.
+	}
 }
 
 void VisualComponent::detachFromParent() {
@@ -217,13 +221,13 @@ bool VisualComponent::hasChild(std::shared_ptr<VisualComponent> child) const {
 	return this->hasChild(child.get());
 }
 
-std::shared_ptr<VisualComponent> VisualComponent::findChildByName(ReadableString name, bool mustExist) const {
+std::shared_ptr<VisualComponent> VisualComponent::findChildByName(ReadableString name) const {
 	for (int i = 0; i < this->getChildCount(); i++) {
 		std::shared_ptr<VisualComponent> current = this->children[i];
 		if (string_match(current->getName(), name)) {
 			return current; // Found the component
 		} else {
-			std::shared_ptr<VisualComponent> searchResult = current->findChildByName(name, mustExist);
+			std::shared_ptr<VisualComponent> searchResult = current->findChildByName(name);
 			if (searchResult.get() != nullptr) {
 				return searchResult; // Found the component recursively
 			}
@@ -232,13 +236,13 @@ std::shared_ptr<VisualComponent> VisualComponent::findChildByName(ReadableString
 	return std::shared_ptr<VisualComponent>(); // Could not find the component
 }
 
-std::shared_ptr<VisualComponent> VisualComponent::findChildByNameAndIndex(ReadableString name, int index, bool mustExist) const {
+std::shared_ptr<VisualComponent> VisualComponent::findChildByNameAndIndex(ReadableString name, int index) const {
 	for (int i = 0; i < this->getChildCount(); i++) {
 		std::shared_ptr<VisualComponent> current = this->children[i];
 		if (string_match(current->getName(), name) && current->getIndex() == index) {
 			return current; // Found the component
 		} else {
-			std::shared_ptr<VisualComponent> searchResult = current->findChildByNameAndIndex(name, index, mustExist);
+			std::shared_ptr<VisualComponent> searchResult = current->findChildByNameAndIndex(name, index);
 			if (searchResult.get() != nullptr) {
 				return searchResult; // Found the component recursively
 			}

+ 2 - 3
Source/DFPSR/gui/VisualComponent.h

@@ -172,10 +172,9 @@ public:
 	bool hasChild(std::shared_ptr<VisualComponent> child) const;
 
 	// Find the first child component with the requested name using a case sensitive match.
-	//   If mustExist is true, failure will raise an exception directly.
 	//   Returns: A shared pointer to the child or null if not found.
-	std::shared_ptr<VisualComponent> findChildByName(ReadableString name, bool mustExist) const;
-	std::shared_ptr<VisualComponent> findChildByNameAndIndex(ReadableString name, int index, bool mustExist) const;
+	std::shared_ptr<VisualComponent> findChildByName(ReadableString name) const;
+	std::shared_ptr<VisualComponent> findChildByNameAndIndex(ReadableString name, int index) const;
 	// Detach the component from any parent
 	void detachFromParent();