Release 4.0.0-preview1-00249
[platform/core/csapi/tizenfx.git] / src / ElmSharp / ElmSharp / Image.cs
1 /*
2  * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  * Licensed under the Apache License, Version 2.0 (the License);
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an AS IS BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 using System;
18 using System.IO;
19 using System.Threading;
20 using System.Threading.Tasks;
21
22 namespace ElmSharp
23 {
24     /// <summary>
25     /// The Image is a widget that allows one to load and display an image file on it,
26     /// be it from a disk file or from a memory region.
27     /// Inherits Widget
28     /// </summary>
29     public class Image : Widget
30     {
31         bool _canScaleUp = true;
32         bool _canScaleDown = true;
33         SmartEvent _clicked;
34         Color _color = Color.Default;
35
36         EvasImage _imageObject = null;
37
38         /// <summary>
39         /// Creates and initializes a new instance of Image class.
40         /// </summary>
41         /// <param name="parent">The parent is a given container which will be attached by Image as a child. It's <see cref="EvasObject"/> type.</param>
42         public Image(EvasObject parent) : base(parent)
43         {
44             _clicked = new SmartEvent(this, "clicked");
45             _clicked.On += (s, e) => Clicked?.Invoke(this, EventArgs.Empty);
46         }
47
48         /// <summary>
49         /// Clicked will be triggered when the image is clicked.
50         /// </summary>
51         public event EventHandler Clicked;
52
53         /// <summary>
54         /// LoadingCompleted will be triggered when the image is loaded completely.
55         /// </summary>
56         public event EventHandler LoadingCompleted;
57
58         /// <summary>
59         /// Clicked will be triggered when the image is fail to load.
60         /// </summary>
61         public event EventHandler LoadingFailed;
62
63         /// <summary>
64         /// Gets the file that is used as an image.
65         /// </summary>
66         public string File
67         {
68             get
69             {
70                 return Interop.Elementary.elm_image_file_get(RealHandle);
71             }
72         }
73
74         /// <summary>
75         /// Sets or gets the smooth effect for an image.
76         /// </summary>
77         public bool IsSmooth
78         {
79             get
80             {
81                 return Interop.Elementary.elm_image_smooth_get(RealHandle);
82             }
83             set
84             {
85                 Interop.Elementary.elm_image_smooth_set(RealHandle, value);
86             }
87         }
88
89         /// <summary>
90         /// Sets or gets whether scaling is disabled on the object.
91         /// </summary>
92         public bool IsScaling
93         {
94             get
95             {
96                 return !Interop.Elementary.elm_image_no_scale_get(RealHandle);
97             }
98             set
99             {
100                 Interop.Elementary.elm_image_no_scale_set(RealHandle, !value);
101             }
102         }
103
104         /// <summary>
105         /// Sets or gets whether the object is down resizeable.
106         /// </summary>
107         public bool CanScaleDown
108         {
109             get
110             {
111                 return _canScaleDown;
112             }
113             set
114             {
115                 _canScaleDown = value;
116                 Interop.Elementary.elm_image_resizable_set(RealHandle, _canScaleUp, _canScaleDown);
117             }
118         }
119
120         /// <summary>
121         /// Sets or gets whether the object is up resizeable.
122         /// </summary>
123         public bool CanScaleUp
124         {
125             get
126             {
127                 return _canScaleUp;
128             }
129             set
130             {
131                 _canScaleUp = value;
132                 Interop.Elementary.elm_image_resizable_set(RealHandle, _canScaleUp, _canScaleDown);
133             }
134         }
135
136         /// <summary>
137         /// Sets or gets whether the image fills the entire object area, when keeping the aspect ratio.
138         /// </summary>
139         public bool CanFillOutside
140         {
141             get
142             {
143                 return Interop.Elementary.elm_image_fill_outside_get(RealHandle);
144             }
145             set
146             {
147                 Interop.Elementary.elm_image_fill_outside_set(RealHandle, value);
148             }
149         }
150
151         /// <summary>
152         /// Sets or gets the prescale size for the image.
153         /// </summary>
154         public int PrescaleSize
155         {
156             get
157             {
158                 return Interop.Elementary.elm_image_prescale_get(RealHandle);
159             }
160             set
161             {
162                 Interop.Elementary.elm_image_prescale_set(RealHandle, value);
163             }
164         }
165
166         /// <summary>
167         /// Sets or gets whether the original aspect ratio of the image should be kept on resize.
168         /// </summary>
169         public bool IsFixedAspect
170         {
171             get
172             {
173                 return Interop.Elementary.elm_image_aspect_fixed_get(RealHandle);
174             }
175             set
176             {
177                 Interop.Elementary.elm_image_aspect_fixed_set(RealHandle, value);
178             }
179         }
180
181         /// <summary>
182         /// Sets or gets whether an image object (which supports animation) is to animate itself.
183         /// </summary>
184         public bool IsAnimated
185         {
186             get
187             {
188                 return Interop.Elementary.elm_image_animated_get(RealHandle);
189             }
190             set
191             {
192                 Interop.Elementary.elm_image_animated_set(RealHandle, value);
193             }
194         }
195
196         /// <summary>
197         /// Gets whether an image object supports animation.
198         /// </summary>
199         public bool IsAnimatedAvailable
200         {
201             get
202             {
203                 return Interop.Elementary.elm_image_animated_available_get(RealHandle);
204             }
205         }
206
207         /// <summary>
208         /// Sets or gets whether an image object is under animation.
209         /// </summary>
210         /// <remarks>
211         /// An image object, even if it supports animation, will be displayed by default without animation.
212         /// To actually start playing any image object's animation, <see cref="IsAnimated"/> should be TRUE before setting this property true.
213         /// </remarks>
214         public bool IsAnimationPlaying
215         {
216             get
217             {
218                 return Interop.Elementary.elm_image_animated_play_get(RealHandle);
219             }
220             set
221             {
222                 Interop.Elementary.elm_image_animated_play_set(RealHandle, value);
223             }
224         }
225
226         /// <summary>
227         /// Sets or gets whether the image is 'editable'.
228         /// </summary>
229         public bool IsEditable
230         {
231             get
232             {
233                 return Interop.Elementary.elm_image_editable_get(RealHandle);
234             }
235             set
236             {
237                 Interop.Elementary.elm_image_editable_set(RealHandle, value);
238             }
239         }
240
241         /// <summary>
242         /// Gets the current size of the image.
243         /// </summary>
244         public Size ObjectSize
245         {
246             get
247             {
248                 Interop.Elementary.elm_image_object_size_get(RealHandle, out int w, out int h);
249                 return new Size(w, h);
250             }
251         }
252
253         /// <summary>
254         /// Sets or gets whether alpha channel data is being used on the given image object.
255         /// </summary>
256         public bool IsOpaque
257         {
258             get
259             {
260                 if (ImageObject != null)
261                 {
262                     return ImageObject.IsOpaque;
263                 }
264                 return false;
265             }
266             set
267             {
268                 if (ImageObject != null)
269                 {
270                     ImageObject.IsOpaque = value;
271                 }
272             }
273         }
274
275         /// <summary>
276         /// Sets or gets the image orientation.
277         /// </summary>
278         public ImageOrientation Orientation
279         {
280             get
281             {
282                 return (ImageOrientation)Interop.Elementary.elm_image_orient_get(RealHandle);
283             }
284             set
285             {
286                 Interop.Elementary.elm_image_orient_set(RealHandle, (int)value);
287             }
288         }
289
290         /// <summary>
291         /// Sets or gets the image color
292         /// </summary>
293         public override Color Color
294         {
295             get
296             {
297                 return _color;
298             }
299             set
300             {
301                 if (ImageObject != null)
302                 {
303                     if (value.IsDefault)
304                     {
305                         ImageObject.Color = Color.FromRgba(255, 255, 255, 255);
306                     }
307                     else
308                     {
309                         ImageObject.Color = value;
310                     }
311                 }
312                 _color = value;
313             }
314         }
315
316         /// <summary>
317         /// Sets the background color
318         /// </summary>
319         public override Color BackgroundColor
320         {
321             set
322             {
323                 if (value.IsDefault)
324                 {
325                     SetPartColor("bg", Color.Transparent);
326                 }
327                 else
328                 {
329                     SetPartColor("bg", value);
330                 }
331                 _backgroundColor = value;
332             }
333         }
334
335         /// <summary>
336         /// Gets the inlined image object of the image widget.
337         /// This property allows one to get the underlying EvasObject of type Image from this elementary widget. It can be useful to do things like save the image to a file, etc.
338         /// </summary>
339         /// <remarks>Be careful to not manipulate it, as it is under the control of widget.</remarks>
340         public EvasImage ImageObject
341         {
342             get
343             {
344                 if (_imageObject == null)
345                 {
346                     IntPtr evasObj = Interop.Elementary.elm_image_object_get(RealHandle);
347                     if (evasObj != IntPtr.Zero)
348                         _imageObject = new EvasImage(this, evasObj);
349                 }
350                 return _imageObject;
351             }
352         }
353
354         /// <summary>
355         /// Sets the dimensions for an image object's border, a region which is not scaled together with its center ever.
356         /// </summary>
357         /// <param name="left">The border's left width</param>
358         /// <param name="right">The border's right width</param>
359         /// <param name="top">The border's top width</param>
360         /// <param name="bottom">The border's bottom width</param>
361         public void SetBorder(int left, int right, int top, int bottom)
362         {
363             ImageObject?.SetBorder(left, right, top, bottom);
364         }
365
366         /// <summary>
367         /// Sets or gets if the center part of the given image object (not the border) should be drawn.
368         /// </summary>
369         /// <remarks>
370         /// When rendering, the image may be scaled to fit the size of the image object.
371         /// This function sets if the center part of the scaled image is to be drawn or left completely blank, or forced to be solid.
372         /// Very useful for frames and decorations.
373         /// </remarks>
374         public ImageBorderFillMode BorderCenterFillMode
375         {
376             get
377             {
378                 if (ImageObject != null)
379                 {
380                     return ImageObject.BorderCenterFillMode;
381                 }
382                 else
383                 {
384                     return default(ImageBorderFillMode);
385                 }
386
387             }
388             set
389             {
390                 if (ImageObject != null)
391                 {
392                     ImageObject.BorderCenterFillMode = value;
393                 }
394             }
395         }
396
397         /// <summary>
398         /// Sets the file that is used as the image's source.
399         /// </summary>
400         /// <param name="file">The path to the file that is used as an image source</param>
401         /// <returns>(true = success, false = error)</returns>
402         public bool Load(string file)
403         {
404             if (file == null)
405                 throw new ArgumentNullException("file");
406
407             Interop.Elementary.elm_image_async_open_set(RealHandle, false);
408             Interop.Elementary.elm_image_preload_disabled_set(RealHandle, true);
409             return Interop.Elementary.elm_image_file_set(RealHandle, file, null);
410         }
411
412         /// <summary>
413         /// Sets the uri that is used as the image's source.
414         /// </summary>
415         /// <param name="uri">The uri to the file that is used as an image source</param>
416         /// <returns>(true = success, false = error)</returns>
417         public bool Load(Uri uri)
418         {
419             if (uri == null)
420                 throw new ArgumentNullException("uri");
421
422             return Load(uri.IsFile ? uri.LocalPath : uri.AbsoluteUri);
423         }
424
425         /// <summary>
426         /// Sets a location in the memory to be used as an image object's source bitmap.
427         /// </summary>
428         /// <remarks>
429         /// This function is handy when the contents of an image file are mapped into the memory, for example.
430         /// The format string should be something like "png", "jpg", "tga", "tiff", "bmp" etc, when provided (null, on the contrary).
431         /// This improves the loader performance as it tries the "correct" loader first, before trying a range of other possible loaders until one succeeds.
432         /// </remarks>
433         /// <param name="img">The binary data that is used as an image source</param>
434         /// <param name="size">The size of the binary data blob img</param>
435         /// <returns>(true = success, false = error)</returns>
436         [Obsolete("This method will be removed. Use Load(Stream stream) instead.")]
437         public unsafe bool Load(byte* img, long size)
438         {
439             if (img == null)
440                 throw new ArgumentNullException("img");
441
442             Interop.Elementary.elm_image_async_open_set(RealHandle, false);
443             Interop.Elementary.elm_image_preload_disabled_set(RealHandle, true);
444             return Interop.Elementary.elm_image_memfile_set(RealHandle, img, size, IntPtr.Zero, IntPtr.Zero);
445         }
446
447         /// <summary>
448         /// Sets the stream that is used as the image's source.
449         /// </summary>
450         /// <param name="stream">The stream that is used as an image source</param>
451         /// <returns>(true = success, false = error)</returns>
452         public bool Load(Stream stream)
453         {
454             if (stream == null)
455                 throw new ArgumentNullException("stream");
456
457             Interop.Elementary.elm_image_async_open_set(RealHandle, false);
458             Interop.Elementary.elm_image_preload_disabled_set(RealHandle, true);
459             MemoryStream memstream = new MemoryStream();
460             stream.CopyTo(memstream);
461             unsafe
462             {
463                 byte[] dataArr = memstream.ToArray();
464                 fixed (byte* data = &dataArr[0])
465                 {
466                     return Interop.Elementary.elm_image_memfile_set(RealHandle, data, dataArr.Length, IntPtr.Zero, IntPtr.Zero);
467                 }
468             }
469         }
470
471         /// <summary>
472         /// Sets the file that is used as the image's source with async.
473         /// </summary>
474         /// <param name="file">The path to the file that is used as an image source</param>
475         /// <param name="cancellationToken">cancellation token</param>
476         /// <returns>(true = success, false = error)</returns>
477         public Task<bool> LoadAsync(string file, CancellationToken cancellationToken = default(CancellationToken))
478         {
479             if (file == null)
480                 throw new ArgumentNullException("file");
481
482             Interop.Elementary.elm_image_async_open_set(RealHandle, true);
483             Interop.Elementary.elm_image_preload_disabled_set(RealHandle, false);
484
485             var tcs = new TaskCompletionSource<bool>();
486
487             cancellationToken.Register(() =>
488             {
489                 if (tcs != null && !tcs.Task.IsCompleted)
490                 {
491                     tcs.SetCanceled();
492                 }
493             });
494
495             SmartEvent loadReady = new SmartEvent(this, RealHandle, "load,ready");
496             loadReady.On += (s, e) =>
497             {
498                 loadReady.Dispose();
499                 LoadingCompleted?.Invoke(this, EventArgs.Empty);
500                 if (tcs != null && !tcs.Task.IsCompleted)
501                 {
502                     tcs.SetResult(true);
503                 }
504             };
505
506             SmartEvent loadError = new SmartEvent(this, RealHandle, "load,error");
507             loadError.On += (s, e) =>
508             {
509                 loadError.Dispose();
510                 LoadingFailed?.Invoke(this, EventArgs.Empty);
511                 if (tcs != null && !tcs.Task.IsCompleted)
512                 {
513                     tcs.SetResult(false);
514                 }
515             };
516
517             bool ret = Interop.Elementary.elm_image_file_set(RealHandle, file, null);
518             if (!ret)
519             {
520                 throw new InvalidOperationException("Failed to set file to Image");
521             }
522
523             return tcs.Task;
524         }
525
526         /// <summary>
527         /// Sets the uri that is used as the image's source with async.
528         /// </summary>
529         /// <param name="uri">The uri to the file that is used as an image source</param>
530         /// <param name="cancellationToken">cancellation token</param>
531         /// <returns>(true = success, false = error)</returns>
532         public Task<bool> LoadAsync(Uri uri, CancellationToken cancellationToken = default(CancellationToken))
533         {
534             if (uri == null)
535                 throw new ArgumentNullException("uri");
536
537             return LoadAsync(uri.IsFile ? uri.LocalPath : uri.AbsoluteUri, cancellationToken);
538         }
539
540         /// <summary>
541         /// Sets the stream that is used as the image's source with async.
542         /// </summary>
543         /// <param name="stream">The stream that is used as an image source</param>
544         /// <param name="cancellationToken">cancellation token</param>
545         /// <returns>(true = success, false = error)</returns>
546         public async Task<bool> LoadAsync(Stream stream, CancellationToken cancellationToken = default(CancellationToken))
547         {
548             if (stream == null)
549                 throw new ArgumentNullException("stream");
550
551             Interop.Elementary.elm_image_async_open_set(RealHandle, true);
552             Interop.Elementary.elm_image_preload_disabled_set(RealHandle, false);
553
554             var tcs = new TaskCompletionSource<bool>();
555
556             cancellationToken.Register(() =>
557             {
558                 if (tcs != null && !tcs.Task.IsCompleted)
559                 {
560                     tcs.SetCanceled();
561                 }
562             });
563
564             SmartEvent loadReady = new SmartEvent(this, RealHandle, "load,ready");
565             loadReady.On += (s, e) =>
566             {
567                 loadReady.Dispose();
568                 LoadingCompleted?.Invoke(this, EventArgs.Empty);
569                 if (tcs != null && !tcs.Task.IsCompleted)
570                 {
571                     tcs.SetResult(true);
572                 }
573             };
574
575             SmartEvent loadError = new SmartEvent(this, RealHandle, "load,error");
576             loadError.On += (s, e) =>
577             {
578                 loadError.Dispose();
579                 LoadingFailed?.Invoke(this, EventArgs.Empty);
580                 if (tcs != null && !tcs.Task.IsCompleted)
581                 {
582                     tcs.SetResult(false);
583                 }
584             };
585
586             MemoryStream memstream = new MemoryStream();
587             await stream.CopyToAsync(memstream);
588
589             unsafe
590             {
591                 byte[] dataArr = memstream.ToArray();
592                 fixed (byte* data = &dataArr[0])
593                 {
594                     bool ret = Interop.Elementary.elm_image_memfile_set(RealHandle, data, dataArr.Length, IntPtr.Zero, IntPtr.Zero);
595                     if (!ret)
596                     {
597                         return false;
598                     }
599                 }
600             }
601
602             memstream.Dispose();
603
604             return await tcs.Task;
605         }
606
607         /// <summary>
608         /// Sets the color of color class for a given widget.
609         /// </summary>
610         /// <param name="part">The name of color class.</param>
611         /// <param name="color">The struct of color</param>
612         public override void SetPartColor(string part, Color color)
613         {
614             Interop.Elementary.elm_object_color_class_color_set(Handle, part, color.R * color.A / 255,
615                                                                               color.G * color.A / 255,
616                                                                               color.B * color.A / 255,
617                                                                               color.A);
618         }
619
620         /// <summary>
621         /// Gets the color of color class for a given widget.
622         /// </summary>
623         /// <param name="part">The name of color class.</param>
624         /// <returns>color object</returns>
625         public override Color GetPartColor(string part)
626         {
627             Interop.Elementary.elm_object_color_class_color_get(Handle, part, out int r, out int g, out int b, out int a);
628             return new Color((int)(r / (a / 255.0)), (int)(g / (a / 255.0)), (int)(b / (a / 255.0)), a);
629         }
630
631         /// <summary>
632         /// Sets the content at a part of a given container widget.
633         /// </summary>
634         /// <param name="parent">The parent is a given container which will be attached by Image as a child. It's <see cref="EvasObject"/> type.</param>
635         /// <returns>The new object, otherwise null if it cannot be created</returns>
636         protected override IntPtr CreateHandle(EvasObject parent)
637         {
638             IntPtr handle = Interop.Elementary.elm_layout_add(parent);
639             Interop.Elementary.elm_layout_theme_set(handle, "layout", "background", "default");
640
641             RealHandle = Interop.Elementary.elm_image_add(handle);
642             Interop.Elementary.elm_object_part_content_set(handle, "elm.swallow.content", RealHandle);
643
644             return handle;
645         }
646     }
647
648     /// <summary>
649     /// Enumeration for the fill mode of image border
650     /// </summary>
651     public enum ImageBorderFillMode
652     {
653         /// <summary>
654         /// None mode of image border
655         /// </summary>
656         None,
657
658         /// <summary>
659         /// Default mode of image border
660         /// </summary>
661         Default,
662
663         /// <summary>
664         /// Solid mode of image border
665         /// </summary>
666         Solid,
667     }
668
669     /// <summary>
670     /// Enumeration for the possible orientation options
671     /// </summary>
672     public enum ImageOrientation : int
673     {
674         /// <summary>
675         /// No orientation change
676         /// </summary>
677         None = 0,
678
679         /// <summary>
680         /// Rotate 90 degrees clockwise
681         /// </summary>
682         Rotate90,
683
684         /// <summary>
685         /// Rotate 180 degrees clockwise
686         /// </summary>
687         Rotate180,
688
689         /// <summary>
690         /// Rotate 90 degrees counter-clockwise (i.e. 270 degrees clockwise)
691         /// </summary>
692         Rotate270,
693
694         /// <summary>
695         /// Flip image horizontally
696         /// </summary>
697         FlipHorizontal,
698
699         /// <summary>
700         /// Flip image vertically
701         /// </summary>
702         FlipVertical,
703
704         /// <summary>
705         /// Flip the image along the y = (width - x) line (bottom-left to top-right)
706         /// </summary>
707         FlipTranspose,
708
709         /// <summary>
710         /// Flip the image along the y = x line (top-left to bottom-right)
711         /// </summary>
712         FlipTransverse
713     }
714 }