Browse Source

Began drawing of overlays (without the mouse interaction).

David Piuva 2 years ago
parent
commit
38e11b2a25
2 changed files with 47 additions and 11 deletions
  1. 24 1
      Source/DFPSR/gui/VisualComponent.cpp
  2. 23 10
      Source/DFPSR/gui/VisualComponent.h

+ 24 - 1
Source/DFPSR/gui/VisualComponent.cpp

@@ -134,6 +134,10 @@ void VisualComponent::draw(ImageRgbaU8& targetImage, const IVector2D& offset) {
 		for (int i = 0; i < this->getChildCount(); i++) {
 			this->children[i]->drawClipped(targetImage, containerBound.upperLeft(), containerBound);
 		}
+		// Draw the overlays
+		if (this->overlayComponent.get() != nullptr) {
+			this->overlayComponent->drawOverlay(targetImage);
+		}
 	}
 }
 
@@ -152,6 +156,8 @@ void VisualComponent::drawSelf(ImageRgbaU8& targetImage, const IRect &relativeLo
 	draw_rectangle(targetImage, relativeLocation, ColorRgbaI32(200, 50, 50, 255));
 }
 
+void VisualComponent::drawOverlay(ImageRgbaU8& targetImage) {}
+
 // Manual use with the correct type
 void VisualComponent::addChildComponent(std::shared_ptr<VisualComponent> child) {
 	if (!this->isContainer()) {
@@ -394,13 +400,30 @@ bool VisualComponent::isFocused() {
 		//   One cannot just check if the parent points back directly, because old pointers may be left from a previous route.
 		VisualComponent *root = this; while (root->parent != nullptr) { root = root->parent; }
 		VisualComponent *leaf = root; while (leaf->focusComponent.get() != nullptr) { leaf = leaf->focusComponent.get(); }
-		return leaf == this; // Focused if the root component points back to this component.
+		return leaf == this; // Focused if the root component points back to this component and not any further.
 	} else {
 		// Root component is focused if it does not redirect its focus to a child component.
 		return this->focusComponent.get() == nullptr; // Focused if no child is focused.
 	}
 }
 
+bool VisualComponent::containsFocused() {
+	if (this->parent != nullptr) {
+		// For child component, go back to the root and then follow the focus pointers to find out which component is focused within the whole tree.
+		//   One cannot just check if the parent points back directly, because old pointers may be left from a previous route.
+		VisualComponent *root = this; while (root->parent != nullptr) { root = root->parent; }
+		VisualComponent *current = root;
+		while (current->focusComponent.get() != nullptr) {
+			current = current->focusComponent.get();
+			if (current == this) return true; // Focused if the root component points back to this component somewhere along the way.
+		}
+		return false;
+	} else {
+		// Root component always contains the focused component is focused if it does not redirect its focus to a child component.
+		return this->focusComponent.get() == nullptr; // Focused if no child is focused.
+	}
+}
+
 MediaResult dsr::component_generateImage(VisualTheme theme, MediaMethod &method, int width, int height, int red, int green, int blue, int pressed, int focused, int hover) {
 	return method.callUsingKeywords([&theme, &method, width, height, red, green, blue, pressed, focused, hover](MediaMachine &machine, int methodIndex, int inputIndex, const ReadableString &argumentName){
 		if (string_caseInsensitiveMatch(argumentName, U"width")) {

+ 23 - 10
Source/DFPSR/gui/VisualComponent.h

@@ -39,19 +39,26 @@ MediaResult component_generateImage(VisualTheme theme, MediaMethod &method, int
 
 class VisualComponent : public Persistent {
 PERSISTENT_DECLARATION(VisualComponent)
-protected:
+public:
 	// Parent component
 	VisualComponent *parent = nullptr;
-	IRect givenSpace; // Remembering the local region that was reserved inside of the parent component
-	bool regionAccessed = false; // If someone requested access to the region, remember to update layout in case of new settings
+	IRect givenSpace; // Remembering the local region that was reserved inside of the parent component.
+	bool regionAccessed = false; // If someone requested access to the region, remember to update layout in case of new settings.
 	// Child components
 	List<std::shared_ptr<VisualComponent>> children;
-	// Remember the component used for a drag event
-	//   Ensures that mouse down events are followed by mouse up events on the same component
+	// Remember the component used for a drag event.
+	//   Ensures that mouse down events are followed by mouse up events on the same component.
 	int holdCount = 0;
+	// Remember the pressed component for sending mouse move events outside of its region.
 	std::shared_ptr<VisualComponent> dragComponent;
-	// Remember the focused component for keyboard input
+	// Remember the focused component for keyboard input.
 	std::shared_ptr<VisualComponent> focusComponent;
+	// The next overlay component, which may refer to one of its children as the next overlay to draw itself on top of other components.
+	//   The linked list goes from the root component in the window, across each component with an active overlay.
+	//   Examples:
+	//     Root -> ToolTipText
+	//     Root -> TopMenu -> SubMenu -> SubMenu
+	std::shared_ptr<VisualComponent> overlayComponent;
 	// Saved properties
 	FlexRegion region;
 	PersistentString name;
@@ -90,7 +97,7 @@ public:
 			return nullptr;
 		}
 	}
-protected:
+public:
 	// Generated automatically from region in applyLayout
 	IRect location;
 	void setLocation(const IRect &newLocation);
@@ -127,7 +134,7 @@ public:
 	DECLARE_CALLBACK(keyUpEvent, keyboardCallback);
 	DECLARE_CALLBACK(keyTypeEvent, keyboardCallback);
 	DECLARE_CALLBACK(selectEvent, indexCallback);
-private:
+public:
 	std::shared_ptr<VisualComponent> getDirectChild(const IVector2D& pixelPosition, bool includeInvisible);
 public:
 	// Draw the component
@@ -140,10 +147,12 @@ public:
 	// offset is the upper left corner of the parent container relative to the image.
 	//   Clipping will affect the offset by being relative to the new sub-image.
 	void draw(ImageRgbaU8& targetImage, const IVector2D& offset);
-	// A basic request to have the component itself drawn to targetImage at relativeLocation.
+	// Draw the component itself to targetImage at relativeLocation.
 	//   The method is responsible for clipping without a warning when bound is outside of targetImage.
-	//   Clipping will be common if the component is drawn using multiple dirty rectangles to save time.
 	virtual void drawSelf(ImageRgbaU8& targetImage, const IRect &relativeLocation);
+	// Draw the component's overlays on top of other components in the window.
+	//   Overlays are drawn using absolute positions in the window, without caring about any parent location.
+	virtual void drawOverlay(ImageRgbaU8& targetImage);
 	// Draw the component while skipping pixels outside of clipRegion
 	//   Multiple calls with non-overlapping clip regions should be equivalent to one call with the union of all clip regions.
 	//     This means that the draw methods should handle border clipping so that no extra borderlines or rounded edges appear from nowhere.
@@ -228,8 +237,12 @@ public:
 	// Custom call handler to manipulate components across a generic API
 	virtual String call(const ReadableString &methodName, const ReadableString &arguments);
 	// Returns true iff the component is focused.
+	//   Used for textboxes to know if they should be drawn as active.
 	//   The root component is considered focused if none of its children are focused.
 	bool isFocused();
+	// Returns true iff itself, a direct child or an indirect child has focus.
+	//   Used for menus to keep the whole path of sub-menus alive all the way down to the focused component.
+	bool containsFocused();
 };
 
 }