/* * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved * * Licensed under the Apache License, Version 2.0 (the License); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an AS IS BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using System; using System.IO; using System.Threading; using System.Threading.Tasks; namespace ElmSharp { /// /// The Image is a widget that allows one to load and display an image file on it, /// be it from a disk file or from a memory region. /// Inherits Widget /// public class Image : Widget { bool _canScaleUp = true; bool _canScaleDown = true; SmartEvent _clicked; Color _color = Color.Default; /// /// Creates and initializes a new instance of Image class. /// /// The parent is a given container which will be attached by Image as a child. It's type. public Image(EvasObject parent) : base(parent) { _clicked = new SmartEvent(this, "clicked"); _clicked.On += (s, e) => Clicked?.Invoke(this, EventArgs.Empty); } /// /// Clicked will be triggered when the image is clicked. /// public event EventHandler Clicked; /// /// LoadingCompleted will be triggered when the image is loaded completely. /// public event EventHandler LoadingCompleted; /// /// Clicked will be triggered when the image is fail to load. /// public event EventHandler LoadingFailed; /// /// Gets the file that is used as an image. /// public string File { get { return Interop.Elementary.elm_image_file_get(RealHandle); } } /// /// Sets or gets the smooth effect for an image. /// public bool IsSmooth { get { return Interop.Elementary.elm_image_smooth_get(RealHandle); } set { Interop.Elementary.elm_image_smooth_set(RealHandle, value); } } /// /// Sets or gets whether scaling is disabled on the object. /// public bool IsScaling { get { return !Interop.Elementary.elm_image_no_scale_get(RealHandle); } set { Interop.Elementary.elm_image_no_scale_set(RealHandle, !value); } } /// /// Sets or gets whether the object is down resizeable. /// public bool CanScaleDown { get { return _canScaleDown; } set { _canScaleDown = value; Interop.Elementary.elm_image_resizable_set(RealHandle, _canScaleUp, _canScaleDown); } } /// /// Sets or gets whether the object is up resizeable. /// public bool CanScaleUp { get { return _canScaleUp; } set { _canScaleUp = value; Interop.Elementary.elm_image_resizable_set(RealHandle, _canScaleUp, _canScaleDown); } } /// /// Sets or gets whether the image fills the entire object area, when keeping the aspect ratio. /// public bool CanFillOutside { get { return Interop.Elementary.elm_image_fill_outside_get(RealHandle); } set { Interop.Elementary.elm_image_fill_outside_set(RealHandle, value); } } /// /// Sets or gets the prescale size for the image. /// public int PrescaleSize { get { return Interop.Elementary.elm_image_prescale_get(RealHandle); } set { Interop.Elementary.elm_image_prescale_set(RealHandle, value); } } /// /// Sets or gets whether the original aspect ratio of the image should be kept on resize. /// public bool IsFixedAspect { get { return Interop.Elementary.elm_image_aspect_fixed_get(RealHandle); } set { Interop.Elementary.elm_image_aspect_fixed_set(RealHandle, value); } } /// /// Sets or gets whether an image object (which supports animation) is to animate itself. /// public bool IsAnimated { get { return Interop.Elementary.elm_image_animated_get(RealHandle); } set { Interop.Elementary.elm_image_animated_set(RealHandle, value); } } /// /// Gets whether an image object supports animation. /// public bool IsAnimatedAvailable { get { return Interop.Elementary.elm_image_animated_available_get(RealHandle); } } /// /// Sets or gets whether an image object is under animation. /// public bool IsAnimationPlaying { get { return Interop.Elementary.elm_image_animated_play_get(RealHandle); } set { Interop.Elementary.elm_image_animated_play_set(RealHandle, value); } } /// /// Sets or gets whether the image is 'editable'. /// public bool IsEditable { get { return Interop.Elementary.elm_image_editable_get(RealHandle); } set { Interop.Elementary.elm_image_editable_set(RealHandle, value); } } /// /// Gets the current size of the image. /// public Size ObjectSize { get { Interop.Elementary.elm_image_object_size_get(RealHandle, out int w, out int h); return new Size(w, h); } } /// /// Sets or gets whether alpha channel data is being used on the given image object. /// public bool IsOpaque { get { IntPtr evasObj = Interop.Elementary.elm_image_object_get(RealHandle); if (evasObj != IntPtr.Zero) { return !Interop.Evas.evas_object_image_alpha_get(evasObj); } return false; } set { IntPtr evasObj = Interop.Elementary.elm_image_object_get(RealHandle); if (evasObj != IntPtr.Zero) { Interop.Evas.evas_object_image_alpha_set(evasObj, !value); } } } /// /// Sets or gets the image orientation. /// public ImageOrientation Orientation { get { return (ImageOrientation)Interop.Elementary.elm_image_orient_get(RealHandle); } set { Interop.Elementary.elm_image_orient_set(RealHandle, (int)value); } } /// /// Sets or gets the image color /// public override Color Color { get { return _color; } set { IntPtr evasObj = Interop.Elementary.elm_image_object_get(RealHandle); if (evasObj != IntPtr.Zero) { if (value.IsDefault) { // Currently, we assume the Image.Color property as a blending color (actually, multiply blending). // Thus we are using Color.White (255,255,255,255) as a default color to ensure original image color. (255/255 * original = original) Interop.Evas.evas_object_color_set(evasObj, 255, 255, 255, 255); } else { Interop.Evas.SetPremultipliedColor(evasObj, value.R, value.G, value.B, value.A); } } _color = value; } } /// /// Sets the background color /// public override Color BackgroundColor { set { if (value.IsDefault) { SetPartColor("bg", Color.Transparent); } else { SetPartColor("bg", value); } _backgroundColor = value; } } /// /// Sets the dimensions for an image object's border, a region which is not scaled together with its center ever. /// /// The border's left width /// The border's right width /// The border's top width /// The border's bottom width public void SetBorder(int left, int right, int top, int bottom) { IntPtr evasObj = Interop.Elementary.elm_image_object_get(RealHandle); Interop.Evas.evas_object_image_border_set(evasObj, left, right, top, bottom); } /// /// Sets or gets if the center part of the given image object (not the border) should be drawn. /// /// /// When rendering, the image may be scaled to fit the size of the image object. /// This function sets if the center part of the scaled image is to be drawn or left completely blank, or forced to be solid. /// Very useful for frames and decorations. /// public ImageBorderFillMode BorderCenterFillMode { get { IntPtr evasObj = Interop.Elementary.elm_image_object_get(RealHandle); return (ImageBorderFillMode)Interop.Evas.evas_object_image_border_center_fill_get(evasObj); } set { IntPtr evasObj = Interop.Elementary.elm_image_object_get(RealHandle); Interop.Evas.evas_object_image_border_center_fill_set(evasObj, (int)value); } } /// /// Sets the file that is used as the image's source. /// /// The path to the file that is used as an image source /// (true = success, false = error) public bool Load(string file) { if (file == null) throw new ArgumentNullException("file"); Interop.Elementary.elm_image_async_open_set(RealHandle, false); Interop.Elementary.elm_image_preload_disabled_set(RealHandle, true); return Interop.Elementary.elm_image_file_set(RealHandle, file, null); } /// /// Sets the uri that is used as the image's source. /// /// The uri to the file that is used as an image source /// (true = success, false = error) public bool Load(Uri uri) { if (uri == null) throw new ArgumentNullException("uri"); return Load(uri.IsFile ? uri.LocalPath : uri.AbsoluteUri); } /// /// Sets a location in the memory to be used as an image object's source bitmap. /// /// /// This function is handy when the contents of an image file are mapped into the memory, for example. /// The format string should be something like "png", "jpg", "tga", "tiff", "bmp" etc, when provided (null, on the contrary). /// This improves the loader performance as it tries the "correct" loader first, before trying a range of other possible loaders until one succeeds. /// /// The binary data that is used as an image source /// The size of the binary data blob img /// (true = success, false = error) [Obsolete("This method will be removed. Use Load(Stream stream) instead.")] public unsafe bool Load(byte* img, long size) { if (img == null) throw new ArgumentNullException("img"); Interop.Elementary.elm_image_async_open_set(RealHandle, false); Interop.Elementary.elm_image_preload_disabled_set(RealHandle, true); return Interop.Elementary.elm_image_memfile_set(RealHandle, img, size, IntPtr.Zero, IntPtr.Zero); } /// /// Sets the stream that is used as the image's source. /// /// The stream that is used as an image source /// (true = success, false = error) public bool Load(Stream stream) { if (stream == null) throw new ArgumentNullException("stream"); Interop.Elementary.elm_image_async_open_set(RealHandle, false); Interop.Elementary.elm_image_preload_disabled_set(RealHandle, true); MemoryStream memstream = new MemoryStream(); stream.CopyTo(memstream); unsafe { byte[] dataArr = memstream.ToArray(); fixed (byte* data = &dataArr[0]) { return Interop.Elementary.elm_image_memfile_set(RealHandle, data, dataArr.Length, IntPtr.Zero, IntPtr.Zero); } } } /// /// Sets the file that is used as the image's source with async. /// /// The path to the file that is used as an image source /// cancellation token /// (true = success, false = error) public Task LoadAsync(string file, CancellationToken cancellationToken = default(CancellationToken)) { if (file == null) throw new ArgumentNullException("file"); Interop.Elementary.elm_image_async_open_set(RealHandle, true); Interop.Elementary.elm_image_preload_disabled_set(RealHandle, false); var tcs = new TaskCompletionSource(); cancellationToken.Register(() => { if (tcs != null && !tcs.Task.IsCompleted) { tcs.SetCanceled(); } }); SmartEvent loadReady = new SmartEvent(this, RealHandle, "load,ready"); loadReady.On += (s, e) => { loadReady.Dispose(); LoadingCompleted?.Invoke(this, EventArgs.Empty); if (tcs != null && !tcs.Task.IsCompleted) { tcs.SetResult(true); } }; SmartEvent loadError = new SmartEvent(this, RealHandle, "load,error"); loadError.On += (s, e) => { loadError.Dispose(); LoadingFailed?.Invoke(this, EventArgs.Empty); if (tcs != null && !tcs.Task.IsCompleted) { tcs.SetResult(false); } }; bool ret = Interop.Elementary.elm_image_file_set(RealHandle, file, null); if (!ret) { throw new InvalidOperationException("Failed to set file to Image"); } return tcs.Task; } /// /// Sets the uri that is used as the image's source with async. /// /// The uri to the file that is used as an image source /// cancellation token /// (true = success, false = error) public Task LoadAsync(Uri uri, CancellationToken cancellationToken = default(CancellationToken)) { if (uri == null) throw new ArgumentNullException("uri"); return LoadAsync(uri.IsFile ? uri.LocalPath : uri.AbsoluteUri, cancellationToken); } /// /// Sets the stream that is used as the image's source with async. /// /// The stream that is used as an image source /// cancellation token /// (true = success, false = error) public async Task LoadAsync(Stream stream, CancellationToken cancellationToken = default(CancellationToken)) { if (stream == null) throw new ArgumentNullException("stream"); Interop.Elementary.elm_image_async_open_set(RealHandle, true); Interop.Elementary.elm_image_preload_disabled_set(RealHandle, false); var tcs = new TaskCompletionSource(); cancellationToken.Register(() => { if (tcs != null && !tcs.Task.IsCompleted) { tcs.SetCanceled(); } }); SmartEvent loadReady = new SmartEvent(this, Handle, "load,ready"); loadReady.On += (s, e) => { loadReady.Dispose(); LoadingCompleted?.Invoke(this, EventArgs.Empty); if (tcs != null && !tcs.Task.IsCompleted) { tcs.SetResult(true); } }; SmartEvent loadError = new SmartEvent(this, Handle, "load,error"); loadError.On += (s, e) => { loadError.Dispose(); LoadingFailed?.Invoke(this, EventArgs.Empty); if (tcs != null && !tcs.Task.IsCompleted) { tcs.SetResult(false); } }; MemoryStream memstream = new MemoryStream(); await stream.CopyToAsync(memstream); unsafe { byte[] dataArr = memstream.ToArray(); fixed (byte* data = &dataArr[0]) { bool ret = Interop.Elementary.elm_image_memfile_set(RealHandle, data, dataArr.Length, IntPtr.Zero, IntPtr.Zero); if (!ret) { return false; } } } return await tcs.Task; } /// /// Sets the color of color class for a given widget. /// /// The name of color class. /// The struct of color public override void SetPartColor(string part, Color color) { Interop.Elementary.elm_object_color_class_color_set(Handle, part, color.R * color.A / 255, color.G * color.A / 255, color.B * color.A / 255, color.A); } /// /// Gets the color of color class for a given widget. /// /// The name of color class. /// color object public override Color GetPartColor(string part) { Interop.Elementary.elm_object_color_class_color_get(Handle, part, out int r, out int g, out int b, out int a); return new Color((int)(r / (a / 255.0)), (int)(g / (a / 255.0)), (int)(b / (a / 255.0)), a); } /// /// Sets the content at a part of a given container widget. /// /// The parent is a given container which will be attached by Image as a child. It's type. /// The new object, otherwise null if it cannot be created protected override IntPtr CreateHandle(EvasObject parent) { IntPtr handle = Interop.Elementary.elm_layout_add(parent); Interop.Elementary.elm_layout_theme_set(handle, "layout", "background", "default"); RealHandle = Interop.Elementary.elm_image_add(handle); Interop.Elementary.elm_object_part_content_set(handle, "elm.swallow.content", RealHandle); return handle; } } public enum ImageBorderFillMode { None, Default, Solid, } /// /// Enumeration for the possible orientation options /// public enum ImageOrientation : int { /// /// No orientation change /// None = 0, /// /// Rotate 90 degrees clockwise /// Rotate90, /// /// Rotate 180 degrees clockwise /// Rotate180, /// /// Rotate 90 degrees counter-clockwise (i.e. 270 degrees clockwise) /// Rotate270, /// /// Flip image horizontally /// FlipHorizontal, /// /// Flip image vertically /// FlipVertical, /// /// Flip the image along the y = (width - x) line (bottom-left to top-right) /// FlipTranspose, /// /// Flip the image along the y = x line (top-left to bottom-right) /// FlipTransverse } }