TizenRefApp-8315 [Gallery] Implement ViewerPage 47/123147/3
authorIgor Nazarov <i.nazarov@samsung.com>
Tue, 4 Apr 2017 16:34:01 +0000 (19:34 +0300)
committerIgor Nazarov <i.nazarov@samsung.com>
Wed, 5 Apr 2017 10:07:36 +0000 (13:07 +0300)
- Added ImageViewer widget to use in ViewerPage;
- Added ViewerPage implementetion;
- MediaItemUPtr changet to MediaItemSRef;
- UCL: added NAVIFRAME_EMPTY style and Naviframe update;
- UCL: added Window::getScreenSize() method.

Change-Id: I446c94fd3374935f4e5b63ef6c0eb9caf490be5b

22 files changed:
inc/model/IMediaAlbum.h
inc/model/MediaItem.h
inc/model/types.h
inc/presentation/ImageViewer.h [new file with mode: 0644]
inc/presentation/PreviewPage.h
inc/presentation/ThumbnailPage.h
inc/presentation/ViewerPage.h [new file with mode: 0644]
inc/presentation/types.h
src/model/MediaItem.cpp
src/presentation/ImageGrid.cpp
src/presentation/ImageViewer.cpp [new file with mode: 0644]
src/presentation/NoContentPage.cpp
src/presentation/PreviewPage.cpp
src/presentation/ThumbnailPage.cpp
src/presentation/ViewerPage.cpp [new file with mode: 0644]
src/presentation/common.h
ucl/inc/ucl/gui/Naviframe.h
ucl/inc/ucl/gui/Naviframe.hpp
ucl/inc/ucl/gui/Window.h
ucl/inc/ucl/gui/Window.hpp
ucl/inc/ucl/gui/stdTheme.h
ucl/inc/ucl/gui/stdTheme/naviframe.h [new file with mode: 0644]

index 3a8a172dc67ff615541087b3aadf3b1ce393c74e..c8933d19c530d0d068a2cc0740cce0881371de0f 100644 (file)
@@ -23,7 +23,7 @@ namespace gallery {
 
        class IMediaAlbum : public ucl::Polymorphic {
        public:
-               using EachCb = ucl::Delegate<bool(MediaItemUPtr &&media)>;
+               using EachCb = ucl::Delegate<bool(MediaItemSRef &&media)>;
 
        public:
                virtual ucl::Result forEachMedia(EachCb cb) const = 0;
index 0e8ff4645efc28c868a2e7987a47a61dc61ab7ce..1c504a3698dca26559e58eebbc5a1d477c48fc61 100644 (file)
@@ -27,7 +27,7 @@ namespace gallery {
                                ucl::Delegate<void(ucl::Result, const std::string &path)>;
 
        public:
-               static MediaItemUPtr newInstance(media_info_h media);
+               static MediaItemSRef newInstance(media_info_h media);
                virtual ~MediaItem();
 
                bool isValid() const;
@@ -43,6 +43,7 @@ namespace gallery {
                ucl::Result removeFile();
 
        protected:
+               friend class ucl::RefCountObj<MediaItem>;
                MediaItem(MediaType type);
 
                ucl::Result prepare(media_info_h media);
index 129c901fde72a12f3b00132647ebb9aa073c29ed..b907517de7b6ae05e035be48684d97cd6e316bff 100644 (file)
@@ -35,8 +35,7 @@ namespace gallery {
 
        UCL_DECLARE_REF_ALIASES(IMediaAlbum);
 
-       class MediaItem;
-       using MediaItemUPtr = std::unique_ptr<MediaItem>;
+       UCL_DECLARE_REF_ALIASES(MediaItem);
 }
 
 #endif // __GALLERY_MODEL_TYPES_H__
diff --git a/inc/presentation/ImageViewer.h b/inc/presentation/ImageViewer.h
new file mode 100644 (file)
index 0000000..3818900
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * Copyright 2017 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://floralicense.org/license/
+ *
+ * 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.
+ */
+
+#ifndef __GALLERY_PRESENTATION_IMAGE_VIEWER_H__
+#define __GALLERY_PRESENTATION_IMAGE_VIEWER_H__
+
+#include "ucl/gui/StyledWidget.h"
+#include "ucl/gui/Layout.h"
+
+#include "types.h"
+
+namespace gallery {
+
+       constexpr ucl::SmartEvent IMAGE_VIEWER_ZOOM_END {"gallery,zoom,end"};
+
+       class ImageViewer final : public ucl::Widget {
+       public:
+               class Builder {
+               public:
+                       Builder();
+                       Builder &setImageSize(int w, int h);
+                       ImageViewerSRef build(ucl::Widget &parent) const;
+               private:
+                       int m_imageW;
+                       int m_imageH;
+               };
+
+       public:
+               void setLowResImagePath(const std::string &path);
+               void setHighResImagePath(const std::string &path);
+
+               bool zoomIn(int originX, int originY);
+               bool zoomOut();
+
+               bool isZooming() const;
+               bool isZoomedIn() const;
+               bool isZoomedOut() const;
+
+       private:
+               friend class ucl::RefCountObj<ImageViewer>;
+               ImageViewer(ucl::RefCountObjBase &rc, int imageW,
+                               int imageH, Evas_Object *scroller);
+               virtual ~ImageViewer();
+
+               void prepare();
+
+               void onImagePreloaded(ucl::Widget &widget, void *eventInfo);
+               void onScrollerResize(ucl::Widget &widget, void *eventInfo);
+
+               bool updateScrollerSize();
+               void updateScales();
+               void updateGridSize();
+               void updateScrollOffset();
+
+               void calcZoomInFactors(int originX, int originY);
+               void calcZoomOutFactors();
+               void startAnimation();
+
+               Eina_Bool onAnimationStartTimer();
+               Eina_Bool onAnimationFrame(double pos);
+
+       private:
+               enum class State {
+                       ZOOMED_OUT,
+                       ZOOMED_IN,
+                       ZOOMING_OUT,
+                       ZOOMING_IN
+               };
+
+       private:
+               const int m_imageW;
+               const int m_imageH;
+
+               ucl::StyledWidgetWRef m_scroller;
+               ucl::Layout m_layout;
+               ucl::Widget m_grid;
+               ucl::Widget m_lowResImage;
+               ucl::Widget m_highResImage;
+
+               int m_scrollerW;
+               int m_scrollerH;
+               int m_gridW;
+               int m_gridH;
+               double m_scale0;
+               double m_scale1;
+
+               double m_xf1;
+               double m_yf1;
+               double m_xf2;
+               double m_yf2;
+               double m_zoom;
+
+               Ecore_Timer *m_animationStartTimer;
+               Ecore_Animator *m_animator;
+               State m_state;
+       };
+}
+
+#endif // __GALLERY_PRESENTATION_IMAGE_VIEWER_H__
index d47f05dd81935236ba45022e6ad23fb3ea53172f..6c32acb1269ccc2ff02b9b61056bd4c138cd6efb 100644 (file)
@@ -54,7 +54,7 @@ namespace gallery {
                ucl::Result prepare();
                void showItem(int itemIndex);
 
-               bool onEachMedia(MediaItemUPtr &&media);
+               bool onEachMedia(MediaItemSRef &&media);
 
                // Page //
 
index 4f46e3b5b88e9fce5b3283b1850ea180c2019f5a..13ec7a8b842c0faf78c946c96b63382fb1b8caee 100644 (file)
@@ -51,7 +51,7 @@ namespace gallery {
 
                ucl::Result prepare();
 
-               bool onEachMedia(MediaItemUPtr &&media);
+               bool onEachMedia(MediaItemSRef &&media);
 
                void onPageExitRequest(Page &page);
 
@@ -72,7 +72,7 @@ namespace gallery {
 
        private:
                const IMediaAlbumSRef m_album;
-               std::vector<MediaItemUPtr> m_mediaItems;
+               std::vector<MediaItemSRef> m_mediaItems;
 
                std::vector<RealizedItemUPtr> m_realizedItems;
 
diff --git a/inc/presentation/ViewerPage.h b/inc/presentation/ViewerPage.h
new file mode 100644 (file)
index 0000000..fc4fcb7
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2017 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://floralicense.org/license/
+ *
+ * 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.
+ */
+
+#ifndef __GALLERY_PRESENTATION_VIEWER_PAGE_H__
+#define __GALLERY_PRESENTATION_VIEWER_PAGE_H__
+
+#include "Page.h"
+
+#include "model/types.h"
+
+namespace gallery {
+
+       class ViewerPage final : public Page {
+       public:
+               class Builder {
+               public:
+                       Builder();
+                       ~Builder();
+                       Builder &setNaviframe(const ucl::NaviframeSRef &navi);
+                       Builder &setMedia(const MediaItemSRef &media);
+                       Builder &setExitOnZoomOut(bool value);
+                       ViewerPageSRef build(ExitRequestHandler onExitRequest) const;
+               private:
+                       ucl::NaviframeSRef m_navi;
+                       MediaItemSRef m_media;
+                       bool m_exitOnZoomOut;
+               };
+
+       public:
+               void zoomIn(int originX, int originY);
+
+       private:
+               friend class ucl::RefCountObj<ViewerPage>;
+               ViewerPage(ucl::RefCountObjBase &rc, const ucl::NaviframeSRef &navi,
+                               ExitRequestHandler onExitRequest, const MediaItemSRef &media,
+                               bool exitOnZoomOut);
+               virtual ~ViewerPage();
+
+               ucl::Result prepare();
+
+               void onThumbnail(ucl::Result result, const std::string &path);
+               void onZoomEnd(ucl::Widget &widget, void *eventInfo);
+
+               // Page //
+
+               virtual void onBackKey() final override;
+
+       private:
+               const MediaItemSRef m_media;
+               const bool m_exitOnZoomOut;
+               ImageViewerSRef m_imageViewer;
+       };
+}
+
+#endif // __GALLERY_PRESENTATION_VIEWER_PAGE_H__
index 25837fbbde1ae370b98d88f8eaa0e04ecd18341e..d34fbb4ab171d7c7e8f62683788e6c5f0b3adff2 100644 (file)
@@ -26,12 +26,14 @@ namespace gallery {
        class IImageGridListener;
 
        UCL_DECLARE_REF_ALIASES(ImageGrid);
+       UCL_DECLARE_REF_ALIASES(ImageViewer);
 
        UCL_DECLARE_REF_ALIASES(Page);
 
+       UCL_DECLARE_REF_ALIASES(NoContentPage);
        UCL_DECLARE_REF_ALIASES(ThumbnailPage);
        UCL_DECLARE_REF_ALIASES(PreviewPage);
-       UCL_DECLARE_REF_ALIASES(NoContentPage);
+       UCL_DECLARE_REF_ALIASES(ViewerPage);
 }
 
 #endif // __GALLERY_PRESENTATION_TYPES_H__
index 725fa2d52bd346d4d1f2c1863b3da86ecdfd1567..5771b7dea576d1b99a4058c3f555491024f305b7 100644 (file)
@@ -37,7 +37,7 @@ namespace gallery {
                freeMediaInfo();
        }
 
-       MediaItemUPtr MediaItem::newInstance(const media_info_h media)
+       MediaItemSRef MediaItem::newInstance(const media_info_h media)
        {
                media_content_type_e contentType = MEDIA_CONTENT_TYPE_OTHERS;
                const int ret = media_info_get_media_type(media, &contentType);
@@ -46,7 +46,7 @@ namespace gallery {
                                        "media_info_get_media_type() failed: %d", ret);
                }
 
-               MediaItemUPtr result{new MediaItem(toMediaType(contentType))};
+               auto result = makeShared<MediaItem>(toMediaType(contentType));
 
                FAIL_RETURN_VALUE(result->prepare(media), {},
                                "result->prepare() failed!");
index 5ce3ab65ef5fd30c9bba20e48c6c1ef8ec808806..a998b5eeabbee6bf1ad2e3e5e42b4f20172d564f 100644 (file)
@@ -32,9 +32,6 @@ namespace gallery { namespace { namespace impl {
        // Related to ImageGrid //
        const TString SLOT_PART_FMT {"swallow.cell_%d"};
 
-       // Related to Scroller //
-       constexpr ElmStyle SCROLLER_STYLE {"effect"};
-
        // Related to Button //
        constexpr ElmStyle ITEM_BTN_STYLE {"gallery_image"};
        constexpr EdjePart PART_BTN_BG {"swallow.bg"};
@@ -531,7 +528,7 @@ namespace gallery {
                elm_box_horizontal_set(m_box, toEina(m_info.isHorizontal));
                show(m_box);
 
-               m_scroller->setStyle(impl::SCROLLER_STYLE);
+               m_scroller->setStyle(SCROLLER_STYLE);
                expandAndFill(*m_scroller);
                if (m_info.isHorizontal) {
                        elm_scroller_page_scroll_limit_set(
diff --git a/src/presentation/ImageViewer.cpp b/src/presentation/ImageViewer.cpp
new file mode 100644 (file)
index 0000000..a74f194
--- /dev/null
@@ -0,0 +1,360 @@
+/*
+ * Copyright 2017 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://floralicense.org/license/
+ *
+ * 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.
+ */
+
+#include "presentation/ImageViewer.h"
+
+#include "common.h"
+
+namespace gallery { namespace { namespace impl {
+
+       constexpr auto ANIMATION_START_TIMEOUT_SEC = (1.0 / 30.0);
+       constexpr auto ANIMATION_RUNTIME_SEC = (300.0 / 1000.0);
+}}}
+
+namespace gallery {
+
+       using namespace ucl;
+
+       // ImageViewer::Builder //
+
+       ImageViewer::Builder::Builder() :
+               m_imageW(0),
+               m_imageH(0)
+       {
+       }
+
+       ImageViewer::Builder &ImageViewer::Builder::setImageSize(
+                       const int w, const int h)
+       {
+               m_imageW = w;
+               m_imageH = h;
+               return *this;
+       }
+
+       ImageViewerSRef ImageViewer::Builder::build(Widget &parent) const
+       {
+               if ((m_imageW <= 0) || (m_imageH <= 0)) {
+                       LOG_RETURN_VALUE(RES_INVALID_ARGUMENTS, {}, "Image size is invalid");
+               }
+
+               auto scroller = elm_scroller_add(parent);
+               if (!scroller) {
+                       LOG_RETURN_VALUE(RES_FAIL, {}, "elm_scroller_add() failed!");
+               }
+
+               return makeShared<ImageViewer>(m_imageW, m_imageH, scroller);
+       }
+
+       // ImageViewer //
+
+       ImageViewer::ImageViewer(RefCountObjBase &rc,
+                       const int imageW, const int imageH,
+                       Evas_Object *const scroller) :
+               Widget(&rc, scroller, true),
+               m_imageW(imageW),
+               m_imageH(imageH),
+
+               m_scroller(makeShared<StyledWidget>(scroller)),
+               m_layout(elm_layout_add(*m_scroller)),
+               m_grid(evas_object_grid_add(m_layout.getEvas())),
+               m_lowResImage(evas_object_image_filled_add(m_grid.getEvas())),
+               m_highResImage(evas_object_image_filled_add(m_grid.getEvas())),
+
+               m_scrollerW(0),
+               m_scrollerH(0),
+               m_gridW(0),
+               m_gridH(0),
+               m_scale0(0),
+               m_scale1(0),
+
+               m_xf1(0.5),
+               m_yf1(0.5),
+               m_xf2(0.5),
+               m_yf2(0.5),
+               m_zoom(0.0),
+
+               m_animationStartTimer(nullptr),
+               m_animator(nullptr),
+               m_state(State::ZOOMED_OUT)
+       {
+               prepare();
+       }
+
+       ImageViewer::~ImageViewer()
+       {
+               if (m_animationStartTimer) {
+                       ecore_timer_del(m_animationStartTimer);
+               }
+               if (m_animator) {
+                       ecore_animator_del(m_animator);
+               }
+       }
+
+       void ImageViewer::prepare()
+       {
+               expandAndFill(*m_scroller);
+               m_scroller->setStyle(SCROLLER_STYLE);
+               elm_scroller_bounce_set(*m_scroller, EINA_TRUE, EINA_TRUE);
+               elm_scroller_policy_set(*m_scroller,
+                               ELM_SCROLLER_POLICY_OFF, ELM_SCROLLER_POLICY_OFF);
+               elm_object_scroll_freeze_push(*m_scroller);
+               show(*m_scroller);
+
+               expandAndFill(m_layout);
+               m_layout.setTheme(LAYOUT_DEFAULT);
+               m_scroller->setContent(m_layout);
+               show(m_layout);
+
+               evas_object_grid_size_set(m_grid, 1, 1);
+               m_layout.setContent(m_grid);
+               show(m_grid);
+
+               evas_object_grid_pack(m_grid, m_lowResImage, 0, 0, 1, 1);
+               show(m_lowResImage);
+               evas_object_grid_pack(m_grid, m_highResImage, 0, 0, 1, 1);
+               show(m_highResImage);
+
+               m_scroller->addEventHandler(WidgetEvent::RESIZE,
+                               WEAK_DELEGATE(ImageViewer::onScrollerResize, asWeak(*this)));
+
+               m_highResImage.addEventHandler(WidgetEvent::IMAGE_PRELOADED,
+                               WEAK_DELEGATE(ImageViewer::onImagePreloaded, asWeak(*this)));
+       }
+
+       void ImageViewer::onScrollerResize(Widget &widget, void *eventInfo)
+       {
+               if (updateScrollerSize()) {
+                       updateScales();
+                       updateGridSize();
+                       updateScrollOffset();
+               }
+       }
+
+       bool ImageViewer::updateScrollerSize()
+       {
+               int scrollerW = 0;
+               int scrollerH = 0;
+               getSize(*m_scroller, &scrollerW, &scrollerH);
+
+               if ((scrollerW == 0) || (scrollerH == 0)) {
+                       DLOG("Scroller has 0 size. Skip.");
+                       return false;
+               }
+
+               if ((scrollerW != m_scrollerW) || (scrollerH != m_scrollerH)) {
+                       m_scrollerW = scrollerW;
+                       m_scrollerH = scrollerH;
+                       return true;
+               }
+
+               return false;
+       }
+
+       void ImageViewer::updateScales()
+       {
+               const double sx = (1.0 * m_scrollerW / m_imageW);
+               const double sy = (1.0 * m_scrollerH / m_imageH);
+
+               m_scale0 = ((sx > sy) ? sx : sy);
+               m_scale1 = 1.0;
+       }
+
+       void ImageViewer::updateGridSize()
+       {
+               const double scale = (m_scale0 + m_zoom * (m_scale1 - m_scale0));
+
+               m_gridW = std::lround(scale * m_imageW);
+               m_gridH = std::lround(scale * m_imageH);
+
+               m_grid.setMin(m_gridW, m_gridH);
+               m_grid.setMax(m_gridW, m_gridH);
+
+               evas_object_smart_calculate(m_layout);
+       }
+
+       void ImageViewer::updateScrollOffset()
+       {
+               const double xf2 = (m_xf2 + m_zoom * (0.5 - m_xf2));
+               const double yf2 = (m_yf2 + m_zoom * (0.5 - m_yf2));
+
+               const int sx = std::lround((m_xf1 * m_gridW) - (xf2 * m_scrollerW));
+               const int sy = std::lround((m_yf1 * m_gridH) - (yf2 * m_scrollerH));
+
+               elm_scroller_region_show(*m_scroller, sx, sy, m_scrollerW, m_scrollerH);
+       }
+
+       void ImageViewer::setLowResImagePath(const std::string &path)
+       {
+               evas_object_image_file_set(m_lowResImage, path.c_str(), nullptr);
+       }
+
+       void ImageViewer::setHighResImagePath(const std::string &path)
+       {
+               hide(m_highResImage);
+               evas_object_image_file_set(m_highResImage, path.c_str(), nullptr);
+               evas_object_image_preload(m_highResImage, EINA_FALSE);
+       }
+
+       void ImageViewer::onImagePreloaded(Widget &widget, void *eventInfo)
+       {
+               show(widget);
+       }
+
+       bool ImageViewer::zoomIn(const int originX, const int originY)
+       {
+               if (m_state != State::ZOOMED_OUT) {
+                       WLOG("Can't zoom in!");
+                       return false;
+               }
+
+               m_state = State::ZOOMING_IN;
+
+               calcZoomInFactors(originX, originY);
+               startAnimation();
+
+               return true;
+       }
+
+       bool ImageViewer::zoomOut()
+       {
+               if (m_state != State::ZOOMED_IN) {
+                       WLOG("Can't zoom out!");
+                       return false;
+               }
+
+               m_state = State::ZOOMING_OUT;
+
+               calcZoomOutFactors();
+               startAnimation();
+
+               return true;
+       }
+
+       bool ImageViewer::isZooming() const
+       {
+               return ((m_state == State::ZOOMING_IN) ||
+                               (m_state == State::ZOOMING_OUT));
+       }
+
+       bool ImageViewer::isZoomedIn() const
+       {
+               return (m_state == State::ZOOMED_IN);
+       }
+
+       bool ImageViewer::isZoomedOut() const
+       {
+               return (m_state == State::ZOOMED_OUT);
+       }
+
+       void ImageViewer::calcZoomInFactors(const int originX, const int originY)
+       {
+               if (m_scale0 > m_scale1) {
+                       m_xf1 = 0.5;
+                       m_yf1 = 0.5;
+                       m_xf2 = 0.5;
+                       m_yf2 = 0.5;
+                       return;
+               }
+
+               int x = 0;
+               int y = 0;
+               getPosition(*m_scroller, &x, &y);
+
+               const int newOriginX = (originX - x);
+               const int newOriginY = (originY - x);
+
+               int sx = 0;
+               int sy = 0;
+               elm_scroller_region_get(*m_scroller, &sx, &sy, nullptr, nullptr);
+
+               m_xf1 = (1.0 * (sx + newOriginX) / m_gridW);
+               m_yf1 = (1.0 * (sy + newOriginY) / m_gridH);
+               m_xf2 = (1.0 * newOriginX / m_scrollerW);
+               m_yf2 = (1.0 * newOriginY / m_scrollerH);
+       }
+
+       void ImageViewer::calcZoomOutFactors()
+       {
+               int sx = 0;
+               int sy = 0;
+               elm_scroller_region_get(*m_scroller, &sx, &sy, nullptr, nullptr);
+
+               if (m_gridW < m_scrollerW) {
+                       sx = (0.5 * (m_gridW - m_scrollerW));
+               }
+               if (m_gridH < m_scrollerH) {
+                       sy = (0.5 * (m_gridH - m_scrollerH));
+               }
+
+               m_xf1 = ((sx + 0.5 * m_scrollerW) / m_gridW);
+               m_yf1 = ((sy + 0.5 * m_scrollerH) / m_gridH);
+               m_xf2 = (m_scale0 * m_imageW * (m_xf1 - 0.5) / m_scrollerW + 0.5);
+               m_yf2 = (m_scale0 * m_imageH * (m_yf1 - 0.5) / m_scrollerH + 0.5);
+       }
+
+       void ImageViewer::startAnimation()
+       {
+               if (m_animationStartTimer) {
+                       WLOG("Timer is running!");
+                       ecore_timer_del(m_animationStartTimer);
+               }
+
+               m_animationStartTimer = ecore_timer_add(
+                               impl::ANIMATION_START_TIMEOUT_SEC,
+                               CALLBACK_A(ImageViewer::onAnimationStartTimer), this);
+       }
+
+       Eina_Bool ImageViewer::onAnimationStartTimer()
+       {
+               m_animationStartTimer = nullptr;
+
+               if (m_animator) {
+                       WLOG("Animator is running!");
+                       ecore_animator_del(m_animator);
+               }
+               m_animator = ecore_animator_timeline_add(
+                               impl::ANIMATION_RUNTIME_SEC,
+                               CALLBACK_A(ImageViewer::onAnimationFrame), this);
+
+               return ECORE_CALLBACK_CANCEL;
+       }
+
+       Eina_Bool ImageViewer::onAnimationFrame(const double pos)
+       {
+               const double t = ecore_animator_pos_map(
+                               pos, ECORE_POS_MAP_DECELERATE, 0.0, 0.0);
+
+               m_zoom = ((m_state == State::ZOOMING_IN) ? t : (1.0 - t));
+
+               updateGridSize();
+               updateScrollOffset();
+
+               if (pos == 1.0) {
+                       m_animator = nullptr;
+                       if (m_state == State::ZOOMING_IN) {
+                               m_state = State::ZOOMED_IN;
+                               elm_object_scroll_freeze_pop(*m_scroller);
+                       } else {
+                               m_state = State::ZOOMED_OUT;
+                               elm_object_scroll_freeze_push(*m_scroller);
+                       }
+                       callSmartEvent(IMAGE_VIEWER_ZOOM_END, nullptr);
+                       return ECORE_CALLBACK_CANCEL;
+               }
+
+               return ECORE_CALLBACK_RENEW;
+       }
+}
index 0b9fd1c337dbce97bae3f96591134d95ff867668..ddbc27269b57b006d3edb5359ac1da355959e2d1 100644 (file)
@@ -104,7 +104,7 @@ namespace gallery {
                FAIL_RETURN(Page::prepare(
                        [this, &layout]()
                        {
-                               return getNaviframe().push(*layout);
+                               return getNaviframe().push(*layout, NAVIFRAME_EMPTY);
                        }),
                        "Page::prepare() failed!");
 
index 3666cf30d12d9992c7f26840c2e67ec3647db4d0..bf70d87c5a46efb2146e64f476d7a96294f12a01 100644 (file)
@@ -89,7 +89,7 @@ namespace gallery {
 
        class PreviewPage::Item : public NonCopyable {
        public:
-               Item(MediaItemUPtr &&media, ImageGrid &imageGrid, const int itemIndex) :
+               Item(MediaItemSRef &&media, ImageGrid &imageGrid, const int itemIndex) :
                        m_media(std::move(media)),
                        m_imageGrid(imageGrid),
                        m_index(itemIndex)
@@ -122,7 +122,7 @@ namespace gallery {
                }
 
        private:
-               const MediaItemUPtr m_media;
+               const MediaItemSRef m_media;
                ImageGrid &m_imageGrid;
                const int m_index;
        };
@@ -173,7 +173,7 @@ namespace gallery {
                FAIL_RETURN(Page::prepare(
                        [this]()
                        {
-                               return getNaviframe().push(*m_imageGrid);
+                               return getNaviframe().push(*m_imageGrid, NAVIFRAME_EMPTY);
                        }),
                        "Page::prepare() failed!");
 
@@ -187,7 +187,7 @@ namespace gallery {
                m_imageGrid->scrollToItem(itemIndex);
        }
 
-       bool PreviewPage::onEachMedia(MediaItemUPtr &&media)
+       bool PreviewPage::onEachMedia(MediaItemSRef &&media)
        {
                m_items.emplace_back(
                                new Item(std::move(media), *m_imageGrid, m_items.size()));
index bff4a29e6c0f079c18bbfcbbf9179c9b7e595bf2..6ce03443065812235ab5dcf37108190ce00bfec7 100644 (file)
@@ -166,7 +166,7 @@ namespace gallery {
                FAIL_RETURN(Page::prepare(
                        [this]()
                        {
-                               return getNaviframe().push(*m_imageGrid);
+                               return getNaviframe().push(*m_imageGrid, NAVIFRAME_EMPTY);
                        }),
                        "Page::prepare() failed!");
 
@@ -175,7 +175,7 @@ namespace gallery {
                return RES_OK;
        }
 
-       bool ThumbnailPage::onEachMedia(MediaItemUPtr &&media)
+       bool ThumbnailPage::onEachMedia(MediaItemSRef &&media)
        {
                m_mediaItems.emplace_back(std::move(media));
                return true;
diff --git a/src/presentation/ViewerPage.cpp b/src/presentation/ViewerPage.cpp
new file mode 100644 (file)
index 0000000..99e75e0
--- /dev/null
@@ -0,0 +1,164 @@
+/*
+ * Copyright 2017 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://floralicense.org/license/
+ *
+ * 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.
+ */
+
+#include "presentation/ViewerPage.h"
+
+#include "model/MediaItem.h"
+
+#include "presentation/ImageViewer.h"
+
+#include "common.h"
+
+namespace gallery {
+
+       using namespace ucl;
+
+       // ViewerPage::Builder //
+
+       ViewerPage::Builder::Builder() :
+               m_exitOnZoomOut(true)
+       {
+       }
+
+       ViewerPage::Builder::~Builder()
+       {
+       }
+
+       ViewerPage::Builder &ViewerPage::Builder::setNaviframe(
+                       const NaviframeSRef &navi)
+       {
+               m_navi = navi;
+               return *this;
+       }
+
+       ViewerPage::Builder &ViewerPage::Builder::setMedia(
+                       const MediaItemSRef &media)
+       {
+               m_media = media;
+               return *this;
+       }
+
+       ViewerPage::Builder &ViewerPage::Builder::setExitOnZoomOut(const bool value)
+       {
+               m_exitOnZoomOut = value;
+               return *this;
+       }
+
+       ViewerPageSRef ViewerPage::Builder::build(
+                       const ExitRequestHandler onExitRequest) const
+       {
+               if (!onExitRequest) {
+                       LOG_RETURN_VALUE(RES_INVALID_ARGUMENTS, {},
+                                       "onExitRequest is NULL");
+               }
+               if (!m_navi) {
+                       LOG_RETURN_VALUE(RES_INVALID_ARGUMENTS, {}, "m_navi is NULL");
+               }
+               if (!m_media) {
+                       LOG_RETURN_VALUE(RES_INVALID_ARGUMENTS, {}, "m_media is NULL");
+               }
+
+               auto result = makeShared<ViewerPage>(
+                               m_navi, onExitRequest, m_media, m_exitOnZoomOut);
+
+               FAIL_RETURN_VALUE(result->prepare(), {}, "result->prepare() failed!");
+
+               return result;
+       }
+
+       // ViewerPage //
+
+       ViewerPage::ViewerPage(RefCountObjBase &rc,
+                       const NaviframeSRef &navi,
+                       const ExitRequestHandler onExitRequest,
+                       const MediaItemSRef &media,
+                       const bool exitOnZoomOut) :
+               Page(rc, navi, onExitRequest),
+               m_media(media),
+               m_exitOnZoomOut(exitOnZoomOut)
+       {
+       }
+
+       ViewerPage::~ViewerPage()
+       {
+       }
+
+       void ViewerPage::zoomIn(const int originX, const int originY)
+       {
+               m_imageViewer->zoomIn(originX, originY);
+       }
+
+       Result ViewerPage::prepare()
+       {
+               int mediaW = 0;
+               int mediaH = 0;
+               m_media->getResolution(mediaW, mediaH);
+
+               m_imageViewer = ImageViewer::Builder().
+                               setImageSize(mediaW, mediaH).
+                               build(getNaviframe());
+               if (!m_imageViewer) {
+                       LOG_RETURN(RES_FAIL, "ImageViewer::build() failed!");
+               }
+
+               FAIL_RETURN(m_media->getThumbnailPath(DELEGATE(
+                               ViewerPage::onThumbnail, this)),
+                               "m_media->getThumbnailPath() failed!");
+
+               m_imageViewer->setHighResImagePath(m_media->getFilePath());
+
+               m_imageViewer->addEventHandler(IMAGE_VIEWER_ZOOM_END,
+                               WEAK_DELEGATE(ViewerPage::onZoomEnd, asWeak(*this)));
+
+               FAIL_RETURN(Page::prepare(
+                       [this]()
+                       {
+                               const auto topItem = getNaviframe().getTopItem();
+                               if (topItem) {
+                                       return getNaviframe().insertAfter(topItem,
+                                                       *m_imageViewer, NAVIFRAME_EMPTY);
+                               }
+                               return getNaviframe().push(*m_imageViewer, NAVIFRAME_EMPTY);
+                       }),
+                       "Page::prepare() failed!");
+
+               return RES_OK;
+       }
+
+       void ViewerPage::onThumbnail(const Result result, const std::string &path)
+       {
+               FAIL_RETURN_VOID(result, "Failed to get thumbnail!");
+
+               m_imageViewer->setLowResImagePath(path);
+       }
+
+       void ViewerPage::onZoomEnd(ucl::Widget &widget, void *eventInfo)
+       {
+               if (m_exitOnZoomOut && m_imageViewer->isZoomedOut()) {
+                       requestExit();
+               }
+       }
+
+       void ViewerPage::onBackKey()
+       {
+               if (m_imageViewer->isZoomedOut()) {
+                       requestExit();
+                       return;
+               }
+
+               m_imageViewer->zoomOut();
+       }
+}
index ec0a4883a01626b3433782ed16f8613f4ed2ee35..87f2d9c2df24fd7e0c7eb8ca297a70b86198294b 100644 (file)
 #ifndef __GALLERY_PRESENTATION_COMMON_H__
 #define __GALLERY_PRESENTATION_COMMON_H__
 
+#include "helpers.h"
+
 #include "../common.h"
 
-#include "helpers.h"
+namespace gallery {
+
+       constexpr ucl::ElmStyle SCROLLER_STYLE {"effect"};
+}
 
 #endif // __GALLERY_PRESENTATION_COMMON_H__
index 1e294d37492fb67b1f3cf8d8d716d46c47720368..73c1d51db615e5348b534e0a344ebb691d5d758b 100644 (file)
@@ -56,26 +56,28 @@ namespace ucl {
 
                Evas_Object *pop();
 
-               NaviItem push(const TString &title, Evas_Object *backBtn,
-                               Evas_Object *moreBtn, Evas_Object *content, ElmStyle style);
-               NaviItem push(const TString &title, Evas_Object *content);
-               NaviItem push(Evas_Object *content);
+               NaviItem push(const TString &title,
+                               Evas_Object *backBtn, Evas_Object *moreBtn,
+                               Evas_Object *content, ElmStyle style = nullptr);
+               NaviItem push(const TString &title,
+                               Evas_Object *content, ElmStyle style = nullptr);
+               NaviItem push(Evas_Object *content, ElmStyle style = nullptr);
 
                NaviItem insertAfter(NaviItem after, const TString &title,
                                Evas_Object *backBtn, Evas_Object *moreBtn,
-                               Evas_Object *content, ElmStyle style);
+                               Evas_Object *content, ElmStyle style = nullptr);
                NaviItem insertAfter(NaviItem after, const TString &title,
-                               Evas_Object *content);
+                               Evas_Object *content, ElmStyle style = nullptr);
                NaviItem insertAfter(NaviItem after,
-                               Evas_Object *content);
+                               Evas_Object *content, ElmStyle style = nullptr);
 
                NaviItem insertBefore(NaviItem before, const TString &title,
                                Evas_Object *backBtn, Evas_Object *moreBtn,
-                               Evas_Object *content, ElmStyle style);
+                               Evas_Object *content, ElmStyle style = nullptr);
                NaviItem insertBefore(NaviItem before, const TString &title,
-                               Evas_Object *content);
+                               Evas_Object *content, ElmStyle style = nullptr);
                NaviItem insertBefore(NaviItem before,
-                               Evas_Object *content);
+                               Evas_Object *content, ElmStyle style = nullptr);
 
                NaviItem getTopItem()const;
                NaviItem getBottomItem() const;
index 8acde08bdefe834bb3ed91bebdbdbd6cf5dd686a..38e20bb4cc87ffb309f102cf78cb9b1f6909c930 100644 (file)
@@ -97,14 +97,15 @@ namespace ucl {
        }
 
        inline NaviItem Naviframe::push(const TString &title,
-                       Evas_Object *const content)
+                       Evas_Object *const content, const ElmStyle style)
        {
-               return push(title, nullptr, nullptr, content, nullptr);
+               return push(title, nullptr, nullptr, content, style);
        }
 
-       inline NaviItem Naviframe::push(Evas_Object *const content)
+       inline NaviItem Naviframe::push(
+                       Evas_Object *const content, const ElmStyle style)
        {
-               return push(nullptr, nullptr, nullptr, content, nullptr);
+               return push(nullptr, nullptr, nullptr, content, style);
        }
 
        inline NaviItem Naviframe::insertAfter(NaviItem after,
@@ -119,15 +120,16 @@ namespace ucl {
        }
 
        inline NaviItem Naviframe::insertAfter(NaviItem after,
-                       const TString &title, Evas_Object *const content)
+                       const TString &title,
+                       Evas_Object *const content, const ElmStyle style)
        {
-               return insertAfter(after, title, nullptr, nullptr, content, nullptr);
+               return insertAfter(after, title, nullptr, nullptr, content, style);
        }
 
        inline NaviItem Naviframe::insertAfter(NaviItem after,
-                       Evas_Object *const content)
+                       Evas_Object *const content, const ElmStyle style)
        {
-               return insertAfter(after, nullptr, nullptr, nullptr, content, nullptr);
+               return insertAfter(after, nullptr, nullptr, nullptr, content, style);
        }
 
        inline NaviItem Naviframe::insertBefore(NaviItem before,
@@ -142,15 +144,16 @@ namespace ucl {
        }
 
        inline NaviItem Naviframe::insertBefore(NaviItem before,
-                       const TString &title, Evas_Object *const content)
+                       const TString &title,
+                       Evas_Object *const content, const ElmStyle style)
        {
-               return insertAfter(before, title, nullptr, nullptr, content, nullptr);
+               return insertAfter(before, title, nullptr, nullptr, content, style);
        }
 
        inline NaviItem Naviframe::insertBefore(NaviItem before,
-                       Evas_Object *const content)
+                       Evas_Object *const content, const ElmStyle style)
        {
-               return insertAfter(before, nullptr, nullptr, nullptr, content, nullptr);
+               return insertAfter(before, nullptr, nullptr, nullptr, content, style);
        }
 
        inline NaviItem Naviframe::getTopItem()const
index 7a617a0994cf8f021dfca24587d2d6ba05a750b0..8e526b4d49c85fddc95bfdbf84dc3350bdc746c2 100644 (file)
@@ -66,6 +66,8 @@ namespace ucl {
                StyledWidget &getConformant();
                const StyledWidget &getConformant() const;
 
+               void getScreenSize(int *w, int *h) const;
+
                void setTitle(const std::string &title);
                std::string getTitle() const;
 
index 37494b09b9058070fd6d0781a76a5995fc0678eb..f1add02bca5eaac89356ef8fa80fa53a67168972 100644 (file)
@@ -101,6 +101,11 @@ namespace ucl {
                return m_conform;
        }
 
+       inline void Window::getScreenSize(int *const w, int *const h) const
+       {
+               elm_win_screen_size_get(getEo(), nullptr, nullptr, w, h);
+       }
+
        inline void Window::setTitle(const std::string &title)
        {
                elm_win_title_set(getEo(), title.c_str());
index 76616d8f532b2707d50ceaf6e323cde3300ec20b..13202cc66e3792f90cdcd7cc6177ca52396c5a6e 100644 (file)
@@ -19,5 +19,6 @@
 
 #include "stdTheme/common.h"
 #include "stdTheme/layout.h"
+#include "stdTheme/naviframe.h"
 
 #endif // __UCL_GUI_STD_THEME_H__
diff --git a/ucl/inc/ucl/gui/stdTheme/naviframe.h b/ucl/inc/ucl/gui/stdTheme/naviframe.h
new file mode 100644 (file)
index 0000000..fd99fdc
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2017 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://floralicense.org/license/
+ *
+ * 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.
+ */
+
+#ifndef __UCL_GUI_STD_THEME_NAVIFRAME_H__
+#define __UCL_GUI_STD_THEME_NAVIFRAME_H__
+
+#include "common.h"
+
+namespace ucl {
+
+       constexpr ElmStyle NAVIFRAME_EMPTY {"empty"};
+}
+
+#endif // __UCL_GUI_STD_THEME_NAVIFRAME_H__