فهرست منبع

Image decorator can now align / position itself within its boundaries.

Michael Ragazzon 6 سال پیش
والد
کامیت
5ffe4f4d80

+ 29 - 14
Samples/basic/demo/data/demo.rml

@@ -8,7 +8,7 @@ body.window
 	max-width: 1400px;
 	max-height: 850px;
 	width: 1300px;
-	height: 800px;
+	height: 750px;
 }
 div#title_bar div#icon
 {
@@ -54,7 +54,7 @@ tab:active, tab:selected
 panels
 {
     display: block;
-    height: 460px;
+    height: 580px;
 	padding: 20px 20px;
 	border: 1px #ddd;
     background-color: #ccc3;
@@ -129,16 +129,21 @@ button:focus {
 	margin-left: 40px;
 	margin-right: 80px;
 }
-.fit-fill       { decorator: image( icon-invader fill ); }
-.fit-contain    { decorator: image( icon-invader contain ); }
-.fit-cover      { decorator: image( icon-invader cover ); }
-.fit-center     { decorator: image( icon-invader center ); }
+.align-default     { decorator: image( icon-invader scale-none             ); }
+.align-right       { decorator: image( icon-invader scale-none right       ); }
+.align-left-bottom { decorator: image( icon-invader scale-none left bottom ); }
+.align-percent     { decorator: image( icon-invader scale-none 70% 30%     ); }
+.align-pixel       { decorator: image( icon-invader scale-none 100px -15px ); }
+.fit-fill       { decorator: image( icon-invader fill       ); }
+.fit-contain    { decorator: image( icon-invader contain    ); }
+.fit-cover      { decorator: image( icon-invader cover      ); }
+.fit-scale-none { decorator: image( icon-invader scale-none ); }
 .fit-scale-down { decorator: image( icon-invader scale-down ); }
-.transform.fit-fill       { decorator: image( icon-invader fill        flip-horizontal ); }
-.transform.fit-contain    { decorator: image( icon-invader contain     flip-horizontal ); }
-.transform.fit-cover      { decorator: image( icon-invader cover       flip-horizontal ); }
-.transform.fit-center     { decorator: image( icon-invader center      flip-horizontal ); }
-.transform.fit-scale-down { decorator: image( icon-invader scale-down  flip-horizontal ); }
+.transform.fit-fill       { decorator: image( icon-invader fill       rotate-90 ); }
+.transform.fit-contain    { decorator: image( icon-invader contain    rotate-90 ); }
+.transform.fit-cover      { decorator: image( icon-invader cover      rotate-90 ); }
+.transform.fit-scale-none { decorator: image( icon-invader scale-none rotate-90 ); }
+.transform.fit-scale-down { decorator: image( icon-invader scale-down rotate-90 ); }
 p.emojis
 {
 	text-align: left;
@@ -180,26 +185,36 @@ textarea {
 		<button class="gradient">Gradient</button>
 		<button class="gradient horizontal">Gradient</button>
 	</div>
+	<h1>Image decorator alignment modes</h1>
+	<div class="image-fit">
+		<div class="align-default" style="font-style: italic;">default</div>
+		<div class="align-right">right</div>
+		<div class="align-left-bottom">left bottom</div>
+		<div class="align-percent">70% 30%</div>
+		<div class="align-pixel">100px -15px</div>
+		<p style="margin: 0.3em 0 0 0;">Using fit mode 'scale-none'.</p>
+	</div>
+
 	<h1>Image decorator fit modes</h1>
 	<div class="image-fit">
 		<div class="fit-fill">fill</div>
 		<div class="fit-contain">contain</div>
 		<div class="fit-cover">cover</div>
-		<div class="fit-center">center</div>
+		<div class="fit-scale-none">scale-none</div>
 		<div class="fit-scale-down">scale-down</div>
 	</div>
 	<div class="image-fit small">
 		<div class="fit-fill"></div>
 		<div class="fit-contain"></div>
 		<div class="fit-cover"></div>
-		<div class="fit-center"></div>
+		<div class="fit-scale-none"></div>
 		<div class="fit-scale-down"></div>
 	</div>
 	<div class="image-fit small">
 		<div class="transform fit-fill"></div>
 		<div class="transform fit-contain"></div>
 		<div class="transform fit-cover"></div>
-		<div class="transform fit-center"></div>
+		<div class="transform fit-scale-none"></div>
 		<div class="transform fit-scale-down"></div>
 	</div>
 </panel>

+ 1 - 1
Samples/basic/demo/src/main.cpp

@@ -191,7 +191,7 @@ int main(int RMLUI_UNUSED_PARAMETER(argc), char** RMLUI_UNUSED_PARAMETER(argv))
 #endif
 
 	const int width = 1600;
-	const int height = 1000;
+	const int height = 950;
 
 	ShellRenderInterfaceOpenGL opengl_renderer;
 	shell_renderer = &opengl_renderer;

+ 22 - 12
Source/Core/DecoratorTiled.cpp

@@ -195,12 +195,11 @@ void DecoratorTiled::Tile::GenerateGeometry(std::vector< Vertex >& vertices, std
 	}
 
 
-	Vector2f tile_offset(0, 0);
-	bool clamp_tile = false;
-	
 	// For now, we assume that fit mode and repeat mode cannot both be set on a single tile. The two code paths won't work well together.
 	RMLUI_ASSERT(repeat_mode == STRETCH || fit_mode == FILL);
 
+	bool offset_and_clip_tile = false;
+
 	switch (fit_mode)
 	{
 	case FILL:
@@ -212,7 +211,7 @@ void DecoratorTiled::Tile::GenerateGeometry(std::vector< Vertex >& vertices, std
 		float min_factor = std::min(scale_factor.x, scale_factor.y);
 		final_tile_dimensions = tile_dimensions * min_factor;
 
-		tile_offset = ((surface_dimensions - final_tile_dimensions) * 0.5f).Round();
+		offset_and_clip_tile = true;
 	}
 	break;
 	case COVER:
@@ -221,16 +220,14 @@ void DecoratorTiled::Tile::GenerateGeometry(std::vector< Vertex >& vertices, std
 		float max_factor = std::max(scale_factor.x, scale_factor.y);
 		final_tile_dimensions = tile_dimensions * max_factor;
 
-		tile_offset = ((surface_dimensions - final_tile_dimensions) * 0.5f).Round();
-		clamp_tile = true;
+		offset_and_clip_tile = true;
 	}
 	break;
-	case CENTER:
+	case SCALE_NONE:
 	{
 		final_tile_dimensions = tile_dimensions;
 		
-		tile_offset = ((surface_dimensions - final_tile_dimensions) * 0.5f).Round();
-		clamp_tile = true;
+		offset_and_clip_tile = true;
 	}
 	break;
 	case SCALE_DOWN:
@@ -242,14 +239,27 @@ void DecoratorTiled::Tile::GenerateGeometry(std::vector< Vertex >& vertices, std
 		else
 			final_tile_dimensions = tile_dimensions;
 
-		tile_offset = ((surface_dimensions - final_tile_dimensions) * 0.5f).Round();
+		offset_and_clip_tile = true;
 	}
 	break;
 	}
 
-	if (clamp_tile)
+
+	Vector2f tile_offset(0, 0);
+
+	if (offset_and_clip_tile)
 	{
-		// Along each dimension, see if our tile extends outside the boundary at either side.
+		// Offset tile along each dimension.
+		for(int i = 0; i < 2; i++)
+		{
+			switch (align[i].type) {
+			case Style::LengthPercentage::Length:      tile_offset[i] = align[i].value;  break;
+			case Style::LengthPercentage::Percentage:  tile_offset[i] = (surface_dimensions[i] - final_tile_dimensions[i]) * align[i].value * 0.01f;  break;
+			}
+		}
+		tile_offset = tile_offset.Round();
+
+		// Clip tile. See if our tile extends outside the boundary at either side, along each dimension.
 		for(int i = 0; i < 2; i++)
 		{
 			// Left/right acts as top/bottom during the second iteration.

+ 6 - 3
Source/Core/DecoratorTiled.h

@@ -81,8 +81,8 @@ public:
 	{
 		FILL,       // Tile is stretched to boundaries.
 		CONTAIN,    // Tile is stretched to boundaries, keeping aspect ratio fixed, 'letter-boxed'.
-		COVER,      // Tile is stretched to cover the boundaries, keeping aspect ratio fixed, and clipped.
-		CENTER,     // Tile is centered and never stretched, clipped if too large.
+		COVER,      // Tile is stretched to cover the boundaries, keeping aspect ratio fixed.
+		SCALE_NONE, // Tile is never scaled.
 		SCALE_DOWN, // Tile acts like 'center' if smaller than boundaries, or like 'contain' otherwise.
 	};
 
@@ -130,8 +130,11 @@ public:
 		mutable TileDataMap data;
 
 		TileRepeatMode repeat_mode;
-		TileFitMode fit_mode;
 		TileOrientation orientation;
+
+		TileFitMode fit_mode;
+		Style::LengthPercentage align[2]; 
+
 	};
 
 protected:

+ 52 - 3
Source/Core/DecoratorTiledInstancer.cpp

@@ -70,11 +70,24 @@ void DecoratorTiledInstancer::RegisterTileProperty(const String& name, bool regi
 	{
 		String fit_name = CreateString(32, "%s-fit", name.c_str());
 		ids.fit = RegisterProperty(fit_name, "fill")
-			.AddParser("keyword", "fill, contain, cover, center, scale-down")
+			.AddParser("keyword", "fill, contain, cover, scale-none, scale-down")
+			.GetId();
+
+		String align_x_name = CreateString(32, "%s-align-x", name.c_str());
+		ids.align_x = RegisterProperty(align_x_name, "center")
+			.AddParser("keyword", "left, center, right")
+			.AddParser("length_percent")
+			.GetId();
+
+		String align_y_name = CreateString(32, "%s-align-y", name.c_str());
+		ids.align_y = RegisterProperty(align_y_name, "center")
+			.AddParser("keyword", "top, center, bottom")
+			.AddParser("length_percent")
 			.GetId();
-		additional_modes += fit_name + ", ";
-	}
 
+		additional_modes += fit_name + ", " + align_x_name + ", " + align_y_name + ", ";
+	}
+	
 	RegisterShorthand(name, CreateString(256, ("%s-src, " + additional_modes + "%s-orientation, %s-x, %s-y, %s-width, %s-height").c_str(),
 		name.c_str(), name.c_str(), name.c_str(), name.c_str(), name.c_str(), name.c_str()),
 		ShorthandType::FallThrough);
@@ -176,8 +189,44 @@ bool DecoratorTiledInstancer::GetTileProperties(DecoratorTiled::Tile* tiles, Tex
 
 		if (ids.fit != PropertyId::Invalid)
 		{
+			RMLUI_ASSERT(ids.align_x != PropertyId::Invalid && ids.align_y != PropertyId::Invalid);
 			const Property& fit_property = *properties.GetProperty(ids.fit);
 			tile.fit_mode = (DecoratorTiled::TileFitMode)fit_property.value.Get< int >();
+
+			const Property* align_properties[2] = {
+				properties.GetProperty(ids.align_x),
+				properties.GetProperty(ids.align_y)
+			};
+
+			for (int i = 0; i < 2; i++)
+			{
+				using Style::LengthPercentage;
+
+				auto& align = tile.align[i];
+				auto& property = *align_properties[i];
+				if (property.unit == Property::KEYWORD)
+				{
+					enum { TOP_LEFT, CENTER, BOTTOM_RIGHT };
+					switch (property.Get<int>())
+					{
+					case TOP_LEFT:     align = LengthPercentage(LengthPercentage::Percentage, 0.0f); break;
+					case CENTER:       align = LengthPercentage(LengthPercentage::Percentage, 50.0f); break;
+					case BOTTOM_RIGHT: align = LengthPercentage(LengthPercentage::Percentage, 100.0f); break;
+					}
+				}
+				else if (property.unit == Property::PERCENT)
+				{
+					align = LengthPercentage(LengthPercentage::Percentage, property.Get<float>());
+				}
+				else if(property.unit == Property::PX) 
+				{
+					align = LengthPercentage(LengthPercentage::Length, property.Get<float>());
+				}
+				else
+				{
+					Log::Message(Log::LT_WARNING, "Decorator alignment value is '%s' which uses an unsupported unit (use px, %%, or keyword)", property.ToString().c_str());
+				}
+			}
 		}
 
 		if (ids.orientation != PropertyId::Invalid)

+ 1 - 1
Source/Core/DecoratorTiledInstancer.h

@@ -63,7 +63,7 @@ protected:
 
 private:
 	struct TilePropertyIds {
-		PropertyId src, repeat, x, y, width, height, orientation, fit;
+		PropertyId src, repeat, x, y, width, height, orientation, fit, align_x, align_y;
 	};
 
 	std::vector<TilePropertyIds> tile_property_ids;