TizenRefApp-8222 [Gallery] Implement Page presenter class 62/120662/2
authorIgor Nazarov <i.nazarov@samsung.com>
Wed, 22 Mar 2017 17:24:14 +0000 (19:24 +0200)
committerIgor Nazarov <i.nazarov@samsung.com>
Thu, 23 Mar 2017 14:34:02 +0000 (16:34 +0200)
- Added Page class implementation;
- "view" folder renamed to "presentation";
- ucl::Naviframe/NaviItem refactoring and functionality extension;
- UCL delegation module bug fix - refactoring;
- Other changes in UCL.

Change-Id: I4b05e40d9662635b015f007468cb0e37219edf75

26 files changed:
inc/model/MediaItem.h
inc/presentation/ImageGrid.h [new file with mode: 0644]
inc/presentation/Page.h [new file with mode: 0644]
inc/presentation/Page.hpp [new file with mode: 0644]
inc/view/ImageGrid.h [deleted file]
src/model/MediaItem.cpp
src/presentation/ImageGrid.cpp [new file with mode: 0644]
src/presentation/Page.cpp [new file with mode: 0644]
src/view/ImageGrid.cpp [deleted file]
ucl/inc/ucl/gui/NaviItem.h
ucl/inc/ucl/gui/NaviItem.hpp
ucl/inc/ucl/gui/Naviframe.h
ucl/inc/ucl/gui/Naviframe.hpp
ucl/inc/ucl/gui/Widget.h
ucl/inc/ucl/gui/Widget.hpp
ucl/inc/ucl/gui/WidgetItem.h
ucl/inc/ucl/gui/WidgetItem.hpp
ucl/inc/ucl/gui/Window.h
ucl/inc/ucl/util/delegation/Delegate.h
ucl/inc/ucl/util/delegation/Delegate.hpp
ucl/inc/ucl/util/delegation/Delegate2.h
ucl/inc/ucl/util/delegation/Delegate2.hpp
ucl/inc/ucl/util/delegation/macro.h
ucl/inc/ucl/util/delegation/shortMacro.h
ucl/src/gui/NaviItem.cpp [new file with mode: 0644]
ucl/src/gui/Naviframe.cpp

index d0e1a7d3607bec1297b83099968a12e58a842872..eab79d9a3e5b29ffbad966243a905b6b5715729f 100644 (file)
@@ -35,7 +35,7 @@ namespace gallery {
 
                const std::string &getFilePath() const;
 
-               ucl::Result getThumbnailPath(const ThumbnailPathGetCb &cb) const;
+               ucl::Result getThumbnailPath(ThumbnailPathGetCb cb) const;
                void cancelThumbnailPathGet() const;
 
                ucl::Result removeFile();
diff --git a/inc/presentation/ImageGrid.h b/inc/presentation/ImageGrid.h
new file mode 100644 (file)
index 0000000..083a920
--- /dev/null
@@ -0,0 +1,167 @@
+/*
+ * 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"
+
+namespace gallery {
+
+       UCL_DECLARE_REF_ALIASES(ImageGrid);
+
+       class ImageGrid : public ucl::Widget {
+       public:
+               enum class Type {
+                       HCOMB_3X3
+               };
+
+               class IListener : public ucl::Polymorphic {
+               public:
+                       virtual void onItemRealized(int itemIndex) = 0;
+                       virtual void onItemUnrealized(int itemIndex) = 0;
+               };
+
+               class Builder {
+               public:
+                       Builder();
+                       Builder &setType(Type value);
+                       Builder &setListener(IListener *value);
+                       ImageGridSRef build(Widget &parent) const;
+               private:
+                       Type m_type;
+                       IListener *m_listener;
+               };
+
+               struct ItemParams {
+                       std::string imagePath;
+               };
+
+       public:
+               void setListener(IListener *listener);
+
+               void setItemCount(int count);
+
+               void update();
+
+               ucl::Result updateItem(int itemIndex, const ItemParams &params);
+
+               ucl::Result isItemRealized(int itemIndex);
+
+       private:
+               class Slot;
+               using SlotUPtr = std::unique_ptr<Slot>;
+
+               struct Info;
+               struct HcombInfo;
+
+       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);
+
+               // Initialization
+               void prepare();
+
+               // 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::StyledWidget m_scroller;
+               ucl::ElmWidget m_box;
+               ucl::Widget m_rect1;
+               ucl::Widget m_rect2;
+
+               IListener *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;
+       };
+}
+
+#endif // __GALLERY_VIEW_IMAGE_GRID_H__
diff --git a/inc/presentation/Page.h b/inc/presentation/Page.h
new file mode 100644 (file)
index 0000000..0f93d71
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * 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 {
+
+       UCL_DECLARE_REF_ALIASES(Page);
+
+       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
new file mode 100644 (file)
index 0000000..909e6ed
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * 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 {
+
+       using namespace ucl;
+
+       template <class ITEM_FACTORY>
+       inline Result Page::prepare(ITEM_FACTORY &&makeItem)
+       {
+               m_item = makeItem();
+               if (isNotValid(m_item)) {
+                       UCL_LOG_RETURN(RES_FAIL, "m_item is NULL");
+               }
+               return preparePart2();
+       }
+
+       template <class ...ARGS>
+       inline NaviItem Page::insertAfter(ARGS &&...args)
+       {
+               return m_navi->insertAfter(m_item, std::forward<ARGS>(args)...);
+       }
+
+       template <class ...ARGS>
+       inline NaviItem Page::insertBefore(ARGS &&...args)
+       {
+               return m_navi->insertBefore(m_item, std::forward<ARGS>(args)...);
+       }
+
+       inline 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/view/ImageGrid.h b/inc/view/ImageGrid.h
deleted file mode 100644 (file)
index 083a920..0000000
+++ /dev/null
@@ -1,167 +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_VIEW_IMAGE_GRID_H__
-#define __GALLERY_VIEW_IMAGE_GRID_H__
-
-#include <deque>
-
-#include "ucl/gui/StyledWidget.h"
-
-namespace gallery {
-
-       UCL_DECLARE_REF_ALIASES(ImageGrid);
-
-       class ImageGrid : public ucl::Widget {
-       public:
-               enum class Type {
-                       HCOMB_3X3
-               };
-
-               class IListener : public ucl::Polymorphic {
-               public:
-                       virtual void onItemRealized(int itemIndex) = 0;
-                       virtual void onItemUnrealized(int itemIndex) = 0;
-               };
-
-               class Builder {
-               public:
-                       Builder();
-                       Builder &setType(Type value);
-                       Builder &setListener(IListener *value);
-                       ImageGridSRef build(Widget &parent) const;
-               private:
-                       Type m_type;
-                       IListener *m_listener;
-               };
-
-               struct ItemParams {
-                       std::string imagePath;
-               };
-
-       public:
-               void setListener(IListener *listener);
-
-               void setItemCount(int count);
-
-               void update();
-
-               ucl::Result updateItem(int itemIndex, const ItemParams &params);
-
-               ucl::Result isItemRealized(int itemIndex);
-
-       private:
-               class Slot;
-               using SlotUPtr = std::unique_ptr<Slot>;
-
-               struct Info;
-               struct HcombInfo;
-
-       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);
-
-               // Initialization
-               void prepare();
-
-               // 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::StyledWidget m_scroller;
-               ucl::ElmWidget m_box;
-               ucl::Widget m_rect1;
-               ucl::Widget m_rect2;
-
-               IListener *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;
-       };
-}
-
-#endif // __GALLERY_VIEW_IMAGE_GRID_H__
index 2352623f76b61da6d62cdf118b7955206ccf30b9..92bdaf159a25b0753375ed68642c385a4880665d 100644 (file)
@@ -138,7 +138,7 @@ namespace gallery {
                return RES_OK;
        }
 
-       Result MediaItem::getThumbnailPath(const ThumbnailPathGetCb &cb) const
+       Result MediaItem::getThumbnailPath(ThumbnailPathGetCb cb) const
        {
                if (!cb) {
                        return RES_INVALID_ARGUMENTS;
diff --git a/src/presentation/ImageGrid.cpp b/src/presentation/ImageGrid.cpp
new file mode 100644 (file)
index 0000000..7ce6f7d
--- /dev/null
@@ -0,0 +1,833 @@
+/*
+ * 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 "../common.h"
+
+namespace gallery { namespace { namespace impl {
+
+       using namespace ucl;
+
+       const TString SLOT_PART_FMT = {"swallow.cell_%d"};
+}}}
+
+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(IListener *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 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;
+
+               Info(const std::array<LayoutTheme, 2> &slotThemes,
+                               const std::array<int, 2> &slotLens,
+                               const int scrollLimit, const bool isHorizontal) :
+                       slotThemes(slotThemes),
+                       slotLens(slotLens),
+                       scrollLimit(scrollLimit),
+                       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);
+               }
+
+               HcombInfo(const int totalLength,
+                               const std::array<LayoutTheme, 2> &slotThemes) :
+                       Info(slotThemes, {{(totalLength / 2), ceilDiv<2>(totalLength)}},
+                               (totalLength - 1), true),
+                       totalLength(totalLength)
+               {
+               }
+       };
+
+       // ImageGrid::Slot //
+
+       class ImageGrid::Slot {
+       private:
+               class Item {
+               public:
+                       Item(const ImageGrid &imageGrid, Widget &parent) :
+                               m_imageGrid(imageGrid),
+                               m_image(evas_object_image_filled_add(parent.getEvas())),
+                               m_realizeIndex(-1),
+                               m_wasUpdated(false)
+                       {
+                               show(m_image);
+                       }
+
+                       Widget &getWidget()
+                       {
+                               return m_image;
+                       }
+
+                       void setImageLoadSize(const int value)
+                       {
+                               evas_object_image_load_size_set(m_image, value, value);
+                       }
+
+                       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_image);
+                               }
+                       }
+
+                       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;
+                               }
+
+                               m_wasUpdated = true;
+
+                               if (isEmpty(params.imagePath)) {
+                                       makeTransparent(m_image);
+                                       return true;
+                               }
+
+                               evas_object_image_file_set(m_image,
+                                               params.imagePath.c_str(), NULL);
+
+                               int w, h;
+                               getSize(m_image, &w, &h);
+                               m_image.setARHint(WidgetARHint::NEITHER, w, h);
+
+                               makeWhite(m_image);
+
+                               return true;
+                       }
+
+               private:
+                       const ImageGrid &m_imageGrid;
+                       Widget m_image;
+                       int m_realizeIndex;
+                       bool m_wasUpdated;
+               };
+
+       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 (!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(new 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<std::unique_ptr<Item>> m_items;
+               Layout m_layout;
+               bool m_isRealized;
+       };
+
+       // ImageGrid //
+
+       ImageGrid::ImageGrid(RefCountObjBase *const rc, const Type type,
+                       Evas_Object *const scroller) :
+               Widget(rc, scroller, true),
+               m_info(getInfo(type)),
+
+               m_scroller(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_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)
+       {
+               prepare();
+
+               updateSlotCount();
+
+               updatePadSizes();
+               updateScrollBias();
+               updateRectMins();
+       }
+
+       const ImageGrid::Info &ImageGrid::getInfo(const Type type)
+       {
+               switch (type) {
+               case Type::HCOMB_3X3:
+               default: {
+                               static HcombInfo info{3, {{
+                                               {"layout", "gallery_image_grid", "hcomb_3x3_even"},
+                                               {"layout", "gallery_image_grid", "hcomb_3x3_odd"}}}};
+                               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);
+
+               expandAndFill(m_scroller);
+               if (m_info.isHorizontal) {
+                       elm_scroller_page_scroll_limit_set(
+                                       m_scroller, m_info.scrollLimit, 0);
+               } else {
+                       elm_scroller_page_scroll_limit_set(
+                                       m_scroller, 0, m_info.scrollLimit);
+               }
+               show(m_scroller);
+
+               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::setListener(IListener *const listener)
+       {
+               m_listener = listener;
+       }
+
+       void ImageGrid::setItemCount(const int count)
+       {
+               if (m_itemCount == count) {
+                       return;
+               }
+
+               unrealizeSlots(0, m_slotCount);
+
+               m_itemCount = count;
+
+               if (updateMaxSlotCount()) {
+                       updateSlotCount();
+                       if (updateMaxBeginSlotIndex()) {
+                               updateBeginSlotIndex();
+                       }
+               }
+
+               realizeSlots();
+               updateRectMins();
+       }
+
+       void ImageGrid::update()
+       {
+               unrealizeSlots(0, m_slotCount);
+               realizeSlots();
+       }
+
+       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)
+       {
+               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)
+       {
+               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);
+
+               const int slotOffset = (slotIndex - m_beginSlotIndex);
+               if ((slotOffset < 0) || (slotOffset >= m_slotCount)) {
+                       return RES_FALSE;
+               }
+
+               return func(*m_slots[slotOffset], itemOffset);
+       }
+
+       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);
+                               if (m_info.isHorizontal) {
+                                       elm_scroller_page_size_set(m_scroller, m_slotSize, 0);
+                               } else {
+                                       elm_scroller_page_size_set(m_scroller, 0, m_slotSize);
+                               }
+                       }
+
+                       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 - 1) + (m_slotSize - 1)) /
+                               m_slotSize + 1) * 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 -
+                               ((m_scrollerSize / m_slotSize) * m_slotSize));
+
+               m_padSize1 = (spaceSize / 2);
+               m_padSize2 = (spaceSize - m_padSize1 + m_slotSize);
+       }
+
+       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()
+       {
+               for (int i = 0; i < m_slotCount; ++i) {
+                       m_slots[i]->realize(m_beginSlotIndex + i);
+               }
+       }
+
+       void ImageGrid::unrealizeSlots(
+                       const int beginSlotOffset, const int endSlotOffset)
+       {
+               for (int i = beginSlotOffset; i < endSlotOffset; ++i) {
+                       m_slots[i]->unrealize();
+               }
+       }
+
+       void ImageGrid::handleScrolling()
+       {
+               if (updateScrollOffset() && updateBeginSlotIndex()) {
+                       realizeSlots();
+                       updateRectMins();
+               }
+       }
+
+       void ImageGrid::handleResize()
+       {
+               if (updateScrollerSize()) {
+                       bool needRealize = false;
+
+                       updatePadSizes();
+
+                       if (updateOptimalSlotCount() && updateSlotCount()) {
+                               updateMaxBeginSlotIndex();
+                               needRealize = true;
+                       }
+
+                       updateScrollBias();
+
+                       if (updateBeginSlotIndex()) {
+                               needRealize = true;
+                       }
+
+                       if (needRealize) {
+                               realizeSlots();
+                       }
+                       updateRectMins();
+               }
+       }
+
+       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/Page.cpp b/src/presentation/Page.cpp
new file mode 100644 (file)
index 0000000..5761cc5
--- /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 "presentation/Page.h"
+
+#include <efl_extension.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,
+                       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()) {
+                       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 (isValid(m_item)) {
+                       m_item.del();
+                       dispatchTopPageChanged();
+               }
+       }
+
+       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/view/ImageGrid.cpp b/src/view/ImageGrid.cpp
deleted file mode 100644 (file)
index 30b1a23..0000000
+++ /dev/null
@@ -1,833 +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 "view/ImageGrid.h"
-
-#include <array>
-#include <vector>
-
-#include "ucl/gui/Layout.h"
-
-#include "../common.h"
-
-namespace gallery { namespace { namespace impl {
-
-       using namespace ucl;
-
-       const TString SLOT_PART_FMT = {"swallow.cell_%d"};
-}}}
-
-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(IListener *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 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;
-
-               Info(const std::array<LayoutTheme, 2> &slotThemes,
-                               const std::array<int, 2> &slotLens,
-                               const int scrollLimit, const bool isHorizontal) :
-                       slotThemes(slotThemes),
-                       slotLens(slotLens),
-                       scrollLimit(scrollLimit),
-                       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);
-               }
-
-               HcombInfo(const int totalLength,
-                               const std::array<LayoutTheme, 2> &slotThemes) :
-                       Info(slotThemes, {{(totalLength / 2), ceilDiv<2>(totalLength)}},
-                               (totalLength - 1), true),
-                       totalLength(totalLength)
-               {
-               }
-       };
-
-       // ImageGrid::Slot //
-
-       class ImageGrid::Slot {
-       private:
-               class Item {
-               public:
-                       Item(const ImageGrid &imageGrid, Widget &parent) :
-                               m_imageGrid(imageGrid),
-                               m_image(evas_object_image_filled_add(parent.getEvas())),
-                               m_realizeIndex(-1),
-                               m_wasUpdated(false)
-                       {
-                               show(m_image);
-                       }
-
-                       Widget &getWidget()
-                       {
-                               return m_image;
-                       }
-
-                       void setImageLoadSize(const int value)
-                       {
-                               evas_object_image_load_size_set(m_image, value, value);
-                       }
-
-                       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_image);
-                               }
-                       }
-
-                       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;
-                               }
-
-                               m_wasUpdated = true;
-
-                               if (isEmpty(params.imagePath)) {
-                                       makeTransparent(m_image);
-                                       return true;
-                               }
-
-                               evas_object_image_file_set(m_image,
-                                               params.imagePath.c_str(), NULL);
-
-                               int w, h;
-                               getSize(m_image, &w, &h);
-                               m_image.setARHint(WidgetARHint::NEITHER, w, h);
-
-                               makeWhite(m_image);
-
-                               return true;
-                       }
-
-               private:
-                       const ImageGrid &m_imageGrid;
-                       Widget m_image;
-                       int m_realizeIndex;
-                       bool m_wasUpdated;
-               };
-
-       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 (!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(new 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<std::unique_ptr<Item>> m_items;
-               Layout m_layout;
-               bool m_isRealized;
-       };
-
-       // ImageGrid //
-
-       ImageGrid::ImageGrid(RefCountObjBase *const rc, const Type type,
-                       Evas_Object *const scroller) :
-               Widget(rc, scroller, true),
-               m_info(getInfo(type)),
-
-               m_scroller(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_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)
-       {
-               prepare();
-
-               updateSlotCount();
-
-               updatePadSizes();
-               updateScrollBias();
-               updateRectMins();
-       }
-
-       const ImageGrid::Info &ImageGrid::getInfo(const Type type)
-       {
-               switch (type) {
-               case Type::HCOMB_3X3:
-               default: {
-                               static HcombInfo info{3, {{
-                                               {"layout", "gallery_image_grid", "hcomb_3x3_even"},
-                                               {"layout", "gallery_image_grid", "hcomb_3x3_odd"}}}};
-                               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);
-
-               expandAndFill(m_scroller);
-               if (m_info.isHorizontal) {
-                       elm_scroller_page_scroll_limit_set(
-                                       m_scroller, m_info.scrollLimit, 0);
-               } else {
-                       elm_scroller_page_scroll_limit_set(
-                                       m_scroller, 0, m_info.scrollLimit);
-               }
-               show(m_scroller);
-
-               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::setListener(IListener *const listener)
-       {
-               m_listener = listener;
-       }
-
-       void ImageGrid::setItemCount(const int count)
-       {
-               if (m_itemCount == count) {
-                       return;
-               }
-
-               unrealizeSlots(0, m_slotCount);
-
-               m_itemCount = count;
-
-               if (updateMaxSlotCount()) {
-                       updateSlotCount();
-                       if (updateMaxBeginSlotIndex()) {
-                               updateBeginSlotIndex();
-                       }
-               }
-
-               realizeSlots();
-               updateRectMins();
-       }
-
-       void ImageGrid::update()
-       {
-               unrealizeSlots(0, m_slotCount);
-               realizeSlots();
-       }
-
-       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)
-       {
-               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)
-       {
-               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);
-
-               const int slotOffset = (slotIndex - m_beginSlotIndex);
-               if ((slotOffset < 0) || (slotOffset >= m_slotCount)) {
-                       return RES_FALSE;
-               }
-
-               return func(*m_slots[slotOffset], itemOffset);
-       }
-
-       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);
-                               if (m_info.isHorizontal) {
-                                       elm_scroller_page_size_set(m_scroller, m_slotSize, 0);
-                               } else {
-                                       elm_scroller_page_size_set(m_scroller, 0, m_slotSize);
-                               }
-                       }
-
-                       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 - 1) + (m_slotSize - 1)) /
-                               m_slotSize + 1) * 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 -
-                               ((m_scrollerSize / m_slotSize) * m_slotSize));
-
-               m_padSize1 = (spaceSize / 2);
-               m_padSize2 = (spaceSize - m_padSize1 + m_slotSize);
-       }
-
-       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()
-       {
-               for (int i = 0; i < m_slotCount; ++i) {
-                       m_slots[i]->realize(m_beginSlotIndex + i);
-               }
-       }
-
-       void ImageGrid::unrealizeSlots(
-                       const int beginSlotOffset, const int endSlotOffset)
-       {
-               for (int i = beginSlotOffset; i < endSlotOffset; ++i) {
-                       m_slots[i]->unrealize();
-               }
-       }
-
-       void ImageGrid::handleScrolling()
-       {
-               if (updateScrollOffset() && updateBeginSlotIndex()) {
-                       realizeSlots();
-                       updateRectMins();
-               }
-       }
-
-       void ImageGrid::handleResize()
-       {
-               if (updateScrollerSize()) {
-                       bool needRealize = false;
-
-                       updatePadSizes();
-
-                       if (updateOptimalSlotCount() && updateSlotCount()) {
-                               updateMaxBeginSlotIndex();
-                               needRealize = true;
-                       }
-
-                       updateScrollBias();
-
-                       if (updateBeginSlotIndex()) {
-                               needRealize = true;
-                       }
-
-                       if (needRealize) {
-                               realizeSlots();
-                       }
-                       updateRectMins();
-               }
-       }
-
-       void ImageGrid::onScrollerResize(Widget &sender, void *eventInfo)
-       {
-               handleResize();
-       }
-
-       void ImageGrid::onScrollerMove(Widget &sender, void *eventInfo)
-       {
-               handleScrolling();
-       }
-
-       void ImageGrid::onBoxMove(Widget &sender, void *eventInfo)
-       {
-               handleScrolling();
-       }
-}
index c8a5c1e5cccff481f7ff79a9401c194c419344d7..1161847002ea8f94e8752deea29fd01b0cc1f0e0 100644 (file)
@@ -21,7 +21,7 @@
 
 namespace ucl {
 
-       class NaviItem : public WidgetItem {
+       class NaviItem final : public WidgetItem {
        public:
                using PopHandler = Delegate<Eina_Bool(Elm_Object_Item *)>;
 
index 1191e2e8ef60466f51938706726bff0c29cbb217..6b33fe45f695532b8ae68dbf686fb4dcd1821edf 100644 (file)
@@ -22,16 +22,6 @@ namespace ucl {
                                handler.getStubA(), handler.getData());
        }
 
-       inline void NaviItem::popTo() const
-       {
-               elm_naviframe_item_pop_to(getIt());
-       }
-
-       inline void NaviItem::promote() const
-       {
-               elm_naviframe_item_promote(getIt());
-       }
-
        inline void NaviItem::setTitleEnabled(
                        const bool value, const bool useTransition) const
        {
index b892beec043d70c1a32e650bb9d7528a7714cb9a..4471ea15ba16e9ca364642e5928ca630039c7293 100644 (file)
 
 namespace ucl {
 
+       constexpr SmartEvent NAVI_TRANSITION_STARTED {"ucl,transition,started"};
+       constexpr SmartEvent NAVI_TRANSITION_FINISHED {"transition,finished"};
+
        UCL_DECLARE_REF_ALIASES(Naviframe);
 
-       class Naviframe : public StyledWidget {
+       class Naviframe final : public StyledWidget {
        public:
-               static constexpr SmartEvent TRANSITION_FINISHED {"transition,finished"};
-
                class Builder {
                public:
                        Builder();
@@ -47,6 +48,8 @@ namespace ucl {
                friend class RefCountObj<Naviframe>;
                using StyledWidget::StyledWidget;
 
+               bool isInTransition() const;
+
                void setAutoBackBtn(bool value);
                bool isAutoBackBtn() const;
 
@@ -63,18 +66,18 @@ namespace ucl {
                NaviItem push(const TString &title, Evas_Object *content);
                NaviItem push(Evas_Object *content);
 
-               NaviItem insertAfter(const TString &title, NaviItem after,
+               NaviItem insertAfter(NaviItem after, const TString &title,
                                Evas_Object *backBtn, Evas_Object *moreBtn,
                                Evas_Object *content, ElmStyle style);
-               NaviItem insertAfter(const TString &title, NaviItem after,
+               NaviItem insertAfter(NaviItem after, const TString &title,
                                Evas_Object *content);
                NaviItem insertAfter(NaviItem after,
                                Evas_Object *content);
 
-               NaviItem insertBefore(const TString &title, NaviItem before,
+               NaviItem insertBefore(NaviItem before, const TString &title,
                                Evas_Object *backBtn, Evas_Object *moreBtn,
                                Evas_Object *content, ElmStyle style);
-               NaviItem insertBefore(const TString &title, NaviItem before,
+               NaviItem insertBefore(NaviItem before, const TString &title,
                                Evas_Object *content);
                NaviItem insertBefore(NaviItem before,
                                Evas_Object *content);
@@ -82,6 +85,18 @@ namespace ucl {
                NaviItem getTopItem()const;
                NaviItem getBottomItem() const;
                std::vector<NaviItem> getItems() const;
+
+       private:
+               friend class RefCountObj<Naviframe>;
+               friend class NaviItem;
+               Naviframe(RefCountObjBase &rc, Evas_Object *eo, bool isOwner = false);
+
+               void startTransition();
+
+               void onTransitionFinished(Widget &widget, void *eventInfo);
+
+       private:
+               bool m_isInTransition;
        };
 }
 
index 5b695942f87c31b4b76c6583ebd7351d65258818..5d67bc4ebca683ae84da65e4ffac2fcdb06a9553 100644 (file)
@@ -46,6 +46,11 @@ namespace ucl {
 
        // Naviframe //
 
+       inline bool Naviframe::isInTransition() const
+       {
+               return m_isInTransition;
+       }
+
        inline void Naviframe::setAutoBackBtn(const bool value)
        {
                elm_naviframe_prev_btn_auto_pushed_set(getEo(), toEina(value));
@@ -78,7 +83,11 @@ namespace ucl {
 
        inline Evas_Object *Naviframe::pop()
        {
-               return elm_naviframe_item_pop(getEo());
+               auto result = elm_naviframe_item_pop(getEo());
+               if (isValid(getBottomItem())) {
+                       startTransition();
+               }
+               return result;
        }
 
        inline NaviItem Naviframe::push(const TString &title,
@@ -88,6 +97,9 @@ namespace ucl {
                auto result = NaviItem(elm_naviframe_item_push(getEo(),
                                nullptr, backBtn, moreBtn, content, style.name));
                result.setTitle(title);
+               if (result != getBottomItem()) {
+                       startTransition();
+               }
                return result;
        }
 
@@ -102,8 +114,8 @@ namespace ucl {
                return push(nullptr, nullptr, nullptr, content, nullptr);
        }
 
-       inline NaviItem Naviframe::insertAfter(const TString &title,
-                       NaviItem after,
+       inline NaviItem Naviframe::insertAfter(NaviItem after,
+                       const TString &title,
                        Evas_Object *const backBtn, Evas_Object *const moreBtn,
                        Evas_Object *const content, const ElmStyle style)
        {
@@ -113,20 +125,20 @@ namespace ucl {
                return result;
        }
 
-       inline NaviItem Naviframe::insertAfter(const TString &title,
-                       NaviItem after, Evas_Object *const content)
+       inline NaviItem Naviframe::insertAfter(NaviItem after,
+                       const TString &title, Evas_Object *const content)
        {
-               return insertAfter(title, after, nullptr, nullptr, content, nullptr);
+               return insertAfter(after, title, nullptr, nullptr, content, nullptr);
        }
 
        inline NaviItem Naviframe::insertAfter(NaviItem after,
                        Evas_Object *const content)
        {
-               return insertAfter(nullptr, after, nullptr, nullptr, content, nullptr);
+               return insertAfter(after, nullptr, nullptr, nullptr, content, nullptr);
        }
 
-       inline NaviItem Naviframe::insertBefore(const TString &title,
-                       NaviItem before,
+       inline NaviItem Naviframe::insertBefore(NaviItem before,
+                       const TString &title,
                        Evas_Object *const backBtn, Evas_Object *const moreBtn,
                        Evas_Object *const content, const ElmStyle style)
        {
@@ -136,16 +148,16 @@ namespace ucl {
                return result;
        }
 
-       inline NaviItem Naviframe::insertBefore(const TString &title,
-                       NaviItem before, Evas_Object *const content)
+       inline NaviItem Naviframe::insertBefore(NaviItem before,
+                       const TString &title, Evas_Object *const content)
        {
-               return insertAfter(title, before, nullptr, nullptr, content, nullptr);
+               return insertAfter(before, title, nullptr, nullptr, content, nullptr);
        }
 
        inline NaviItem Naviframe::insertBefore(NaviItem before,
                        Evas_Object *const content)
        {
-               return insertAfter(nullptr, before, nullptr, nullptr, content, nullptr);
+               return insertAfter(before, nullptr, nullptr, nullptr, content, nullptr);
        }
 
        inline NaviItem Naviframe::getTopItem()const
index e95c5d857c62c4f7ce5bb091bef9fcfa2e58daa2..3e6afa5784fde33d062c40daff509d7a11e452ca 100644 (file)
@@ -55,6 +55,8 @@ namespace ucl {
                void delEventHandler(WidgetEvent event, WidgetEventHandler handler);
                void delEventHandler(SmartEvent event, WidgetEventHandler handler);
 
+               void callSmartEvent(SmartEvent event, void *eventInfo = nullptr);
+
                void markForDeletion();
 
                void setVisible(bool value);
index 3bd2f4f80b5517cb3ff8dedb6e9a2b8f8caacaf5..996558a667e32d5b140716890c6d11352f3748e5 100644 (file)
@@ -59,6 +59,11 @@ namespace ucl {
                return evas_object_evas_get(getEo());
        }
 
+       inline void Widget::callSmartEvent(SmartEvent event, void *eventInfo)
+       {
+               evas_object_smart_callback_call(getEo(), event, eventInfo);
+       }
+
        inline void Widget::markForDeletion()
        {
                evas_object_del(getEo());
index 914ce4c5a391bbd846144e8e66036d576b97b34f..db769656219d23fef3b4c3c247ba60495b9cb82e 100644 (file)
@@ -31,6 +31,8 @@ namespace ucl {
 
                operator Elm_Object_Item *() const;
 
+               Evas_Object *getWidget() const;
+
                void setDelCallback(Evas_Smart_Cb cb) const;
 
                void del();
@@ -67,6 +69,9 @@ namespace ucl {
        void disable(WidgetItem item);
 
        bool isValid(WidgetItem item);
+
+       bool operator==(WidgetItem lhs, WidgetItem rhs);
+       bool operator!=(WidgetItem lhs, WidgetItem rhs);
 }
 
 #include "WidgetItem.hpp"
index 577a02f6bbcbdb4f8a90381fded86f47fc6eb52d..d4ba2692d17834496fa48c1a9df6afc159e94faf 100644 (file)
@@ -41,6 +41,11 @@ namespace ucl {
                return m_it;
        }
 
+       inline Evas_Object *WidgetItem::getWidget() const
+       {
+               return elm_object_item_widget_get(getIt());
+       }
+
        inline void WidgetItem::setDelCallback(const Evas_Smart_Cb cb) const
        {
                elm_object_item_del_cb_set(getIt(), cb);
@@ -121,18 +126,28 @@ namespace ucl {
 
        // Non-member functions //
 
-       inline void enable(WidgetItem item)
+       inline void enable(const WidgetItem item)
        {
                item.setEnabled(true);
        }
 
-       inline void disable(WidgetItem item)
+       inline void disable(const WidgetItem item)
        {
                item.setEnabled(false);
        }
 
-       inline bool isValid(WidgetItem item)
+       inline bool isValid(const WidgetItem item)
        {
                return !!item.getIt();
        }
+
+       inline bool operator==(const WidgetItem lhs, const WidgetItem rhs)
+       {
+               return (lhs.getIt() == rhs.getIt());
+       }
+
+       inline bool operator!=(const WidgetItem lhs, const WidgetItem rhs)
+       {
+               return (lhs.getIt() != rhs.getIt());
+       }
 }
index 384a653b87ca3923dfc3a4d3f0099b02d331ee4b..7a617a0994cf8f021dfca24587d2d6ba05a750b0 100644 (file)
 
 namespace ucl {
 
+       constexpr SmartEvent WIN_ROTATION_CHANGED {"wm,rotation,changed"};
+
        UCL_DECLARE_REF_ALIASES(Window);
 
-       class Window : public ElmWidget {
+       class Window final : public ElmWidget {
        public:
-               static constexpr SmartEvent ROTATION_CHANGED {"wm,rotation,changed"};
-
                enum class Type {
                        BASIC = ELM_WIN_BASIC
                };
index abd49794d4d8ad49b8bbd969ba52f047cbe6b81d..fd53a0ad4f0ac503946f659a3d732676dfbd01f5 100644 (file)
@@ -35,14 +35,14 @@ namespace ucl {
                static Delegate make(const CLASS *data) noexcept;
 
                template <class CLASS, R(*FUNC)(CLASS &, ARGS...)>
-               static Delegate make(CLASS &data) noexcept;
+               static Delegate makeA(CLASS &data) noexcept;
                template <class CLASS, R(*FUNC)(ARGS..., CLASS &)>
-               static Delegate make(CLASS &data) noexcept;
+               static Delegate makeB(CLASS &data) noexcept;
 
                template <class HANDLE, R(*FUNC)(HANDLE, ARGS...)>
-               static Delegate make(HANDLE data) noexcept;
+               static Delegate makeA(HANDLE data) noexcept;
                template <class HANDLE, R(*FUNC)(ARGS..., HANDLE)>
-               static Delegate make(HANDLE data) noexcept;
+               static Delegate makeB(HANDLE data) noexcept;
 
                template <R(*FUNC)(ARGS...)>
                static Delegate make() noexcept;
index 19a2483dce59362a5f2ad5e66d92cfe8a22fc864..5f7be3d49cc8e6d2365b60b7ffdb3f11f27a8c4f 100644 (file)
@@ -37,7 +37,7 @@ namespace ucl {
        template <class R, class ...ARGS>
        template <class CLASS, R(*FUNC)(CLASS &, ARGS...)>
        inline Delegate<R(ARGS...)>
-                       Delegate<R(ARGS...)>::make(CLASS &data) noexcept
+                       Delegate<R(ARGS...)>::makeA(CLASS &data) noexcept
        {
                return {const_cast<void *>(static_cast<const void *>(&data)),
                                Delegate::Cb::template stubA2A<CLASS, FUNC>};
@@ -46,7 +46,7 @@ namespace ucl {
        template <class R, class ...ARGS>
        template <class CLASS, R(*FUNC)(ARGS..., CLASS &)>
        inline Delegate<R(ARGS...)>
-                       Delegate<R(ARGS...)>::make(CLASS &data) noexcept
+                       Delegate<R(ARGS...)>::makeB(CLASS &data) noexcept
        {
                return {const_cast<void *>(static_cast<const void *>(&data)),
                                Delegate::Cb::template stubA2B<CLASS, FUNC>};
@@ -55,7 +55,7 @@ namespace ucl {
        template <class R, class ...ARGS>
        template <class HANDLE, R(*FUNC)(HANDLE, ARGS...)>
        inline Delegate<R(ARGS...)>
-                       Delegate<R(ARGS...)>::make(const HANDLE data) noexcept
+                       Delegate<R(ARGS...)>::makeA(const HANDLE data) noexcept
        {
                return {const_cast<void *>(static_cast<const void *>(data)),
                                Delegate::Cb::template stubA2A<HANDLE, FUNC>};
@@ -64,7 +64,7 @@ namespace ucl {
        template <class R, class ...ARGS>
        template <class HANDLE, R(*FUNC)(ARGS..., HANDLE)>
        inline Delegate<R(ARGS...)>
-                       Delegate<R(ARGS...)>::make(const HANDLE data) noexcept
+                       Delegate<R(ARGS...)>::makeB(const HANDLE data) noexcept
        {
                return {const_cast<void *>(static_cast<const void *>(data)),
                                Delegate::Cb::template stubA2B<HANDLE, FUNC>};
index 11af82a33c76c889762e85ce2866094f42e4dda8..c49d31c9fc6b2d293cbe68bd73cd99c128d40d79 100644 (file)
@@ -35,14 +35,14 @@ namespace ucl {
                static Delegate2 make(const CLASS *data) noexcept;
 
                template <class CLASS, R(*FUNC)(CLASS &, ARGS...)>
-               static Delegate2 make(CLASS &data) noexcept;
+               static Delegate2 makeA(CLASS &data) noexcept;
                template <class CLASS, R(*FUNC)(ARGS..., CLASS &)>
-               static Delegate2 make(CLASS &data) noexcept;
+               static Delegate2 makeB(CLASS &data) noexcept;
 
                template <class HANDLE, R(*FUNC)(HANDLE, ARGS...)>
-               static Delegate2 make(HANDLE data) noexcept;
+               static Delegate2 makeA(HANDLE data) noexcept;
                template <class HANDLE, R(*FUNC)(ARGS..., HANDLE)>
-               static Delegate2 make(HANDLE data) noexcept;
+               static Delegate2 makeB(HANDLE data) noexcept;
 
                template <R(*FUNC)(ARGS...)>
                static Delegate2 make() noexcept;
index bba1fc88122a36aebeebac7e6e3d759a7dfb5e07..4d7786031857a4c5f1c1fea504d1eaa1ac25bb1d 100644 (file)
@@ -39,7 +39,7 @@ namespace ucl {
        template <class R, class ...ARGS>
        template <class CLASS, R(*FUNC)(CLASS &, ARGS...)>
        inline Delegate2<R(ARGS...)>
-                       Delegate2<R(ARGS...)>::make(CLASS &data) noexcept
+                       Delegate2<R(ARGS...)>::makeA(CLASS &data) noexcept
        {
                return {const_cast<void *>(static_cast<const void *>(&data)),
                                Delegate2::Cb::template stubA2A<CLASS, FUNC>,
@@ -49,7 +49,7 @@ namespace ucl {
        template <class R, class ...ARGS>
        template <class CLASS, R(*FUNC)(ARGS..., CLASS &)>
        inline Delegate2<R(ARGS...)>
-                       Delegate2<R(ARGS...)>::make(CLASS &data) noexcept
+                       Delegate2<R(ARGS...)>::makeB(CLASS &data) noexcept
        {
                return {const_cast<void *>(static_cast<const void *>(&data)),
                                Delegate2::Cb::template stubA2B<CLASS, FUNC>,
@@ -59,7 +59,7 @@ namespace ucl {
        template <class R, class ...ARGS>
        template <class HANDLE, R(*FUNC)(HANDLE, ARGS...)>
        inline Delegate2<R(ARGS...)>
-                       Delegate2<R(ARGS...)>::make(const HANDLE data) noexcept
+                       Delegate2<R(ARGS...)>::makeA(const HANDLE data) noexcept
        {
                return {const_cast<void *>(static_cast<const void *>(data)),
                                Delegate2::Cb::template stubA2A<HANDLE, FUNC>,
@@ -69,7 +69,7 @@ namespace ucl {
        template <class R, class ...ARGS>
        template <class HANDLE, R(*FUNC)(ARGS..., HANDLE)>
        inline Delegate2<R(ARGS...)>
-                       Delegate2<R(ARGS...)>::make(const HANDLE data) noexcept
+                       Delegate2<R(ARGS...)>::makeB(const HANDLE data) noexcept
        {
                return {const_cast<void *>(static_cast<const void *>(data)),
                                Delegate2::Cb::template stubA2B<HANDLE, FUNC>,
index dfd95876af3a920d328c026d53e18ed7a96be053..62bf88ff44f7cc6d853d1c4e4cd0a3552cd4883b 100644 (file)
@@ -27,6 +27,9 @@
 #define _UCL_DELEGATE(DELEGATE, FUNC, DATA) (_UCL_AFS(DELEGATE, FUNC):: \
                Type::make<_UCL_AFS(DELEGATE, FUNC)::Data, &FUNC>(DATA))
 
+#define _UCL_DELEGATE_A(DELEGATE, FUNC, DATA) (_UCL_AFS(DELEGATE, FUNC):: \
+               Type::makeA<_UCL_AFS(DELEGATE, FUNC)::Data, &FUNC>(DATA))
+
 #define _UCL_DELEGATE_V(DELEGATE, FUNC) \
                (::ucl::AutoFuncSig<DELEGATE, void, decltype(&FUNC)>::\
                        Type::make<&FUNC>())
 // Helper macro to automatically generate Delegate objects //
 
 #define UCL_DELEGATE(FUNC, DATA) _UCL_DELEGATE(::ucl::Delegate, FUNC, DATA)
+#define UCL_DELEGATE_A(FUNC, DATA) _UCL_DELEGATE_A(::ucl::Delegate, FUNC, DATA)
 #define UCL_DELEGATE_V(FUNC) _UCL_DELEGATE_V(::ucl::Delegate, FUNC)
 
 // Helper macro to automatically generate Delegate2 objects //
 
 #define UCL_DELEGATE2(FUNC, DATA) _UCL_DELEGATE(::ucl::Delegate2, FUNC, DATA)
+#define UCL_DELEGATE2_A(FUNC, DATA) \
+               _UCL_DELEGATE_A(::ucl::Delegate2, FUNC, DATA)
 #define UCL_DELEGATE2_V(FUNC) _UCL_DELEGATE_V(::ucl::Delegate2, FUNC)
 
 // Helper macro to automatically generate Callback stubs //
index 33d0a2f89824c8747095b879a5e439bfe3bf9062..3837977d42a8219d70b0bcc16cb8b509aabfda22 100644 (file)
 
 // Helper macro to automatically generate Delegate objects //
 
-#define DELEGATE(FUNC, DATA)  UCL_DELEGATE(FUNC, DATA)
-#define DELEGATE_V(FUNC)      UCL_DELEGATE_V(FUNC)
+#define DELEGATE(FUNC, DATA)    UCL_DELEGATE(FUNC, DATA)
+#define DELEGATE_A(FUNC, DATA)  UCL_DELEGATE_A(FUNC, DATA)
+#define DELEGATE_V(FUNC)        UCL_DELEGATE_V(FUNC)
 
 // Helper macro to automatically generate Delegate2 objects //
 
-#define DELEGATE2(FUNC, DATA)  UCL_DELEGATE2(FUNC, DATA)
-#define DELEGATE2_V(FUNC)      UCL_DELEGATE2_V(FUNC)
+#define DELEGATE2(FUNC, DATA)    UCL_DELEGATE2(FUNC, DATA)
+#define DELEGATE2_A(FUNC, DATA)  UCL_DELEGATE2_A(FUNC, DATA)
+#define DELEGATE2_V(FUNC)        UCL_DELEGATE2_V(FUNC)
 
 // Helper macro to automatically generate Callback stubs //
 
diff --git a/ucl/src/gui/NaviItem.cpp b/ucl/src/gui/NaviItem.cpp
new file mode 100644 (file)
index 0000000..052a8ea
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * 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/gui/NaviItem.h"
+
+#include "ucl/gui/Naviframe.h"
+#include "ucl/gui/helpers.h"
+
+namespace ucl {
+
+       void NaviItem::popTo() const
+       {
+               const auto navi = dynamicCast<Naviframe>(getWidget());
+               const bool needStartTransition =
+                               (navi && (navi->getTopItem() != *this));
+
+               elm_naviframe_item_pop_to(getIt());
+
+               if (needStartTransition) {
+                       navi->startTransition();
+               }
+       }
+
+       void NaviItem::promote() const
+       {
+               const auto navi = dynamicCast<Naviframe>(getWidget());
+               const bool needStartTransition =
+                               (navi && (navi->getTopItem() != *this));
+
+               elm_naviframe_item_promote(getIt());
+
+               if (needStartTransition) {
+                       navi->startTransition();
+               }
+       }
+}
index 73a39fa64e9482fda6ba807c98d47e74f46415bd..6527094561eefb58e5fb92cecc61b6e7b2d521af 100644 (file)
@@ -44,4 +44,27 @@ namespace ucl {
 
                return result;
        }
+
+       // Naviframe //
+
+       Naviframe::Naviframe(RefCountObjBase &rc, Evas_Object *eo, bool isOwner) :
+               StyledWidget(&rc, eo, isOwner),
+               m_isInTransition(false)
+       {
+               addEventHandler(NAVI_TRANSITION_FINISHED, WEAK_DELEGATE(
+                               Naviframe::onTransitionFinished, asWeak(*this)));
+       }
+
+       void Naviframe::startTransition()
+       {
+               if (!m_isInTransition) {
+                       m_isInTransition = true;
+                       callSmartEvent(NAVI_TRANSITION_STARTED);
+               }
+       }
+
+       void Naviframe::onTransitionFinished(Widget &widget, void *eventInfo)
+       {
+               m_isInTransition = false;
+       }
 }