Просмотр исходного кода

Implement 'max' attribute on progress bars

Michael Ragazzon 4 лет назад
Родитель
Сommit
6687833f77

+ 5 - 4
Include/RmlUi/Core/Elements/ElementProgressBar.h

@@ -67,10 +67,13 @@ public:
 	ElementProgressBar(const String& tag);
 	virtual ~ElementProgressBar();
 
-	/// Return the value of the progress bar [0, 1]
+	/// Returns the value of the progress bar.
 	float GetValue() const;
 
-	/// Set the value of the progress bar
+	/// Returns the maximum value of the progress bar.
+	float GetMax() const;
+
+	/// Sets the value of the progress bar.
 	void SetValue(float value);
 
 	/// Returns the element's inherent size.
@@ -98,8 +101,6 @@ private:
 	Direction direction;
 	StartEdge start_edge;
 
-	float value;
-
 	Element* fill;
 
 	// The size of the fill geometry as if fully filled, and the offset relative to the 'progressbar' element.

+ 24 - 16
Source/Core/Elements/ElementProgressBar.cpp

@@ -39,7 +39,7 @@
 
 namespace Rml {
 
-ElementProgressBar::ElementProgressBar(const String& tag) : Element(tag), direction(DefaultDirection), start_edge(DefaultStartEdge), value(0), fill(nullptr), rect_set(false), geometry(this)
+ElementProgressBar::ElementProgressBar(const String& tag) : Element(tag), direction(DefaultDirection), start_edge(DefaultStartEdge), fill(nullptr), rect_set(false), geometry(this)
 {
 	geometry_dirty = false;
 
@@ -55,7 +55,14 @@ ElementProgressBar::~ElementProgressBar()
 
 float ElementProgressBar::GetValue() const
 {
-	return value;
+	const float max_value = GetMax();
+	return Math::Clamp(GetAttribute< float >("value", 0.0f), 0.0f, max_value);
+}
+
+float ElementProgressBar::GetMax() const
+{
+	const float max_value = GetAttribute< float >("max", 1.0f);
+	return max_value <= 0.0f ? 1.0f : max_value;
 }
 
 void ElementProgressBar::SetValue(float in_value)
@@ -77,16 +84,16 @@ void ElementProgressBar::OnRender()
 		GenerateGeometry();
 
 	// Render the geometry at the fill element's content region.
-	geometry.Render(fill->GetAbsoluteOffset().Round());
+	geometry.Render(fill->GetAbsoluteOffset());
 }
 
 void ElementProgressBar::OnAttributeChange(const ElementAttributes& changed_attributes)
 {
 	Element::OnAttributeChange(changed_attributes);
 
-	if (changed_attributes.find("value") != changed_attributes.end())
+	if (changed_attributes.find("value") != changed_attributes.end()
+		|| changed_attributes.find("max") != changed_attributes.end())
 	{
-		value = Math::Clamp( GetAttribute< float >("value", 0.0f), 0.0f, 1.0f);
 		geometry_dirty = true;
 	}
 
@@ -171,6 +178,7 @@ void ElementProgressBar::GenerateGeometry()
 	if (fill->GetLocalProperty(PropertyId::FillImage))
 		Log::Message(Log::LT_WARNING, "Breaking change: The 'fill-image' property now needs to be set on the <progressbar> element, instead of its inner <fill> element. Please update your RCSS source to fix progress bars in this document.");
 
+	const float normalized_value = GetValue() / GetMax();
 	Vector2f render_size = fill_size;
 
 	{
@@ -179,17 +187,17 @@ void ElementProgressBar::GenerateGeometry()
 
 		switch (direction) {
 		case Direction::Top:
-			render_size.y = fill_size.y * value;
+			render_size.y = fill_size.y * normalized_value;
 			offset.y = fill_offset.y + fill_size.y - render_size.y;
 			break;
 		case Direction::Right:
-			render_size.x = fill_size.x * value;
+			render_size.x = fill_size.x * normalized_value;
 			break;
 		case Direction::Bottom:
-			render_size.y = fill_size.y * value;
+			render_size.y = fill_size.y * normalized_value;
 			break;
 		case Direction::Left:
-			render_size.x = fill_size.x * value;
+			render_size.x = fill_size.x * normalized_value;
 			offset.x = fill_offset.x + fill_size.x - render_size.x;
 			break;
 		case Direction::Clockwise:
@@ -253,10 +261,10 @@ void ElementProgressBar::GenerateGeometry()
 	{
 		// For the top, right, bottom, left directions the fill element already describes where we should draw the fill,
 		// we only need to generate the final texture coordinates here.
-	case Direction::Top:    texcoords[0].y = texcoords[0].y + (1.0f - value) * (texcoords[1].y - texcoords[0].y); break;
-	case Direction::Right:  texcoords[1].x = texcoords[0].x + value * (texcoords[1].x - texcoords[0].x);          break;
-	case Direction::Bottom: texcoords[1].y = texcoords[0].y + value * (texcoords[1].y - texcoords[0].y);          break;
-	case Direction::Left:   texcoords[0].x = texcoords[0].x + (1.0f - value) * (texcoords[1].x - texcoords[0].x); break;
+	case Direction::Top:    texcoords[0].y = texcoords[0].y + (1.0f - normalized_value) * (texcoords[1].y - texcoords[0].y); break;
+	case Direction::Right:  texcoords[1].x = texcoords[0].x + normalized_value * (texcoords[1].x - texcoords[0].x);          break;
+	case Direction::Bottom: texcoords[1].y = texcoords[0].y + normalized_value * (texcoords[1].y - texcoords[0].y);          break;
+	case Direction::Left:   texcoords[0].x = texcoords[0].x + (1.0f - normalized_value) * (texcoords[1].x - texcoords[0].x); break;
 
 	case Direction::Clockwise:
 	case Direction::CounterClockwise:
@@ -264,7 +272,7 @@ void ElementProgressBar::GenerateGeometry()
 		// The circular directions require custom geometry as a box is insufficient.
 		// We divide the "circle" into eight parts, here called octants, such that each part can be represented by a triangle.
 		// 'num_octants' tells us how many of these are completely or partially filled.
-		const int num_octants = Math::Clamp(Math::RoundUpToInteger(8.f * value), 0, 8);
+		const int num_octants = Math::Clamp(Math::RoundUpToInteger(8.f * normalized_value), 0, 8);
 		const int num_vertices = 2 + num_octants;
 		const int num_triangles = num_octants;
 		const bool cw = (direction == Direction::Clockwise);
@@ -293,11 +301,11 @@ void ElementProgressBar::GenerateGeometry()
 		}
 
 		// Find the position of the vertex representing the partially filled triangle.
-		if (value < 1.f)
+		if (normalized_value < 1.f)
 		{
 			using namespace Math;
 			const float angle_offset = float(start_octant) / 8.f * 2.f * RMLUI_PI;
-			const float angle = angle_offset + (cw ? 1.f : -1.f) * value * 2.f * RMLUI_PI;
+			const float angle = angle_offset + (cw ? 1.f : -1.f) * normalized_value * 2.f * RMLUI_PI;
 			Vector2f pos(Sin(angle), -Cos(angle));
 			// Project it from the circle towards the surrounding unit square.
 			pos = pos / Max(AbsoluteValue(pos.x), AbsoluteValue(pos.y));

+ 1 - 0
changelog.md

@@ -137,6 +137,7 @@ See the [media queries documentation](https://mikke89.github.io/RmlUiDoc/pages/r
 - `<select>` elements now react to changes in the `value` attribute.
 - Element attributes can now use escaped RML characters, eg. `<p example="&quot;Quoted text&quot;"/>`. [#154](https://github.com/mikke89/RmlUi/pull/154) (thanks @actboy168).
 - Tabs and panels in tab sets will no longer set the `display` property to `inline-block`, thus it is now possible to customize the display property.
+- `<progressbar>` elements now supports the `max` attribute.
 - Changing the `fill-image` property of `<progressbar>` elements now actually updates the image.
 
 ### Input handling