TizenRefApp-8332 [Gallery] Refactor application directory structure 08/123708/1
authorIgor Nazarov <i.nazarov@samsung.com>
Thu, 6 Apr 2017 15:33:15 +0000 (18:33 +0300)
committerIgor Nazarov <i.nazarov@samsung.com>
Thu, 6 Apr 2017 15:33:15 +0000 (18:33 +0300)
- "presentation" folder split into "presenters" and "view".

Change-Id: Ife435970d2a7dc4c5164e92644ba01089c2d6b3c

60 files changed:
inc/presentation/IImageGridListener.h [deleted file]
inc/presentation/ImageGrid.h [deleted file]
inc/presentation/ImageViewer.h [deleted file]
inc/presentation/Instance.h [deleted file]
inc/presentation/InstanceManager.h [deleted file]
inc/presentation/NoContentPage.h [deleted file]
inc/presentation/Page.h [deleted file]
inc/presentation/Page.hpp [deleted file]
inc/presentation/PreviewPage.h [deleted file]
inc/presentation/ThumbnailPage.h [deleted file]
inc/presentation/TouchParser.h [deleted file]
inc/presentation/ViewerPage.h [deleted file]
inc/presentation/types.h [deleted file]
inc/presenters/Instance.h [new file with mode: 0644]
inc/presenters/InstanceManager.h [new file with mode: 0644]
inc/presenters/NoContentPage.h [new file with mode: 0644]
inc/presenters/Page.h [new file with mode: 0644]
inc/presenters/Page.hpp [new file with mode: 0644]
inc/presenters/PreviewPage.h [new file with mode: 0644]
inc/presenters/ThumbnailPage.h [new file with mode: 0644]
inc/presenters/ViewerPage.h [new file with mode: 0644]
inc/presenters/types.h [new file with mode: 0644]
inc/resources.h
inc/view/IImageGridListener.h [new file with mode: 0644]
inc/view/ImageGrid.h [new file with mode: 0644]
inc/view/ImageViewer.h [new file with mode: 0644]
inc/view/TouchParser.h [new file with mode: 0644]
inc/view/helpers.h [new file with mode: 0644]
inc/view/types.h [new file with mode: 0644]
src/common.h
src/main.cpp
src/model/GalleryAlbum.cpp
src/model/MediaItem.cpp
src/model/common.h
src/presentation/ImageGrid.cpp [deleted file]
src/presentation/ImageViewer.cpp [deleted file]
src/presentation/Instance.cpp [deleted file]
src/presentation/InstanceManager.cpp [deleted file]
src/presentation/NoContentPage.cpp [deleted file]
src/presentation/Page.cpp [deleted file]
src/presentation/PreviewPage.cpp [deleted file]
src/presentation/ThumbnailPage.cpp [deleted file]
src/presentation/TouchParser.cpp [deleted file]
src/presentation/ViewerPage.cpp [deleted file]
src/presentation/common.h [deleted file]
src/presentation/helpers.cpp [deleted file]
src/presentation/helpers.h [deleted file]
src/presenters/Instance.cpp [new file with mode: 0644]
src/presenters/InstanceManager.cpp [new file with mode: 0644]
src/presenters/NoContentPage.cpp [new file with mode: 0644]
src/presenters/Page.cpp [new file with mode: 0644]
src/presenters/PreviewPage.cpp [new file with mode: 0644]
src/presenters/ThumbnailPage.cpp [new file with mode: 0644]
src/presenters/ViewerPage.cpp [new file with mode: 0644]
src/presenters/common.h [new file with mode: 0644]
src/view/ImageGrid.cpp [new file with mode: 0644]
src/view/ImageViewer.cpp [new file with mode: 0644]
src/view/TouchParser.cpp [new file with mode: 0644]
src/view/common.h [new file with mode: 0644]
src/view/helpers.cpp [new file with mode: 0644]

diff --git a/inc/presentation/IImageGridListener.h b/inc/presentation/IImageGridListener.h
deleted file mode 100644 (file)
index dd77813..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * 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_I_IMAGE_GRID_LISTENER_H__
-#define __GALLERY_PRESENTATION_I_IMAGE_GRID_LISTENER_H__
-
-#include "types.h"
-
-namespace gallery {
-
-       class IImageGridListener : public ucl::Polymorphic {
-       public:
-               virtual void onItemRealized(int itemIndex) = 0;
-               virtual void onItemUnrealized(int itemIndex) = 0;
-               virtual void onItemEvent(int itemIndex, int event, int x, int y) = 0;
-       };
-}
-
-#endif // __GALLERY_PRESENTATION_I_IMAGE_GRID_LISTENER_H__
diff --git a/inc/presentation/ImageGrid.h b/inc/presentation/ImageGrid.h
deleted file mode 100644 (file)
index dd0694d..0000000
+++ /dev/null
@@ -1,207 +0,0 @@
-/*
- * 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_GRID_H__
-#define __GALLERY_PRESENTATION_IMAGE_GRID_H__
-
-#include <deque>
-
-#include "ucl/gui/StyledWidget.h"
-
-#include "types.h"
-
-namespace gallery {
-
-       class ImageGrid : public ucl::Widget {
-       public:
-               enum class Type {
-                       HCOMB_3X3,
-                       LINEAR
-               };
-
-               enum ItemEvent {
-                       ITEM_EVENT_CLICK,
-                       ITEM_EVENT_DOUBLE_TAP
-               };
-
-               class Builder {
-               public:
-                       Builder();
-                       Builder &setType(Type value);
-                       Builder &setListener(IImageGridListener *value);
-                       ImageGridSRef build(Widget &parent) const;
-               private:
-                       Type m_type;
-                       IImageGridListener *m_listener;
-               };
-
-               enum {
-                       UF_LOSE_IMAGE = 1,
-                       UF_LOSE_BG = 2,
-                       UF_BLOCK_CLICKS = 4
-               };
-
-               struct ItemParams {
-                       int flags;
-                       int aspectX;
-                       int aspectY;
-                       std::string imagePath;
-                       std::string bgImagePath;
-               };
-
-               class Unrealizer : ucl::NonCopyable {
-               public:
-                       Unrealizer(ImageGrid &imageGrid);
-                       ~Unrealizer();
-               private:
-                       ImageGrid &m_imageGrid;
-               };
-
-       public:
-               void setListener(IImageGridListener *listener);
-
-               void setItemCount(int count);
-
-               void update();
-
-               ucl::Result updateItem(int itemIndex, const ItemParams &params);
-
-               ucl::Result isItemRealized(int itemIndex) const;
-
-               ucl::Result scrollToItem(int itemIndex);
-               ucl::Result bringInItem(int itemIndex);
-
-               void activateRotary();
-               void deactivateRotary();
-
-       private:
-               class Slot;
-               using SlotUPtr = std::unique_ptr<Slot>;
-
-               struct Info;
-               struct HcombInfo;
-               struct LinearInfo;
-
-       private:
-               friend class ucl::RefCountObj<ImageGrid>;
-               ImageGrid(ucl::RefCountObjBase *rc, Type type, Evas_Object *scroller);
-
-               static const Info &getInfo(Type type);
-
-               template <class FUNC>
-               ucl::Result doWithItem(int itemIndex, FUNC &&func) const;
-               template <class FUNC>
-               ucl::Result doWithCell(int itemIndex, FUNC &&func) const;
-
-               template <class SHOW_FUNC>
-               ucl::Result showItem(int itemIndex, SHOW_FUNC &&showFunc);
-
-               void addUnrealizeLock();
-               void removeUnrealizeLock();
-
-               void handleItemEvent(int itemIndex, int event, int x, int y) const;
-
-               // Initialization
-               void prepare();
-               void createCircleScroller();
-
-               // Actual slots count
-               bool updateSlotCount();
-               int calcSlotCount();
-               void setSlotCount(int newSlotCount);
-
-               // Optimal slots count
-               bool updateOptimalSlotCount();
-               int calcOptimalSlotCount();
-
-               // Maximum slots count
-               bool updateMaxSlotCount();
-               int calcMaxSlotCount();
-
-               // Actual begin slot index
-               bool updateBeginSlotIndex();
-               int calcBeginSlotIndex();
-               void setBeginSlotIndex(int newBeginSlotIndex);
-
-               // Maximum begin slot index
-               bool updateMaxBeginSlotIndex();
-               int calcMaxBeginSlotIndex();
-
-               // Misc
-               void updatePadSizes();
-               void updateScrollBias();
-               void updateRectMins();
-
-               // Scroller size
-               bool updateScrollerSize();
-               int calcScrollerSize();
-
-               // Scroller scroll offset
-               bool updateScrollOffset();
-               int calcScrollOffset();
-
-               // Slots rotations
-               void rotateSlotsRight(int count);
-               void rotateSlotsLeft(int count);
-
-               // Slots realization/unrealization
-               void realizeSlots();
-               void unrealizeSlots(int beginSlotOffset, int endSlotOffset);
-
-               // Event handling
-               void handleScrolling();
-               void handleResize();
-
-               // Events
-               void onScrollerResize(Widget &sender, void *eventInfo);
-               void onScrollerMove(Widget &sender, void *eventInfo);
-               void onBoxMove(Widget &sender, void *eventInfo);
-
-       private:
-               const Info &m_info;
-
-               ucl::StyledWidgetWRef m_scroller;
-               ucl::ElmWidget m_box;
-               ucl::Widget m_rect1;
-               ucl::Widget m_rect2;
-               Evas_Object *m_circleScroller;
-
-               IImageGridListener *m_listener;
-               int m_itemCount;
-
-               std::deque<SlotUPtr> m_slots;
-
-               int m_slotCount;
-               int m_optimalSlotCount;
-               int m_maxSlotCount;
-
-               int m_beginSlotIndex;
-               int m_maxBeginSlotIndex;
-
-               int m_scrollBias;
-               int m_padSize1;
-               int m_padSize2;
-
-               int m_slotSize;
-               int m_scrollerSize;
-               int m_scrollOffset;
-
-               int m_unrealizeLock;
-               int m_eventsLock;
-       };
-}
-
-#endif // __GALLERY_PRESENTATION_IMAGE_GRID_H__
diff --git a/inc/presentation/ImageViewer.h b/inc/presentation/ImageViewer.h
deleted file mode 100644 (file)
index 3818900..0000000
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * 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__
diff --git a/inc/presentation/Instance.h b/inc/presentation/Instance.h
deleted file mode 100644 (file)
index 0440c14..0000000
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * 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_INSTANCE_H__
-#define __GALLERY_PRESENTATION_INSTANCE_H__
-
-#include "types.h"
-
-#include "ucl/appfw/IInstance.h"
-#include "ucl/appfw/IInstanceAppControlExt.h"
-
-#include "ucl/gui/Theme.h"
-#include "ucl/gui/Naviframe.h"
-
-#include "types.h"
-#include "model/types.h"
-
-namespace gallery {
-
-       class Instance final :
-                       public ucl::IInstance,
-                       public ucl::IInstanceAppControlExt {
-       public:
-               Instance(ucl::SysEventProvider &sysEventProvider);
-               virtual ~Instance();
-
-               // IInstance //
-
-               virtual ucl::Result onCreate(
-                               ucl::IInstanceContext *context) final override;
-               virtual void onPause() final override;
-               virtual void onResume() final override;
-
-               // IInstanceAppControlExt //
-
-               virtual void onAppControl(app_control_h appControl) final override;
-
-       private:
-               ucl::Result setupTheme();
-
-               void rescanMediaContent();
-               void stopMediaContentScan();
-               void startMediaContentScan();
-               void onScanComplete(media_content_error_e error);
-
-               void createNoContentPage();
-               void createThumbnailPage();
-
-               void onPageExitRequest(Page &page);
-
-               void onSysEvent(const ucl::SysEvent sysEvent);
-
-       private:
-               ucl::SysEventProvider &m_sysEventProvider;
-               ucl::IInstanceContext *m_context;
-
-               GallerySRef m_gallery;
-               bool m_isScanInProgress;
-
-               ucl::WindowSRef m_win;
-               ucl::Theme m_theme;
-               ucl::NaviframeSRef m_navi;
-
-               PageWRef m_page;
-       };
-}
-
-#endif // __GALLERY_PRESENTATION_INSTANCE_H__
diff --git a/inc/presentation/InstanceManager.h b/inc/presentation/InstanceManager.h
deleted file mode 100644 (file)
index 9320544..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * 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_INSTANCE_MANAGER_H__
-#define __GALLERY_PRESENTATION_INSTANCE_MANAGER_H__
-
-#include "types.h"
-
-#include "ucl/appfw/InstanceManagerBase.h"
-
-namespace gallery {
-
-       class InstanceManager : public ucl::InstanceManagerBase {
-       public:
-               InstanceManager();
-
-               // ucl::InstanceManagerBase //
-
-               virtual ucl::IInstanceSRef newInstance() const final override;
-       };
-}
-
-#endif // __GALLERY_PRESENTATION_INSTANCE_MANAGER_H__
diff --git a/inc/presentation/NoContentPage.h b/inc/presentation/NoContentPage.h
deleted file mode 100644 (file)
index e83674b..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * 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_NO_CONTENT_PAGE_H__
-#define __GALLERY_PRESENTATION_NO_CONTENT_PAGE_H__
-
-#include "Page.h"
-
-namespace gallery {
-
-       class NoContentPage final : public Page {
-       public:
-               class Builder {
-               public:
-                       Builder();
-                       ~Builder();
-                       Builder &setNaviframe(const ucl::NaviframeSRef &navi);
-                       NoContentPageSRef build(ExitRequestHandler onExitRequest) const;
-               private:
-                       ucl::NaviframeSRef m_navi;
-               };
-
-       private:
-               friend class ucl::RefCountObj<NoContentPage>;
-               NoContentPage(ucl::RefCountObjBase &rc, const ucl::NaviframeSRef &navi,
-                               ExitRequestHandler onExitRequest);
-               virtual ~NoContentPage();
-
-               ucl::Result prepare();
-       };
-}
-
-#endif // __GALLERY_PRESENTATION_NO_CONTENT_PAGE_H__
diff --git a/inc/presentation/Page.h b/inc/presentation/Page.h
deleted file mode 100644 (file)
index 90febec..0000000
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * 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_PAGE_H__
-#define __GALLERY_PRESENTATION_PAGE_H__
-
-#include "ucl/gui/Naviframe.h"
-
-#include "types.h"
-
-namespace gallery {
-
-       class Page : public ucl::RefCountAware {
-       public:
-               using ExitRequestHandler = ucl::Delegate<void(Page &page)>;
-
-       public:
-               ucl::Naviframe &getNaviframe();
-
-               bool isActive() const;
-
-               bool isAtTop() const;
-               bool isAtBottom() const;
-
-               void exit();
-               void exitNoTransition();
-
-               void popTo();
-               void deleteTo();
-               void promote();
-
-               template <class ...ARGS>
-               ucl::NaviItem insertAfter(ARGS &&...args);
-
-               template <class ...ARGS>
-               ucl::NaviItem insertBefore(ARGS &&...args);
-
-       protected:
-               Page(ucl::RefCountObjBase &rc, const ucl::NaviframeSRef &navi,
-                               ExitRequestHandler onExitRequest);
-               virtual ~Page();
-
-               template <class ITEM_FACTORY>
-               ucl::Result prepare(ITEM_FACTORY &&makeItem);
-
-               ucl::NaviItem getItem();
-
-               void requestExit();
-
-               virtual void onActivate();
-               virtual void onDeactivate();
-               virtual void onBackKey();
-
-       private:
-               ucl::Result preparePart2();
-
-               void dispatchTopPageChanged();
-
-               void activate();
-               void deactivate();
-               void updateActiveState();
-
-               void onTransitionStarted(ucl::Widget &widget, void *eventInfo);
-               void onTransitionFinished(ucl::Widget &widget, void *eventInfo);
-               void onTopPageChanged(ucl::Widget &widget, void *eventInfo);
-
-               void onHWBackKey(Evas_Object *obj, void *eventInfo);
-               void onItemDel(Evas_Object *obj, void *eventInfo);
-
-       private:
-               const ucl::NaviframeSRef m_navi;
-               const ExitRequestHandler m_onExitRequest;
-               ucl::NaviItem m_item;
-               bool m_isActive;
-       };
-
-       // Non-member functions //
-
-       bool isLast(const Page &page);
-}
-
-#include "Page.hpp"
-
-#endif // __GALLERY_PRESENTATION_PAGE_H__
diff --git a/inc/presentation/Page.hpp b/inc/presentation/Page.hpp
deleted file mode 100644 (file)
index 58be44b..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * 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 "ucl/util/logging.h"
-
-namespace gallery {
-
-       template <class ITEM_FACTORY>
-       inline ucl::Result Page::prepare(ITEM_FACTORY &&makeItem)
-       {
-               m_item = makeItem();
-               if (isNotValid(m_item)) {
-                       UCL_LOG_RETURN(ucl::RES_FAIL, "m_item is NULL");
-               }
-               return preparePart2();
-       }
-
-       template <class ...ARGS>
-       inline ucl::NaviItem Page::insertAfter(ARGS &&...args)
-       {
-               return m_navi->insertAfter(m_item, std::forward<ARGS>(args)...);
-       }
-
-       template <class ...ARGS>
-       inline ucl::NaviItem Page::insertBefore(ARGS &&...args)
-       {
-               return m_navi->insertBefore(m_item, std::forward<ARGS>(args)...);
-       }
-
-       inline ucl::Naviframe &Page::getNaviframe()
-       {
-               UCL_ASSERT(m_navi, "m_navi is NULL");
-               return *m_navi;
-       }
-
-       inline bool Page::isActive() const
-       {
-               return m_isActive;
-       }
-
-       inline bool Page::isAtTop() const
-       {
-               return (m_navi->getTopItem() == m_item);
-       }
-
-       inline bool Page::isAtBottom() const
-       {
-               return (m_navi->getBottomItem() == m_item);
-       }
-
-       // Non-member functions //
-
-       inline bool isLast(const Page &page)
-       {
-               return (page.isAtBottom() && page.isAtTop());
-       }
-}
diff --git a/inc/presentation/PreviewPage.h b/inc/presentation/PreviewPage.h
deleted file mode 100644 (file)
index a2ea01e..0000000
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * 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_PREVIEW_PAGE_H__
-#define __GALLERY_PRESENTATION_PREVIEW_PAGE_H__
-
-#include "Page.h"
-
-#include "IImageGridListener.h"
-
-#include "model/types.h"
-
-namespace gallery {
-
-       class PreviewPage final : public Page,
-                       private IImageGridListener {
-       public:
-               class Builder {
-               public:
-                       Builder();
-                       ~Builder();
-                       Builder &setNaviframe(const ucl::NaviframeSRef &navi);
-                       Builder &setAlbum(const IMediaAlbumSRef &album);
-                       Builder &setStartItemIndex(int index);
-                       PreviewPageSRef build(ExitRequestHandler onExitRequest) const;
-               private:
-                       ucl::NaviframeSRef m_navi;
-                       IMediaAlbumSRef m_album;
-                       int m_startItemIndex;
-               };
-
-       public:
-               void reload();
-
-       private:
-               friend class ucl::RefCountObj<PreviewPage>;
-               PreviewPage(ucl::RefCountObjBase &rc, const ucl::NaviframeSRef &navi,
-                               ExitRequestHandler onExitRequest, const IMediaAlbumSRef &album);
-               virtual ~PreviewPage();
-
-               ucl::Result prepare();
-               void showItem(int itemIndex);
-
-               bool onEachMedia(MediaItemSRef &&media);
-
-               void onPageExitRequest(Page &page);
-
-               // Page //
-
-               virtual void onActivate() final override;
-               virtual void onDeactivate() final override;
-
-               // IImageGridListener //
-
-               virtual void onItemRealized(int itemIndex) final override;
-               virtual void onItemUnrealized(int itemIndex) final override;
-               virtual void onItemEvent(int itemIndex,
-                               int event, int x, int y) final override;
-
-       private:
-               class Item;
-               using ItemUPtr = std::unique_ptr<Item>;
-
-       private:
-               const IMediaAlbumSRef m_album;
-               ImageGridSRef m_imageGrid;
-               std::vector<ItemUPtr> m_items;
-               PageWRef m_page;
-       };
-}
-
-#endif // __GALLERY_PRESENTATION_PREVIEW_PAGE_H__
diff --git a/inc/presentation/ThumbnailPage.h b/inc/presentation/ThumbnailPage.h
deleted file mode 100644 (file)
index 0b53f14..0000000
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * 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_THUMBNAIL_PAGE_H__
-#define __GALLERY_PRESENTATION_THUMBNAIL_PAGE_H__
-
-#include "Page.h"
-
-#include "IImageGridListener.h"
-
-#include "model/types.h"
-
-namespace gallery {
-
-       class ThumbnailPage final : public Page,
-                       private IImageGridListener {
-       public:
-               class Builder {
-               public:
-                       Builder();
-                       ~Builder();
-                       Builder &setNaviframe(const ucl::NaviframeSRef &navi);
-                       Builder &setAlbum(const IMediaAlbumSRef &album);
-                       ThumbnailPageSRef build(ExitRequestHandler onExitRequest) const;
-               private:
-                       ucl::NaviframeSRef m_navi;
-                       IMediaAlbumSRef m_album;
-               };
-
-       public:
-               void reload();
-
-       private:
-               friend class ucl::RefCountObj<ThumbnailPage>;
-               ThumbnailPage(ucl::RefCountObjBase &rc, const ucl::NaviframeSRef &navi,
-                               ExitRequestHandler onExitRequest, const IMediaAlbumSRef &album);
-               virtual ~ThumbnailPage();
-
-               ucl::Result prepare();
-
-               bool onEachMedia(MediaItemSRef &&media);
-
-               void onPageExitRequest(Page &page);
-
-               // Page //
-
-               virtual void onActivate() final override;
-               virtual void onDeactivate() final override;
-
-               // IImageGridListener //
-
-               virtual void onItemRealized(int itemIndex) final override;
-               virtual void onItemUnrealized(int itemIndex) final override;
-               virtual void onItemEvent(int itemIndex,
-                               int event, int x, int y) final override;
-
-       private:
-               class RealizedItem;
-               using RealizedItemUPtr = std::unique_ptr<RealizedItem>;
-
-       private:
-               const IMediaAlbumSRef m_album;
-               std::vector<MediaItemSRef> m_mediaItems;
-
-               std::vector<RealizedItemUPtr> m_realizedItems;
-
-               ImageGridSRef m_imageGrid;
-
-               PageWRef m_page;
-       };
-}
-
-#endif // __GALLERY_PRESENTATION_THUMBNAIL_PAGE_H__
diff --git a/inc/presentation/TouchParser.h b/inc/presentation/TouchParser.h
deleted file mode 100644 (file)
index 2c65fb3..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * 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_TOUCH_PARSER_H__
-#define __GALLERY_PRESENTATION_TOUCH_PARSER_H__
-
-#include "ucl/gui/Widget.h"
-
-#include "types.h"
-
-namespace gallery {
-
-       class TouchParser final : public ucl::RefCountAware {
-       public:
-               using TapHandler = ucl::Delegate<void(int x, int y)>;
-
-       private:
-               friend class ucl::RefCountObj<TouchParser>;
-               TouchParser(ucl::RefCountObjBase &rc, ucl::Widget &eventSource);
-               virtual ~TouchParser();
-
-       public:
-               void setTapHandler(TapHandler handler);
-               void setDoubleTapHandler(TapHandler handler);
-
-       private:
-               void onMouseDown(ucl::Widget &widget, void *eventInfo);
-               void onMouseUp(ucl::Widget &widget, void *eventInfo);
-               void onMouseMove(ucl::Widget &widget, void *eventInfo);
-
-               void updateIsTapPossible(int flags, int curX, int curY);
-
-               bool isFastTap(ucl::UInt curTime, int curX, int curY) const;
-               double calcDownDistance(int curX, int curY) const;
-
-       private:
-               TapHandler m_tapHandler;
-               TapHandler m_doubleTapHandler;
-               ucl::UInt m_downTime;
-               int m_downX;
-               int m_downY;
-               int m_tapCounter;
-               bool m_isMouseDown;
-               bool m_isTapPossible;
-       };
-}
-
-#endif // __GALLERY_PRESENTATION_TOUCH_PARSER_H__
diff --git a/inc/presentation/ViewerPage.h b/inc/presentation/ViewerPage.h
deleted file mode 100644 (file)
index 3d298fb..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * 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 &setZoomIn(int x, int y);
-                       Builder &setExitOnZoomOut(bool value);
-                       ViewerPageSRef build(ExitRequestHandler onExitRequest) const;
-               private:
-                       ucl::NaviframeSRef m_navi;
-                       MediaItemSRef m_media;
-                       int m_zoomInX;
-                       int m_zoomInY;
-                       bool m_exitOnZoomOut;
-               };
-
-       public:
-               const std::string &getMediaId() const;
-
-       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 zoomIn(int originX, int originY);
-
-               void onThumbnail(ucl::Result result, const std::string &path);
-               void onZoomEnd(ucl::Widget &widget, void *eventInfo);
-               void onDoubleTap(int x, int y);
-
-               // Page //
-
-               virtual void onBackKey() final override;
-
-       private:
-               const MediaItemSRef m_media;
-               const bool m_exitOnZoomOut;
-               ImageViewerSRef m_imageViewer;
-               TouchParserSRef m_touchParser;
-       };
-}
-
-#endif // __GALLERY_PRESENTATION_VIEWER_PAGE_H__
diff --git a/inc/presentation/types.h b/inc/presentation/types.h
deleted file mode 100644 (file)
index 4e277c8..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * 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_TYPES_H__
-#define __GALLERY_PRESENTATION_TYPES_H__
-
-#include <efl_extension.h>
-
-#include "../types.h"
-
-namespace gallery {
-
-       class IImageGridListener;
-
-       UCL_DECLARE_REF_ALIASES(TouchParser);
-
-       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(ViewerPage);
-}
-
-#endif // __GALLERY_PRESENTATION_TYPES_H__
diff --git a/inc/presenters/Instance.h b/inc/presenters/Instance.h
new file mode 100644 (file)
index 0000000..be20bd5
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * 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_PRESENTERS_INSTANCE_H__
+#define __GALLERY_PRESENTERS_INSTANCE_H__
+
+#include "ucl/appfw/IInstance.h"
+#include "ucl/appfw/IInstanceAppControlExt.h"
+
+#include "ucl/gui/Theme.h"
+#include "ucl/gui/Naviframe.h"
+
+#include "types.h"
+
+namespace gallery {
+
+       class Instance final :
+                       public ucl::IInstance,
+                       public ucl::IInstanceAppControlExt {
+       public:
+               Instance(ucl::SysEventProvider &sysEventProvider);
+               virtual ~Instance();
+
+               // IInstance //
+
+               virtual ucl::Result onCreate(
+                               ucl::IInstanceContext *context) final override;
+               virtual void onPause() final override;
+               virtual void onResume() final override;
+
+               // IInstanceAppControlExt //
+
+               virtual void onAppControl(app_control_h appControl) final override;
+
+       private:
+               ucl::Result setupTheme();
+
+               void rescanMediaContent();
+               void stopMediaContentScan();
+               void startMediaContentScan();
+               void onScanComplete(media_content_error_e error);
+
+               void createNoContentPage();
+               void createThumbnailPage();
+
+               void onPageExitRequest(Page &page);
+
+               void onSysEvent(const ucl::SysEvent sysEvent);
+
+       private:
+               ucl::SysEventProvider &m_sysEventProvider;
+               ucl::IInstanceContext *m_context;
+
+               GallerySRef m_gallery;
+               bool m_isScanInProgress;
+
+               ucl::WindowSRef m_win;
+               ucl::Theme m_theme;
+               ucl::NaviframeSRef m_navi;
+
+               PageWRef m_page;
+       };
+}
+
+#endif // __GALLERY_PRESENTERS_INSTANCE_H__
diff --git a/inc/presenters/InstanceManager.h b/inc/presenters/InstanceManager.h
new file mode 100644 (file)
index 0000000..b83b576
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * 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_PRESENTERS_INSTANCE_MANAGER_H__
+#define __GALLERY_PRESENTERS_INSTANCE_MANAGER_H__
+
+#include "ucl/appfw/InstanceManagerBase.h"
+
+#include "types.h"
+
+namespace gallery {
+
+       class InstanceManager : public ucl::InstanceManagerBase {
+       public:
+               InstanceManager();
+
+               // ucl::InstanceManagerBase //
+
+               virtual ucl::IInstanceSRef newInstance() const final override;
+       };
+}
+
+#endif // __GALLERY_PRESENTERS_INSTANCE_MANAGER_H__
diff --git a/inc/presenters/NoContentPage.h b/inc/presenters/NoContentPage.h
new file mode 100644 (file)
index 0000000..67008e5
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * 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_PRESENTERS_NO_CONTENT_PAGE_H__
+#define __GALLERY_PRESENTERS_NO_CONTENT_PAGE_H__
+
+#include "Page.h"
+
+namespace gallery {
+
+       class NoContentPage final : public Page {
+       public:
+               class Builder {
+               public:
+                       Builder();
+                       ~Builder();
+                       Builder &setNaviframe(const ucl::NaviframeSRef &navi);
+                       NoContentPageSRef build(ExitRequestHandler onExitRequest) const;
+               private:
+                       ucl::NaviframeSRef m_navi;
+               };
+
+       private:
+               friend class ucl::RefCountObj<NoContentPage>;
+               NoContentPage(ucl::RefCountObjBase &rc, const ucl::NaviframeSRef &navi,
+                               ExitRequestHandler onExitRequest);
+               virtual ~NoContentPage();
+
+               ucl::Result prepare();
+       };
+}
+
+#endif // __GALLERY_PRESENTERS_NO_CONTENT_PAGE_H__
diff --git a/inc/presenters/Page.h b/inc/presenters/Page.h
new file mode 100644 (file)
index 0000000..e1362cc
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * 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_PRESENTERS_PAGE_H__
+#define __GALLERY_PRESENTERS_PAGE_H__
+
+#include "ucl/gui/Naviframe.h"
+
+#include "types.h"
+
+namespace gallery {
+
+       class Page : public ucl::RefCountAware {
+       public:
+               using ExitRequestHandler = ucl::Delegate<void(Page &page)>;
+
+       public:
+               ucl::Naviframe &getNaviframe();
+
+               bool isActive() const;
+
+               bool isAtTop() const;
+               bool isAtBottom() const;
+
+               void exit();
+               void exitNoTransition();
+
+               void popTo();
+               void deleteTo();
+               void promote();
+
+               template <class ...ARGS>
+               ucl::NaviItem insertAfter(ARGS &&...args);
+
+               template <class ...ARGS>
+               ucl::NaviItem insertBefore(ARGS &&...args);
+
+       protected:
+               Page(ucl::RefCountObjBase &rc, const ucl::NaviframeSRef &navi,
+                               ExitRequestHandler onExitRequest);
+               virtual ~Page();
+
+               template <class ITEM_FACTORY>
+               ucl::Result prepare(ITEM_FACTORY &&makeItem);
+
+               ucl::NaviItem getItem();
+
+               void requestExit();
+
+               virtual void onActivate();
+               virtual void onDeactivate();
+               virtual void onBackKey();
+
+       private:
+               ucl::Result preparePart2();
+
+               void dispatchTopPageChanged();
+
+               void activate();
+               void deactivate();
+               void updateActiveState();
+
+               void onTransitionStarted(ucl::Widget &widget, void *eventInfo);
+               void onTransitionFinished(ucl::Widget &widget, void *eventInfo);
+               void onTopPageChanged(ucl::Widget &widget, void *eventInfo);
+
+               void onHWBackKey(Evas_Object *obj, void *eventInfo);
+               void onItemDel(Evas_Object *obj, void *eventInfo);
+
+       private:
+               const ucl::NaviframeSRef m_navi;
+               const ExitRequestHandler m_onExitRequest;
+               ucl::NaviItem m_item;
+               bool m_isActive;
+       };
+
+       // Non-member functions //
+
+       bool isLast(const Page &page);
+}
+
+#include "Page.hpp"
+
+#endif // __GALLERY_PRESENTERS_PAGE_H__
diff --git a/inc/presenters/Page.hpp b/inc/presenters/Page.hpp
new file mode 100644 (file)
index 0000000..58be44b
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * 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 "ucl/util/logging.h"
+
+namespace gallery {
+
+       template <class ITEM_FACTORY>
+       inline ucl::Result Page::prepare(ITEM_FACTORY &&makeItem)
+       {
+               m_item = makeItem();
+               if (isNotValid(m_item)) {
+                       UCL_LOG_RETURN(ucl::RES_FAIL, "m_item is NULL");
+               }
+               return preparePart2();
+       }
+
+       template <class ...ARGS>
+       inline ucl::NaviItem Page::insertAfter(ARGS &&...args)
+       {
+               return m_navi->insertAfter(m_item, std::forward<ARGS>(args)...);
+       }
+
+       template <class ...ARGS>
+       inline ucl::NaviItem Page::insertBefore(ARGS &&...args)
+       {
+               return m_navi->insertBefore(m_item, std::forward<ARGS>(args)...);
+       }
+
+       inline ucl::Naviframe &Page::getNaviframe()
+       {
+               UCL_ASSERT(m_navi, "m_navi is NULL");
+               return *m_navi;
+       }
+
+       inline bool Page::isActive() const
+       {
+               return m_isActive;
+       }
+
+       inline bool Page::isAtTop() const
+       {
+               return (m_navi->getTopItem() == m_item);
+       }
+
+       inline bool Page::isAtBottom() const
+       {
+               return (m_navi->getBottomItem() == m_item);
+       }
+
+       // Non-member functions //
+
+       inline bool isLast(const Page &page)
+       {
+               return (page.isAtBottom() && page.isAtTop());
+       }
+}
diff --git a/inc/presenters/PreviewPage.h b/inc/presenters/PreviewPage.h
new file mode 100644 (file)
index 0000000..86fcedc
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * 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_PRESENTERS_PREVIEW_PAGE_H__
+#define __GALLERY_PRESENTERS_PREVIEW_PAGE_H__
+
+#include "Page.h"
+
+#include "view/IImageGridListener.h"
+
+namespace gallery {
+
+       class PreviewPage final : public Page,
+                       private IImageGridListener {
+       public:
+               class Builder {
+               public:
+                       Builder();
+                       ~Builder();
+                       Builder &setNaviframe(const ucl::NaviframeSRef &navi);
+                       Builder &setAlbum(const IMediaAlbumSRef &album);
+                       Builder &setStartItemIndex(int index);
+                       PreviewPageSRef build(ExitRequestHandler onExitRequest) const;
+               private:
+                       ucl::NaviframeSRef m_navi;
+                       IMediaAlbumSRef m_album;
+                       int m_startItemIndex;
+               };
+
+       public:
+               void reload();
+
+       private:
+               friend class ucl::RefCountObj<PreviewPage>;
+               PreviewPage(ucl::RefCountObjBase &rc, const ucl::NaviframeSRef &navi,
+                               ExitRequestHandler onExitRequest, const IMediaAlbumSRef &album);
+               virtual ~PreviewPage();
+
+               ucl::Result prepare();
+               void showItem(int itemIndex);
+
+               bool onEachMedia(MediaItemSRef &&media);
+
+               void onPageExitRequest(Page &page);
+
+               // Page //
+
+               virtual void onActivate() final override;
+               virtual void onDeactivate() final override;
+
+               // IImageGridListener //
+
+               virtual void onItemRealized(int itemIndex) final override;
+               virtual void onItemUnrealized(int itemIndex) final override;
+               virtual void onItemEvent(int itemIndex,
+                               int event, int x, int y) final override;
+
+       private:
+               class Item;
+               using ItemUPtr = std::unique_ptr<Item>;
+
+       private:
+               const IMediaAlbumSRef m_album;
+               ImageGridSRef m_imageGrid;
+               std::vector<ItemUPtr> m_items;
+               PageWRef m_page;
+       };
+}
+
+#endif // __GALLERY_PRESENTERS_PREVIEW_PAGE_H__
diff --git a/inc/presenters/ThumbnailPage.h b/inc/presenters/ThumbnailPage.h
new file mode 100644 (file)
index 0000000..941ce90
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * 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_PRESENTERS_THUMBNAIL_PAGE_H__
+#define __GALLERY_PRESENTERS_THUMBNAIL_PAGE_H__
+
+#include "Page.h"
+
+#include "view/IImageGridListener.h"
+
+namespace gallery {
+
+       class ThumbnailPage final : public Page,
+                       private IImageGridListener {
+       public:
+               class Builder {
+               public:
+                       Builder();
+                       ~Builder();
+                       Builder &setNaviframe(const ucl::NaviframeSRef &navi);
+                       Builder &setAlbum(const IMediaAlbumSRef &album);
+                       ThumbnailPageSRef build(ExitRequestHandler onExitRequest) const;
+               private:
+                       ucl::NaviframeSRef m_navi;
+                       IMediaAlbumSRef m_album;
+               };
+
+       public:
+               void reload();
+
+       private:
+               friend class ucl::RefCountObj<ThumbnailPage>;
+               ThumbnailPage(ucl::RefCountObjBase &rc, const ucl::NaviframeSRef &navi,
+                               ExitRequestHandler onExitRequest, const IMediaAlbumSRef &album);
+               virtual ~ThumbnailPage();
+
+               ucl::Result prepare();
+
+               bool onEachMedia(MediaItemSRef &&media);
+
+               void onPageExitRequest(Page &page);
+
+               // Page //
+
+               virtual void onActivate() final override;
+               virtual void onDeactivate() final override;
+
+               // IImageGridListener //
+
+               virtual void onItemRealized(int itemIndex) final override;
+               virtual void onItemUnrealized(int itemIndex) final override;
+               virtual void onItemEvent(int itemIndex,
+                               int event, int x, int y) final override;
+
+       private:
+               class RealizedItem;
+               using RealizedItemUPtr = std::unique_ptr<RealizedItem>;
+
+       private:
+               const IMediaAlbumSRef m_album;
+               std::vector<MediaItemSRef> m_mediaItems;
+
+               std::vector<RealizedItemUPtr> m_realizedItems;
+
+               ImageGridSRef m_imageGrid;
+
+               PageWRef m_page;
+       };
+}
+
+#endif // __GALLERY_PRESENTERS_THUMBNAIL_PAGE_H__
diff --git a/inc/presenters/ViewerPage.h b/inc/presenters/ViewerPage.h
new file mode 100644 (file)
index 0000000..c944dc4
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * 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_PRESENTERS_VIEWER_PAGE_H__
+#define __GALLERY_PRESENTERS_VIEWER_PAGE_H__
+
+#include "Page.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 &setZoomIn(int x, int y);
+                       Builder &setExitOnZoomOut(bool value);
+                       ViewerPageSRef build(ExitRequestHandler onExitRequest) const;
+               private:
+                       ucl::NaviframeSRef m_navi;
+                       MediaItemSRef m_media;
+                       int m_zoomInX;
+                       int m_zoomInY;
+                       bool m_exitOnZoomOut;
+               };
+
+       public:
+               const std::string &getMediaId() const;
+
+       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 zoomIn(int originX, int originY);
+
+               void onThumbnail(ucl::Result result, const std::string &path);
+               void onZoomEnd(ucl::Widget &widget, void *eventInfo);
+               void onDoubleTap(int x, int y);
+
+               // Page //
+
+               virtual void onBackKey() final override;
+
+       private:
+               const MediaItemSRef m_media;
+               const bool m_exitOnZoomOut;
+               ImageViewerSRef m_imageViewer;
+               TouchParserSRef m_touchParser;
+       };
+}
+
+#endif // __GALLERY_PRESENTERS_VIEWER_PAGE_H__
diff --git a/inc/presenters/types.h b/inc/presenters/types.h
new file mode 100644 (file)
index 0000000..ad884c3
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * 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_PRESENTERS_TYPES_H__
+#define __GALLERY_PRESENTERS_TYPES_H__
+
+#include "../types.h"
+#include "view/types.h"
+#include "model/types.h"
+
+namespace gallery {
+
+       UCL_DECLARE_REF_ALIASES(Page);
+
+       UCL_DECLARE_REF_ALIASES(NoContentPage);
+       UCL_DECLARE_REF_ALIASES(ThumbnailPage);
+       UCL_DECLARE_REF_ALIASES(PreviewPage);
+       UCL_DECLARE_REF_ALIASES(ViewerPage);
+}
+
+#endif // __GALLERY_PRESENTERS_TYPES_H__
index fbdef93ae13152a28c0c3ec0c8a3e6982ebed301..9e087d1d1100cf96a7fc56b3ba53ad91abb5f680 100644 (file)
 #ifndef __GALLERY_RESOURCES_H__
 #define __GALLERY_RESOURCES_H__
 
-#include "config.h"
-
 #include "ucl/misc/TString.h"
 
+#include "config.h"
+
 namespace gallery {
 
        constexpr auto THEME_EDJE_PATH = "edje/theme.edj";
diff --git a/inc/view/IImageGridListener.h b/inc/view/IImageGridListener.h
new file mode 100644 (file)
index 0000000..1f2992f
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * 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_VIEW_I_IMAGE_GRID_LISTENER_H__
+#define __GALLERY_VIEW_I_IMAGE_GRID_LISTENER_H__
+
+#include "types.h"
+
+namespace gallery {
+
+       class IImageGridListener : public ucl::Polymorphic {
+       public:
+               virtual void onItemRealized(int itemIndex) = 0;
+               virtual void onItemUnrealized(int itemIndex) = 0;
+               virtual void onItemEvent(int itemIndex, int event, int x, int y) = 0;
+       };
+}
+
+#endif // __GALLERY_VIEW_I_IMAGE_GRID_LISTENER_H__
diff --git a/inc/view/ImageGrid.h b/inc/view/ImageGrid.h
new file mode 100644 (file)
index 0000000..3016f09
--- /dev/null
@@ -0,0 +1,207 @@
+/*
+ * 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_VIEW_IMAGE_GRID_H__
+#define __GALLERY_VIEW_IMAGE_GRID_H__
+
+#include <deque>
+
+#include "ucl/gui/StyledWidget.h"
+
+#include "types.h"
+
+namespace gallery {
+
+       class ImageGrid : public ucl::Widget {
+       public:
+               enum class Type {
+                       HCOMB_3X3,
+                       LINEAR
+               };
+
+               enum ItemEvent {
+                       ITEM_EVENT_CLICK,
+                       ITEM_EVENT_DOUBLE_TAP
+               };
+
+               class Builder {
+               public:
+                       Builder();
+                       Builder &setType(Type value);
+                       Builder &setListener(IImageGridListener *value);
+                       ImageGridSRef build(Widget &parent) const;
+               private:
+                       Type m_type;
+                       IImageGridListener *m_listener;
+               };
+
+               enum {
+                       UF_LOSE_IMAGE = 1,
+                       UF_LOSE_BG = 2,
+                       UF_BLOCK_CLICKS = 4
+               };
+
+               struct ItemParams {
+                       int flags;
+                       int aspectX;
+                       int aspectY;
+                       std::string imagePath;
+                       std::string bgImagePath;
+               };
+
+               class Unrealizer : ucl::NonCopyable {
+               public:
+                       Unrealizer(ImageGrid &imageGrid);
+                       ~Unrealizer();
+               private:
+                       ImageGrid &m_imageGrid;
+               };
+
+       public:
+               void setListener(IImageGridListener *listener);
+
+               void setItemCount(int count);
+
+               void update();
+
+               ucl::Result updateItem(int itemIndex, const ItemParams &params);
+
+               ucl::Result isItemRealized(int itemIndex) const;
+
+               ucl::Result scrollToItem(int itemIndex);
+               ucl::Result bringInItem(int itemIndex);
+
+               void activateRotary();
+               void deactivateRotary();
+
+       private:
+               class Slot;
+               using SlotUPtr = std::unique_ptr<Slot>;
+
+               struct Info;
+               struct HcombInfo;
+               struct LinearInfo;
+
+       private:
+               friend class ucl::RefCountObj<ImageGrid>;
+               ImageGrid(ucl::RefCountObjBase *rc, Type type, Evas_Object *scroller);
+
+               static const Info &getInfo(Type type);
+
+               template <class FUNC>
+               ucl::Result doWithItem(int itemIndex, FUNC &&func) const;
+               template <class FUNC>
+               ucl::Result doWithCell(int itemIndex, FUNC &&func) const;
+
+               template <class SHOW_FUNC>
+               ucl::Result showItem(int itemIndex, SHOW_FUNC &&showFunc);
+
+               void addUnrealizeLock();
+               void removeUnrealizeLock();
+
+               void handleItemEvent(int itemIndex, int event, int x, int y) const;
+
+               // Initialization
+               void prepare();
+               void createCircleScroller();
+
+               // Actual slots count
+               bool updateSlotCount();
+               int calcSlotCount();
+               void setSlotCount(int newSlotCount);
+
+               // Optimal slots count
+               bool updateOptimalSlotCount();
+               int calcOptimalSlotCount();
+
+               // Maximum slots count
+               bool updateMaxSlotCount();
+               int calcMaxSlotCount();
+
+               // Actual begin slot index
+               bool updateBeginSlotIndex();
+               int calcBeginSlotIndex();
+               void setBeginSlotIndex(int newBeginSlotIndex);
+
+               // Maximum begin slot index
+               bool updateMaxBeginSlotIndex();
+               int calcMaxBeginSlotIndex();
+
+               // Misc
+               void updatePadSizes();
+               void updateScrollBias();
+               void updateRectMins();
+
+               // Scroller size
+               bool updateScrollerSize();
+               int calcScrollerSize();
+
+               // Scroller scroll offset
+               bool updateScrollOffset();
+               int calcScrollOffset();
+
+               // Slots rotations
+               void rotateSlotsRight(int count);
+               void rotateSlotsLeft(int count);
+
+               // Slots realization/unrealization
+               void realizeSlots();
+               void unrealizeSlots(int beginSlotOffset, int endSlotOffset);
+
+               // Event handling
+               void handleScrolling();
+               void handleResize();
+
+               // Events
+               void onScrollerResize(Widget &sender, void *eventInfo);
+               void onScrollerMove(Widget &sender, void *eventInfo);
+               void onBoxMove(Widget &sender, void *eventInfo);
+
+       private:
+               const Info &m_info;
+
+               ucl::StyledWidgetWRef m_scroller;
+               ucl::ElmWidget m_box;
+               ucl::Widget m_rect1;
+               ucl::Widget m_rect2;
+               Evas_Object *m_circleScroller;
+
+               IImageGridListener *m_listener;
+               int m_itemCount;
+
+               std::deque<SlotUPtr> m_slots;
+
+               int m_slotCount;
+               int m_optimalSlotCount;
+               int m_maxSlotCount;
+
+               int m_beginSlotIndex;
+               int m_maxBeginSlotIndex;
+
+               int m_scrollBias;
+               int m_padSize1;
+               int m_padSize2;
+
+               int m_slotSize;
+               int m_scrollerSize;
+               int m_scrollOffset;
+
+               int m_unrealizeLock;
+               int m_eventsLock;
+       };
+}
+
+#endif // __GALLERY_VIEW_IMAGE_GRID_H__
diff --git a/inc/view/ImageViewer.h b/inc/view/ImageViewer.h
new file mode 100644 (file)
index 0000000..024dffb
--- /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_VIEW_IMAGE_VIEWER_H__
+#define __GALLERY_VIEW_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_VIEW_IMAGE_VIEWER_H__
diff --git a/inc/view/TouchParser.h b/inc/view/TouchParser.h
new file mode 100644 (file)
index 0000000..98334e5
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * 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_VIEW_TOUCH_PARSER_H__
+#define __GALLERY_VIEW_TOUCH_PARSER_H__
+
+#include "ucl/gui/Widget.h"
+
+#include "types.h"
+
+namespace gallery {
+
+       class TouchParser final : public ucl::RefCountAware {
+       public:
+               using TapHandler = ucl::Delegate<void(int x, int y)>;
+
+       private:
+               friend class ucl::RefCountObj<TouchParser>;
+               TouchParser(ucl::RefCountObjBase &rc, ucl::Widget &eventSource);
+               virtual ~TouchParser();
+
+       public:
+               void setTapHandler(TapHandler handler);
+               void setDoubleTapHandler(TapHandler handler);
+
+       private:
+               void onMouseDown(ucl::Widget &widget, void *eventInfo);
+               void onMouseUp(ucl::Widget &widget, void *eventInfo);
+               void onMouseMove(ucl::Widget &widget, void *eventInfo);
+
+               void updateIsTapPossible(int flags, int curX, int curY);
+
+               bool isFastTap(ucl::UInt curTime, int curX, int curY) const;
+               double calcDownDistance(int curX, int curY) const;
+
+       private:
+               TapHandler m_tapHandler;
+               TapHandler m_doubleTapHandler;
+               ucl::UInt m_downTime;
+               int m_downX;
+               int m_downY;
+               int m_tapCounter;
+               bool m_isMouseDown;
+               bool m_isTapPossible;
+       };
+}
+
+#endif // __GALLERY_VIEW_TOUCH_PARSER_H__
diff --git a/inc/view/helpers.h b/inc/view/helpers.h
new file mode 100644 (file)
index 0000000..dab1486
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * 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_VIEW_HELPERS_H__
+#define __GALLERY_VIEW_HELPERS_H__
+
+#include <efl_extension.h>
+
+#include "types.h"
+
+namespace ucl {
+
+       class ElmWidget;
+       class Naviframe;
+}
+
+namespace gallery {
+
+       ucl::Result createCircleSurface(ucl::Naviframe &navi);
+
+       Eext_Circle_Surface *getCircleSurface(const ucl::ElmWidget &widget);
+}
+
+#endif // __GALLERY_VIEW_HELPERS_H__
diff --git a/inc/view/types.h b/inc/view/types.h
new file mode 100644 (file)
index 0000000..996f843
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * 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_VIEW_TYPES_H__
+#define __GALLERY_VIEW_TYPES_H__
+
+#include "../types.h"
+
+namespace gallery {
+
+       class IImageGridListener;
+
+       UCL_DECLARE_REF_ALIASES(TouchParser);
+
+       UCL_DECLARE_REF_ALIASES(ImageGrid);
+       UCL_DECLARE_REF_ALIASES(ImageViewer);
+}
+
+#endif // __GALLERY_VIEW_TYPES_H__
index e617be6a357e5dea9420ac5ec9fc6de1c7c16e1e..753d2422e083987a60feb3500063dd3b4f23c6cb 100644 (file)
 
 #include <algorithm>
 
-#include <Ecore.h>
-
 #include "ucl/util/helpers.h"
 #include "ucl/util/logging.h"
 #include "ucl/util/shortLogs.h"
 
-#include "ucl/gui/stdTheme.h"
-#include "ucl/gui/helpers.h"
-
-#include "resources.h"
-
 #undef UCL_LOG_TAG
-#define UCL_LOG_TAG "GALLERY"
+#define UCL_LOG_TAG GALLERY_LOG_TAG
 
 #endif // __GALLERY_COMMON_H__
index 526bf3d7f2f4b8d8c092a442f68d5e9c9a743a75..e548152229bc1b617ccd20a16486217b49272504 100644 (file)
@@ -16,7 +16,7 @@
 
 #include "ucl/appfw/UIApp.h"
 
-#include "presentation/InstanceManager.h"
+#include "presenters/InstanceManager.h"
 
 #include "common.h"
 
index c79359f100bec3b7ea91bddeeb6d23a3872a7d3f..7fe098c6832385e83783ac18df1ebe6f378bc0a1 100644 (file)
@@ -16,6 +16,8 @@
 
 #include "GalleryAlbum.h"
 
+#include "ucl/misc/TString.h"
+
 #include "model/MediaItem.h"
 
 #include "common.h"
@@ -24,9 +26,8 @@ namespace gallery { namespace { namespace impl {
 
        using namespace ucl;
 
-       const auto CONDITION = TString("%s=%d OR %s=%d").format(
-                       MEDIA_TYPE, MEDIA_CONTENT_TYPE_IMAGE,
-                       MEDIA_TYPE, MEDIA_CONTENT_TYPE_VIDEO);
+       const auto CONDITION = TString("%s=%d").format(
+                       MEDIA_TYPE, MEDIA_CONTENT_TYPE_IMAGE);
 }}}
 
 namespace gallery {
index c25d2c3e1530286b4db3c59f5e64d6d5ab1a8b54..39c4b6fb4e19eaefab9c25ab4afd188aa1f47b6e 100644 (file)
@@ -16,6 +16,8 @@
 
 #include "model/MediaItem.h"
 
+#include <Ecore_File.h>
+
 #include "common.h"
 
 namespace gallery {
index 594f735d80fa77d22f0e92a0071920b84dcc827e..7581a14041f081e8002e349ae1c499b54d9060ce 100644 (file)
@@ -17,8 +17,8 @@
 #ifndef __GALLERY_MODEL_COMMON_H__
 #define __GALLERY_MODEL_COMMON_H__
 
-#include "../common.h"
-
 #include "helpers.h"
 
+#include "../common.h"
+
 #endif // __GALLERY_MODEL_COMMON_H__
diff --git a/src/presentation/ImageGrid.cpp b/src/presentation/ImageGrid.cpp
deleted file mode 100644 (file)
index 76aefa2..0000000
+++ /dev/null
@@ -1,1133 +0,0 @@
-/*
- * 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/ImageGrid.h"
-
-#include <array>
-#include <vector>
-
-#include "ucl/gui/Layout.h"
-
-#include "presentation/IImageGridListener.h"
-#include "presentation/TouchParser.h"
-
-#include "common.h"
-
-namespace gallery { namespace { namespace impl {
-
-       using namespace ucl;
-
-       // Related to ImageGrid //
-       const TString SLOT_PART_FMT {"swallow.cell_%d"};
-
-       // Related to Button //
-       constexpr ElmStyle ITEM_BTN_STYLE {"gallery_image"};
-       constexpr EdjePart PART_BTN_BG {"swallow.bg"};
-       constexpr SmartEvent BTN_CLICKED {"clicked"};
-       constexpr EdjeSignal BTN_BLOCK_CLICKS {"gallery,block,clicks"};
-       constexpr EdjeSignal BTN_UNBLOCK_CLICKS {"gallery,unblock,clicks"};
-
-       // Other //
-       constexpr auto HCOMB_SCROLL_LIMIT = 1000;
-}}}
-
-namespace gallery {
-
-       using namespace ucl;
-
-       // ImageGrid::Builder //
-
-       ImageGrid::Builder::Builder() :
-               m_type(Type::HCOMB_3X3),
-               m_listener(nullptr)
-       {
-       }
-
-       ImageGrid::Builder &ImageGrid::Builder::setType(const Type value)
-       {
-               m_type = value;
-               return *this;
-       }
-
-       ImageGrid::Builder &ImageGrid::Builder::setListener(
-                       IImageGridListener *const value)
-       {
-               m_listener = value;
-               return *this;
-       }
-
-       ImageGridSRef ImageGrid::Builder::build(Widget &parent) const
-       {
-               Evas_Object *const scrollerEo = elm_scroller_add(parent);
-               if (!scrollerEo) {
-                       ELOG("elm_scroller_add() failed!");
-                       return {};
-               }
-
-               auto result = makeShared<ImageGrid>(m_type, scrollerEo);
-
-               result->bindToEo();
-               result->setListener(m_listener);
-
-               return result;
-       }
-
-       // ImageGrid::Info //
-
-       struct ImageGrid::Info {
-               const std::array<LayoutTheme, 2> slotThemes;
-               const std::array<int, 2> slotLens;
-               const int scrollLimit;
-               const int slotsPerPage;
-               const bool isHorizontal;
-
-               virtual int calcItemIndexFromCell(
-                               const int slotIndex, const int itemOffset) const = 0;
-               virtual void calcCellFromItemIndex(const int itemIndex,
-                               int &slotIndex, int &itemOffset) const = 0;
-
-               virtual int calcMaxSlotCount(const int itemCount) const = 0;
-
-               virtual int calcExtraPaddingSize(const int slotSize,
-                               const int itemCount) const
-               {
-                       return 0;
-               }
-
-               Info(const std::array<LayoutTheme, 2> &slotThemes,
-                               const std::array<int, 2> &slotLens,
-                               const int scrollLimit, const int slotsPerPage,
-                               const bool isHorizontal) :
-                       slotThemes(slotThemes),
-                       slotLens(slotLens),
-                       scrollLimit(scrollLimit),
-                       slotsPerPage(slotsPerPage),
-                       isHorizontal(isHorizontal)
-               {
-               }
-       };
-
-       // ImageGrid::HcombInfo //
-
-       struct ImageGrid::HcombInfo : Info {
-               const int totalLength;
-
-               virtual int calcItemIndexFromCell(
-                               const int slotIndex, const int itemOffset) const final override
-               {
-                       return ((slotIndex / 2 * totalLength) +
-                                       (itemOffset * 2) + ((slotIndex ^ 1) & 1));
-               }
-
-               virtual void calcCellFromItemIndex(const int itemIndex,
-                               int &slotIndex, int &itemOffset) const final override
-               {
-                       slotIndex = (itemIndex / totalLength);
-                       itemOffset = (itemIndex % totalLength);
-                       slotIndex += (slotIndex + ((itemOffset ^ 1) & 1));
-                       itemOffset /= 2;
-               }
-
-               virtual int calcMaxSlotCount(const int itemCount) const final override
-               {
-                       return ((itemCount + (totalLength - 1)) / totalLength * 2);
-               }
-
-               virtual int calcExtraPaddingSize(const int slotSize,
-                               const int itemCount) const final override
-               {
-                       return slotSize;
-               }
-
-               HcombInfo(const int totalLength,
-                               const std::array<LayoutTheme, 2> &slotThemes) :
-                       Info(slotThemes, {{(totalLength / 2), ceilDiv<2>(totalLength)}},
-                               impl::HCOMB_SCROLL_LIMIT, (totalLength - 1), true),
-                       totalLength(totalLength)
-               {
-               }
-       };
-
-       // ImageGrid::LinearInfo //
-
-       struct ImageGrid::LinearInfo : Info {
-               virtual int calcItemIndexFromCell(
-                               const int slotIndex, const int itemOffset) const final override
-               {
-                       return (slotIndex / 2);
-               }
-
-               virtual void calcCellFromItemIndex(const int itemIndex,
-                               int &slotIndex, int &itemOffset) const final override
-               {
-                       slotIndex = (itemIndex * 2);
-                       itemOffset = 0;
-               }
-
-               virtual int calcMaxSlotCount(const int itemCount) const final override
-               {
-                       return (itemCount * 2);
-               }
-
-               LinearInfo(const LayoutTheme &slotTheme, const bool isHorizontal) :
-                       Info({{slotTheme}}, {{1, 0}}, 1, 1, isHorizontal)
-               {
-               }
-       };
-
-       // ImageGrid::Slot //
-
-       class ImageGrid::Slot {
-       private:
-               class Item : public RefCountAware {
-               public:
-                       friend class RefCountObj<Item>;
-                       Item(RefCountObjBase &rc,
-                                       const ImageGrid &imageGrid, Widget &parent) :
-                               RefCountAware(&rc),
-                               m_imageGrid(imageGrid),
-                               m_btn(elm_button_add(parent)),
-                               m_image(elm_image_add(m_btn)),
-                               m_realizeIndex(-1),
-                               m_imageLoadSize(0),
-                               m_wasUpdated(false),
-                               m_isClicksBlocked(false)
-                       {
-                               m_btn.setFocusAlowed(false);
-                               m_btn.setStyle(impl::ITEM_BTN_STYLE);
-                               show(m_btn);
-
-                               elm_image_preload_disabled_set(m_image, EINA_FALSE);
-                               elm_image_aspect_fixed_set(m_image, EINA_TRUE);
-                               elm_image_fill_outside_set(m_image, EINA_TRUE);
-                               m_btn.setContent(m_image);
-                               show(m_image);
-
-                               m_btn.addEventHandler(impl::BTN_CLICKED, WEAK_DELEGATE(
-                                               Item::onClicked, asWeak(*this)));
-
-                               m_touchParser = makeShared<TouchParser>(m_btn);
-                               m_touchParser->setDoubleTapHandler(
-                                               DELEGATE(Item::onDoubleTap, this));
-                       }
-
-                       Widget &getWidget()
-                       {
-                               return m_btn;
-                       }
-
-                       void setImageLoadSize(const int value)
-                       {
-                               m_imageLoadSize = value;
-                               elm_image_prescale_set(m_image, m_imageLoadSize);
-                       }
-
-                       bool isRealized() const
-                       {
-                               return (m_realizeIndex >= 0);
-                       }
-
-                       void realize(const int itemIndex)
-                       {
-                               if (isRealized()) {
-                                       return;
-                               }
-
-                               m_wasUpdated = false;
-
-                               if (itemIndex < m_imageGrid.m_itemCount) {
-                                       m_realizeIndex = itemIndex;
-
-                                       if (m_imageGrid.m_listener) {
-                                               m_imageGrid.m_listener->onItemRealized(itemIndex);
-                                       }
-                               }
-
-                               if (!m_wasUpdated) {
-                                       makeTransparent(m_btn);
-                               }
-                       }
-
-                       void unrealize()
-                       {
-                               if (!isRealized()) {
-                                       return;
-                               }
-
-                               const int itemIndex = m_realizeIndex;
-                               m_realizeIndex = -1;
-
-                               if (m_imageGrid.m_listener) {
-                                       m_imageGrid.m_listener->onItemUnrealized(itemIndex);
-                               }
-                       }
-
-                       bool update(const ItemParams &params)
-                       {
-                               if (!isRealized()) {
-                                       return false;
-                               }
-
-                               updateClicksBlock(params);
-                               updateImage(params);
-                               updateBgImage(params);
-
-                               makeWhite(m_btn);
-
-                               m_wasUpdated = true;
-
-                               return true;
-                       }
-
-               private:
-                       void updateClicksBlock(const ItemParams &params)
-                       {
-                               if (params.flags & UF_BLOCK_CLICKS) {
-                                       if (!m_isClicksBlocked) {
-                                               m_isClicksBlocked = true;
-                                               m_btn.emitSignal(impl::BTN_BLOCK_CLICKS);
-                                       }
-                               } else if (m_isClicksBlocked) {
-                                       m_isClicksBlocked = false;
-                                       m_btn.emitSignal(impl::BTN_UNBLOCK_CLICKS);
-                               }
-                       }
-
-                       void updateImage(const ItemParams &params)
-                       {
-                               if (isEmpty(params.imagePath)) {
-                                       if (!m_wasUpdated || (params.flags & UF_LOSE_IMAGE)) {
-                                               makeTransparent(m_image);
-                                       }
-                                       return;
-                               }
-
-                               elm_image_file_set(m_image, params.imagePath.c_str(), NULL);
-
-                               makeWhite(m_image);
-                       }
-
-                       void updateBgImage(const ItemParams &params)
-                       {
-                               if (isEmpty(params.bgImagePath)) {
-                                       if (m_bgImage && (!m_wasUpdated ||
-                                                       (params.flags & UF_LOSE_BG))) {
-                                               makeTransparent(*m_bgImage);
-                                       }
-                                       return;
-                               }
-
-                               if (!m_bgImage) {
-                                       m_bgImage = makeShared<Widget>(
-                                                       evas_object_image_filled_add(m_btn.getEvas()));
-                                       evas_object_image_load_size_set(*m_bgImage,
-                                                       m_imageLoadSize, m_imageLoadSize);
-                                       m_btn.setContent(impl::PART_BTN_BG, *m_bgImage);
-                                       show(*m_bgImage);
-                               }
-
-                               evas_object_image_file_set(*m_bgImage,
-                                               params.bgImagePath.c_str(), NULL);
-
-                               int w = params.aspectX;
-                               int h = params.aspectY;
-                               if ((w == 0) || (h == 0)) {
-                                       evas_object_image_size_get(*m_bgImage, &w, &h);
-                               }
-                               m_bgImage->setARHint(WidgetARHint::NEITHER, w, h);
-
-                               makeWhite(*m_bgImage);
-                       }
-
-                       void onClicked(Widget &wifget, void *eventInfo)
-                       {
-                               if (isRealized()) {
-                                       m_imageGrid.handleItemEvent(m_realizeIndex,
-                                                       ITEM_EVENT_CLICK, -1, -1);
-                               }
-                       }
-
-                       void onDoubleTap(const int x, const int y)
-                       {
-                               if (isRealized()) {
-                                       m_imageGrid.handleItemEvent(m_realizeIndex,
-                                                       ITEM_EVENT_DOUBLE_TAP, x, y);
-                               }
-                       }
-
-               private:
-                       const ImageGrid &m_imageGrid;
-                       StyledWidget m_btn;
-                       StyledWidget m_image;
-                       WidgetSRef m_bgImage;
-                       TouchParserSRef m_touchParser;
-                       int m_realizeIndex;
-                       int m_imageLoadSize;
-                       bool m_wasUpdated;
-                       bool m_isClicksBlocked;
-               };
-
-       public:
-               Slot(ImageGrid &imageGrid, const bool isOdd) :
-                       m_info(imageGrid.m_info),
-                       m_layout(elm_layout_add(imageGrid.m_box), true),
-                       m_isRealized(false)
-               {
-                       if (isValid(m_info.slotThemes[isOdd]) &&
-                                       !m_layout.setTheme(m_info.slotThemes[isOdd])) {
-                               ELOG("setTheme() failed!");
-                       }
-                       fill(m_layout);
-                       show(m_layout);
-
-                       const int length = m_info.slotLens[isOdd];
-                       for (int i = 0; i < length; ++i) {
-                               m_items.emplace_back(makeShared<Item>(imageGrid, m_layout));
-
-                               m_layout.setContent(
-                                               EdjePart(impl::SLOT_PART_FMT.format(i)),
-                                               m_items.back()->getWidget());
-                       }
-               }
-
-               Widget &getWidget()
-               {
-                       return m_layout;
-               }
-
-               int calcSize()
-               {
-                       int w = 0;
-                       int h = 0;
-                       m_layout.calculate();
-                       m_layout.getMin(&w, &h);
-                       return (m_info.isHorizontal ? w : h);
-               }
-
-               void setImageLoadSize(const int value)
-               {
-                       for (auto &item: m_items) {
-                               item->setImageLoadSize(value);
-                       }
-               }
-
-               void unrealize()
-               {
-                       if (!m_isRealized) {
-                               return;
-                       }
-                       m_isRealized = false;
-
-                       for (auto &item: m_items) {
-                               item->unrealize();
-                       }
-               }
-
-               void realize(const int slotIndex)
-               {
-                       if (m_isRealized) {
-                               return;
-                       }
-                       m_isRealized = true;
-
-                       for (UInt i = 0; i < m_items.size(); ++i) {
-                               m_items[i]->realize(
-                                               m_info.calcItemIndexFromCell(slotIndex, i));
-                       }
-               }
-
-               bool updateItem(const int itemOffset, const ItemParams &params)
-               {
-                       return m_items[itemOffset]->update(params);
-               }
-
-               bool isItemRealized(const int itemOffset) const
-               {
-                       return m_items[itemOffset]->isRealized();
-               }
-
-       private:
-               const Info &m_info;
-               std::vector<SharedRef<Item>> m_items;
-               Layout m_layout;
-               bool m_isRealized;
-       };
-
-       // ImageGrid::Unrealizer //
-
-       ImageGrid::Unrealizer::Unrealizer(ImageGrid &imageGrid) :
-               m_imageGrid(imageGrid)
-       {
-               m_imageGrid.addUnrealizeLock();
-       }
-
-       ImageGrid::Unrealizer::~Unrealizer()
-       {
-               m_imageGrid.removeUnrealizeLock();
-       }
-
-       // ImageGrid //
-
-       ImageGrid::ImageGrid(RefCountObjBase *const rc, const Type type,
-                       Evas_Object *const scroller) :
-               Widget(rc, scroller, true),
-               m_info(getInfo(type)),
-
-               m_scroller(makeShared<StyledWidget>(scroller)),
-               m_box(elm_box_add(*m_scroller)),
-               m_rect1(evas_object_rectangle_add(m_box.getEvas())),
-               m_rect2(evas_object_rectangle_add(m_box.getEvas())),
-               m_circleScroller(nullptr),
-
-               m_listener(nullptr),
-               m_itemCount(0),
-
-               m_slotCount(0), // Must be even >= 2
-               m_optimalSlotCount(2), // Must be even >= 2
-               m_maxSlotCount(2), // Must be even >= 2
-
-               m_beginSlotIndex(0),
-               m_maxBeginSlotIndex(0),
-
-               m_scrollBias(0),
-               m_padSize1(0),
-               m_padSize2(0),
-
-               m_slotSize(0), // Must not be 0
-               m_scrollerSize(1), // Must not be 0
-               m_scrollOffset(0),
-
-               m_unrealizeLock(0),
-               m_eventsLock(0)
-       {
-               prepare();
-
-               ++m_eventsLock;
-
-               updateSlotCount();
-
-               updatePadSizes();
-               updateScrollBias();
-               updateRectMins();
-
-               --m_eventsLock;
-       }
-
-       const ImageGrid::Info &ImageGrid::getInfo(const Type type)
-       {
-               switch (type) {
-               case Type::HCOMB_3X3: {
-                               static HcombInfo info{3, {{
-                                               {"layout", "gallery_image_grid", "hcomb_3x3_even"},
-                                               {"layout", "gallery_image_grid", "hcomb_3x3_odd"}}}};
-                               return info;
-                       }
-               case Type::LINEAR:
-               default: {
-                               static LinearInfo info{
-                                               {"layout", "gallery_image_grid", "linear"}, true};
-                               return info;
-                       }
-               }
-       }
-
-       void ImageGrid::prepare()
-       {
-               fill(m_rect1);
-               elm_box_pack_end(m_box, m_rect1);
-               makeTransparent(m_rect1);
-               show(m_rect1);
-
-               expandAndFill(m_rect2);
-               elm_box_pack_end(m_box, m_rect2);
-               makeTransparent(m_rect2);
-               show(m_rect2);
-
-               expandAndFill(m_box);
-               m_scroller->setContent(m_box);
-               elm_box_horizontal_set(m_box, toEina(m_info.isHorizontal));
-               show(m_box);
-
-               m_scroller->setStyle(SCROLLER_STYLE);
-               expandAndFill(*m_scroller);
-               if (m_info.isHorizontal) {
-                       elm_scroller_page_scroll_limit_set(
-                                       *m_scroller, m_info.scrollLimit, 0);
-                       elm_scroller_bounce_set(*m_scroller, EINA_TRUE, EINA_FALSE);
-               } else {
-                       elm_scroller_page_scroll_limit_set(
-                                       *m_scroller, 0, m_info.scrollLimit);
-                       elm_scroller_bounce_set(*m_scroller, EINA_FALSE, EINA_TRUE);
-               }
-               show(*m_scroller);
-
-               createCircleScroller();
-
-               m_scroller->addEventHandler(WidgetEvent::RESIZE,
-                               WEAK_DELEGATE(ImageGrid::onScrollerResize, asWeak(*this)));
-
-               m_scroller->addEventHandler(WidgetEvent::MOVE,
-                               WEAK_DELEGATE(ImageGrid::onScrollerMove, asWeak(*this)));
-
-               m_box.addEventHandler(WidgetEvent::MOVE,
-                               WEAK_DELEGATE(ImageGrid::onBoxMove, asWeak(*this)));
-       }
-
-       void ImageGrid::createCircleScroller()
-       {
-               const auto sfc = getCircleSurface(*m_scroller);
-               if (!sfc) {
-                       LOG_RETURN_VOID(RES_FAIL, "getCircleSurface() failed!");
-               }
-
-               m_circleScroller = eext_circle_object_scroller_add(*m_scroller, sfc);
-               if (!m_circleScroller) {
-                       LOG_RETURN_VOID(RES_FAIL,
-                                       "eext_circle_object_scroller_add() failed!");
-               }
-
-               if (m_info.isHorizontal) {
-                       eext_circle_object_scroller_policy_set(m_circleScroller,
-                                       ELM_SCROLLER_POLICY_AUTO, ELM_SCROLLER_POLICY_OFF);
-               } else {
-                       eext_circle_object_scroller_policy_set(m_circleScroller,
-                                       ELM_SCROLLER_POLICY_OFF, ELM_SCROLLER_POLICY_AUTO);
-               }
-       }
-
-       void ImageGrid::setListener(IImageGridListener *const listener)
-       {
-               m_listener = listener;
-       }
-
-       void ImageGrid::setItemCount(const int count)
-       {
-               if (m_itemCount == count) {
-                       return;
-               }
-
-               ++m_eventsLock;
-
-               unrealizeSlots(0, m_slotCount);
-
-               m_itemCount = count;
-
-               if (updateMaxSlotCount()) {
-                       updateSlotCount();
-                       if (updateMaxBeginSlotIndex()) {
-                               updateBeginSlotIndex();
-                       }
-               }
-
-               realizeSlots();
-               updateRectMins();
-
-               --m_eventsLock;
-       }
-
-       void ImageGrid::update()
-       {
-               Unrealizer(*this);
-       }
-
-       Result ImageGrid::updateItem(const int itemIndex, const ItemParams &params)
-       {
-               return doWithItem(itemIndex,
-                       [&params](Slot &slot, const int itemOffset)
-                       {
-                               return (slot.updateItem(itemOffset, params) ?
-                                               RES_OK : RES_FALSE);
-                       });
-       }
-
-       Result ImageGrid::isItemRealized(const int itemIndex) const
-       {
-               return doWithItem(itemIndex,
-                       [](Slot &slot, const int itemOffset)
-                       {
-                               return (slot.isItemRealized(itemOffset) ? RES_OK : RES_FALSE);
-                       });
-       }
-
-       template <class FUNC>
-       Result ImageGrid::doWithItem(const int itemIndex, FUNC &&func) const
-       {
-               return doWithCell(itemIndex,
-                       [this, &func](const int slotIndex, const int itemOffset)
-                       {
-                               const int slotOffset = (slotIndex - m_beginSlotIndex);
-                               if ((slotOffset < 0) || (slotOffset >= m_slotCount)) {
-                                       return RES_FALSE;
-                               }
-                               return func(*m_slots[slotOffset], itemOffset);
-                       });
-       }
-
-       template <class FUNC>
-       Result ImageGrid::doWithCell(const int itemIndex, FUNC &&func) const
-       {
-               if ((itemIndex < 0) || (itemIndex >= m_itemCount)) {
-                       LOG_RETURN(RES_INVALID_ARGUMENTS,
-                                       "Item index out of range: %d", itemIndex);
-               }
-
-               int slotIndex = 0;
-               int itemOffset = 0;
-               m_info.calcCellFromItemIndex(itemIndex, slotIndex, itemOffset);
-
-               return func(slotIndex, itemOffset);
-       }
-
-       Result ImageGrid::scrollToItem(const int itemIndex)
-       {
-               return showItem(itemIndex, elm_scroller_region_show);
-       }
-
-       Result ImageGrid::bringInItem(int itemIndex)
-       {
-               return showItem(itemIndex, elm_scroller_region_bring_in);
-       }
-
-       template <class SHOW_FUNC>
-       Result ImageGrid::showItem(const int itemIndex, SHOW_FUNC &&showFunc)
-       {
-               return doWithCell(itemIndex,
-                       [this, &showFunc](const int slotIndex, const int itemOffset)
-                       {
-                               const int scrollOffset = ((slotIndex / 2) * m_slotSize);
-                               if (m_info.isHorizontal) {
-                                       showFunc(*m_scroller, scrollOffset, 0, m_scrollerSize, 1);
-                               } else {
-                                       showFunc(*m_scroller, 0, scrollOffset, 1, m_scrollerSize);
-                               }
-                               return RES_OK;
-                       });
-       }
-
-       void ImageGrid::activateRotary()
-       {
-               eext_rotary_object_event_activated_set(m_circleScroller, EINA_TRUE);
-       }
-
-       void ImageGrid::deactivateRotary()
-       {
-               eext_rotary_object_event_activated_set(m_circleScroller, EINA_FALSE);
-       }
-
-       void ImageGrid::addUnrealizeLock()
-       {
-               unrealizeSlots(0, m_slotCount);
-               ++m_unrealizeLock;
-       }
-
-       void ImageGrid::removeUnrealizeLock()
-       {
-               if (m_unrealizeLock > 0) {
-                       --m_unrealizeLock;
-                       realizeSlots();
-               } else {
-                       WLOG("m_unrealizeLock = 0!");
-               }
-       }
-
-       void ImageGrid::handleItemEvent(const int itemIndex, const int event,
-                       const int x, const int y) const
-       {
-               if (m_listener) {
-                       m_listener->onItemEvent(itemIndex, event, x, y);
-               }
-       }
-
-       bool ImageGrid::updateSlotCount()
-       {
-               const int newSlotCount = calcSlotCount();
-
-               if (newSlotCount != m_slotCount) {
-                       DLOG("newSlotCount: %d; m_slotCount: %d;",
-                                       newSlotCount, m_slotCount);
-                       setSlotCount(newSlotCount);
-                       return true;
-               }
-
-               return false;
-       }
-
-       int ImageGrid::calcSlotCount()
-       {
-               return std::min(m_optimalSlotCount, m_maxSlotCount);
-       }
-
-       void ImageGrid::setSlotCount(const int newSlotCount)
-       {
-               for (int i = m_slotCount; i < newSlotCount; ++i) {
-                       const bool isOdd = ((m_beginSlotIndex + i) & 1);
-
-                       auto slot = util::makeUnique(new Slot(*this, isOdd));
-
-                       if (m_slotSize == 0) {
-                               UCL_ASSERT(!isOdd, "Must be even!");
-                               m_slotSize = std::max(slot->calcSize(), 1);
-                               const int pageSize = (m_slotSize * m_info.slotsPerPage);
-                               if (m_info.isHorizontal) {
-                                       elm_scroller_page_size_set(*m_scroller, pageSize, 0);
-                               } else {
-                                       elm_scroller_page_size_set(*m_scroller, 0, pageSize);
-                               }
-                       }
-
-                       slot->setImageLoadSize(m_slotSize);
-
-                       elm_box_pack_before(m_box, slot->getWidget(), m_rect2);
-
-                       m_slots.emplace_back(std::move(slot));
-               }
-
-               unrealizeSlots(newSlotCount, m_slotCount);
-
-               m_slots.resize(newSlotCount);
-               m_slotCount = newSlotCount;
-       }
-
-       bool ImageGrid::updateOptimalSlotCount()
-       {
-               const int newOptimalSlotCount = calcOptimalSlotCount();
-
-               if (newOptimalSlotCount != m_optimalSlotCount) {
-                       DLOG("newOptimalSlotCount: %d; m_optimalSlotCount: %d;",
-                                       newOptimalSlotCount, m_optimalSlotCount);
-                       m_optimalSlotCount = newOptimalSlotCount;
-                       return true;
-               }
-
-               return false;
-       }
-
-       int ImageGrid::calcOptimalSlotCount()
-       {
-               return (((m_scrollerSize / m_slotSize) + 3) * 2);
-       }
-
-       bool ImageGrid::updateMaxSlotCount()
-       {
-               const int newMaxSlotCount = calcMaxSlotCount();
-
-               if (newMaxSlotCount != m_maxSlotCount) {
-                       DLOG("newMaxSlotCount: %d; m_maxSlotCount: %d;",
-                                       newMaxSlotCount, m_maxSlotCount);
-                       m_maxSlotCount = newMaxSlotCount;
-                       return true;
-               }
-
-               return false;
-       }
-
-       int ImageGrid::calcMaxSlotCount()
-       {
-               return std::max(m_info.calcMaxSlotCount(m_itemCount), 2);
-       }
-
-       bool ImageGrid::updateBeginSlotIndex()
-       {
-               const int newBeginSlotIndex = calcBeginSlotIndex();
-
-               if (newBeginSlotIndex != m_beginSlotIndex) {
-                       DLOG("newBeginSlotIndex: %d; m_beginSlotIndex: %d;",
-                                       newBeginSlotIndex, m_beginSlotIndex);
-                       setBeginSlotIndex(newBeginSlotIndex);
-                       return true;
-               }
-
-               return false;
-       }
-
-       int ImageGrid::calcBeginSlotIndex()
-       {
-               const int evenScrolledSize = (m_scrollOffset - m_scrollBias);
-               const int oddScrolledSize = (evenScrolledSize - m_slotSize / 2);
-
-               const int beginEvenSlotIndex = (evenScrolledSize / m_slotSize);
-               const int beginOddSlotIndex = (oddScrolledSize / m_slotSize);
-
-               int beginSlotIndex = ((beginEvenSlotIndex <= beginOddSlotIndex) ?
-                               (beginEvenSlotIndex * 2) : (beginOddSlotIndex * 2 + 1));
-
-               if (beginSlotIndex < 0) {
-                       beginSlotIndex = 0;
-               } else if (beginSlotIndex > m_maxBeginSlotIndex) {
-                       beginSlotIndex = m_maxBeginSlotIndex;
-               }
-
-               return beginSlotIndex;
-       }
-
-       void ImageGrid::setBeginSlotIndex(const int newBeginSlotIndex)
-       {
-               const int beginSlotIndex = m_beginSlotIndex;
-               const int endSlotIndex = (beginSlotIndex + m_slotCount);
-               const int newEndSlotIndex = (newBeginSlotIndex + m_slotCount);
-
-               if ((newEndSlotIndex <= beginSlotIndex) ||
-                               (endSlotIndex <= newBeginSlotIndex)) {
-
-                       unrealizeSlots(0, m_slotCount);
-
-                       if ((beginSlotIndex ^ newBeginSlotIndex) & 1) {
-                               rotateSlotsRight(1);
-                       }
-
-               } else if (newBeginSlotIndex < beginSlotIndex) {
-                       const int goodSlots = (newEndSlotIndex - beginSlotIndex);
-                       const int badSlots = (m_slotCount - goodSlots);
-
-                       unrealizeSlots(goodSlots, m_slotCount);
-
-                       if (goodSlots > badSlots) {
-                               rotateSlotsRight(badSlots);
-                       } else {
-                               rotateSlotsLeft(goodSlots);
-                       }
-               } else {
-                       const int goodSlots = (endSlotIndex - newBeginSlotIndex);
-                       const int badSlots = (m_slotCount - goodSlots);
-
-                       unrealizeSlots(0, badSlots);
-
-                       if (goodSlots > badSlots) {
-                               rotateSlotsLeft(badSlots);
-                       } else {
-                               rotateSlotsRight(goodSlots);
-                       }
-               }
-
-               m_beginSlotIndex = newBeginSlotIndex;
-       }
-
-       bool ImageGrid::updateMaxBeginSlotIndex()
-       {
-               const int newMaxBeginSlotIndex = calcMaxBeginSlotIndex();
-
-               if (newMaxBeginSlotIndex != m_maxBeginSlotIndex) {
-                       DLOG("newMaxBeginSlotIndex: %d; m_maxBeginSlotIndex: %d;",
-                                       newMaxBeginSlotIndex, m_maxBeginSlotIndex);
-                       m_maxBeginSlotIndex = newMaxBeginSlotIndex;
-                       return true;
-               }
-
-               return false;
-       }
-
-       int ImageGrid::calcMaxBeginSlotIndex()
-       {
-               return (m_maxSlotCount - m_slotCount);
-       }
-
-       void ImageGrid::updatePadSizes()
-       {
-               const int spaceSize = (m_scrollerSize -
-                               (std::max((m_scrollerSize / m_slotSize), 1) * m_slotSize));
-
-               m_padSize1 = (spaceSize / 2);
-               m_padSize2 = (spaceSize - m_padSize1 +
-                               m_info.calcExtraPaddingSize(m_slotSize, m_itemCount));
-       }
-
-       void ImageGrid::updateScrollBias()
-       {
-               m_scrollBias = (((m_optimalSlotCount / 2 - 1) * m_slotSize -
-                               m_scrollerSize) / 2 + m_padSize1);
-       }
-
-       void ImageGrid::updateRectMins()
-       {
-               const int beginEvenCols = ((m_beginSlotIndex + 1) / 2);
-               const int sideEvenCols = ((m_maxSlotCount - m_slotCount) / 2);
-               const int endEvenCols = (sideEvenCols - beginEvenCols);
-
-               const int rectMin1 = (m_padSize1 + (beginEvenCols * m_slotSize));
-               const int rectMin2 = (m_padSize2 + (endEvenCols * m_slotSize));
-
-               if (m_info.isHorizontal) {
-                       m_rect1.setMin(rectMin1, 0);
-                       m_rect2.setMin(rectMin2, 0);
-               } else {
-                       m_rect1.setMin(0, rectMin1);
-                       m_rect2.setMin(0, rectMin2);
-               }
-       }
-
-       int ImageGrid::calcScrollerSize()
-       {
-               int scrollerW = 0;
-               int scrollerH = 0;
-               getSize(*m_scroller, &scrollerW, &scrollerH);
-
-               return std::max((m_info.isHorizontal ? scrollerW : scrollerH), 1);
-       }
-
-       bool ImageGrid::updateScrollerSize()
-       {
-               const int newScrollerSize = calcScrollerSize();
-
-               if (newScrollerSize != m_scrollerSize) {
-                       DLOG("newScrollerSize: %d; m_scrollerSize: %d;",
-                                       newScrollerSize, m_scrollerSize);
-                       m_scrollerSize = newScrollerSize;
-                       return true;
-               }
-
-               return false;
-       }
-
-       int ImageGrid::calcScrollOffset()
-       {
-               int scrollerX = 0;
-               int scrollerY = 0;
-               getPosition(*m_scroller, &scrollerX, &scrollerY);
-
-               int boxX = 0;
-               int boxY = 0;
-               getPosition(m_box, &boxX, &boxY);
-
-               int scrollOffset = (m_info.isHorizontal ?
-                               (scrollerX - boxX) : (scrollerY - boxY));
-               if (scrollOffset < 0) {
-                       scrollOffset = 0;
-               }
-
-               return scrollOffset;
-       }
-
-       bool ImageGrid::updateScrollOffset()
-       {
-               const int newScrollOffset = calcScrollOffset();
-
-               if (newScrollOffset != m_scrollOffset) {
-                       DLOG("newScrollOffset: %d; m_scrollOffset: %d;",
-                                       newScrollOffset, m_scrollOffset);
-                       m_scrollOffset= newScrollOffset;
-                       return true;
-               }
-
-               return false;
-       }
-
-       void ImageGrid::rotateSlotsRight(const int count)
-       {
-               DLOG("count: %d", count);
-               for (int i = 0; i < count; ++i) {
-                       SlotUPtr slot = std::move(m_slots.back());
-                       m_slots.pop_back();
-                       elm_box_unpack(m_box, slot->getWidget());
-                       elm_box_pack_after(m_box, slot->getWidget(), m_rect1);
-                       m_slots.emplace_front(std::move(slot));
-               }
-       }
-
-       void ImageGrid::rotateSlotsLeft(const int count)
-       {
-               DLOG("count: %d", count);
-               for (int i = 0; i < count; ++i) {
-                       SlotUPtr slot = std::move(m_slots.front());
-                       m_slots.pop_front();
-                       elm_box_unpack(m_box, slot->getWidget());
-                       elm_box_pack_before(m_box, slot->getWidget(), m_rect2);
-                       m_slots.emplace_back(std::move(slot));
-               }
-       }
-
-       void ImageGrid::realizeSlots()
-       {
-               if (m_unrealizeLock == 0) {
-                       for (int i = 0; i < m_slotCount; ++i) {
-                               m_slots[i]->realize(m_beginSlotIndex + i);
-                       }
-               }
-       }
-
-       void ImageGrid::unrealizeSlots(
-                       const int beginSlotOffset, const int endSlotOffset)
-       {
-               if (m_unrealizeLock == 0) {
-                       for (int i = beginSlotOffset; i < endSlotOffset; ++i) {
-                               m_slots[i]->unrealize();
-                       }
-               }
-       }
-
-       void ImageGrid::handleScrolling()
-       {
-               if (m_eventsLock > 0) {
-                       WLOG("Event handling was blocked!");
-                       return;
-               }
-               ++m_eventsLock;
-
-               if (updateScrollOffset() && updateBeginSlotIndex()) {
-                       realizeSlots();
-                       updateRectMins();
-               }
-
-               --m_eventsLock;
-       }
-
-       void ImageGrid::handleResize()
-       {
-               if (m_eventsLock > 0) {
-                       WLOG("Event handling was blocked!");
-                       return;
-               }
-               ++m_eventsLock;
-
-               if (updateScrollerSize()) {
-                       bool needRealize = false;
-
-                       updatePadSizes();
-
-                       if (updateOptimalSlotCount() && updateSlotCount()) {
-                               updateMaxBeginSlotIndex();
-                               needRealize = true;
-                       }
-
-                       updateScrollBias();
-
-                       if (updateBeginSlotIndex()) {
-                               needRealize = true;
-                       }
-
-                       if (needRealize) {
-                               realizeSlots();
-                       }
-                       updateRectMins();
-               }
-
-               --m_eventsLock;
-       }
-
-       void ImageGrid::onScrollerResize(Widget &sender, void *eventInfo)
-       {
-               handleResize();
-       }
-
-       void ImageGrid::onScrollerMove(Widget &sender, void *eventInfo)
-       {
-               handleScrolling();
-       }
-
-       void ImageGrid::onBoxMove(Widget &sender, void *eventInfo)
-       {
-               handleScrolling();
-       }
-}
diff --git a/src/presentation/ImageViewer.cpp b/src/presentation/ImageViewer.cpp
deleted file mode 100644 (file)
index 4fd2764..0000000
+++ /dev/null
@@ -1,363 +0,0 @@
-/*
- * 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);
-       constexpr auto ANIMATION_STOP_POS = 0.999999;
-}}}
-
-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_scroller_single_direction_set(*m_scroller,
-                               ELM_SCROLLER_SINGLE_DIRECTION_NONE);
-               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 >= impl::ANIMATION_STOP_POS) {
-                       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;
-       }
-}
diff --git a/src/presentation/Instance.cpp b/src/presentation/Instance.cpp
deleted file mode 100644 (file)
index 33a5f65..0000000
+++ /dev/null
@@ -1,233 +0,0 @@
-/*
- * 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/Instance.h"
-
-#include <system_settings.h>
-
-#include "ucl/appfw/SysEventProvider.h"
-#include "ucl/appfw/helpers.h"
-
-#include "model/Gallery.h"
-#include "model/IMediaAlbum.h"
-
-#include "presentation/NoContentPage.h"
-#include "presentation/ThumbnailPage.h"
-
-#include "common.h"
-
-namespace gallery { namespace { namespace impl {
-
-       // TODO Since feature is temporary using hard-coded path
-       constexpr auto MEDIA_FOLDER = "/opt/usr/home/owner/media";
-}}}
-
-namespace gallery {
-
-       using namespace ucl;
-
-       Instance::Instance(SysEventProvider &sysEventProvider) :
-               m_sysEventProvider(sysEventProvider),
-               m_isScanInProgress(false)
-       {
-       }
-
-       Instance::~Instance()
-       {
-               stopMediaContentScan();
-       }
-
-       Result Instance::onCreate(IInstanceContext *const context)
-       {
-               m_context = context;
-
-               m_gallery = Gallery::newInstance();
-               if (!m_gallery) {
-                       LOG_RETURN(RES_FAIL, "Gallery::newInstance() failed!");
-               }
-
-               m_win = m_context->getWindow();
-
-               FAIL_RETURN(setupTheme(), "setupTheme() failed!");
-
-               m_navi = Naviframe::Builder().
-                               build(m_win->getConformant());
-               if (!m_navi) {
-                       LOG_RETURN(RES_FAIL, "Naviframe::build() failed!");
-               }
-
-               m_win->getConformant().setContent(*m_navi);
-
-               FAIL_RETURN(createCircleSurface(*m_navi),
-                               "createCircleSurface() failed!");
-
-               m_sysEventProvider.addEventHandler(
-                               DELEGATE(Instance::onSysEvent, this));
-
-               return RES_OK;
-       }
-
-       Result Instance::setupTheme()
-       {
-               m_theme = Theme::create();
-               if (isNotValid(m_theme)) {
-                       LOG_RETURN(RES_FAIL, "Theme::create() failed!");
-               }
-
-               m_theme.addExtension(getResPath(THEME_EDJE_PATH));
-
-               m_win->setTheme(m_theme);
-
-               return RES_OK;
-       }
-
-       void Instance::onPause()
-       {
-               DLOG("PAUSE");
-       }
-
-       void Instance::onResume()
-       {
-               DLOG("RESUME");
-
-               if (SCAN_MEDIA_ON_RESUME) {
-                       rescanMediaContent();
-               }
-
-               ecore_animator_frametime_set(1.0 / 60.0);
-       }
-
-       void Instance::rescanMediaContent()
-       {
-               stopMediaContentScan();
-               startMediaContentScan();
-       }
-
-       void Instance::stopMediaContentScan()
-       {
-               if (m_isScanInProgress) {
-                       m_isScanInProgress = false;
-                       DLOG("Scan is in progress. Terminating...");
-                       const int ret = media_content_cancel_scan_folder(
-                                       impl::MEDIA_FOLDER);
-                       if (ret != 0) {
-                               WLOG("media_content_cancel_scan_folder() failed: %d", ret);
-                       }
-               }
-       }
-
-       void Instance::startMediaContentScan()
-       {
-               DLOG("Starting media scan...");
-
-               int ret = media_content_scan_folder(impl::MEDIA_FOLDER, true,
-                               CALLBACK_B(Instance::onScanComplete), this);
-               if (ret != 0) {
-                       ELOG("media_content_scan_folder() failed: %d", ret);
-                       return;
-               }
-
-               m_isScanInProgress = true;
-       }
-
-       void Instance::onScanComplete(media_content_error_e error)
-       {
-               DLOG("Media scan complete. error: %d", error);
-
-               m_isScanInProgress = false;
-
-               const auto thumbPage = dynamicRefCast<ThumbnailPage>(m_page);
-
-               if (isNotEmpty(m_gallery->getAlbum())) {
-                       if (thumbPage) {
-                               DLOG("Reloading the ThumbnailPage...");
-                               thumbPage->reload();
-                       } else {
-                               if (m_page) {
-                                       m_page->exitNoTransition();
-                               }
-                               createThumbnailPage();
-                       }
-               } else if (thumbPage) {
-                       DLOG("Exit from ThumbnailPage witout transition...");
-                       thumbPage->exitNoTransition();
-                       createNoContentPage();
-               }
-       }
-
-       void Instance::onAppControl(app_control_h appControl)
-       {
-               DLOG("APP CONTROL");
-
-               if (!m_page) {
-                       if (isEmpty(m_gallery->getAlbum())) {
-                               createNoContentPage();
-                       } else {
-                               createThumbnailPage();
-                       }
-               }
-
-               if (!m_win->isVisible()) {
-                       DLOG("Show the window.");
-                       show(*m_win);
-               }
-       }
-
-       void Instance::createNoContentPage()
-       {
-               DLOG("Creating NoContentPage.");
-               m_page = NoContentPage::Builder().setNaviframe(m_navi).
-                               build(DELEGATE(Instance::onPageExitRequest, this));
-       }
-
-       void Instance::createThumbnailPage()
-       {
-               DLOG("Creating ThumbnailPage.");
-               m_page = ThumbnailPage::Builder().setNaviframe(m_navi).
-                               setAlbum(m_gallery->getAlbum()).
-                               build(DELEGATE(Instance::onPageExitRequest, this));
-       }
-
-       void Instance::onPageExitRequest(Page &page)
-       {
-               if (page.isAtBottom()) {
-                       DLOG("Bottom page. Lowering the window.");
-                       m_win->lower();
-               } else {
-                       DLOG("Exit page.");
-                       page.exit();
-               }
-       }
-
-       void Instance::onSysEvent(const SysEvent sysEvent)
-       {
-               switch(sysEvent) {
-               case SysEvent::LANGUAGE_CHANGED:
-                       DLOG("SysEvent::LANGUAGE_CHANGED");
-                       {
-                               char *locale = NULL;
-                               system_settings_get_value_string(
-                                               SYSTEM_SETTINGS_KEY_LOCALE_LANGUAGE, &locale);
-                               elm_language_set(locale);
-                               free(locale);
-                       }
-                       break;
-               default:
-                       DLOG("sysEvent: %d", sysEvent);
-                       break;
-               }
-       }
-}
diff --git a/src/presentation/InstanceManager.cpp b/src/presentation/InstanceManager.cpp
deleted file mode 100644 (file)
index e0b3f2f..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * 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/InstanceManager.h"
-
-#include "presentation/Instance.h"
-
-namespace gallery {
-
-       using namespace ucl;
-
-       InstanceManager::InstanceManager() :
-               InstanceManagerBase(AppParams().
-                               set(AppParam::WINDOW_NAME, WINDOW_NAME).
-                               set(AppParam::BASE_SCALE, BASE_SCALE))
-       {
-       }
-
-       IInstanceSRef InstanceManager::newInstance() const
-       {
-               return makeShared<Instance>(getSysEventProvider());
-       }
-}
diff --git a/src/presentation/NoContentPage.cpp b/src/presentation/NoContentPage.cpp
deleted file mode 100644 (file)
index ddbc272..0000000
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * 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/NoContentPage.h"
-
-#include "ucl/gui/Layout.h"
-
-#include "common.h"
-
-namespace gallery {namespace { namespace impl {
-
-       using namespace ucl;
-
-       constexpr LayoutTheme ICON_THEME
-                       {"layout", "gallery_image", "gallery_icon_no_photos.png"};
-}}}
-
-namespace gallery {
-
-       using namespace ucl;
-
-       // NoContentPage::Builder //
-
-       NoContentPage::Builder::Builder()
-       {
-       }
-
-       NoContentPage::Builder::~Builder()
-       {
-       }
-
-       NoContentPage::Builder &NoContentPage::Builder::setNaviframe(
-                       const NaviframeSRef &navi)
-       {
-               m_navi = navi;
-               return *this;
-       }
-
-       NoContentPageSRef NoContentPage::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");
-               }
-
-               auto result = makeShared<NoContentPage>(m_navi, onExitRequest);
-
-               FAIL_RETURN_VALUE(result->prepare(), {}, "result->prepare() failed!");
-
-               return result;
-       }
-
-       // NoContentPage //
-
-       NoContentPage::NoContentPage(RefCountObjBase &rc,
-                       const NaviframeSRef &navi,
-                       const ExitRequestHandler onExitRequest) :
-               Page(rc, navi, onExitRequest)
-       {
-       }
-
-       NoContentPage::~NoContentPage()
-       {
-       }
-
-       Result NoContentPage::prepare()
-       {
-               const auto layout = Layout::Builder().
-                               setIsOwner(true).
-                               setTheme(LAYOUT_NO_CONTENTS).
-                               build(getNaviframe());
-               if (!layout) {
-                       LOG_RETURN(RES_FAIL, "Layout::build() failed!");
-               }
-
-               const auto icon = Layout::Builder().
-                               setTheme(impl::ICON_THEME).
-                               build(*layout);
-               if (!layout) {
-                       LOG_RETURN(RES_FAIL, "Layout::build() failed!");
-               }
-
-               layout->setContent(*icon);
-               layout->setText(PART_TITLE, STR_APP_NAME);
-               layout->setText(STR_NO_PHOTOS);
-
-               FAIL_RETURN(Page::prepare(
-                       [this, &layout]()
-                       {
-                               return getNaviframe().push(*layout, NAVIFRAME_EMPTY);
-                       }),
-                       "Page::prepare() failed!");
-
-               layout->setIsOwner(false);
-
-               return RES_OK;
-       }
-}
diff --git a/src/presentation/Page.cpp b/src/presentation/Page.cpp
deleted file mode 100644 (file)
index 0f4bf2d..0000000
+++ /dev/null
@@ -1,202 +0,0 @@
-/*
- * 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/Page.h"
-
-#include "common.h"
-
-namespace gallery { namespace { namespace impl {
-
-       using namespace ucl;
-
-       constexpr SmartEvent TOP_PAGE_CHANGED {"ucl,top,page,changed"};
-}}}
-
-namespace gallery {
-
-       using namespace ucl;
-
-       Page::Page(RefCountObjBase &rc, const NaviframeSRef &navi,
-                       const ExitRequestHandler onExitRequest) :
-               RefCountAware(&rc),
-               m_navi(navi),
-               m_onExitRequest(onExitRequest),
-               m_isActive(false)
-       {
-               UCL_ASSERT(navi, "navi is NULL!");
-               UCL_ASSERT(onExitRequest, "onExitRequest is NULL!");
-       }
-
-       Page::~Page()
-       {
-       }
-
-       Result Page::preparePart2()
-       {
-               Evas_Object *content = m_item.getContent();
-               if (!content) {
-                       LOG_RETURN(RES_FAIL, "content is NULL");
-               }
-
-               m_navi->addEventHandler(NAVI_TRANSITION_STARTED,
-                               WEAK_DELEGATE(Page::onTransitionStarted, asWeak(*this)));
-
-               m_navi->addEventHandler(NAVI_TRANSITION_FINISHED,
-                               WEAK_DELEGATE(Page::onTransitionFinished, asWeak(*this)));
-
-               m_navi->addEventHandler(impl::TOP_PAGE_CHANGED,
-                               WEAK_DELEGATE(Page::onTopPageChanged, asWeak(*this)));
-
-               eext_object_event_callback_add(content, EEXT_CALLBACK_BACK,
-                               CALLBACK_A(Page::onHWBackKey), this);
-
-               m_item.setData(this);
-               m_item.setDelCallback(CALLBACK_A(Page::onItemDel));
-
-               m_rc->ref();
-
-               if (!m_navi->isInTransition() && isAtTop()) {
-                       dispatchTopPageChanged();
-               }
-
-               return RES_OK;
-       }
-
-       void Page::dispatchTopPageChanged()
-       {
-               m_navi->callSmartEvent(impl::TOP_PAGE_CHANGED, nullptr);
-       }
-
-       void Page::onItemDel(Evas_Object *obj, void *eventInfo)
-       {
-               m_item = nullptr;
-               m_rc->unref();
-       }
-
-       void Page::exit()
-       {
-               if (isAtTop() && !isAtBottom()) {
-                       m_navi->pop();
-                       m_item = nullptr;
-               } else {
-                       exitNoTransition();
-               }
-       }
-
-       void Page::exitNoTransition()
-       {
-               if (isAtTop()) {
-                       m_item.del();
-                       dispatchTopPageChanged();
-               } else if (isValid(m_item)) {
-                       m_item.del();
-               }
-       }
-
-       void Page::popTo()
-       {
-               if (isValid(m_item) && !isAtTop()) {
-                       m_item.popTo();
-               }
-       }
-
-       void Page::deleteTo()
-       {
-               if (isValid(m_item) && !isAtTop()) {
-                       while (!isAtTop()) {
-                               m_navi->getTopItem().del();
-                       }
-                       dispatchTopPageChanged();
-               }
-       }
-
-       void Page::promote()
-       {
-               if (isValid(m_item) && !isAtTop()) {
-                       m_item.promote();
-               }
-       }
-
-       NaviItem Page::getItem()
-       {
-               return m_item;
-       }
-
-       void Page::requestExit()
-       {
-               m_onExitRequest(*this);
-       }
-
-       void Page::activate()
-       {
-               if (!m_isActive) {
-                       m_isActive = true;
-                       onActivate();
-               }
-       }
-
-       void Page::deactivate()
-       {
-               if (m_isActive) {
-                       m_isActive = false;
-                       onDeactivate();
-               }
-       }
-
-       void Page::updateActiveState()
-       {
-               if (isAtTop()) {
-                       activate();
-               } else {
-                       deactivate();
-               }
-       }
-
-       void Page::onTransitionStarted(Widget &widget, void *eventInfo)
-       {
-               deactivate();
-       }
-
-       void Page::onTransitionFinished(Widget &widget, void *eventInfo)
-       {
-               updateActiveState();
-       }
-
-       void Page::onTopPageChanged(Widget &widget, void *eventInfo)
-       {
-               updateActiveState();
-       }
-
-       void Page::onHWBackKey(Evas_Object *obj, void *eventInfo)
-       {
-               if (m_isActive) {
-                       onBackKey();
-               }
-       }
-
-       void Page::onActivate()
-       {
-       }
-
-       void Page::onDeactivate()
-       {
-       }
-
-       void Page::onBackKey()
-       {
-               requestExit();
-       }
-}
diff --git a/src/presentation/PreviewPage.cpp b/src/presentation/PreviewPage.cpp
deleted file mode 100644 (file)
index 1020226..0000000
+++ /dev/null
@@ -1,261 +0,0 @@
-/*
- * 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/PreviewPage.h"
-
-#include "model/IMediaAlbum.h"
-#include "model/MediaItem.h"
-
-#include "presentation/ImageGrid.h"
-#include "presentation/ViewerPage.h"
-
-#include "common.h"
-
-namespace gallery {
-
-       using namespace ucl;
-
-       // PreviewPage::Builder //
-
-       PreviewPage::Builder::Builder() :
-               m_startItemIndex(0)
-       {
-       }
-
-       PreviewPage::Builder::~Builder()
-       {
-       }
-
-       PreviewPage::Builder &PreviewPage::Builder::setNaviframe(
-                       const NaviframeSRef &navi)
-       {
-               m_navi = navi;
-               return *this;
-       }
-
-       PreviewPage::Builder &PreviewPage::Builder::setAlbum(
-                       const IMediaAlbumSRef &album)
-       {
-               m_album = album;
-               return *this;
-       }
-
-       PreviewPage::Builder &PreviewPage::Builder::setStartItemIndex(
-                       const int index)
-       {
-               m_startItemIndex = index;
-               return *this;
-       }
-
-       PreviewPageSRef PreviewPage::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_album) {
-                       LOG_RETURN_VALUE(RES_INVALID_ARGUMENTS, {}, "m_album is NULL");
-               }
-
-               auto result = makeShared<PreviewPage>(
-                               m_navi, onExitRequest, m_album);
-
-               FAIL_RETURN_VALUE(result->prepare(), {}, "result->prepare() failed!");
-
-               if (m_startItemIndex > 0) {
-                       result->showItem(m_startItemIndex);
-               }
-
-               return result;
-       }
-
-       // PreviewPage::Item //
-
-       class PreviewPage::Item : public NonCopyable {
-       public:
-               Item(MediaItemSRef &&media, ImageGrid &imageGrid, const int itemIndex) :
-                       m_media(std::move(media)),
-                       m_imageGrid(imageGrid),
-                       m_index(itemIndex)
-               {
-               }
-
-               void realize()
-               {
-                       FAIL_LOG(m_media->getThumbnailPath(
-                                       DELEGATE(Item::onThumbnail, this)),
-                                       "getThumbnailPath() failed!");
-               }
-
-               void unrealize()
-               {
-                       m_media->cancelThumbnailPathGet();
-               }
-
-               MediaItemSRef getMedia()
-               {
-                       return m_media;
-               }
-
-       private:
-               void onThumbnail(const Result result, const std::string &path)
-               {
-                       FAIL_LOG(result, "Failed to get thumbnail!");
-
-                       ImageGrid::ItemParams params = {};
-                       m_media->getResolution(params.aspectX, params.aspectY);
-                       params.imagePath = m_media->getFilePath();
-                       params.bgImagePath = path;
-                       params.flags = ImageGrid::UF_BLOCK_CLICKS;
-
-                       m_imageGrid.updateItem(m_index, params);
-               }
-
-       private:
-               const MediaItemSRef m_media;
-               ImageGrid &m_imageGrid;
-               const int m_index;
-       };
-
-       // PreviewPage //
-
-       PreviewPage::PreviewPage(RefCountObjBase &rc,
-                       const NaviframeSRef &navi,
-                       const ExitRequestHandler onExitRequest,
-                       const IMediaAlbumSRef &album) :
-               Page(rc, navi, onExitRequest),
-               m_album(album)
-       {
-       }
-
-       PreviewPage::~PreviewPage()
-       {
-               if (m_page) {
-                       m_page->exitNoTransition();
-               }
-               m_imageGrid->setListener(nullptr);
-       }
-
-       void PreviewPage::reload()
-       {
-               ImageGrid::Unrealizer u(*m_imageGrid);
-
-               m_items.clear();
-
-               FAIL_LOG(m_album->forEachMedia(
-                               DELEGATE(PreviewPage::onEachMedia, this)),
-                               "m_album->forEachMedia() failed!");
-
-               m_imageGrid->setItemCount(m_items.size());
-
-               const auto viewerPage = dynamicRefCast<ViewerPage>(m_page);
-               if (viewerPage) {
-                       const auto mediaId = viewerPage->getMediaId();
-                       const auto it = std::find_if(m_items.begin(), m_items.end(),
-                               [&mediaId](const ItemUPtr &item)
-                               {
-                                       return (item->getMedia()->getId() == mediaId);
-                               });
-                       if (it == m_items.end()) {
-                               DLOG("Viewed media item was removed.");
-                               deleteTo();
-                       } else {
-                               m_imageGrid->scrollToItem(it - m_items.begin());
-                       }
-               }
-       }
-
-       Result PreviewPage::prepare()
-       {
-               m_imageGrid = ImageGrid::Builder().
-                               setListener(this).
-                               setType(ImageGrid::Type::LINEAR).
-                               build(getNaviframe());
-               if (!m_imageGrid) {
-                       LOG_RETURN(RES_FAIL, "ImageGrid::build() failed!");
-               }
-
-               FAIL_RETURN(m_album->forEachMedia(
-                               DELEGATE(PreviewPage::onEachMedia, this)),
-                               "m_album->forEachMedia() failed!");
-
-               FAIL_RETURN(Page::prepare(
-                       [this]()
-                       {
-                               return getNaviframe().push(*m_imageGrid, NAVIFRAME_EMPTY);
-                       }),
-                       "Page::prepare() failed!");
-
-               m_imageGrid->setItemCount(m_items.size());
-
-               return RES_OK;
-       }
-
-       void PreviewPage::showItem(const int itemIndex)
-       {
-               m_imageGrid->scrollToItem(itemIndex);
-       }
-
-       bool PreviewPage::onEachMedia(MediaItemSRef &&media)
-       {
-               m_items.emplace_back(
-                               new Item(std::move(media), *m_imageGrid, m_items.size()));
-               return true;
-       }
-
-       void PreviewPage::onActivate()
-       {
-               m_imageGrid->activateRotary();
-       }
-
-       void PreviewPage::onDeactivate()
-       {
-               m_imageGrid->deactivateRotary();
-       }
-
-       void PreviewPage::onItemRealized(const int itemIndex)
-       {
-               m_items[itemIndex]->realize();
-       }
-
-       void PreviewPage::onItemUnrealized(const int itemIndex)
-       {
-               m_items[itemIndex]->unrealize();
-       }
-
-       void PreviewPage::onItemEvent(const int itemIndex,
-                       const int event, const int x, const int y)
-       {
-               if (!isActive() || (event != ImageGrid::ITEM_EVENT_DOUBLE_TAP)) {
-                       return;
-               }
-
-               m_page = ViewerPage::Builder().
-                               setNaviframe(asShared(getNaviframe())).
-                               setZoomIn(x, y).
-                               setMedia(m_items[itemIndex]->getMedia()).
-                               build(DELEGATE(PreviewPage::onPageExitRequest, this));
-       }
-
-       void PreviewPage::onPageExitRequest(Page &page)
-       {
-               deleteTo();
-       }
-}
diff --git a/src/presentation/ThumbnailPage.cpp b/src/presentation/ThumbnailPage.cpp
deleted file mode 100644 (file)
index 2628d98..0000000
+++ /dev/null
@@ -1,232 +0,0 @@
-/*
- * 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/ThumbnailPage.h"
-
-#include "model/IMediaAlbum.h"
-#include "model/MediaItem.h"
-
-#include "presentation/ImageGrid.h"
-#include "presentation/PreviewPage.h"
-
-#include "common.h"
-
-namespace gallery {
-
-       using namespace ucl;
-
-       // ThumbnailPage::Builder //
-
-       ThumbnailPage::Builder::Builder()
-       {
-       }
-
-       ThumbnailPage::Builder::~Builder()
-       {
-       }
-
-       ThumbnailPage::Builder &ThumbnailPage::Builder::setNaviframe(
-                       const NaviframeSRef &navi)
-       {
-               m_navi = navi;
-               return *this;
-       }
-
-       ThumbnailPage::Builder &ThumbnailPage::Builder::setAlbum(
-                       const IMediaAlbumSRef &album)
-       {
-               m_album = album;
-               return *this;
-       }
-
-       ThumbnailPageSRef ThumbnailPage::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_album) {
-                       LOG_RETURN_VALUE(RES_INVALID_ARGUMENTS, {}, "m_album is NULL");
-               }
-
-               auto result = makeShared<ThumbnailPage>(
-                               m_navi, onExitRequest, m_album);
-
-               FAIL_RETURN_VALUE(result->prepare(), {}, "result->prepare() failed!");
-
-               return result;
-       }
-
-       // ThumbnailPage::RealizedItem //
-
-       class ThumbnailPage::RealizedItem : public NonCopyable {
-       public:
-               RealizedItem(ThumbnailPage &parent, const int index) :
-                       m_parent(parent),
-                       m_index(index)
-               {
-                       FAIL_LOG(m_parent.m_mediaItems[m_index]->getThumbnailPath(
-                                       DELEGATE(RealizedItem::onThumbnail, this)),
-                                       "getThumbnailPath() failed!");
-               }
-
-               ~RealizedItem()
-               {
-                       m_parent.m_mediaItems[m_index]->cancelThumbnailPathGet();
-               }
-
-               int getIndex() const
-               {
-                       return m_index;
-               }
-
-       private:
-               void onThumbnail(const Result result, const std::string &path)
-               {
-                       FAIL_RETURN_VOID(result, "Failed to get thumbnail!");
-
-                       ImageGrid::ItemParams params = {};
-                       params.imagePath = path;
-
-                       m_parent.m_imageGrid->updateItem(m_index, params);
-               }
-
-       private:
-               ThumbnailPage &m_parent;
-               int m_index;
-       };
-
-       // ThumbnailPage //
-
-       ThumbnailPage::ThumbnailPage(RefCountObjBase &rc,
-                       const NaviframeSRef &navi,
-                       const ExitRequestHandler onExitRequest,
-                       const IMediaAlbumSRef &album) :
-               Page(rc, navi, onExitRequest),
-               m_album(album)
-       {
-       }
-
-       ThumbnailPage::~ThumbnailPage()
-       {
-               if (m_page) {
-                       m_page->exitNoTransition();
-               }
-               m_imageGrid->setListener(nullptr);
-       }
-
-       void ThumbnailPage::reload()
-       {
-               ImageGrid::Unrealizer u(*m_imageGrid);
-
-               m_mediaItems.clear();
-
-               FAIL_LOG(m_album->forEachMedia(
-                               DELEGATE(ThumbnailPage::onEachMedia, this)),
-                               "m_album->forEachMedia() failed!");
-
-               m_imageGrid->setItemCount(m_mediaItems.size());
-
-               if (const auto vp = dynamic_cast<PreviewPage *>(m_page.get())) {
-                       vp->reload();
-               }
-       }
-
-       Result ThumbnailPage::prepare()
-       {
-               FAIL_RETURN(m_album->forEachMedia(
-                               DELEGATE(ThumbnailPage::onEachMedia, this)),
-                               "m_album->forEachMedia() failed!");
-
-               m_imageGrid = ImageGrid::Builder().
-                               setListener(this).
-                               setType(ImageGrid::Type::HCOMB_3X3).
-                               build(getNaviframe());
-               if (!m_imageGrid) {
-                       LOG_RETURN(RES_FAIL, "ImageGrid::build() failed!");
-               }
-
-               FAIL_RETURN(Page::prepare(
-                       [this]()
-                       {
-                               return getNaviframe().push(*m_imageGrid, NAVIFRAME_EMPTY);
-                       }),
-                       "Page::prepare() failed!");
-
-               m_imageGrid->setItemCount(m_mediaItems.size());
-
-               return RES_OK;
-       }
-
-       bool ThumbnailPage::onEachMedia(MediaItemSRef &&media)
-       {
-               m_mediaItems.emplace_back(std::move(media));
-               return true;
-       }
-
-       void ThumbnailPage::onActivate()
-       {
-               m_imageGrid->activateRotary();
-       }
-
-       void ThumbnailPage::onDeactivate()
-       {
-               m_imageGrid->deactivateRotary();
-       }
-
-       void ThumbnailPage::onItemRealized(const int itemIndex)
-       {
-               m_realizedItems.emplace_back(new RealizedItem(*this, itemIndex));
-       }
-
-       void ThumbnailPage::onItemUnrealized(const int itemIndex)
-       {
-               const auto it = std::find_if(
-                               m_realizedItems.begin(), m_realizedItems.end(),
-                               [itemIndex](const RealizedItemUPtr &item)
-                               {
-                                       return (item->getIndex() == itemIndex);
-                               });
-               if (it != m_realizedItems.end()) {
-                       m_realizedItems.erase(it);
-               } else {
-                       WLOG("Item is not found in realized list!");
-               }
-       }
-
-       void ThumbnailPage::onItemEvent(const int itemIndex,
-                       const int event, const int x, const int y)
-       {
-               if (!isActive() || (event != ImageGrid::ITEM_EVENT_CLICK)) {
-                       return;
-               }
-
-               m_page = PreviewPage::Builder().
-                               setNaviframe(asShared(getNaviframe())).
-                               setAlbum(m_album).
-                               setStartItemIndex(itemIndex).
-                               build(DELEGATE(ThumbnailPage::onPageExitRequest, this));
-       }
-
-       void ThumbnailPage::onPageExitRequest(Page &page)
-       {
-               popTo();
-       }
-}
diff --git a/src/presentation/TouchParser.cpp b/src/presentation/TouchParser.cpp
deleted file mode 100644 (file)
index a556fd5..0000000
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * 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/TouchParser.h"
-
-#include "common.h"
-
-namespace gallery { namespace { namespace impl {
-
-       constexpr auto TAP_MOVE_THRESHOLD = 30;
-       constexpr auto FAST_TAP_DISTANCE = 60;
-       constexpr auto FAST_TAP_DELAY_MS = 300;
-}}}
-
-namespace gallery {
-
-       using namespace ucl;
-
-       TouchParser::TouchParser(RefCountObjBase &rc, Widget &eventSource) :
-               RefCountAware(&rc),
-               m_downTime(0),
-               m_downX(0),
-               m_downY(0),
-               m_tapCounter(0),
-               m_isMouseDown(false),
-               m_isTapPossible(false)
-       {
-               eventSource.addEventHandler(WidgetEvent::MOUSE_DOWN,
-                               WEAK_DELEGATE(TouchParser::onMouseDown, asWeak(*this)));
-
-               eventSource.addEventHandler(WidgetEvent::MOUSE_UP,
-                               WEAK_DELEGATE(TouchParser::onMouseUp, asWeak(*this)));
-
-               eventSource.addEventHandler(WidgetEvent::MOUSE_MOVE,
-                               WEAK_DELEGATE(TouchParser::onMouseMove, asWeak(*this)));
-       }
-
-       TouchParser::~TouchParser()
-       {
-       }
-
-       void TouchParser::setTapHandler(TapHandler handler)
-       {
-               m_tapHandler = handler;
-       }
-
-       void TouchParser::setDoubleTapHandler(TapHandler handler)
-       {
-               m_doubleTapHandler = handler;
-       }
-
-       void TouchParser::onMouseDown(Widget &widget, void *eventInfo)
-       {
-               if (m_isMouseDown) {
-                       return;
-               }
-               m_isMouseDown = true;
-
-               const auto e = static_cast<Evas_Event_Mouse_Down *>(eventInfo);
-
-               if (!isFastTap(e->timestamp, e->canvas.x, e->canvas.y)) {
-                       m_tapCounter = 0;
-               } else if (m_doubleTapHandler && (m_tapCounter == 1)) {
-                       m_doubleTapHandler(m_downX, m_downY);
-               }
-
-               m_downTime = e->timestamp;
-               m_downX = e->canvas.x;
-               m_downY = e->canvas.y;
-               m_isTapPossible = true;
-       }
-
-       void TouchParser::onMouseUp(Widget &widget, void *eventInfo)
-       {
-               if (!m_isMouseDown) {
-                       return;
-               }
-               m_isMouseDown = false;
-
-               const auto e = static_cast<Evas_Event_Mouse_Up *>(eventInfo);
-
-               updateIsTapPossible(e->event_flags, e->canvas.x, e->canvas.y);
-
-               if (!m_isTapPossible) {
-                       m_tapCounter = 0;
-                       return;
-               }
-
-               ++m_tapCounter;
-
-               if (m_tapHandler) {
-                       m_tapHandler(e->canvas.x, e->canvas.y);
-               }
-       }
-
-       void TouchParser::onMouseMove(Widget &widget, void *eventInfo)
-       {
-               if (!m_isMouseDown || !m_isTapPossible) {
-                       return;
-               }
-
-               const auto e = static_cast<Evas_Event_Mouse_Move *>(eventInfo);
-
-               updateIsTapPossible(e->event_flags, e->cur.canvas.x, e->cur.canvas.y);
-       }
-
-       void TouchParser::updateIsTapPossible(const int flags,
-                       const int curX, const int curY)
-       {
-               if (!m_isTapPossible) {
-                       return;
-               }
-               if ((flags & EVAS_EVENT_FLAG_ON_HOLD) || (calcDownDistance(curX, curY) >
-                               ELM_SCALE_SIZE(impl::TAP_MOVE_THRESHOLD))) {
-                       m_isTapPossible = false;
-               }
-       }
-
-       bool TouchParser::isFastTap(const UInt curTime,
-                       const int curX, const int curY) const
-       {
-               return (((curTime - m_downTime) <= impl::FAST_TAP_DELAY_MS) &&
-                               (calcDownDistance(curX, curY) <=
-                                               ELM_SCALE_SIZE(impl::FAST_TAP_DISTANCE)));
-       }
-
-       double TouchParser::calcDownDistance(int curX, int curY) const
-       {
-               const auto dx = (curX - m_downX);
-               const auto dy = (curY - m_downY);
-
-               return sqrt(1.0 * dx * dx + 1.0 * dy * dy);
-       }
-}
diff --git a/src/presentation/ViewerPage.cpp b/src/presentation/ViewerPage.cpp
deleted file mode 100644 (file)
index 60ad7c2..0000000
+++ /dev/null
@@ -1,199 +0,0 @@
-/*
- * 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 "presentation/TouchParser.h"
-
-#include "common.h"
-
-namespace gallery {
-
-       using namespace ucl;
-
-       // ViewerPage::Builder //
-
-       ViewerPage::Builder::Builder() :
-               m_zoomInX(-1),
-               m_zoomInY(-1),
-               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::setZoomIn(
-                       const int x, const int y)
-       {
-               m_zoomInX = x;
-               m_zoomInY = y;
-               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!");
-
-               if ((m_zoomInX >= 0) && (m_zoomInY >= 0)) {
-                       result->zoomIn(m_zoomInX, m_zoomInY);
-               }
-
-               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()
-       {
-       }
-
-       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!");
-
-               m_touchParser = makeShared<TouchParser>(*m_imageViewer);
-               m_touchParser->setDoubleTapHandler(
-                               DELEGATE(ViewerPage::onDoubleTap, this));
-
-               return RES_OK;
-       }
-
-       void ViewerPage::zoomIn(const int originX, const int originY)
-       {
-               m_imageViewer->zoomIn(originX, originY);
-       }
-
-       const std::string &ViewerPage::getMediaId() const
-       {
-               return m_media->getId();
-       }
-
-       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::onDoubleTap(int x, int y)
-       {
-               if (!isActive()) {
-                       return;
-               }
-               if (m_imageViewer->isZoomedOut()) {
-                       m_imageViewer->zoomIn(x, y);
-               } else if (m_imageViewer->isZoomedIn()) {
-                       m_imageViewer->zoomOut();
-               }
-       }
-
-       void ViewerPage::onBackKey()
-       {
-               if (m_imageViewer->isZoomedOut()) {
-                       requestExit();
-               } else if (m_imageViewer->isZoomedIn()) {
-                       m_imageViewer->zoomOut();
-               }
-       }
-}
diff --git a/src/presentation/common.h b/src/presentation/common.h
deleted file mode 100644 (file)
index 87f2d9c..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * 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_COMMON_H__
-#define __GALLERY_PRESENTATION_COMMON_H__
-
-#include "helpers.h"
-
-#include "../common.h"
-
-namespace gallery {
-
-       constexpr ucl::ElmStyle SCROLLER_STYLE {"effect"};
-}
-
-#endif // __GALLERY_PRESENTATION_COMMON_H__
diff --git a/src/presentation/helpers.cpp b/src/presentation/helpers.cpp
deleted file mode 100644 (file)
index 3bf55ce..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * 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 "helpers.h"
-
-#include "ucl/gui/Window.h"
-#include "ucl/gui/Naviframe.h"
-
-#include "common.h"
-
-namespace gallery { namespace { namespace impl {
-
-       using namespace ucl;
-
-       constexpr EoDataKey CIRCLE_SURFACE {"gallery,eext,circle,surface"};
-}}}
-
-namespace gallery {
-
-       using namespace ucl;
-
-       Result createCircleSurface(Naviframe &navi)
-       {
-               const auto win = navi.getWindow();
-               if (!win) {
-                       LOG_RETURN(RES_FAIL, "Failed to get Window from Naviframe!");
-               }
-
-               if (win->getData(impl::CIRCLE_SURFACE)) {
-                       LOG_RETURN(RES_ILLEGAL_STATE, "Circle Surface data already set!");
-               }
-
-               const auto sfc = eext_circle_surface_naviframe_add(navi);
-               if (!sfc) {
-                       LOG_RETURN(RES_FAIL,
-                                       "eext_circle_surface_conformant_add() failed!");
-               }
-
-               win->setData(impl::CIRCLE_SURFACE, sfc);
-
-               return RES_OK;
-       }
-
-       Eext_Circle_Surface *getCircleSurface(const ElmWidget &widget)
-       {
-               const auto win = widget.getWindow();
-               if (!win) {
-                       LOG_RETURN_VALUE(RES_FAIL, nullptr,
-                                       "Failed to get Window from widget!");
-               }
-
-               const auto sfc = static_cast<Eext_Circle_Surface *>(
-                               win->getData(impl::CIRCLE_SURFACE));
-               if (!sfc) {
-                       LOG_RETURN_VALUE(RES_FAIL, nullptr,
-                                       "Failed to get Eext_Circle_Surface from window!");
-               }
-
-               return sfc;
-       }
-}
-
diff --git a/src/presentation/helpers.h b/src/presentation/helpers.h
deleted file mode 100644 (file)
index fa3d195..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * 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_HELPERS_H__
-#define __GALLERY_PRESENTATION_HELPERS_H__
-
-#include "presentation/types.h"
-
-namespace ucl {
-
-       class ElmWidget;
-       class Naviframe;
-}
-
-namespace gallery {
-
-       ucl::Result createCircleSurface(ucl::Naviframe &navi);
-
-       Eext_Circle_Surface *getCircleSurface(const ucl::ElmWidget &widget);
-}
-
-#endif // __GALLERY_PRESENTATION_HELPERS_H__
diff --git a/src/presenters/Instance.cpp b/src/presenters/Instance.cpp
new file mode 100644 (file)
index 0000000..803af63
--- /dev/null
@@ -0,0 +1,234 @@
+/*
+ * 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 "presenters/Instance.h"
+
+#include <system_settings.h>
+
+#include "ucl/appfw/SysEventProvider.h"
+#include "ucl/appfw/helpers.h"
+
+#include "model/Gallery.h"
+#include "model/IMediaAlbum.h"
+
+#include "presenters/NoContentPage.h"
+#include "presenters/ThumbnailPage.h"
+
+#include "resources.h"
+#include "common.h"
+
+namespace gallery { namespace { namespace impl {
+
+       // TODO Since feature is temporary using hard-coded path
+       constexpr auto MEDIA_FOLDER = "/opt/usr/home/owner/media";
+}}}
+
+namespace gallery {
+
+       using namespace ucl;
+
+       Instance::Instance(SysEventProvider &sysEventProvider) :
+               m_sysEventProvider(sysEventProvider),
+               m_isScanInProgress(false)
+       {
+       }
+
+       Instance::~Instance()
+       {
+               stopMediaContentScan();
+       }
+
+       Result Instance::onCreate(IInstanceContext *const context)
+       {
+               m_context = context;
+
+               m_gallery = Gallery::newInstance();
+               if (!m_gallery) {
+                       LOG_RETURN(RES_FAIL, "Gallery::newInstance() failed!");
+               }
+
+               m_win = m_context->getWindow();
+
+               FAIL_RETURN(setupTheme(), "setupTheme() failed!");
+
+               m_navi = Naviframe::Builder().
+                               build(m_win->getConformant());
+               if (!m_navi) {
+                       LOG_RETURN(RES_FAIL, "Naviframe::build() failed!");
+               }
+
+               m_win->getConformant().setContent(*m_navi);
+
+               FAIL_RETURN(createCircleSurface(*m_navi),
+                               "createCircleSurface() failed!");
+
+               m_sysEventProvider.addEventHandler(
+                               DELEGATE(Instance::onSysEvent, this));
+
+               return RES_OK;
+       }
+
+       Result Instance::setupTheme()
+       {
+               m_theme = Theme::create();
+               if (isNotValid(m_theme)) {
+                       LOG_RETURN(RES_FAIL, "Theme::create() failed!");
+               }
+
+               m_theme.addExtension(getResPath(THEME_EDJE_PATH));
+
+               m_win->setTheme(m_theme);
+
+               return RES_OK;
+       }
+
+       void Instance::onPause()
+       {
+               DLOG("PAUSE");
+       }
+
+       void Instance::onResume()
+       {
+               DLOG("RESUME");
+
+               if (SCAN_MEDIA_ON_RESUME) {
+                       rescanMediaContent();
+               }
+
+               ecore_animator_frametime_set(1.0 / 60.0);
+       }
+
+       void Instance::rescanMediaContent()
+       {
+               stopMediaContentScan();
+               startMediaContentScan();
+       }
+
+       void Instance::stopMediaContentScan()
+       {
+               if (m_isScanInProgress) {
+                       m_isScanInProgress = false;
+                       DLOG("Scan is in progress. Terminating...");
+                       const int ret = media_content_cancel_scan_folder(
+                                       impl::MEDIA_FOLDER);
+                       if (ret != 0) {
+                               WLOG("media_content_cancel_scan_folder() failed: %d", ret);
+                       }
+               }
+       }
+
+       void Instance::startMediaContentScan()
+       {
+               DLOG("Starting media scan...");
+
+               int ret = media_content_scan_folder(impl::MEDIA_FOLDER, true,
+                               CALLBACK_B(Instance::onScanComplete), this);
+               if (ret != 0) {
+                       ELOG("media_content_scan_folder() failed: %d", ret);
+                       return;
+               }
+
+               m_isScanInProgress = true;
+       }
+
+       void Instance::onScanComplete(media_content_error_e error)
+       {
+               DLOG("Media scan complete. error: %d", error);
+
+               m_isScanInProgress = false;
+
+               const auto thumbPage = dynamicRefCast<ThumbnailPage>(m_page);
+
+               if (isNotEmpty(m_gallery->getAlbum())) {
+                       if (thumbPage) {
+                               DLOG("Reloading the ThumbnailPage...");
+                               thumbPage->reload();
+                       } else {
+                               if (m_page) {
+                                       m_page->exitNoTransition();
+                               }
+                               createThumbnailPage();
+                       }
+               } else if (thumbPage) {
+                       DLOG("Exit from ThumbnailPage witout transition...");
+                       thumbPage->exitNoTransition();
+                       createNoContentPage();
+               }
+       }
+
+       void Instance::onAppControl(app_control_h appControl)
+       {
+               DLOG("APP CONTROL");
+
+               if (!m_page) {
+                       if (isEmpty(m_gallery->getAlbum())) {
+                               createNoContentPage();
+                       } else {
+                               createThumbnailPage();
+                       }
+               }
+
+               if (!m_win->isVisible()) {
+                       DLOG("Show the window.");
+                       show(*m_win);
+               }
+       }
+
+       void Instance::createNoContentPage()
+       {
+               DLOG("Creating NoContentPage.");
+               m_page = NoContentPage::Builder().setNaviframe(m_navi).
+                               build(DELEGATE(Instance::onPageExitRequest, this));
+       }
+
+       void Instance::createThumbnailPage()
+       {
+               DLOG("Creating ThumbnailPage.");
+               m_page = ThumbnailPage::Builder().setNaviframe(m_navi).
+                               setAlbum(m_gallery->getAlbum()).
+                               build(DELEGATE(Instance::onPageExitRequest, this));
+       }
+
+       void Instance::onPageExitRequest(Page &page)
+       {
+               if (page.isAtBottom()) {
+                       DLOG("Bottom page. Lowering the window.");
+                       m_win->lower();
+               } else {
+                       DLOG("Exit page.");
+                       page.exit();
+               }
+       }
+
+       void Instance::onSysEvent(const SysEvent sysEvent)
+       {
+               switch(sysEvent) {
+               case SysEvent::LANGUAGE_CHANGED:
+                       DLOG("SysEvent::LANGUAGE_CHANGED");
+                       {
+                               char *locale = NULL;
+                               system_settings_get_value_string(
+                                               SYSTEM_SETTINGS_KEY_LOCALE_LANGUAGE, &locale);
+                               elm_language_set(locale);
+                               free(locale);
+                       }
+                       break;
+               default:
+                       DLOG("sysEvent: %d", sysEvent);
+                       break;
+               }
+       }
+}
diff --git a/src/presenters/InstanceManager.cpp b/src/presenters/InstanceManager.cpp
new file mode 100644 (file)
index 0000000..6aabaef
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * 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 "presenters/InstanceManager.h"
+
+#include "presenters/Instance.h"
+
+namespace gallery {
+
+       using namespace ucl;
+
+       InstanceManager::InstanceManager() :
+               InstanceManagerBase(AppParams().
+                               set(AppParam::WINDOW_NAME, WINDOW_NAME).
+                               set(AppParam::BASE_SCALE, BASE_SCALE))
+       {
+       }
+
+       IInstanceSRef InstanceManager::newInstance() const
+       {
+               return makeShared<Instance>(getSysEventProvider());
+       }
+}
diff --git a/src/presenters/NoContentPage.cpp b/src/presenters/NoContentPage.cpp
new file mode 100644 (file)
index 0000000..7cb2793
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * 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 "presenters/NoContentPage.h"
+
+#include "ucl/gui/Layout.h"
+
+#include "resources.h"
+#include "common.h"
+
+namespace gallery {namespace { namespace impl {
+
+       using namespace ucl;
+
+       constexpr LayoutTheme ICON_THEME
+                       {"layout", "gallery_image", "gallery_icon_no_photos.png"};
+}}}
+
+namespace gallery {
+
+       using namespace ucl;
+
+       // NoContentPage::Builder //
+
+       NoContentPage::Builder::Builder()
+       {
+       }
+
+       NoContentPage::Builder::~Builder()
+       {
+       }
+
+       NoContentPage::Builder &NoContentPage::Builder::setNaviframe(
+                       const NaviframeSRef &navi)
+       {
+               m_navi = navi;
+               return *this;
+       }
+
+       NoContentPageSRef NoContentPage::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");
+               }
+
+               auto result = makeShared<NoContentPage>(m_navi, onExitRequest);
+
+               FAIL_RETURN_VALUE(result->prepare(), {}, "result->prepare() failed!");
+
+               return result;
+       }
+
+       // NoContentPage //
+
+       NoContentPage::NoContentPage(RefCountObjBase &rc,
+                       const NaviframeSRef &navi,
+                       const ExitRequestHandler onExitRequest) :
+               Page(rc, navi, onExitRequest)
+       {
+       }
+
+       NoContentPage::~NoContentPage()
+       {
+       }
+
+       Result NoContentPage::prepare()
+       {
+               const auto layout = Layout::Builder().
+                               setIsOwner(true).
+                               setTheme(LAYOUT_NO_CONTENTS).
+                               build(getNaviframe());
+               if (!layout) {
+                       LOG_RETURN(RES_FAIL, "Layout::build() failed!");
+               }
+
+               const auto icon = Layout::Builder().
+                               setTheme(impl::ICON_THEME).
+                               build(*layout);
+               if (!layout) {
+                       LOG_RETURN(RES_FAIL, "Layout::build() failed!");
+               }
+
+               layout->setContent(*icon);
+               layout->setText(PART_TITLE, STR_APP_NAME);
+               layout->setText(STR_NO_PHOTOS);
+
+               FAIL_RETURN(Page::prepare(
+                       [this, &layout]()
+                       {
+                               return getNaviframe().push(*layout, NAVIFRAME_EMPTY);
+                       }),
+                       "Page::prepare() failed!");
+
+               layout->setIsOwner(false);
+
+               return RES_OK;
+       }
+}
diff --git a/src/presenters/Page.cpp b/src/presenters/Page.cpp
new file mode 100644 (file)
index 0000000..7479a18
--- /dev/null
@@ -0,0 +1,202 @@
+/*
+ * 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 "presenters/Page.h"
+
+#include "common.h"
+
+namespace gallery { namespace { namespace impl {
+
+       using namespace ucl;
+
+       constexpr SmartEvent TOP_PAGE_CHANGED {"ucl,top,page,changed"};
+}}}
+
+namespace gallery {
+
+       using namespace ucl;
+
+       Page::Page(RefCountObjBase &rc, const NaviframeSRef &navi,
+                       const ExitRequestHandler onExitRequest) :
+               RefCountAware(&rc),
+               m_navi(navi),
+               m_onExitRequest(onExitRequest),
+               m_isActive(false)
+       {
+               UCL_ASSERT(navi, "navi is NULL!");
+               UCL_ASSERT(onExitRequest, "onExitRequest is NULL!");
+       }
+
+       Page::~Page()
+       {
+       }
+
+       Result Page::preparePart2()
+       {
+               Evas_Object *content = m_item.getContent();
+               if (!content) {
+                       LOG_RETURN(RES_FAIL, "content is NULL");
+               }
+
+               m_navi->addEventHandler(NAVI_TRANSITION_STARTED,
+                               WEAK_DELEGATE(Page::onTransitionStarted, asWeak(*this)));
+
+               m_navi->addEventHandler(NAVI_TRANSITION_FINISHED,
+                               WEAK_DELEGATE(Page::onTransitionFinished, asWeak(*this)));
+
+               m_navi->addEventHandler(impl::TOP_PAGE_CHANGED,
+                               WEAK_DELEGATE(Page::onTopPageChanged, asWeak(*this)));
+
+               eext_object_event_callback_add(content, EEXT_CALLBACK_BACK,
+                               CALLBACK_A(Page::onHWBackKey), this);
+
+               m_item.setData(this);
+               m_item.setDelCallback(CALLBACK_A(Page::onItemDel));
+
+               m_rc->ref();
+
+               if (!m_navi->isInTransition() && isAtTop()) {
+                       dispatchTopPageChanged();
+               }
+
+               return RES_OK;
+       }
+
+       void Page::dispatchTopPageChanged()
+       {
+               m_navi->callSmartEvent(impl::TOP_PAGE_CHANGED, nullptr);
+       }
+
+       void Page::onItemDel(Evas_Object *obj, void *eventInfo)
+       {
+               m_item = nullptr;
+               m_rc->unref();
+       }
+
+       void Page::exit()
+       {
+               if (isAtTop() && !isAtBottom()) {
+                       m_navi->pop();
+                       m_item = nullptr;
+               } else {
+                       exitNoTransition();
+               }
+       }
+
+       void Page::exitNoTransition()
+       {
+               if (isAtTop()) {
+                       m_item.del();
+                       dispatchTopPageChanged();
+               } else if (isValid(m_item)) {
+                       m_item.del();
+               }
+       }
+
+       void Page::popTo()
+       {
+               if (isValid(m_item) && !isAtTop()) {
+                       m_item.popTo();
+               }
+       }
+
+       void Page::deleteTo()
+       {
+               if (isValid(m_item) && !isAtTop()) {
+                       while (!isAtTop()) {
+                               m_navi->getTopItem().del();
+                       }
+                       dispatchTopPageChanged();
+               }
+       }
+
+       void Page::promote()
+       {
+               if (isValid(m_item) && !isAtTop()) {
+                       m_item.promote();
+               }
+       }
+
+       NaviItem Page::getItem()
+       {
+               return m_item;
+       }
+
+       void Page::requestExit()
+       {
+               m_onExitRequest(*this);
+       }
+
+       void Page::activate()
+       {
+               if (!m_isActive) {
+                       m_isActive = true;
+                       onActivate();
+               }
+       }
+
+       void Page::deactivate()
+       {
+               if (m_isActive) {
+                       m_isActive = false;
+                       onDeactivate();
+               }
+       }
+
+       void Page::updateActiveState()
+       {
+               if (isAtTop()) {
+                       activate();
+               } else {
+                       deactivate();
+               }
+       }
+
+       void Page::onTransitionStarted(Widget &widget, void *eventInfo)
+       {
+               deactivate();
+       }
+
+       void Page::onTransitionFinished(Widget &widget, void *eventInfo)
+       {
+               updateActiveState();
+       }
+
+       void Page::onTopPageChanged(Widget &widget, void *eventInfo)
+       {
+               updateActiveState();
+       }
+
+       void Page::onHWBackKey(Evas_Object *obj, void *eventInfo)
+       {
+               if (m_isActive) {
+                       onBackKey();
+               }
+       }
+
+       void Page::onActivate()
+       {
+       }
+
+       void Page::onDeactivate()
+       {
+       }
+
+       void Page::onBackKey()
+       {
+               requestExit();
+       }
+}
diff --git a/src/presenters/PreviewPage.cpp b/src/presenters/PreviewPage.cpp
new file mode 100644 (file)
index 0000000..6b36bba
--- /dev/null
@@ -0,0 +1,262 @@
+/*
+ * 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 "presenters/PreviewPage.h"
+
+#include "model/IMediaAlbum.h"
+#include "model/MediaItem.h"
+
+#include "view/ImageGrid.h"
+
+#include "presenters/ViewerPage.h"
+
+#include "common.h"
+
+namespace gallery {
+
+       using namespace ucl;
+
+       // PreviewPage::Builder //
+
+       PreviewPage::Builder::Builder() :
+               m_startItemIndex(0)
+       {
+       }
+
+       PreviewPage::Builder::~Builder()
+       {
+       }
+
+       PreviewPage::Builder &PreviewPage::Builder::setNaviframe(
+                       const NaviframeSRef &navi)
+       {
+               m_navi = navi;
+               return *this;
+       }
+
+       PreviewPage::Builder &PreviewPage::Builder::setAlbum(
+                       const IMediaAlbumSRef &album)
+       {
+               m_album = album;
+               return *this;
+       }
+
+       PreviewPage::Builder &PreviewPage::Builder::setStartItemIndex(
+                       const int index)
+       {
+               m_startItemIndex = index;
+               return *this;
+       }
+
+       PreviewPageSRef PreviewPage::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_album) {
+                       LOG_RETURN_VALUE(RES_INVALID_ARGUMENTS, {}, "m_album is NULL");
+               }
+
+               auto result = makeShared<PreviewPage>(
+                               m_navi, onExitRequest, m_album);
+
+               FAIL_RETURN_VALUE(result->prepare(), {}, "result->prepare() failed!");
+
+               if (m_startItemIndex > 0) {
+                       result->showItem(m_startItemIndex);
+               }
+
+               return result;
+       }
+
+       // PreviewPage::Item //
+
+       class PreviewPage::Item : public NonCopyable {
+       public:
+               Item(MediaItemSRef &&media, ImageGrid &imageGrid, const int itemIndex) :
+                       m_media(std::move(media)),
+                       m_imageGrid(imageGrid),
+                       m_index(itemIndex)
+               {
+               }
+
+               void realize()
+               {
+                       FAIL_LOG(m_media->getThumbnailPath(
+                                       DELEGATE(Item::onThumbnail, this)),
+                                       "getThumbnailPath() failed!");
+               }
+
+               void unrealize()
+               {
+                       m_media->cancelThumbnailPathGet();
+               }
+
+               MediaItemSRef getMedia()
+               {
+                       return m_media;
+               }
+
+       private:
+               void onThumbnail(const Result result, const std::string &path)
+               {
+                       FAIL_LOG(result, "Failed to get thumbnail!");
+
+                       ImageGrid::ItemParams params = {};
+                       m_media->getResolution(params.aspectX, params.aspectY);
+                       params.imagePath = m_media->getFilePath();
+                       params.bgImagePath = path;
+                       params.flags = ImageGrid::UF_BLOCK_CLICKS;
+
+                       m_imageGrid.updateItem(m_index, params);
+               }
+
+       private:
+               const MediaItemSRef m_media;
+               ImageGrid &m_imageGrid;
+               const int m_index;
+       };
+
+       // PreviewPage //
+
+       PreviewPage::PreviewPage(RefCountObjBase &rc,
+                       const NaviframeSRef &navi,
+                       const ExitRequestHandler onExitRequest,
+                       const IMediaAlbumSRef &album) :
+               Page(rc, navi, onExitRequest),
+               m_album(album)
+       {
+       }
+
+       PreviewPage::~PreviewPage()
+       {
+               if (m_page) {
+                       m_page->exitNoTransition();
+               }
+               m_imageGrid->setListener(nullptr);
+       }
+
+       void PreviewPage::reload()
+       {
+               ImageGrid::Unrealizer u(*m_imageGrid);
+
+               m_items.clear();
+
+               FAIL_LOG(m_album->forEachMedia(
+                               DELEGATE(PreviewPage::onEachMedia, this)),
+                               "m_album->forEachMedia() failed!");
+
+               m_imageGrid->setItemCount(m_items.size());
+
+               const auto viewerPage = dynamicRefCast<ViewerPage>(m_page);
+               if (viewerPage) {
+                       const auto mediaId = viewerPage->getMediaId();
+                       const auto it = std::find_if(m_items.begin(), m_items.end(),
+                               [&mediaId](const ItemUPtr &item)
+                               {
+                                       return (item->getMedia()->getId() == mediaId);
+                               });
+                       if (it == m_items.end()) {
+                               DLOG("Viewed media item was removed.");
+                               deleteTo();
+                       } else {
+                               m_imageGrid->scrollToItem(it - m_items.begin());
+                       }
+               }
+       }
+
+       Result PreviewPage::prepare()
+       {
+               m_imageGrid = ImageGrid::Builder().
+                               setListener(this).
+                               setType(ImageGrid::Type::LINEAR).
+                               build(getNaviframe());
+               if (!m_imageGrid) {
+                       LOG_RETURN(RES_FAIL, "ImageGrid::build() failed!");
+               }
+
+               FAIL_RETURN(m_album->forEachMedia(
+                               DELEGATE(PreviewPage::onEachMedia, this)),
+                               "m_album->forEachMedia() failed!");
+
+               FAIL_RETURN(Page::prepare(
+                       [this]()
+                       {
+                               return getNaviframe().push(*m_imageGrid, NAVIFRAME_EMPTY);
+                       }),
+                       "Page::prepare() failed!");
+
+               m_imageGrid->setItemCount(m_items.size());
+
+               return RES_OK;
+       }
+
+       void PreviewPage::showItem(const int itemIndex)
+       {
+               m_imageGrid->scrollToItem(itemIndex);
+       }
+
+       bool PreviewPage::onEachMedia(MediaItemSRef &&media)
+       {
+               m_items.emplace_back(
+                               new Item(std::move(media), *m_imageGrid, m_items.size()));
+               return true;
+       }
+
+       void PreviewPage::onActivate()
+       {
+               m_imageGrid->activateRotary();
+       }
+
+       void PreviewPage::onDeactivate()
+       {
+               m_imageGrid->deactivateRotary();
+       }
+
+       void PreviewPage::onItemRealized(const int itemIndex)
+       {
+               m_items[itemIndex]->realize();
+       }
+
+       void PreviewPage::onItemUnrealized(const int itemIndex)
+       {
+               m_items[itemIndex]->unrealize();
+       }
+
+       void PreviewPage::onItemEvent(const int itemIndex,
+                       const int event, const int x, const int y)
+       {
+               if (!isActive() || (event != ImageGrid::ITEM_EVENT_DOUBLE_TAP)) {
+                       return;
+               }
+
+               m_page = ViewerPage::Builder().
+                               setNaviframe(asShared(getNaviframe())).
+                               setZoomIn(x, y).
+                               setMedia(m_items[itemIndex]->getMedia()).
+                               build(DELEGATE(PreviewPage::onPageExitRequest, this));
+       }
+
+       void PreviewPage::onPageExitRequest(Page &page)
+       {
+               deleteTo();
+       }
+}
diff --git a/src/presenters/ThumbnailPage.cpp b/src/presenters/ThumbnailPage.cpp
new file mode 100644 (file)
index 0000000..f28f58f
--- /dev/null
@@ -0,0 +1,233 @@
+/*
+ * 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 "presenters/ThumbnailPage.h"
+
+#include "model/IMediaAlbum.h"
+#include "model/MediaItem.h"
+
+#include "view/ImageGrid.h"
+
+#include "presenters/PreviewPage.h"
+
+#include "common.h"
+
+namespace gallery {
+
+       using namespace ucl;
+
+       // ThumbnailPage::Builder //
+
+       ThumbnailPage::Builder::Builder()
+       {
+       }
+
+       ThumbnailPage::Builder::~Builder()
+       {
+       }
+
+       ThumbnailPage::Builder &ThumbnailPage::Builder::setNaviframe(
+                       const NaviframeSRef &navi)
+       {
+               m_navi = navi;
+               return *this;
+       }
+
+       ThumbnailPage::Builder &ThumbnailPage::Builder::setAlbum(
+                       const IMediaAlbumSRef &album)
+       {
+               m_album = album;
+               return *this;
+       }
+
+       ThumbnailPageSRef ThumbnailPage::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_album) {
+                       LOG_RETURN_VALUE(RES_INVALID_ARGUMENTS, {}, "m_album is NULL");
+               }
+
+               auto result = makeShared<ThumbnailPage>(
+                               m_navi, onExitRequest, m_album);
+
+               FAIL_RETURN_VALUE(result->prepare(), {}, "result->prepare() failed!");
+
+               return result;
+       }
+
+       // ThumbnailPage::RealizedItem //
+
+       class ThumbnailPage::RealizedItem : public NonCopyable {
+       public:
+               RealizedItem(ThumbnailPage &parent, const int index) :
+                       m_parent(parent),
+                       m_index(index)
+               {
+                       FAIL_LOG(m_parent.m_mediaItems[m_index]->getThumbnailPath(
+                                       DELEGATE(RealizedItem::onThumbnail, this)),
+                                       "getThumbnailPath() failed!");
+               }
+
+               ~RealizedItem()
+               {
+                       m_parent.m_mediaItems[m_index]->cancelThumbnailPathGet();
+               }
+
+               int getIndex() const
+               {
+                       return m_index;
+               }
+
+       private:
+               void onThumbnail(const Result result, const std::string &path)
+               {
+                       FAIL_RETURN_VOID(result, "Failed to get thumbnail!");
+
+                       ImageGrid::ItemParams params = {};
+                       params.imagePath = path;
+
+                       m_parent.m_imageGrid->updateItem(m_index, params);
+               }
+
+       private:
+               ThumbnailPage &m_parent;
+               int m_index;
+       };
+
+       // ThumbnailPage //
+
+       ThumbnailPage::ThumbnailPage(RefCountObjBase &rc,
+                       const NaviframeSRef &navi,
+                       const ExitRequestHandler onExitRequest,
+                       const IMediaAlbumSRef &album) :
+               Page(rc, navi, onExitRequest),
+               m_album(album)
+       {
+       }
+
+       ThumbnailPage::~ThumbnailPage()
+       {
+               if (m_page) {
+                       m_page->exitNoTransition();
+               }
+               m_imageGrid->setListener(nullptr);
+       }
+
+       void ThumbnailPage::reload()
+       {
+               ImageGrid::Unrealizer u(*m_imageGrid);
+
+               m_mediaItems.clear();
+
+               FAIL_LOG(m_album->forEachMedia(
+                               DELEGATE(ThumbnailPage::onEachMedia, this)),
+                               "m_album->forEachMedia() failed!");
+
+               m_imageGrid->setItemCount(m_mediaItems.size());
+
+               if (const auto vp = dynamic_cast<PreviewPage *>(m_page.get())) {
+                       vp->reload();
+               }
+       }
+
+       Result ThumbnailPage::prepare()
+       {
+               FAIL_RETURN(m_album->forEachMedia(
+                               DELEGATE(ThumbnailPage::onEachMedia, this)),
+                               "m_album->forEachMedia() failed!");
+
+               m_imageGrid = ImageGrid::Builder().
+                               setListener(this).
+                               setType(ImageGrid::Type::HCOMB_3X3).
+                               build(getNaviframe());
+               if (!m_imageGrid) {
+                       LOG_RETURN(RES_FAIL, "ImageGrid::build() failed!");
+               }
+
+               FAIL_RETURN(Page::prepare(
+                       [this]()
+                       {
+                               return getNaviframe().push(*m_imageGrid, NAVIFRAME_EMPTY);
+                       }),
+                       "Page::prepare() failed!");
+
+               m_imageGrid->setItemCount(m_mediaItems.size());
+
+               return RES_OK;
+       }
+
+       bool ThumbnailPage::onEachMedia(MediaItemSRef &&media)
+       {
+               m_mediaItems.emplace_back(std::move(media));
+               return true;
+       }
+
+       void ThumbnailPage::onActivate()
+       {
+               m_imageGrid->activateRotary();
+       }
+
+       void ThumbnailPage::onDeactivate()
+       {
+               m_imageGrid->deactivateRotary();
+       }
+
+       void ThumbnailPage::onItemRealized(const int itemIndex)
+       {
+               m_realizedItems.emplace_back(new RealizedItem(*this, itemIndex));
+       }
+
+       void ThumbnailPage::onItemUnrealized(const int itemIndex)
+       {
+               const auto it = std::find_if(
+                               m_realizedItems.begin(), m_realizedItems.end(),
+                               [itemIndex](const RealizedItemUPtr &item)
+                               {
+                                       return (item->getIndex() == itemIndex);
+                               });
+               if (it != m_realizedItems.end()) {
+                       m_realizedItems.erase(it);
+               } else {
+                       WLOG("Item is not found in realized list!");
+               }
+       }
+
+       void ThumbnailPage::onItemEvent(const int itemIndex,
+                       const int event, const int x, const int y)
+       {
+               if (!isActive() || (event != ImageGrid::ITEM_EVENT_CLICK)) {
+                       return;
+               }
+
+               m_page = PreviewPage::Builder().
+                               setNaviframe(asShared(getNaviframe())).
+                               setAlbum(m_album).
+                               setStartItemIndex(itemIndex).
+                               build(DELEGATE(ThumbnailPage::onPageExitRequest, this));
+       }
+
+       void ThumbnailPage::onPageExitRequest(Page &page)
+       {
+               popTo();
+       }
+}
diff --git a/src/presenters/ViewerPage.cpp b/src/presenters/ViewerPage.cpp
new file mode 100644 (file)
index 0000000..a6944b8
--- /dev/null
@@ -0,0 +1,199 @@
+/*
+ * 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 "presenters/ViewerPage.h"
+
+#include "model/MediaItem.h"
+
+#include "view/ImageViewer.h"
+#include "view/TouchParser.h"
+
+#include "common.h"
+
+namespace gallery {
+
+       using namespace ucl;
+
+       // ViewerPage::Builder //
+
+       ViewerPage::Builder::Builder() :
+               m_zoomInX(-1),
+               m_zoomInY(-1),
+               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::setZoomIn(
+                       const int x, const int y)
+       {
+               m_zoomInX = x;
+               m_zoomInY = y;
+               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!");
+
+               if ((m_zoomInX >= 0) && (m_zoomInY >= 0)) {
+                       result->zoomIn(m_zoomInX, m_zoomInY);
+               }
+
+               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()
+       {
+       }
+
+       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!");
+
+               m_touchParser = makeShared<TouchParser>(*m_imageViewer);
+               m_touchParser->setDoubleTapHandler(
+                               DELEGATE(ViewerPage::onDoubleTap, this));
+
+               return RES_OK;
+       }
+
+       void ViewerPage::zoomIn(const int originX, const int originY)
+       {
+               m_imageViewer->zoomIn(originX, originY);
+       }
+
+       const std::string &ViewerPage::getMediaId() const
+       {
+               return m_media->getId();
+       }
+
+       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::onDoubleTap(int x, int y)
+       {
+               if (!isActive()) {
+                       return;
+               }
+               if (m_imageViewer->isZoomedOut()) {
+                       m_imageViewer->zoomIn(x, y);
+               } else if (m_imageViewer->isZoomedIn()) {
+                       m_imageViewer->zoomOut();
+               }
+       }
+
+       void ViewerPage::onBackKey()
+       {
+               if (m_imageViewer->isZoomedOut()) {
+                       requestExit();
+               } else if (m_imageViewer->isZoomedIn()) {
+                       m_imageViewer->zoomOut();
+               }
+       }
+}
diff --git a/src/presenters/common.h b/src/presenters/common.h
new file mode 100644 (file)
index 0000000..aec536f
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * 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_PRESENTERS_COMMON_H__
+#define __GALLERY_PRESENTERS_COMMON_H__
+
+#include "ucl/gui/stdTheme.h"
+
+#include "view/helpers.h"
+
+#include "../common.h"
+
+#endif // __GALLERY_PRESENTERS_COMMON_H__
diff --git a/src/view/ImageGrid.cpp b/src/view/ImageGrid.cpp
new file mode 100644 (file)
index 0000000..5d1a247
--- /dev/null
@@ -0,0 +1,1133 @@
+/*
+ * 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 "view/ImageGrid.h"
+
+#include <array>
+#include <vector>
+
+#include "ucl/gui/Layout.h"
+
+#include "view/IImageGridListener.h"
+#include "view/TouchParser.h"
+
+#include "common.h"
+
+namespace gallery { namespace { namespace impl {
+
+       using namespace ucl;
+
+       // Related to ImageGrid //
+       const TString SLOT_PART_FMT {"swallow.cell_%d"};
+
+       // Related to Button //
+       constexpr ElmStyle ITEM_BTN_STYLE {"gallery_image"};
+       constexpr EdjePart PART_BTN_BG {"swallow.bg"};
+       constexpr SmartEvent BTN_CLICKED {"clicked"};
+       constexpr EdjeSignal BTN_BLOCK_CLICKS {"gallery,block,clicks"};
+       constexpr EdjeSignal BTN_UNBLOCK_CLICKS {"gallery,unblock,clicks"};
+
+       // Other //
+       constexpr auto HCOMB_SCROLL_LIMIT = 1000;
+}}}
+
+namespace gallery {
+
+       using namespace ucl;
+
+       // ImageGrid::Builder //
+
+       ImageGrid::Builder::Builder() :
+               m_type(Type::HCOMB_3X3),
+               m_listener(nullptr)
+       {
+       }
+
+       ImageGrid::Builder &ImageGrid::Builder::setType(const Type value)
+       {
+               m_type = value;
+               return *this;
+       }
+
+       ImageGrid::Builder &ImageGrid::Builder::setListener(
+                       IImageGridListener *const value)
+       {
+               m_listener = value;
+               return *this;
+       }
+
+       ImageGridSRef ImageGrid::Builder::build(Widget &parent) const
+       {
+               Evas_Object *const scrollerEo = elm_scroller_add(parent);
+               if (!scrollerEo) {
+                       ELOG("elm_scroller_add() failed!");
+                       return {};
+               }
+
+               auto result = makeShared<ImageGrid>(m_type, scrollerEo);
+
+               result->bindToEo();
+               result->setListener(m_listener);
+
+               return result;
+       }
+
+       // ImageGrid::Info //
+
+       struct ImageGrid::Info {
+               const std::array<LayoutTheme, 2> slotThemes;
+               const std::array<int, 2> slotLens;
+               const int scrollLimit;
+               const int slotsPerPage;
+               const bool isHorizontal;
+
+               virtual int calcItemIndexFromCell(
+                               const int slotIndex, const int itemOffset) const = 0;
+               virtual void calcCellFromItemIndex(const int itemIndex,
+                               int &slotIndex, int &itemOffset) const = 0;
+
+               virtual int calcMaxSlotCount(const int itemCount) const = 0;
+
+               virtual int calcExtraPaddingSize(const int slotSize,
+                               const int itemCount) const
+               {
+                       return 0;
+               }
+
+               Info(const std::array<LayoutTheme, 2> &slotThemes,
+                               const std::array<int, 2> &slotLens,
+                               const int scrollLimit, const int slotsPerPage,
+                               const bool isHorizontal) :
+                       slotThemes(slotThemes),
+                       slotLens(slotLens),
+                       scrollLimit(scrollLimit),
+                       slotsPerPage(slotsPerPage),
+                       isHorizontal(isHorizontal)
+               {
+               }
+       };
+
+       // ImageGrid::HcombInfo //
+
+       struct ImageGrid::HcombInfo : Info {
+               const int totalLength;
+
+               virtual int calcItemIndexFromCell(
+                               const int slotIndex, const int itemOffset) const final override
+               {
+                       return ((slotIndex / 2 * totalLength) +
+                                       (itemOffset * 2) + ((slotIndex ^ 1) & 1));
+               }
+
+               virtual void calcCellFromItemIndex(const int itemIndex,
+                               int &slotIndex, int &itemOffset) const final override
+               {
+                       slotIndex = (itemIndex / totalLength);
+                       itemOffset = (itemIndex % totalLength);
+                       slotIndex += (slotIndex + ((itemOffset ^ 1) & 1));
+                       itemOffset /= 2;
+               }
+
+               virtual int calcMaxSlotCount(const int itemCount) const final override
+               {
+                       return ((itemCount + (totalLength - 1)) / totalLength * 2);
+               }
+
+               virtual int calcExtraPaddingSize(const int slotSize,
+                               const int itemCount) const final override
+               {
+                       return slotSize;
+               }
+
+               HcombInfo(const int totalLength,
+                               const std::array<LayoutTheme, 2> &slotThemes) :
+                       Info(slotThemes, {{(totalLength / 2), ceilDiv<2>(totalLength)}},
+                               impl::HCOMB_SCROLL_LIMIT, (totalLength - 1), true),
+                       totalLength(totalLength)
+               {
+               }
+       };
+
+       // ImageGrid::LinearInfo //
+
+       struct ImageGrid::LinearInfo : Info {
+               virtual int calcItemIndexFromCell(
+                               const int slotIndex, const int itemOffset) const final override
+               {
+                       return (slotIndex / 2);
+               }
+
+               virtual void calcCellFromItemIndex(const int itemIndex,
+                               int &slotIndex, int &itemOffset) const final override
+               {
+                       slotIndex = (itemIndex * 2);
+                       itemOffset = 0;
+               }
+
+               virtual int calcMaxSlotCount(const int itemCount) const final override
+               {
+                       return (itemCount * 2);
+               }
+
+               LinearInfo(const LayoutTheme &slotTheme, const bool isHorizontal) :
+                       Info({{slotTheme}}, {{1, 0}}, 1, 1, isHorizontal)
+               {
+               }
+       };
+
+       // ImageGrid::Slot //
+
+       class ImageGrid::Slot {
+       private:
+               class Item : public RefCountAware {
+               public:
+                       friend class RefCountObj<Item>;
+                       Item(RefCountObjBase &rc,
+                                       const ImageGrid &imageGrid, Widget &parent) :
+                               RefCountAware(&rc),
+                               m_imageGrid(imageGrid),
+                               m_btn(elm_button_add(parent)),
+                               m_image(elm_image_add(m_btn)),
+                               m_realizeIndex(-1),
+                               m_imageLoadSize(0),
+                               m_wasUpdated(false),
+                               m_isClicksBlocked(false)
+                       {
+                               m_btn.setFocusAlowed(false);
+                               m_btn.setStyle(impl::ITEM_BTN_STYLE);
+                               show(m_btn);
+
+                               elm_image_preload_disabled_set(m_image, EINA_FALSE);
+                               elm_image_aspect_fixed_set(m_image, EINA_TRUE);
+                               elm_image_fill_outside_set(m_image, EINA_TRUE);
+                               m_btn.setContent(m_image);
+                               show(m_image);
+
+                               m_btn.addEventHandler(impl::BTN_CLICKED, WEAK_DELEGATE(
+                                               Item::onClicked, asWeak(*this)));
+
+                               m_touchParser = makeShared<TouchParser>(m_btn);
+                               m_touchParser->setDoubleTapHandler(
+                                               DELEGATE(Item::onDoubleTap, this));
+                       }
+
+                       Widget &getWidget()
+                       {
+                               return m_btn;
+                       }
+
+                       void setImageLoadSize(const int value)
+                       {
+                               m_imageLoadSize = value;
+                               elm_image_prescale_set(m_image, m_imageLoadSize);
+                       }
+
+                       bool isRealized() const
+                       {
+                               return (m_realizeIndex >= 0);
+                       }
+
+                       void realize(const int itemIndex)
+                       {
+                               if (isRealized()) {
+                                       return;
+                               }
+
+                               m_wasUpdated = false;
+
+                               if (itemIndex < m_imageGrid.m_itemCount) {
+                                       m_realizeIndex = itemIndex;
+
+                                       if (m_imageGrid.m_listener) {
+                                               m_imageGrid.m_listener->onItemRealized(itemIndex);
+                                       }
+                               }
+
+                               if (!m_wasUpdated) {
+                                       makeTransparent(m_btn);
+                               }
+                       }
+
+                       void unrealize()
+                       {
+                               if (!isRealized()) {
+                                       return;
+                               }
+
+                               const int itemIndex = m_realizeIndex;
+                               m_realizeIndex = -1;
+
+                               if (m_imageGrid.m_listener) {
+                                       m_imageGrid.m_listener->onItemUnrealized(itemIndex);
+                               }
+                       }
+
+                       bool update(const ItemParams &params)
+                       {
+                               if (!isRealized()) {
+                                       return false;
+                               }
+
+                               updateClicksBlock(params);
+                               updateImage(params);
+                               updateBgImage(params);
+
+                               makeWhite(m_btn);
+
+                               m_wasUpdated = true;
+
+                               return true;
+                       }
+
+               private:
+                       void updateClicksBlock(const ItemParams &params)
+                       {
+                               if (params.flags & UF_BLOCK_CLICKS) {
+                                       if (!m_isClicksBlocked) {
+                                               m_isClicksBlocked = true;
+                                               m_btn.emitSignal(impl::BTN_BLOCK_CLICKS);
+                                       }
+                               } else if (m_isClicksBlocked) {
+                                       m_isClicksBlocked = false;
+                                       m_btn.emitSignal(impl::BTN_UNBLOCK_CLICKS);
+                               }
+                       }
+
+                       void updateImage(const ItemParams &params)
+                       {
+                               if (isEmpty(params.imagePath)) {
+                                       if (!m_wasUpdated || (params.flags & UF_LOSE_IMAGE)) {
+                                               makeTransparent(m_image);
+                                       }
+                                       return;
+                               }
+
+                               elm_image_file_set(m_image, params.imagePath.c_str(), NULL);
+
+                               makeWhite(m_image);
+                       }
+
+                       void updateBgImage(const ItemParams &params)
+                       {
+                               if (isEmpty(params.bgImagePath)) {
+                                       if (m_bgImage && (!m_wasUpdated ||
+                                                       (params.flags & UF_LOSE_BG))) {
+                                               makeTransparent(*m_bgImage);
+                                       }
+                                       return;
+                               }
+
+                               if (!m_bgImage) {
+                                       m_bgImage = makeShared<Widget>(
+                                                       evas_object_image_filled_add(m_btn.getEvas()));
+                                       evas_object_image_load_size_set(*m_bgImage,
+                                                       m_imageLoadSize, m_imageLoadSize);
+                                       m_btn.setContent(impl::PART_BTN_BG, *m_bgImage);
+                                       show(*m_bgImage);
+                               }
+
+                               evas_object_image_file_set(*m_bgImage,
+                                               params.bgImagePath.c_str(), NULL);
+
+                               int w = params.aspectX;
+                               int h = params.aspectY;
+                               if ((w == 0) || (h == 0)) {
+                                       evas_object_image_size_get(*m_bgImage, &w, &h);
+                               }
+                               m_bgImage->setARHint(WidgetARHint::NEITHER, w, h);
+
+                               makeWhite(*m_bgImage);
+                       }
+
+                       void onClicked(Widget &wifget, void *eventInfo)
+                       {
+                               if (isRealized()) {
+                                       m_imageGrid.handleItemEvent(m_realizeIndex,
+                                                       ITEM_EVENT_CLICK, -1, -1);
+                               }
+                       }
+
+                       void onDoubleTap(const int x, const int y)
+                       {
+                               if (isRealized()) {
+                                       m_imageGrid.handleItemEvent(m_realizeIndex,
+                                                       ITEM_EVENT_DOUBLE_TAP, x, y);
+                               }
+                       }
+
+               private:
+                       const ImageGrid &m_imageGrid;
+                       StyledWidget m_btn;
+                       StyledWidget m_image;
+                       WidgetSRef m_bgImage;
+                       TouchParserSRef m_touchParser;
+                       int m_realizeIndex;
+                       int m_imageLoadSize;
+                       bool m_wasUpdated;
+                       bool m_isClicksBlocked;
+               };
+
+       public:
+               Slot(ImageGrid &imageGrid, const bool isOdd) :
+                       m_info(imageGrid.m_info),
+                       m_layout(elm_layout_add(imageGrid.m_box), true),
+                       m_isRealized(false)
+               {
+                       if (isValid(m_info.slotThemes[isOdd]) &&
+                                       !m_layout.setTheme(m_info.slotThemes[isOdd])) {
+                               ELOG("setTheme() failed!");
+                       }
+                       fill(m_layout);
+                       show(m_layout);
+
+                       const int length = m_info.slotLens[isOdd];
+                       for (int i = 0; i < length; ++i) {
+                               m_items.emplace_back(makeShared<Item>(imageGrid, m_layout));
+
+                               m_layout.setContent(
+                                               EdjePart(impl::SLOT_PART_FMT.format(i)),
+                                               m_items.back()->getWidget());
+                       }
+               }
+
+               Widget &getWidget()
+               {
+                       return m_layout;
+               }
+
+               int calcSize()
+               {
+                       int w = 0;
+                       int h = 0;
+                       m_layout.calculate();
+                       m_layout.getMin(&w, &h);
+                       return (m_info.isHorizontal ? w : h);
+               }
+
+               void setImageLoadSize(const int value)
+               {
+                       for (auto &item: m_items) {
+                               item->setImageLoadSize(value);
+                       }
+               }
+
+               void unrealize()
+               {
+                       if (!m_isRealized) {
+                               return;
+                       }
+                       m_isRealized = false;
+
+                       for (auto &item: m_items) {
+                               item->unrealize();
+                       }
+               }
+
+               void realize(const int slotIndex)
+               {
+                       if (m_isRealized) {
+                               return;
+                       }
+                       m_isRealized = true;
+
+                       for (UInt i = 0; i < m_items.size(); ++i) {
+                               m_items[i]->realize(
+                                               m_info.calcItemIndexFromCell(slotIndex, i));
+                       }
+               }
+
+               bool updateItem(const int itemOffset, const ItemParams &params)
+               {
+                       return m_items[itemOffset]->update(params);
+               }
+
+               bool isItemRealized(const int itemOffset) const
+               {
+                       return m_items[itemOffset]->isRealized();
+               }
+
+       private:
+               const Info &m_info;
+               std::vector<SharedRef<Item>> m_items;
+               Layout m_layout;
+               bool m_isRealized;
+       };
+
+       // ImageGrid::Unrealizer //
+
+       ImageGrid::Unrealizer::Unrealizer(ImageGrid &imageGrid) :
+               m_imageGrid(imageGrid)
+       {
+               m_imageGrid.addUnrealizeLock();
+       }
+
+       ImageGrid::Unrealizer::~Unrealizer()
+       {
+               m_imageGrid.removeUnrealizeLock();
+       }
+
+       // ImageGrid //
+
+       ImageGrid::ImageGrid(RefCountObjBase *const rc, const Type type,
+                       Evas_Object *const scroller) :
+               Widget(rc, scroller, true),
+               m_info(getInfo(type)),
+
+               m_scroller(makeShared<StyledWidget>(scroller)),
+               m_box(elm_box_add(*m_scroller)),
+               m_rect1(evas_object_rectangle_add(m_box.getEvas())),
+               m_rect2(evas_object_rectangle_add(m_box.getEvas())),
+               m_circleScroller(nullptr),
+
+               m_listener(nullptr),
+               m_itemCount(0),
+
+               m_slotCount(0), // Must be even >= 2
+               m_optimalSlotCount(2), // Must be even >= 2
+               m_maxSlotCount(2), // Must be even >= 2
+
+               m_beginSlotIndex(0),
+               m_maxBeginSlotIndex(0),
+
+               m_scrollBias(0),
+               m_padSize1(0),
+               m_padSize2(0),
+
+               m_slotSize(0), // Must not be 0
+               m_scrollerSize(1), // Must not be 0
+               m_scrollOffset(0),
+
+               m_unrealizeLock(0),
+               m_eventsLock(0)
+       {
+               prepare();
+
+               ++m_eventsLock;
+
+               updateSlotCount();
+
+               updatePadSizes();
+               updateScrollBias();
+               updateRectMins();
+
+               --m_eventsLock;
+       }
+
+       const ImageGrid::Info &ImageGrid::getInfo(const Type type)
+       {
+               switch (type) {
+               case Type::HCOMB_3X3: {
+                               static HcombInfo info{3, {{
+                                               {"layout", "gallery_image_grid", "hcomb_3x3_even"},
+                                               {"layout", "gallery_image_grid", "hcomb_3x3_odd"}}}};
+                               return info;
+                       }
+               case Type::LINEAR:
+               default: {
+                               static LinearInfo info{
+                                               {"layout", "gallery_image_grid", "linear"}, true};
+                               return info;
+                       }
+               }
+       }
+
+       void ImageGrid::prepare()
+       {
+               fill(m_rect1);
+               elm_box_pack_end(m_box, m_rect1);
+               makeTransparent(m_rect1);
+               show(m_rect1);
+
+               expandAndFill(m_rect2);
+               elm_box_pack_end(m_box, m_rect2);
+               makeTransparent(m_rect2);
+               show(m_rect2);
+
+               expandAndFill(m_box);
+               m_scroller->setContent(m_box);
+               elm_box_horizontal_set(m_box, toEina(m_info.isHorizontal));
+               show(m_box);
+
+               m_scroller->setStyle(SCROLLER_STYLE);
+               expandAndFill(*m_scroller);
+               if (m_info.isHorizontal) {
+                       elm_scroller_page_scroll_limit_set(
+                                       *m_scroller, m_info.scrollLimit, 0);
+                       elm_scroller_bounce_set(*m_scroller, EINA_TRUE, EINA_FALSE);
+               } else {
+                       elm_scroller_page_scroll_limit_set(
+                                       *m_scroller, 0, m_info.scrollLimit);
+                       elm_scroller_bounce_set(*m_scroller, EINA_FALSE, EINA_TRUE);
+               }
+               show(*m_scroller);
+
+               createCircleScroller();
+
+               m_scroller->addEventHandler(WidgetEvent::RESIZE,
+                               WEAK_DELEGATE(ImageGrid::onScrollerResize, asWeak(*this)));
+
+               m_scroller->addEventHandler(WidgetEvent::MOVE,
+                               WEAK_DELEGATE(ImageGrid::onScrollerMove, asWeak(*this)));
+
+               m_box.addEventHandler(WidgetEvent::MOVE,
+                               WEAK_DELEGATE(ImageGrid::onBoxMove, asWeak(*this)));
+       }
+
+       void ImageGrid::createCircleScroller()
+       {
+               const auto sfc = getCircleSurface(*m_scroller);
+               if (!sfc) {
+                       LOG_RETURN_VOID(RES_FAIL, "getCircleSurface() failed!");
+               }
+
+               m_circleScroller = eext_circle_object_scroller_add(*m_scroller, sfc);
+               if (!m_circleScroller) {
+                       LOG_RETURN_VOID(RES_FAIL,
+                                       "eext_circle_object_scroller_add() failed!");
+               }
+
+               if (m_info.isHorizontal) {
+                       eext_circle_object_scroller_policy_set(m_circleScroller,
+                                       ELM_SCROLLER_POLICY_AUTO, ELM_SCROLLER_POLICY_OFF);
+               } else {
+                       eext_circle_object_scroller_policy_set(m_circleScroller,
+                                       ELM_SCROLLER_POLICY_OFF, ELM_SCROLLER_POLICY_AUTO);
+               }
+       }
+
+       void ImageGrid::setListener(IImageGridListener *const listener)
+       {
+               m_listener = listener;
+       }
+
+       void ImageGrid::setItemCount(const int count)
+       {
+               if (m_itemCount == count) {
+                       return;
+               }
+
+               ++m_eventsLock;
+
+               unrealizeSlots(0, m_slotCount);
+
+               m_itemCount = count;
+
+               if (updateMaxSlotCount()) {
+                       updateSlotCount();
+                       if (updateMaxBeginSlotIndex()) {
+                               updateBeginSlotIndex();
+                       }
+               }
+
+               realizeSlots();
+               updateRectMins();
+
+               --m_eventsLock;
+       }
+
+       void ImageGrid::update()
+       {
+               Unrealizer(*this);
+       }
+
+       Result ImageGrid::updateItem(const int itemIndex, const ItemParams &params)
+       {
+               return doWithItem(itemIndex,
+                       [&params](Slot &slot, const int itemOffset)
+                       {
+                               return (slot.updateItem(itemOffset, params) ?
+                                               RES_OK : RES_FALSE);
+                       });
+       }
+
+       Result ImageGrid::isItemRealized(const int itemIndex) const
+       {
+               return doWithItem(itemIndex,
+                       [](Slot &slot, const int itemOffset)
+                       {
+                               return (slot.isItemRealized(itemOffset) ? RES_OK : RES_FALSE);
+                       });
+       }
+
+       template <class FUNC>
+       Result ImageGrid::doWithItem(const int itemIndex, FUNC &&func) const
+       {
+               return doWithCell(itemIndex,
+                       [this, &func](const int slotIndex, const int itemOffset)
+                       {
+                               const int slotOffset = (slotIndex - m_beginSlotIndex);
+                               if ((slotOffset < 0) || (slotOffset >= m_slotCount)) {
+                                       return RES_FALSE;
+                               }
+                               return func(*m_slots[slotOffset], itemOffset);
+                       });
+       }
+
+       template <class FUNC>
+       Result ImageGrid::doWithCell(const int itemIndex, FUNC &&func) const
+       {
+               if ((itemIndex < 0) || (itemIndex >= m_itemCount)) {
+                       LOG_RETURN(RES_INVALID_ARGUMENTS,
+                                       "Item index out of range: %d", itemIndex);
+               }
+
+               int slotIndex = 0;
+               int itemOffset = 0;
+               m_info.calcCellFromItemIndex(itemIndex, slotIndex, itemOffset);
+
+               return func(slotIndex, itemOffset);
+       }
+
+       Result ImageGrid::scrollToItem(const int itemIndex)
+       {
+               return showItem(itemIndex, elm_scroller_region_show);
+       }
+
+       Result ImageGrid::bringInItem(int itemIndex)
+       {
+               return showItem(itemIndex, elm_scroller_region_bring_in);
+       }
+
+       template <class SHOW_FUNC>
+       Result ImageGrid::showItem(const int itemIndex, SHOW_FUNC &&showFunc)
+       {
+               return doWithCell(itemIndex,
+                       [this, &showFunc](const int slotIndex, const int itemOffset)
+                       {
+                               const int scrollOffset = ((slotIndex / 2) * m_slotSize);
+                               if (m_info.isHorizontal) {
+                                       showFunc(*m_scroller, scrollOffset, 0, m_scrollerSize, 1);
+                               } else {
+                                       showFunc(*m_scroller, 0, scrollOffset, 1, m_scrollerSize);
+                               }
+                               return RES_OK;
+                       });
+       }
+
+       void ImageGrid::activateRotary()
+       {
+               eext_rotary_object_event_activated_set(m_circleScroller, EINA_TRUE);
+       }
+
+       void ImageGrid::deactivateRotary()
+       {
+               eext_rotary_object_event_activated_set(m_circleScroller, EINA_FALSE);
+       }
+
+       void ImageGrid::addUnrealizeLock()
+       {
+               unrealizeSlots(0, m_slotCount);
+               ++m_unrealizeLock;
+       }
+
+       void ImageGrid::removeUnrealizeLock()
+       {
+               if (m_unrealizeLock > 0) {
+                       --m_unrealizeLock;
+                       realizeSlots();
+               } else {
+                       WLOG("m_unrealizeLock = 0!");
+               }
+       }
+
+       void ImageGrid::handleItemEvent(const int itemIndex, const int event,
+                       const int x, const int y) const
+       {
+               if (m_listener) {
+                       m_listener->onItemEvent(itemIndex, event, x, y);
+               }
+       }
+
+       bool ImageGrid::updateSlotCount()
+       {
+               const int newSlotCount = calcSlotCount();
+
+               if (newSlotCount != m_slotCount) {
+                       DLOG("newSlotCount: %d; m_slotCount: %d;",
+                                       newSlotCount, m_slotCount);
+                       setSlotCount(newSlotCount);
+                       return true;
+               }
+
+               return false;
+       }
+
+       int ImageGrid::calcSlotCount()
+       {
+               return std::min(m_optimalSlotCount, m_maxSlotCount);
+       }
+
+       void ImageGrid::setSlotCount(const int newSlotCount)
+       {
+               for (int i = m_slotCount; i < newSlotCount; ++i) {
+                       const bool isOdd = ((m_beginSlotIndex + i) & 1);
+
+                       auto slot = util::makeUnique(new Slot(*this, isOdd));
+
+                       if (m_slotSize == 0) {
+                               UCL_ASSERT(!isOdd, "Must be even!");
+                               m_slotSize = std::max(slot->calcSize(), 1);
+                               const int pageSize = (m_slotSize * m_info.slotsPerPage);
+                               if (m_info.isHorizontal) {
+                                       elm_scroller_page_size_set(*m_scroller, pageSize, 0);
+                               } else {
+                                       elm_scroller_page_size_set(*m_scroller, 0, pageSize);
+                               }
+                       }
+
+                       slot->setImageLoadSize(m_slotSize);
+
+                       elm_box_pack_before(m_box, slot->getWidget(), m_rect2);
+
+                       m_slots.emplace_back(std::move(slot));
+               }
+
+               unrealizeSlots(newSlotCount, m_slotCount);
+
+               m_slots.resize(newSlotCount);
+               m_slotCount = newSlotCount;
+       }
+
+       bool ImageGrid::updateOptimalSlotCount()
+       {
+               const int newOptimalSlotCount = calcOptimalSlotCount();
+
+               if (newOptimalSlotCount != m_optimalSlotCount) {
+                       DLOG("newOptimalSlotCount: %d; m_optimalSlotCount: %d;",
+                                       newOptimalSlotCount, m_optimalSlotCount);
+                       m_optimalSlotCount = newOptimalSlotCount;
+                       return true;
+               }
+
+               return false;
+       }
+
+       int ImageGrid::calcOptimalSlotCount()
+       {
+               return (((m_scrollerSize / m_slotSize) + 3) * 2);
+       }
+
+       bool ImageGrid::updateMaxSlotCount()
+       {
+               const int newMaxSlotCount = calcMaxSlotCount();
+
+               if (newMaxSlotCount != m_maxSlotCount) {
+                       DLOG("newMaxSlotCount: %d; m_maxSlotCount: %d;",
+                                       newMaxSlotCount, m_maxSlotCount);
+                       m_maxSlotCount = newMaxSlotCount;
+                       return true;
+               }
+
+               return false;
+       }
+
+       int ImageGrid::calcMaxSlotCount()
+       {
+               return std::max(m_info.calcMaxSlotCount(m_itemCount), 2);
+       }
+
+       bool ImageGrid::updateBeginSlotIndex()
+       {
+               const int newBeginSlotIndex = calcBeginSlotIndex();
+
+               if (newBeginSlotIndex != m_beginSlotIndex) {
+                       DLOG("newBeginSlotIndex: %d; m_beginSlotIndex: %d;",
+                                       newBeginSlotIndex, m_beginSlotIndex);
+                       setBeginSlotIndex(newBeginSlotIndex);
+                       return true;
+               }
+
+               return false;
+       }
+
+       int ImageGrid::calcBeginSlotIndex()
+       {
+               const int evenScrolledSize = (m_scrollOffset - m_scrollBias);
+               const int oddScrolledSize = (evenScrolledSize - m_slotSize / 2);
+
+               const int beginEvenSlotIndex = (evenScrolledSize / m_slotSize);
+               const int beginOddSlotIndex = (oddScrolledSize / m_slotSize);
+
+               int beginSlotIndex = ((beginEvenSlotIndex <= beginOddSlotIndex) ?
+                               (beginEvenSlotIndex * 2) : (beginOddSlotIndex * 2 + 1));
+
+               if (beginSlotIndex < 0) {
+                       beginSlotIndex = 0;
+               } else if (beginSlotIndex > m_maxBeginSlotIndex) {
+                       beginSlotIndex = m_maxBeginSlotIndex;
+               }
+
+               return beginSlotIndex;
+       }
+
+       void ImageGrid::setBeginSlotIndex(const int newBeginSlotIndex)
+       {
+               const int beginSlotIndex = m_beginSlotIndex;
+               const int endSlotIndex = (beginSlotIndex + m_slotCount);
+               const int newEndSlotIndex = (newBeginSlotIndex + m_slotCount);
+
+               if ((newEndSlotIndex <= beginSlotIndex) ||
+                               (endSlotIndex <= newBeginSlotIndex)) {
+
+                       unrealizeSlots(0, m_slotCount);
+
+                       if ((beginSlotIndex ^ newBeginSlotIndex) & 1) {
+                               rotateSlotsRight(1);
+                       }
+
+               } else if (newBeginSlotIndex < beginSlotIndex) {
+                       const int goodSlots = (newEndSlotIndex - beginSlotIndex);
+                       const int badSlots = (m_slotCount - goodSlots);
+
+                       unrealizeSlots(goodSlots, m_slotCount);
+
+                       if (goodSlots > badSlots) {
+                               rotateSlotsRight(badSlots);
+                       } else {
+                               rotateSlotsLeft(goodSlots);
+                       }
+               } else {
+                       const int goodSlots = (endSlotIndex - newBeginSlotIndex);
+                       const int badSlots = (m_slotCount - goodSlots);
+
+                       unrealizeSlots(0, badSlots);
+
+                       if (goodSlots > badSlots) {
+                               rotateSlotsLeft(badSlots);
+                       } else {
+                               rotateSlotsRight(goodSlots);
+                       }
+               }
+
+               m_beginSlotIndex = newBeginSlotIndex;
+       }
+
+       bool ImageGrid::updateMaxBeginSlotIndex()
+       {
+               const int newMaxBeginSlotIndex = calcMaxBeginSlotIndex();
+
+               if (newMaxBeginSlotIndex != m_maxBeginSlotIndex) {
+                       DLOG("newMaxBeginSlotIndex: %d; m_maxBeginSlotIndex: %d;",
+                                       newMaxBeginSlotIndex, m_maxBeginSlotIndex);
+                       m_maxBeginSlotIndex = newMaxBeginSlotIndex;
+                       return true;
+               }
+
+               return false;
+       }
+
+       int ImageGrid::calcMaxBeginSlotIndex()
+       {
+               return (m_maxSlotCount - m_slotCount);
+       }
+
+       void ImageGrid::updatePadSizes()
+       {
+               const int spaceSize = (m_scrollerSize -
+                               (std::max((m_scrollerSize / m_slotSize), 1) * m_slotSize));
+
+               m_padSize1 = (spaceSize / 2);
+               m_padSize2 = (spaceSize - m_padSize1 +
+                               m_info.calcExtraPaddingSize(m_slotSize, m_itemCount));
+       }
+
+       void ImageGrid::updateScrollBias()
+       {
+               m_scrollBias = (((m_optimalSlotCount / 2 - 1) * m_slotSize -
+                               m_scrollerSize) / 2 + m_padSize1);
+       }
+
+       void ImageGrid::updateRectMins()
+       {
+               const int beginEvenCols = ((m_beginSlotIndex + 1) / 2);
+               const int sideEvenCols = ((m_maxSlotCount - m_slotCount) / 2);
+               const int endEvenCols = (sideEvenCols - beginEvenCols);
+
+               const int rectMin1 = (m_padSize1 + (beginEvenCols * m_slotSize));
+               const int rectMin2 = (m_padSize2 + (endEvenCols * m_slotSize));
+
+               if (m_info.isHorizontal) {
+                       m_rect1.setMin(rectMin1, 0);
+                       m_rect2.setMin(rectMin2, 0);
+               } else {
+                       m_rect1.setMin(0, rectMin1);
+                       m_rect2.setMin(0, rectMin2);
+               }
+       }
+
+       int ImageGrid::calcScrollerSize()
+       {
+               int scrollerW = 0;
+               int scrollerH = 0;
+               getSize(*m_scroller, &scrollerW, &scrollerH);
+
+               return std::max((m_info.isHorizontal ? scrollerW : scrollerH), 1);
+       }
+
+       bool ImageGrid::updateScrollerSize()
+       {
+               const int newScrollerSize = calcScrollerSize();
+
+               if (newScrollerSize != m_scrollerSize) {
+                       DLOG("newScrollerSize: %d; m_scrollerSize: %d;",
+                                       newScrollerSize, m_scrollerSize);
+                       m_scrollerSize = newScrollerSize;
+                       return true;
+               }
+
+               return false;
+       }
+
+       int ImageGrid::calcScrollOffset()
+       {
+               int scrollerX = 0;
+               int scrollerY = 0;
+               getPosition(*m_scroller, &scrollerX, &scrollerY);
+
+               int boxX = 0;
+               int boxY = 0;
+               getPosition(m_box, &boxX, &boxY);
+
+               int scrollOffset = (m_info.isHorizontal ?
+                               (scrollerX - boxX) : (scrollerY - boxY));
+               if (scrollOffset < 0) {
+                       scrollOffset = 0;
+               }
+
+               return scrollOffset;
+       }
+
+       bool ImageGrid::updateScrollOffset()
+       {
+               const int newScrollOffset = calcScrollOffset();
+
+               if (newScrollOffset != m_scrollOffset) {
+                       DLOG("newScrollOffset: %d; m_scrollOffset: %d;",
+                                       newScrollOffset, m_scrollOffset);
+                       m_scrollOffset= newScrollOffset;
+                       return true;
+               }
+
+               return false;
+       }
+
+       void ImageGrid::rotateSlotsRight(const int count)
+       {
+               DLOG("count: %d", count);
+               for (int i = 0; i < count; ++i) {
+                       SlotUPtr slot = std::move(m_slots.back());
+                       m_slots.pop_back();
+                       elm_box_unpack(m_box, slot->getWidget());
+                       elm_box_pack_after(m_box, slot->getWidget(), m_rect1);
+                       m_slots.emplace_front(std::move(slot));
+               }
+       }
+
+       void ImageGrid::rotateSlotsLeft(const int count)
+       {
+               DLOG("count: %d", count);
+               for (int i = 0; i < count; ++i) {
+                       SlotUPtr slot = std::move(m_slots.front());
+                       m_slots.pop_front();
+                       elm_box_unpack(m_box, slot->getWidget());
+                       elm_box_pack_before(m_box, slot->getWidget(), m_rect2);
+                       m_slots.emplace_back(std::move(slot));
+               }
+       }
+
+       void ImageGrid::realizeSlots()
+       {
+               if (m_unrealizeLock == 0) {
+                       for (int i = 0; i < m_slotCount; ++i) {
+                               m_slots[i]->realize(m_beginSlotIndex + i);
+                       }
+               }
+       }
+
+       void ImageGrid::unrealizeSlots(
+                       const int beginSlotOffset, const int endSlotOffset)
+       {
+               if (m_unrealizeLock == 0) {
+                       for (int i = beginSlotOffset; i < endSlotOffset; ++i) {
+                               m_slots[i]->unrealize();
+                       }
+               }
+       }
+
+       void ImageGrid::handleScrolling()
+       {
+               if (m_eventsLock > 0) {
+                       WLOG("Event handling was blocked!");
+                       return;
+               }
+               ++m_eventsLock;
+
+               if (updateScrollOffset() && updateBeginSlotIndex()) {
+                       realizeSlots();
+                       updateRectMins();
+               }
+
+               --m_eventsLock;
+       }
+
+       void ImageGrid::handleResize()
+       {
+               if (m_eventsLock > 0) {
+                       WLOG("Event handling was blocked!");
+                       return;
+               }
+               ++m_eventsLock;
+
+               if (updateScrollerSize()) {
+                       bool needRealize = false;
+
+                       updatePadSizes();
+
+                       if (updateOptimalSlotCount() && updateSlotCount()) {
+                               updateMaxBeginSlotIndex();
+                               needRealize = true;
+                       }
+
+                       updateScrollBias();
+
+                       if (updateBeginSlotIndex()) {
+                               needRealize = true;
+                       }
+
+                       if (needRealize) {
+                               realizeSlots();
+                       }
+                       updateRectMins();
+               }
+
+               --m_eventsLock;
+       }
+
+       void ImageGrid::onScrollerResize(Widget &sender, void *eventInfo)
+       {
+               handleResize();
+       }
+
+       void ImageGrid::onScrollerMove(Widget &sender, void *eventInfo)
+       {
+               handleScrolling();
+       }
+
+       void ImageGrid::onBoxMove(Widget &sender, void *eventInfo)
+       {
+               handleScrolling();
+       }
+}
diff --git a/src/view/ImageViewer.cpp b/src/view/ImageViewer.cpp
new file mode 100644 (file)
index 0000000..4cfccf4
--- /dev/null
@@ -0,0 +1,363 @@
+/*
+ * 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 "view/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);
+       constexpr auto ANIMATION_STOP_POS = 0.999999;
+}}}
+
+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_scroller_single_direction_set(*m_scroller,
+                               ELM_SCROLLER_SINGLE_DIRECTION_NONE);
+               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 >= impl::ANIMATION_STOP_POS) {
+                       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;
+       }
+}
diff --git a/src/view/TouchParser.cpp b/src/view/TouchParser.cpp
new file mode 100644 (file)
index 0000000..ed1d600
--- /dev/null
@@ -0,0 +1,147 @@
+/*
+ * 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 "view/TouchParser.h"
+
+#include "common.h"
+
+namespace gallery { namespace { namespace impl {
+
+       constexpr auto TAP_MOVE_THRESHOLD = 30;
+       constexpr auto FAST_TAP_DISTANCE = 60;
+       constexpr auto FAST_TAP_DELAY_MS = 300;
+}}}
+
+namespace gallery {
+
+       using namespace ucl;
+
+       TouchParser::TouchParser(RefCountObjBase &rc, Widget &eventSource) :
+               RefCountAware(&rc),
+               m_downTime(0),
+               m_downX(0),
+               m_downY(0),
+               m_tapCounter(0),
+               m_isMouseDown(false),
+               m_isTapPossible(false)
+       {
+               eventSource.addEventHandler(WidgetEvent::MOUSE_DOWN,
+                               WEAK_DELEGATE(TouchParser::onMouseDown, asWeak(*this)));
+
+               eventSource.addEventHandler(WidgetEvent::MOUSE_UP,
+                               WEAK_DELEGATE(TouchParser::onMouseUp, asWeak(*this)));
+
+               eventSource.addEventHandler(WidgetEvent::MOUSE_MOVE,
+                               WEAK_DELEGATE(TouchParser::onMouseMove, asWeak(*this)));
+       }
+
+       TouchParser::~TouchParser()
+       {
+       }
+
+       void TouchParser::setTapHandler(TapHandler handler)
+       {
+               m_tapHandler = handler;
+       }
+
+       void TouchParser::setDoubleTapHandler(TapHandler handler)
+       {
+               m_doubleTapHandler = handler;
+       }
+
+       void TouchParser::onMouseDown(Widget &widget, void *eventInfo)
+       {
+               if (m_isMouseDown) {
+                       return;
+               }
+               m_isMouseDown = true;
+
+               const auto e = static_cast<Evas_Event_Mouse_Down *>(eventInfo);
+
+               if (!isFastTap(e->timestamp, e->canvas.x, e->canvas.y)) {
+                       m_tapCounter = 0;
+               } else if (m_doubleTapHandler && (m_tapCounter == 1)) {
+                       m_doubleTapHandler(m_downX, m_downY);
+               }
+
+               m_downTime = e->timestamp;
+               m_downX = e->canvas.x;
+               m_downY = e->canvas.y;
+               m_isTapPossible = true;
+       }
+
+       void TouchParser::onMouseUp(Widget &widget, void *eventInfo)
+       {
+               if (!m_isMouseDown) {
+                       return;
+               }
+               m_isMouseDown = false;
+
+               const auto e = static_cast<Evas_Event_Mouse_Up *>(eventInfo);
+
+               updateIsTapPossible(e->event_flags, e->canvas.x, e->canvas.y);
+
+               if (!m_isTapPossible) {
+                       m_tapCounter = 0;
+                       return;
+               }
+
+               ++m_tapCounter;
+
+               if (m_tapHandler) {
+                       m_tapHandler(e->canvas.x, e->canvas.y);
+               }
+       }
+
+       void TouchParser::onMouseMove(Widget &widget, void *eventInfo)
+       {
+               if (!m_isMouseDown || !m_isTapPossible) {
+                       return;
+               }
+
+               const auto e = static_cast<Evas_Event_Mouse_Move *>(eventInfo);
+
+               updateIsTapPossible(e->event_flags, e->cur.canvas.x, e->cur.canvas.y);
+       }
+
+       void TouchParser::updateIsTapPossible(const int flags,
+                       const int curX, const int curY)
+       {
+               if (!m_isTapPossible) {
+                       return;
+               }
+               if ((flags & EVAS_EVENT_FLAG_ON_HOLD) || (calcDownDistance(curX, curY) >
+                               ELM_SCALE_SIZE(impl::TAP_MOVE_THRESHOLD))) {
+                       m_isTapPossible = false;
+               }
+       }
+
+       bool TouchParser::isFastTap(const UInt curTime,
+                       const int curX, const int curY) const
+       {
+               return (((curTime - m_downTime) <= impl::FAST_TAP_DELAY_MS) &&
+                               (calcDownDistance(curX, curY) <=
+                                               ELM_SCALE_SIZE(impl::FAST_TAP_DISTANCE)));
+       }
+
+       double TouchParser::calcDownDistance(int curX, int curY) const
+       {
+               const auto dx = (curX - m_downX);
+               const auto dy = (curY - m_downY);
+
+               return sqrt(1.0 * dx * dx + 1.0 * dy * dy);
+       }
+}
diff --git a/src/view/common.h b/src/view/common.h
new file mode 100644 (file)
index 0000000..92ae050
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * 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_VIEW_COMMON_H__
+#define __GALLERY_VIEW_COMMON_H__
+
+#include "ucl/gui/stdTheme.h"
+#include "ucl/gui/helpers.h"
+
+#include "view/helpers.h"
+
+#include "../common.h"
+
+namespace gallery {
+
+       constexpr ucl::ElmStyle SCROLLER_STYLE {"effect"};
+}
+
+#endif // __GALLERY_VIEW_COMMON_H__
diff --git a/src/view/helpers.cpp b/src/view/helpers.cpp
new file mode 100644 (file)
index 0000000..77b6810
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * 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 "view/helpers.h"
+
+#include "ucl/gui/Window.h"
+#include "ucl/gui/Naviframe.h"
+
+#include "common.h"
+
+namespace gallery { namespace { namespace impl {
+
+       using namespace ucl;
+
+       constexpr EoDataKey CIRCLE_SURFACE {"gallery,eext,circle,surface"};
+}}}
+
+namespace gallery {
+
+       using namespace ucl;
+
+       Result createCircleSurface(Naviframe &navi)
+       {
+               const auto win = navi.getWindow();
+               if (!win) {
+                       LOG_RETURN(RES_FAIL, "Failed to get Window from Naviframe!");
+               }
+
+               if (win->getData(impl::CIRCLE_SURFACE)) {
+                       LOG_RETURN(RES_ILLEGAL_STATE, "Circle Surface data already set!");
+               }
+
+               const auto sfc = eext_circle_surface_naviframe_add(navi);
+               if (!sfc) {
+                       LOG_RETURN(RES_FAIL,
+                                       "eext_circle_surface_conformant_add() failed!");
+               }
+
+               win->setData(impl::CIRCLE_SURFACE, sfc);
+
+               return RES_OK;
+       }
+
+       Eext_Circle_Surface *getCircleSurface(const ElmWidget &widget)
+       {
+               const auto win = widget.getWindow();
+               if (!win) {
+                       LOG_RETURN_VALUE(RES_FAIL, nullptr,
+                                       "Failed to get Window from widget!");
+               }
+
+               const auto sfc = static_cast<Eext_Circle_Surface *>(
+                               win->getData(impl::CIRCLE_SURFACE));
+               if (!sfc) {
+                       LOG_RETURN_VALUE(RES_FAIL, nullptr,
+                                       "Failed to get Eext_Circle_Surface from window!");
+               }
+
+               return sfc;
+       }
+}
+