From 1686397626c0e8983fbdbe83127ae36d700fed87 Mon Sep 17 00:00:00 2001 From: "t.dakowicz" Date: Fri, 4 Sep 2015 17:25:46 +0200 Subject: [PATCH] Implemented ZoomUI service [Issue#] https://bugs.tizen.org/jira/browse/TT-133 [Problem] Page zoom implementation [Cause] N/A [Solution] New ZoomUI service [Verify] Open a new page -> MoreMenu -> Screen Zoom Check if zooming/navigating the page works. Change-Id: I1c47d5fd37927e0a8f88f8952af1350791eac02f --- core/AbstractWebEngine/AbstractWebEngine.h | 11 + services/CMakeLists.txt | 1 + services/MoreMenuUI/MoreMenuUI.cpp | 1 + services/MoreMenuUI/MoreMenuUI.h | 1 + services/SimpleUI/CMakeLists.txt | 3 + services/SimpleUI/SimpleUI.cpp | 46 ++- services/SimpleUI/SimpleUI.h | 10 + .../WebKitEngineService/WebKitEngineService.cpp | 5 + services/WebKitEngineService/WebKitEngineService.h | 2 + services/WebKitEngineService/WebView.cpp | 7 +- services/WebKitEngineService/WebView.h | 12 +- services/ZoomUI/CMakeLists.txt | 36 +++ services/ZoomUI/ZoomUI.cpp | 322 +++++++++++++++++++++ services/ZoomUI/ZoomUI.h | 105 +++++++ services/ZoomUI/edc/ZoomUI.edc | 277 ++++++++++++++++++ .../ZoomUI/images/ic_zoom_indicator_down_foc.png | Bin 0 -> 2807 bytes .../ZoomUI/images/ic_zoom_indicator_down_nor.png | Bin 0 -> 2728 bytes .../ZoomUI/images/ic_zoom_indicator_left_foc.png | Bin 0 -> 2786 bytes .../ZoomUI/images/ic_zoom_indicator_left_nor.png | Bin 0 -> 2764 bytes .../ZoomUI/images/ic_zoom_indicator_right_foc.png | Bin 0 -> 2777 bytes .../ZoomUI/images/ic_zoom_indicator_right_nor.png | Bin 0 -> 2759 bytes .../ZoomUI/images/ic_zoom_indicator_up_foc.png | Bin 0 -> 2803 bytes .../ZoomUI/images/ic_zoom_indicator_up_nor.png | Bin 0 -> 2667 bytes 23 files changed, 836 insertions(+), 3 deletions(-) create mode 100644 services/ZoomUI/CMakeLists.txt create mode 100644 services/ZoomUI/ZoomUI.cpp create mode 100644 services/ZoomUI/ZoomUI.h create mode 100644 services/ZoomUI/edc/ZoomUI.edc create mode 100644 services/ZoomUI/images/ic_zoom_indicator_down_foc.png create mode 100644 services/ZoomUI/images/ic_zoom_indicator_down_nor.png create mode 100644 services/ZoomUI/images/ic_zoom_indicator_left_foc.png create mode 100644 services/ZoomUI/images/ic_zoom_indicator_left_nor.png create mode 100644 services/ZoomUI/images/ic_zoom_indicator_right_foc.png create mode 100644 services/ZoomUI/images/ic_zoom_indicator_right_nor.png create mode 100644 services/ZoomUI/images/ic_zoom_indicator_up_foc.png create mode 100644 services/ZoomUI/images/ic_zoom_indicator_up_nor.png diff --git a/core/AbstractWebEngine/AbstractWebEngine.h b/core/AbstractWebEngine/AbstractWebEngine.h index ea0e663..99f19c9 100644 --- a/core/AbstractWebEngine/AbstractWebEngine.h +++ b/core/AbstractWebEngine/AbstractWebEngine.h @@ -275,6 +275,17 @@ public: virtual bool isDesktopMode() const = 0; /** + * Sets an absolute scroll of the given view. + * + * Both values are from zero to the contents size minus the viewport + * size. + * + * @param x horizontal position to scroll + * @param y vertical position to scroll + */ + virtual void scrollView(const int& dx, const int& dy) = 0; + + /** * FavIcon of current page changed */ boost::signals2::signal)> favIconChanged; diff --git a/services/CMakeLists.txt b/services/CMakeLists.txt index 975dd93..8ff9167 100644 --- a/services/CMakeLists.txt +++ b/services/CMakeLists.txt @@ -14,3 +14,4 @@ add_subdirectory(HistoryService) add_subdirectory(PlatformInputManager) add_subdirectory(SessionStorage) add_subdirectory(BookmarkService) +add_subdirectory(ZoomUI) diff --git a/services/MoreMenuUI/MoreMenuUI.cpp b/services/MoreMenuUI/MoreMenuUI.cpp index a550e06..f623118 100644 --- a/services/MoreMenuUI/MoreMenuUI.cpp +++ b/services/MoreMenuUI/MoreMenuUI.cpp @@ -529,6 +529,7 @@ void MoreMenuUI::_thumbSelected(void* data, Evas_Object*, void*) break; #endif case SCREEN_ZOOM: + itemData->moreMenuUI->zoomUIClicked(); break; #ifdef START_MINIBROWSER_ENABLED case START_MINIBROWSER: diff --git a/services/MoreMenuUI/MoreMenuUI.h b/services/MoreMenuUI/MoreMenuUI.h index f60d7af..72ce2d6 100644 --- a/services/MoreMenuUI/MoreMenuUI.h +++ b/services/MoreMenuUI/MoreMenuUI.h @@ -85,6 +85,7 @@ public: boost::signals2::signal historyUIClicked; boost::signals2::signal settingsClicked; boost::signals2::signal closeMoreMenuClicked; + boost::signals2::signal zoomUIClicked; boost::signals2::signal switchToMobileMode; boost::signals2::signal switchToDesktopMode; boost::signals2::signal isBookmark; diff --git a/services/SimpleUI/CMakeLists.txt b/services/SimpleUI/CMakeLists.txt index fe55ea3..02f8aed 100644 --- a/services/SimpleUI/CMakeLists.txt +++ b/services/SimpleUI/CMakeLists.txt @@ -34,6 +34,7 @@ include_directories(${CMAKE_SOURCE_DIR}/services/HistoryUI) include_directories(${CMAKE_SOURCE_DIR}/services/MainUI) include_directories(${CMAKE_SOURCE_DIR}/services/SettingsUI) include_directories(${CMAKE_SOURCE_DIR}/services/TabUI) +include_directories(${CMAKE_SOURCE_DIR}/services/ZoomUI) include_directories(${CMAKE_SOURCE_DIR}/services/PlatformInputManager) include_directories(${CMAKE_SOURCE_DIR}/services/SessionStorage) @@ -52,6 +53,7 @@ add_dependencies(${PROJECT_NAME} MainUI) add_dependencies(${PROJECT_NAME} HistoryUI) add_dependencies(${PROJECT_NAME} TabUI) add_dependencies(${PROJECT_NAME} SettingsUI) +add_dependencies(${PROJECT_NAME} ZoomUI) add_dependencies(${PROJECT_NAME} PlatformInputManager) add_dependencies(${PROJECT_NAME} SessionStorage) target_link_libraries(${PROJECT_NAME} WebPageUI) @@ -63,6 +65,7 @@ target_link_libraries(${PROJECT_NAME} HistoryUI) target_link_libraries(${PROJECT_NAME} TabUI) target_link_libraries(${PROJECT_NAME} SettingsUI) target_link_libraries(${PROJECT_NAME} BookmarkManagerUI) +target_link_libraries(${PROJECT_NAME} ZoomUI) target_link_libraries(${PROJECT_NAME} PlatformInputManager) target_link_libraries(${PROJECT_NAME} SessionStorage) target_link_libraries(${PROJECT_NAME} ${EFL_LDFLAGS}) diff --git a/services/SimpleUI/SimpleUI.cpp b/services/SimpleUI/SimpleUI.cpp index 472c528..189c284 100644 --- a/services/SimpleUI/SimpleUI.cpp +++ b/services/SimpleUI/SimpleUI.cpp @@ -221,6 +221,11 @@ void SimpleUI::loadUIServices() std::dynamic_pointer_cast (tizen_browser::core::ServiceManager::getInstance().getService("org.tizen.browser.bookmarkmanagerui")); + + m_zoomUI = + std::dynamic_pointer_cast + + (tizen_browser::core::ServiceManager::getInstance().getService("org.tizen.browser.zoomui")); } void SimpleUI::connectUISignals() @@ -279,11 +284,15 @@ void SimpleUI::connectUISignals() m_moreMenuUI->addToBookmarkClicked.connect(boost::bind(&SimpleUI::addToBookmarks, this, _1)); m_moreMenuUI->isBookmark.connect(boost::bind(&SimpleUI::checkBookmark, this)); m_moreMenuUI->deleteBookmark.connect(boost::bind(&SimpleUI::deleteBookmark, this)); + m_moreMenuUI->zoomUIClicked.connect(boost::bind(&SimpleUI::showZoomUI, this)); M_ASSERT(m_bookmarkManagerUI.get()); m_bookmarkManagerUI->closeBookmarkManagerClicked.connect(boost::bind(&SimpleUI::closeBookmarkManagerUI, this)); m_bookmarkManagerUI->bookmarkItemClicked.connect(boost::bind(&SimpleUI::onBookmarkClicked, this, _1)); + M_ASSERT(m_zoomUI.get()); + m_zoomUI->setZoom.connect(boost::bind(&SimpleUI::setZoomFactor, this, _1)); + m_zoomUI->scrollView.connect(boost::bind(&SimpleUI::scrollView, this, _1, _2)); } void SimpleUI::loadModelServices() @@ -341,6 +350,9 @@ void SimpleUI::initUIServices() M_ASSERT(m_bookmarkManagerUI.get()); m_bookmarkManagerUI->init(m_viewManager->getContent()); + + M_ASSERT(m_zoomUI.get()); + m_zoomUI->init(m_viewManager->getContent()); } void SimpleUI::initModelServices() @@ -365,7 +377,9 @@ void SimpleUI::connectModelSignals() m_webEngine->uriChanged.connect(boost::bind(&SimpleUI::webEngineURLChanged, this, _1)); m_webEngine->uriChanged.connect(boost::bind(&URIEntry::changeUri, &m_webPageUI->getURIEntry(), _1)); + m_webEngine->uriChanged.connect(boost::bind(&MoreMenuUI::setURL, m_moreMenuUI.get(), _1)); m_webEngine->uriOnTabChanged.connect(boost::bind(&SimpleUI::checkTabId,this,_1)); + m_webEngine->uriOnTabChanged.connect(boost::bind(&SimpleUI::closeZoomUI, this)); m_webEngine->webViewClicked.connect(boost::bind(&URIEntry::clearFocus, &m_webPageUI->getURIEntry())); m_webEngine->backwardEnableChanged.connect(boost::bind(&WebPageUI::setBackButtonEnabled, m_webPageUI.get(), _1)); m_webEngine->forwardEnableChanged.connect(boost::bind(&WebPageUI::setForwardButtonEnabled, m_webPageUI.get(), _1)); @@ -380,7 +394,6 @@ void SimpleUI::connectModelSignals() m_webEngine->IMEStateChanged.connect(boost::bind(&SimpleUI::setwvIMEStatus, this, _1)); m_webEngine->favIconChanged.connect(boost::bind(&MoreMenuUI::setFavIcon, m_moreMenuUI.get(), _1)); m_webEngine->titleChanged.connect(boost::bind(&MoreMenuUI::setWebTitle, m_moreMenuUI.get(), _1)); - m_webEngine->uriChanged.connect(boost::bind(&MoreMenuUI::setURL, m_moreMenuUI.get(), _1)); m_favoriteService->bookmarkAdded.connect(boost::bind(&SimpleUI::onBookmarkAdded, this,_1)); m_favoriteService->bookmarkDeleted.connect(boost::bind(&SimpleUI::onBookmarkRemoved, this, _1)); @@ -661,6 +674,37 @@ void SimpleUI::webEngineURLChanged(const std::string url) m_webPageUI->getURIEntry().clearFocus(); } +void SimpleUI::showZoomUI() +{ + BROWSER_LOGD("[%s:%d] ", __PRETTY_FUNCTION__, __LINE__); + if(! m_webPageUI->isHomePageActive()) { + M_ASSERT(m_viewManager); + m_viewManager->popStackTo(m_webPageUI.get()); + m_webPageUI->showTabUI.connect(boost::bind(&SimpleUI::closeZoomUI, this)); + m_webPageUI->showMoreMenu.connect(boost::bind(&SimpleUI::closeZoomUI, this)); + m_zoomUI->show(m_window.get()); + } +} + +void SimpleUI::closeZoomUI() +{ + BROWSER_LOGD("[%s:%d] ", __PRETTY_FUNCTION__, __LINE__); + M_ASSERT(m_zoomUI); + m_webPageUI->showTabUI.disconnect(boost::bind(&SimpleUI::closeZoomUI, this)); + m_webPageUI->showMoreMenu.disconnect(boost::bind(&SimpleUI::closeZoomUI, this)); + m_zoomUI->hideUI(); +} + +void SimpleUI::setZoomFactor(int level) +{ + m_webEngine->setZoomFactor(level); +} + +void SimpleUI::scrollView(const int& dx, const int& dy) +{ + m_webEngine->scrollView(dx, dy); +} + void SimpleUI::showTabUI() { BROWSER_LOGD("[%s:%d] ", __PRETTY_FUNCTION__, __LINE__); diff --git a/services/SimpleUI/SimpleUI.h b/services/SimpleUI/SimpleUI.h index 5b62197..0e8c58a 100644 --- a/services/SimpleUI/SimpleUI.h +++ b/services/SimpleUI/SimpleUI.h @@ -40,6 +40,7 @@ #include "SettingsUI.h" #include "MainUI.h" #include "TabUI.h" +#include "ZoomUI.h" #include "HistoryService.h" #include "BookmarkManagerUI.h" #include "PlatformInputManager.h" @@ -183,6 +184,14 @@ private: */ void deleteBookmark(void); + /** + * @brief show Zoom Menu + */ + void showZoomUI(); + void closeZoomUI(); + void setZoomFactor(int level); + void scrollView(const int& dx, const int& dy); + void showTabUI(); void closeTabUI(); void showMoreMenu(); @@ -232,6 +241,7 @@ private: std::shared_ptr m_platformInputManager; std::shared_ptr m_sessionService; Session::Session m_currentSession; + std::shared_ptr m_zoomUI; std::shared_ptr m_bookmarks_manager; bool m_initialised; int m_tabLimit; diff --git a/services/WebKitEngineService/WebKitEngineService.cpp b/services/WebKitEngineService/WebKitEngineService.cpp index f88b5da..2e0df96 100644 --- a/services/WebKitEngineService/WebKitEngineService.cpp +++ b/services/WebKitEngineService/WebKitEngineService.cpp @@ -525,6 +525,11 @@ bool WebKitEngineService::isDesktopMode() const return m_currentWebView->isDesktopMode(); } +void WebKitEngineService::scrollView(const int& dx, const int& dy) +{ + m_currentWebView->scrollView(dx, dy); +} + } /* end of webkitengine_service */ } /* end of basic_webengine */ } /* end of tizen_browser */ diff --git a/services/WebKitEngineService/WebKitEngineService.h b/services/WebKitEngineService/WebKitEngineService.h index 4f586cb..ed1fc6d 100644 --- a/services/WebKitEngineService/WebKitEngineService.h +++ b/services/WebKitEngineService/WebKitEngineService.h @@ -163,6 +163,8 @@ public: void switchToDesktopMode(); bool isDesktopMode() const; + void scrollView(const int& dx, const int& dy); + private: // callbacks from WebView void _favIconChanged(std::shared_ptr bi); diff --git a/services/WebKitEngineService/WebView.cpp b/services/WebKitEngineService/WebView.cpp index 60d7a4e..fd78851 100644 --- a/services/WebKitEngineService/WebView.cpp +++ b/services/WebKitEngineService/WebView.cpp @@ -823,11 +823,16 @@ void WebView::setZoomFactor(double zoomFactor) if(m_ewkView){ //using zoomFactor = 0 sets zoom "fit to screen" - ewk_view_page_zoom_set(m_ewkView, zoomFactor); + if(zoomFactor != getZoomFactor()) + ewk_view_page_zoom_set(m_ewkView, zoomFactor); } #endif } +void WebView::scrollView(const int& dx, const int& dy) +{ + ewk_view_scroll_by(m_ewkView, dx, dy); +} const TabId& WebView::getTabId(){ return m_tabId; diff --git a/services/WebKitEngineService/WebView.h b/services/WebKitEngineService/WebView.h index 1672438..224e657 100644 --- a/services/WebKitEngineService/WebView.h +++ b/services/WebKitEngineService/WebView.h @@ -43,7 +43,6 @@ public: virtual ~WebView(); void init(bool desktopMode, Evas_Object * opener = NULL); - void setURI(const std::string &); std::string getURI(void); @@ -131,6 +130,17 @@ public: */ std::shared_ptr getFavicon(); + /** + * Sets an absolute scroll of the given view. + * + * Both values are from zero to the contents size minus the viewport + * size. + * + * @param x horizontal position to scroll + * @param y vertical position to scroll + */ + void scrollView(const int& dx, const int& dy); + // signals boost::signals2::signal)> favIconChanged; boost::signals2::signal titleChanged; diff --git a/services/ZoomUI/CMakeLists.txt b/services/ZoomUI/CMakeLists.txt new file mode 100644 index 0000000..d8b752c --- /dev/null +++ b/services/ZoomUI/CMakeLists.txt @@ -0,0 +1,36 @@ +project(ZoomUI) + +set(ZoomUI_SRCS + ZoomUI.cpp + ) + +set(ZoomUI_HEADERS + ZoomUI.h + ) + +include(Coreheaders) +include(EFLHelpers) + +include_directories(${CMAKE_SOURCE_DIR}/services/FavoriteService) + +add_library(${PROJECT_NAME} SHARED ${ZoomUI_SRCS}) + +if(TIZEN_BUILD) + target_link_libraries(${PROJECT_NAME} ${pkgs_LDFLAGS}) +endif(TIZEN_BUILD) + +install(TARGETS ${PROJECT_NAME} + LIBRARY DESTINATION services + ARCHIVE DESTINATION services/static) + +#please do not add edc/ directory +set(edcFiles + ZoomUI.edc + ) + +foreach(edec ${edcFiles}) + string(REPLACE ".edc" ".edj" target_name ${edec}) + EDJ_TARGET(${target_name} + ${CMAKE_CURRENT_SOURCE_DIR}/edc/${edec} + ${CMAKE_CURRENT_BINARY_DIR}) +endforeach(edec) diff --git a/services/ZoomUI/ZoomUI.cpp b/services/ZoomUI/ZoomUI.cpp new file mode 100644 index 0000000..dcbe068 --- /dev/null +++ b/services/ZoomUI/ZoomUI.cpp @@ -0,0 +1,322 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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 +#include +#include +#include + +#include "ZoomUI.h" +#include "BrowserLogger.h" +#include "ServiceManager.h" + +#define DX 50 +#define iDX -50 + +namespace tizen_browser{ +namespace base_ui{ + +EXPORT_SERVICE(ZoomUI, "org.tizen.browser.zoomui") + +ZoomUI::ZoomUI() + : m_layout(nullptr) + , m_nav_layout(nullptr) + , m_zoom_slider(nullptr) + , m_current_translation_x(0) + , m_current_translation_y(0) +{ + BROWSER_LOGD("[%s:%d] ", __PRETTY_FUNCTION__, __LINE__); + m_edjFilePath = EDJE_DIR; + m_edjFilePath.append("ZoomUI/ZoomUI.edj"); + elm_theme_extension_add(nullptr, m_edjFilePath.c_str()); +} + +ZoomUI::~ZoomUI() {} + +void ZoomUI::init(Evas_Object* parent) +{ + BROWSER_LOGD("[%s:%d] ", __PRETTY_FUNCTION__, __LINE__); + M_ASSERT(parent); + m_parent = parent; +} + +Evas_Object* ZoomUI::getContent() +{ + BROWSER_LOGD("[%s:%d] ", __PRETTY_FUNCTION__, __LINE__); + M_ASSERT(m_parent); + if(!m_layout) + createLayout(m_parent); + return m_layout; +} + +void ZoomUI::showUI() +{ + evas_object_show(m_layout); + evas_object_show(m_nav_layout); + evas_object_show(m_zoom_slider); +} + +void ZoomUI::hideUI() +{ + evas_object_hide(m_zoom_slider); + evas_object_hide(m_nav_layout); + evas_object_hide(m_layout); +} + +void ZoomUI::show(Evas_Object* parent) +{ + BROWSER_LOGD("[%s:%d] ", __PRETTY_FUNCTION__, __LINE__); + init(parent); + createLayout(parent); + showUI(); +} + +void ZoomUI::createLayout(Evas_Object *parent) +{ + BROWSER_LOGD("[%s:%d] ", __PRETTY_FUNCTION__, __LINE__); + + m_layout = elm_layout_add(parent); + elm_layout_file_set(m_layout, m_edjFilePath.c_str(), "zoom-layout"); + evas_object_size_hint_weight_set(m_layout, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_size_hint_align_set(m_layout, EVAS_HINT_FILL, EVAS_HINT_FILL); + + createZoomSlider(); + createNavigationButtons(); +} + +void ZoomUI::createZoomSlider() +{ + m_zoom_slider = elm_slider_add(m_layout); + evas_object_size_hint_weight_set(m_zoom_slider, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_size_hint_align_set(m_zoom_slider, EVAS_HINT_FILL, EVAS_HINT_FILL); + evas_object_smart_callback_add(m_zoom_slider, "changed", _zoom_slider_changed, this); + elm_object_style_set(m_zoom_slider, "default"); + elm_slider_horizontal_set(m_zoom_slider, EINA_TRUE); + elm_slider_min_max_set(m_zoom_slider, 1, 6); + elm_slider_step_set(m_zoom_slider, 1); + elm_slider_value_set(m_zoom_slider, 3); + elm_slider_indicator_format_set(m_zoom_slider, "%1.0f"); + + elm_object_part_content_set(m_layout, "slider_swallow", m_zoom_slider); +} + +void ZoomUI::createNavigationButtons() +{ + m_nav_layout = elm_layout_add(m_layout); + elm_layout_file_set(m_nav_layout, m_edjFilePath.c_str(), "nav-layout"); + evas_object_size_hint_weight_set(m_nav_layout, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_size_hint_align_set(m_nav_layout, EVAS_HINT_FILL, EVAS_HINT_FILL); + elm_object_part_content_set(m_layout, "nav_buttons", m_nav_layout); + + Evas_Object* icon = elm_icon_add(m_nav_layout); + setImageFile(icon, LEFT, false); + evas_object_smart_callback_add(icon, "clicked", _left_button_clicked, this); + evas_object_event_callback_add(icon, EVAS_CALLBACK_MOUSE_IN, _cb_focus_in_left_button, this); + evas_object_event_callback_add(icon, EVAS_CALLBACK_MOUSE_OUT, _cb_focus_out_left_button, this); + elm_object_part_content_set(m_nav_layout, "left_button", icon); + + icon = elm_icon_add(m_nav_layout); + setImageFile(icon, RIGHT, false); + evas_object_smart_callback_add(icon, "clicked", _right_button_clicked, this); + evas_object_event_callback_add(icon, EVAS_CALLBACK_MOUSE_IN, _cb_focus_in_right_button, this); + evas_object_event_callback_add(icon, EVAS_CALLBACK_MOUSE_OUT, _cb_focus_out_right_button, this); + elm_object_part_content_set(m_nav_layout, "right_button", icon); + + icon = elm_icon_add(m_nav_layout); + setImageFile(icon, DOWN, false); + evas_object_smart_callback_add(icon, "clicked", _down_button_clicked, this); + evas_object_event_callback_add(icon, EVAS_CALLBACK_MOUSE_IN, _cb_focus_in_down_button, this); + evas_object_event_callback_add(icon, EVAS_CALLBACK_MOUSE_OUT, _cb_focus_out_down_button, this); + elm_object_part_content_set(m_nav_layout, "down_button", icon); + + icon = elm_icon_add(m_nav_layout); + setImageFile(icon, UP, false); + evas_object_smart_callback_add(icon, "clicked", _up_button_clicked, this); + evas_object_event_callback_add(icon, EVAS_CALLBACK_MOUSE_IN, _cb_focus_in_up_button, this); + evas_object_event_callback_add(icon, EVAS_CALLBACK_MOUSE_OUT, _cb_focus_out_up_button, this); + elm_object_part_content_set(m_nav_layout, "up_button", icon); +} + +void ZoomUI::clearItems() +{ + evas_object_del(m_layout); + setZoom(ZOOM_DEFAULT); +} + +void ZoomUI::setImageFile(Evas_Object* obj, int direction, bool focused) +{ + switch (direction) { + case LEFT: elm_image_file_set(obj, m_edjFilePath.c_str(), focused ? "ic_zoom_indicator_left_foc.png" : "ic_zoom_indicator_left_nor.png"); + break; + case RIGHT: elm_image_file_set(obj, m_edjFilePath.c_str(), focused ? "ic_zoom_indicator_right_foc.png" : "ic_zoom_indicator_right_nor.png"); + break; + case DOWN: elm_image_file_set(obj, m_edjFilePath.c_str(), focused ? "ic_zoom_indicator_down_foc.png" : "ic_zoom_indicator_down_nor.png"); + break; + case UP: elm_image_file_set(obj, m_edjFilePath.c_str(), focused ? "ic_zoom_indicator_up_foc.png" : "ic_zoom_indicator_up_nor.png"); + break; + default: BROWSER_LOGD("[%s:%d] Warning: Unhandled button", __PRETTY_FUNCTION__, __LINE__); + break; + } +} + +void ZoomUI::_zoom_slider_changed(void *data, Evas_Object *obj, void *event_info) +{ + BROWSER_LOGD("[%s:%d] ", __PRETTY_FUNCTION__, __LINE__); + if(data && obj) { + int val = elm_slider_value_get(obj); + int zoomLevel = ZOOM_DEFAULT; + ZoomUI *zoomUI = static_cast(data); + + switch (val) { + case 1: zoomLevel = ZOOM_50; + break; + case 2: zoomLevel = ZOOM_75; + break; + case 3: zoomLevel = ZOOM_DEFAULT; + break; + case 4: zoomLevel = ZOOM_150; + break; + case 5: zoomLevel = ZOOM_200; + break; + case 6: zoomLevel = ZOOM_300; + break; + default:BROWSER_LOGD("[%s:%d] Warning: Unhandled zoom level", __PRETTY_FUNCTION__, __LINE__); + break; + } + zoomUI->setZoom(zoomLevel); + } +} + +void ZoomUI::_left_button_clicked(void * data, Evas_Object * obj, void * event_info) +{ + BROWSER_LOGD("[%s:%d] ", __PRETTY_FUNCTION__, __LINE__); + if (data && obj) { + ZoomUI *zoomUI = static_cast(data); + zoomUI->scrollView(iDX, 0); + } +} + +void ZoomUI::_right_button_clicked(void * data, Evas_Object * obj, void * event_info) +{ + BROWSER_LOGD("[%s:%d] ", __PRETTY_FUNCTION__, __LINE__); + if (data && obj) { + ZoomUI *zoomUI = static_cast(data); + zoomUI->scrollView(DX, 0); + } +} + +void ZoomUI::_up_button_clicked(void * data, Evas_Object * obj, void * event_info) +{ + BROWSER_LOGD("[%s:%d] ", __PRETTY_FUNCTION__, __LINE__); + if (data && obj) { + ZoomUI *zoomUI = static_cast(data); + zoomUI->scrollView(0, iDX); + } +} + +void ZoomUI::_down_button_clicked(void * data, Evas_Object * obj, void * event_info) +{ + BROWSER_LOGD("[%s:%d] ", __PRETTY_FUNCTION__, __LINE__); + if (data && obj) { + ZoomUI *zoomUI = static_cast(data); + zoomUI->scrollView(0, DX); + } +} + +void ZoomUI::_cb_focus_in_left_button(void * data, Evas *, Evas_Object *obj, void *) +{ + BROWSER_LOGD("[%s:%d] ", __PRETTY_FUNCTION__, __LINE__); + if (data && obj) { + elm_object_focus_set(obj, EINA_TRUE); + ZoomUI *zoomUI = static_cast(data); + zoomUI->setImageFile(obj, LEFT, true); + } +} + +void ZoomUI::_cb_focus_out_left_button(void * data, Evas *, Evas_Object *obj, void *) +{ + BROWSER_LOGD("[%s:%d] ", __PRETTY_FUNCTION__, __LINE__); + if (data && obj) { + elm_object_focus_set(obj, EINA_FALSE); + ZoomUI *zoomUI = static_cast(data); + zoomUI->setImageFile(obj, LEFT, false); + } +} + +void ZoomUI::_cb_focus_in_right_button(void * data, Evas *, Evas_Object *obj, void *) +{ + BROWSER_LOGD("[%s:%d] ", __PRETTY_FUNCTION__, __LINE__); + if (data && obj) { + elm_object_focus_set(obj, EINA_TRUE); + ZoomUI *zoomUI = static_cast(data); + zoomUI->setImageFile(obj, RIGHT, true); + } +} + +void ZoomUI::_cb_focus_out_right_button(void * data, Evas *, Evas_Object *obj, void *) +{ + BROWSER_LOGD("[%s:%d] ", __PRETTY_FUNCTION__, __LINE__); + if (data && obj) { + elm_object_focus_set(obj, EINA_FALSE); + ZoomUI *zoomUI = static_cast(data); + zoomUI->setImageFile(obj, RIGHT, false); + } +} + +void ZoomUI::_cb_focus_in_up_button(void * data, Evas *, Evas_Object *obj, void *) +{ + BROWSER_LOGD("[%s:%d] ", __PRETTY_FUNCTION__, __LINE__); + if (data && obj) { + elm_object_focus_set(obj, EINA_TRUE); + ZoomUI *zoomUI = static_cast(data); + zoomUI->setImageFile(obj, UP, true); + } +} + +void ZoomUI::_cb_focus_out_up_button(void * data, Evas *, Evas_Object *obj, void *) +{ + BROWSER_LOGD("[%s:%d] ", __PRETTY_FUNCTION__, __LINE__); + if (data && obj) { + elm_object_focus_set(obj, EINA_FALSE); + ZoomUI *zoomUI = static_cast(data); + zoomUI->setImageFile(obj, UP, false); + } +} + +void ZoomUI::_cb_focus_in_down_button(void * data, Evas *, Evas_Object *obj, void *) +{ + BROWSER_LOGD("[%s:%d] ", __PRETTY_FUNCTION__, __LINE__); + if (data && obj) { + elm_object_focus_set(obj, EINA_TRUE); + ZoomUI *zoomUI = static_cast(data); + zoomUI->setImageFile(obj, DOWN, true); + } +} + +void ZoomUI::_cb_focus_out_down_button(void * data, Evas *, Evas_Object *obj, void *) +{ + BROWSER_LOGD("[%s:%d] ", __PRETTY_FUNCTION__, __LINE__); + if (data && obj) { + elm_object_focus_set(obj, EINA_FALSE); + ZoomUI *zoomUI = static_cast(data); + zoomUI->setImageFile(obj, DOWN, false); + } +} + + +} +} diff --git a/services/ZoomUI/ZoomUI.h b/services/ZoomUI/ZoomUI.h new file mode 100644 index 0000000..e6206a8 --- /dev/null +++ b/services/ZoomUI/ZoomUI.h @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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 ZOOMUI_H +#define ZOOMUI_H + +#include +#include + +#include "AbstractUIComponent.h" +#include "AbstractService.h" +#include "ServiceFactory.h" +#include "service_macros.h" + +namespace tizen_browser{ +namespace base_ui{ + +class BROWSER_EXPORT ZoomUI + : public tizen_browser::interfaces::AbstractUIComponent + , public tizen_browser::core::AbstractService +{ +public: + ZoomUI(); + ~ZoomUI(); + + //AbstractUIComponent interface methods + void init(Evas_Object* parent); + Evas_Object* getContent(); + void showUI(); + void hideUI(); + std::string getName(); + + void show(Evas_Object* parent); + void clearItems(); + + boost::signals2::signal closeZoomUI; + boost::signals2::signal setZoom; + boost::signals2::signal scrollView; +private: + void createLayout(Evas_Object* parent); + void createZoomSlider(); + void createNavigationButtons(); + void setImageFile(Evas_Object* obj, int direction, bool focused); + + static void _zoom_slider_changed(void * data, Evas_Object * obj, void * event_info); + static void _left_button_clicked(void * data, Evas_Object * obj, void * event_info); + static void _right_button_clicked(void * data, Evas_Object * obj, void * event_info); + static void _up_button_clicked(void * data, Evas_Object * obj, void * event_info); + static void _down_button_clicked(void * data, Evas_Object * obj, void * event_info); + static void _close_button_clicked(void * data, Evas_Object * obj, void * event_info); + static void _cb_focus_in_left_button(void * data, Evas *, Evas_Object *obj, void *); + static void _cb_focus_out_left_button(void * data, Evas *, Evas_Object *obj, void *); + static void _cb_focus_in_right_button(void * data, Evas *, Evas_Object *obj, void *); + static void _cb_focus_out_right_button(void * data, Evas *, Evas_Object *obj, void *); + static void _cb_focus_in_up_button(void * data, Evas *, Evas_Object *obj, void *); + static void _cb_focus_out_up_button(void * data, Evas *, Evas_Object *obj, void *); + static void _cb_focus_in_down_button(void * data, Evas *, Evas_Object *obj, void *); + static void _cb_focus_out_down_button(void * data, Evas *, Evas_Object *obj, void *); + + std::string m_edjFilePath; + Evas_Object* m_layout; + Evas_Object* m_zoom_slider; + Evas_Object* m_nav_layout; + Evas_Object* m_parent; + + int m_current_translation_x; + int m_current_translation_y; + + enum ZoomLevel { + ZOOM_50 = 50, + ZOOM_75 = 75, + ZOOM_100 = 100, + ZOOM_150 = 150, + ZOOM_200 = 200, + ZOOM_300 = 300, + + ZOOM_MIN = ZOOM_50, + ZOOM_DEFAULT = ZOOM_100, + ZOOM_MAX = ZOOM_300 + }; + enum ArrowType { + LEFT = 1, + RIGHT = 2, + UP = 3, + DOWN = 4 + }; +}; + +} +} + +#endif // ZOOMUI_H diff --git a/services/ZoomUI/edc/ZoomUI.edc b/services/ZoomUI/edc/ZoomUI.edc new file mode 100644 index 0000000..e3da119 --- /dev/null +++ b/services/ZoomUI/edc/ZoomUI.edc @@ -0,0 +1,277 @@ +#define RESOURCE_IMAGE_LOSSY( FILE_NAME ) \ + group { \ + name: FILE_NAME; \ + images.image: FILE_NAME LOSSY 100; \ + parts { \ + part { name: "image"; \ + description { \ + state: "default" 0.0; \ + image.normal: FILE_NAME; \ + aspect: 1 1; \ + aspect_preference: BOTH; \ + } \ + } \ + } \ + } + + +collections { + +#define WIDTH 1920 +#define HEIGHT 976 + +RESOURCE_IMAGE_LOSSY("ic_zoom_indicator_down_foc.png"); +RESOURCE_IMAGE_LOSSY("ic_zoom_indicator_down_nor.png"); +RESOURCE_IMAGE_LOSSY("ic_zoom_indicator_left_foc.png"); +RESOURCE_IMAGE_LOSSY("ic_zoom_indicator_left_nor.png"); +RESOURCE_IMAGE_LOSSY("ic_zoom_indicator_right_foc.png"); +RESOURCE_IMAGE_LOSSY("ic_zoom_indicator_right_nor.png"); +RESOURCE_IMAGE_LOSSY("ic_zoom_indicator_up_foc.png"); +RESOURCE_IMAGE_LOSSY("ic_zoom_indicator_up_nor.png"); + + group { + name: "zoom-layout"; + data.item: "contents" "close_button"; + + parts { + + part { name: "bg"; + type: RECT; + mouse_events: 1; + description { state: "default" 0.0; + color: 0 0 0 50; + visible: 1; + min: WIDTH HEIGHT; + max: WIDTH HEIGHT; + align: 0.0 0.0; + rel1 {relative: 0.0 0.0; offset: 0 104;} + rel2 {relative: 1.0 1.0;} + } + } + + part { name: "zoom_rect"; + type: RECT; + mouse_events: 1; + description { state: "default" 0.0; + color: 230 230 230 255; + min: 700 300; + max: 700 300; + visible: 1; + align: 0.0 1.0; + rel1 { + to: "bg"; + offset: 0 0; + relative: 0.0 0.0; + } + rel2 { + to: "bg"; + relative: 1.0 1.0; + } + } + } + + part { name: "slider_swallow"; + type: SWALLOW; + description { + min: 500 100; + max: 500 100; + visible: 1; + fixed: 1 1; + align: 0.0 0.0; + rel1 { + relative: 0.15 0.4; + to: "zoom_rect"; + } + rel2 { + relative: 0.0 0.0; + to: "zoom_rect"; + } + } + } + + part { name: "zoom_text"; + type: TEXT; + description { + visible: 1; + min: 200 122; + max: 200 122; + align: 0.0 0.0; + fixed: 1 1; + color: 51 51 51 255; + rel1 { + to: "zoom_rect"; + relative: 0.45 0.0; + offset: 0 0; + } + rel2 { + to: "zoom_rect"; + relative: 1.0 1.0; + } + text { + text: "Zoom"; + font: "Sans"; + size: 32; + align: 0 0.5; + } + } + } + + part { name: "slider_begin_text"; + type: TEXT; + description { + visible: 1; + min: 100 122; + max: 100 122; + align: 0.0 0.0; + fixed: 1 1; + color: 51 51 51 255; + rel1 { + to: "slider_swallow"; + relative: 0.0 0.0; + offset: -50 -10; + } + rel2 { + to: "slider_swallow"; + relative: 1.0 1.0; + offset: 0 0; + } + text { + text: "50%"; + font: "Sans"; + size: 22; + align: 0 0.5; + } + } + } + + part { name: "slider_end_text"; + type: TEXT; + description { + visible: 1; + min: 100 122; + max: 100 122; + align: 0.0 0.0; + fixed: 1 1; + color: 51 51 51 255; + rel1 { + to: "slider_swallow"; + relative: 1.0 0.0; + offset: 5 -10; + } + rel2 { + to: "slider_swallow"; + relative: 1.0 1.0; + offset: 0 0; + } + text { + text: "300%"; + font: "Sans"; + size: 22; + align: 0 0.5; + } + } + } + + + part { + name: "nav_buttons"; + type : SWALLOW; + scale: 1; + description { + state: "default" 0.0; + visible: 1; + min: WIDTH HEIGHT; + max: WIDTH HEIGHT; + align: 0.0 0.0; + fixed: 0 0; + rel1 { relative: 0.0 0.0; to: "bg"; } + rel2 { relative: 1.0 1.0; to: "bg"; } + } + } + + } + } + + group { + name: "nav-layout"; + min: WIDTH HEIGHT; + max: WIDTH HEIGHT; + data.item: "contents" "left_button right_button up_button down_button"; + parts { + part { + name: "left_button"; + type: SWALLOW; + mouse_events: 1; + scale: 1; + description { + state: "default" 0.0; + visible: 1; + align: 0 0.5; + fixed: 1 1; + min: 90 90; + max: 90 90; + rel1 { relative: 0.0 0.0; offset: 38 0;} + rel2 { relative: 1.0 1.0;} + } + } + part { + name: "right_button"; + type: SWALLOW; + scale: 1; + mouse_events: 1; + description { + state: "default" 0.0; + visible: 1; + align: 1 0.5; + fixed: 1 1; + min: 90 90; + max: 90 90; + rel1 { relative: 0.0 0.0; } + rel2 { relative: 1.0 1.0; offset: -38 0; } + } + } + part { + name: "up_button"; + type: SWALLOW; + scale: 1; + mouse_events: 1; + description { + state: "default" 0.0; + visible: 1; + align: 0.5 0; + fixed: 1 1; + min: 90 90; + max: 90 90; + rel1 { relative: 0.0 0.0; offset: 0 38; } + rel2 { relative: 1.0 1.0; } + } + } + part { + name: "down_button"; + type: SWALLOW; + scale: 1; + mouse_events: 1; + description { + state: "default" 0.0; + visible: 1; + align: 0.5 1; + fixed: 1 1; + min: 90 90; + max: 90 90; + rel1 { relative: 0.0 0.0; } + rel2 { relative: 1.0 1.0; offset: 0 -38; } + } + } + } + programs{ + program { + name: "mouse_click"; + signal: "mouse,clicked,1"; + source: "*"; + script { + emit("elm,action,click", ""); + } + } + } + } +} \ No newline at end of file diff --git a/services/ZoomUI/images/ic_zoom_indicator_down_foc.png b/services/ZoomUI/images/ic_zoom_indicator_down_foc.png new file mode 100644 index 0000000000000000000000000000000000000000..797738cdcdc4f65b219602cf020801ce7b7f6218 GIT binary patch literal 2807 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 literal 0 HcmV?d00001 diff --git a/services/ZoomUI/images/ic_zoom_indicator_down_nor.png b/services/ZoomUI/images/ic_zoom_indicator_down_nor.png new file mode 100644 index 0000000000000000000000000000000000000000..1ec7c1a80d11c72e90d59cfa1a80266960d0ad66 GIT binary patch literal 2728 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 QT>5wPbn|7LrA24{2lAhgh5!Hn literal 0 HcmV?d00001 diff --git a/services/ZoomUI/images/ic_zoom_indicator_left_foc.png b/services/ZoomUI/images/ic_zoom_indicator_left_foc.png new file mode 100644 index 0000000000000000000000000000000000000000..d224bb1106fde1b80ad4e7e76f3f189d3f3e47c6 GIT binary patch literal 2786 zcmbVOdpwi-A0H}3lA@5DwVd4AW@A^D%`VPz-`pZGyD)6iHjIwk(oLLla1v>5kxKES zs8C7=jg|dY6=X;AeV&$`5;`ZTq23= zQ0@~i4McbDdNNf>P z$c+?p1$^KVBO_Q4CB}i2mVR}C7wO{iH!)xIEl|pkK_!exC=6l+is5V2eV?x6y)Koly7 z1QO{;pqUSs&l1Fl%$L&h)msu<$c<*RC_(`b_$9tr?my^9JD_b~NQwgr3AZLAU@!t2 zMIw+XM4~l}q+C0IzF}GaPt2f7W1vgL@ju0~yrrzbrRm?LuU!1yJZ!$QV}#1qaM@Dw z2LPbHfl4BHN}f)fjg9d1(!KvsY~Y_$lPcA7w@Tcm(YgVDCoyQX?eX1G&#TS$c-1v3 z8;c(4TOB5W!nE|6q?~GBwcR>tn#Ze1crYjow4RjOt)G3^A@3EuV7lQkEo^MI<1ME% zFE;S4ikh{o-X1bmIlV8?O5en-(^Ad;!;|hf6C+w={Ix$sXO4g}5PrEItB+JobF@$P z;`)aA%Z&s2Rid>P;0qcz&n#LltX*)7F1~oetJ3VB>3fgKYJQ{bZ9+*)$ZE(7X#R{EUYQY-VJsVNZfu2ceoCjW z-8EksJU<2A;MA35dtZh0C$)9? zCUu51J%edoh-x+qlS9e27Q2PNYZRB`wM|95hd!dIz#IMZF*GAos8Z^2~$LPV=SJZj+7h<&w@tf-kJ#p9t z#fuh{$Fz}`0ly$X-q6RaAx>pcJ-uI+QPsK>Lk>;n<+m%#w#w5bs@ z${vxXr}vf19{C*gce<0cv5Q&GXQF(tBaBpXsS0-Pz|Ys#m-VUOysclBzURot_m6Ul z%CvhP7tqrU?-~v0C=Rli$tE5SU`RnW_fyQXulpYC9H=5UvHJFe6 z(=EN`#{`^t?|MsliVfw&)WCw~BE{{+k%}D_gIlHdcTDCBSpA#C3A{(6ta-(=pAWWA zj~Cllq}cGB62nw0^>4kqt~%sMFZnDkYS8>-gSJnvcqDD_aH{5=o)J61HyZ`YS?)tuS zzj#;Dy`>LpU7q_Lin@~=Flr}$oxQ0=YXoB{cTaty@V{~?XmWjkeQAXvl(jlLywbwg za_~(lrtQ!jS#gTzT-Afg#QVgwiV*!LS-o3ox7?lKi8>ay9$yiyt~|&kIwDdi1(Zh0 zFh!g7!r5!ya01e=qBZ$sxTIJeK64fjFFb#2G^gB;H28Q}@G%m}wRPl-Qak3Nvksdk z-WzVoc`=N|!Z!+b&eo+~rfKXyU*Kg~?Qx*E+&O4=ce#CyYCJ6tSTM2XlErovE!^v# zuz}in%te%Vg<%;xTViCZyUy$r(oim^vy8u+xDcPzF`hBZQWs~JtamGX9PYIfzlFY* zRWS1E73C~2FXVLJ%Jdf7{0K=8bD-#Aa|tX*S{T^(z^)POx5L@&iF8~3I`0V>Qa?g- zOzo5m`aE{5TKDj$ZF}rywmQjMsc7(ouZ9C9S95ao_fP_{E`wRI_A#AoS}N-~^&|RB z=^7brWcN?o%>naAvk=b*AVmRc&E>1zj!iiQw=R^N@JP>KR`q#1j$-uM`nH(oRQHe< zHn)U%ZA>T5z%tvc%IhuIdvvIG$4nHQk-F&ooza88-yI*J<(zIi78Q3Q=Zzf0SsWB6 z1YW*pwDNS13tJ;+?0TZ zi=UEszurr+xsrCEO&$$jICy;M&Q9Oi569z=%Jjz5j>$X>=NeRR`v)u5-8iUckrAwT z(3mS5>)wx!o>}zoEon+q&;J~J&Q#93PYb|qCh1SS6k^f|P~ literal 0 HcmV?d00001 diff --git a/services/ZoomUI/images/ic_zoom_indicator_left_nor.png b/services/ZoomUI/images/ic_zoom_indicator_left_nor.png new file mode 100644 index 0000000000000000000000000000000000000000..bdc35fe9fe93e18b3d5ec84833b12b8f78a9d114 GIT binary patch literal 2764 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 C3$>d7 literal 0 HcmV?d00001 diff --git a/services/ZoomUI/images/ic_zoom_indicator_right_foc.png b/services/ZoomUI/images/ic_zoom_indicator_right_foc.png new file mode 100644 index 0000000000000000000000000000000000000000..2509aa1295d00e3c3ed740fa9a89ef1ab0c3dce6 GIT binary patch literal 2777 zcmbVOc|4T)AD^g%6jmjRrg21=i#ang=0L6tNhFP#$IL7E&xD8CO-@SyL0I*fCkW+anZK{M-WIo zoZ}xT3iR^CGx%I6eOU%7;YO*@AduruNfezC0f@k10E@#TKwh=9L%~ z0c?(2ya4cv_x5MRM=)?q$WAA)qXe%a-~u8#Si+6u3GosFyxxlL<9b7 z#@|W{{o|ql7!45eV+0IUKElnuf>p8mXGP0`Dr@jQ0*)#v^hh$F5yJ&|B6l(YqB?;x zIZV6@8SQ|?qKG&g1xs;2Ag~yFG?{Eq#JFIPSPBO5mE-TQ6e7YNLq?F0R2&L{prBlk z7<(d;LPo&RL^Oi@4eQPmis(EB@KrBIrS}Wg}K;td?A}3 z1t$5S!B%@YJSIO@XuX`C&)$*&0Y?llsRBM1{3*V8&fnQeF0eGs85vW>29=-?# zfiyJT$wYt2sIpiZX|TtjyI1^dbj~e!%_vA~HJofZc}6aW7^*$(4>U`oC6_LN^z;u? zT@EK6*=o3@0u@%OXJ?ROROKJ%wle+rnhJ`u*UG~cIhNG&$^P)M+4$>)4XMtt_(i9N z9iekX?G|No`+@t9gnx|hIDHWAR;^zH{j;l~{pE!$DPEEG z@DyXq!B?!ruIoAJa_wP2iBm3qcl5@;)NM9RWh5SHlZAABgpKHUi?dAckKc0Ytv=}E zMq6w8*F~+rlrnvf(PYz(YGBEnV2epz$`o3x?wo7xoRRd!)?Tg6u4nD)9e{KqNnvA< zI{Z2Z!IIW|jgkf=?NB?gy{_7AFvdntu2J`5xTd}Z&#oBT6IPv1FaM#>=Z>NHVoHQ| z=f|=}iU}LG=rwOCe(zv4ea$0yJnu>+sJNp#9Olt+C$6&5ZrhOj&4_f^g5&7r3*q+o zY*46KM{lDoM3gpO29LT_BCPs>u>tbXmZDm@2x@__0=?FS_@Hr zhUNxuTOCY7$lKusC02d0b(p4K#@=PY({0!_)8}~532{uOdFa@xwj&8OcjqmWZ$FVF zLz(TeLdx_`EmT-W0!wrd)mrF%^&B_2Tkh*_$E_t;~oR- zU`l|Wet`T$OB?RVfi_24UqSiF+4{`D2J4=+q1Zm5^<@vWQ&o?mQhtt-dt4@u!+J@f zP6^uYUd|NQqHjVK*Ojk>O2-e(lv$@VR9t!F8q#30!brI=ydvc6Ge}eGmDK7hy0R8R z=9S|Mw=N`}sXJfRALL5+d0_Bva_3mZp_YlB)!rPWS)@;%bv zUuyO`4ySIMcu3iy&@4_ibwgXa(ayw#UL8n#6(p;%$!L&`UkXgUfwWcVoh%Ez){rXx zs1KiWm_yB736s^T5j=&{$!OD9-n$3sX=ujExo3w;5Fh-i=mByKj?a&V$(|F6^X*0{ z{=*%lmW>NmFjosDF+jeUufFnD(&J&{vy-X&8X2dv4=vEdi8g&#apfOe79^4RB_CFl z-d1l=q})uH?jNetzU2H~FwlA9qdoU+4{N5jCi3Ws052L!`GT_w|FiMA_gRfbq@C=0 zM1ZvT#0<{0Wfbw1OJI90l4cvNJj@bF$K zJNG6gdrove=}rNT3cDJBQ+Bk5k%dcuGK;HYPpc7>+ zVp%xAWQ*y$hQPKRhtr-rP_wq~R~(=#yfedwVgfe1NE<03$iWB$i@u17{VlN-fl_5s z_c;nGef|4Ym|nymC;Kx?CLWjm_&l}k?mG4vSY6+fHaJ5qN;`6cWA~V+{c^L)a;2<~M)b^E>B!%Xy#YdB694zwdXl0{pz7 z>Za-t2n0&;ChrE@khMou8GPd^Nb+D~BJ>Cr?g0)76X|>wgv10QSTG8g9?9CxqB9T2 z-D9~xAPR>#fx*IHsxN^7a1r!18-$1(3!)(q7gtd%oe|9v!Xj9a93BzAAZdfcI7}iu z$cgGejdf?SIo?Tp)}AE4Kt@tD1J8uJ?tr<72p|EMC8Wbd+!&sKAR@v)^Af=R+B6al z`)neNCc^)8DwrAoa|ie=m=gkR&u~DYU|1{yg>k}SQFbs#2b3ey0lcyHC=9^~OK^0C zeYxPE8lQQHu$%1pMGG7e;cTHWmViViCMF^h(FlMaiA3S?_%#kkM|;r1UT~Nvq>Jo% zf-UO|WR`%z=fny*01vjtNRI&Gg+w^$>7PsB#!{(&5%UCJ0tJQ)DWbMn3p93a^9zzBg@mv;9 zNFfv9;1>jw!z8$ou^3036A6#^z+B(Juz4kiR6ZN z^u#-%P#z$O0~UuSlgJn{8jnHa*Rd3yKuG5?SnIkRQ1=TK_m5bDJD)`t0{lP#h*__I z05%{51Z*G{=Dr6D`znaTV*-f+>$UX!xmq%d&q-i0J^26^_Bp-;&fnxlLMy(i(E$s`X?cXu?3436F4U$D&oCuT^{8RS}V{7Cm7*VXwsVu%}-hlzd2s5m{QT{`7rmIJ~Tq1U?+TEiVih8pz!?7043idZTf+8 zXi=Sh;=;4!G>IUg-_@kKXJj5&=o90o=QrIM8p_{#F+-7^VyvR7x!U7BaQPC=_I6>0 zcy!u=M(Q0Oxoy>6nntZVrBz3F*gmQ=3j0uUQd1PVQBxUM)lqLSork_h9ZCDwg6il& znzlISFj^?mz&txUcl%MghfJ^L&iK5_oU)`lTx|!`^bSckINj(@pqmJ;eDLpvvsE2+mc4(c91ZQGMAKVwM~(|}d>yWdrU z(W3$&T}$!4{I~Cay^_77&T8N6oR(>o#DDbGQCHPz|GwxeHq+?j6N%TPr(izw^*=}% zBl!zaCM!E+xRl~k`|5{=%T(CC2-((8d+iu?6=fqIXzG_edSG$&JKMAht&H0OZ5Y?e z%Aj^w6Q%JY$I7gcuSspthTU~39=0aMN^&_q)MBMQjgNbcf8O}ku)6uezrV^w{a`es zTF6m7+}8zvsgRUMs|YT>ksfaGAavqFc+b@V`J@Z9%OM+w)4RmYitW^!y2jh@mW^b| z$bt>m{h%{9nX^xahFI9**Y_tUCoh%U4zJP|8VBne)J8`|Elx~Kj7P=9JT*5kxa+>d ze5x`vPALg$S$k>|elcV4m5}V^)!o?8@C#I3T}H2pvr8j; zz8y^Ydl9^yzJMI=#H5rA0waP0d2_Kml}fn7-2M z*RTB-mzHcdX>|`~W@ZlC+uJKyZnnVngEXSXlE893)&ke8R&*VNPm<#M^r za&mIYZiwSOX<9Ei5idsT8Hs%*_&pgT6bdEu>b@#*ZgM-ntjN2>8i}l}Zf^b!9=B|kdT(N)X+~1e4_KKaEfe+dmjZJ zGGk+72UV1nk85dbYj-?fF_3Gld}AIYp=@?>>mt4BIHr-T1i@$}@qykVTTZtPsMf7*`t*`X6+vG~caE$7a?xZKgvQAG~hSfoJg(_?OW z3!59w7{M8b*cE!Z{X#5IAa-a>j!6=0cN|%XmFtXT0Kmf88#iu5W%lQ{+|sF1>%`?a;^~Si zMyZ?1ERbCqTK(v?wYBwN^s&hP(rUcu&2wr8^2Z?K7Wt2YH&lD8A+oF>7AjPuG>ylAUsdvTItMh^|^ZB{Cx%PK% zVa{8%n#YH6)4cMU;_MNrRJxZ)B(@d*{1S+5&CQTVU(ULYwZ1ZIEREpUCgfM@8B)i6 z1kcVOm&-q>CH9}p?UqPc%L>huKSI-sqs9`JmGA=@HJ<(!QeVbS4farcyMH}%|6%!@ z{(%GS0~dawn6;2>_GjKT&^SSRwXdiA&Y-ikT+Y2^r}n|>8j8A=ET3n;0-dj?t!A5{ zu@BwSx-8Ed7UpVv3@W+dtzN8MDYeUJB|HI7h^V5#x5&K`+bcc@>*ebm7kz%#W=sD# z)=EhJc*~*r{QDC(QoGI^<$h!So5iG8lx*<`sekgjoU6XeM$l{BSFe=oP-zACs;IQc zt&dIT6q8m9EV4YuT2f0lVB_dJ<vHG6TC=rW$iHhUp-51ABGfK6W?PkB+t5<6>K-oZeZtDiosdVZeYTN?hc z`1jc}#GsBt`$tW;dGZHWC>OenpSoT$`k?03`VMj>wbXWAJr%mQUb}n#LO{m;CRE=~ zx&vKesrW^gFzhQ!f&T1Uxu0bEtj!DTb9akyH6hzR+TMnAW~B^gQlGNdek~~;e&iZA HTKazgHFuh~ literal 0 HcmV?d00001 diff --git a/services/ZoomUI/images/ic_zoom_indicator_up_foc.png b/services/ZoomUI/images/ic_zoom_indicator_up_foc.png new file mode 100644 index 0000000000000000000000000000000000000000..ee95deec26860d1ab8b6ed7b74b14a160562542e GIT binary patch literal 2803 zcmbVOc|4T)A0J0$=@Q0OjKMPPnlWQ8v&I-^CgaSts10LgFvc8ao{S@@l%sM~rVtV; z5+SP15?V*eQHrdFPLXS~j%=ylXtTfHAN$%re$VT9p6~T}zd!f$dQx|~?bx8IrwRgr zHqad@p7L?m%A>MY{>GP*73G62K=lK>1R;QgA!38bEI}|ELgz6;*`90$D<<+T+Xe(u z3gLMB0e-G71g3xoXROG;qj^F(8U(T-MGF~BE*pRZvqL$2B6OzyHWb2P5uv^qS4&r+ z13Qf47%O6X#kzSjW4TOg7L;TQv56+g33zOP0g2{C@Wq5^BJ>L{K|WvEMnEB7L;x-k z`j=6Dt~((P0udX6fm>NHEs;nF77ItBF<30}dkD%Bi9%S)Z>$9pO~7CYC>-SL1(j

NLi@yd+9x_BULx@1aEfGB4ieF!(#egUK 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