Jelajahi Sumber

Added window_flushDeferredActions to the GUI API, so that one can get updated lists of child components without drawing the whole interface.

David Piuva 6 bulan lalu
induk
melakukan
15fca9d2b5

+ 5 - 0
Source/DFPSR/api/guiAPI.cpp

@@ -172,6 +172,11 @@ void dsr::window_drawComponents(const Window& window) {
 	MUST_EXIST(window, window_drawComponents);
 	MUST_EXIST(window, window_drawComponents);
 	window->drawComponents();
 	window->drawComponents();
 }
 }
+void dsr::window_flushDeferredActions(const Window& window) {
+	MUST_EXIST(window, window_flushDeferredActions);
+	window->flushDeferredActions();
+}
+
 void dsr::window_showCanvas(const Window& window) {
 void dsr::window_showCanvas(const Window& window) {
 	MUST_EXIST(window, window_showCanvas);
 	MUST_EXIST(window, window_showCanvas);
 	window->showCanvas();
 	window->showCanvas();

+ 9 - 4
Source/DFPSR/api/guiAPI.h

@@ -146,6 +146,13 @@ namespace dsr {
 	// Draw the root component and its children to the canvas.
 	// Draw the root component and its children to the canvas.
 	//   Raises an exception if window doesn't exist.
 	//   Raises an exception if window doesn't exist.
 	void window_drawComponents(const Window& window);
 	void window_drawComponents(const Window& window);
+	// Executes deferred actions without having to call window_drawComponents.
+	// So if you just called component_detachFromParent to remove a child component, this will trigger it instantly
+	//   so that calls to component_getChildCount will show the new count without having to wait for window_drawComponents.
+	// Make sure not to call window_flushDeferredActions from inside of a comonent's event, because that would remove the whole point of deferring actions.
+	//   If an event is triggered from within another event, it can easily cause bugs in the program by not executing transactions one after another.
+	// Raises an exception if window doesn't exist.
+	void window_flushDeferredActions(const Window& window);
 	// Show the canvas.
 	// Show the canvas.
 	//   Raises an exception if window doesn't exist.
 	//   Raises an exception if window doesn't exist.
 	void window_showCanvas(const Window& window);
 	void window_showCanvas(const Window& window);
@@ -265,10 +272,8 @@ namespace dsr {
 	Component component_createWithInterfaceFromFile(Component& parent, const String& filename);
 	Component component_createWithInterfaceFromFile(Component& parent, const String& filename);
 	// Returns true iff the component exists.
 	// Returns true iff the component exists.
 	bool component_exists(const Component& component);
 	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, 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.
+	// Marks component as detached, so that it will be safely removed from the parent's list next time window_drawComponents or window_flushDeferredActions is called.
+	//   Deferring the removal makes sure that no event's callback is called from inside of another event.
 	void component_detachFromParent(const Component& component);
 	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.
 	// 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);
 	int component_getChildCount(const Component& parent);

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

@@ -248,6 +248,10 @@ void DsrWindow::drawComponents() {
 	this->mainPanel->draw(canvas, IVector2D(0, 0));
 	this->mainPanel->draw(canvas, IVector2D(0, 0));
 }
 }
 
 
+void DsrWindow::flushDeferredActions() {
+	this->mainPanel->flushDeferredActions();
+}
+
 AlignedImageRgbaU8 DsrWindow::getCanvas() {
 AlignedImageRgbaU8 DsrWindow::getCanvas() {
 	auto fullResolutionCanvas = this->backend->getCanvas();
 	auto fullResolutionCanvas = this->backend->getCanvas();
 	if (this->pixelScale > 1) {
 	if (this->pixelScale > 1) {

+ 2 - 0
Source/DFPSR/implementation/gui/DsrWindow.h

@@ -127,6 +127,8 @@ public:
 		void removeDepthBuffer();
 		void removeDepthBuffer();
 		// Draw components directly to the canvas in full resolution
 		// Draw components directly to the canvas in full resolution
 		void drawComponents();
 		void drawComponents();
+		// Execute deferred actions once it is safe to trigger callbacks from affected components.
+		void flushDeferredActions();
 		// Show the canvas when an image is ready
 		// Show the canvas when an image is ready
 		void showCanvas();
 		void showCanvas();
 		// Canvas width in the pre-upscale resolution
 		// Canvas width in the pre-upscale resolution

+ 9 - 1
Source/DFPSR/implementation/gui/VisualComponent.cpp

@@ -202,9 +202,17 @@ static void drawOverlays(ImageRgbaU8& targetImage, VisualComponent &component, c
 	}
 	}
 }
 }
 
 
+void VisualComponent::flushDeferredActions() {
+	this->sendNotifications();
+	if (!this->managesChildren()) {
+		for (int i = 0; i < this->getChildCount(); i++) {
+			this->children[i]->flushDeferredActions();
+		}
+	}
+}
+
 // Offset may become non-zero when the origin is outside of targetImage from being clipped outside of the parent region
 // Offset may become non-zero when the origin is outside of targetImage from being clipped outside of the parent region
 void VisualComponent::draw(ImageRgbaU8& targetImage, const IVector2D& offset) {
 void VisualComponent::draw(ImageRgbaU8& targetImage, const IVector2D& offset) {
-	// TODO: Any more good places to send notifications to make the GUI respond faster?
 	// When about to start drawing from the root, check for state changes and handle events before drawing,
 	// When about to start drawing from the root, check for state changes and handle events before drawing,
 	//   so that anything needed for visuals is handled without further delay.
 	//   so that anything needed for visuals is handled without further delay.
 	if (this->parent == nullptr) {
 	if (this->parent == nullptr) {

+ 2 - 0
Source/DFPSR/implementation/gui/VisualComponent.h

@@ -55,6 +55,8 @@ public: // Relations
 	int holdCount = 0;
 	int holdCount = 0;
 	// Marked for removal from the parent when set to true.
 	// Marked for removal from the parent when set to true.
 	bool detach = false;
 	bool detach = false;
+	// Applying deferred actions before drawing.
+	void flushDeferredActions();
 	// Remember the pressed component for sending mouse move events outside of its region.
 	// Remember the pressed component for sending mouse move events outside of its region.
 	Handle<VisualComponent> dragComponent;
 	Handle<VisualComponent> dragComponent;
 private: // States
 private: // States