Browse Source

Disabled form control elements are now properly handled. They cannot receive focus or click events from user input.
Added example to invader sample options page.

Michael Ragazzon 6 years ago
parent
commit
60e88e7e65

+ 6 - 0
Samples/assets/invader.rcss

@@ -174,6 +174,12 @@ input.submit:active
 	background-image-t: 90px 135px;
 }
 
+input.submit:disabled
+{
+	background-image-t: 0px 45px;
+	image-color: rgba(50, 150, 150, 120);
+}
+
 
 
 input.text

+ 2 - 2
Samples/invaders/data/high_score.rml

@@ -5,8 +5,8 @@
 		<style>
 			body
 			{
-				width: 420px;
-				height: 420px;
+				width: 440px;
+				height: 440px;
 				
 				margin: auto;
 			}

+ 3 - 3
Samples/invaders/data/options.rml

@@ -6,7 +6,7 @@
 			body
 			{
 				width: 350px;
-				height: 350px;
+				height: 330px;
 				
 				margin: auto;
 			}
@@ -27,7 +27,7 @@
 		</style>
 	</head>
 	<body template="window" onload="restore">
-		<form onsubmit="store; goto main_menu">
+		<form onsubmit="store; goto main_menu" onchange="enable_accept">
 			<div>
 				<p>
 					Graphics:<br />
@@ -42,7 +42,7 @@
 					<input id="3d" type="checkbox" name="3d" value="true" /> 3D Spatialisation
 				</p>
 			</div>
-			<input type="submit" value="accept">Accept</input>
+			<input type="submit" id="accept" value="accept" disabled>Accept</input>
 			<input type="submit" value="cancel">Cancel</input>
 		</form>
 	</body>

+ 20 - 0
Samples/invaders/src/EventHandlerOptions.cpp

@@ -89,6 +89,13 @@ void EventHandlerOptions::ProcessEvent(Rocket::Core::Event& event, const Rocket:
 			else
 				spatialisation_option->RemoveAttribute("checked");
 		}
+
+		// Disable the accept button when default values are given
+		Rocket::Controls::ElementFormControlInput* accept = dynamic_cast<Rocket::Controls::ElementFormControlInput*>(options_body->GetElementById("accept"));
+		if (accept != NULL)
+		{
+			accept->SetDisabled(true);
+		}
 	}
 
 	// Sent from the 'onsubmit' action of the options menu; we read the values sent from the form and make the
@@ -139,4 +146,17 @@ void EventHandlerOptions::ProcessEvent(Rocket::Core::Event& event, const Rocket:
 				bad_warning->SetProperty("display", Property(Style::Display::Block));
 		}
 	}
+	else if (value == "enable_accept")
+	{
+		Rocket::Core::ElementDocument* options_body = event.GetTargetElement()->GetOwnerDocument();
+		if (options_body == NULL)
+			return;
+
+		// Enable the accept button when values are changed
+		Rocket::Controls::ElementFormControlInput* accept = dynamic_cast<Rocket::Controls::ElementFormControlInput*>(options_body->GetElementById("accept"));
+		if (accept != NULL)
+		{
+			accept->SetDisabled(false);
+		}
+	}
 }

+ 14 - 4
Source/Controls/ElementFormControl.cpp

@@ -68,10 +68,7 @@ bool ElementFormControl::IsDisabled() const
 void ElementFormControl::SetDisabled(bool disable)
 {
 	if (disable)
-	{
 		SetAttribute("disabled", "");
-		Blur();
-	}
 	else
 		RemoveAttribute("disabled");
 }
@@ -82,7 +79,20 @@ void ElementFormControl::OnAttributeChange(const Core::AttributeNameList& change
 	Core::Element::OnAttributeChange(changed_attributes);
 
 	if (changed_attributes.find("disabled") != changed_attributes.end())
-		SetPseudoClass("disabled", IsDisabled());
+	{
+		bool is_disabled = IsDisabled();
+		SetPseudoClass("disabled", is_disabled);
+
+		// Disable focus when element is disabled. This will also prevent click
+		// events (when originating from user inputs, see Context) to reach the element.
+		if (is_disabled)
+		{
+			SetProperty("focus", Core::Property(Core::Style::Focus::None));
+			Blur();
+		}
+		else
+			RemoveProperty("focus");
+	}
 }
 
 }

+ 5 - 0
Source/Controls/ElementFormControlInput.cpp

@@ -54,6 +54,7 @@ ElementFormControlInput::~ElementFormControlInput()
 // Returns a string representation of the current value of the form control.
 Rocket::Core::String ElementFormControlInput::GetValue() const
 {
+	ROCKET_ASSERT(type);
 	return type->GetValue();
 }
 
@@ -66,23 +67,27 @@ void ElementFormControlInput::SetValue(const Rocket::Core::String& value)
 // Returns if this value should be submitted with the form.
 bool ElementFormControlInput::IsSubmitted()
 {
+	ROCKET_ASSERT(type);
 	return type->IsSubmitted();
 }
 
 // Updates the element's underlying type.
 void ElementFormControlInput::OnUpdate()
 {
+	ROCKET_ASSERT(type);
 	type->OnUpdate();
 }
 
 // Renders the element's underlying type.
 void ElementFormControlInput::OnRender()
 {
+	ROCKET_ASSERT(type);
 	type->OnRender();
 }
 
 void ElementFormControlInput::OnResize()
 {
+	ROCKET_ASSERT(type);
 	type->OnResize();
 }
 

+ 0 - 43
Source/Controls/InputTypeButton.cpp

@@ -34,18 +34,10 @@ namespace Controls {
 
 InputTypeButton::InputTypeButton(ElementFormControlInput* element) : InputType(element)
 {
-	document = NULL;
-
-	// Call OnChildAdd() immediately; if the input element is already part of a document, this will
-	// attach our listeners to the document so the events can be intercepted.
-	OnChildAdd();
 }
 
 InputTypeButton::~InputTypeButton()
 {
-	// Call OnChildRemove(); in case our element is still attached to a document, this will detach
-	// our listeners.
-	OnChildRemove();
 }
 
 // Buttons are never submitted.
@@ -54,21 +46,8 @@ bool InputTypeButton::IsSubmitted()
 	return false;
 }
 
-// Checks for necessary functional changes in the control as a result of the event.
 void InputTypeButton::ProcessDefaultAction(Core::Event& event)
 {
-	// Stop a click event from proceeding any further if this button is disabled.
-	if (event.GetTargetElement() == element &&
-		element->IsDisabled() &&
-		(event == Core::EventId::Click || event == Core::EventId::Dblclick))
-	{
-		event.StopPropagation();
-	}
-}
-
-void InputTypeButton::ProcessEvent(Core::Event& event)
-{
-	ProcessDefaultAction(event);
 }
 
 // Sizes the dimensions to the element's inherent size.
@@ -79,27 +58,5 @@ bool InputTypeButton::GetIntrinsicDimensions(Rocket::Core::Vector2f& ROCKET_UNUS
 	return false;
 }
 
-// Called when the element is added into a hierarchy.
-void InputTypeButton::OnChildAdd()
-{
-	document = element->GetOwnerDocument();
-	if (document == NULL)
-		return;
-
-	document->AddEventListener("click", this, true);
-	document->AddEventListener("dblclick", this, true);
-}
-
-// Called when the element is removed from a hierarchy.
-void InputTypeButton::OnChildRemove()
-{
-	if (document != NULL)
-	{
-		document->RemoveEventListener("click", this, true);
-		document->RemoveEventListener("dblclick", this, true);
-		document = NULL;
-	}
-}
-
 }
 }

+ 4 - 15
Source/Controls/InputTypeButton.h

@@ -36,14 +36,13 @@ namespace Rocket {
 namespace Controls {
 
 /**
-	A button input type handler. The only functionality a button provides over a normal element is
-	the ability to be disabled to prevent 'click' events from being propagated any further than the
-	element's document.
+	A button input type handler. The only functionality a button provides over a normal element is the ability
+	to be disabled. This prevents 'click' events on this element and the ability to receive focus.
 
 	@author Peter Curry
  */
 
-class InputTypeButton : public InputType, public Core::EventListener
+class InputTypeButton : public InputType
 {
 public:
 	InputTypeButton(ElementFormControlInput* element);
@@ -56,20 +55,10 @@ public:
 	/// Checks for necessary functional changes in the control as a result of the event.
 	/// @param[in] event The event to process.
 	virtual void ProcessDefaultAction(Core::Event& event) override;
-	/// If button is disabled, cancels the event during the capture phase
-	virtual void ProcessEvent(Core::Event& event) override;
 
 	/// Sizes the dimensions to the element's inherent size.
-	/// @return True.
+	/// @return False.
 	virtual bool GetIntrinsicDimensions(Rocket::Core::Vector2f& dimensions);
-
-	// Called when the element is added into a hierarchy.
-	virtual void OnChildAdd();
-	/// Called when the element is removed from a hierarchy.
-	virtual void OnChildRemove();
-
-private:
-	Core::ElementDocument* document;
 };
 
 }

+ 1 - 1
Source/Controls/InputTypeRadio.cpp

@@ -79,7 +79,7 @@ void InputTypeRadio::OnChildAdd()
 // Checks for necessary functional changes in the control as a result of the event.
 void InputTypeRadio::ProcessDefaultAction(Core::Event& event)
 {
-	if (event == "click" &&
+	if (event == Core::EventId::Click &&
 		!element->IsDisabled())
 		element->SetAttribute("checked", "");
 }

+ 1 - 1
Source/Controls/InputTypeSubmit.h

@@ -54,7 +54,7 @@ public:
 	virtual void ProcessDefaultAction(Core::Event& event) override;
 
 	/// Sizes the dimensions to the element's inherent size.
-	/// @return True.
+	/// @return False.
 	virtual bool GetIntrinsicDimensions(Rocket::Core::Vector2f& dimensions);
 };
 

+ 1 - 3
Source/Controls/WidgetTextInput.cpp

@@ -370,8 +370,6 @@ void WidgetTextInput::ProcessEvent(Core::Event& event)
 			return;
 
 		default:
-		{
-		}
 		break;
 		}
 
@@ -428,7 +426,7 @@ void WidgetTextInput::ProcessEvent(Core::Event& event)
 			UpdateCursorPosition();
 			ideal_cursor_position = cursor_position.x;
 
-			UpdateSelection(event == "drag" || event.GetParameter< int >("shift_key", 0) > 0);
+			UpdateSelection(event == Core::EventId::Drag || event.GetParameter< int >("shift_key", 0) > 0);
 
 			ShowCursor(true);
 		}

+ 1 - 13
Source/Core/Context.cpp

@@ -591,7 +591,7 @@ static Element* FindFocusElement(Element* element)
 	if (!owner_document || owner_document->GetComputedValues().focus == Style::Focus::None)
 		return NULL;
 	
-	while (element && element->GetProperty< int >(FOCUS) == FOCUS_NONE)
+	while (element && element->GetComputedValues().focus == Style::Focus::None)
 	{
 		element = element->GetParentNode();
 	}
@@ -985,18 +985,6 @@ void Context::UpdateHoverChain(const Dictionary& parameters, const Dictionary& d
 			element = element->GetParentNode();
 		}
 
-/*		if (mouse_moved && !drag_started)
-		{
-			drag->DispatchEvent(DRAGSTART, drag_parameters);
-			drag_started = true;
-
-			if (drag->GetProperty< int >(DRAG) == DRAG_CLONE)
-			{
-				// Clone the element and attach it to the mouse cursor.
-				CreateDragClone(*drag);
-			}
-		}*/
-
 		if (drag_started &&
 			drag_verbose)
 		{

+ 4 - 0
Source/Core/EventDispatcher.cpp

@@ -119,6 +119,10 @@ bool EventDispatcher::DispatchEvent(Element* target_element, EventId id, const S
 	if (!event)
 		return false;
 
+	//// Click events may be disabled on the element.
+	//if (id == EventId::Click && target_element->IsDisabled())
+	//	return false;
+
 	// Build the element traversal from the tree
 	typedef std::vector<Element*> Elements;
 	Elements elements;