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