Release 4.0.0-preview1-00258
[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                     {
349                         _imageObject = new EvasImage(this, evasObj);
350                         _imageObject.Deleted += (s, e) => _imageObject = null;
351                     }
352                 }
353                 return _imageObject;
354             }
355         }
356
357         /// <summary>
358         /// Sets the dimensions for an image object's border, a region which is not scaled together with its center ever.
359         /// </summary>
360         /// <param name="left">The border's left width</param>
361         /// <param name="right">The border's right width</param>
362         /// <param name="top">The border's top width</param>
363         /// <param name="bottom">The border's bottom width</param>
364         public void SetBorder(int left, int right, int top, int bottom)
365         {
366             ImageObject?.SetBorder(left, right, top, bottom);
367         }
368
369         /// <summary>
370         /// Sets or gets if the center part of the given image object (not the border) should be drawn.
371         /// </summary>
372         /// <remarks>
373         /// When rendering, the image may be scaled to fit the size of the image object.
374         /// This function sets if the center part of the scaled image is to be drawn or left completely blank, or forced to be solid.
375         /// Very useful for frames and decorations.
376         /// </remarks>
377         public ImageBorderFillMode BorderCenterFillMode
378         {
379             get
380             {
381                 if (ImageObject != null)
382                 {
383                     return ImageObject.BorderCenterFillMode;
384                 }
385                 else
386                 {
387                     return default(ImageBorderFillMode);
388                 }
389
390             }
391             set
392             {
393                 if (ImageObject != null)
394                 {
395                     ImageObject.BorderCenterFillMode = value;
396                 }
397             }
398         }
399
400         /// <summary>
401         /// Sets the file that is used as the image's source.
402         /// </summary>
403         /// <param name="file">The path to the file that is used as an image source</param>
404         /// <returns>(true = success, false = error)</returns>
405         public bool Load(string file)
406         {
407             if (file == null)
408                 throw new ArgumentNullException("file");
409
410             Interop.Elementary.elm_image_async_open_set(RealHandle, false);
411             Interop.Elementary.elm_image_preload_disabled_set(RealHandle, true);
412             return Interop.Elementary.elm_image_file_set(RealHandle, file, null);
413         }
414
415         /// <summary>
416         /// Sets the uri that is used as the image's source.
417         /// </summary>
418         /// <param name="uri">The uri to the file that is used as an image source</param>
419         /// <returns>(true = success, false = error)</returns>
420         public bool Load(Uri uri)
421         {
422             if (uri == null)
423                 throw new ArgumentNullException("uri");
424
425             return Load(uri.IsFile ? uri.LocalPath : uri.AbsoluteUri);
426         }
427
428         /// <summary>
429         /// Sets a location in the memory to be used as an image object's source bitmap.
430         /// </summary>
431         /// <remarks>
432         /// This function is handy when the contents of an image file are mapped into the memory, for example.
433         /// The format string should be something like "png", "jpg", "tga", "tiff", "bmp" etc, when provided (null, on the contrary).
434         /// This improves the loader performance as it tries the "correct" loader first, before trying a range of other possible loaders until one succeeds.
435         /// </remarks>
436         /// <param name="img">The binary data that is used as an image source</param>
437         /// <param name="size">The size of the binary data blob img</param>
438         /// <returns>(true = success, false = error)</returns>
439         [Obsolete("This method will be removed. Use Load(Stream stream) instead.")]
440         public unsafe bool Load(byte* img, long size)
441         {
442             if (img == null)
443                 throw new ArgumentNullException("img");
444
445             Interop.Elementary.elm_image_async_open_set(RealHandle, false);
446             Interop.Elementary.elm_image_preload_disabled_set(RealHandle, true);
447             return Interop.Elementary.elm_image_memfile_set(RealHandle, img, size, IntPtr.Zero, IntPtr.Zero);
448         }
449
450         /// <summary>
451         /// Sets the stream that is used as the image's source.
452         /// </summary>
453         /// <param name="stream">The stream that is used as an image source</param>
454         /// <returns>(true = success, false = error)</returns>
455         public bool Load(Stream stream)
456         {
457             if (stream == null)
458                 throw new ArgumentNullException("stream");
459
460             Interop.Elementary.elm_image_async_open_set(RealHandle, false);
461             Interop.Elementary.elm_image_preload_disabled_set(RealHandle, true);
462             MemoryStream memstream = new MemoryStream();
463             stream.CopyTo(memstream);
464             unsafe
465             {
466                 byte[] dataArr = memstream.ToArray();
467                 fixed (byte* data = &dataArr[0])
468                 {
469                     return Interop.Elementary.elm_image_memfile_set(RealHandle, data, dataArr.Length, IntPtr.Zero, IntPtr.Zero);
470                 }
471             }
472         }
473
474         /// <summary>
475         /// Sets the file that is used as the image's source with async.
476         /// </summary>
477         /// <param name="file">The path to the file that is used as an image source</param>
478         /// <param name="cancellationToken">cancellation token</param>
479         /// <returns>(true = success, false = error)</returns>
480         public Task<bool> LoadAsync(string file, CancellationToken cancellationToken = default(CancellationToken))
481         {
482             if (file == null)
483                 throw new ArgumentNullException("file");
484
485             Interop.Elementary.elm_image_async_open_set(RealHandle, true);
486             Interop.Elementary.elm_image_preload_disabled_set(RealHandle, false);
487
488             var tcs = new TaskCompletionSource<bool>();
489
490             cancellationToken.Register(() =>
491             {
492                 if (tcs != null && !tcs.Task.IsCompleted)
493                 {
494                     tcs.SetCanceled();
495                 }
496             });
497
498             SmartEvent loadReady = new SmartEvent(this, RealHandle, "load,ready");
499             loadReady.On += (s, e) =>
500             {
501                 loadReady.Dispose();
502                 LoadingCompleted?.Invoke(this, EventArgs.Empty);
503                 if (tcs != null && !tcs.Task.IsCompleted)
504                 {
505                     tcs.SetResult(true);
506                 }
507             };
508
509             SmartEvent loadError = new SmartEvent(this, RealHandle, "load,error");
510             loadError.On += (s, e) =>
511             {
512                 loadError.Dispose();
513                 LoadingFailed?.Invoke(this, EventArgs.Empty);
514                 if (tcs != null && !tcs.Task.IsCompleted)
515                 {
516                     tcs.SetResult(false);
517                 }
518             };
519
520             bool ret = Interop.Elementary.elm_image_file_set(RealHandle, file, null);
521             if (!ret)
522             {
523                 throw new InvalidOperationException("Failed to set file to Image");
524             }
525
526             return tcs.Task;
527         }
528
529         /// <summary>
530         /// Sets the uri that is used as the image's source with async.
531         /// </summary>
532         /// <param name="uri">The uri to the file that is used as an image source</param>
533         /// <param name="cancellationToken">cancellation token</param>
534         /// <returns>(true = success, false = error)</returns>
535         public Task<bool> LoadAsync(Uri uri, CancellationToken cancellationToken = default(CancellationToken))
536         {
537             if (uri == null)
538                 throw new ArgumentNullException("uri");
539
540             return LoadAsync(uri.IsFile ? uri.LocalPath : uri.AbsoluteUri, cancellationToken);
541         }
542
543         /// <summary>
544         /// Sets the stream that is used as the image's source with async.
545         /// </summary>
546         /// <param name="stream">The stream that is used as an image source</param>
547         /// <param name="cancellationToken">cancellation token</param>
548         /// <returns>(true = success, false = error)</returns>
549         public async Task<bool> LoadAsync(Stream stream, CancellationToken cancellationToken = default(CancellationToken))
550         {
551             if (stream == null)
552                 throw new ArgumentNullException("stream");
553
554             Interop.Elementary.elm_image_async_open_set(RealHandle, true);
555             Interop.Elementary.elm_image_preload_disabled_set(RealHandle, false);
556
557             var tcs = new TaskCompletionSource<bool>();
558
559             cancellationToken.Register(() =>
560             {
561                 if (tcs != null && !tcs.Task.IsCompleted)
562                 {
563                     tcs.SetCanceled();
564                 }
565             });
566
567             SmartEvent loadReady = new SmartEvent(this, RealHandle, "load,ready");
568             loadReady.On += (s, e) =>
569             {
570                 loadReady.Dispose();
571                 LoadingCompleted?.Invoke(this, EventArgs.Empty);
572                 if (tcs != null && !tcs.Task.IsCompleted)
573                 {
574                     tcs.SetResult(true);
575                 }
576             };
577
578             SmartEvent loadError = new SmartEvent(this, RealHandle, "load,error");
579             loadError.On += (s, e) =>
580             {
581                 loadError.Dispose();
582                 LoadingFailed?.Invoke(this, EventArgs.Empty);
583                 if (tcs != null && !tcs.Task.IsCompleted)
584                 {
585                     tcs.SetResult(false);
586                 }
587             };
588
589             MemoryStream memstream = new MemoryStream();
590             await stream.CopyToAsync(memstream);
591
592             unsafe
593             {
594                 byte[] dataArr = memstream.ToArray();
595                 fixed (byte* data = &dataArr[0])
596                 {
597                     bool ret = Interop.Elementary.elm_image_memfile_set(RealHandle, data, dataArr.Length, IntPtr.Zero, IntPtr.Zero);
598                     if (!ret)
599                     {
600                         return false;
601                     }
602                 }
603             }
604
605             memstream.Dispose();
606
607             return await tcs.Task;
608         }
609
610         /// <summary>
611         /// Sets the color of color class for a given widget.
612         /// </summary>
613         /// <param name="part">The name of color class.</param>
614         /// <param name="color">The struct of color</param>
615         public override void SetPartColor(string part, Color color)
616         {
617             Interop.Elementary.elm_object_color_class_color_set(Handle, part, color.R * color.A / 255,
618                                                                               color.G * color.A / 255,
619                                                                               color.B * color.A / 255,
620                                                                               color.A);
621         }
622
623         /// <summary>
624         /// Gets the color of color class for a given widget.
625         /// </summary>
626         /// <param name="part">The name of color class.</param>
627         /// <returns>color object</returns>
628         public override Color GetPartColor(string part)
629         {
630             Interop.Elementary.elm_object_color_class_color_get(Handle, part, out int r, out int g, out int b, out int a);
631             return new Color((int)(r / (a / 255.0)), (int)(g / (a / 255.0)), (int)(b / (a / 255.0)), a);
632         }
633
634         /// <summary>
635         /// Sets the content at a part of a given container widget.
636         /// </summary>
637         /// <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>
638         /// <returns>The new object, otherwise null if it cannot be created</returns>
639         protected override IntPtr CreateHandle(EvasObject parent)
640         {
641             IntPtr handle = Interop.Elementary.elm_layout_add(parent);
642             Interop.Elementary.elm_layout_theme_set(handle, "layout", "background", "default");
643
644             RealHandle = Interop.Elementary.elm_image_add(handle);
645             Interop.Elementary.elm_object_part_content_set(handle, "elm.swallow.content", RealHandle);
646
647             return handle;
648         }
649     }
650
651     /// <summary>
652     /// Enumeration for the fill mode of image border
653     /// </summary>
654     public enum ImageBorderFillMode
655     {
656         /// <summary>
657         /// None mode of image border
658         /// </summary>
659         None,
660
661         /// <summary>
662         /// Default mode of image border
663         /// </summary>
664         Default,
665
666         /// <summary>
667         /// Solid mode of image border
668         /// </summary>
669         Solid,
670     }
671
672     /// <summary>
673     /// Enumeration for the possible orientation options
674     /// </summary>
675     public enum ImageOrientation : int
676     {
677         /// <summary>
678         /// No orientation change
679         /// </summary>
680         None = 0,
681
682         /// <summary>
683         /// Rotate 90 degrees clockwise
684         /// </summary>
685         Rotate90,
686
687         /// <summary>
688         /// Rotate 180 degrees clockwise
689         /// </summary>
690         Rotate180,
691
692         /// <summary>
693         /// Rotate 90 degrees counter-clockwise (i.e. 270 degrees clockwise)
694         /// </summary>
695         Rotate270,
696
697         /// <summary>
698         /// Flip image horizontally
699         /// </summary>
700         FlipHorizontal,
701
702         /// <summary>
703         /// Flip image vertically
704         /// </summary>
705         FlipVertical,
706
707         /// <summary>
708         /// Flip the image along the y = (width - x) line (bottom-left to top-right)
709         /// </summary>
710         FlipTranspose,
711
712         /// <summary>
713         /// Flip the image along the y = x line (top-left to bottom-right)
714         /// </summary>
715         FlipTransverse
716     }
717 }