--- /dev/null
+/*
+ * Copyright 2017 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://floralicense.org/license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __GALLERY_PRESENTERS_ATSPI_HIGHLIGH_HELPER_H__
+#define __GALLERY_PRESENTERS_ATSPI_HIGHLIGH_HELPER_H__
+
+#include "Presenter.h"
+
+namespace gallery {
+
+ UCL_DECLARE_REF_ALIASES(AtspiHighlightHelper);
+
+ class AtspiHighlightHelper final : public Presenter {
+ public:
+ using EventHandler = ucl::WeakDelegate<Elm_Interface_Atspi_Accessible *(
+ ucl::Widget &widget, Elm_Atspi_Relation_Type flowRelation)>;
+
+ public:
+ static AtspiHighlightHelperSRef newInstance(ucl::ElmWidget &rootWidget);
+
+ void setEventHandler(EventHandler handler);
+ void registerWidget(ucl::ElmWidget &widget);
+
+ private:
+ friend class ucl::RefCountObj<AtspiHighlightHelper>;
+ AtspiHighlightHelper(ucl::RefCountObjBase &rc);
+ virtual ~AtspiHighlightHelper();
+
+ ucl::Result prepare(ucl::ElmWidget &rootWidget);
+
+ private:
+ void onAtspiGesture(ucl::Widget &widget, void *eventInfo);
+
+ private:
+ EventHandler m_eventHandler;
+ };
+}
+
+#endif // __GALLERY_PRESENTERS_ATSPI_HIGHLIGH_HELPER_H__
ucl::Result prepare(ucl::ElmWidget &widget);
ucl::Window &getWindow();
+ bool isWindowReady() const;
void addDeactivatorSource(ucl::Widget &source);
void addDeactivatorException(void *deactivator);
#include "view/IImageGridListener.h"
+#include "AtspiHighlightHelper.h"
#include "IMoreOptionsListener.h"
namespace gallery {
void onPageExitRequest(Page &page);
- // Page //
+ Elm_Interface_Atspi_Accessible *onAtspiHighlight(
+ ucl::Widget &widget, Elm_Atspi_Relation_Type flowRelation);
+
+ // Presenter //
virtual void onActivateBy(const DeactivatorInfo &info) final override;
virtual void onDeactivateBy(const DeactivatorInfo &info) final override;
PageContentSRef m_content;
ImageGridSRef m_imageGrid;
MoreOptionsPresenterSRef m_more;
+ AtspiHighlightHelperSRef m_atspiHelper;
PageWRef m_page;
};
#include <deque>
-#include "ucl/gui/Layout.h"
#include "ucl/gui/StyledWidget.h"
#include "ucl/misc/Timeout.h"
bool m_isInSelectMode;
bool m_isRotaryActive;
- ucl::LayoutSRef m_highlighKeeper;
+ ucl::ElmWidgetSRef m_highlighKeeper;
ucl::TimeoutSRef m_highlightTimeout;
int m_highlightID;
bool m_isHighlightLocked;
#ifndef __GALLERY_VIEW_HELPERS_H__
#define __GALLERY_VIEW_HELPERS_H__
-#include "types.h"
-
-namespace ucl {
+#include "ucl/gui/Naviframe.h"
- class ElmWidget;
- class Naviframe;
-}
+#include "types.h"
namespace gallery { namespace util {
ucl::Result createCircleSurface(ucl::Naviframe &navi);
Eext_Circle_Surface *getCircleSurface(const ucl::ElmWidget &widget);
+
+ ucl::ElmWidgetSRef createFakeAccessObject(ucl::ElmWidget &parent);
}}
namespace gallery {
--- /dev/null
+/*
+ * Copyright 2017 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://floralicense.org/license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "presenters/AtspiHighlightHelper.h"
+
+#include "common.h"
+
+namespace gallery { namespace { namespace impl {
+
+ using namespace ucl;
+
+ constexpr EoDataKey ATSPI_HELPER_DATA {"gallery,atspi,highlight,helper"};
+}}}
+
+namespace gallery {
+
+ using namespace ucl;
+
+ AtspiHighlightHelperSRef AtspiHighlightHelper::newInstance(
+ ElmWidget &rootWidget)
+ {
+ auto result = makeShared<AtspiHighlightHelper>();
+
+ FAIL_RETURN_VALUE(result->prepare(rootWidget), {},
+ "result->prepare() failed!");
+
+ return result;
+ }
+
+ AtspiHighlightHelper::AtspiHighlightHelper(RefCountObjBase &rc) :
+ Presenter(rc)
+ {
+ }
+
+ AtspiHighlightHelper::~AtspiHighlightHelper()
+ {
+ }
+
+ Result AtspiHighlightHelper::prepare(ElmWidget &rootWidget)
+ {
+ FAIL_RETURN(Presenter::prepare(rootWidget),
+ "Presenter::prepare() failed!");
+
+ registerWidget(rootWidget);
+
+ return RES_OK;
+ }
+
+ void AtspiHighlightHelper::setEventHandler(EventHandler handler)
+ {
+ m_eventHandler = handler;
+ }
+
+ void AtspiHighlightHelper::registerWidget(ElmWidget &widget)
+ {
+ widget.addEventHandler(ATSPI_ON_GESTURE, WEAK_DELEGATE(
+ AtspiHighlightHelper::onAtspiGesture, asWeak(*this)));
+ }
+
+ void AtspiHighlightHelper::onAtspiGesture(
+ Widget &widget, void *eventInfo)
+ {
+ auto &e = *static_cast<AtspiGestureEventInfo *>(eventInfo);
+ if (e.stopPropagation) {
+ return;
+ }
+ if (!isActive()) {
+ e.preventDefault = true;
+ return;
+ }
+
+ e.preventDefault = false;
+ e.stopPropagation = true;
+
+ if (!m_eventHandler) {
+ return;
+ }
+ const Elm_Atspi_Relation_Type relation = getFlowRelation(e.gestureInfo);
+ if (relation == ELM_ATSPI_RELATION_NULL) {
+ return;
+ }
+ const auto relationObj = m_eventHandler(widget, relation);
+ if (!relationObj) {
+ return;
+ }
+
+ auto &win = getWindow();
+ auto atspiHelper = static_cast<Elm_Interface_Atspi_Accessible *>
+ (win.getData(impl::ATSPI_HELPER_DATA));
+
+ if (!atspiHelper) {
+ const auto obj = util::createFakeAccessObject(win);
+ if (!obj) {
+ LOG_RETURN_VOID(RES_FAIL, "createFakeAccessObject() failed!");
+ }
+ obj->setIsOwner(false);
+ atspiHelper = obj->getEo();
+ win.setData(impl::ATSPI_HELPER_DATA, atspiHelper);
+ }
+
+ elm_atspi_component_highlight_grab(atspiHelper);
+
+ elm_atspi_accessible_relationships_clear(atspiHelper);
+ elm_atspi_accessible_relationship_append(atspiHelper,
+ relation, relationObj);
+ }
+}
m_widget->addEventHandler(impl::MORE_ITEM_SELECTED, WEAK_DELEGATE(
MoreOptionsPresenter::onItemSelected, asWeak(*this)));
+ addDeactivatorException(this);
deactivateBy(m_widget.get());
return RES_OK;
Window &Presenter::getWindow()
{
+ UCL_ASSERT(isWindowReady(), "m_window is NULL!");
return *m_window;
}
+ bool Presenter::isWindowReady() const
+ {
+ return !!m_window;
+ }
+
void Presenter::addDeactivatorSource(Widget &source)
{
source.addEventHandler(impl::ACTIVATE_BY,
eext_object_event_callback_del(*m_popup, EEXT_CALLBACK_BACK,
CALLBACK_A(ProcessingPresenter::onPopupHWBackKey));
- m_popup.reset();
-
deactivateBy(m_popup.get());
broadcastActivateBy(this);
- m_rc->unref();
+ m_popup.reset();
+ if (m_isComplete) {
+ m_rc->unref();
+ }
}
}
}),
"Page::prepare() failed!");
+ m_atspiHelper = AtspiHighlightHelper::newInstance(getWindow());
+ if (!m_atspiHelper) {
+ LOG_RETURN(RES_FAIL, "AtspiHighlightHelper::newInstance() failed!");
+ }
+
m_imageGrid->setItemCount(m_mediaItems.size());
m_album->addChangeHandler(WEAK_DELEGATE(
ThumbnailPage::onAlbumChanged, asWeak(*this)));
- m_more->setListener(asWeakThis<IMoreOptionsListener>(this));
+ m_atspiHelper->setEventHandler(WEAK_DELEGATE(
+ ThumbnailPage::onAtspiHighlight, asWeak(*this)));
return RES_OK;
}
impl::PAGE_SCROLL_IN_FRICTION);
elm_config_scroll_bring_in_scroll_friction_set(
impl::BRING_IN_SCROLL_FRICTION);
+ }
+ if (!info.isBroadcast) {
m_more->activateBy(info.deactivator);
+ if (m_atspiHelper) {
+ m_atspiHelper->activateBy(info.deactivator);
+ }
}
if (isActive()) {
void ThumbnailPage::onDeactivateBy(const DeactivatorInfo &info)
{
- if (info.deactivator == &getNaviframe()) {
+ if (!info.isBroadcast) {
m_more->deactivateBy(info.deactivator);
+ m_atspiHelper->deactivateBy(info.deactivator);
}
m_imageGrid->deactivateRotary();
}
+ Elm_Interface_Atspi_Accessible *ThumbnailPage::onAtspiHighlight(
+ Widget &widget, Elm_Atspi_Relation_Type flowRelation)
+ {
+ return m_imageGrid->getAccessObject(true);
+ }
+
void ThumbnailPage::onItemRealized(const int itemIndex)
{
m_realizedItems.emplace_back(new RealizedItem(*this, itemIndex));
VideoPlayerPage::~VideoPlayerPage()
{
- setScreenAlwaysOn(false);
+ if (isWindowReady()) {
+ setScreenAlwaysOn(false);
+ }
delRotaryEventHandler(CALLBACK_A(VideoPlayerPage::onRotary), this);
constexpr EdjeSignal BTN_UNBLOCK_CLICKS {"gallery,unblock,clicks"};
// Other //
- constexpr LayoutTheme LAYOUT_FAKE_ACCESS_OBJECT
- {"layout", "gallery", "fake_access_object"};
-
constexpr auto HCOMB_SCROLL_LIMIT = 1000;
constexpr auto SCROLL_HIGHLIGHT_TIMEOUT_SEC = 0.1;
return;
}
- if (m_isHighlighted && m_imageGrid.m_highlightTimeout) {
+ if ((m_imageGrid.m_highlightID == m_realizeIndex) &&
+ m_imageGrid.m_highlightTimeout) {
m_imageGrid.m_isHighlightLocked = true;
elm_atspi_component_highlight_clear(m_btn);
}
void onHighlighted(Widget &widget, void *eventInfo)
{
- if (m_isHighlighted) {
- return;
- }
- m_isHighlighted = true;
if (!isRealized()) {
LOG_RETURN_VOID(RES_ILLEGAL_STATE, "Item is not realized!");
}
void onUnhighlighted(Widget &widget, void *eventInfo)
{
- if (!m_isHighlighted) {
- return;
- }
- m_isHighlighted = false;
if (!isRealized()) {
LOG_RETURN_VOID(RES_ILLEGAL_STATE, "Item is not realized!");
}
bool m_isImageLoaded = false;
bool m_isClicksBlocked = false;
bool m_isSelected = false;
- bool m_isHighlighted = false;
};
public:
void ImageGrid::createHighlighKeeper()
{
- m_highlighKeeper = Layout::Builder().
- setTheme(impl::LAYOUT_FAKE_ACCESS_OBJECT).
- setIsOwner(true).
- build(*m_box.getWindow());
+ m_highlighKeeper = util::createFakeAccessObject(*m_box.getWindow());
UCL_ASSERT(m_highlighKeeper, "m_highlighKeeper is NULL");
- m_highlighKeeper->setGeometry(0, 0, 1, 1);
- show(*m_highlighKeeper);
-
- elm_atspi_accessible_reading_info_type_set(*m_highlighKeeper, 0);
-
- elm_atspi_accessible_gesture_cb_set(*m_highlighKeeper,
- [](void *, Elm_Atspi_Gesture_Info, Evas_Object *) -> Eina_Bool
- {
- return EINA_TRUE;
- },
- nullptr);
-
m_highlighKeeper->addEventHandler(ATSPI_UNHIGHLIGHTED,
WEAK_DELEGATE(ImageGrid::onKeeperUnhighlighted, asWeak(*this)));
}
} else {
m_highlightTimeout.reset();
}
- } else {
- WLOG("Item was not highlighted: %d.", itemIndex);
}
}
elm_atspi_component_highlight_grab(
slot.getItemAtspi(itemOffset));
return RES_OK;
- }), "Failed to get item Atspi!");
+ }), "Failed to Grab item highlight!");
}
Elm_Interface_Atspi_Accessible *ImageGrid::requestAtspi(const int itemIndex)
}
return nullptr;
}
- return getItemAtspi(itemIndex);
+
+ const int oldHighlightID = m_highlightID;
+ m_highlightID = itemIndex; // To prevent autohighlight timer to start
+
+ const auto result = getItemAtspi(itemIndex);
+ if (!result) {
+ m_highlightID = oldHighlightID;
+ return nullptr;
+ }
+
+ m_highlightTimeout.reset();
+
+ return result;
}
Elm_Interface_Atspi_Accessible *ImageGrid::getItemAtspi(
++m_eventsLock;
if (updateScrollOffset()) {
+ updateHighlightTimeout();
if (updateBeginSlotIndex()) {
realizeSlots();
updateRectMins();
}
- updateHighlightTimeout();
}
--m_eventsLock;
#include <vector>
#include "ucl/gui/Window.h"
-#include "ucl/gui/Naviframe.h"
+#include "ucl/gui/Layout.h"
#include "common.h"
using namespace ucl;
constexpr EoDataKey CIRCLE_SURFACE {"gallery,eext,circle,surface"};
+
+ constexpr LayoutTheme LAYOUT_FAKE_ACCESS_OBJECT
+ {"layout", "gallery", "fake_access_object"};
}}}
namespace gallery { namespace util {
return sfc;
}
+
+ ElmWidgetSRef createFakeAccessObject(ElmWidget &parent)
+ {
+ const auto result = Layout::Builder().
+ setTheme(impl::LAYOUT_FAKE_ACCESS_OBJECT).
+ setIsOwner(true).
+ setNeedBindToEo(true).
+ build(parent);
+ if (!result) {
+ LOG_RETURN_VALUE(RES_FAIL, {}, "Layout::build() failed!");
+ }
+
+ result->setGeometry(0, 0, 1, 1);
+ show(*result);
+
+ elm_atspi_accessible_reading_info_type_set(*result, 0);
+
+ elm_atspi_accessible_gesture_cb_set(*result,
+ [](void *, Elm_Atspi_Gesture_Info, Evas_Object *) -> Eina_Bool
+ {
+ return EINA_TRUE;
+ },
+ nullptr);
+
+ return result;
+ }
}}
namespace gallery {
struct AtspiGestureEventInfo {
Elm_Atspi_Gesture_Info gestureInfo;
bool preventDefault;
+ bool stopPropagation;
};
// WidgetARHint //
Eina_Bool ElmWidget::onAtspiGesture(Elm_Atspi_Gesture_Info gestureInfo,
Evas_Object *obj)
{
- AtspiGestureEventInfo eventInfo{gestureInfo, false};
+ AtspiGestureEventInfo eventInfo{gestureInfo};
callEvent(ATSPI_ON_GESTURE, &eventInfo);
return toEina(eventInfo.preventDefault);
}