Add support for 9-patch images
This commit is contained in:
Родитель
0c3884d56d
Коммит
5b1f32a80e
|
@ -86,7 +86,7 @@ namespace Samples
|
|||
AddSample (listView, "Editable checkboxes", typeof(ListView2));
|
||||
AddSample (w, "Markdown", typeof (MarkDownSample));
|
||||
AddSample (w, "Menu", typeof(MenuSamples));
|
||||
var mn = AddSample (w, "Mnemonics", typeof (Mnemonics));
|
||||
AddSample (w, "Mnemonics", typeof (Mnemonics));
|
||||
AddSample (w, "Notebook", typeof(NotebookSample));
|
||||
AddSample (w, "Paneds", typeof(PanedViews));
|
||||
AddSample (w, "Popover", typeof(PopoverSample));
|
||||
|
@ -111,6 +111,7 @@ namespace Samples
|
|||
AddSample (n, "Text", typeof(DrawingText));
|
||||
AddSample (n, "Partial Images", typeof (PartialImages));
|
||||
AddSample (n, "Custom Drawn Image", typeof (ImageScaling));
|
||||
AddSample (n, "9-patch Image", typeof (Image9Patch));
|
||||
AddSample (n, "Widget Rendering", typeof (WidgetRendering));
|
||||
|
||||
var wf = AddSample (null, "Widget Features", null);
|
||||
|
|
|
@ -101,6 +101,7 @@
|
|||
<Compile Include="Samples\ListView2.cs" />
|
||||
<Compile Include="Samples\OpacitySample.cs" />
|
||||
<Compile Include="Samples\PasswordEntries.cs" />
|
||||
<Compile Include="Samples\Image9Patch.cs" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||
<ItemGroup>
|
||||
|
@ -126,6 +127,28 @@
|
|||
<EmbeddedResource Include="document-generic%402x.png">
|
||||
<LogicalName>document-generic@2x.png</LogicalName>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="zoom-panel-dark.9.png">
|
||||
<LogicalName>zoom-panel-dark.9.png</LogicalName>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="zoom-panel-dark%402x.9.png">
|
||||
<LogicalName>zoom-panel-dark@2x.9.png</LogicalName>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="..\Testing\Tests\ninep-ss.9.png">
|
||||
<Link>Samples\ninep-ss.9.png</Link>
|
||||
<LogicalName>ninep-ss.9.png</LogicalName>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="..\Testing\Tests\ninep-st.9.png">
|
||||
<Link>Samples\ninep-st.9.png</Link>
|
||||
<LogicalName>ninep-st.9.png</LogicalName>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="..\Testing\Tests\ninep-ts.9.png">
|
||||
<Link>Samples\ninep-ts.9.png</Link>
|
||||
<LogicalName>ninep-ts.9.png</LogicalName>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="..\Testing\Tests\ninep-tt.9.png">
|
||||
<Link>Samples\ninep-tt.9.png</Link>
|
||||
<LogicalName>ninep-tt.9.png</LogicalName>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
<ProjectExtensions>
|
||||
<MonoDevelop>
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
//
|
||||
// Image9Patch.cs
|
||||
//
|
||||
// Author:
|
||||
// lluis <>
|
||||
//
|
||||
// Copyright (c) 2013 lluis
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
using System;
|
||||
using Xwt;
|
||||
using Xwt.Drawing;
|
||||
|
||||
namespace Samples
|
||||
{
|
||||
public class Image9Patch: Canvas
|
||||
{
|
||||
Image img_ss, img_tt, img_st, img_ts;
|
||||
|
||||
public Image9Patch ()
|
||||
{
|
||||
img_ss = Image.FromResource ("ninep-ss.9.png");
|
||||
img_tt = Image.FromResource ("ninep-tt.9.png");
|
||||
img_st = Image.FromResource ("ninep-st.9.png");
|
||||
img_ts = Image.FromResource ("ninep-ts.9.png");
|
||||
Margin = 30;
|
||||
}
|
||||
|
||||
protected override void OnDraw (Context ctx, Rectangle dirtyRect)
|
||||
{
|
||||
var w = Math.Truncate (Bounds.Width / 2);
|
||||
var h = Math.Truncate (Bounds.Height / 2);
|
||||
ctx.DrawImage (img_ss, new Rectangle (0, 0, w, h).Inflate (-10, -10));
|
||||
ctx.DrawImage (img_tt, new Rectangle (w, 0, w, h).Inflate (-10, -10));
|
||||
ctx.DrawImage (img_st, new Rectangle (0, h, w, h).Inflate (-10, -10));
|
||||
ctx.DrawImage (img_ts, new Rectangle (w, h, w, h).Inflate (-10, -10));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 2.0 KiB |
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 4.0 KiB |
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 1.7 KiB |
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 1.7 KiB |
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 1.7 KiB |
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 1.7 KiB |
|
@ -91,6 +91,12 @@ namespace Xwt.CairoBackend
|
|||
|
||||
#region IContextBackendHandler implementation
|
||||
|
||||
public override double GetScaleFactor (object backend)
|
||||
{
|
||||
CairoContextBackend gc = (CairoContextBackend)backend;
|
||||
return gc.ScaleFactor;
|
||||
}
|
||||
|
||||
public override void Save (object backend)
|
||||
{
|
||||
CairoContextBackend gc = (CairoContextBackend)backend;
|
||||
|
@ -312,9 +318,9 @@ namespace Xwt.CairoBackend
|
|||
ctx.Context.NewPath();
|
||||
ctx.Context.Rectangle (destRect.X, destRect.Y, destRect.Width, destRect.Height);
|
||||
ctx.Context.Clip ();
|
||||
ctx.Context.Translate (destRect.X-srcRect.X, destRect.Y-srcRect.Y);
|
||||
double sx = destRect.Width / srcRect.Width;
|
||||
double sy = destRect.Height / srcRect.Height;
|
||||
ctx.Context.Translate (destRect.X-srcRect.X*sx, destRect.Y-srcRect.Y*sy);
|
||||
ctx.Context.Scale (sx, sy);
|
||||
img.Alpha *= ctx.GlobalAlpha;
|
||||
|
||||
|
|
|
@ -54,6 +54,11 @@ namespace Xwt.Mac
|
|||
{
|
||||
const double degrees = System.Math.PI / 180d;
|
||||
|
||||
public override double GetScaleFactor (object backend)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
public override void Save (object backend)
|
||||
{
|
||||
var ct = (CGContextBackend) backend;
|
||||
|
|
|
@ -207,7 +207,17 @@ namespace Xwt.Mac
|
|||
|
||||
public override object CropBitmap (object backend, int srcX, int srcY, int width, int height)
|
||||
{
|
||||
throw new NotImplementedException ();
|
||||
NSImage img = (NSImage)backend;
|
||||
NSBitmapImageRep bitmap = img.Representations ().OfType<NSBitmapImageRep> ().FirstOrDefault ();
|
||||
if (bitmap != null) {
|
||||
RectangleF empty = RectangleF.Empty;
|
||||
var cgi = bitmap.AsCGImage (ref empty, null, null).WithImageInRect (new RectangleF (srcX, srcY, width, height));
|
||||
NSImage res = new NSImage (cgi, new SizeF (width, height));
|
||||
cgi.Dispose ();
|
||||
return res;
|
||||
}
|
||||
else
|
||||
throw new InvalidOperationException ("Not a bitmnap image");
|
||||
}
|
||||
|
||||
static NSImage FromResource (string res)
|
||||
|
|
|
@ -81,6 +81,8 @@ namespace Xwt.Backends
|
|||
/// It doesn't affect colors that have already been set.
|
||||
/// </summary>
|
||||
public abstract void SetGlobalAlpha (object backend, double globalAlpha);
|
||||
|
||||
public abstract double GetScaleFactor (object backend);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -92,6 +92,20 @@ namespace Xwt.Drawing
|
|||
return new BitmapImage (ToolkitEngine.ImageBackendHandler.CropBitmap (Backend, x, y, pixelWidth, pixelHeight), new Size (pixelWidth / scaleX, pixelHeight / scaleY));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a crop of the image
|
||||
/// </summary>
|
||||
/// <param name="x">X coordinate, in physical pixels</param>
|
||||
/// <param name="srcY">Y coordinate, in physical pixels</param>
|
||||
/// <param name="pixelWidth">Width, in physical pixels</param>
|
||||
/// <param name="pixelHeight">Height, in physical pixels</param>
|
||||
public BitmapImage Crop (Rectangle pixelRect)
|
||||
{
|
||||
var scaleX = Math.Truncate (PixelWidth / Width);
|
||||
var scaleY = Math.Truncate (PixelHeight / Height);
|
||||
return new BitmapImage (ToolkitEngine.ImageBackendHandler.CropBitmap (Backend, (int)pixelRect.X, (int)pixelRect.Y, (int)pixelRect.Width, (int)pixelRect.Height), new Size (pixelRect.Width / scaleX, pixelRect.Height / scaleY));
|
||||
}
|
||||
|
||||
public Size PixelSize {
|
||||
get { return pixelSize; }
|
||||
}
|
||||
|
|
|
@ -358,6 +358,10 @@ namespace Xwt.Drawing
|
|||
{
|
||||
handler.SetLineDash (Backend, offset, pattern);
|
||||
}
|
||||
|
||||
internal double ScaleFactor {
|
||||
get { return handler.GetScaleFactor (Backend); }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -40,6 +40,8 @@ namespace Xwt.Drawing
|
|||
internal NativeImageRef NativeRef;
|
||||
internal double requestedAlpha = 1;
|
||||
|
||||
static int[] supportedScales = { 2 };
|
||||
|
||||
internal Image ()
|
||||
{
|
||||
}
|
||||
|
@ -173,7 +175,9 @@ namespace Xwt.Drawing
|
|||
|
||||
var reqSize = toolkit.ImageBackendHandler.GetSize (img);
|
||||
|
||||
List<object> altImages = new List<object> ();
|
||||
var ext = GetExtension (resource);
|
||||
var altImages = new List<Tuple<string,object>> ();
|
||||
|
||||
foreach (var r in assembly.GetManifestResourceNames ()) {
|
||||
int i = r.LastIndexOf ('@');
|
||||
if (i != -1) {
|
||||
|
@ -181,17 +185,22 @@ namespace Xwt.Drawing
|
|||
if (rname == resource || rname == name) {
|
||||
var rim = toolkit.ImageBackendHandler.LoadFromResource (assembly, r);
|
||||
if (rim != null)
|
||||
altImages.Add (rim);
|
||||
altImages.Add (new Tuple<string, object> (r, rim));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (altImages.Count > 0) {
|
||||
altImages.Insert (0, img);
|
||||
img = toolkit.ImageBackendHandler.CreateMultiResolutionImage (altImages);
|
||||
altImages.Insert (0, new Tuple<string, object> (resource, img));
|
||||
if (ext == ".9.png")
|
||||
return CreateComposedNinePatch (toolkit, altImages);
|
||||
img = toolkit.ImageBackendHandler.CreateMultiResolutionImage (altImages.Select (i => i.Item2));
|
||||
}
|
||||
return new Image (img, toolkit) {
|
||||
var res = new Image (img, toolkit) {
|
||||
requestedSize = reqSize
|
||||
};
|
||||
if (ext == ".9.png")
|
||||
res = new NinePatchImage (res.ToBitmap ());
|
||||
return res;
|
||||
}
|
||||
|
||||
public static Image CreateMultiSizeIcon (IEnumerable<Image> images)
|
||||
|
@ -201,66 +210,57 @@ namespace Xwt.Drawing
|
|||
return new Image (Toolkit.CurrentEngine.ImageBackendHandler.CreateMultiSizeIcon (images.Select (i => i.GetBackend ())));
|
||||
}
|
||||
|
||||
/* static bool ParseImageName (string resourceId, string fileName, out int size, out int scale)
|
||||
{
|
||||
if (!fileName.StartsWith (resourceId)) {
|
||||
size = -1;
|
||||
scale = -1;
|
||||
return false;
|
||||
}
|
||||
|
||||
size = -1;
|
||||
int i = fileName.LastIndexOf ('.');
|
||||
if (i < 0)
|
||||
i = fileName.Length - 1;
|
||||
|
||||
scale = ParseScale (fileName, ref i);
|
||||
size = ParseSize (fileName, ref i);
|
||||
|
||||
return i == resourceId.Length - 1;
|
||||
}
|
||||
|
||||
static int ParseScale (string s, ref int i)
|
||||
{
|
||||
if (i > 1 && s [i] >= '0' && s [i] <= '9' && s [i - 1] == '@') {
|
||||
var scale = s [i] - '0';
|
||||
i = i - 2;
|
||||
return scale;
|
||||
} else
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int ParseSize (string s, ref int i)
|
||||
{
|
||||
int end = i;
|
||||
int n = i;
|
||||
while (n >= 0 && char.IsDigit (s[n]))
|
||||
n--;
|
||||
if (end == n || n < 0 || s [n] != 'x')
|
||||
return -1;
|
||||
|
||||
var x = n;
|
||||
var n2 = end;
|
||||
n--;
|
||||
|
||||
while (n >= 0 && n2 > x && s[n] == s[n2]) {
|
||||
n--;
|
||||
n2--;
|
||||
}
|
||||
if (n2 == x && n >= 0 && s[n] == '_') {
|
||||
i = n - 1;
|
||||
return int.Parse (s.Substring (x + 1, end - x - 1));
|
||||
}
|
||||
else
|
||||
return -1;
|
||||
}*/
|
||||
|
||||
public static Image FromFile (string file)
|
||||
{
|
||||
var toolkit = Toolkit.CurrentEngine;
|
||||
if (toolkit == null)
|
||||
throw new ToolkitNotInitializedException ();
|
||||
return new Image (toolkit.ImageBackendHandler.LoadFromFile (file), toolkit);
|
||||
|
||||
var ext = GetExtension (file);
|
||||
var img = toolkit.ImageBackendHandler.LoadFromFile (file);
|
||||
|
||||
List<Tuple<string,object>> altImages = null;
|
||||
foreach (var s in supportedScales) {
|
||||
var fn = file.Substring (0, file.Length - ext.Length) + "@" + s + ext;
|
||||
if (File.Exists (fn)) {
|
||||
if (altImages == null) {
|
||||
altImages = new List<Tuple<string, object>> ();
|
||||
altImages.Add (new Tuple<string, object> (file, img));
|
||||
}
|
||||
altImages.Add (new Tuple<string, object> (fn, toolkit.ImageBackendHandler.LoadFromFile (fn)));
|
||||
}
|
||||
}
|
||||
|
||||
if (altImages != null) {
|
||||
if (ext == ".9.png")
|
||||
return CreateComposedNinePatch (toolkit, altImages);
|
||||
img = toolkit.ImageBackendHandler.CreateMultiResolutionImage (altImages.Select (i => i.Item2));
|
||||
}
|
||||
|
||||
var res = new Image (img, toolkit);
|
||||
if (ext == ".9.png")
|
||||
res = new NinePatchImage (res.ToBitmap ());
|
||||
return res;
|
||||
}
|
||||
|
||||
static Image CreateComposedNinePatch (Toolkit toolkit, List<Tuple<string,object>> altImages)
|
||||
{
|
||||
var npImage = new NinePatchImage ();
|
||||
foreach (var fi in altImages) {
|
||||
int i = fi.Item1.LastIndexOf ('@');
|
||||
double scaleFactor;
|
||||
if (i == -1)
|
||||
scaleFactor = 1;
|
||||
else {
|
||||
int j = fi.Item1.IndexOf ('.', ++i);
|
||||
if (!double.TryParse (fi.Item1.Substring (i + 1, j - i), out scaleFactor)) {
|
||||
toolkit.ImageBackendHandler.Dispose (fi.Item2);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
npImage.AddFrame (new Image (fi.Item2, toolkit).ToBitmap (), scaleFactor);
|
||||
}
|
||||
return npImage;
|
||||
}
|
||||
|
||||
public static Image FromStream (Stream stream)
|
||||
|
@ -271,6 +271,14 @@ namespace Xwt.Drawing
|
|||
return new Image (toolkit.ImageBackendHandler.LoadFromStream (stream), toolkit);
|
||||
}
|
||||
|
||||
static string GetExtension (string fileName)
|
||||
{
|
||||
if (fileName.EndsWith (".9.png", StringComparison.Ordinal))
|
||||
return ".9.png";
|
||||
else
|
||||
return Path.GetExtension (fileName);
|
||||
}
|
||||
|
||||
public void Save (string file, ImageFileType fileType)
|
||||
{
|
||||
using (var f = File.OpenWrite (file))
|
||||
|
|
|
@ -0,0 +1,242 @@
|
|||
//
|
||||
// NinePatchImage.cs
|
||||
//
|
||||
// Author:
|
||||
// Lluis Sanchez <lluis@xamarin.com>
|
||||
//
|
||||
// Copyright (c) 2013 Xamarin Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Xwt.Drawing
|
||||
{
|
||||
public class NinePatchImage: DrawingImage
|
||||
{
|
||||
List<ImageFrame> frames = new List<ImageFrame> ();
|
||||
|
||||
class ImageFrame {
|
||||
public BitmapImage Bitmap;
|
||||
public double ScaleFactor;
|
||||
public List<ImageSection> HorizontalSections;
|
||||
public List<ImageSection> VerticalSections;
|
||||
public double StretchableWidth;
|
||||
public double StretchableHeight;
|
||||
public BitmapImage[] TileCache;
|
||||
}
|
||||
|
||||
class ImageSection {
|
||||
public int Start;
|
||||
public double Size;
|
||||
public RenderMode Mode;
|
||||
}
|
||||
|
||||
enum RenderMode {
|
||||
Fixed,
|
||||
Stretch,
|
||||
Tile
|
||||
}
|
||||
|
||||
public NinePatchImage ()
|
||||
{
|
||||
}
|
||||
|
||||
public NinePatchImage (BitmapImage bitmap)
|
||||
{
|
||||
AddFrame (bitmap, 1);
|
||||
}
|
||||
|
||||
internal void AddFrame (BitmapImage bitmap, double scaleFactor)
|
||||
{
|
||||
ImageFrame frame = new ImageFrame {
|
||||
Bitmap = bitmap,
|
||||
ScaleFactor = scaleFactor
|
||||
};
|
||||
frames.Add (frame);
|
||||
|
||||
frame.HorizontalSections = CreateSections (frame, Enumerable.Range (1, (int)bitmap.Width - 2).Select (n => bitmap.GetPixel (n, 0)));
|
||||
frame.VerticalSections = CreateSections (frame, Enumerable.Range (1, (int)bitmap.Height - 2).Select (n => bitmap.GetPixel (0, n)));
|
||||
|
||||
double padLeft = 0, padTop = 0, padRight = 0, padBottom = 0;
|
||||
var hbox = CreateSections (frame, Enumerable.Range (1, (int)bitmap.Width - 1).Select (n => bitmap.GetPixel (n, (int)bitmap.Height - 1)));
|
||||
var sec = hbox.FirstOrDefault (s => s.Mode != RenderMode.Fixed);
|
||||
if (sec != null) {
|
||||
padLeft = sec.Start;
|
||||
padRight = bitmap.Width - 2 - padLeft - sec.Size;
|
||||
}
|
||||
|
||||
var vbox = CreateSections (frame, Enumerable.Range (1, (int)bitmap.Height - 1).Select (n => bitmap.GetPixel ((int)bitmap.Width - 1, n)));
|
||||
sec = vbox.FirstOrDefault (s => s.Mode != RenderMode.Fixed);
|
||||
if (sec != null) {
|
||||
padTop = sec.Start;
|
||||
padBottom = bitmap.Height - 2 - padTop - sec.Size;
|
||||
}
|
||||
|
||||
Padding = new WidgetSpacing (padLeft, padTop, padRight, padBottom);
|
||||
|
||||
frame.StretchableWidth = frame.HorizontalSections.Where (s => s.Mode != RenderMode.Fixed).Sum (s => s.Size);
|
||||
frame.StretchableHeight = frame.VerticalSections.Where (s => s.Mode != RenderMode.Fixed).Sum (s => s.Size);
|
||||
}
|
||||
|
||||
List<ImageSection> CreateSections (ImageFrame frame, IEnumerable<Color> pixels)
|
||||
{
|
||||
List<ImageSection> sections = new List<ImageSection> ();
|
||||
|
||||
ImageSection section = null;
|
||||
int n = 0;
|
||||
|
||||
foreach (var p in pixels) {
|
||||
RenderMode mode;
|
||||
if (p == Colors.Red)
|
||||
mode = RenderMode.Tile;
|
||||
else if (p == Colors.Black)
|
||||
mode = RenderMode.Stretch;
|
||||
else
|
||||
mode = RenderMode.Fixed;
|
||||
|
||||
if (section == null || mode != section.Mode) {
|
||||
section = new ImageSection {
|
||||
Start = n,
|
||||
Size = 1,
|
||||
Mode = mode
|
||||
};
|
||||
sections.Add (section);
|
||||
} else
|
||||
section.Size++;
|
||||
n++;
|
||||
}
|
||||
return sections;
|
||||
}
|
||||
|
||||
ImageFrame GetFrame (double scaleFactor)
|
||||
{
|
||||
return frames.FirstOrDefault (i => Math.Abs (i.ScaleFactor - scaleFactor) < 0.1) ?? frames[0];
|
||||
}
|
||||
|
||||
protected sealed override void OnDraw (Context ctx, Rectangle bounds)
|
||||
{
|
||||
var frame = GetFrame (ctx.ScaleFactor);
|
||||
var fixedWidth = frame.Bitmap.Width - frame.StretchableWidth;
|
||||
var fixedHeight = frame.Bitmap.Height - frame.StretchableHeight;
|
||||
double totalVariableWidth = bounds.Width - fixedWidth;
|
||||
double totalVariableHeight = bounds.Height - fixedHeight;
|
||||
double remainingVariableHeight = totalVariableHeight;
|
||||
|
||||
double y = bounds.Y, yb = 1;
|
||||
int tileIndex = 0;
|
||||
|
||||
ctx.Save ();
|
||||
if (totalVariableWidth < 0) {
|
||||
if (fixedWidth > 0)
|
||||
ctx.Scale (bounds.Width / fixedWidth, 1);
|
||||
totalVariableWidth = 0;
|
||||
}
|
||||
if (totalVariableHeight < 0) {
|
||||
if (fixedHeight > 0)
|
||||
ctx.Scale (1, bounds.Height / fixedHeight);
|
||||
totalVariableHeight = 0;
|
||||
}
|
||||
|
||||
foreach (var vs in frame.VerticalSections) {
|
||||
|
||||
double sh = CalcSectionSize (frame, vs, totalVariableHeight, frame.StretchableHeight, ref remainingVariableHeight);
|
||||
|
||||
double x = bounds.X, xb = 1;
|
||||
double remainingVariableWidth = totalVariableWidth;
|
||||
|
||||
foreach (var hs in frame.HorizontalSections) {
|
||||
var sourceRegion = new Rectangle (xb, yb, hs.Size, vs.Size);
|
||||
double sw = CalcSectionSize (frame, hs, totalVariableWidth, frame.StretchableWidth, ref remainingVariableWidth);
|
||||
var targetRegion = new Rectangle (x, y, sw, sh);
|
||||
|
||||
if (vs.Mode != RenderMode.Tile && hs.Mode != RenderMode.Tile) {
|
||||
var t = GetTile (frame, tileIndex, sourceRegion);
|
||||
ctx.DrawImage (t, targetRegion);
|
||||
} else {
|
||||
double scaleX = 1;
|
||||
double scaleY = 1;
|
||||
if (hs.Mode == RenderMode.Stretch) {
|
||||
scaleX = sw / hs.Size;
|
||||
targetRegion.Width = hs.Size;
|
||||
}
|
||||
if (vs.Mode == RenderMode.Stretch) {
|
||||
scaleY = sh / vs.Size;
|
||||
targetRegion.Height = vs.Size;
|
||||
}
|
||||
|
||||
ctx.Save ();
|
||||
ctx.Translate (targetRegion.Location);
|
||||
if (scaleX != 1 || scaleY != 1)
|
||||
ctx.Scale (scaleX, scaleY);
|
||||
targetRegion.Location = Point.Zero;
|
||||
ctx.Pattern = new ImagePattern (GetTile (frame, tileIndex, sourceRegion));
|
||||
ctx.NewPath ();
|
||||
ctx.Rectangle (targetRegion);
|
||||
ctx.Fill ();
|
||||
ctx.Restore ();
|
||||
}
|
||||
x += sw / frame.ScaleFactor;
|
||||
xb += hs.Size;
|
||||
tileIndex++;
|
||||
}
|
||||
yb += vs.Size;
|
||||
y += sh / frame.ScaleFactor;
|
||||
}
|
||||
ctx.Restore ();
|
||||
}
|
||||
|
||||
double CalcSectionSize (ImageFrame frame, ImageSection sec, double totalVariable, double stretchableSize, ref double remainingVariable)
|
||||
{
|
||||
if (sec.Mode != RenderMode.Fixed) {
|
||||
double sw = Math.Round (totalVariable * (sec.Size / stretchableSize));
|
||||
if (sw > remainingVariable)
|
||||
sw = remainingVariable;
|
||||
remainingVariable -= sw;
|
||||
return sw;
|
||||
}
|
||||
else {
|
||||
return sec.Size;
|
||||
}
|
||||
}
|
||||
|
||||
BitmapImage GetTile (ImageFrame frame, int tileIndex, Rectangle sourceRegion)
|
||||
{
|
||||
if (frame.TileCache == null)
|
||||
frame.TileCache = new BitmapImage [frame.HorizontalSections.Count * frame.VerticalSections.Count];
|
||||
|
||||
var img = frame.TileCache [tileIndex];
|
||||
if (img != null)
|
||||
return img;
|
||||
|
||||
img = frame.Bitmap.Crop (sourceRegion);
|
||||
return frame.TileCache [tileIndex] = img;
|
||||
}
|
||||
|
||||
protected sealed override Size GetDefaultSize ()
|
||||
{
|
||||
var frame = frames [0];
|
||||
return new Size (frame.Bitmap.Width - 2, frame.Bitmap.Height - 2);
|
||||
}
|
||||
|
||||
public WidgetSpacing Padding { get; private set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -583,6 +583,13 @@ namespace Xwt.Drawing
|
|||
return ctx.NativePathHandler.IsPointInFill (ctx.NativeBackend, x, y);
|
||||
}
|
||||
|
||||
public override double GetScaleFactor (object backend)
|
||||
{
|
||||
var ctx = (VectorBackend)backend;
|
||||
CreateNativePathBackend (ctx);
|
||||
return ctx.NativeContextHandler.GetScaleFactor (ctx.NativeBackend);
|
||||
}
|
||||
|
||||
public override void Dispose (object backend)
|
||||
{
|
||||
var ctx = (VectorBackend)backend;
|
||||
|
|
|
@ -316,6 +316,7 @@
|
|||
<Compile Include="Xwt.Backends\KeyboardHandler.cs" />
|
||||
<Compile Include="Xwt\FrameBox.cs" />
|
||||
<Compile Include="Xwt\ToolkitNotInitializedException.cs" />
|
||||
<Compile Include="Xwt.Drawing\NinePatchImage.cs" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||
<ItemGroup />
|
||||
|
|
Загрузка…
Ссылка в новой задаче