Add support for 9-patch images

This commit is contained in:
Lluis Sanchez 2013-11-28 20:46:53 +01:00
Родитель 0c3884d56d
Коммит 5b1f32a80e
19 изменённых файлов: 442 добавлений и 63 удалений

Просмотреть файл

@ -86,7 +86,7 @@ namespace Samples
AddSample (listView, "Editable checkboxes", typeof(ListView2)); AddSample (listView, "Editable checkboxes", typeof(ListView2));
AddSample (w, "Markdown", typeof (MarkDownSample)); AddSample (w, "Markdown", typeof (MarkDownSample));
AddSample (w, "Menu", typeof(MenuSamples)); AddSample (w, "Menu", typeof(MenuSamples));
var mn = AddSample (w, "Mnemonics", typeof (Mnemonics)); AddSample (w, "Mnemonics", typeof (Mnemonics));
AddSample (w, "Notebook", typeof(NotebookSample)); AddSample (w, "Notebook", typeof(NotebookSample));
AddSample (w, "Paneds", typeof(PanedViews)); AddSample (w, "Paneds", typeof(PanedViews));
AddSample (w, "Popover", typeof(PopoverSample)); AddSample (w, "Popover", typeof(PopoverSample));
@ -111,6 +111,7 @@ namespace Samples
AddSample (n, "Text", typeof(DrawingText)); AddSample (n, "Text", typeof(DrawingText));
AddSample (n, "Partial Images", typeof (PartialImages)); AddSample (n, "Partial Images", typeof (PartialImages));
AddSample (n, "Custom Drawn Image", typeof (ImageScaling)); AddSample (n, "Custom Drawn Image", typeof (ImageScaling));
AddSample (n, "9-patch Image", typeof (Image9Patch));
AddSample (n, "Widget Rendering", typeof (WidgetRendering)); AddSample (n, "Widget Rendering", typeof (WidgetRendering));
var wf = AddSample (null, "Widget Features", null); var wf = AddSample (null, "Widget Features", null);

Просмотреть файл

@ -101,6 +101,7 @@
<Compile Include="Samples\ListView2.cs" /> <Compile Include="Samples\ListView2.cs" />
<Compile Include="Samples\OpacitySample.cs" /> <Compile Include="Samples\OpacitySample.cs" />
<Compile Include="Samples\PasswordEntries.cs" /> <Compile Include="Samples\PasswordEntries.cs" />
<Compile Include="Samples\Image9Patch.cs" />
</ItemGroup> </ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ItemGroup> <ItemGroup>
@ -126,6 +127,28 @@
<EmbeddedResource Include="document-generic%402x.png"> <EmbeddedResource Include="document-generic%402x.png">
<LogicalName>document-generic@2x.png</LogicalName> <LogicalName>document-generic@2x.png</LogicalName>
</EmbeddedResource> </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> </ItemGroup>
<ProjectExtensions> <ProjectExtensions>
<MonoDevelop> <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));
}
}
}

Двоичные данные
Samples/zoom-panel-dark.9.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 2.0 KiB

Двоичные данные
Samples/zoom-panel-dark@2x.9.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 4.0 KiB

Двоичные данные
Testing/Tests/ninep-ss.9.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 1.7 KiB

Двоичные данные
Testing/Tests/ninep-st.9.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 1.7 KiB

Двоичные данные
Testing/Tests/ninep-ts.9.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 1.7 KiB

Двоичные данные
Testing/Tests/ninep-tt.9.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 1.7 KiB

Просмотреть файл

@ -91,6 +91,12 @@ namespace Xwt.CairoBackend
#region IContextBackendHandler implementation #region IContextBackendHandler implementation
public override double GetScaleFactor (object backend)
{
CairoContextBackend gc = (CairoContextBackend)backend;
return gc.ScaleFactor;
}
public override void Save (object backend) public override void Save (object backend)
{ {
CairoContextBackend gc = (CairoContextBackend)backend; CairoContextBackend gc = (CairoContextBackend)backend;
@ -312,9 +318,9 @@ namespace Xwt.CairoBackend
ctx.Context.NewPath(); ctx.Context.NewPath();
ctx.Context.Rectangle (destRect.X, destRect.Y, destRect.Width, destRect.Height); ctx.Context.Rectangle (destRect.X, destRect.Y, destRect.Width, destRect.Height);
ctx.Context.Clip (); ctx.Context.Clip ();
ctx.Context.Translate (destRect.X-srcRect.X, destRect.Y-srcRect.Y);
double sx = destRect.Width / srcRect.Width; double sx = destRect.Width / srcRect.Width;
double sy = destRect.Height / srcRect.Height; double sy = destRect.Height / srcRect.Height;
ctx.Context.Translate (destRect.X-srcRect.X*sx, destRect.Y-srcRect.Y*sy);
ctx.Context.Scale (sx, sy); ctx.Context.Scale (sx, sy);
img.Alpha *= ctx.GlobalAlpha; img.Alpha *= ctx.GlobalAlpha;

Просмотреть файл

@ -54,6 +54,11 @@ namespace Xwt.Mac
{ {
const double degrees = System.Math.PI / 180d; const double degrees = System.Math.PI / 180d;
public override double GetScaleFactor (object backend)
{
return 1;
}
public override void Save (object backend) public override void Save (object backend)
{ {
var ct = (CGContextBackend) 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) 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) static NSImage FromResource (string res)

Просмотреть файл

@ -81,6 +81,8 @@ namespace Xwt.Backends
/// It doesn't affect colors that have already been set. /// It doesn't affect colors that have already been set.
/// </summary> /// </summary>
public abstract void SetGlobalAlpha (object backend, double globalAlpha); 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)); 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 { public Size PixelSize {
get { return pixelSize; } get { return pixelSize; }
} }

Просмотреть файл

@ -358,6 +358,10 @@ namespace Xwt.Drawing
{ {
handler.SetLineDash (Backend, offset, pattern); handler.SetLineDash (Backend, offset, pattern);
} }
internal double ScaleFactor {
get { return handler.GetScaleFactor (Backend); }
}
} }
} }

Просмотреть файл

@ -40,6 +40,8 @@ namespace Xwt.Drawing
internal NativeImageRef NativeRef; internal NativeImageRef NativeRef;
internal double requestedAlpha = 1; internal double requestedAlpha = 1;
static int[] supportedScales = { 2 };
internal Image () internal Image ()
{ {
} }
@ -173,7 +175,9 @@ namespace Xwt.Drawing
var reqSize = toolkit.ImageBackendHandler.GetSize (img); 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 ()) { foreach (var r in assembly.GetManifestResourceNames ()) {
int i = r.LastIndexOf ('@'); int i = r.LastIndexOf ('@');
if (i != -1) { if (i != -1) {
@ -181,17 +185,22 @@ namespace Xwt.Drawing
if (rname == resource || rname == name) { if (rname == resource || rname == name) {
var rim = toolkit.ImageBackendHandler.LoadFromResource (assembly, r); var rim = toolkit.ImageBackendHandler.LoadFromResource (assembly, r);
if (rim != null) if (rim != null)
altImages.Add (rim); altImages.Add (new Tuple<string, object> (r, rim));
} }
} }
} }
if (altImages.Count > 0) { if (altImages.Count > 0) {
altImages.Insert (0, img); altImages.Insert (0, new Tuple<string, object> (resource, img));
img = toolkit.ImageBackendHandler.CreateMultiResolutionImage (altImages); 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 requestedSize = reqSize
}; };
if (ext == ".9.png")
res = new NinePatchImage (res.ToBitmap ());
return res;
} }
public static Image CreateMultiSizeIcon (IEnumerable<Image> images) 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 ()))); 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) public static Image FromFile (string file)
{ {
var toolkit = Toolkit.CurrentEngine; var toolkit = Toolkit.CurrentEngine;
if (toolkit == null) if (toolkit == null)
throw new ToolkitNotInitializedException (); 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) public static Image FromStream (Stream stream)
@ -271,6 +271,14 @@ namespace Xwt.Drawing
return new Image (toolkit.ImageBackendHandler.LoadFromStream (stream), toolkit); 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) public void Save (string file, ImageFileType fileType)
{ {
using (var f = File.OpenWrite (file)) 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); 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) public override void Dispose (object backend)
{ {
var ctx = (VectorBackend)backend; var ctx = (VectorBackend)backend;

Просмотреть файл

@ -316,6 +316,7 @@
<Compile Include="Xwt.Backends\KeyboardHandler.cs" /> <Compile Include="Xwt.Backends\KeyboardHandler.cs" />
<Compile Include="Xwt\FrameBox.cs" /> <Compile Include="Xwt\FrameBox.cs" />
<Compile Include="Xwt\ToolkitNotInitializedException.cs" /> <Compile Include="Xwt\ToolkitNotInitializedException.cs" />
<Compile Include="Xwt.Drawing\NinePatchImage.cs" />
</ItemGroup> </ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ItemGroup /> <ItemGroup />