From 5d1d6731421318519c3e013897213bd598a2741a Mon Sep 17 00:00:00 2001 From: "sungwook79.park" Date: Fri, 28 Jul 2017 16:23:41 +0900 Subject: [PATCH] Upload initial code Change-Id: I6af96280a49f83334e164edc661066f8af2cc2fc Signed-off-by: sungwook79.park --- Build/appendix.mk | 1 + Build/basedef.mk | 34 + Build/build_c.mk | 113 + Build/build_edc.mk | 81 + Build/build_po.mk | 64 + Build/flags.mk | 16 + Build/funcs.mk | 50 + Build/makefile | 34 + Build/makefile.mk | 197 ++ Build/platform.mk | 15 + Build/tooldef.mk | 70 + build_def.prop | 6 + edje_images/b_ic_press_full_circle_bg.png | Bin 0 -> 7317 bytes edje_images/gear_tutorial_bg.png | Bin 0 -> 6922 bytes edje_images/gear_tutorial_bg_focus.png | Bin 0 -> 39725 bytes .../gear_tutorial_bt_cancel_normal.png | Bin 0 -> 2464 bytes edje_images/gear_tutorial_bt_cancel_press.png | Bin 0 -> 2804 bytes edje_images/gear_tutorial_rotate_ccw.png | Bin 0 -> 3687 bytes edje_images/gear_tutorial_rotate_cw.png | Bin 0 -> 3767 bytes edje_images/wi_more_option_bg.png | Bin 0 -> 6340 bytes inc/DrDebug.h | 14 + inc/DrDefine.h | 115 + inc/app-assist-efl/IWWindowController.h | 83 + inc/app-assist-efl/WApp.h | 137 + inc/app-assist-efl/WAppEventHandler.h | 80 + inc/app-assist-efl/WContentViewController.h | 294 +++ inc/app-assist-efl/WDebugBase.h | 151 ++ inc/app-assist-efl/WDefine.h | 62 + inc/app-assist-efl/WEvasObject.h | 42 + inc/app-assist-efl/WGengridItem.h | 176 ++ inc/app-assist-efl/WGenlistItem.h | 175 ++ inc/app-assist-efl/WMenuPopupController.h | 86 + inc/app-assist-efl/WNaviframeController.h | 197 ++ inc/app-assist-efl/WPageSlideViewController.h | 250 ++ inc/app-assist-efl/WPopupController.h | 168 ++ inc/app-assist-efl/WSignal.h | 245 ++ inc/app-assist-efl/WSignalIdGenerator.h | 40 + inc/app-assist-efl/WSignalImpl.h | 128 + inc/app-assist-efl/WUiThread.h | 232 ++ inc/app-assist-efl/WUiTimer.h | 239 ++ inc/app-assist-efl/WViewController.h | 222 ++ inc/app-assist-efl/WWindowController.h | 246 ++ packaging/projects.list | 1 + project_def.prop | 63 + res/edje/animations2circle.edc | 943 +++++++ res/edje/btneffect.edc | 2321 +++++++++++++++++ res/edje/drawing_layout.edc | 216 ++ res/edje/drawing_popup.edc | 153 ++ res/edje/drawing_stroke.edc | 205 ++ res/images/b_ic_press_full_circle_bg_a.png | Bin 0 -> 8859 bytes res/images/b_more_option_icon_bg.png | Bin 0 -> 1679 bytes res/images/b_more_option_icon_select_bg.png | Bin 0 -> 1925 bytes res/images/b_slider_icon_minus.png | Bin 0 -> 2894 bytes res/images/b_slider_icon_plus.png | Bin 0 -> 2933 bytes res/images/drawing_popup_btn_check.png | Bin 0 -> 1331 bytes res/images/drawing_popup_btn_delete.png | Bin 0 -> 1457 bytes res/images/wear_comm_stroke_option.png | Bin 0 -> 633 bytes res/images/wi_drawing_bg_01.png | Bin 0 -> 40493 bytes res/images/wi_drawing_bg_02.png | Bin 0 -> 58234 bytes res/images/wi_drawing_bg_03.png | Bin 0 -> 45464 bytes res/images/wi_drawing_bg_04.png | Bin 0 -> 66637 bytes res/images/wi_drawing_bg_pattern.png | Bin 0 -> 3069 bytes res/images/wi_drawing_bg_pattern_negative.png | Bin 0 -> 2183 bytes res/images/wi_drawing_more_options_erase.png | Bin 0 -> 1527 bytes res/images/wi_drawing_more_options_icon.png | Bin 0 -> 1512 bytes .../wi_drawing_select_button_center.png | Bin 0 -> 1596 bytes res/po/ar.po | 33 + res/po/as.po | 33 + res/po/az.po | 33 + res/po/be_BY.po | 33 + res/po/bg.po | 33 + res/po/bn.po | 33 + res/po/bn_BD.po | 33 + res/po/bs_BA.po | 33 + res/po/ca.po | 33 + res/po/cs.po | 33 + res/po/da.po | 33 + res/po/de.po | 33 + res/po/el_GR.po | 33 + res/po/en.po | 33 + res/po/en_PH.po | 33 + res/po/en_US.po | 33 + res/po/es_ES.po | 33 + res/po/es_US.po | 33 + res/po/et.po | 33 + res/po/eu.po | 33 + res/po/fa.po | 33 + res/po/fi.po | 33 + res/po/fr.po | 33 + res/po/fr_CA.po | 33 + res/po/ga.po | 33 + res/po/gl.po | 33 + res/po/gu.po | 33 + res/po/he.po | 33 + res/po/hi.po | 33 + res/po/hr.po | 33 + res/po/hu.po | 33 + res/po/hy.po | 33 + res/po/id.po | 33 + res/po/is.po | 33 + res/po/it_IT.po | 33 + res/po/ja_JP.po | 33 + res/po/ka.po | 33 + res/po/kk.po | 33 + res/po/km.po | 33 + res/po/kn.po | 33 + res/po/ko_KR.po | 33 + res/po/ky_KG.po | 33 + res/po/lo.po | 33 + res/po/lt.po | 33 + res/po/lv.po | 33 + res/po/mk.po | 33 + res/po/ml.po | 33 + res/po/mn_MN.po | 33 + res/po/mr.po | 33 + res/po/ms.po | 33 + res/po/my_MM.po | 33 + res/po/my_ZG.po | 33 + res/po/nb.po | 33 + res/po/ne.po | 33 + res/po/nl.po | 33 + res/po/or.po | 33 + res/po/pa.po | 33 + res/po/pl.po | 33 + res/po/pl_SP.po | 33 + res/po/pt_BR.po | 33 + res/po/pt_PT.po | 33 + res/po/ro.po | 33 + res/po/ru_RU.po | 33 + res/po/si.po | 33 + res/po/sk.po | 33 + res/po/sl.po | 33 + res/po/sq.po | 33 + res/po/sr.po | 33 + res/po/sv.po | 33 + res/po/ta.po | 33 + res/po/te.po | 33 + res/po/tg_TJ.po | 33 + res/po/th.po | 33 + res/po/tk_TM.po | 33 + res/po/tl.po | 33 + res/po/tr_TR.po | 33 + res/po/uk.po | 33 + res/po/ur.po | 33 + res/po/uz.po | 33 + res/po/vi.po | 33 + res/po/zh_CN.po | 33 + res/po/zh_HK.po | 33 + res/po/zh_TW.po | 33 + shared/res/org.tizen.sketch.png | Bin 0 -> 2832 bytes .../res/tables/org.tizen.w-drawing_color.xml | 166 ++ .../res/tables/org.tizen.w-drawing_font.xml | 30 + src/CDrUtil.cpp | 519 ++++ src/CDrUtil.h | 52 + src/EventManager/CDrEvent.h | 50 + src/EventManager/CDrEventListener.h | 12 + src/EventManager/CDrEventManager.cpp | 319 +++ src/EventManager/CDrEventManager.h | 59 + src/EventManager/CDrSingleton.h | 34 + src/MediaDB/CDrMediaContent.cpp | 69 + src/MediaDB/CDrMediaContent.h | 29 + src/Singleton.h | 51 + src/View/CDrMainView.cpp | 795 ++++++ src/View/CDrMainView.h | 99 + src/View/CDrStrokeView.cpp | 299 +++ src/View/CDrStrokeView.h | 64 + src/app-assist-efl/WApp.cpp | 149 ++ src/app-assist-efl/WAppEventHandler.cpp | 104 + src/app-assist-efl/WContentViewController.cpp | 228 ++ .../WContentViewControllerImpl.cpp | 62 + src/app-assist-efl/WEvasObject.cpp | 58 + src/app-assist-efl/WGengridItem.cpp | 126 + src/app-assist-efl/WGenlistItem.cpp | 128 + src/app-assist-efl/WMenuPopupController.cpp | 80 + .../WMenuPopupControllerImpl.cpp | 128 + src/app-assist-efl/WNaviframeController.cpp | 245 ++ .../WPageSlideViewController.cpp | 528 ++++ src/app-assist-efl/WPopupController.cpp | 278 ++ src/app-assist-efl/WSignalIdGenerator.cpp | 27 + src/app-assist-efl/WUiThread.cpp | 330 +++ src/app-assist-efl/WUiTimer.cpp | 204 ++ src/app-assist-efl/WUiTimerImpl.cpp | 145 + src/app-assist-efl/WUiTimerImpl.h | 64 + src/app-assist-efl/WVersion.cpp | 49 + src/app-assist-efl/WViewController.cpp | 206 ++ src/app-assist-efl/WViewControllerImpl.cpp | 77 + src/app-assist-efl/WViewControllerImpl.h | 55 + src/app-assist-efl/WWindowController.cpp | 366 +++ .../inc/WContentViewControllerImpl.h | 59 + src/app-assist-efl/inc/WDebugInternal.h | 30 + src/app-assist-efl/inc/WDefineInternal.h | 27 + .../inc/WMenuPopupControllerImpl.h | 59 + src/app/CDrApp.cpp | 315 +++ src/app/CDrApp.h | 51 + src/app/CDrAppData.cpp | 226 ++ src/app/CDrAppData.h | 82 + src/controls/CDrCairoImage.cpp | 1459 +++++++++++ src/controls/CDrCairoImage.h | 278 ++ src/controls/CDrControl.h | 48 + src/controls/CDrControlManager.cpp | 145 + src/controls/CDrControlManager.h | 63 + src/controls/CDrDrawingView.cpp | 852 ++++++ src/controls/CDrDrawingView.h | 110 + src/controls/CDrHistoryControl.cpp | 233 ++ src/controls/CDrHistoryControl.h | 47 + src/controls/CDrTutorialView.cpp | 107 + src/controls/CDrTutorialView.h | 49 + src/controls/Drawing.cpp | 1324 ++++++++++ src/controls/Drawing.h | 159 ++ src/controls/History.cpp | 234 ++ src/controls/History.h | 59 + src/main.cpp | 15 + src/popup/CDrClosePopup.cpp | 121 + src/popup/CDrClosePopup.h | 34 + tizen-manifest.xml | 17 + 215 files changed, 23191 insertions(+) create mode 100644 Build/appendix.mk create mode 100644 Build/basedef.mk create mode 100644 Build/build_c.mk create mode 100644 Build/build_edc.mk create mode 100644 Build/build_po.mk create mode 100644 Build/flags.mk create mode 100644 Build/funcs.mk create mode 100644 Build/makefile create mode 100644 Build/makefile.mk create mode 100644 Build/platform.mk create mode 100644 Build/tooldef.mk create mode 100644 build_def.prop create mode 100755 edje_images/b_ic_press_full_circle_bg.png create mode 100755 edje_images/gear_tutorial_bg.png create mode 100755 edje_images/gear_tutorial_bg_focus.png create mode 100755 edje_images/gear_tutorial_bt_cancel_normal.png create mode 100755 edje_images/gear_tutorial_bt_cancel_press.png create mode 100755 edje_images/gear_tutorial_rotate_ccw.png create mode 100755 edje_images/gear_tutorial_rotate_cw.png create mode 100755 edje_images/wi_more_option_bg.png create mode 100755 inc/DrDebug.h create mode 100755 inc/DrDefine.h create mode 100755 inc/app-assist-efl/IWWindowController.h create mode 100755 inc/app-assist-efl/WApp.h create mode 100755 inc/app-assist-efl/WAppEventHandler.h create mode 100755 inc/app-assist-efl/WContentViewController.h create mode 100755 inc/app-assist-efl/WDebugBase.h create mode 100755 inc/app-assist-efl/WDefine.h create mode 100755 inc/app-assist-efl/WEvasObject.h create mode 100755 inc/app-assist-efl/WGengridItem.h create mode 100755 inc/app-assist-efl/WGenlistItem.h create mode 100755 inc/app-assist-efl/WMenuPopupController.h create mode 100755 inc/app-assist-efl/WNaviframeController.h create mode 100755 inc/app-assist-efl/WPageSlideViewController.h create mode 100755 inc/app-assist-efl/WPopupController.h create mode 100755 inc/app-assist-efl/WSignal.h create mode 100755 inc/app-assist-efl/WSignalIdGenerator.h create mode 100755 inc/app-assist-efl/WSignalImpl.h create mode 100755 inc/app-assist-efl/WUiThread.h create mode 100755 inc/app-assist-efl/WUiTimer.h create mode 100755 inc/app-assist-efl/WViewController.h create mode 100755 inc/app-assist-efl/WWindowController.h create mode 100755 packaging/projects.list create mode 100644 project_def.prop create mode 100755 res/edje/animations2circle.edc create mode 100755 res/edje/btneffect.edc create mode 100755 res/edje/drawing_layout.edc create mode 100755 res/edje/drawing_popup.edc create mode 100755 res/edje/drawing_stroke.edc create mode 100755 res/images/b_ic_press_full_circle_bg_a.png create mode 100755 res/images/b_more_option_icon_bg.png create mode 100755 res/images/b_more_option_icon_select_bg.png create mode 100755 res/images/b_slider_icon_minus.png create mode 100755 res/images/b_slider_icon_plus.png create mode 100755 res/images/drawing_popup_btn_check.png create mode 100755 res/images/drawing_popup_btn_delete.png create mode 100755 res/images/wear_comm_stroke_option.png create mode 100755 res/images/wi_drawing_bg_01.png create mode 100755 res/images/wi_drawing_bg_02.png create mode 100755 res/images/wi_drawing_bg_03.png create mode 100755 res/images/wi_drawing_bg_04.png create mode 100755 res/images/wi_drawing_bg_pattern.png create mode 100644 res/images/wi_drawing_bg_pattern_negative.png create mode 100755 res/images/wi_drawing_more_options_erase.png create mode 100755 res/images/wi_drawing_more_options_icon.png create mode 100755 res/images/wi_drawing_select_button_center.png create mode 100755 res/po/ar.po create mode 100755 res/po/as.po create mode 100755 res/po/az.po create mode 100755 res/po/be_BY.po create mode 100755 res/po/bg.po create mode 100755 res/po/bn.po create mode 100755 res/po/bn_BD.po create mode 100755 res/po/bs_BA.po create mode 100755 res/po/ca.po create mode 100755 res/po/cs.po create mode 100755 res/po/da.po create mode 100755 res/po/de.po create mode 100755 res/po/el_GR.po create mode 100755 res/po/en.po create mode 100755 res/po/en_PH.po create mode 100755 res/po/en_US.po create mode 100755 res/po/es_ES.po create mode 100755 res/po/es_US.po create mode 100755 res/po/et.po create mode 100755 res/po/eu.po create mode 100755 res/po/fa.po create mode 100755 res/po/fi.po create mode 100755 res/po/fr.po create mode 100755 res/po/fr_CA.po create mode 100755 res/po/ga.po create mode 100755 res/po/gl.po create mode 100755 res/po/gu.po create mode 100755 res/po/he.po create mode 100755 res/po/hi.po create mode 100755 res/po/hr.po create mode 100755 res/po/hu.po create mode 100755 res/po/hy.po create mode 100755 res/po/id.po create mode 100755 res/po/is.po create mode 100755 res/po/it_IT.po create mode 100755 res/po/ja_JP.po create mode 100755 res/po/ka.po create mode 100755 res/po/kk.po create mode 100755 res/po/km.po create mode 100755 res/po/kn.po create mode 100755 res/po/ko_KR.po create mode 100755 res/po/ky_KG.po create mode 100755 res/po/lo.po create mode 100755 res/po/lt.po create mode 100755 res/po/lv.po create mode 100755 res/po/mk.po create mode 100755 res/po/ml.po create mode 100755 res/po/mn_MN.po create mode 100755 res/po/mr.po create mode 100755 res/po/ms.po create mode 100755 res/po/my_MM.po create mode 100755 res/po/my_ZG.po create mode 100755 res/po/nb.po create mode 100755 res/po/ne.po create mode 100755 res/po/nl.po create mode 100755 res/po/or.po create mode 100755 res/po/pa.po create mode 100755 res/po/pl.po create mode 100755 res/po/pl_SP.po create mode 100755 res/po/pt_BR.po create mode 100755 res/po/pt_PT.po create mode 100755 res/po/ro.po create mode 100755 res/po/ru_RU.po create mode 100755 res/po/si.po create mode 100755 res/po/sk.po create mode 100755 res/po/sl.po create mode 100755 res/po/sq.po create mode 100755 res/po/sr.po create mode 100755 res/po/sv.po create mode 100755 res/po/ta.po create mode 100755 res/po/te.po create mode 100755 res/po/tg_TJ.po create mode 100755 res/po/th.po create mode 100755 res/po/tk_TM.po create mode 100755 res/po/tl.po create mode 100755 res/po/tr_TR.po create mode 100755 res/po/uk.po create mode 100755 res/po/ur.po create mode 100755 res/po/uz.po create mode 100755 res/po/vi.po create mode 100755 res/po/zh_CN.po create mode 100755 res/po/zh_HK.po create mode 100755 res/po/zh_TW.po create mode 100755 shared/res/org.tizen.sketch.png create mode 100755 shared/res/tables/org.tizen.w-drawing_color.xml create mode 100755 shared/res/tables/org.tizen.w-drawing_font.xml create mode 100644 src/CDrUtil.cpp create mode 100644 src/CDrUtil.h create mode 100755 src/EventManager/CDrEvent.h create mode 100755 src/EventManager/CDrEventListener.h create mode 100644 src/EventManager/CDrEventManager.cpp create mode 100755 src/EventManager/CDrEventManager.h create mode 100755 src/EventManager/CDrSingleton.h create mode 100755 src/MediaDB/CDrMediaContent.cpp create mode 100755 src/MediaDB/CDrMediaContent.h create mode 100644 src/Singleton.h create mode 100755 src/View/CDrMainView.cpp create mode 100755 src/View/CDrMainView.h create mode 100755 src/View/CDrStrokeView.cpp create mode 100755 src/View/CDrStrokeView.h create mode 100644 src/app-assist-efl/WApp.cpp create mode 100644 src/app-assist-efl/WAppEventHandler.cpp create mode 100644 src/app-assist-efl/WContentViewController.cpp create mode 100644 src/app-assist-efl/WContentViewControllerImpl.cpp create mode 100644 src/app-assist-efl/WEvasObject.cpp create mode 100644 src/app-assist-efl/WGengridItem.cpp create mode 100644 src/app-assist-efl/WGenlistItem.cpp create mode 100644 src/app-assist-efl/WMenuPopupController.cpp create mode 100644 src/app-assist-efl/WMenuPopupControllerImpl.cpp create mode 100644 src/app-assist-efl/WNaviframeController.cpp create mode 100644 src/app-assist-efl/WPageSlideViewController.cpp create mode 100644 src/app-assist-efl/WPopupController.cpp create mode 100644 src/app-assist-efl/WSignalIdGenerator.cpp create mode 100644 src/app-assist-efl/WUiThread.cpp create mode 100644 src/app-assist-efl/WUiTimer.cpp create mode 100644 src/app-assist-efl/WUiTimerImpl.cpp create mode 100644 src/app-assist-efl/WUiTimerImpl.h create mode 100644 src/app-assist-efl/WVersion.cpp create mode 100644 src/app-assist-efl/WViewController.cpp create mode 100644 src/app-assist-efl/WViewControllerImpl.cpp create mode 100644 src/app-assist-efl/WViewControllerImpl.h create mode 100644 src/app-assist-efl/WWindowController.cpp create mode 100644 src/app-assist-efl/inc/WContentViewControllerImpl.h create mode 100755 src/app-assist-efl/inc/WDebugInternal.h create mode 100755 src/app-assist-efl/inc/WDefineInternal.h create mode 100644 src/app-assist-efl/inc/WMenuPopupControllerImpl.h create mode 100755 src/app/CDrApp.cpp create mode 100755 src/app/CDrApp.h create mode 100755 src/app/CDrAppData.cpp create mode 100755 src/app/CDrAppData.h create mode 100755 src/controls/CDrCairoImage.cpp create mode 100755 src/controls/CDrCairoImage.h create mode 100755 src/controls/CDrControl.h create mode 100755 src/controls/CDrControlManager.cpp create mode 100755 src/controls/CDrControlManager.h create mode 100755 src/controls/CDrDrawingView.cpp create mode 100755 src/controls/CDrDrawingView.h create mode 100755 src/controls/CDrHistoryControl.cpp create mode 100755 src/controls/CDrHistoryControl.h create mode 100755 src/controls/CDrTutorialView.cpp create mode 100755 src/controls/CDrTutorialView.h create mode 100755 src/controls/Drawing.cpp create mode 100755 src/controls/Drawing.h create mode 100755 src/controls/History.cpp create mode 100755 src/controls/History.h create mode 100755 src/main.cpp create mode 100755 src/popup/CDrClosePopup.cpp create mode 100755 src/popup/CDrClosePopup.h create mode 100755 tizen-manifest.xml diff --git a/Build/appendix.mk b/Build/appendix.mk new file mode 100644 index 0000000..2e06c34 --- /dev/null +++ b/Build/appendix.mk @@ -0,0 +1 @@ +# Appendix diff --git a/Build/basedef.mk b/Build/basedef.mk new file mode 100644 index 0000000..a762983 --- /dev/null +++ b/Build/basedef.mk @@ -0,0 +1,34 @@ +# Add inputs and outputs from these tool invocations to the build variables + + +OS_NAME := $(shell $(UNAME)) + + +#ifeq ($(origin BUILD_CONFIG), undefined) +BUILD_CONFIG ?= Debug +#endif + +#ifeq ($(origin ARCH), undefined) +ARCH ?= i386 +#endif + +#ifeq ($(origin PROJPATH), undefined) +PROJPATH ?= . +#endif + + +#ifeq ($(origin PROJ_PATH), undefined) +PROJ_PATH ?= $(PROJPATH) +#endif + +#ifeq ($(strip $(OUTPUT_DIR)),) +#OUTPUT_DIR ?= $(PROJ_PATH)/$(BUILD_CONFIG) +#endif + +#ifeq ($(strip $(BUILD_ARCH)),) +BUILD_ARCH ?= $(ARCH) +#endif + +#ifeq ($(strip $(ENVENTOR_PATH)),) +ENVENTOR_PATH ?= $(SDK_TOOLPATH)/enventor +#endif diff --git a/Build/build_c.mk b/Build/build_c.mk new file mode 100644 index 0000000..5fffeea --- /dev/null +++ b/Build/build_c.mk @@ -0,0 +1,113 @@ +# C/C++ build script + + +_FUNC_EXT2O = $(patsubst %.$(3),$(1)/%.o,$(2)) +_FUNC_C2O = $(call _FUNC_EXT2O,$(1),$(2),c) +_FUNC_CPP2O = $(call _FUNC_EXT2O,$(1),$(2),cpp) + + +# parameter : +# $(1) - C/C++ soruce file +# $(2) - output path +# $(3) - .ext +# $(4) - unique id +CONVERT_ESC_EXT_TO_O = $(addprefix $(2)/,$(notdir $(patsubst %.$(3),%-$(4).o,$(1)))) + +#CONVERT_ESC_C_TO_O = $(call CONVERT_ESC_EXT_TO_O,$(1),$(2),c) +#CONVERT_ESC_CPP_TO_O = $(call CONVERT_ESC_EXT_TO_O,$(1),$(2),cpp) + + +# parameter : +# $(1) - encoded one C/C++ soruce file +# $(2) - output path +# $(3) - ext title (C/C++) +# $(4) - ext (c/cpp) +# $(5) - compiler ($(CC)/$(CXX)) +# $(6) - build opt +# $(7) - build opt file +# output : +# $(8) - output files list +define C_BUILD_PROC_RAW +$(call CONVERT_ESC_EXT_TO_O,$(1),$(2),$(4),$(8)) : $(call DECODE_4MAKE,$(1)) $(7) + @echo ' Building file: $$<' + @echo ' Invoking: $(3) Compiler' + $$(call MAKEDIRS,$$(@D)) + $(5) -c "$$<" -o "$$@" $(6) -Wp,@$(7) + @echo ' Finished building: $$<' +$(9) += $(call CONVERT_ESC_EXT_TO_O,$(1),$(2),$(4),$(8)) +endef + + +# parameter : +# $(1) - output paths +# $(2) - src paths +# $(3) - inc paths +# $(4) - inc files +# $(5) - Defs +# $(6) - UnDefs +# $(7) - compiler opt +# $(8) - compiler opt file +# $(9) - ext title (C/C++) +# $(10) - ext (c/cpp) +# $(11) - compiler ($(CC)/$(CXX)) +# output : +# $(12) - OBJS +# return : +# none +define C_PROC_RAW + +_OUTPUT_DIR := $$(strip $(1))# +_SRCS := $(2)# +_INCS := $(3)# +_INC_FILES := $(4)# +_DEFS := $(5)# +_UNDEFS := $(6)# + +_OPT := $(7) +_OPT_FILE := $(8) + +_EXT_TITLE := $(9) +_EXT := $(10) +_COMPILER := $(11) + +#_OUTPUT_FILES := $(12) + +_ENC_SRCS := $$(call ENCODE_4MAKE,$$(_SRCS)) +_ENC_SRCS := $$(filter %.$$(_EXT),$$(_ENC_SRCS)) + +ifneq ($$(strip $$(_SRCS)),) + +_NORMAL_SRCS := $$(filter-out %*.$$(_EXT),$$(_ENC_SRCS)) +_WIDLCARD_SRCS := $$(filter %*.$$(_EXT),$$(_ENC_SRCS)) + +_ALL_SRCS := $$(call DECODE_4MAKE,$$(_NORMAL_SRCS)) \ + $$(foreach var,$$(_WIDLCARD_SRCS),$$(call FIND_FILES_4MAKE,$$(call DECODE_4MAKE,$$(var)))) + +ifneq ($$(strip $$(_ALL_SRCS)),) + +_ENC_SRCS := $$(call ENCODE_4MAKE,$$(_ALL_SRCS)) + +_CDEFS := $$(CDEFS) +_CDEFS += $$(addprefix -D,$$(_DEFS)) +_CDEFS += $$(addprefix -U,$$(_UNDEFS)) + +_ENC_C_INCS := $$(call ENCODE_4MAKE,$$(_INCS)) +_ENC_C_INCS := $$(addprefix -I,$$(_ENC_C_INCS)) + +_ENC_INC_FILES := $$(call ENCODE_4MAKE,$$(_INC_FILES)) +_ENC_INC_FILES += $$(addprefix -include,$$(_ENC_INC_FILES)) + +_C_INCS := $$(call DECODE_4MAKE,$$(_ENC_C_INCS) $$(_ENC_C_INC_FILES)) + +_DEFS := $$(_CDEFS) $$(_C_INCS) -I"pch" $$(_OPT) + +_UNIQUE_ID = $$(firstword $$(shell echo $$(var) | $$(CKSUM))) + +$$(foreach var,$$(_ENC_SRCS),$$(eval $$(call C_BUILD_PROC_RAW,$$(var),$$(_OUTPUT_DIR),$$(_EXT_TITLE),$$(_EXT),$$(_COMPILER),$$(_DEFS),$$(_OPT_FILE),$$(_UNIQUE_ID),$(12)))) + +endif # (_(strip _(_ALL_SRCS)),) + +endif # (_(strip _(_SRCS)),) + + +endef diff --git a/Build/build_edc.mk b/Build/build_edc.mk new file mode 100644 index 0000000..6f85fdd --- /dev/null +++ b/Build/build_edc.mk @@ -0,0 +1,81 @@ +# EDC build script + + +FUNC_EDC2EDJ = $(patsubst %.edc,$(2)/%.edj,$(1)) + +# parameter : +# $(1) - C/C++ soruce file +# $(2) - output path +CONVERT_ESC_EDC_TO_EDJ = $(call CONVERT_4MAKE_TO_OUT,$(call FUNC_EDC2EDJ,$(1),$(2))) + + +# parameter : +# $(1) - encoded one C/C++ soruce file +# $(2) - output path +# $(3) - build opt +# output : +# $(4) - output files list +define EDJ_BUILD_PROC_RAW +$(call CONVERT_ESC_EDC_TO_EDJ,$(1),$(2)) : $(call DECODE_4MAKE,$(1)) + @echo ' Building file: $$<' + @echo ' Invoking: EDC Resource Compiler' + $$(call MAKEDIRS,$$(@D)) + $$(EDJE_CC) $(3) "$$<" "$$@" + @echo ' Finished building: $$<' +$(4) += $(call CONVERT_ESC_EDC_TO_EDJ,$(1),$(2)) +endef + + +# parameter : +# $(1) - output paths +# $(2) - src paths +# $(3) - image inc paths +# $(4) - sound inc paths +# $(5) - font inc paths +# output : +# $(6) - OBJS +# return : +# none +define EDJ_PROC_RAW + +_OUTPUT_DIR := $$(strip $(1))# +_SRCS := $(2)# +_IMAGE_DIRS := $(3)# +_SOUND_DIRS := $(4)# +_FONT_DIRS := $(5)# + +ifneq ($$(strip $$(_SRCS)),) + +_ENC_SRCS := $$(call ENCODE_4MAKE,$$(_SRCS)) + +_NORMAL_SRCS := $$(filter-out %*.edc,$$(_ENC_SRCS)) +_WIDLCARD_SRCS := $$(filter %*.edc,$$(_ENC_SRCS)) + +_ALL_SRCS := $$(call DECODE_4MAKE,$$(_NORMAL_SRCS)) \ + $$(foreach var,$$(_WIDLCARD_SRCS),$$(call FIND_FILES_4MAKE,$$(call DECODE_4MAKE,$$(var)))) + +ifneq ($$(strip $$(_ALL_SRCS)),) + +_ENC_SRCS := $$(call ENCODE_4MAKE,$$(_ALL_SRCS)) + +_COMPILER_FLAGS := -id "$$(ENVENTOR_SHARED_RES_PATH)/images" +_COMPILER_FLAGS += -sd "$$(ENVENTOR_SHARED_RES_PATH)/sounds" +_COMPILER_FLAGS += -fd "$$(ENVENTOR_SHARED_RES_PATH)/fonts" + +ifneq ($$(strip $$(_IMAGE_DIRS)),) +_COMPILER_FLAGS += $$(addprefix -id ,$$(_IMAGE_DIRS)) +endif +ifneq ($$(strip $$(_SOUND_DIRS)),) +_COMPILER_FLAGS += $$(addprefix -sd ,$$(_SOUND_DIRS)) +endif +ifneq ($$(strip $$(_FONT_DIRS)),) +_COMPILER_FLAGS += $$(addprefix -fd ,$$(_FONT_DIRS)) +endif + +$$(foreach var,$$(_ENC_SRCS),$$(eval $$(call EDJ_BUILD_PROC_RAW,$$(var),$$(_OUTPUT_DIR),$$(_COMPILER_FLAGS),$(6)))) + +endif # (_(strip _(_ALL_SRCS)),) + +endif # (_(strip _(_SRCS)),) + +endef diff --git a/Build/build_po.mk b/Build/build_po.mk new file mode 100644 index 0000000..d88d71a --- /dev/null +++ b/Build/build_po.mk @@ -0,0 +1,64 @@ +# PO build script + + +_FUNC_PO2MO = $(patsubst %.po,$(2)/res/locale/%/LC_MESSAGES/$(3).mo,$(notdir $(1))) + + +# parameter : +# $(1) - C/C++ soruce file +# $(2) - output path +# $(3) - app name +CONVERT_ESC_PO_TO_MO = $(call CONVERT_4MAKE_TO_OUT,$(call _FUNC_PO2MO,$(1),$(2),$(3))) + + +# parameter : +# $(1) - encoded one C/C++ soruce file +# $(2) - output path +# $(3) - app name +# output : +# $(4) - output files list +define MO_BUILD_PROC_RAW +$(call CONVERT_ESC_PO_TO_MO,$(1),$(2),$(3)) : $(call DECODE_4MAKE,$(1)) + @echo ' Building file: $$<' + @echo ' Invoking: msgfmt String Formatter' + $$(call MAKEDIRS,$$(@D)) + $$(MSGFMT) -o "$$@" "$$<" + @echo ' Finished building: $$<' +$(4) += $(call CONVERT_ESC_PO_TO_MO,$(1),$(2),$(3)) +endef + + +# parameter : +# $(1) - output dir +# $(2) - src paths +# $(3) - app name +# output : +# $(4) - OBJS + +define MO_PROC_RAW + +_OUTPUT_DIR := $(1) +_SRCS := $(2) +_APPNAME := $(3) + +ifneq ($$(strip $$(_SRCS)),) + +_ENC_SRCS := $$(call ENCODE_4MAKE,$$(_SRCS)) + +_NORMAL_SRCS := $$(filter-out %*.po,$$(_ENC_SRCS)) +_WIDLCARD_SRCS := $$(filter %*.po,$$(_ENC_SRCS)) + +_ALL_SRCS := $$(call DECODE_4MAKE,$$(_NORMAL_SRCS)) \ + $$(foreach var,$$(_WIDLCARD_SRCS),$$(call FIND_FILES_4MAKE,$$(call DECODE_4MAKE,$$(var)))) + +ifneq ($$(strip $$(_ALL_SRCS)),) + +_ENC_SRCS := $$(call ENCODE_4MAKE,$$(_ALL_SRCS)) + +$$(foreach var,$$(_ENC_SRCS),$$(eval $$(call MO_BUILD_PROC_RAW,$$(var),$$(_OUTPUT_DIR),$$(_APPNAME),$(4)))) + +endif # (_(strip _(_ALL_SRCS)),) + +endif # (_(strip _(_SRCS)),) + +endef diff --git a/Build/flags.mk b/Build/flags.mk new file mode 100644 index 0000000..79d154e --- /dev/null +++ b/Build/flags.mk @@ -0,0 +1,16 @@ + +DEBUG_OP = -D_DEBUG +CPP_DEBUG_OP = -g3 -D_DEBUG + +OPTIMIZATION_OP = +CPP_OPTIMIZATION_OP = -O2 + +COMPILE_FLAGS = $(DEBUG_OP) $(OPTIMIZATION_OP) + +CPP_COMPILE_FLAGS = $(CPP_DEBUG_OP) $(CPP_OPTIMIZATION_OP) -std=c++0x -c -fmessage-length=0 -fvisibility=hidden -fvisibility-inlines-hidden -c -fmessage-length=0 -fPIC + +LINK_FLAGS = -Xlinker --as-needed -Xlinker -O1 -Xlinker -hash-style=gnu -shared -Wl,--no-undefined + +AR_FLAGS = + +EDC_COMPILE_FLAGS = \ No newline at end of file diff --git a/Build/funcs.mk b/Build/funcs.mk new file mode 100644 index 0000000..3ba778b --- /dev/null +++ b/Build/funcs.mk @@ -0,0 +1,50 @@ + +BSLASH := \\# +NULL_CHAR := # +SPACE := \ # +COLON := :# +DOTDOT := ..# +SPACE_ESC := &sp;# +COLON_ESC := &co;# +SPACE_OUT := ~sp~# +COLON_OUT := ~co~# +DOTDOT_OUT := ~dtdt~# + +BSLASH2SLASH = $(subst $(BSLASH),/,$(1)) + +REMOVE_TAIL = $(patsubst %/,%,$(1)) + +#LOWER_CASE = $(shell echo translit($(1),[A-Z],[a-z])|$(M4)) +LOWER_CASE = $(shell echo $(1)|$(TR) [A-Z] [a-z]) + +#ifneq ($(findstring Windows,$(OS)),) +# ... +#endif + +FIND_FILES = $(shell $(FIND) $(1)/$(2) | $(SED) 's/^$(subst /,$(BSLASH)/,$(1))$(BSLASH)///') +FIND_FILES_ESC = $(shell $(FIND) $(1)/$(2) | $(SED) 's/^$(subst /,$(BSLASH)/,$(1))$(BSLASH)///' -e 's/:/$(BSLASH)&co;/g' -e 's/$(BSLASH) /$(BSLASH)&sp;/g') +FIND_FILES_4MAKE = $(shell $(FIND) $(1)/$(2) | $(SED) 's/^$(subst /,$(BSLASH)/,$(1))$(BSLASH)///') + +FIND_FILES_ABS = $(shell $(FIND) $(1)) +FIND_FILES_ABS_4MAKE = $(shell $(FIND) $(1) -e 's/$(BSLASH) /$(BSLASH)&sp;/g') +FIND_FILES_ABS_ESC = $(shell $(FIND) $(1) -e 's/:/$(BSLASH)&co;/g' -e 's/$(BSLASH) /$(BSLASH)&sp;/g') + +FIND_FILES_4MAKE = $(shell $(FIND) $(1) | $(SED) 's/ /\\\ /g') + +#ENCODE_ESC = $(shell echo $(1) | $(SED) -e 's/:/$(BSLASH)&co;/g' -e 's/$(BSLASH) /$(BSLASH)&sp;/g') +#DECODE_ESC = $(shell echo $(1) | $(SED) -e 's/$(BSLASH)&co;/:/g' -e 's/$(BSLASH)&sp;/$(BSLASH) / g') +ENCODE_ESC = $(subst $(SPACE),$(SPACE_ESC),$(subst $(COLON),$(COLON_ESC),$(1))) +DECODE_ESC = $(subst $(COLON_ESC),$(COLON),$(subst $(SPACE_ESC),$(SPACE),$(1))) +ENCODE_4MAKE = $(subst $(SPACE),$(SPACE_ESC),$(1)) +DECODE_4MAKE = $(subst $(SPACE_ESC),$(SPACE),$(1)) + +CONVERT_TO_OUT = $(subst $(DOTDOT),$(DOTDOT_OUT),$(subst $(COLON),$(COLON_OUT),$(subst $(SPACE),$(SPACE_OUT),$(1)))) +CONVERT_ESC_TO_OUT = $(subst $(DOTDOT),$(DOTDOT_OUT),$(subst $(COLON_ESC),$(COLON_OUT),$(subst $(SPACE_ESC),$(SPACE_OUT),$(1)))) +CONVERT_4MAKE_TO_OUT = $(subst $(DOTDOT),$(DOTDOT_OUT),$(subst $(COLON),$(COLON_OUT),$(subst $(SPACE_ESC),$(SPACE_OUT),$(1)))) + +PROC_NO_EXIST = $(if $(wildcard $(1)),,$(call $(2),$(1))) +define MAKEDIRS0 + @echo ' Building directory: $(1)' + @$(MKDIR) $(MKDIR_OP) $(subst $(BSLASH),/,$(1)) +endef +MAKEDIRS = $(call PROC_NO_EXIST,$(1),MAKEDIRS0) diff --git a/Build/makefile b/Build/makefile new file mode 100644 index 0000000..f491b50 --- /dev/null +++ b/Build/makefile @@ -0,0 +1,34 @@ +# +# Usege : make -f /Build/makefile -C +# + +BUILD_SCRIPT_VERSION := 1.1.0 + +.PHONY : app_version app_build app_clean build_version + + +all : app_build + +clean : app_clean + +version : build_version + +#PROJ_ROOT = . +BUILD_ROOT := $(PROJ_PATH)/Build# + +ifeq ($(MAKE_NAME),mingw32-make) +ifneq ($(SHELL),) +OPTIONS += --eval="SHELL=$(SHELL)" +endif +endif + +app_build : + @echo $(MAKE) -f "$(BUILD_ROOT)/makefile.mk" + @$(MAKE_BIN) -f "$(BUILD_ROOT)/makefile.mk" -C "$(PROJ_PATH)" $(OPTIONS) + +app_clean : + @$(MAKE) -f "$(BUILD_ROOT)/makefile.mk" -C "$(PROJ_PATH)" $(OPTIONS) clean + +build_version : + @echo makefile : $(BUILD_SCRIPT_VERSION) + @$(MAKE) -f "$(BUILD_ROOT)/makefile.mk" -C "$(PROJ_PATH)" $(OPTIONS) version diff --git a/Build/makefile.mk b/Build/makefile.mk new file mode 100644 index 0000000..205a3ad --- /dev/null +++ b/Build/makefile.mk @@ -0,0 +1,197 @@ +# +# Usege : make -f /Build/makefile -C +# + +BUILD_SCRIPT_VERSION := 1.2.3 + +.PHONY : app_version app_clean build_version + + +all : app_build + +clean : app_clean + +version : build_version + + +#PROJ_ROOT := $(call BSLASH2SLASH,$(PROJ_PATH)) +PROJ_ROOT := . +BUILD_ROOT := $(PROJ_ROOT)/Build + +include $(BUILD_ROOT)/basedef.mk + +include $(PROJ_ROOT)/project_def.prop +-include $(PROJ_ROOT)/build_def.prop + +include $(BUILD_ROOT)/funcs.mk + +-include $(BUILD_ROOT)/tooldef.mk +-include $(BUILD_ROOT)/flags.mk +-include $(BUILD_ROOT)/platform.mk + + +APPTYPE := $(type) + +OUTPUT_DIR := $(PROJ_ROOT)/$(BUILD_CONFIG) +OBJ_OUTPUT := $(OUTPUT_DIR)/objs + +LOWER_APPNAME := $(call LOWER_CASE,$(APPNAME)) +APPID2 := $(subst $(basename $(APPID)).,,$(APPID)) + +ifeq ($(strip $(APPTYPE)),app) +APPFILE := $(OUTPUT_DIR)/$(LOWER_APPNAME) +endif +ifeq ($(strip $(APPTYPE)),staticLib) +APPFILE := $(OUTPUT_DIR)/lib$(LOWER_APPNAME).a +endif +ifeq ($(strip $(APPTYPE)),sharedLib) +APPFILE := $(OUTPUT_DIR)/lib$(LOWER_APPNAME).so +endif + +ifneq ($(strip $(PLATFORM_INCS)),) +PLATFORM_INCS_FILE := $(OBJ_OUTPUT)/platform_incs_file.inc +endif + +include $(BUILD_ROOT)/build_c.mk + + +ifeq ($(strip $(APPTYPE)),app) +EXT_OP := -fPIE +endif +ifeq ($(strip $(APPTYPE)),staticLib) +EXT_OP := -fPIE +endif +ifeq ($(strip $(APPTYPE)),sharedLib) +EXT_OP := -fPIC +endif + +C_OPT := $(COMPILE_FLAGS) $(TC_COMPILER_MISC) $(RS_COMPILER_MISC) $(EXT_OP) --sysroot="$(SYSROOT)" -Werror-implicit-function-declaration $(M_OPT) $(USER_C_OPTS) +CPP_OPT := $(CPP_COMPILE_FLAGS) $(TC_COMPILER_MISC) $(RS_COMPILER_MISC) $(EXT_OP) --sysroot="$(SYSROOT)" -Werror-implicit-function-declaration $(M_OPT) $(USER_CPP_OPTS) +C_OPT_FILE := $(PLATFORM_INCS_FILE) + +OBJS := # + +# Global C/C++ +ifeq ($(strip $(USER_ROOT)),) +USER_ROOT := $(PROJ_ROOT) +endif +$(eval $(call C_PROC_RAW,$(OBJ_OUTPUT),$(USER_SRCS),$(USER_INC_DIRS),$(USER_INC_FILES),$(USER_DEFS),$(USER_UNDEFS),$(C_OPT),$(C_OPT_FILE),C,c,$(CC),OBJS)) +$(foreach ext,cpp cxx cc c++ C,$(eval $(call C_PROC_RAW,$(OBJ_OUTPUT),$(USER_SRCS),$(USER_INC_DIRS),$(USER_CPP_INC_FILES),$(USER_CPP_DEFS),$(USER_CPP_UNDEFS),$(CPP_OPT),$(C_OPT_FILE),C++,$(ext),$(CXX),OBJS))) + +# Individual C/C++ +ifneq ($(strip $(USER_EXT_C_KEYS)),) +$(foreach var,$(USER_EXT_C_KEYS),$(eval $(call C_PROC_RAW,$(OBJ_OUTPUT),$(USER_EXT_$(var)_SRCS),$(USER_EXT_$(var)_INC_DIRS),$(USER_EXT_$(var)_INC_FILES),$(USER_EXT_$(var)_DEFS),$(USER_EXT_$(var)_UNDEFS),$(C_OPT),$(C_OPT_FILE),C,c,$(CC),OBJS))) +$(foreach ext,cpp cxx cc c++ C,$(foreach var,$(USER_EXT_C_KEYS),$(eval $(call C_PROC_RAW,$(OBJ_OUTPUT),$(USER_EXT_$(var)_SRCS),$(USER_EXT_$(var)_INC_DIRS),$(USER_EXT_$(var)_CPP_INC_FILES),$(USER_EXT_$(var)_CPP_DEFS),$(USER_EXT_$(var)_CPP_UNDEFS),$(CPP_OPT),$(C_OPT_FILE),C++,$(ext),$(CXX),OBJS)))) +endif + + +ifneq ($(strip $(USER_LIB_DIRS)),) +_ENC_USER_LIB_DIRS := $(call ENCODE_4MAKE,$(USER_LIB_DIRS)) +_ENC_USER_LIB_DIRS := $(addprefix -L,$(_ENC_USER_LIB_DIRS)) +LIBPATHS := $(call DECODE_4MAKE,$(_ENC_USER_LIB_DIRS)) +endif + +LIBS += $(addprefix -l,$(USER_LIBS)) + +UOBJS += $(USER_OBJS) + +M_OPT = -MMD -MP -MF"$(@:%.o=%.d)" + +DEPS := $(OBJS:.o=.d) + +ifneq ($(strip $(DEPS)),) +-include $(PROJ_ROOT)/Build/$(DEPS) +endif + + +ifeq ($(strip $(APPTYPE)),app) +$(APPFILE) : $(OBJS) $(UOBJS) + @echo ' Building target: $@' + @echo ' Invoking: C/C++ Linker' + $(call MAKEDIRS,$(@D)) + $(CXX) -o $(APPFILE) $(OBJS) $(UOBJS) $(LIBPATHS) -Xlinker --as-needed $(LIBS) $(LINK_FLAGS) $(TC_LINKER_MISC) $(RS_LINKER_MISC) -pie -lpthread --sysroot="$(SYSROOT)" -Xlinker --version-script="$(PROJ_ROOT)/.exportMap" $(RS_LIB_PATHS) $(RS_LIBRARIES) -Xlinker -rpath="/opt/usr/apps/$(APPID)/lib" -Werror-implicit-function-declaration $(USER_LINK_OPTS) + @echo ' Finished building target: $@' +endif +ifeq ($(strip $(APPTYPE)),staticLib) +$(APPFILE) : $(OBJS) $(UOBJS) + @echo ' Building target: $@' + @echo ' Invoking: Archive utility' + $(call MAKEDIRS,$(@D)) + $(AR) -r $(APPFILE) $(OBJS) $(UOBJS) $(AR_FLAGS) $(USER_LINK_OPTS) + @echo ' Finished building target: $@' +endif +ifeq ($(strip $(APPTYPE)),sharedLib) +$(APPFILE) : $(OBJS) $(UOBJS) + @echo ' Building target: $@' + @echo ' Invoking: C/C++ Linker' + $(call MAKEDIRS,$(@D)) + $(CXX) -o $(APPFILE) $(OBJS) $(UOBJS) $(LIBPATHS) -Xlinker --as-needed $(LIBS) $(LINK_FLAGS) $(TC_LINKER_MISC) $(RS_LINKER_MISC) -shared -lpthread --sysroot="$(SYSROOT)" $(RS_LIB_PATHS) $(RS_LIBRARIES) $(USER_LINK_OPTS) + @echo ' Finished building target: $@' +endif + + +$(OBJ_OUTPUT) : + $(call MAKEDIRS,$@) + +$(OUTPUT_DIR) : + $(call MAKEDIRS,$@) + + +ifneq ($(strip $(PLATFORM_INCS)),) +$(PLATFORM_INCS_FILE) : $(OBJ_OUTPUT) + @echo ' Building inc file: $@' +ifneq ($(findstring Windows,$(OS)),) +ifneq ($(findstring 3.82,$(MAKE_VERSION)),) + $(file > $@,$(PLATFORM_INCS)) +else + @echo $(PLATFORM_INCS) > $@ +endif +else + @echo $(PLATFORM_INCS) > $@ +endif +endif + + +include $(BUILD_ROOT)/build_edc.mk + +#ifeq ($(strip $(ENVENTOR_SHARED_RES_PATH)),) +ENVENTOR_SHARED_RES_PATH ?= $(ENVENTOR_PATH)/share/enventor +#endif + +EDJ_FILES := + +# Global EDCs +ifneq ($(strip $(USER_EDCS)),) +$(eval $(call EDJ_PROC_RAW,$(OUTPUT_DIR),$(USER_EDCS),$(USER_EDCS_IMAGE_DIRS),$(USER_EDCS_SOUND_DIRS),$(USER_EDCS_FONT_DIRS),EDJ_FILES)) +endif + +# Individual EDCs +ifneq ($(strip $(USER_EXT_EDC_KEYS)),) +$(foreach var,$(USER_EXT_EDC_KEYS),$(eval $(call EDJ_PROC_RAW,$(OUTPUT_DIR),$(USER_EXT_$(var)_EDCS),$(USER_EXT_$(var)_EDCS_IMAGE_DIRS),$(USER_EXT_$(var)_EDCS_SOUND_DIRS),$(USER_EXT_$(var)_EDCS_FONT_DIRS),EDJ_FILES))) +endif + + +include $(BUILD_ROOT)/build_po.mk + +MO_FILES := + +# Global POs +ifneq ($(strip $(USER_POS)),) +$(eval $(call MO_PROC_RAW,$(OUTPUT_DIR),$(USER_POS),$(APPID2),MO_FILES)) +endif + + +secondary-outputs : $(EDJ_FILES) $(MO_FILES) + +-include appendix.mk + +app_build : $(OUTPUT_DIR) $(APPFILE) secondary-outputs + @echo ========= done ========= + + +app_clean : + rm -f $(APPFILE) + rm -rf $(OUTPUT_DIR) + +build_version : + @echo makefile.mk : $(BUILD_SCRIPT_VERSION) diff --git a/Build/platform.mk b/Build/platform.mk new file mode 100644 index 0000000..294a38a --- /dev/null +++ b/Build/platform.mk @@ -0,0 +1,15 @@ +# Add inputs and outputs from these tool invocations to the build variables + +SYSROOT = $(SBI_SYSROOT) + +USR_INCS := $(addprefix -I $(SYSROOT),$(PLATFORM_INCS_EX)) + +ifeq ($(strip $(PLATFORM_LIB_PATHS)),) +RS_LIB_PATHS := "$(SYSROOT)/usr/lib" +else +RS_LIB_PATHS := $(addprefix -L$(SYSROOT),$(PLATFORM_LIB_PATHS)) +endif + +RS_LIBRARIES := $(addprefix -l,$(RS_LIBRARIES_EX)) + +PLATFORM_INCS = $(USR_INCS) -I"$(SDK_PATH)/library" diff --git a/Build/tooldef.mk b/Build/tooldef.mk new file mode 100644 index 0000000..c62243c --- /dev/null +++ b/Build/tooldef.mk @@ -0,0 +1,70 @@ +# Add inputs and outputs from these tool invocations to the build variables + +ifneq ($(strip $(SHELL_BIN)),) +SHELL = $(SHELL_BIN) +else +SHELL = sh +endif + +ifneq ($(strip $(MKDIR_BIN)),) +MKDIR = $(MKDIR_BIN) +MKDIR_OP = -p +else +MKDIR = mkdir +MKDIR_OP = -p +endif + +ifneq ($(strip $(UNAME_BIN)),) +UNAME = $(UNAME_BIN) +else +UNAME = uname +endif + +ifneq ($(strip $(M4_BIN)),) +M4 = $(M4_BIN) +else +M4 = m4 +endif + +ifneq ($(strip $(TR_BIN)),) +TR = $(TR_BIN) +else +TR = tr +endif + +ifneq ($(strip $(FIND_BIN)),) +FIND = $(FIND_BIN) +else +FIND = find +endif + +ifneq ($(strip $(SED_BIN)),) +SED = $(SED_BIN) +else +SED = sed +endif + +ifneq ($(strip $(GREP_BIN)),) +GREP = $(GREP_BIN) +else +GREP = grep +endif + +ifneq ($(strip $(EDJE_CC_BIN)),) +EDJE_CC = $(EDJE_CC_BIN) +else +EDJE_CC = edje_cc +endif + +ifneq ($(strip $(MSGFMT_BIN)),) +MSGFMT = $(MSGFMT_BIN) +else +MSGFMT = msgfmt +endif + +ifneq ($(strip $(CKSUM_BIN)),) +CKSUM = $(CKSUM_BIN) +else +CKSUM = cksum +endif + diff --git a/build_def.prop b/build_def.prop new file mode 100644 index 0000000..6bb5e2f --- /dev/null +++ b/build_def.prop @@ -0,0 +1,6 @@ + +# Add pre/post build process +PREBUILD_DESC = +PREBUILD_COMMAND = +POSTBUILD_DESC = +POSTBUILD_COMMAND = diff --git a/edje_images/b_ic_press_full_circle_bg.png b/edje_images/b_ic_press_full_circle_bg.png new file mode 100755 index 0000000000000000000000000000000000000000..5b9f7e44474bd0213f3f346ddde3f0e9c4247460 GIT binary patch literal 7317 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 literal 0 HcmV?d00001 diff --git a/edje_images/gear_tutorial_bg.png b/edje_images/gear_tutorial_bg.png new file mode 100755 index 0000000000000000000000000000000000000000..f9a0646ed228d5c6c5805d14347f05421fe1f236 GIT binary patch literal 6922 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 T(-r=?1zerBJKo!JDEWT?;B@~; literal 0 HcmV?d00001 diff --git a/edje_images/gear_tutorial_bg_focus.png b/edje_images/gear_tutorial_bg_focus.png new file mode 100755 index 0000000000000000000000000000000000000000..10cee539f82d32727f5b4bc462b3fdda83313a05 GIT binary patch literal 39725 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 Q_b&$WqWV&*Jfda)0rpJxPyhe` literal 0 HcmV?d00001 diff --git a/edje_images/gear_tutorial_bt_cancel_press.png b/edje_images/gear_tutorial_bt_cancel_press.png new file mode 100755 index 0000000000000000000000000000000000000000..0f7fee69cf399bfffda4a2bc2568557616e7de3d GIT binary patch literal 2804 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 T4MFc#fBo!i9I1E7hvWYZy&7xd literal 0 HcmV?d00001 diff --git a/edje_images/gear_tutorial_rotate_cw.png b/edje_images/gear_tutorial_rotate_cw.png new file mode 100755 index 0000000000000000000000000000000000000000..0e2699de00f0870d9289adddadac0c390e345a00 GIT binary patch literal 3767 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 literal 0 HcmV?d00001 diff --git a/edje_images/wi_more_option_bg.png b/edje_images/wi_more_option_bg.png new file mode 100755 index 0000000000000000000000000000000000000000..6e3237068a4a88116d8eee6520b30490954797c5 GIT binary patch literal 6340 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 literal 0 HcmV?d00001 diff --git a/inc/DrDebug.h b/inc/DrDebug.h new file mode 100755 index 0000000..137bf4c --- /dev/null +++ b/inc/DrDebug.h @@ -0,0 +1,14 @@ +#ifndef _DR_DEBUG_H_ +#define _DR_DEBUG_H_ + +#ifdef LOG_TAG +#undef LOG_TAG +#endif + +#define LOG_TAG "W-DRAWING" + +#include "WDebugBase.h" + +/* TODO : add your own macro */ + +#endif /* _VE_DEBUG_H_ */ diff --git a/inc/DrDefine.h b/inc/DrDefine.h new file mode 100755 index 0000000..7a794bd --- /dev/null +++ b/inc/DrDefine.h @@ -0,0 +1,115 @@ +#ifndef _DR_DEFINE_H_ +#define _DR_DEFINE_H_ + +#include "DrDebug.h" + + +/***************************************** + * package and install related + *****************************************/ +#ifndef LOCALE_DOMAIN +#define LOCALE_DOMAIN "sketch" +#endif + +//#ifndef SKETCH_DRAW_COLORS_CHANGABLE +//#define SKETCH_DRAW_COLORS_CHANGABLE +//#endif +#ifndef SKETCH_DRAW_ENABLE_DRAWING_EFFECT +#define SKETCH_DRAW_ENABLE_DRAWING_EFFECT +#endif + + +#define PACKAGE_NAME "org.tizen.w-drawing" +#define INSTALLED_PATH "/opt/usr/apps" +#define ROOT_INSTALLED_PATH "/usr/apps" +#define DATA_DIRECTORY_NAME "data" +#define REFERENCE_BASE_SCALE 2.4 //based on z910f device(1280x720) +#define DRAWING_SYATEM_TERMINATE_APP "System will terminate video editor due to internal issues, such as low memory,etc." +#define DRAWING_SAVE_FILE_DIRECTORY "/opt/usr/media/Images/" +#define DRAWING_OUTPUT_FILE_FORMAT ".png" +#define DRAWING_OUTPUT_FILE_FORMAT_MMS ".jpg" + + + +/***************************************** + * edj + *****************************************/ +#define EDJ_FILE "edje/animations2circle.edj" +#define EDJ_THEME_FILE "edje/btneffect.edj" +#define EDJ_POPUP_CUSTOM_FILE "edje/drawing_popup.edj" +#define DRAWING_LAYOUT_GROUP_NAME "drawing_group" +#define DRAWING_TUTORIAL_LAYOUT_GROUP_NAME "tutorial_view" + + +#define DRAWING_BUTTON_SAVE_MODE_STYLE "pallet/savemode_effect" +#define DRAWING_BUTTON_SEND_MODE_STYLE "pallet/sendmode_effect" + +/***************************************** + * image + *****************************************/ +#define CLOSE_POPUP_CANCEL_ICON "images/drawing_popup_btn_delete.png" +#define CLOSE_POPUP_DISCARD_ICON "images/drawing_popup_btn_check.png" +#define DRAWING_MORE_OPTIONS_ICON "images/wi_drawing_more_options_icon.png" +#define DRAWING_STROKE_OPTIONS_ICON "images/wear_comm_stroke_option.png" +#define DRAWING_MORE_OPTION_ICON_BG "images/b_more_option_icon_bg.png" +#define DRAWING_MORE_OPTION_ICON_SELECTED_BG "images/b_more_option_icon_select_bg.png" +#define DRAWING_PALLET_COLOR_PICKER_ERASER_ICON "images/wi_drawing_more_options_erase.png" +#define DRAWING_PALLET_COLOR_PICKER_SELECTOR_ICON "images/wi_drawing_select_button_center.png" +#define DRAWING_STROKE_SLIDER_ICON_MINUS "images/b_slider_icon_minus.png" +#define DRAWING_STROKE_SLIDER_ICON_PLUS "images/b_slider_icon_plus.png" +#define DRAWING_DRAWING_PATTERN_BG "images/wi_drawing_bg_pattern_negative.png" +#define SKETCH_DRAWING_PATTERN_BG "images/wi_drawing_bg_pattern.png" +#define SKETCH_DRAWING_COLOR_BG_01 "images/wi_drawing_bg_01.png" +#define SKETCH_DRAWING_COLOR_BG_02 "images/wi_drawing_bg_02.png" +#define SKETCH_DRAWING_COLOR_BG_03 "images/wi_drawing_bg_03.png" +#define SKETCH_DRAWING_COLOR_BG_04 "images/wi_drawing_bg_04.png" + + + + +/***************************************** + * text + *****************************************/ +#define DRAWING_STRING_ID_MMS_TITLE_TEXT "WDS_MSG_SBODY_MMS_ABB" +#define DRAWING_STRING_ID_TEXT_SEND "WDS_IME_ACBUTTON_SEND" +#define DRAWING_STRING_ID_SEND_DRAW_START_INDICATOR "WDS_IME_NPBODY_START_DOODLING_YOUR_MESSAGE_ABB" +#define DRAWING_STRING_ID_SEND_DRAW_START_INDICATOR_ATNT "WDS_IME_NPBODY_START_DRAWING_YOUR_IMAGE_ABB" + +//#define DRAWING_MMS_TITLE_TEXT "MMS" +#define DRAWING_TEXT_SAVE "SAVE" +//#define DRAWING_TEXT_SEND_DRAW_START_INDICATOR "Start drawing send to as image" +#define DRAWING_TEXT_SAVE_DRAW_START_INDICATOR "Start drawing save to as image" +#define MORE_OPTION_PALLET_RED "Red" +#define MORE_OPTION_PALLET_GREEN "Green" + + +/* popup */ +#define DRAWING_STRING_ID_POPUP_DISCARD_CONTENT "WDS_IME_POP_ARE_YOU_SURE_YOU_WANT_TO_DISCARD_YOUR_DRAWING_Q" +//#define DRAWING_POPUP_DISCARD_CONTENT "All changes will be discard?" +#define DRAWING_POPUP_DISCARD_CANCEL_BUTTON "Cancel" +#define DRAWING_POPUP_DISCARD_DISCARD_BUTTON "Discard" +#define DRAWING_POPUP_DISCARD_TITLE "Discard" +#define DRAWING_TUTORIAL_POPUP_TITLE "WDS_TTRL_HEADER_TIPS_ABB" +#define DRAWING_TUTORIAL_POPUP_CONTENTS_1 "WDS_TTRL_BODY_TURN_THE_BEZEL_ANTICLOCKWISE_TO_UNDO_A_DOODLE_ABB" +#define DRAWING_TUTORIAL_POPUP_CONTENTS_2 "WDS_TTRL_BODY_AND_CLOCKWISE_TO_BRING_YOUR_DOODLE_BACK_ABB" + + +#define MMS_MODE_STROKE_LINE_WIDTH 15.0 +#define SAVE_MODE_STROKE_LINE_WIDTH 3.0 +#define MAX_HISTORY 15 + +#define MAX_ANIMATION_TIME 0.5 +#define MIN_ANIMATION_TIME 0.05 +#define DRAW_POINTS 64 //128 +#define DRAW_SPEED 128 //320 + + +#define PREFERENCE_KEY_TUTORIAL_IS_SHOWED "tutorial_showed_key" +#define PREFERENCE_KEY_APP_BG_INDEX "app_bg_index_key" + +typedef enum { + DRAWING_SAVE = 0, + DRAWING_SEND, +}LaunchMode; + +#endif /* _VE_DEFINE_H_ */ diff --git a/inc/app-assist-efl/IWWindowController.h b/inc/app-assist-efl/IWWindowController.h new file mode 100755 index 0000000..861c619 --- /dev/null +++ b/inc/app-assist-efl/IWWindowController.h @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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 _APP_ASSIST_IWWINDOW_CONTROLLER_H_ +#define _APP_ASSIST_IWWINDOW_CONTROLLER_H_ + +#include +#include "WDefine.h" + +namespace app_assist { + +class WViewController; + +/** +* @class IWWindowController +* @brief This class is the interface class for the elements related to the window. +* +* The %IWWindowController provides interfaces for evas object related to the window class instance. +*/ +class WAPP_ASSIST_EXPORT IWWindowController { +public: + /** + * Gets the class name. + * + * @return the class name + */ + virtual const char* getClassName() = 0; + + /** + * Gets the evas object of window. + * + * @return evas object + */ + virtual Evas_Object* getEvasObj() const = 0; + + /** + * Gets the base layout evas object + * + * @return The pointer to the evas object of the layout + */ + virtual Evas_Object* getBaseLayoutEvasObj() = 0; + + /** + * Gets the conformant evas object. + * + * @return The pointer to the evas object of the conformant + */ + virtual Evas_Object* getConformantEvasObj() = 0; + + /** + * Gets the base view controller attached. + * + * @return The pointer to the base view controller + * @see attachBaseViewController() + */ + virtual WViewController* getBaseViewController() = 0; + +protected: + /** + * This is the destructor for this class. + * + */ + virtual ~IWWindowController() {}; + // +}; + +} // namespace + +#endif /* _APP_ASSIST_IWWINDOW_CONTROLLER_H_ */ diff --git a/inc/app-assist-efl/WApp.h b/inc/app-assist-efl/WApp.h new file mode 100755 index 0000000..d485c5c --- /dev/null +++ b/inc/app-assist-efl/WApp.h @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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 _APP_ASSIST_WAPP_H_ +#define _APP_ASSIST_WAPP_H_ + +#include +#include "WDefine.h" + +namespace app_assist { + +// forward declaration +class WWindowController; + +/** +* @class WApp +* @brief This class is the base class of an application +* +* +* The %WApp class is the base class of an application. An application class must be inherited from this class +* @code +* +* // main.cpp +* WAPP_ASSIST_EXPORT int main( int argc, char* argv[] ) +* { +* MyApp app; +* int ret = app.start( argc, argv ); +* return ret; +* } +* @endcode +*/ +class WAPP_ASSIST_EXPORT WApp { +public: + /** + * This is the default constructor for this class. + * + */ + WApp(); + + /** + * This is the destructor for this class. + * + */ + virtual ~WApp(); + +public: + /** + * Starts the application. + * + * @param[in] argc The argument count + * @param[in] argv The argument vector + * + * @return result + */ + int start(int argc, char* argv[]); + +protected: + /** + * Called when the application started + * + * @param[in] argc The argument count + * @param[in] argv The argument vector + * + * @return result + */ + virtual int onStart(int argc, char* argv[]); + + /** + * Called when the application created + * + * @return true if the application created successfully, else false + */ + virtual bool onCreate() { return true; }; + + /** + * Called when the application is terminated. + * + */ + virtual void onTerminate() {}; + + /** + * Called when the application is paused. + * + */ + virtual void onPause() {}; + + /** + * Called when the application is resumed. + * + */ + virtual void onResume() {}; + + /** + * Called when some request comes to the application + * + * @param[in] request handle of request information + * @param[in] firstLaunch true, if it is called after creation + */ + virtual void onAppControl(app_control_h request, bool firstLaunch); + + /** + * Gets the window class instance of the application. + * + * @return The pointer to the window + */ + WWindowController* getWindowController(); + + /** + * Attaches a window to the application. + * + * @param[in] win A pointer to the window to attach + * @return true if the window attached sucessfully, else false + */ + bool attachWindowController(WWindowController* win); + +private: + WDECLARE_PRIVATE_IMPL(WApp); + WDISABLE_COPY_AND_ASSIGN(WApp); +}; + +} // namespace + +#endif /* _APP_ASSIST_WAPP_H_ */ diff --git a/inc/app-assist-efl/WAppEventHandler.h b/inc/app-assist-efl/WAppEventHandler.h new file mode 100755 index 0000000..1b6eb5a --- /dev/null +++ b/inc/app-assist-efl/WAppEventHandler.h @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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 _APP_ASSIST_WAPP_EVENT_HANDLER_H_ +#define _APP_ASSIST_WAPP_EVENT_HANDLER_H_ + +#include +#include +#include "WDefine.h" + +namespace app_assist { +/** +* @class WAppEventHandler +* @brief This class is +* +*/ +class WAPP_ASSIST_EXPORT WAppEventHandler { +public: + /** + * This is the default constructor for this class. + * + */ + WAppEventHandler(); + + /** + * This is the destructor for this class. + * + */ + virtual ~WAppEventHandler(); + +public: + /** + * Adds application event handler of event type. + * + * @param[in] eventType event type to be handled + * @param[in] handlerFunc The pointer to handler function + * @param[in] userData user data pointer to be used in handler function + * + * @return 0 on success, otherwise error + */ + int addEventHandler(app_event_type_e eventType, const std::function& handlerFunc, void* userData); + + /** + * Removes application event handler + * + */ + void removeEventHandler(); + +protected: + /** + * Returns the handle of added event handler + * + * @return the handle + * + * @see addEventHandler() + */ + app_event_handler_h getHandle(); + +private: + WDECLARE_PRIVATE_IMPL(WAppEventHandler); + WDISABLE_COPY_AND_ASSIGN(WAppEventHandler); +}; + +} // namespace + +#endif /* _APP_ASSIST_WAPP_EVENT_HANDLER_H_ */ diff --git a/inc/app-assist-efl/WContentViewController.h b/inc/app-assist-efl/WContentViewController.h new file mode 100755 index 0000000..85b0a91 --- /dev/null +++ b/inc/app-assist-efl/WContentViewController.h @@ -0,0 +1,294 @@ +/* + * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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 _APP_ASSIST_WCONTENT_VIEW_CONTROLLER_H_ +#define _APP_ASSIST_WCONTENT_VIEW_CONTROLLER_H_ + +#include +#include +#include +#include +#include "WViewController.h" +#include "WNaviframeController.h" +#include "IWWindowController.h" + +namespace app_assist { + +/** +* @class WContentViewController +* @brief This class means the view represented by an evas object, which can be pushed into naviframe elementary. +* +* The %WContentViewController class keeps an evas object and provides methods to handle the case when the view is pushed into naviframe. +*/ +class WAPP_ASSIST_EXPORT WContentViewController : public WViewController { +public: + /** + * This is the default constructor for this class. + * + */ + WContentViewController(); + + /** + * Constructor + * + * @param[in] name the instance name to be set + */ + explicit WContentViewController(const char* name); + + /** + * Gets the class name. + * + */ + virtual const char* getClassName() const; //override; + +public: + /** + * Creates evas object which represents this view. + * "onCreate" will be called subsequently. + * + * @param[in] parent parent evas object of the view + * @param[in] viewParam user data + * @see onCreate + * @see onCreateView + * @see onCreated + */ + bool create(Evas_Object* parent, void* param); //final; + + /** + * Destroys the class instance and deletes evas object. + * If it has been pushed into naviframe, it will be popped out without onPop method being called. + * + * @see onDestroy + */ + void destroy(); //final; + +public: + + /** + * Sets a delegate function. It delegates onPushed handling to delegateFunc. + * This is simpler alternative to overriding the virtual method onPushed(), allowing direct use of WContentViewController without sub-classing. + * If delegation is used, onPushed() will not be called. + * + * @param[in] delegateFunc The pointer to delegate function + * @see onPushed() + */ + void setOnPushed(const std::function& delegateFunc); + +protected: + + /** + * Called when create method is called. + * It creates a default view. + * + * @param[in] parent parent evas object + * @param[in] viewParam user data + * + * @return the most parent evas object created in this method. It will be related to the class instance. + */ + virtual Evas_Object* onCreateView(Evas_Object* parent, void* viewParam); //override; + + /** + * Called when the container properties are set by Naviframe or other container views. + * Container view should override this method in order to set container properties for any views it contains, + * so that those page views can access window and naviframe. + * + * @param[in] win IWWindowController instance + * @param[in] naviframe WNaviframeController instance + * @param[in] item navi item pointer of container view which is pushed into naviframe. + */ + virtual void onSetContainerProperties(WNaviframeController* naviframe, Elm_Object_Item* item); + + /** + * Called when this view instance evas object should be pushed into naviframe. + * Override this method to do something and push the view into naviframe by itself. + * + * @param[in] naviFrame naviframe evas object + * + * @return navi item resulted from pushing the view to the naviframe. + * @see %WNaviframeController::push() + * @see onPushed() + */ + virtual Elm_Object_Item* onPushToNaviframe(Evas_Object* naviFrame); + + /** + * Called when this view instance evas object is pushed into naviframe. + * Override this method to do something with navi item. + * + * @param[in] naviItem navi item resulted from naviframe push + * @see %WNaviframeController::push() + * @see onPushToNaviframe() + */ + virtual void onPushed(Elm_Object_Item* naviItem); + + /** + * Called when the view evas object is popped from naviframe. + * Override this method to do something before it is popped out. + * + * @return false, if you want to keep the view instead of being popped out. + */ + virtual bool onPop(); + + /** + * Called when the view evas object will be becoming top item on naviframe. + * Override this method to do something before it actually become top item. + * It is called sequentially after onPop method of the previous top view being popped. + */ + virtual void onBecomeTop(); + + /** + * Called when this view instance evas object is attached to WPageSlideView. + * Override this method to do something with navi item after being attached. + * + * @param[in] parentNaviItem navi item of WPageSlideView object pushed into naviframe + * @see onPushed() + */ + virtual void onSetAsPageContent(Elm_Object_Item* parentNaviItem); + + + /** + * Called when setMoreButton method is called to create option menu. + * Override this method to create your own option menu. + * + * @param[in] naviItem navi item to add more button + * @param[in] clickedCb clicked callback function pointer + * @param[in] userData clicked callback user data parameter + * @see onPushed() + */ + virtual void onSetMoreButton(Elm_Object_Item* naviItem, Evas_Smart_Cb clickedCb, void* userData); + + /** + * Stores the title string of the view. It is used as title string, when this view is pushed into an WNaviframeController object. + * + * @param[in] title string of the title to be stored + * + */ + void setTitle(const char* title); + + /** + * Gets the title string stored by the method setTitle. + * + * @return title string + * @see setTitle + */ + const char* getTitle(); + + /** + * Gets the pointer to the IWWindowController type class instance. + * Usually it will be normal window instance, but if the view created on UG module, it will be UG window instance. + * Through this returned pointer, you can get window related properties. + * + * @return The pointer to the IWWindowController type instance. + */ +// IWWindowController* getWindowController(); + + /** + * Gets the WNaviframeController class instance. + * + * @return the pointer to the WNaviframeController class instance. If this view instance is not pushed into naviframe, it will be nullptr. + */ + WNaviframeController* getNaviframeController(); + + /** + * Gets a navi item. + * + * @return The pointer to navi item. If this view instance is not pushed into naviframe, it will be nullptr. + */ + Elm_Object_Item* getNaviItem(); + + /** + * Pops out this view instance evas object from naviframe. + * + * @return true, if succeeded + */ + bool popOut(); + + /** + * Create more button on navi item. + * + * @param[in] naviItem + * @param[in] clickedCb + * @param[in] userData + * @see %WNaviframeController::push() + * @see onPushed() + */ + bool setMoreButton(Elm_Object_Item* naviItem, Evas_Smart_Cb clickedCb, void* userData); + + // +protected: + /** + * This is the destructor for this class. + * + */ + virtual ~WContentViewController(); + +private: + WDECLARE_PRIVATE_IMPL(WContentViewController); + WDISABLE_COPY_AND_ASSIGN(WContentViewController); + friend class WNaviframeController; + friend class WPageSlideViewController; +}; + +/** + * Sets the container class properties to the view. + * It will be used only to create your own container view class and set its properties to child views, like WPageSlideView. + * + * @param[in] view WContentViewController instance to set these properties + * @param[in] naviframe WNaviframeController instance + * + * @see wcontentviewcontroller_set_container_naviitem_property + * @see wcontentviewcontroller_propagate_container_properties_to_childviews + */ +WAPP_ASSIST_EXPORT void wcontentviewcontroller_set_container_properties(WContentViewController* view, WNaviframeController* naviframe); + +/** + * Sets the container class navi item property to the view. + * It will be used only to create your own container view class and set its properties to child views, like WPageSlideView. + * + * @param[in] view WContentViewController instance to set these properties + * @param[in] item navi item pointer of container view which is pushed into naviframe. + * @param[in] isViewNaviItem If the Elm_Object_Item is for the view itself, set it true. + * Otherwise if it is a container's Elm_Object_Item, set it false. + * + * @see wcontentviewcontroller_set_container_properties + * @see wcontentviewcontroller_propagate_container_properties_to_childviews + */ +WAPP_ASSIST_EXPORT void wcontentviewcontroller_set_container_naviitem_property(WContentViewController* view, Elm_Object_Item* item, bool isViewNaviItem); + + +/** + * Propagates container properties (including naviItem property) set on the view to its child views. + * + * Whenever wcontentviewcontroller_set_container_properties and/or wcontentviewcontroller_set_container_naviitem_property is called for a view, + * this function should be called afterwards, so that in case the view is a custom container view, + * it will get a chance to propagate the properties it just received to its child views. + * + * This function invokes virtual method onSetContainerProperties() of the view, + * implementation of which should, in turn, set properties for each child views. + * + * @param[in] view WContentViewController instance whose child views to set these properties + * + * @see wcontentviewcontroller_set_container_properties + * @see wcontentviewcontroller_set_container_naviitem_property + * @see onSetContainerProperties + */ +WAPP_ASSIST_EXPORT void wcontentviewcontroller_propagate_container_properties_to_childviews(WContentViewController* view); + + +} // namespace + + +#endif /* _APP_ASSIST_WCONTENT_VIEW_CONTROLLER_H_ */ diff --git a/inc/app-assist-efl/WDebugBase.h b/inc/app-assist-efl/WDebugBase.h new file mode 100755 index 0000000..9c2960e --- /dev/null +++ b/inc/app-assist-efl/WDebugBase.h @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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 _APP_ASSIST_WDEBUG_BASE_H_ +#define _APP_ASSIST_WDEBUG_BASE_H_ + +#ifndef LOG_TAG +#define LOG_TAG "WAPP" +#endif + +#include +#include +#include +#include "WDefine.h" + +// If it is set as 1, assert() is called in WERROR +#define WENABLE_ASSERT_IN_ERROR (0) + +#define WCOLOR_RED "\033[0;31m" +#define WCOLOR_GREEN "\033[0;32m" +#define WCOLOR_BROWN "\033[0;33m" +#define WCOLOR_BLUE "\033[0;34m" +#define WCOLOR_PURPLE "\033[0;35m" +#define WCOLOR_CYAN "\033[0;36m" +#define WCOLOR_LIGHTBLUE "\033[0;37m" +#define WCOLOR_END "\033[0;m" + +//#ifdef WUSING_PUBLIC_SDK +// normal log +#define _WFILE_NAME (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/')+1 : __FILE__) + +#define _WDLOG_PRINT(prio, fmt, args...) \ + dlog_print(prio, LOG_TAG, "%s: %s(%d) > " fmt, _WFILE_NAME, __func__, __LINE__, ##args) + +#define WDEBUG(fmt, args...) _WDLOG_PRINT(DLOG_DEBUG, fmt, ##args) +#define WDEBUG_(fmt, args...) _WDLOG_PRINT(DLOG_DEBUG, WCOLOR_RED fmt WCOLOR_END, ##args) // temporal red-colored text for debugging + +#define WVERBOSE(fmt, args...) _WDLOG_PRINT(DLOG_DEBUG, WCOLOR_BROWN fmt WCOLOR_END, ##args) +#define WINFO(fmt, args...) _WDLOG_PRINT(DLOG_INFO, WCOLOR_GREEN fmt WCOLOR_END, ##args) +#define WWARNING(fmt, args...) _WDLOG_PRINT(DLOG_WARN, WCOLOR_PURPLE fmt WCOLOR_END, ##args) +// +#if (WENABLE_ASSERT_IN_ERROR == 1) +#define WERROR(fmt, args...) do { \ + _WDLOG_PRINT(DLOG_ERROR, WCOLOR_RED "* Critical * " fmt WCOLOR_END, ##args); \ + assert(0); \ + } while (0) +#else +#define WERROR(fmt, args...) _WDLOG_PRINT(DLOG_ERROR, WCOLOR_RED "* Critical * " fmt WCOLOR_END, ##args) +#endif + +#define WHIT() _WDLOG_PRINT(DLOG_DEBUG, WCOLOR_BLUE ">>>HIT<<<" WCOLOR_END) +#define WHIT_() _WDLOG_PRINT(DLOG_DEBUG, WCOLOR_RED ">>>HIT<<<" WCOLOR_END) +#define WHITM(fmt, args...) _WDLOG_PRINT(DLOG_DEBUG, WCOLOR_BLUE ">>>HIT<<<" fmt WCOLOR_END, ##args) + +#define WENTER() _WDLOG_PRINT(DLOG_DEBUG, WCOLOR_GREEN "BEGIN >>>>" WCOLOR_END) +#define WLEAVE() _WDLOG_PRINT(DLOG_DEBUG, WCOLOR_GREEN "END <<<<" WCOLOR_END) + +// secure log +#define WSDEBUG(fmt, args...) +#define WSVERBOSE(fmt, args...) +#define WSINFO(fmt, args...) +// +#define WSERROR(fmt, args...) + +/* +#else // WUSING_PUBLIC_SDK +// normal log +#define WDEBUG(fmt, args...) LOGD(fmt, ##args) +#define WDEBUG_(fmt, args...) LOGD(WCOLOR_RED fmt WCOLOR_END, ##args) // temporal red-colored text for debugging + +#define WVERBOSE(fmt, args...) LOGD(WCOLOR_BROWN fmt WCOLOR_END, ##args) +#define WINFO(fmt, args...) LOGI(WCOLOR_GREEN fmt WCOLOR_END, ##args) +#define WWARNING(fmt, args...) LOGW(WCOLOR_PURPLE fmt WCOLOR_END, ##args) +// +#if (WENABLE_ASSERT_IN_ERROR == 1) +#define WERROR(fmt, args...) do { \ + LOGE(WCOLOR_RED "* Critical * " fmt WCOLOR_END, ##args); \ + assert(0); \ + } while(0) +#else +#define WERROR(fmt, args...) LOGE(WCOLOR_RED "* Critical * " fmt WCOLOR_END, ##args) +#endif + +#define WHIT() LOGD(WCOLOR_BLUE ">>>HIT<<<" WCOLOR_END) +#define WHIT_() LOGD(WCOLOR_RED ">>>HIT<<<" WCOLOR_END) +#define WHITM(fmt, args... ) LOGD(WCOLOR_BLUE ">>>HIT<<<" fmt WCOLOR_END, ##args) + +#define WENTER() LOGD(WCOLOR_GREEN "BEGIN >>>>" WCOLOR_END) +#define WLEAVE() LOGD(WCOLOR_GREEN "END <<<<" WCOLOR_END) + +// secure log +#define WSDEBUG(fmt, args...) SECURE_LOGD(fmt, ##args) +#define WSVERBOSE(fmt, args...) SECURE_LOGD(WCOLOR_BROWN fmt WCOLOR_END, ##args) +#define WSINFO(fmt, args...) SECURE_LOGI(WCOLOR_GREEN fmt WCOLOR_END, ##args) +// +#if (WENABLE_ASSERT_IN_ERROR == 1) +#define WSERROR(fmt, args...) do { \ + SECURE_LOGE(WCOLOR_RED "* Critical * " fmt WCOLOR_END, ##args); \ + assert(0); \ + } while(0) +#else +#define WSERROR(fmt, args...) SECURE_LOGE(WCOLOR_RED "* Critical * " fmt WCOLOR_END, ##args) +#endif + +#endif // WUSING_PUBLIC_SDK +*/ +#define WPRET_VM(expr, val, fmt, arg...) do { \ + if (expr) { \ + WERROR(fmt, ##arg); \ + return (val); \ + } \ + } while (0) + +#define WPRET_M(expr, fmt, arg...) do { \ + if (expr) { \ + WERROR(fmt, ##arg); \ + return; \ + } \ + } while (0) + +#define WASSERT(expr) do { \ + if(!(expr)) \ + {\ + WERROR("WASSERT! "#expr);\ + assert((expr)); \ + }\ + }while(0); + +#define WASSERT_EX(expr, fmt, args...) do { \ + if(!(expr)) \ + {\ + WERROR("WASSERT! " fmt, ##args);\ + assert((expr)); \ + }\ + }while(0); + +#endif /* _APP_ASSIST_WDEBUG_BASE_H_ */ diff --git a/inc/app-assist-efl/WDefine.h b/inc/app-assist-efl/WDefine.h new file mode 100755 index 0000000..8c79ff1 --- /dev/null +++ b/inc/app-assist-efl/WDefine.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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 _APP_ASSIST_WDEFINE_H_ +#define _APP_ASSIST_WDEFINE_H_ + +/** +* @file WDefine.h +* @brief This file defines version number MACRO and functions. +* +*/ +#include + +#define WUSING_SDK_2_3 + + +const int WAPP_ASSIST_VERSION_MAJOR = 2; +const int WAPP_ASSIST_VERSION_MINOR = 1; +const int WAPP_ASSIST_VERSION_PATCH = 7; +const char* const WAPP_ASSIST_VERSION_PRE = ""; + +#define WAPP_ASSIST_EXPORT __attribute__((visibility("default"))) + +namespace app_assist { +WAPP_ASSIST_EXPORT int WVersion_getMajor(); +WAPP_ASSIST_EXPORT int WVersion_getMinor(); +WAPP_ASSIST_EXPORT int WVersion_getPatch(); +WAPP_ASSIST_EXPORT const char* WVersion_getPre(); +WAPP_ASSIST_EXPORT const char* WVersion_get(); + +template +std::unique_ptr make_unique(Ts&&... params) +{ + return std::unique_ptr(new T(std::forward(params)...)); +} +} + +#define WDISABLE_COPY_AND_ASSIGN(A) \ + A( const A& ) = delete; \ + const A& operator=( const A& ) = delete + +#define WDECLARE_PRIVATE_IMPL(A) \ + class _##A##Impl* __pv; \ + friend class _##A##Impl + + + +#endif /* _APP_ASSIST_WDEFINE_H_ */ diff --git a/inc/app-assist-efl/WEvasObject.h b/inc/app-assist-efl/WEvasObject.h new file mode 100755 index 0000000..bae0c4f --- /dev/null +++ b/inc/app-assist-efl/WEvasObject.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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 _APP_ASSIST_WEVAS_OBJECT_H_ +#define _APP_ASSIST_WEVAS_OBJECT_H_ + +#include +#include +#include "WDefine.h" + +namespace app_assist { + +class IWEvasObject; + +typedef std::weak_ptr WEvasObjectPtr; + +WAPP_ASSIST_EXPORT WEvasObjectPtr wevasobject_get_weak_ptr(Evas_Object* obj); + +class WAPP_ASSIST_EXPORT IWEvasObject { +protected: + virtual ~IWEvasObject() {}; +public: + virtual Evas_Object* getEvasObj() = 0; +}; + +} // namespace + +#endif /* _APP_ASSIST_WEVAS_OBJECT_H_ */ diff --git a/inc/app-assist-efl/WGengridItem.h b/inc/app-assist-efl/WGengridItem.h new file mode 100755 index 0000000..b3cb183 --- /dev/null +++ b/inc/app-assist-efl/WGengridItem.h @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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 _APP_ASSIST_WGENGRID_ITEM_H_ +#define _APP_ASSIST_WGENGRID_ITEM_H_ + +#include +#include +#include +#include "WDefine.h" + +namespace app_assist { + +class WViewController; +/** +* @class WGengridItem +* @brief This class is +* +* +* The %WGengridItem is +*/ +class WAPP_ASSIST_EXPORT WGengridItem { +public: + /** + * This is the default constructor for this class. + * + */ + WGengridItem(); + + /** + * This is the destructor for this class. + * + */ + virtual ~WGengridItem(); +public: + /** + * Override this method to create Elm_Gengrid_Item_Class structure. + * It is used to append item to the gengrid. Define static Elm_Gengrid_Item_Class variable and return it. + * + * @return the pointer of Elm_Gengrid_Item_Class instantiated as static variable. + * It is not needed to be free. + * @see getItemClassNew() + */ + virtual Elm_Gengrid_Item_Class* getItemClassStatic(); + + /** + * Override this method to create Elm_Gengrid_Item_Class structure. + * It is used to append item to the gengrid. + * + * @return the pointer of Elm_Gengrid_Item_Class created by elm_gengrid_item_class_new. + * It should be free by elm_gengrid_item_class_free if it is not used anymore. + * @see getItemClassStatic() + */ + virtual Elm_Gengrid_Item_Class* getItemClassNew(); + + /** + * Gets Elm_Object_Item of this item instance after it is appened to gengrid. + * + * @return the Elm_Object_Item + * @see setElmObjectItem() + */ + Elm_Object_Item* getElmObjectItem(); + + /** + * Sets Elm_Object_Item, which is returned when this item is appended to gengrid. + * If this Elm_Object_Item is required in your gengrid item implementation, set it by this method. + * Then you can get it by getElmObjectItem method. + * After calling this method, consequently virtual method onSetElmObjectItem will be called. + * + * @param[in] objItem The pointer of Elm_Object_Item + * + * @see getElmObjectItem() + * @see onSetElmObjectItem() + */ + void setElmObjectItem(Elm_Object_Item* objItem); + + /** + * Gets static callback function to be used to append item to the gengrid. + * Then callback will call onSelect( Elm_Object_Item* item ) method when callback is invoked. + * + * @see Evas_Smart_Cb + * @see onSelect() + */ + static Evas_Smart_Cb getSelectCb(); + +protected: + /** + * Override this method to do something when gengrid is selected. + * Before this, "selectCb" should be set as select callback of gengrid when this item is appended. + * + * @param[in] objItem Elm_Object_Item of this instance + * + * @see selectCb() + */ + virtual void onSelect(Elm_Object_Item* objItem); + + /** + * Override this method to set more properties to Elm_Object_Item of this item. + * It is called when setElmObjectItem method is called to set the Elm_Object_Item pointer of this item. + * + * @param[in] objItem Elm_Object_Item of this instance + * + * @see setElmObjectItem() + */ + virtual void onSetElmObjectItem(Elm_Object_Item* objItem); + + /** + * Attaches the pop-up to the view, which is the container view of this item. + * + * @param[in] popup The pointer to the pop-up instance to be attached + * + * @return true the view is found and it is attached successfully. + */ + bool attachToParentViewController(WViewController* popup); + +private: + WDECLARE_PRIVATE_IMPL(WGengridItem); + WDISABLE_COPY_AND_ASSIGN(WGengridItem); +}; + +#define WGENGRID_ITEM_DEL() [](void* data, Evas_Object* obj) \ + { \ + WGengridItem* item = static_cast(data); \ + delete item; \ + } + +/** + * This is a helper function. + * Appends gengrid item to the gengrid. It helps to add gengrid item using WGengridItem class to gengrid. + * Internally setElmObjectItem method of the WGengridItem is called to set Elm_Object_Item pointer. + * The virtual method onSelect of WGengridItem class will be called when the item is selected. + * + * @param[in] gengrid gengrid Evas Object + * @param[in] itc item class + * @param[in] item WGengridItem type object pointer to be appended + * + * @see gengrid_item_append + */ +WAPP_ASSIST_EXPORT Elm_Object_Item* wgengrid_item_append(Evas_Object* gengrid, const Elm_Gengrid_Item_Class* itc, WGengridItem* item); + +/** + * This is a helper function. + * Appends gengrid item to the gengrid. It helps to add gengrid item using WGengridItem class to gengrid. + * Internally setElmObjectItem method of the WGengridItem is called to set Elm_Object_Item pointer. + * When the item is selected, selectCb will be called instead of onSelect virtual method of the WGengridItem class. + * + * @param[in] gengrid gengrid Evas Object + * @param[in] itc item class + * @param[in] item WGengridItem type object pointer + * @param[in] selectCb the callback function to be called when the item is selected + * @param[in] userData select callback function user data pointer + * + * @see gengrid_item_append + * @see wgengrid_item_append + */ +WAPP_ASSIST_EXPORT Elm_Object_Item* wgengrid_item_append_with_callback(Evas_Object* gengrid, const Elm_Gengrid_Item_Class* itc, WGengridItem* item, Evas_Smart_Cb selectCb, const void* userData); + +} // namespace + + + +#endif /* _APP_ASSIST_WGENGRID_ITEM_H_ */ diff --git a/inc/app-assist-efl/WGenlistItem.h b/inc/app-assist-efl/WGenlistItem.h new file mode 100755 index 0000000..ce13870 --- /dev/null +++ b/inc/app-assist-efl/WGenlistItem.h @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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 _APP_ASSIST_WGENLIST_ITEM_H_ +#define _APP_ASSIST_WGENLIST_ITEM_H_ + +#include +#include +#include +#include "WDefine.h" + +namespace app_assist { + +class WViewController; +/** +* @class WGenlistItem +* @brief This class is +* +* +* The %WGenlistItem is +*/ +class WAPP_ASSIST_EXPORT WGenlistItem { +public: + /** + * This is the default constructor for this class. + * + */ + WGenlistItem(); + + /** + * This is the destructor for this class. + * + */ + virtual ~WGenlistItem(); +public: + /** + * Override this method to create Elm_Genlist_Item_Class structure. + * It is used to append item to the genlist. Define static Elm_Getnlist_Item_Class variable and return it. + * + * @return the pointer of Elm_Genlist_Item_Class instantiated as static variable. + * It is not needed to be free. + * @see getItemClassNew() + */ + virtual Elm_Genlist_Item_Class* getItemClassStatic(); + + /** + * Override this method to create Elm_Genlist_Item_Class structure. + * It is used to append item to the genlist. + * + * @return the pointer of Elm_Genlist_Item_Class created by elm_genlist_item_class_new. + * It should be free by elm_genlist_item_class_free if it is not used anymore. + * @see getItemClassStatic() + */ + virtual Elm_Genlist_Item_Class* getItemClassNew(); + + /** + * Gets Elm_Object_Item of this item instance after it is appened to genlist. + * + * @return the Elm_Object_Item + * @see setElmObjectItem() + */ + Elm_Object_Item* getElmObjectItem(); + + /** + * Sets Elm_Object_Item, which is returned when this item is appended to genlist. + * If this Elm_Object_Item is required in your genlist item implementation, set it by this method. + * Then you can get it by getElmObjectItem method. + * After calling this method, consequently virtual method onSetElmObjectItem will be called. + * + * @param[in] objItem The pointer of Elm_Object_Item + * + * @see getElmObjectItem() + * @see onSetElmObjectItem() + */ + void setElmObjectItem(Elm_Object_Item* objItem); + + /** + * Gets static callback function to be used to append item to the genlist. + * Then callback will call onSelect( Elm_Object_Item* item ) method when callback is invoked. + * + * @see Evas_Smart_Cb + * @see onSelect( Elm_Object_Item* item ) + */ + static Evas_Smart_Cb getSelectCb(); + +protected: + /** + * Override this method to do something when genlist is selected. + * Before this, the function pointer returned by getSelectCb method, should be set as select callback of genlist when this item is appended. + * + * @param[in] objItem Elm_Object_Item of this instance + * + * @see getSelectCb() + */ + virtual void onSelect(Elm_Object_Item* objItem); + + /** + * Override this method to set more properties to Elm_Object_Item of this item. + * It is called when setElmObjectItem method is called to set the Elm_Object_Item pointer of this item. + * + * @param[in] objItem Elm_Object_Item of this instance + * + * @see setElmObjectItem() + */ + virtual void onSetElmObjectItem(Elm_Object_Item* objItem); + + /** + * Attaches the pop-up to the view, which is the container view of this item. + * + * @param[in] popup The pointer to the pop-up instance to be attached + * + * @return true the view is found and it is attached successfully. + */ + bool attachToParentViewController(WViewController* popup); + +private: + WDECLARE_PRIVATE_IMPL(WGenlistItem); + WDISABLE_COPY_AND_ASSIGN(WGenlistItem); +}; + +#define WGENLIST_ITEM_DEL() [](void* data, Evas_Object* obj) \ + { \ + WGenlistItem* item = static_cast(data); \ + delete item; \ + } +/** + * This is a helper function. + * Appends genlist item to the genlist. It helps to add genlist item using WGenlistItem class to genlist. + * Internally setElmObjectItem method of the WGenlistItem is called to set Elm_Object_Item pointer. + * The virtual method onSelect of WGenlistItem class will be called when the item is selected. + * + * @param[in] genlist genlist Evas Object + * @param[in] itc item class + * @param[in] item WGenlistItem type object pointer to be appended + * @param[in] type genlist item type + * + * @see genlist_item_append + */ +WAPP_ASSIST_EXPORT Elm_Object_Item* wgenlist_item_append(Evas_Object* genlist, const Elm_Genlist_Item_Class* itc, WGenlistItem* item, Elm_Genlist_Item_Type type); + +/** + * This is a helper function. + * Appends genlist item to the genlist. It helps to add genlist item using WGenlistItem class to genlist. + * Internally setElmObjectItem method of the WGenlistItem is called to set Elm_Object_Item pointer. + * When the item is selected, selectCb will be called instead of onSelect virtual method of the WGenlistItem class. + * + * @param[in] genlist genlist Evas Object + * @param[in] itc item class + * @param[in] item WGenlistItem type object pointer to be appended + * @param[in] type genlist item type + * @param[in] selectCb the callback function to be called when the item is selected + * @param[in] userData select callback function user data pointer + * + * @see genlist_item_append + * @see wgenlist_item_append + */ +WAPP_ASSIST_EXPORT Elm_Object_Item* wgenlist_item_append_with_callback(Evas_Object* genlist, const Elm_Genlist_Item_Class* itc, WGenlistItem* item, Elm_Genlist_Item_Type type, Evas_Smart_Cb selectCb, const void* userData); + +} // namespace + +#endif /* _APP_ASSIST_WGENLIST_ITEM_H_ */ diff --git a/inc/app-assist-efl/WMenuPopupController.h b/inc/app-assist-efl/WMenuPopupController.h new file mode 100755 index 0000000..2bb4e5a --- /dev/null +++ b/inc/app-assist-efl/WMenuPopupController.h @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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 _APP_ASSIST_WMENU_POPUP_CONTROLLER_H_ +#define _APP_ASSIST_WMENU_POPUP_CONTROLLER_H_ + +#include +#include +#include +#include "WViewController.h" + +namespace app_assist { +/** +* @class WMenuPopupController +* @brief This class is the menu pop-up class to make easy to manage menus. +* +* +* The %WMenuPopupController is the menu pop-up class. +*/ +class WAPP_ASSIST_EXPORT WMenuPopupController: public WViewController { +public: + /** + * This is the constructor for this class. + * + */ + WMenuPopupController(); +public: + + /** + * Creates a menu pop-up. + * + * @param[in] win parent window evas object + * @param[in] resizableObj resizable base evas object. According to this size, menu popup will be resized. + * + * @return true if it is succeeded + */ + bool createMenu(Evas_Object* win, Evas_Object* resizableObj); + + /** + * Appends menu items. + * + * @param[in] label label text of menu item + * @param[in] selectItemCb callback function object when the item is selected + * + * @return appended item. nullptr,if failed. + */ + Elm_Object_Item* appendItem(const char* label, const std::function< void()>& selectItemCb); + + /** + * Resize and show menu pop-up. + * + * @return true if it is succeeded + */ + bool showMenu(); + // +protected: + /** + * This is the destructor for this class. + * + */ + virtual ~WMenuPopupController(); +private: + virtual Evas_Object* onCreateView(Evas_Object* parent, void* param); //override; + virtual void onDestroy(); //override; +private: + WDECLARE_PRIVATE_IMPL(WMenuPopupController); + WDISABLE_COPY_AND_ASSIGN(WMenuPopupController); +}; + +} // namespace + +#endif /* _APP_ASSIST_WMENU_POPUP_CONTROLLER_H_ */ diff --git a/inc/app-assist-efl/WNaviframeController.h b/inc/app-assist-efl/WNaviframeController.h new file mode 100755 index 0000000..2664391 --- /dev/null +++ b/inc/app-assist-efl/WNaviframeController.h @@ -0,0 +1,197 @@ +/* + * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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 _APP_ASSIST_WNAVI_FRAME_CONTROLLER_H_ +#define _APP_ASSIST_WNAVI_FRAME_CONTROLLER_H_ + +#include +#include +#include +#include +#include "WViewController.h" +#include "IWWindowController.h" + +namespace app_assist { + +// forward declaration +class WContentViewController; + +/** +* @class WNaviframeController +* @brief This class is the controller class of naviframe elementary. +* +* +* The %WNaviframeController class is to control naviframe elementary. +*/ +class WAPP_ASSIST_EXPORT WNaviframeController : public WViewController { +public: + /** + * This is the default constructor for this class. + * + */ + WNaviframeController(); + + /** + * Gets the class name. + * + * @return The class name + */ + virtual const char* getClassName() const; //override; + +public: + /** + * Initializes and creates the evas object. + * "onCreate" will be called subsequently. + * + * @param[in] parent the parent evas object + * @param[in] param user data + * + * @return true if the creation is succeeded, else false + * @see onCreate() + */ + bool create(Evas_Object* parent, void* param); //final; + + /** + * Destroy the instance. "onDestroy" will be called subsequently. + * The naviframe elementary will be deleted together. + * + * @see onDestroy() + */ + void destroy(); //final; + + /** + * Pushes the view controller instance into naviframe. "onPushToNaviframe" will be called subsequently. + * If the view controller is not yet called "create", it will be called internally. + * + * @param[in] vc the pointer to the view controller instance to be pushed + * @param[in] vcName the view controller instance name to be set when it is pushed. + * @param[in] vcParam the user data to be passed as parameter of "create" method of the view controller. + * + * @return true if succeed, else false + * @see onPushToNaviframe + */ + bool push(WContentViewController* vc, const char* vcName, void* vcCreationParam); + bool push(WContentViewController* vc, const char* vcName); + bool push(WContentViewController* vc); + + /** + * Destroy all views stacked on naviframe. + * + */ + void destroyAllViewControllers(); + + /** + * Check if the view of view controller is on top of naviframe. + * + * @param[in] vc the pointer to the view controller instance to be checked + * + * @return true if it is top, else false + */ + bool isTopContentViewController(WContentViewController* vc); + /** + * Get the view controller on top of naviframe. + * + * @return WContentViewController pointer related with naviframe item + */ + WContentViewController* getTopContentViewController(); +public: + + /** + * Sets a delegate function. It delegates onLastItemPop handling to delegateFunc. + * This is simpler alternative to overriding the virtual method onLastItemPop(), allowing direct use of WNaviframeController without sub-classing. + * If delegation is used, onLastItemPop() will not be called. + * + * @param[in] delegateFunc The pointer to delegate function + * @see onLastItemPop() + */ + void setOnLastItemPop(const std::function& delegateFunc); +protected: + + /** + * Override this method to create your own naviframe elementary. + * + * @param[in] parent The pointer to the parent evas object + * @param[in] param user data + * @return The pointer to naviframe evas object created + */ + virtual Evas_Object* onCreateView(Evas_Object* parent, void* param); //override; + + /** + * Override this method to do something on this instance deletion. + * + * @see destroy() + */ + virtual void onDestroy(); //override; + + /** + * Override this method to do something before pushing the view to the naviframe. + * In the overridden method, WNaviframeController::onPush should be called to do the base operation. + * + * @param[in] vc The pointer to the view controller instance to be pushed + * @param[in] viewParam user data to be passed from "push". It is passed to the "create" method of the WContentViewController class + * + * @return result + * @see push + */ + virtual bool onPush(WContentViewController* vc, void* viewParam); + + /** + * Override this method to do something before popping the view from the naviframe. + * If you override this method, call WNaviframeController::onItemPop at the bottom of your method to do the base operations. + * + * @param[in] vc The pointer to the view controller instance to be popped + * @param[in] item The pointer to the navi item + * + * @return true the view will be popped out, false the view will not be popped. + * @see onLastItemPop() + */ + virtual bool onItemPop(WContentViewController* vc, Elm_Object_Item* item); + + /** + * Override this method to change how the application should work when last view is popped from naviframe. + * If you don't override it, the application will go background by default. + * Even though onLastItemPop is called, "onItemPop" will be called before. + * + * @param[out] popOut Set true, if you will pop out the last view and end the application. If not, set false before return + * @see onItemPop() + */ + virtual void onLastItemPop(bool* popOut); + + /** + * Gets the pointer to the IWWindowController type class instance. + * Usually it will be normal window instance, but if the naviframe created on UG module, it will be UG window instance. + * Through this returned pointer, you can get window related properties. + * + * @return The pointer to the IWWindowController type instance. + */ +// IWWindowController* getWindowController(); + +protected: + /** + * This is the destructor for this class. + * + */ + virtual ~WNaviframeController(); + +private: + WDECLARE_PRIVATE_IMPL(WNaviframeController); + WDISABLE_COPY_AND_ASSIGN(WNaviframeController); +}; + +} // namespace + +#endif /* _APP_ASSIST_WNAVI_FRAME_CONTROLLER_H_ */ diff --git a/inc/app-assist-efl/WPageSlideViewController.h b/inc/app-assist-efl/WPageSlideViewController.h new file mode 100755 index 0000000..c895dd3 --- /dev/null +++ b/inc/app-assist-efl/WPageSlideViewController.h @@ -0,0 +1,250 @@ +/* + * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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 _APP_ASSIST_WPAGE_SLIDE_VIEW_CONTROLLER_H_ +#define _APP_ASSIST_WPAGE_SLIDE_VIEW_CONTROLLER_H_ + +#include +#include +#include "WContentViewController.h" + +namespace app_assist { + +class IWWindowController; +class WNaviframeController; + +/** +* @class WPageSlideViewController +* @brief This class provides slide view with pages +* +* +* The %WPageSlideViewController is the class to provide slide page view. +*/ +class WAPP_ASSIST_EXPORT WPageSlideViewController : public WContentViewController { +public: + /** + * This is the default constructor for this class. + * + */ + WPageSlideViewController(); + + /** + * Retuns the class name string + * + * @return class name + */ + virtual const char* getClassName() const; //override; + +public: + /** + * Attaches WContentViewController ui object as a page + * + * @param[in] view WContentViewController object to be attached. + * + * @return true if succeeded. + * @see WContentViewController::onSetAsPageContent() + */ + bool appendPage(WContentViewController* content); + + /** + * Attaches WViewController ui object as a page. + * + * @param[in] control WViewController instance to be attached. + * + * @return true if succeeded. + */ + bool appendPage(WViewController* content); + + /** + * Attaches empty ui object as a page + * + * @return true if succeeded. + */ + bool appendPage(); + + /** + * Remove the page and delete its content. + * + * @param[in] index the index of the page.If it is out of range, it will fail. + * + * @return true if succeeded. + */ + bool removePage(int index); + + /** + * Resizes the page slide layout. + * Call this API when you append or remove pages by some events after creation is finished. + * If it is not called, the screen will not be updated. + * At the view creation time, you don't need to call this API. + * + * @see appendPage(), removePage() + */ + void resizePageSlideLayout(); + + /** + * Sets the page WContentViewController. If the previous page WContentViewController is exist, it returns false. + * + * @param[in] index the index of the page + * @param[in] view WContentViewController object + */ + bool setPageContent(int index, WContentViewController* view); + + /** + * Sets the page WViewController. If the previous page WViewController is exist, it returns false. + * + * @param[in] index the index of the page + * @param[in] control WViewController object + */ + bool setPageContent(int index, WViewController* control); + + /** + * Returns the number of page. + * + * @return the number of page + */ + int getPageCount(); + + /** + * Gets the page instance. + * + * @param[in] index index of the page + * + * @return UI object + */ + WViewController* getPageContent(int index); + + /** + * Gets the current page index. + * + * @return The current page index + */ + int getCurrentPageIndex(); + + /** + * Gets the scroller evas object. + * + * + * @return The pointer to the evas object of the scroller + */ + Evas_Object* getScroller(); + + /** + * Sets the flag whether the scroller is shown or not. + * + * @param[in] show true if it should be shown. + */ + void setScrollerShowState(bool show); + + /** + * Changes to the page + * + * @param[in] index the index of the page + * @param[in] withAnimation flag if animation is shown or not. + */ + void showPage(int index, bool withAnimation); + + /** + * Changes to the page. The animation effect is off. + * + * @param[in] index the index of the page + */ + void showPage(int index); + +public: + /** + * Sets a delegate function. It delegates onInitScroller handling to delegateFunc. it is called when scroller is created. + * Use this to set additional property to the scroller. + * + * @param[in] delegateFunc The pointer to delegate function + * + * @see onInitScroller() + */ + void setOnInitScroller(const std::function& delegateFunc); + + /** + * Sets 'scroll animation stop' event handling function. it is called when scroll animation completed. + * + * The dir parameter to the handlerFunc tells in which direction the pages moved. + * If dir > 0, the page right to the previously shown page is now showing. Page slid from right to left. + * if dir < 0, the page left to the previously shown page is now showing. Page slid from left to right. + * + * @param[in] handlerFunc The pointer to handler function + */ + void setOnScrollAnimStop(const std::function& handlerFunc); + +protected: + /** + * Unsets the page content. The page content is not deleted. + * It should be used with setPageContent method to set the page again. + * + * @param[in] index the index of the page + * + * @see setPageObject + */ + WViewController* unsetPageContent(int index); + +protected: + /** + * Called when the view is created. It comes from WContentViewController class. + * + * @param[in] parent parent evas object + * @param[in] viewParam user parameter + */ + virtual Evas_Object* onCreateView(Evas_Object* parent, void* viewParam); //override; + + /** + * Called when the container properties are set by Naviframe or other container views. + * Sets container properties for any existing page views, + * so that those page views can access window and naviframe. + * + * @param[in] naviframe WNaviframe instance + * @param[in] item navi item pointer of container view which is pushed into naviframe. + */ + virtual void onSetContainerProperties(WNaviframeController* naviframe, Elm_Object_Item* item); //override; + + /** + * Called when the layout is created. It comes from WContentViewController class. + * + * @param[in] parent parent evas object + * + * @return The evas object of layout to be created. + */ + virtual Evas_Object* onCreateLayout(Evas_Object* parent); + + /** + * Called when the scroller is created. + * Override this to set additional property to the scroller. + * + * @param[in] scroller scroller evas object + * + * @see setOnInitScroller() + */ + virtual void onInitScroller(Evas_Object* scroller); +protected: + /** + * This is the destructor for this class. + * + */ + virtual ~WPageSlideViewController(); +private: + WDECLARE_PRIVATE_IMPL(WPageSlideViewController); + WDISABLE_COPY_AND_ASSIGN(WPageSlideViewController); +}; + +} // namespace + +#endif /* _APP_ASSIST_WPAGE_SLIDE_VIEW_CONTROLLER_H_ */ diff --git a/inc/app-assist-efl/WPopupController.h b/inc/app-assist-efl/WPopupController.h new file mode 100755 index 0000000..57856f2 --- /dev/null +++ b/inc/app-assist-efl/WPopupController.h @@ -0,0 +1,168 @@ +/* + * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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 _APP_ASSIST_WPOPUP_CONTROLLER_H_ +#define _APP_ASSIST_WPOPUP_CONTROLLER_H_ + +#include "WViewController.h" +#include + +namespace app_assist { +/** +* @class WPopupController +* @brief This class is the pop-up class to make easy to create pop-up. +* +* +* The %WPopupController is the general pop-up class. +*/ +class WAPP_ASSIST_EXPORT WPopupController : public WViewController { +public: + /** + * This is the default constructor for this class. + * + */ + WPopupController(); + + /** + * This is the constructor with title and content string. + * + */ + WPopupController(const char* title, const char* textContent); +public: + /** + * Sets the title string of the pop-up. + * + * @param[in] title title text string + * + * @see setContent() + */ + void setTitle(const char* title); + + /** + * Sets the content string of the pop-up. + * + * @param[in] text content text string + * + * @see other setContent() + */ + void setContent(const char* text); + + /** + * Sets the content of the pop-up with WViewController instance. + * This instance life-time will be attached to WPopupController instance. + * + * @param[in] control WViewController instance to be set + * + * @see other setContent() + */ + void setContent(WViewController* control); + + /** + * Sets the creation function of the content Evas Object of the pop-up. + * + * @param[in] contentCreator content creation function object. At this function, create the content evas object and return it. + * + * @see other setContent() + */ + void setContent(const std::function& contentCreator); + + + /** + * Sets the string ID's domain name to be automatically translated on language change. + * The text content and title text should be set with string ID. + * + * @see setTitle( const char* title), setContent( const char* text) + */ + void setTextTranslatable(); + + /** + * Sets the string ID's domain name to be automatically translated on language change. The text content and title text should be set with string ID. + * If you want to use other text domain, use this API exceptionally. + * + * @param[in] textDomain text domain name + * + * @see setTitle( const char* title), setContent( const char* text) + */ + void setTextTranslatable(const char* textDomain); + + /** + * Add buttons with button text string and button pressed callback function. + * + * @param[in] buttonText text string of button + * @param[in] buttonCb callback function object to be called when button is pressed. + * At this function, if it returns true, pop-up will be deleted. If not, pop-up will not. + * @param[in] setPropertyCb callback function object. + * Through this function object, additional properties can be set to the button evas object. + * + * @return true if succeeded + */ + bool addButton(const char* buttonText, const std::function& buttonCb, const std::function& setPropertyCb); + bool addButton(const char* buttonText, const std::function& buttonCb); + + /** + * Add handler function when back button is pressed. + * If it is not set, pop-up will be closed. + * + * @param[in] backCb call back function object. + * If it returns true, pop-up will be closed, if not, remained. + * + */ + void setOnBack(const std::function& backCb); + + /** + * Add handler function to set more properties of pop-up. + * It will be called just after pop-up evas object is created in onCreate method. + * + * @param[in] addPropertiesCb callback function object + * + * @return true if succeeded + */ + void setOnAddProperties(const std::function& addPropertiesCb); + +protected: + /** + * Override it, if you want to create your own pop-up. WPopupController::onCreate will be called at the end of that function. + * This method comes from WViewController class. + * + * @param[in] parent parent evas object + * @param[in] param user data + * + * @return Evas object created + */ + virtual Evas_Object* onCreateView(Evas_Object* parent, void* param); //override; + + /** + * It is called when pop-up instance is deleted. This method comes from WViewController class. + * + * @see onCreate() + */ + virtual void onDestroy(); //override; + +protected: + /** + * This is the destructor for this class. + * + */ + virtual ~WPopupController(); +private: + WDECLARE_PRIVATE_IMPL(WPopupController); + WDISABLE_COPY_AND_ASSIGN(WPopupController); +}; + +} // namespace + +#endif /* _APP_ASSIST_WPOPUP_CONTROLLER_H_ */ diff --git a/inc/app-assist-efl/WSignal.h b/inc/app-assist-efl/WSignal.h new file mode 100755 index 0000000..19b0c0f --- /dev/null +++ b/inc/app-assist-efl/WSignal.h @@ -0,0 +1,245 @@ +/* + * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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 _APP_ASSIST_WSIGNAL_H_ +#define _APP_ASSIST_WSIGNAL_H_ + +#include +#include +#include +#include +#include "WSignalIdGenerator.h" +#include "WSignalImpl.h" +#include "WDebugBase.h" + +namespace app_assist { + +const unsigned int WSIGNAL_INVALID_ID = 0; + +typedef unsigned int WSignal_ListenerId; + +/** +* @class WSignal +* @brief WSignal is a base template class. WSignal class is to provide the implementation of observer or publish-subscribe patterns. +* +*/ +template< typename Func > +class WSignal { +}; + +/** +* @class WSignal +* @brief WSignal< Ret(Args...) > is template class when a callback function has return type and variadic arguments. +* Return type and arguments types and the number of arguments are decided by template parameters. +*/ +template< typename Ret, typename... Args > +class WSignal { +public: + /** + * This is the default constructor for this class. + * + */ + WSignal() : __guardFlag(false) {}; + + /** + * This is the destructor for this class. + * + */ + virtual ~WSignal() { removeAllListeners(); }; + + /** + * Adds a listener function object to this signal object to get a signal. + * + * @param[in] listener callback function object + * @param[in] evasObj optional. evas object related to listener function object. + * When this evas object is deleted, automatically this listener will be removed from the signal object. + * Then you don't need to call removeListener method. + * If it is not set, do not miss call removeListener by yourself. + * + * @return the added listener id + * + * @see removeListener + */ + WSignal_ListenerId addListener(const std::function< Ret(Args...) >& listener, Evas_Object* evasObj) { WSIGNAL_IMPL_ADD_LISTENER(listener, evasObj) } + WSignal_ListenerId addListener(const std::function< Ret(Args...) >& listener) { WSIGNAL_IMPL_ADD_LISTENER(listener, nullptr) } + + /** + * Removes a listener function object from this signal object. + * + * @param[in] id listener id which is returned from addListener + * + * @see addListener + */ + void removeListener(WSignal_ListenerId& id) { WSIGNAL_IMPL_REMOVE_LISTENER(id) } + + /** + * Checks the validity of listener id. + * + * @param[in] id the id of a listener + * + * @return true, if it is valid. + * + * @see addListener + */ + bool isValid(WSignal_ListenerId id) { WSIGNAL_IMPL_IS_VALID(id) } + + /** + * Emits a signal to all added listeners. + * + * @param[in] args variadic arguments to be given to listeners + * + */ + void emit(Args... args) { WSIGNAL_IMPL_EMIT(args) } + + /** + * Gets the number of added listeners. + * + * @return the number of listeners + */ + int getListenerCount() { WSIGNAL_IMPL_GET_LISTENER_COUNT() } + + /** + * Removes all added listeners + * + */ + void removeAllListeners() { WSIGNAL_IMPL_REMOVE_ALL_LISTENERS() } + +protected: + /** + * Overrides this method and set how to emit signals to listeners and how to handle the return value from listeners. + * + * @param[in] args variadic arguments to be given to listeners + */ + virtual void onEmit(Args... args) = 0; +protected: + WSIGNAL_IMPL_LISTENER_MAP(Ret, Args) + +private: + static void __listenerEvasObjDelCb(void* data, Evas* evas, Evas_Object* obj, void* event_info) { WSIGNAL_IMPL_LISTENER_EVAS_OBJECT_DEL_CB(data) } + + bool __guardFlag; + std::list< std::unique_ptr > __listAddedListeners; + + WDISABLE_COPY_AND_ASSIGN(WSignal); +}; + +/** +* @class WSignal +* @brief WSignal< void(Args...) > is template class when a callback function has no return type and variadic arguments. +* Arguments types and the number of arguments are decided by template parameters. +* +*/ +template< typename... Args > +class WSignal { +public: + /** + * This is the default constructor for this class. + * + */ + WSignal() : __guardFlag(false) {}; + /** + * This is the destructor for this class. + * + */ + virtual ~WSignal() { removeAllListeners(); }; + + /** + * Adds a listener function object to this signal object to get a signal. + * + * @param[in] listener callback function object + * @param[in] evasObj optional. evas object related to listener function object. + * When this evas object is deleted, automatically this listener will be removed from the signal object. + * Then you don't need to call removeListener method. + * If it is not set, do not miss call removeListener by yourself. + * + * @return the added listener id + * + * @see removeListener + */ + WSignal_ListenerId addListener(const std::function< void(Args...) >& listener, Evas_Object* evasObj) { WSIGNAL_IMPL_ADD_LISTENER(listener, evasObj) } + WSignal_ListenerId addListener(const std::function< void(Args...) >& listener) { WSIGNAL_IMPL_ADD_LISTENER(listener, nullptr) } + + /** + * Removes a listener function object from this signal object. + * + * @param[in] id listener id which is returned from addListener + * + * @see addListener + */ + void removeListener(WSignal_ListenerId& id) { WSIGNAL_IMPL_REMOVE_LISTENER(id) } + + /** + * Checks the validity of listener id. + * + * @param[in] id the id of a listener + * + * @return true, if it is valid. + * + * @see addListener + */ + bool isValid(WSignal_ListenerId id) { WSIGNAL_IMPL_IS_VALID(id) } + + /** + * Emits a signal to all added listeners. + * + * @param[in] args variadic arguments to be given to listeners + * + */ + void emit(Args... args) { WSIGNAL_IMPL_EMIT(args) } + + /** + * Gets the number of added listeners. + * + * @return the number of listeners + */ + int getListenerCount() { WSIGNAL_IMPL_GET_LISTENER_COUNT() } + + /** + * Removes all added listeners + * + */ + void removeAllListeners() { WSIGNAL_IMPL_REMOVE_ALL_LISTENERS() } + +protected: + /** + * Overrides this method to change how to send signals to listeners. + * The default implementation is to call listeners' callback sequentially. + * + * @param[in] args variadic arguments to be given to listeners + */ + virtual void onEmit(Args... args) + { + for ( auto& it : __mapListeners ) { + if (it.second->removed) continue; + it.second->cb(args...); + } + } +protected: + WSIGNAL_IMPL_LISTENER_MAP(void, Args) + +private: + static void __listenerEvasObjDelCb(void* data, Evas* evas, Evas_Object* obj, void* event_info) { WSIGNAL_IMPL_LISTENER_EVAS_OBJECT_DEL_CB(data) } + + bool __guardFlag; + std::list< std::unique_ptr > __listAddedListeners; + + WDISABLE_COPY_AND_ASSIGN(WSignal); +}; + +} // namespace + +#endif /* _APP_ASSIST_WSIGNAL_H_ */ diff --git a/inc/app-assist-efl/WSignalIdGenerator.h b/inc/app-assist-efl/WSignalIdGenerator.h new file mode 100755 index 0000000..bb117c6 --- /dev/null +++ b/inc/app-assist-efl/WSignalIdGenerator.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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 _APP_ASSIST_WSIGNAL_ID_GENERATOR_H_ +#define _APP_ASSIST_WSIGNAL_ID_GENERATOR_H_ + +#include "WDefine.h" + +namespace app_assist { + +class WAPP_ASSIST_EXPORT WSignalIdGenerator { +public: + /** + * Gets the unique id for WSignal listener. + * WSignal class internal use only + * + * @return the id + * + * @see addListener + */ + static unsigned int generate(); +}; + +} // namespace + +#endif /* _APP_ASSIST_WSIGNAL_ID_GENERATOR_H_ */ diff --git a/inc/app-assist-efl/WSignalImpl.h b/inc/app-assist-efl/WSignalImpl.h new file mode 100755 index 0000000..f36fc41 --- /dev/null +++ b/inc/app-assist-efl/WSignalImpl.h @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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 _APP_ASSIST_WSIGNAL_IMPL_H_ +#define _APP_ASSIST_WSIGNAL_IMPL_H_ + +#define WSIGNAL_IMPL_ADD_LISTENER(listener, obj) \ + WSignal_ListenerId id = WSignalIdGenerator::generate(); \ + auto l = app_assist::make_unique(); \ + l->cb = listener; \ + l->evasObj = obj; \ + l->id = id; \ + l->signal = this; \ + if( __guardFlag ) \ + { \ + __listAddedListeners.push_back(std::move(l)); \ + } \ + else \ + { \ + __mapListeners[id] = std::move(l); \ + if( obj ) \ + evas_object_event_callback_add(obj, EVAS_CALLBACK_DEL, __listenerEvasObjDelCb, __mapListeners[id].get()); \ + } \ + return id; + +#define WSIGNAL_IMPL_REMOVE_LISTENER(id) \ + if( id == WSIGNAL_INVALID_ID ) return; \ + auto it = __mapListeners.find(id); \ + if( it != __mapListeners.end() ) \ + { \ + if( it->second->evasObj ) \ + evas_object_event_callback_del_full(it->second->evasObj, EVAS_CALLBACK_DEL, __listenerEvasObjDelCb, it->second.get()); \ + if( __guardFlag ) \ + it->second->removed = true; \ + else \ + __mapListeners.erase(id); \ + } \ + else \ + { \ + WERROR("Already removed listener! =%d", id); \ + } \ + id = WSIGNAL_INVALID_ID; + +#define WSIGNAL_IMPL_IS_VALID(id) \ + if( id == WSIGNAL_INVALID_ID ) return false; \ + auto it = __mapListeners.find(id); \ + if( it != __mapListeners.end() ) \ + return true; \ + else \ + return false; + +#define WSIGNAL_IMPL_EMIT(args) \ + __guardFlag = true; \ + onEmit(args...); \ + __guardFlag = false; \ + for( auto it = __mapListeners.begin(); it != __mapListeners.end(); ) \ + { \ + if( it->second->removed ) \ + __mapListeners.erase(it++); \ + else \ + it++; \ + } \ + if( __listAddedListeners.empty() == false ) \ + { \ + for( auto& elem : __listAddedListeners ) \ + { \ + WSignal_ListenerId id = elem->id; \ + __mapListeners[id] = std::move(elem); \ + if( __mapListeners[id]->evasObj ) \ + evas_object_event_callback_add(__mapListeners[id]->evasObj, EVAS_CALLBACK_DEL, __listenerEvasObjDelCb, __mapListeners[id].get()); \ + } \ + __listAddedListeners.clear(); \ + } + +#define WSIGNAL_IMPL_GET_LISTENER_COUNT() \ + return __mapListeners.size(); + + +#define WSIGNAL_IMPL_REMOVE_ALL_LISTENERS() \ + for( auto& it : __mapListeners ) \ + { \ + if( it.second->evasObj ) \ + evas_object_event_callback_del_full(it.second->evasObj, EVAS_CALLBACK_DEL, __listenerEvasObjDelCb, it.second.get()); \ + if( __guardFlag) \ + it.second->removed = true; \ + } \ + if( __guardFlag == false ) \ + __mapListeners.clear(); + + +#define WSIGNAL_IMPL_LISTENER_MAP(Ret, Args) \ + struct ListenerInfo \ + { \ + ListenerInfo(): evasObj(nullptr), removed(false), id(0), signal(nullptr){} \ + ~ListenerInfo(){} \ + std::function< Ret(Args...)> cb; \ + Evas_Object* evasObj; \ + bool removed; \ + WSignal_ListenerId id; \ + WSignal* signal; \ + }; \ + std::map< WSignal_ListenerId, std::unique_ptr > __mapListeners; + +#define WSIGNAL_IMPL_LISTENER_EVAS_OBJECT_DEL_CB(data) \ + auto li = (ListenerInfo*)(data); \ + li->evasObj = nullptr; \ + if( li->signal->__guardFlag ) \ + { \ + li->removed = true; \ + return; \ + } \ + li->signal->removeListener(li->id); + +#endif /* _APP_ASSIST_WSIGNAL_IMPL_H_ */ diff --git a/inc/app-assist-efl/WUiThread.h b/inc/app-assist-efl/WUiThread.h new file mode 100755 index 0000000..13ca6cb --- /dev/null +++ b/inc/app-assist-efl/WUiThread.h @@ -0,0 +1,232 @@ +/* + * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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 _APP_ASSIST_WUI_THREAD_H_ +#define _APP_ASSIST_WUI_THREAD_H_ + +#include +#include +#include "WDefine.h" + +namespace app_assist { + +/** +* @class WUiThread +* @brief This class is implemented based on ecore thread module. +* +* The %WUiThread is the class managing ecore thread +*/ +class WAPP_ASSIST_EXPORT WUiThread +{ +public: + WUiThread(); + virtual ~WUiThread(); + +public: + /** + * @class IStatus + * @brief WUiThread inner class for thread worker function + * + */ + class IStatus + { + public: + virtual ~IStatus(){}; + // + /** + * Check if cancellation is requested or not. + * If it returns true, thread worker function can do exit from the thread. + * + * @param[in] thread the thread pointer given from worker function parameter + * + * @return true if the cancellation is requested by cancel() method. + * @see cancel() + * @see ecore_thread_check() + */ + virtual bool isCancelRequested(Ecore_Thread* thread) = 0; + + /** + * Gets a integer data sent from the main thread. + * After getting this data, this data will be removed from ecore_thread_global_data. + * + * @return The integer data set by setThreadGlobalDataInt method. + * If it returns -1, it means that there is no data come. + * @see setThreadGlobalDataInt() + * @see ecore_thread_global_data_find() + */ + virtual int getThreadGlobalDataInt() = 0; + + /** + * Gets a integer data sent from the main thread with a key. + * After getting this data, this data and key will be removed from ecore_thread_global_data. + * + * @return The integer data set by setThreadGlobalDataInt method. + * If it returns -1, it means that there is no data come. + * @see setThreadGlobalDataInt() + * @see ecore_thread_global_data_find() + */ + virtual int getThreadGlobalDataInt(const char* key) = 0; + + /** + * Sends feedback to main thread. + * It leads to call notify callback set by setNotifyCb method. If it is not set, this method will not do anything. + * + * @param[in] thread the thread pointer given from worker function parameter + * @param[in] userData user data + * + * @return true if succeeded + * @see ecore_thread_feedback() + * @see ecore_thread_feedback_run() + */ + virtual bool sendFeedback(Ecore_Thread* thread, void* msgData) = 0; + }; + /** + * Sets the thread worker function + * + * @param[in] func the thread worker function + * + * @return false, if the thread is already created and running + * @see ecore_thread_run() + * @see ecore_thread_feedback_run() + */ + bool setWorker(const std::function& func); + + /** + * Sets the thread end callback function. + * It is called in the main thread context, when the thread worker function exits normally without cancellation request. + * If the cancellation is requested, the cancel callback will be called instead of this end callback. + * + * @param[in] endCb the thread end callback function + * + * @return false, if the thread is already created and running + * @see setCancelCb() + * @see ecore_thread_run() + * @see ecore_thread_feedback_run() + */ + bool setEndCb(const std::function& endCb); + + /** + * Sets the thread cancel callback function. + * It is called in the main thread context, when the thread worker function exits with cancellation request. + * When it becomes to be called, the end callback will not be called. + * + * @param[in] cancelCb the thread cancel callback function + * + * @return false, if the thread is already created and running + * @see setEndCb() + * @see ecore_thread_run() + * @see ecore_thread_feedback_run() + */ + bool setCancelCb(const std::function& cancelCb); + + /** + * Sets the thread feedback notification callback function. + * It is called in the main thread context, when the sendFeedback method is called in the thread worker function. + * + * @param[in] notifyCb the thread feedback notification callback function + * + * @return false, if the thread is already created and running + * @see ecore_thread_feedback_run() + */ + bool setNotifyCb(const std::function& notifyCb); + +public: + /** + * Starts the thread. + * + * @return false, if the thread is already created and running or failed. + * + * @see setWorker() + * @see ecore_thread_run() + * @see ecore_thread_feedback_run() + */ + bool run(); + + /** + * Send cancellation message to the thread and wait the thread work function to exit, with timeout timer. + * The thread is not cancelled by the framework. + * In the your worker function, It should be checked if cancellation is request or not by calling isCancelRequested periodically. + * If this checking interval is long, it will be blocked for that much time. + * When the thread worker function exits, cancel callback will be called set by setCancelCb method. + * In public SDK, time-out is NOT SUPPORTED.So you should wait cancel callback to check the cancellation is completed. + * + * @param[in] waitSeconds timeout time in seconds (NOT SUPPORTED in public SDK) + * + * @return false, if it is timeout. + * + * @see setCancelCb() + * @see isCancelRequested() + * @see ecore_thread_cancel() + * @see ecore_thread_wait() + */ + bool cancel(double waitSeconds); + + /** + * Wait the thread worker function to exit for the time. + * This method is NOT SUPPORTED in public SDK! + * + * @param[in] waitSeconds timeout time in seconds (NOT SUPPORTED in public SDK) + * + * @return false, if it is timeout. + * @see ecore_thread_wait() + */ + bool wait(double waitSeconds); + + /** + * Cancel the thread without calling cancel callback. + * It works same as cancel method, but cancel or end callback function will not be called. + * In the destructor, this method is called to cancel the running thread. + * + * @param[in] waitSeconds timeout time in seconds (NOT SUPPORTED in public SDK) + * + * @return false, if it is timeout. + * + * @see cancel() + */ + bool cancelWithoutCallback(double waitSeconds); + + /** + * Sets a integer data to be get in the thread. + * In the thread worker function, this data can be get by getThreadGlobalDataInt method. + * + * @param[in] data a message data + * + * @see getThreadGlobalDataInt() + * @see ecore_thread_global_data_set() + */ + void setThreadGlobalDataInt(int data); + + /** + * Sets a integer data with the key to be get in the thread. + * In the thread worker function, this data can be get by getThreadGlobalDataInt method. + * + * @param[in] key a key of message + * @param[in] data a data message + * + * @see getThreadGlobalDataInt() + * @see ecore_thread_global_data_set() + */ + void setThreadGlobalDataInt(const char* key, int data); + +private: + WDECLARE_PRIVATE_IMPL(WUiThread); + WDISABLE_COPY_AND_ASSIGN(WUiThread); +}; + +} // namespace + +#endif /* _APP_ASSIST_WUI_THREAD_H_ */ diff --git a/inc/app-assist-efl/WUiTimer.h b/inc/app-assist-efl/WUiTimer.h new file mode 100755 index 0000000..35598b8 --- /dev/null +++ b/inc/app-assist-efl/WUiTimer.h @@ -0,0 +1,239 @@ +/* + * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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 _APP_ASSIST_WUI_TIMER_H_ +#define _APP_ASSIST_WUI_TIMER_H_ + +#include +#include +#include +#include +#include "WDefine.h" + +namespace app_assist { + +class WUiTimer; + +typedef std::weak_ptr WUiTimerWeakPtr; + +/** +* @class WUiTimer +* @brief This class wraps ecore timer module. +* +* +* The %WUiTimer is the class managing ecore timer +*/ +class WAPP_ASSIST_EXPORT WUiTimer { +public: + enum class Type { + IDLER, ///< Can be called multiple times with in one rendering cycle, based on system load. + ANIMATOR, ///< Called just once per rendering cycle. + TIMER, ///< Called just once per rendering cycle, if the "set time" is elapsed before next vsync. + JOB ///< Called just once per registration prior to timer, idler and animator. + }; + + /** + * Returns type of timer. + * + * @return timer type + * @see enum class Type + */ + WUiTimer::Type getType(); + + /** + * Deletes this instance. + * The created timer will be deleted together. + * + * @param[in,out] timer the reference type of weak pointer of WUiTimer instance. timer variable will be reset. + * + */ + static void destroy(WUiTimerWeakPtr& timer); + + /** + * Creates a IDLER type timer. It uses ecore_idler internally. + * It can be called multiple times with in one rendering cycle, based on system load. + * + * @param[in] timerFunc std::function object of worker function + * @param[in] userData user data + * @param[in] ownerObj the owner Evas_Object + * When this Evas Object is deleted, the WUiTimer will be deleted together, if it is still alive. + * nullptr is not allowed. + * + * @return The weak pointer of WUiTimer instance created. The validity of the pointer can be checked with the lock() method. + * If it is failed or invalid when lock() method is called with this weak pointer will return empty shared_ptr. + */ + static WUiTimerWeakPtr addIdler(const std::function& timerFunc, void* userData, Evas_Object* ownerObj); + + /** + * Creates a IDLER type timer. It uses ecore_idler internally. + * It can be called multiple times with in one rendering cycle, based on system load. + * + * @param[in] timerFunc std::function object of worker function + * @param[in] userData user data + * + * @return The weak pointer of WUiTimer instance created. The validity of the pointer can be checked with the lock() method. + * If it is failed or invalid when lock() method is called with this weak pointer will return empty shared_ptr. + * The returned value should be released by WUiTimer::destroy(). + */ + static WUiTimerWeakPtr addIdler(const std::function& timerFunc, void* userData); + + /** + * Creates a ANIMATOR type timer. It uses ecore_animator internally. + * It will be called just once per rendering cycle. + * + * @param[in] timerFunc std::function object of worker function + * @param[in] userData user data + * @param[in] ownerObj the owner Evas_Object + * When this Evas Object is deleted, the WUiTimer will be deleted together, if it is still alive. + * nullptr is not allowed. + * + * @return The weak pointer of WUiTimer instance created. The validity of the pointer can be checked with the lock() method. + * If it is failed or invalid when lock() method is called with this weak pointer will return empty shared_ptr. + */ + static WUiTimerWeakPtr addAnimator(const std::function& timerFunc, void* userData, Evas_Object* ownerObj); + + /** + * Creates a ANIMATOR type timer. It uses ecore_animator internally. + * It will be called just once per rendering cycle. + * + * @param[in] timerFunc std::function object of worker function + * @param[in] userData user data + * + * @return The weak pointer of WUiTimer instance created. The validity of the pointer can be checked with the lock() method. + * If it is failed or invalid when lock() method is called with this weak pointer will return empty shared_ptr. + * The returned value should be released by WUiTimer::destroy(). + */ + static WUiTimerWeakPtr addAnimator(const std::function& timerFunc, void* userData); + + /** + * Creates a timer. It uses ecore_timer internally. + * It will be called just once per rendering cycle, if the "set time" is elapsed before next vsync. + * + * @param[in] interval The interval in seconds. + * @param[in] timerFunc std::function object of worker function + * @param[in] userData user data + * @param[in] ownerObj the owner Evas_Object + * When this Evas Object is deleted, the WUiTimer will be deleted together, if it is still alive. + * nullptr is not allowed. + * + * @return The weak pointer of WUiTimer instance created. The validity of the pointer can be checked with the lock() method. + * If it is failed or invalid when lock() method is called with this weak pointer will return empty shared_ptr. + */ + static WUiTimerWeakPtr addTimer(double interval, const std::function& timerFunc, void* userData, Evas_Object* ownerObj); + + /** + * Creates a timer. It uses ecore_timer internally. + * It will be called just once per rendering cycle, if the "set time" is elapsed before next vsync. + * + * @param[in] interval The interval in seconds. + * @param[in] timerFunc std::function object of worker function + * @param[in] userData user data + * + * @return The weak pointer of WUiTimer instance created. The validity of the pointer can be checked with the lock() method. + * If it is failed or invalid when lock() method is called with this weak pointer will return empty shared_ptr. + * The returned value should be released by WUiTimer::destroy(). + */ + static WUiTimerWeakPtr addTimer(double interval, const std::function& timerFunc, void* userData); + + /** + * Creates a JOB type timer. It uses ecore_job internally. + * It will be called just once per registration prior to timer, idler and animator. + * + * @param[in] timerFunc std::function object of worker function + * @param[in] userData user data + * @param[in] ownerObj the owner Evas_Object + * When this Evas Object is deleted, the WUiTimer will be deleted together, if it is still alive. + * nullptr is not allowed. + * + * @return The weak pointer of WUiTimer instance created. The validity of the pointer can be checked with the lock() method. + * If it is failed or invalid when lock() method is called with this weak pointer will return empty shared_ptr. + */ + static WUiTimerWeakPtr addJob(const std::function& timerFunc, void* userData, Evas_Object* ownerObj); + + /** + * Creates a JOB type timer. It uses ecore_job internally. + * It will be called just once per registration prior to timer, idler and animator. + * + * @param[in] timerFunc std::function object of worker function + * @param[in] userData user data + * + * @return The weak pointer of WUiTimer instance created. The validity of the pointer can be checked with the lock() method. + * If it is failed or invalid when lock() method is called with this weak pointer will return empty shared_ptr. + * The returned value should be released by WUiTimer::destroy(). + */ + static WUiTimerWeakPtr addJob(const std::function& timerFunc, void* userData); +private: + WUiTimer(); + ~WUiTimer(); + +private: + WDECLARE_PRIVATE_IMPL(WUiTimer); + WDISABLE_COPY_AND_ASSIGN(WUiTimer); +}; + +/** + * Gets Ecore_Idler handle pointer. + * Do not call ecore_idler_del with this returned pointer, because it is internal property of this WUiTimer instance. + * To delete the Ecore_Idler, call destroy method of this WUiTimer class. + * + * @param[in] uiTimer the reference of WUiTimer weak pointer + * + * @return Ecore_Idler handle pointer + * @see addIder() + */ +WAPP_ASSIST_EXPORT Ecore_Idler* wuitimer_get_idler_handle(const WUiTimerWeakPtr& uiTimer); + +/** + * Gets Ecore_Animator handle pointer. + * Do not call ecore_animator_del with this returned pointer, because it is internal property of this WUiTimer instance. + * To delete the Ecore_Animator, call destroy method of this WUiTimer class. + * + * @param[in] uiTimer the reference of WUiTimer weak pointer + * + * @return Ecore_Animator handle pointer + * @see addAnimator() + */ +WAPP_ASSIST_EXPORT Ecore_Animator* wuitimer_get_animator_handle(const WUiTimerWeakPtr& uiTimer); + +/** + * Gets Ecore_Timer handle pointer. + * Do not call ecore_timer_del with this returned pointer, because it is internal property of this WUiTimer instance. + * To delete the Ecore_Timer, call destroy method of this WUiTimer class. + * + * @param[in] uiTimer the reference of WUiTimer weak pointer + * + * @return Ecore_Timer handle pointer + * @see addTimer() + */ +WAPP_ASSIST_EXPORT Ecore_Timer* wuitimer_get_timer_handle(const WUiTimerWeakPtr& uiTimer); + +/** + * Gets Ecore_Job handle pointer. + * Do not call ecore_job_del with this returned pointer, because it is internal property of this WUiTimer instance. + * To delete the Ecore_Job, call destroy method of this WUiTimer class. + * + * @param[in] uiTimer the reference of WUiTimer weak pointer + * + * @return Ecore_Job handle pointer + * @see addJob() + */ +WAPP_ASSIST_EXPORT Ecore_Job* wuitimer_get_job_handle(const WUiTimerWeakPtr& uiTimer); + + +} // namespace + +#endif /* _APP_ASSIST_WUI_TIMER_H_ */ diff --git a/inc/app-assist-efl/WViewController.h b/inc/app-assist-efl/WViewController.h new file mode 100755 index 0000000..f9346e8 --- /dev/null +++ b/inc/app-assist-efl/WViewController.h @@ -0,0 +1,222 @@ +/* + * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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 _APP_ASSIST_WVIEW_CONTROLLER_H_ +#define _APP_ASSIST_WVIEW_CONTROLLER_H_ + +#include +#include +#include +#include "WDefine.h" +#include "IWWindowController.h" + +namespace app_assist { + +class WViewController; + +typedef std::weak_ptr WViewControllerWeakPtr; + +/** +* @class WViewController +* @brief This class is the UI control class linked with one evas object. +* +* +* The %WViewController is the abstract class managing an evas object +*/ +class WAPP_ASSIST_EXPORT WViewController { +public: + /** + * This is the default constructor for this class. + * + */ + WViewController(); + + /** + * Gets class name + * + * @return The class name + */ + virtual const char* getClassName() const; +public: + + /** + * Initializes and creates the control. onCreate will be called subsequently + * + * @param[in] parent parent evas object + * @param[in] param user data + * + * @return result + * @see onCreate() + */ + virtual bool create(Evas_Object* parent, void* param); + + /** + * Destroys the control. The linked evas object will be delete together. + * "onDestroy" will be called subsequently. + * + * @see onDestroy() + */ + virtual void destroy(); + + /** + * Gets evas object of this class. + * + * @return The pointer to evas object + */ + Evas_Object* getEvasObj() const; + + /** + * Sets the name of the instance. + * + * @param[in] name blash + */ + void setName(const char* name); + + /** + * Gets the name of the instance. + * + * @return The control name + */ + const char* getName() const; + + /** + * Returns weak pointer of this instance to refer it safe. + * + * @return weak pointer of this class instance + */ + WViewControllerWeakPtr getWeakPtr(); + + /** + * Attaches popup to the control.It means that it binds them to have same life-time. + * Internally create method of the pop-up will be called, if it is not yet created. + * If previous pop-up exists, it will be destroyed. + * + * @param[in] popup pop-up instance pointer to be attached + * + * @see destroyPopup() + */ + void attachPopup(WViewController* popup); + + /** + * Destroys pop-up. Use this method when you want to destroy pop-up explicitly. + * Pop-up will be deleted when the control is deleted, although this method is not called. + * + * @see attachPopup() + */ + void destroyPopup(); +public: + /** + * Sets a delegate function. It delegates onCreate handling to delegateFunc. + * This is simpler alternative to overriding the virtual method onCreate(), allowing direct use of WContentViewController without sub-classing. + * If delegation is used, onCreateView() will not be called. + * + * @param[in] delegateFunc The pointer to delegate function + * @see onCreateView() + */ + void setOnCreateView(const std::function& delegateFunc); + +protected: + /** + * Override this method to initialize this WViewController class. + * It is called when create method is called. + * + * @param[in] param user parameter + * + * @return true if it is succeeded. + * @see create() + * @see onCreated() + */ + virtual bool onCreate( void* param ) {return true;}; + /** + * Override this method to create evas object of this WViewController class. + * + * @param[in] parent the parent evas object + * @param[in] param user parameter + * + * @return The pointer to evas object created, which should be the most parent evas object among them created in this method. + * @see create() + * @see onCreated() + */ + virtual Evas_Object* onCreateView( Evas_Object* parent, void* param ) {return nullptr;} + + /** + * Override this method to do something after evas object is created. + * + * @see create() + * @see onCreate() + */ + virtual void onCreated() {}; + + /** + * Override this method to do something on this instance deletion. + * + * @see destroy() + */ + virtual void onDestroy() {}; + + /** + * Gets the pointer to the IWWindowController type class instance. + * Usually it will be normal window instance, but if the view created on UG module, it will be UG window instance. + * Through this returned pointer, you can get window related properties. + * + * @return The pointer to the IWWindowController type instance. + */ + IWWindowController* getWindowController(); + +protected: + /** + * This is the destructor for this class. + * + */ + virtual ~WViewController(); + +private: + WDECLARE_PRIVATE_IMPL(WViewController); + WDISABLE_COPY_AND_ASSIGN(WViewController); +}; + +/** + * Gets the class instance from evas object + * + * @param[in] obj evas object + * + * @return The pointer to WViewController class instance. It will be nullptr, if no instance is related. + */ +WAPP_ASSIST_EXPORT WViewController* wviewcontroller_get_instance_from_evasobj(Evas_Object* obj); + +/** + * Get the evas object of window baseLayout related to view. + * + * @param[in] view WViewController instance + * + * @return nullptr, if this failed to get window baseLayout. + */ +WAPP_ASSIST_EXPORT Evas_Object* wviewcontroller_get_window_baselayout_evasobj(WViewController* view); + +/** + * Get the evas object of window related to view. + * + * @param[in] view WViewController instance + * + * @return nullptr, if this failed to get window. + */ +WAPP_ASSIST_EXPORT Evas_Object* wviewcontroller_get_window_evasobj(WViewController* view); + +} // namespace + + +#endif /* _APP_ASSIST_WVIEW_CONTROLLER_H_ */ diff --git a/inc/app-assist-efl/WWindowController.h b/inc/app-assist-efl/WWindowController.h new file mode 100755 index 0000000..344eeb5 --- /dev/null +++ b/inc/app-assist-efl/WWindowController.h @@ -0,0 +1,246 @@ +/* + * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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 _APP_ASSIST_WWINDOW_CONTROLLER_H_ +#define _APP_ASSIST_WWINDOW_CONTROLLER_H_ + +#include +#include +#include +#include "WDefine.h" +#include "IWWindowController.h" + +namespace app_assist { + +class WViewController; + +/** +* @class WWindowController +* @brief This class represents window and base layout evas object. +* +* The %WWindowController manages window evas object and common base evas objects. +*/ +class WAPP_ASSIST_EXPORT WWindowController : public IWWindowController { +public: + WWindowController() = delete; + /** + * Constructor + * Initializes this instance of WWindowController with the specified value. + * + * @param[in] name The window name + * @param[in] winType The type of the window + */ + WWindowController(const char* name, Elm_Win_Type winType); + + /** + * Gets the class name of this class + * + * @return The class name + */ + virtual const char* getClassName(); //override; +public: + /** + * Creates the windows + * "onCreateWin" and "onCreateBaseLayout" will be called subsequently. + * + * @return true if the windows created sucessfully, else false + * @see onCreateWin() + * @see onCreateBaseLayout() + */ + bool create(); + + /** + * Creates the windows but not be shown + * "onCreateWin" and "onCreateBaseLayout" will be called subsequently. + * + * @return true if the windows created sucessfully, else false + * @see create() + * @see onCreateWin() + * @see onCreateBaseLayout() + */ + bool precreate(); + + /** + * Destroys the window class instance and delete window evas object. + * "onDestroy" will be called subsequently. + * + * @see onDestroy() + */ + void destroy(); + + /** + * Gets the evas object of the window + * + * @return The pointer to the evas object of the window + * @see onCreateWin() + */ + virtual Evas_Object* getEvasObj() const; //override; + + /** + * Gets the base layout evas object + * + * @return The pointer to the evas object of the layout + * @see onCreateBaseLayout() + */ + virtual Evas_Object* getBaseLayoutEvasObj(); //override; + + /** + * Gets the conformant evas object. + * + * @return The pointer to the evas object of the conformant + */ + virtual Evas_Object* getConformantEvasObj(); //override; + + /** + * Gets the base UI object attached. + * + * @return The pointer to the base ui object + * @see attachBaseViewController() + */ + virtual WViewController* getBaseViewController(); //override; + + /** + * Attaches base UI object, which can be WViewController instance. + * + * @param[in] baseObj WViewController instance to be attached + * @param[in] creationParam parameter to be passed as parameter of create method of the WViewController class + * + * @return true if the base ui object attached sucessfully, else false + * @see getBaseViewController() + */ + bool attachBaseViewController(WViewController* vc, void* creationParam); + bool attachBaseViewController(WViewController* vc); + + /** + * Detaches the base UI object. + * + * @return the base UI object, which should be deleted explicitly later. + */ + WViewController* detachBaseViewController(); + + /** + * Destroys the base UI object. + * + */ + void destroyBaseViewController(); + + /** + * Gets the window name + * + * @return The name of the window + */ + const char* getName(); + + /** + * Gets the type of the window + * + * @return The type of the window + */ + Elm_Win_Type getWinType(); + + /** + * Sets a delegate function. It delegates onCreateWin handling to delegateFunc. + * This is simpler alternative to overriding the virtual method onCreateWin(), allowing direct use of WWindowController without sub-classing. + * If delegation is used, onCreateWin() will not be called. + * + * @param[in] delegateFunc The pointer to delegate function + * @see onCreateWin() + */ + void setOnCreateWin(const std::function& delegateFunc); + + /** + * Sets a delegate function. It delegates onCreateBaseLayout handling to delegateFunc. + * This is simpler alternative to overriding the virtual method onCreateBaseLayout(), allowing direct use of WWindowController without sub-classing. + * If delegation is used, onCreateBaseLayout() will not be called. + * + * @param[in] delegateFunc The pointer to delegate function + * @see onCreateBaseLayout() + */ + void setOnCreateBaseLayout(const std::function& delegateFunc); + + /** + * Sets a back key handler function. It is called when 'back' key is pressed. + * Normally it is used for single view controller application without naviframe. + * + * @param[in] backHandlerFunc The pointer to handler function + */ + void setOnBack(const std::function& backHandlerFunc); +protected: + /** + * Called when create method is called to create window + * Override this method to create your own window evas object. + * + * @return The pointer to the evas object of the window created. + * @see create() + */ + virtual Evas_Object* onCreateWin(); + + /** + * Called when create method is called to create base layout. + * Override this method to create your own base layout and conformant evas objects. + * + * @param[in] win A pointer to evas object of the window + * @param[out] outConformant The pointer to the evas object of the conformant created. + * + * @return The pointer to the evas object of base layout created. + */ + virtual Evas_Object* onCreateBaseLayout(Evas_Object* win, Evas_Object** outConformant); + + /** + * Called when attachBaseViewController is called. + * Default behavior is to set the given base UI object to elm.swallow.content part of the default base layout. + * Override this method to add custom behaviors just before attachment, or if the default base layout is not used. + * + * @param[in] vc WViewController instance which is about to be attached + * + * @see attachBaseViewController() + */ + virtual void onAttachBaseViewController(WViewController* vc); + + /** + * Called when detachBaseViewController is called. + * Default behavior is to do nothing. + * Override this method to add custom behaviors just before detachment. + * + * @param[in] vc WViewController instance which is about to be detached + * + * @see detachBaseViewController() + */ + virtual void onDetachBaseViewController(WViewController* vc); + + /** + * Called when the window is destroyed + * Override this method to do something on destruction. + * + */ + virtual void onDestroy(); + + +protected: + /** + * This is the destructor for this class. + * + */ + virtual ~WWindowController(); +private: + WDECLARE_PRIVATE_IMPL(WWindowController); + WDISABLE_COPY_AND_ASSIGN(WWindowController); +}; + +} // namespace + +#endif /* _APP_ASSIST_WWINDOW_CONTROLLER_H_ */ diff --git a/packaging/projects.list b/packaging/projects.list new file mode 100755 index 0000000..fd27234 --- /dev/null +++ b/packaging/projects.list @@ -0,0 +1 @@ +Sketch diff --git a/project_def.prop b/project_def.prop new file mode 100644 index 0000000..9016a51 --- /dev/null +++ b/project_def.prop @@ -0,0 +1,63 @@ + +# Project Name +APPNAME = sketch + +# Project Type +type = app + +# Project Profile +profile = wearable-4.0 + +# C/CPP Sources +USER_SRCS = src/app-assist-efl/WViewControllerImpl.cpp src/app-assist-efl/WViewController.cpp src/app-assist-efl/WApp.cpp src/app-assist-efl/WPopupController.cpp src/controls/CDrCairoImage.cpp src/app-assist-efl/WMenuPopupControllerImpl.cpp src/View/CDrStrokeView.cpp src/app-assist-efl/WNaviframeController.cpp src/controls/CDrDrawingView.cpp src/app/CDrAppData.cpp src/app-assist-efl/WGengridItem.cpp src/app-assist-efl/WUiTimerImpl.cpp src/main.cpp src/controls/CDrHistoryControl.cpp src/controls/History.cpp src/app-assist-efl/WContentViewControllerImpl.cpp src/app/CDrApp.cpp src/EventManager/CDrEventManager.cpp src/CDrUtil.cpp src/app-assist-efl/WPageSlideViewController.cpp src/controls/CDrControlManager.cpp src/app-assist-efl/WVersion.cpp src/app-assist-efl/WAppEventHandler.cpp src/app-assist-efl/WSignalIdGenerator.cpp src/app-assist-efl/WGenlistItem.cpp src/app-assist-efl/WWindowController.cpp src/app-assist-efl/WContentViewController.cpp src/View/CDrMainView.cpp src/app-assist-efl/WEvasObject.cpp src/app-assist-efl/WMenuPopupController.cpp src/popup/CDrClosePopup.cpp src/controls/CDrTutorialView.cpp src/app-assist-efl/WUiThread.cpp src/controls/Drawing.cpp src/MediaDB/CDrMediaContent.cpp src/app-assist-efl/WUiTimer.cpp + +# EDC Sources +USER_EDCS = + +# PO Sources +USER_POS = res/po/bg.po res/po/kn.po res/po/mr.po res/po/bs_BA.po res/po/cs.po res/po/fr_CA.po res/po/hr.po res/po/km.po res/po/pl.po res/po/mn_MN.po res/po/uk.po res/po/en_US.po res/po/da.po res/po/en.po res/po/hi.po res/po/ky_KG.po res/po/en_PH.po res/po/lo.po res/po/sr.po res/po/ar.po res/po/hu.po res/po/ta.po res/po/ko_KR.po res/po/is.po res/po/ka.po res/po/sq.po res/po/eu.po res/po/kk.po res/po/ru_RU.po res/po/it_IT.po res/po/sv.po res/po/uz.po res/po/es_US.po res/po/nb.po res/po/pl_SP.po res/po/zh_TW.po res/po/et.po res/po/ne.po res/po/fr.po res/po/az.po res/po/pa.po res/po/tg_TJ.po res/po/zh_HK.po res/po/es_ES.po res/po/my_MM.po res/po/gl.po res/po/hy.po res/po/te.po res/po/ur.po res/po/vi.po res/po/gu.po res/po/mk.po res/po/bn.po res/po/bn_BD.po res/po/tr_TR.po res/po/my_ZG.po res/po/nl.po res/po/tk_TM.po res/po/as.po res/po/ca.po res/po/pt_PT.po res/po/fi.po res/po/id.po res/po/ml.po res/po/fa.po res/po/he.po res/po/el_GR.po res/po/pt_BR.po res/po/zh_CN.po res/po/tl.po res/po/ro.po res/po/ms.po res/po/si.po res/po/be_BY.po res/po/ja_JP.po res/po/lt.po res/po/sl.po res/po/or.po res/po/sk.po res/po/ga.po res/po/lv.po res/po/th.po res/po/de.po + +# User Defines +USER_DEFS = +USER_CPP_DEFS = TIZEN_DEBUG_ENABLE REDO_UNDO SQLITE_HAS_CODEC + +# User Undefines +USER_UNDEFS = +USER_CPP_UNDEFS = + +# User Libraries +USER_LIBS = + +# User Objects +USER_OBJS = + +# User Includes +## C Compiler +USER_C_INC_DIRS = +USER_INC_FILES = +## C++ Compiler +USER_CPP_INC_DIRS = inc src inc/app-assist-efl src/app-assist-efl src/app-assist-efl/inc src/app src/EventManager src/View src/controls src/MediaDB src/popup +USER_CPP_INC_FILES = + +USER_INC_DIRS = $(USER_C_INC_DIRS) $(USER_CPP_INC_DIRS) + +# User Library Path +USER_LIB_DIRS = + +# EDC Resource Path +USER_EDCS_IMAGE_DIRS = ${OUTPUT_DIR} edje_images res/images +USER_EDCS_SOUND_DIRS = ${OUTPUT_DIR} edje/sounds +USER_EDCS_FONT_DIRS = ${OUTPUT_DIR} edje/fonts + +# EDC Flags +USER_EXT_EDC_KEYS = EDC0 + +USER_EXT_EDC0_EDCS = res/edje/drawing_layout.edc res/edje/btneffect.edc res/edje/animations2circle.edc res/edje/drawing_popup.edc +USER_EXT_EDC0_EDCS_IMAGE_DIRS = ${OUTPUT_DIR} edje_images res/images +USER_EXT_EDC0_EDCS_SOUND_DIRS = ${OUTPUT_DIR} edje/sounds +USER_EXT_EDC0_EDCS_FONT_DIRS = ${OUTPUT_DIR} edje/fonts + +# Resource Filter +USER_RES_INCLUDE = +USER_RES_EXCLUDE = + diff --git a/res/edje/animations2circle.edc b/res/edje/animations2circle.edc new file mode 100755 index 0000000..04466f6 --- /dev/null +++ b/res/edje/animations2circle.edc @@ -0,0 +1,943 @@ +#define MSG_VALUE 1 + +collections { + base_scale: 1.3; + plugins { + plugin { + name: "touch_sound"; + source: "feedback"; + param: "FEEDBACK_TYPE_SOUND FEEDBACK_PATTERN_TAP"; + } + } + + group { + script { + public send_mode = 0; //Landscape status + } + styles { + style { name: "mms_txt_style"; + base: "font=Tizen:style=Regular font_size="30" align=center color=#FFFFFF color_class=AT033 ellipsis=1.0 wrap=mixed text_class=AT033"; + } + style { name: "indicator_txt_style"; + base: "font=Tizen:style=Regular font_size="30" align=center color=#FFFFFF color_class=ATO032 ellipsis=1.0 wrap=mixed text_class=ATO032"; + } + } + name: "bg"; + parts { + part { + name: "bg"; + scale: 1; + type: RECT; + description { + state: "default" 0.0; + color_class: "AO0117"; + } + } + part { + name: "pre-view"; + scale: 1; + type: SWALLOW; + description { + state: "default" 0.0; + } + } + part { + name: "circle_menu"; + scale: 1; + type: SWALLOW; + description { + state: "default" 0.0; + visible: 0; + } + description { + state: "show" 0.0; + visible: 1; + } + + } + part { + name: "more_option"; + scale: 1; + type: SWALLOW; + description { + state: "default" 0.0; + rel1.relative: 0.0 0.0; + rel2.relative: 1.0 1.0; + } + } + part { + name: "elm.button.padding"; + scale: 1; + type: RECT; + mouse_events: 1; + repeat_events: 0; + description { + state: "default" 0.0; + rel1 {relative: 1.0 0.5; } + rel2 {relative: 1.0 0.5; } + min: 50 10; + max: 50 10; + fixed: 1 1; + align: 1.0 0.5; + color: 0 0 0 0; + } + } + part { + name: "elm.button.pallet"; + scale: 1; + type: SWALLOW; + mouse_events: 1; + repeat_events: 0; + description { + state: "default" 0.0; + rel1 {relative: 1.0 0.0; to_y: "elm.button.padding";} + rel2 {relative: 1.0 0.0; to_y: "elm.button.padding";} + min: 60 60; + max: 60 60; + fixed: 1 1; + align: 1.0 1.0; + + } + description { + state: "send_default" 0.0; + rel1 {relative: 1.0 0.0; } + rel2 {relative: 1.0 1.0; } + min: 150 150; + max: 150 150; + fixed: 1 1; + align: 0.5 0.5; + + } + description { + state: "hide" 0.0; + inherit: "default" 0.0; + visible: 0; + } + } + part { + name: "elm.button.stroke"; + scale: 1; + type: SWALLOW; + mouse_events: 1; + repeat_events: 0; + description { + state: "default" 0.0; + rel1 { relative: 1.0 1.0; to_y: "elm.button.padding";} + rel2 { relative: 1.0 1.0; to_y: "elm.button.padding";} + min: 60 60; + max: 60 60; + fixed: 1 1; + align: 1.0 0.0; + } + description { + state: "hide" 0.0; + inherit: "default" 0.0; + visible: 0; + } + } + part{ + name: "bottom_padding"; + scale: 1; + type: SPACER; + description { + state: "default" 0.0; + min: 360 8; + max: 360 8; + fixed: 1 1; + rel1 { relative: 0.0 1.0;} + rel2 { relative: 1.0 1.0;} + align: 0.0 1.0; + } + } + part { + name: "elm.rect.button_send"; + scale: 1; + type: RECT; + description { + state: "default" 0.0; + visible: 1; + min: 66 66; + max: 66 66; + fixed: 1 1; + rel1 { relative: 0.0 1.0; } + rel2 { relative: 1.0 1.0; } + align: 0.5 0.0; + color: 0 0 0 0; + } + description { + state: "moveup" 0.0; + min: 66 66; + max: 66 66; + fixed: 1 1; + rel1 { relative: 0.0 0.0; to_y:"bottom_padding";} + rel2 { relative: 1.0 0.0; to_y:"bottom_padding"; } + align: 0.5 1.0; + color: 0 0 0 0; + } + } + part { + name: "elm.button.send"; + scale: 1; + type: SWALLOW; + description { + state: "default" 0.0; + min: 66 66; + max: 66 66; + fixed: 1 1; + rel1 { relative: 0.0 0.0; to:"elm.rect.button_send";} + rel2 { relative: 1.0 1.0; to:"elm.rect.button_send"; } + align: 0.5 0.5; + } + } + + + part{ + name: "top_padding"; + scale: 1; + type: SPACER; + description { + state: "default" 0.0; + min: 360 15; + max: 360 15; + fixed: 1 1; + rel1 { relative: 0.0 0.0;} + rel2 { relative: 1.0 0.0;} + align: 0.0 0.0; + } + } + part{ + name: "elm.txt.indicator"; + scale: 1; + type: TEXTBLOCK; + mouse_events: 1; + repeat_events: 1; + description { + state: "default" 0.0; + visible: 1; + max: 360 360; + fixed: 1 1; + rel1 {relative: 0.2 0.0; } + rel2 {relative: 0.8 1.0; } + align: 0.5 0.5; + text { + style: "indicator_txt_style"; + min: 0 1; + } + } + description { + state: "hide" 0.0; + inherit: "default" 0.0; + visible: 0; + + } + } + part{ + name: "elm.spacer.mms"; + type: SPACER; + description { + state: "default" 0.0; + rel1 {relative: 0.0 1.0; to_y:"top_padding";} + rel2 {relative: 1.0 1.0; to_y:"top_padding";} + align: 0.5 0.0; + } + description{ + state: "hide" 0.0; + rel1 {relative: 0.0 0.0; } + rel1.offset: -120 -120; + rel2 { relative: 1.0 0.0;} + rel2.offset: 120 120; + align: 0.5 0.0; + } + } + + part{ + name: "elm.txt.mms"; + scale: 1; + type: TEXTBLOCK; + description { + state: "default" 0.0; + visible: 1; + rel1 {relative: 0.0 0.0; to_y:"elm.spacer.mms";} + rel2 {relative: 1.0 0.0; to_y:"elm.spacer.mms";} + align: 0.5 0.0; + text { + style: "mms_txt_style"; + min: 0 1; + } + } + description { + state: "hide" 0.0; + inherit: "default" 0.0; + visible: 0; + + } + } + part{ + name: "elm.spacer.index"; + type: SPACER; + description { + state: "default" 0.0; + align: 0.0 0.0; + rel1.relative: 0.0 0.0; + rel2.relative: 1.0 1.0; + } + description{ + state: "hide" 0.0; + rel1 {relative: 0.0 0.0; } + rel1.offset: -120 -120; + rel2 { relative: 1.0 1.0;} + rel2.offset: 120 120; + } + } + part { + name: "elm.swallow.history.index"; + scale: 1; + type: SWALLOW; + description { + state: "default" 0.0; + visible: 1; + align: 0.5 0.5; + rel1 {relative: 0.0 0.0; to_y:"elm.spacer.index";} + rel2 {relative: 1.0 1.0; to_y:"elm.spacer.index";} + } + /* + description { + state: "hide" 0.0; + inherit: "default" 0.0; + visible: 0; + rel1 {relative: 0.0 0.0; to_y:"elm.spacer.index";} + rel2 {relative: 1.0 1.0; to_y:"elm.spacer.index";} + }*/ + } + part { + name: "elm.swallow.tutorial"; + scale: 1; + type: SWALLOW; + description { + state: "default" 0.0; + visible: 1; + //align: 0.5 0.5; + rel1 {relative: 0.0 0.0; to_y:"bg";} + rel2 {relative: 1.0 1.0; to_y:"bg";} + } + description { + state: "hide" 0.0; + inherit: "default" 0.0; + visible: 0; + rel1 {relative: 0.0 0.0; to_y:"bg";} + rel2 {relative: 1.0 1.0; to_y:"bg";} + } + } + + }//parts + programs { + program { + name: "pallet.button.sendmode"; + signal: "elm.state.pallet.button.sendmode"; + source: "*"; + script { + set_state(PART:"elm.button.pallet", "send_default", 0.0); + set_int(send_mode, 1); + } + + } + program { + name: "pallet.button.savemode"; + signal: "elm.state.pallet.button.savemode"; + source: "*"; + script { + set_state(PART:"elm.button.pallet", "default", 0.0); + set_int(send_mode, 0); + } + } + program { + name: "hide.mms"; + signal: "elm.state.hide.mms"; + source: "*"; + action: STATE_SET "hide" 0.0; + target: "elm.txt.mms"; + } + program { + name: "show.mms"; + signal: "elm.state.show.mms"; + source: "*"; + action: STATE_SET "default" 0.0; + target: "elm.txt.mms"; + } + program { + name: "hide.index"; + signal: "elm.state.hide.index"; + source: "*"; + script { + run_program(PROGRAM:"hide_index_animation"); + } + } + program { + name: "hide_index_animation"; + action: STATE_SET "hide" 0.0; + target: "elm.spacer.index"; + target: "elm.spacer.mms"; + transition: CUBIC_BEZIER (0.2) 0.45 0.03 0.41 1.0; + //transition: ACCEL 0.5; + //after: "hide_effect2"; + } + program { name: "hide_effect2"; + script { + set_state(PART:"elm.swallow.history.index", "hide", 0.0); + set_state(PART:"elm.txt.mms", "hide", 0.0); + } + } + program { + name: "show.index.mms"; + signal: "elm.state.show.index.mms"; + source: "*"; + script { + set_state(PART:"elm.spacer.index", "hide", 0.0); + if (get_int(send_mode)) { + set_state(PART:"elm.txt.mms", "default", 0.0); + } + run_program(PROGRAM:"show_index_mms_animation"); + } + } + program { + name: "show_index_mms_animation"; + action: STATE_SET "default" 0.0; + target: "elm.spacer.index"; + target: "elm.spacer.mms"; + transition: CUBIC_BEZIER (0.2) 0.25 0.46 0.45 1.0; + //transition: ACCEL 0.5; + //after: "show_effect2"; + } + program { name: "show_effect2"; + script { + set_state(PART:"elm.spacer.index", "default", 0.0); + set_state(PART:"elm.spacer.mms", "default", 0.0); + } + } + + program { + name: "show.index"; + signal: "elm.state.show.index"; + source: "*"; + script { + set_state(PART:"elm.swallow.history.index", "default", 0.0); + set_state(PART:"elm.txt.mms", "hide", 0.0); + + run_program(PROGRAM:"show_index_animation"); + } + } + program { + name: "show_index_animation"; + action: STATE_SET "default" 0.0; + target: "elm.spacer.index"; + transition: CUBIC_BEZIER (0.2) 0.25 0.46 0.45 1.0; + //transition: ACCEL 0.5; + } + program { + name: "hide.btnpallet"; + signal: "elm.state.hide.btnpallet"; + source: "*"; + action: STATE_SET "hide" 0.0; + target: "elm.button.pallet"; + target: "elm.button.stroke"; + } + program { + name: "show.btnpallet"; + signal: "elm.state.show.btnpallet"; + source: "*"; + script { + set_state(PART:"elm.button.stroke", "default", 0.0); + if (get_int(send_mode)) { + set_state(PART:"elm.button.pallet","send_default", 0.0); + } else { + set_state(PART:"elm.button.pallet","default", 0.0); + } + } + } + program { + name: "hide.indicator"; + signal: "elm.state.hide.indicator"; + source: "*"; + action: STATE_SET "hide" 0.0; + target: "elm.txt.indicator"; + target: "elm.button.pallet"; + target: "elm.button.stroke"; + } + program { + name: "show.indicator"; + signal: "elm.state.show.indicator"; + source: "*"; + script { + set_state(PART:"elm.button.stroke", "default", 0.0); + if (get_int(send_mode)) { + set_state(PART:"elm.button.pallet","send_default", 0.0); + } else { + set_state(PART:"elm.button.pallet","default", 0.0); + } + set_state(PART:"elm.txt.indicator", "default", 0.0); + } + } + program { + name: "hide.pallet.view"; + signal: "hide,pallet,view"; + source: "elm"; + action: STATE_SET "default" 0.0; + target: "circle_menu"; + } + program { + name: "show.pallet.view"; + signal: "show,pallet,view"; + source: "elm"; + action: STATE_SET "show" 0.0; + target: "circle_menu"; + } + program { name: "button.send.moveup"; + signal: "elm,state,button,send.moveup"; + source: "elm"; + script { + set_state(PART:"elm.rect.button_send", "default", 0.0); + run_program(PROGRAM:"moveup_button_send"); + } + } + program { + name: "moveup_button_send"; + action: STATE_SET "moveup" 0.0; + target: "elm.rect.button_send"; + transition: CUBIC_BEZIER (0.2) 0.25 0.46 0.45 1.0; + } + program { + name: "movedown.button.send"; + signal: "movedown,rect,button_send"; + source: "elm"; + action: STATE_SET "default" 0.0; + target: "elm.rect.button_send"; + } + } + } + group { + styles { + style { name: "title_txt_style"; + base: "font=Tizen:style=Regular font_size="30" align=center color=#FFFFFF color_class=AT011 ellipsis=1.0 wrap=mixed text_class=AT011"; + } + style { name: "content_txt_style"; + base: "font=Tizen:style=Regular font_size="30" align=center color=#FFFFFF color_class=AT012 ellipsis=1.0 wrap=mixed text_class=AT012"; + } + } + images { + image: "gear_tutorial_bg.png" COMP; + image: "gear_tutorial_rotate_ccw.png" COMP; + image: "gear_tutorial_rotate_cw.png" COMP; + image: "gear_tutorial_bg_focus.png" COMP; + image: "gear_tutorial_bt_cancel_normal.png" COMP; + image: "gear_tutorial_bt_cancel_press.png" COMP; + } + name: "tutorial_view"; + parts { + part { + name: "bg"; + type: RECT; + scale: 1; + description { + state: "default" 0.0; + min: 360 360; + color: 0 0 0 0; + } + } + part { + name: "bg.image"; + type: IMAGE; + mouse_events: 0; + repeat_events: 1; + description { + state: "default" 0.0; + rel1 { relative: 0.0 0.0;} + rel2 { relative: 1.0 1.0;} + image { + normal: "gear_tutorial_bg.png"; + } + visible: 1; + } + } + part { + name: "top.left.padding"; + type: SPACER; + scale: 1; + description { + state: "default" 0.0; + min: 75 66; + rel1 {relative: 0.0 0.0; to_y:"bg";} + rel2 {relative: 0.0 0.0; to_y:"bg";} + align: 0.0 0.0; + fixed: 1 1; + } + } + part { + name: "top.right.padding"; + type: SPACER; + scale: 1; + description { + state: "default" 0.0; + min: 75 66; + rel1 {relative: 1.0 0.0; to_y:"bg";} + rel2 {relative: 1.0 0.0; to_y:"bg";} + align: 1.0 0.0; + fixed: 1 1; + } + } + part { + name: "clipper"; + type: RECT; + mouse_events: 1; + scale: 1; + description { + state: "default" 0.0; + rel1.relative: 0.0 0.0; + rel2.relative: 1.0 1.0; + fixed: 1 1; + color: 0 0 0 0; + } + description { + state: "show" 0.0; + inherit: "default" 0.0; + color: 255 255 255 255; + } + } + part { + name: "image.ccw"; + type: IMAGE; + //clip_to: "clipper"; + mouse_events: 0; + repeat_events: 1; + scale: 1; + description { + state: "default" 0.0; + min: 180 180; + max: 180 180; + fixed: 1 1; + rel1 { relative: 0.0 0.0;} + rel2 { relative: 0.0 0.0;} + image { + normal: "gear_tutorial_rotate_ccw.png"; + } + visible: 0; + align: 0.0 0.0; + } + description { + state: "show" 0.0; + inherit: "default" 0.0; + visible: 1; + } + } + part { + name: "image.cw"; + type: IMAGE; + //clip_to: "clipper"; + mouse_events: 0; + repeat_events: 1; + scale: 1; + description { + state: "default" 0.0; + min: 180 180; + max: 180 180; + fixed: 1 1; + rel1 { relative: 1.0 0.0;} + rel2 { relative: 1.0 0.0;} + image { + normal: "gear_tutorial_rotate_cw.png"; + } + visible: 0; + align: 1.0 0.0; + } + description { + state: "show" 0.0; + inherit: "default" 0.0; + visible: 1; + } + } + part { + name: "image.bg.focus"; + type: IMAGE; + clip_to: "clipper"; + mouse_events: 0; + repeat_events: 1; + scale: 1; + description { + state: "default" 0.0; + min: 360 360; + max: 360 360; + fixed: 1 1; + rel1 { relative: 0.5 0.5;} + rel2 { relative: 0.5 0.5;} + image { + normal: "gear_tutorial_bg_focus.png"; + } + visible: 0; + align: 0.5 0.5; + } + description { + state: "show" 0.0; + inherit: "default" 0.0; + visible: 1; + } + } + + part { name: "elm.text.title.bg"; + type: SPACER; + scale: 1; + description { state: "default" 0.0; + min: 210 41; + rel1 { + to: "top.left.padding"; + relative: 1.0 1.0; + } + rel2 { + to: "top.right.padding"; + relative: 0.0 1.0; + } + align: 0.5 0.0; + fixed: 0 1; + } + } + part { name: "elm.text.title"; + type: TEXTBLOCK; + scale: 1; + description { state: "default" 0.0; + rel1 { + to: "elm.text.title.bg"; + relative: 0.5 0.5; + } + rel2 { + to: "elm.text.title.bg"; + relative: 0.5 0.5; + } + fixed: 1 1; + max: 210 41; + text { + style: "title_txt_style"; + min: 1 1; + max: 0 1; + ellipsis: -1.0; + fade_ellipsis: 1.0; + } + } + description { state: "title_invisible" 0.0; + inherit: "default" 0.0; + text.min: 0 0; + } + } + part { name: "title.bottom.padding"; + type: SPACER; + scale: 1; + description { state: "default" 0.0; + min: 0 50; + rel1 { + to: "elm.text.title.bg"; + relative: 0.0 1.0; + } + rel2.to: "elm.text.title.bg"; + align: 0.5 0.0; + fixed: 0 1; + } + description { state: "title_invisible" 0.0; + inherit: "default" 0.0; + rel1 { + to: "elm.text.title.bg"; + relative: 0.0 0.0; + } + rel2 { + to: "elm.text.title.bg"; + relative: 1.0 0.0; + } + min: 0 0; + } + } + part { name: "text.left.padding"; + type: SPACER; + scale: 1; + description { state: "default" 0.0; + min: 33 18; + rel1 {relative: 0.0 0.0; to:"bg";} + rel2 {relative: 0.0 0.0; to:"bg";} + align: 0.0 0.0; + fixed: 1 1; + } + } + part { name: "text.right.padding"; + type: SPACER; + scale: 1; + description { state: "default" 0.0; + min: 33 18; + rel1 {relative: 1.0 0.0; to:"bg";} + rel2 {relative: 1.0 0.0; to:"bg";} + align: 1.0 0.0; + fixed: 1 1; + } + } + part { name: "text.bottom.padding"; + type: SPACER; + scale: 1; + description { state: "default" 0.0; + fixed: 1 1; + align: 0.5 1.0; + min: 0 80; + max: -1 80; + rel1.relative: 0.0 1.0; + } + } + part { name: "elm.text"; + type: TEXTBLOCK; + scale: 1; + description { state: "default" 0.0; + rel1 { + to_y: "title.bottom.padding"; + to_x: "text.left.padding"; + relative: 1.0 1.0; + } + rel2 { + to_y: "text.bottom.padding"; + to_x: "text.right.padding"; + relative: 0.0 0.0; + } + text { + style: "content_txt_style"; + align: 0.5 0; + min: 0 1; + } + } + } + part { name: "bottom.padding"; + type: SPACER; + scale: 1; + description { state: "default" 0.0; + fixed: 1 1; + align: 0.5 1.0; + min: 0 15; + max: -1 15; + rel1 {relative: 0.0 1.0; to:"bg";} + rel2 {relative: 1.0 1.0; to:"bg";} + } + } + part { + name: "elm.image.cancel.button"; + type: IMAGE; + scale: 1; + mouse_events: 1; + description { state: "default" 0.0; + fixed: 1 1; + align: 0.5 1.0; + min: 56 56; + max: 56 56; + rel1 {relative: 0.0 0.0; to:"bottom.padding";} + rel2 {relative: 1.0 0.0; to:"bottom.padding";} + image { + normal: "gear_tutorial_bt_cancel_normal.png"; + } + visible: 1; + } + description { + state: "pressed" 0.0; + inherit: "default" 0.0; + image { + normal: "gear_tutorial_bt_cancel_press.png"; + } + visible: 1; + } + description { + state: "hide" 0.0; + inherit: "default" 0.0; + image { + normal: "gear_tutorial_bt_cancel_normal.png"; + } + visible: 0; + } + } + part{ name: "actionbtn1"; + type: SWALLOW; + scale: 1; + mouse_events: 1; + repeat_events: 1; + description { state: "default" 0.0; + align: 0.0 0.0; + rel1 { to: "elm.image.cancel.button";} + rel2 { to: "elm.image.cancel.button";} + } + } + + }//parts + programs { + program { name: "play_sound"; + action: RUN_PLUGIN "touch_sound"; + } + program { + signal: "elm,image,ccw,show"; + source: "*"; + action: STATE_SET "show" 0.0; + target: "image.ccw"; + } + program { + signal: "elm,image,ccw,hide"; + source: "*"; + action: STATE_SET "default" 0.0; + target: "image.ccw"; + } + program { + signal: "elm,image,cw,show"; + source: "*"; + action: STATE_SET "show" 0.0; + target: "image.cw"; + } + program { + signal: "elm,image,cw,hide"; + source: "*"; + action: STATE_SET "default" 0.0; + target: "image.cw"; + } + program { + signal: "elm,image,bg,focus,show"; + source: "*"; + action: STATE_SET "show" 0.0; + target: "image.bg.focus"; + } + program { + signal: "elm,image,bg,focus,hide"; + source: "*"; + action: STATE_SET "default" 0.0; + target: "image.bg.focus"; + } + program { + signal: "mouse,down,1"; + source: "elm.image.cancel.button"; + action: STATE_SET "pressed" 0.0; + target: "elm.image.cancel.button"; + } + program { + signal: "mouse,up,1"; + source: "elm.image.cancel.button"; + action: STATE_SET "default" 0.0; + target: "elm.image.cancel.button"; + } + program { + name:"actionbtn1,sound"; + signal: "mouse,clicked,1"; + source:"actionbtn1"; + script { + run_program(PROGRAM:"play_sound"); + emit("clicked", "actionbtn1"); + } + } + program { + signal: "elm,image,btn,show"; + source: "*"; + action: STATE_SET "default" 0.0; + target: "elm.image.cancel.button"; + } + program { + signal: "elm,image,btn,hide"; + source: "*"; + action: STATE_SET "hide" 0.0; + target: "elm.image.cancel.button"; + } + } + } + #include "drawing_stroke.edc" +} diff --git a/res/edje/btneffect.edc b/res/edje/btneffect.edc new file mode 100755 index 0000000..d5575db --- /dev/null +++ b/res/edje/btneffect.edc @@ -0,0 +1,2321 @@ +collections { + +#define COLOR_A color: 255 255 255 255 +#define COLOR_B color: 255 255 255 50 + +#define IMAGE_NAME "b_ic_press_full_circle_bg_a.png" + +#define ANIM_TIME 1.0 + +#define ZOOM_INIT 0.5 +#define ZOOM_END 1.3 + +#define ZOOM_INIT_INNER 0.5 +#define ZOOM_END_INNER 1.3 + + + group { name: "elm/button/base/myeffect/default"; + images { + image: IMAGE_NAME COMP; + image: IMAGE_INVERSE COMP; + } + script { + public mouse_down = 0; + public mouse_click = 0; + public multi_down = 0; + public click_cnt = 0; + public timer0(val) { + if(val == 1) + run_program(PROGRAM:"change_opacity"); + else if(val == 2) + run_program(PROGRAM:"change_opacity2"); + else if(val == 3) + run_program(PROGRAM:"change_opacity3"); + else + run_program(PROGRAM:"change_opacity4"); + } + } + parts { + part { name: "base"; + type: SPACER; + scale: 1; + description { + state: "default" 0.0; + } + } + + part { name: "bg"; + type: SWALLOW; + scale: 1; + clip_to: "bg_clipper"; + description { state: "default" 0.0; + rel1.to: "base"; + rel2.to: "base"; + } + } + part { name: "bg_clipper"; + scale: 1; + description { state: "default" 0.0; + rel1.to: "bg"; + rel2.to: "bg"; + image.normal: IMAGE_NAME; + color: 255 255 255 255; + } + } + + part { name: "elm.swallow.content"; + type: SWALLOW; + clip_to: "elm.swallow.content.clip"; + scale: 1; + description { state: "default" 0.0; + rel1.to: "base"; + rel2.to: "base"; + } + } + + part { name: "elm.swallow.content.clip"; + scale: 1; + description { state: "default" 0.0; + image.normal: IMAGE_NAME; + color: 255 255 255 255; + rel1.to: "elm.swallow.content"; + rel2.to: "elm.swallow.content"; + } + description { state: "pressed" 0.0; + inherit: "default" 0.0; + } + description { state: "disabled" 0.0; + inherit: "default" 0.0; + color: 0 0 0 0; + } + } + + // clip_to is not working if clipper uses map + part { name: "effect_bg"; + scale: 1; + clip_to: "effect_bg_clip"; + description { state: "default" 0.0; + rel1.to: "base"; + rel2.to: "base"; + image.normal: IMAGE_NAME; + COLOR_A; + map.on: 1; + } + description { state: "pressed" 0.0; + inherit: "default" 0.0; + COLOR_A; + map { + zoom.x: ZOOM_INIT; + zoom.y: ZOOM_INIT; + } + } + description { state: "disabled" 0.0; + inherit: "default" 0.0; + } + description { state: "start_persp" 0.0; + inherit: "default" 0.0; + COLOR_B; + map { + zoom.x: ZOOM_END; + zoom.y: ZOOM_END; + } + } + } + + part { name: "effect_bg_clip"; + scale: 1; + type: RECT; + description { state: "default" 0.0; + rel1.to: "base"; + rel1.relative: -0.35 -0.35; + rel2.to: "base"; + rel2.relative: 1.35 1.35; + color: 255 255 255 0; + } + description { state: "pressed" 0.0; + inherit: "default" 0.0; + color: 255 255 255 255; + } + description { state: "disabled" 0.0; + inherit: "default" 0.0; + } + } + part { name: "effect_bg2"; + scale: 1; + clip_to: "effect_bg_clip2"; + description { state: "default" 0.0; + rel1.to: "base"; + rel2.to: "base"; + image.normal: IMAGE_NAME; + color_class: "transparent"; + map.on: 1; + } + description { state: "pressed" 0.0; + inherit: "default" 0.0; + COLOR_A; + map { + zoom.x: ZOOM_INIT; + zoom.y: ZOOM_INIT; + } + } + description { state: "disabled" 0.0; + inherit: "default" 0.0; + } + description { state: "start_persp" 0.0; + inherit: "default" 0.0; + COLOR_B; + map { + zoom.x: ZOOM_END; + zoom.y: ZOOM_END; + } + } + } + part { name: "effect_bg_clip2"; + scale: 1; + type: RECT; + description { state: "default" 0.0; + rel1.to: "base"; + rel1.relative: -0.35 -0.35; + rel2.to: "base"; + rel2.relative: 1.35 1.35; + color: 255 255 255 0; + } + description { state: "pressed" 0.0; + inherit: "default" 0.0; + color: 255 255 255 255; + } + description { state: "disabled" 0.0; + inherit: "default" 0.0; + } + } + part { name: "effect_bg3"; + scale: 1; + clip_to: "effect_bg_clip3"; + description { state: "default" 0.0; + rel1.to: "base"; + rel2.to: "base"; + image.normal: IMAGE_NAME; + color_class: "transparent"; + map.on: 1; + } + description { state: "pressed" 0.0; + inherit: "default" 0.0; + COLOR_A; + map { + zoom.x: ZOOM_INIT; + zoom.y: ZOOM_INIT; + } + } + description { state: "disabled" 0.0; + inherit: "default" 0.0; + } + description { state: "start_persp" 0.0; + inherit: "default" 0.0; + COLOR_B; + map { + zoom.x: ZOOM_END; + zoom.y: ZOOM_END; + } + } + } + part { name: "effect_bg_clip3"; + scale: 1; + type: RECT; + description { state: "default" 0.0; + rel1.to: "base"; + rel1.relative: -0.35 -0.35; + rel2.to: "base"; + rel2.relative: 1.35 1.35; + color: 255 255 255 0; + } + description { state: "pressed" 0.0; + inherit: "default" 0.0; + color: 255 255 255 255; + } + description { state: "disabled" 0.0; + inherit: "default" 0.0; + } + } + part { name: "effect_bg4"; + scale: 1; + clip_to: "effect_bg_clip4"; + description { state: "default" 0.0; + rel1.to: "base"; + rel2.to: "base"; + image.normal: IMAGE_NAME; + color_class: "transparent"; + map.on: 1; + } + description { state: "pressed" 0.0; + inherit: "default" 0.0; + COLOR_A; + map { + zoom.x: ZOOM_INIT; + zoom.y: ZOOM_INIT; + } + } + description { state: "disabled" 0.0; + inherit: "default" 0.0; + } + description { state: "start_persp" 0.0; + inherit: "default" 0.0; + COLOR_B; + map { + zoom.x: ZOOM_END; + zoom.y: ZOOM_END; + } + } + } + part { name: "effect_bg_clip4"; + scale: 1; + type: RECT; + description { state: "default" 0.0; + rel1.to: "base"; + rel1.relative: -0.35 -0.35; + rel2.to: "base"; + rel2.relative: 1.35 1.35; + color: 255 255 255 0; + } + description { state: "pressed" 0.0; + inherit: "default" 0.0; + color: 255 255 255 255; + } + description { state: "disabled" 0.0; + inherit: "default" 0.0; + } + } + + part { name: "event"; + type: RECT; + scale: 1; + description { state: "default" 0.0; + color: 0 0 0 0; + rel1.to: "base"; + rel2.to: "base"; + } + } + } + programs { + program { name: "pressed"; + signal: "effect,mouse,down,1*"; + source: "event"; + script { + if ((get_int(multi_down) == 0) && (get_int(mouse_down) == 0)) + { + set_int(mouse_down, 1); + run_program(PROGRAM:"button_press1"); + } + } + } + + program { name: "button_press1"; + script { + new st[31]; + new Float:vl; + get_state(PART:"effect_bg", st, 30, vl); + if (strcmp(st, "disabled")) { + set_state(PART:"elm.swallow.content.clip", "pressed", 0.0); + emit("elm,action,press", ""); + if(get_int(click_cnt) == 0) { + set_state(PART:"effect_bg", "pressed", 0.0); + set_state(PART:"effect_bg_clip", "pressed", 0.0); + + run_program(PROGRAM:"start_persp"); + timer(0.1, "timer0", 1); + } + else if(get_int(click_cnt) == 1) { + set_state(PART:"effect_bg2", "pressed", 0.0); + set_state(PART:"effect_bg_clip2", "pressed", 0.0); + run_program(PROGRAM:"start_persp2"); + timer(0.1, "timer0", 2); + } + else if(get_int(click_cnt) == 2) { + set_state(PART:"effect_bg3", "pressed", 0.0); + set_state(PART:"effect_bg_clip3", "pressed", 0.0); + run_program(PROGRAM:"start_persp3"); + timer(0.1, "timer0", 3); + } + else { + set_state(PART:"effect_bg4", "pressed", 0.0); + set_state(PART:"effect_bg_clip4", "pressed", 0.0); + run_program(PROGRAM:"start_persp4"); + timer(0.1, "timer0", 4); + } + } + } + } + program { name: "unpressed"; + signal: "mouse,up,1"; + source: "event"; + script { + if (get_int(mouse_down) == 1) { + set_int(mouse_down, 0); + run_program(PROGRAM:"button_unpress1"); + } + } + } + program { name: "button_unpress1"; + script { + new st[31]; + new Float:vl; + get_state(PART:"effect_bg", st, 30, vl); + if (strcmp(st, "disabled")) { + set_state(PART:"elm.swallow.content.clip", "default", 0.0); + emit("elm,action,unpress", ""); + if(get_int(click_cnt) == 0) + set_int(click_cnt, 1); + else if(get_int(click_cnt) == 1) + set_int(click_cnt, 2); + else if(get_int(click_cnt) == 2) + set_int(click_cnt, 3); + else + set_int(click_cnt, 0); + } + } + } + + program { name: "play_example"; + signal: "play,once"; + source: "event"; + script { + set_int(click_cnt, 0); + run_program(PROGRAM:"button_press1"); + } + } + + + program { name: "touch_snd"; + signal: "mouse,clicked,1"; + source: "event"; + script { + new st[31]; + new Float:vl; + if (get_int(multi_down) == 0) { + get_state(PART:"effect_bg", st, 30, vl); + if (strcmp(st, "disabled")) { + run_program(PROGRAM:"play_sample"); + emit("elm,action,click", ""); + set_int(mouse_click, 0); + } + } + } + } + program { + name: "play_sample"; + action: RUN_PLUGIN "touch_sound"; + } + program { name: "disable"; + signal: "elm,state,disabled"; + source: "elm"; + action: STATE_SET "disabled" 0.0; + target: "effect_bg"; + target: "elm.swallow.content.clip"; + } + program { name: "enable"; + signal: "elm,state,enabled"; + source: "elm"; + action: STATE_SET "default" 0.0; + target: "effect_bg"; + target: "elm.swallow.content.clip"; + } + program { name: "multi_down"; + signal: "elm,action,multi,down"; + source: "elm"; + script { + set_int(multi_down, 1); + } + } + program { name: "multi_up"; + signal: "elm,action,multi,up"; + source: "elm"; + script { + set_int(multi_down, 0); + } + } + program { name: "start_persp"; + action: STATE_SET "start_persp" 0.0; + transition: CUBIC_BEZIER ANIM_TIME 0.45 0.03 0.41 1.0; + target: "effect_bg"; + } + program { name: "change_opacity"; + action: STATE_SET "default" 0.0; + transition: CUBIC_BEZIER ANIM_TIME 0.39 0.575 0.565 1.0; + target: "effect_bg_clip"; + } + program { name: "start_persp2"; + action: STATE_SET "start_persp" 0.0; + transition: CUBIC_BEZIER ANIM_TIME 0.45 0.03 0.41 1.0; + target: "effect_bg2"; + } + program { name: "change_opacity2"; + action: STATE_SET "default" 0.0; + transition: CUBIC_BEZIER ANIM_TIME 0.39 0.575 0.565 1.0; + target: "effect_bg_clip2"; + } + program { name: "start_persp3"; + action: STATE_SET "start_persp" 0.0; + transition: CUBIC_BEZIER ANIM_TIME 0.45 0.03 0.41 1.0; + target: "effect_bg3"; + } + program { name: "change_opacity3"; + action: STATE_SET "default" 0.0; + transition: CUBIC_BEZIER ANIM_TIME 0.39 0.575 0.565 1.0; + target: "effect_bg_clip3"; + } + program { name: "start_persp4"; + action: STATE_SET "start_persp" 0.0; + transition: CUBIC_BEZIER ANIM_TIME 0.45 0.03 0.41 1.0; + target: "effect_bg4"; + } + program { name: "change_opacity4"; + action: STATE_SET "default" 0.0; + transition: CUBIC_BEZIER ANIM_TIME 0.39 0.575 0.565 1.0; + target: "effect_bg_clip4"; + } + } + } + + group { name: "elm/button/base/drawing/effect/left"; + images { + image: "b_ic_press_full_circle_bg.png" COMP; + } + script { + public mouse_down = 0; + public mouse_click = 0; + public multi_down = 0; + public click_cnt = 0; + public timer0(val) { + if(val == 1) + run_program(PROGRAM:"change_opacity"); + else if(val == 2) + run_program(PROGRAM:"change_opacity2"); + else if(val == 3) + run_program(PROGRAM:"change_opacity3"); + else + run_program(PROGRAM:"change_opacity4"); + } + } + parts { + part { name: "base"; + type: SPACER; + scale: 1; + description { state: "default" 0.0; + } + } + part { name: "bg"; + type: SWALLOW; + scale: 1; + clip_to: "bg_clipper"; + description { state: "default" 0.0; + rel1.to: "base"; + rel2.to: "base"; + } + } + part { name: "bg_clipper"; + scale: 1; + description { state: "default" 0.0; + rel1.to: "bg"; + rel2.to: "bg"; + image.normal: "b_ic_press_full_circle_bg.png"; + color: 255 255 255 255; + } + } + part { name: "elm.swallow.content"; + type: SWALLOW; + clip_to: "elm.swallow.content.clip"; + scale: 1; + mouse_events:0; + description { state: "default" 0.0; + rel1 {relative: 0.5 0.0; to_x:"base";} + rel2 {relative: 0.5 1.0; to_x:"base";} + //rel1.to: "base"; + //rel2.to: "base"; + align: 0.0 0.5; + min: 36 36 ; + max: 36 36; + fixed: 1 1; + } + } + /* + part { name: "elm.swallow.content.clip"; + scale: 1; + description { state: "default" 0.0; + image.normal: "b_ic_press_full_circle_bg.png"; + color: 255 255 255 255; + rel1.to: "elm.swallow.content"; + rel2.to: "elm.swallow.content"; + } + description { state: "pressed" 0.0; + inherit: "default" 0.0; + } + description { state: "disabled" 0.0; + inherit: "default" 0.0; + color: 0 0 0 0; + } + } + */ + part { name: "elm.swallow.content.clip"; + type: RECT; + scale: 1; + description { state: "default" 0.0; + color_class: "AO0272"; + } + description { state: "pressed" 0.0; + inherit: "default" 0.0; + color_class: "AO0272P"; + } + description { state: "disabled" 0.0; + inherit: "default" 0.0; + color_class: "AO0272D"; + } + } + part { name: "effect_bg"; + scale: 1; + clip_to: "effect_bg_clip"; + description { state: "default" 0.0; + rel1.to: "base"; + rel2.to: "base"; + image.normal: "b_ic_press_full_circle_bg.png"; + color_class: "B02111"; + map.on: 1; + } + description { state: "pressed" 0.0; + inherit: "default" 0.0; + color_class: "B02111"; + map { + zoom.x: 1.0; + zoom.y: 1.0; + } + } + description { state: "disabled" 0.0; + inherit: "default" 0.0; + } + description { state: "start_persp" 0.0; + inherit: "default" 0.0; + color_class: "B02121"; + map { + zoom.x: 1.2; + zoom.y: 1.2; + } + } + } + part { name: "effect_bg_clip"; + scale: 1; + type: RECT; + description { state: "default" 0.0; + rel1.to: "base"; + rel1.relative: -0.35 -0.35; + // rel1.relative: -0.0 -0.0; + rel2.to: "base"; + rel2.relative: 2.35 2.35; + color: 255 255 255 0; + } + description { state: "pressed" 0.0; + inherit: "default" 0.0; + color: 255 255 255 255; + } + description { state: "disabled" 0.0; + inherit: "default" 0.0; + } + } + part { name: "effect_bg2"; + scale: 1; + clip_to: "effect_bg_clip2"; + description { state: "default" 0.0; + rel1.to: "base"; + rel2.to: "base"; + // rel2.relative: 2 2; + image.normal: "b_ic_press_full_circle_bg.png"; + color_class: "transparent"; + map.on: 1; + } + description { state: "pressed" 0.0; + inherit: "default" 0.0; + color_class: "B02111"; + map { + zoom.x: 1.0; + zoom.y: 1.0; + } + } + description { state: "disabled" 0.0; + inherit: "default" 0.0; + } + description { state: "start_persp" 0.0; + inherit: "default" 0.0; + color_class: "B02121"; + map { + zoom.x: 1.2; + zoom.y: 1.2; + } + } + } + part { name: "effect_bg_clip2"; + scale: 1; + type: RECT; + description { state: "default" 0.0; + rel1.to: "base"; + rel1.relative: -0.35 -0.35; + //rel1.relative: -0.0 -0.0; + rel2.to: "base"; + rel2.relative: 2.35 2.35; + color: 255 255 255 0; + } + description { state: "pressed" 0.0; + inherit: "default" 0.0; + color: 255 255 255 255; + } + description { state: "disabled" 0.0; + inherit: "default" 0.0; + } + } + part { name: "effect_bg3"; + scale: 1; + clip_to: "effect_bg_clip3"; + description { state: "default" 0.0; + rel1.to: "base"; + rel2.to: "base"; + image.normal: "b_ic_press_full_circle_bg.png"; + color_class: "transparent"; + map.on: 1; + } + description { state: "pressed" 0.0; + inherit: "default" 0.0; + color_class: "B02111"; + map { + zoom.x: 1.0; + zoom.y: 1.0; + } + } + description { state: "disabled" 0.0; + inherit: "default" 0.0; + } + description { state: "start_persp" 0.0; + inherit: "default" 0.0; + color_class: "B02121"; + map { + zoom.x: 1.2; + zoom.y: 1.2; + } + } + } + part { name: "effect_bg_clip3"; + scale: 1; + type: RECT; + description { state: "default" 0.0; + rel1.to: "base"; + rel1.relative: -0.35 -0.35; + // rel1.relative: -0.0 -0.0; + rel2.to: "base"; + rel2.relative: 2.35 2.35; + color: 255 255 255 0; + } + description { state: "pressed" 0.0; + inherit: "default" 0.0; + color: 255 255 255 255; + } + description { state: "disabled" 0.0; + inherit: "default" 0.0; + } + } + part { name: "effect_bg4"; + scale: 1; + clip_to: "effect_bg_clip4"; + description { state: "default" 0.0; + rel1.to: "base"; + rel2.to: "base"; + image.normal: "b_ic_press_full_circle_bg.png"; + color_class: "transparent"; + map.on: 1; + } + description { state: "pressed" 0.0; + inherit: "default" 0.0; + color_class: "B02111"; + map { + zoom.x: 1.0; + zoom.y: 1.0; + } + } + description { state: "disabled" 0.0; + inherit: "default" 0.0; + } + description { state: "start_persp" 0.0; + inherit: "default" 0.0; + color_class: "B02121"; + map { + zoom.x: 1.2; + zoom.y: 1.2; + } + } + } + part { name: "effect_bg_clip4"; + scale: 1; + type: RECT; + description { state: "default" 0.0; + rel1.to: "base"; + rel1.relative: -0.35 -0.35; + // rel1.relative: -0.0 -0.0; + rel2.to: "base"; + rel2.relative: 2.35 2.35; + color: 255 255 255 0; + } + description { state: "pressed" 0.0; + inherit: "default" 0.0; + color: 255 255 255 255; + } + description { state: "disabled" 0.0; + inherit: "default" 0.0; + } + } + + part { name: "event"; + type: RECT; + scale: 1; + description { state: "default" 0.0; + color: 255 255 0 0; + rel1 { relative: 0.0 0.0; to: "base"; offset: -25 -32;} + rel2 { relative: 1.0 1.0; to: "base"; offset: 25 72;} + } + } + } + programs { + program { name: "pressed"; + signal: "mouse,down,1*"; + source: "event"; + script { + if ((get_int(multi_down) == 0) && (get_int(mouse_down) == 0)) + { + set_int(mouse_down, 1); + run_program(PROGRAM:"button_press1"); + } + } + } + program { name: "button_press1"; + script { + new st[31]; + new Float:vl; + get_state(PART:"effect_bg", st, 30, vl); + if (strcmp(st, "disabled")) { + set_state(PART:"elm.swallow.content.clip", "pressed", 0.0); + emit("elm,action,press", ""); + if(get_int(click_cnt) == 0) { + set_state(PART:"effect_bg", "pressed", 0.0); + set_state(PART:"effect_bg_clip", "pressed", 0.0); + run_program(PROGRAM:"start_persp"); + timer(0.2, "timer0", 1); + } + else if(get_int(click_cnt) == 1) { + set_state(PART:"effect_bg2", "pressed", 0.0); + set_state(PART:"effect_bg_clip2", "pressed", 0.0); + run_program(PROGRAM:"start_persp2"); + timer(0.1, "timer0", 2); + } + else if(get_int(click_cnt) == 2) { + set_state(PART:"effect_bg3", "pressed", 0.0); + set_state(PART:"effect_bg_clip3", "pressed", 0.0); + run_program(PROGRAM:"start_persp3"); + timer(0.1, "timer0", 3); + } + else { + set_state(PART:"effect_bg4", "pressed", 0.0); + set_state(PART:"effect_bg_clip4", "pressed", 0.0); + run_program(PROGRAM:"start_persp4"); + timer(0.1, "timer0", 4); + } + } + } + } + program { name: "unpressed"; + signal: "mouse,up,1"; + source: "event"; + script { + if (get_int(mouse_down) == 1) { + set_int(mouse_down, 0); + run_program(PROGRAM:"button_unpress1"); + } + } + } + program { name: "button_unpress1"; + script { + new st[31]; + new Float:vl; + get_state(PART:"effect_bg", st, 30, vl); + if (strcmp(st, "disabled")) { + set_state(PART:"elm.swallow.content.clip", "default", 0.0); + emit("elm,action,unpress", ""); + if(get_int(click_cnt) == 0) + set_int(click_cnt, 1); + else if(get_int(click_cnt) == 1) + set_int(click_cnt, 2); + else if(get_int(click_cnt) == 2) + set_int(click_cnt, 3); + else + set_int(click_cnt, 0); + } + } + } + program { name: "touch_snd"; + signal: "mouse,clicked,1"; + source: "event"; + script { + new st[31]; + new Float:vl; + if (get_int(multi_down) == 0) { + get_state(PART:"effect_bg", st, 30, vl); + if (strcmp(st, "disabled")) { + run_program(PROGRAM:"play_sample"); + emit("elm,action,click", ""); + set_int(mouse_click, 0); + } + } + } + } + program { + name: "play_sample"; + action: RUN_PLUGIN "touch_sound"; + } + program { name: "disable"; + signal: "elm,state,disabled"; + source: "elm"; + action: STATE_SET "disabled" 0.0; + target: "effect_bg"; + target: "elm.swallow.content.clip"; + } + program { name: "enable"; + signal: "elm,state,enabled"; + source: "elm"; + action: STATE_SET "default" 0.0; + target: "effect_bg"; + target: "elm.swallow.content.clip"; + } + program { name: "multi_down"; + signal: "elm,action,multi,down"; + source: "elm"; + script { + set_int(multi_down, 1); + } + } + program { name: "multi_up"; + signal: "elm,action,multi,up"; + source: "elm"; + script { + set_int(multi_down, 0); + } + } + program { name: "start_persp"; + action: STATE_SET "start_persp" 0.0; + transition: CUBIC_BEZIER 0.3 0.45 0.03 0.41 1.0; + target: "effect_bg"; + } + program { name: "change_opacity"; + action: STATE_SET "default" 0.0; + transition: CUBIC_BEZIER 0.3 0.39 0.575 0.565 1.0; + target: "effect_bg_clip"; + } + program { name: "start_persp2"; + action: STATE_SET "start_persp" 0.0; + transition: CUBIC_BEZIER 0.3 0.45 0.03 0.41 1.0; + target: "effect_bg2"; + } + program { name: "change_opacity2"; + action: STATE_SET "default" 0.0; + transition: CUBIC_BEZIER 0.3 0.39 0.575 0.565 1.0; + target: "effect_bg_clip2"; + } + program { name: "start_persp3"; + action: STATE_SET "start_persp" 0.0; + transition: CUBIC_BEZIER 0.3 0.45 0.03 0.41 1.0; + target: "effect_bg3"; + } + program { name: "change_opacity3"; + action: STATE_SET "default" 0.0; + transition: CUBIC_BEZIER 0.3 0.39 0.575 0.565 1.0; + target: "effect_bg_clip3"; + } + program { name: "start_persp4"; + action: STATE_SET "start_persp" 0.0; + transition: CUBIC_BEZIER 0.3 0.45 0.03 0.41 1.0; + target: "effect_bg4"; + } + program { name: "change_opacity4"; + action: STATE_SET "default" 0.0; + transition: CUBIC_BEZIER 0.3 0.39 0.575 0.565 1.0; + target: "effect_bg_clip4"; + } + } + } + group { name: "elm/button/base/pallet/savemode_effect"; + images { + image: "b_ic_press_full_circle_bg.png" COMP; + } + script { + public mouse_down = 0; + public mouse_click = 0; + public multi_down = 0; + public click_cnt = 0; + public timer0(val) { + if(val == 1) + run_program(PROGRAM:"change_opacity"); + else if(val == 2) + run_program(PROGRAM:"change_opacity2"); + else if(val == 3) + run_program(PROGRAM:"change_opacity3"); + else + run_program(PROGRAM:"change_opacity4"); + } + } + parts { + part { name: "base"; + type: SPACER; + scale: 1; + description { state: "default" 0.0; + } + } + part { name: "bg"; + type: SWALLOW; + scale: 1; + clip_to: "bg_clipper"; + description { state: "default" 0.0; + rel1.to: "base"; + rel2.to: "base"; + } + } + part { name: "bg_clipper"; + scale: 1; + description { state: "default" 0.0; + rel1.to: "bg"; + rel2.to: "bg"; + image.normal: "b_ic_press_full_circle_bg.png"; + color: 255 255 255 255; + } + } + part { name: "elm.swallow.content"; + type: SWALLOW; + clip_to: "elm.swallow.content.clip"; + scale: 1; + mouse_events:0; + description { state: "default" 0.0; + rel1 {relative: 0.0 0.0; to_x:"base";} + rel2 {relative: 1.0 1.0; to_x:"base";} + //rel1.to: "base"; + //rel2.to: "base"; + align: 0.5 0.5; + min: 43 43 ; + max: 43 43; + fixed: 1 1; + } + } + /* + part { name: "elm.swallow.content.clip"; + scale: 1; + description { state: "default" 0.0; + image.normal: "b_ic_press_full_circle_bg.png"; + color: 255 255 255 255; + rel1.to: "elm.swallow.content"; + rel2.to: "elm.swallow.content"; + } + description { state: "pressed" 0.0; + inherit: "default" 0.0; + } + description { state: "disabled" 0.0; + inherit: "default" 0.0; + color: 0 0 0 0; + } + } + */ + part { name: "elm.swallow.content.clip"; + type: RECT; + scale: 1; + description { state: "default" 0.0; + color_class: "AO0272"; + } + description { state: "pressed" 0.0; + inherit: "default" 0.0; + color_class: "AO0272P"; + } + description { state: "disabled" 0.0; + inherit: "default" 0.0; + color_class: "AO0272D"; + } + } + part { name: "effect_bg"; + scale: 1; + clip_to: "effect_bg_clip"; + description { state: "default" 0.0; + rel1.to: "base"; + rel2.to: "base"; + image.normal: "b_ic_press_full_circle_bg.png"; + color_class: "B02111"; + map.on: 1; + } + description { state: "pressed" 0.0; + inherit: "default" 0.0; + color_class: "B02111"; + map { + zoom.x: 1.0; + zoom.y: 1.0; + } + } + description { state: "disabled" 0.0; + inherit: "default" 0.0; + } + description { state: "start_persp" 0.0; + inherit: "default" 0.0; + color_class: "B02121"; + map { + zoom.x: 1.2; + zoom.y: 1.2; + } + } + } + part { name: "effect_bg_clip"; + scale: 1; + type: RECT; + description { state: "default" 0.0; + rel1.to: "base"; + rel1.relative: -0.35 -0.35; + // rel1.relative: -0.0 -0.0; + rel2.to: "base"; + rel2.relative: 2.35 2.35; + color: 255 255 255 0; + } + description { state: "pressed" 0.0; + inherit: "default" 0.0; + color: 255 255 255 255; + } + description { state: "disabled" 0.0; + inherit: "default" 0.0; + } + } + part { name: "effect_bg2"; + scale: 1; + clip_to: "effect_bg_clip2"; + description { state: "default" 0.0; + rel1.to: "base"; + rel2.to: "base"; + // rel2.relative: 2 2; + image.normal: "b_ic_press_full_circle_bg.png"; + color_class: "transparent"; + map.on: 1; + } + description { state: "pressed" 0.0; + inherit: "default" 0.0; + color_class: "B02111"; + map { + zoom.x: 1.0; + zoom.y: 1.0; + } + } + description { state: "disabled" 0.0; + inherit: "default" 0.0; + } + description { state: "start_persp" 0.0; + inherit: "default" 0.0; + color_class: "B02121"; + map { + zoom.x: 1.2; + zoom.y: 1.2; + } + } + } + part { name: "effect_bg_clip2"; + scale: 1; + type: RECT; + description { state: "default" 0.0; + rel1.to: "base"; + rel1.relative: -0.35 -0.35; + //rel1.relative: -0.0 -0.0; + rel2.to: "base"; + rel2.relative: 2.35 2.35; + color: 255 255 255 0; + } + description { state: "pressed" 0.0; + inherit: "default" 0.0; + color: 255 255 255 255; + } + description { state: "disabled" 0.0; + inherit: "default" 0.0; + } + } + part { name: "effect_bg3"; + scale: 1; + clip_to: "effect_bg_clip3"; + description { state: "default" 0.0; + rel1.to: "base"; + rel2.to: "base"; + image.normal: "b_ic_press_full_circle_bg.png"; + color_class: "transparent"; + map.on: 1; + } + description { state: "pressed" 0.0; + inherit: "default" 0.0; + color_class: "B02111"; + map { + zoom.x: 1.0; + zoom.y: 1.0; + } + } + description { state: "disabled" 0.0; + inherit: "default" 0.0; + } + description { state: "start_persp" 0.0; + inherit: "default" 0.0; + color_class: "B02121"; + map { + zoom.x: 1.2; + zoom.y: 1.2; + } + } + } + part { name: "effect_bg_clip3"; + scale: 1; + type: RECT; + description { state: "default" 0.0; + rel1.to: "base"; + rel1.relative: -0.35 -0.35; + // rel1.relative: -0.0 -0.0; + rel2.to: "base"; + rel2.relative: 2.35 2.35; + color: 255 255 255 0; + } + description { state: "pressed" 0.0; + inherit: "default" 0.0; + color: 255 255 255 255; + } + description { state: "disabled" 0.0; + inherit: "default" 0.0; + } + } + part { name: "effect_bg4"; + scale: 1; + clip_to: "effect_bg_clip4"; + description { state: "default" 0.0; + rel1.to: "base"; + rel2.to: "base"; + image.normal: "b_ic_press_full_circle_bg.png"; + color_class: "transparent"; + map.on: 1; + } + description { state: "pressed" 0.0; + inherit: "default" 0.0; + color_class: "B02111"; + map { + zoom.x: 1.0; + zoom.y: 1.0; + } + } + description { state: "disabled" 0.0; + inherit: "default" 0.0; + } + description { state: "start_persp" 0.0; + inherit: "default" 0.0; + color_class: "B02121"; + map { + zoom.x: 1.2; + zoom.y: 1.2; + } + } + } + part { name: "effect_bg_clip4"; + scale: 1; + type: RECT; + description { state: "default" 0.0; + rel1.to: "base"; + rel1.relative: -0.35 -0.35; + // rel1.relative: -0.0 -0.0; + rel2.to: "base"; + rel2.relative: 2.35 2.35; + color: 255 255 255 0; + } + description { state: "pressed" 0.0; + inherit: "default" 0.0; + color: 255 255 255 255; + } + description { state: "disabled" 0.0; + inherit: "default" 0.0; + } + } + + part { name: "event"; + type: RECT; + scale: 1; + description { state: "default" 0.0; + color: 255 255 0 0; + rel1 { relative: 0.0 0.0; to: "base"; offset: -25 -32;} + rel2 { relative: 1.0 1.0; to: "base"; offset: 25 72;} + } + } + } + programs { + program { name: "pressed"; + signal: "mouse,down,1*"; + source: "event"; + script { + if ((get_int(multi_down) == 0) && (get_int(mouse_down) == 0)) + { + set_int(mouse_down, 1); + run_program(PROGRAM:"button_press1"); + } + } + } + program { name: "button_press1"; + script { + new st[31]; + new Float:vl; + get_state(PART:"effect_bg", st, 30, vl); + if (strcmp(st, "disabled")) { + set_state(PART:"elm.swallow.content.clip", "pressed", 0.0); + emit("elm,action,press", ""); + if(get_int(click_cnt) == 0) { + set_state(PART:"effect_bg", "pressed", 0.0); + set_state(PART:"effect_bg_clip", "pressed", 0.0); + run_program(PROGRAM:"start_persp"); + timer(0.2, "timer0", 1); + } + else if(get_int(click_cnt) == 1) { + set_state(PART:"effect_bg2", "pressed", 0.0); + set_state(PART:"effect_bg_clip2", "pressed", 0.0); + run_program(PROGRAM:"start_persp2"); + timer(0.1, "timer0", 2); + } + else if(get_int(click_cnt) == 2) { + set_state(PART:"effect_bg3", "pressed", 0.0); + set_state(PART:"effect_bg_clip3", "pressed", 0.0); + run_program(PROGRAM:"start_persp3"); + timer(0.1, "timer0", 3); + } + else { + set_state(PART:"effect_bg4", "pressed", 0.0); + set_state(PART:"effect_bg_clip4", "pressed", 0.0); + run_program(PROGRAM:"start_persp4"); + timer(0.1, "timer0", 4); + } + } + } + } + program { name: "unpressed"; + signal: "mouse,up,1"; + source: "event"; + script { + if (get_int(mouse_down) == 1) { + set_int(mouse_down, 0); + run_program(PROGRAM:"button_unpress1"); + } + } + } + program { name: "button_unpress1"; + script { + new st[31]; + new Float:vl; + get_state(PART:"effect_bg", st, 30, vl); + if (strcmp(st, "disabled")) { + set_state(PART:"elm.swallow.content.clip", "default", 0.0); + emit("elm,action,unpress", ""); + if(get_int(click_cnt) == 0) + set_int(click_cnt, 1); + else if(get_int(click_cnt) == 1) + set_int(click_cnt, 2); + else if(get_int(click_cnt) == 2) + set_int(click_cnt, 3); + else + set_int(click_cnt, 0); + } + } + } + program { name: "touch_snd"; + signal: "mouse,clicked,1"; + source: "event"; + script { + new st[31]; + new Float:vl; + if (get_int(multi_down) == 0) { + get_state(PART:"effect_bg", st, 30, vl); + if (strcmp(st, "disabled")) { + run_program(PROGRAM:"play_sample"); + emit("elm,action,click", ""); + set_int(mouse_click, 0); + } + } + } + } + program { + name: "play_sample"; + action: RUN_PLUGIN "touch_sound"; + } + program { name: "disable"; + signal: "elm,state,disabled"; + source: "elm"; + action: STATE_SET "disabled" 0.0; + target: "effect_bg"; + target: "elm.swallow.content.clip"; + } + program { name: "enable"; + signal: "elm,state,enabled"; + source: "elm"; + action: STATE_SET "default" 0.0; + target: "effect_bg"; + target: "elm.swallow.content.clip"; + } + program { name: "multi_down"; + signal: "elm,action,multi,down"; + source: "elm"; + script { + set_int(multi_down, 1); + } + } + program { name: "multi_up"; + signal: "elm,action,multi,up"; + source: "elm"; + script { + set_int(multi_down, 0); + } + } + program { name: "start_persp"; + action: STATE_SET "start_persp" 0.0; + transition: CUBIC_BEZIER 0.3 0.45 0.03 0.41 1.0; + target: "effect_bg"; + } + program { name: "change_opacity"; + action: STATE_SET "default" 0.0; + transition: CUBIC_BEZIER 0.3 0.39 0.575 0.565 1.0; + target: "effect_bg_clip"; + } + program { name: "start_persp2"; + action: STATE_SET "start_persp" 0.0; + transition: CUBIC_BEZIER 0.3 0.45 0.03 0.41 1.0; + target: "effect_bg2"; + } + program { name: "change_opacity2"; + action: STATE_SET "default" 0.0; + transition: CUBIC_BEZIER 0.3 0.39 0.575 0.565 1.0; + target: "effect_bg_clip2"; + } + program { name: "start_persp3"; + action: STATE_SET "start_persp" 0.0; + transition: CUBIC_BEZIER 0.3 0.45 0.03 0.41 1.0; + target: "effect_bg3"; + } + program { name: "change_opacity3"; + action: STATE_SET "default" 0.0; + transition: CUBIC_BEZIER 0.3 0.39 0.575 0.565 1.0; + target: "effect_bg_clip3"; + } + program { name: "start_persp4"; + action: STATE_SET "start_persp" 0.0; + transition: CUBIC_BEZIER 0.3 0.45 0.03 0.41 1.0; + target: "effect_bg4"; + } + program { name: "change_opacity4"; + action: STATE_SET "default" 0.0; + transition: CUBIC_BEZIER 0.3 0.39 0.575 0.565 1.0; + target: "effect_bg_clip4"; + } + } + } + group { name: "elm/button/base/drawing/stroke_effect/default"; + images { + image: "b_ic_press_full_circle_bg.png" COMP; + } + script { + public mouse_down = 0; + public mouse_click = 0; + public multi_down = 0; + public click_cnt = 0; + public timer0(val) { + if(val == 1) + run_program(PROGRAM:"change_opacity"); + else if(val == 2) + run_program(PROGRAM:"change_opacity2"); + else if(val == 3) + run_program(PROGRAM:"change_opacity3"); + else + run_program(PROGRAM:"change_opacity4"); + } + } + parts { + part { name: "base"; + type: SPACER; + scale: 1; + description { state: "default" 0.0; + } + } + part { name: "bg"; + type: SWALLOW; + scale: 1; + clip_to: "bg_clipper"; + description { state: "default" 0.0; + rel1.to: "base"; + rel2.to: "base"; + } + } + part { name: "bg_clipper"; + scale: 1; + description { state: "default" 0.0; + rel1.to: "bg"; + rel2.to: "bg"; + image.normal: "b_ic_press_full_circle_bg.png"; + color: 255 255 255 255; + } + } + part { name: "elm.swallow.content"; + type: SWALLOW; + clip_to: "elm.swallow.content.clip"; + scale: 1; + description { state: "default" 0.0; + rel1.to: "base"; + rel2.to: "base"; + } + } + part { name: "elm.swallow.content.clip"; + scale: 1; + description { state: "default" 0.0; + image.normal: "b_ic_press_full_circle_bg.png"; + color: 255 255 255 255; + rel1.to: "elm.swallow.content"; + rel2.to: "elm.swallow.content"; + } + description { state: "pressed" 0.0; + inherit: "default" 0.0; + } + description { state: "disabled" 0.0; + inherit: "default" 0.0; + color: 255 255 255 100; + } + } + part { name: "effect_bg"; + scale: 1; + clip_to: "effect_bg_clip"; + description { state: "default" 0.0; + rel1.to: "base"; + rel2.to: "base"; + image.normal: "b_ic_press_full_circle_bg.png"; + color_class: "B02111"; + map.on: 1; + } + description { state: "pressed" 0.0; + inherit: "default" 0.0; + color_class: "B02111"; + map { + zoom.x: 1.4; + zoom.y: 1.4; + } + } + description { state: "disabled" 0.0; + inherit: "default" 0.0; + } + description { state: "start_persp" 0.0; + inherit: "default" 0.0; + color_class: "B02121"; + //color_class: "B02111"; + map { + zoom.x: 1.7; + zoom.y: 1.7; + } + } + } + part { name: "effect_bg_clip"; + scale: 1; + type: RECT; + description { state: "default" 0.0; + rel1.to: "base"; + rel1.relative: -0.35 -0.35; + rel2.to: "base"; + rel2.relative: 1.35 1.35; + color: 255 255 255 0; + } + description { state: "pressed" 0.0; + inherit: "default" 0.0; + color: 255 255 255 255; + } + description { state: "disabled" 0.0; + inherit: "default" 0.0; + } + } + part { name: "effect_bg2"; + scale: 1; + clip_to: "effect_bg_clip2"; + description { state: "default" 0.0; + rel1.to: "base"; + rel2.to: "base"; + image.normal: "b_ic_press_full_circle_bg.png"; + color_class: "transparent"; + map.on: 1; + } + description { state: "pressed" 0.0; + inherit: "default" 0.0; + color_class: "B02111"; + map { + zoom.x: 1.4; + zoom.y: 1.4; + } + } + description { state: "disabled" 0.0; + inherit: "default" 0.0; + } + description { state: "start_persp" 0.0; + inherit: "default" 0.0; + color_class: "B02121"; + map { + zoom.x: 1.7; + zoom.y: 1.7; + } + } + } + part { name: "effect_bg_clip2"; + scale: 1; + type: RECT; + description { state: "default" 0.0; + rel1.to: "base"; + rel1.relative: -0.35 -0.35; + rel2.to: "base"; + rel2.relative: 1.35 1.35; + color: 255 255 255 0; + } + description { state: "pressed" 0.0; + inherit: "default" 0.0; + color: 255 255 255 255; + } + description { state: "disabled" 0.0; + inherit: "default" 0.0; + } + } + part { name: "effect_bg3"; + scale: 1; + clip_to: "effect_bg_clip3"; + description { state: "default" 0.0; + rel1.to: "base"; + rel2.to: "base"; + image.normal: "b_ic_press_full_circle_bg.png"; + color_class: "transparent"; + map.on: 1; + } + description { state: "pressed" 0.0; + inherit: "default" 0.0; + color_class: "B02111"; + map { + zoom.x: 1.4; + zoom.y: 1.4; + } + } + description { state: "disabled" 0.0; + inherit: "default" 0.0; + } + description { state: "start_persp" 0.0; + inherit: "default" 0.0; + color_class: "B02121"; + map { + zoom.x: 1.7; + zoom.y: 1.7; + } + } + } + part { name: "effect_bg_clip3"; + scale: 1; + type: RECT; + description { state: "default" 0.0; + rel1.to: "base"; + rel1.relative: -0.35 -0.35; + rel2.to: "base"; + rel2.relative: 1.35 1.35; + color: 255 255 255 0; + } + description { state: "pressed" 0.0; + inherit: "default" 0.0; + color: 255 255 255 255; + } + description { state: "disabled" 0.0; + inherit: "default" 0.0; + } + } + part { name: "effect_bg4"; + scale: 1; + clip_to: "effect_bg_clip4"; + description { state: "default" 0.0; + rel1.to: "base"; + rel2.to: "base"; + image.normal: "b_ic_press_full_circle_bg.png"; + color_class: "transparent"; + map.on: 1; + } + description { state: "pressed" 0.0; + inherit: "default" 0.0; + color_class: "B02111"; + map { + zoom.x: 1.4; + zoom.y: 1.4; + } + } + description { state: "disabled" 0.0; + inherit: "default" 0.0; + } + description { state: "start_persp" 0.0; + inherit: "default" 0.0; + color_class: "B02121"; + map { + zoom.x: 1.7; + zoom.y: 1.7; + } + } + } + part { name: "effect_bg_clip4"; + scale: 1; + type: RECT; + description { state: "default" 0.0; + rel1.to: "base"; + rel1.relative: -0.35 -0.35; + rel2.to: "base"; + rel2.relative: 1.35 1.35; + color: 255 255 255 0; + } + description { state: "pressed" 0.0; + inherit: "default" 0.0; + color: 255 255 255 255; + } + description { state: "disabled" 0.0; + inherit: "default" 0.0; + } + } + part { name: "event"; + type: RECT; + scale: 1; + description { state: "default" 0.0; + color: 0 0 0 0; + rel1.to: "base"; + rel2.to: "base"; + } + } + } + programs { + program { name: "pressed"; + signal: "mouse,down,1*"; + source: "event"; + script { + if ((get_int(multi_down) == 0) && (get_int(mouse_down) == 0)) + { + set_int(mouse_down, 1); + run_program(PROGRAM:"button_press1"); + } + } + } + program { name: "button_press1"; + script { + new st[31]; + new Float:vl; + get_state(PART:"effect_bg", st, 30, vl); + if (strcmp(st, "disabled")) { + set_state(PART:"elm.swallow.content.clip", "pressed", 0.0); + emit("elm,action,press", ""); + if(get_int(click_cnt) == 0) { + set_state(PART:"effect_bg", "pressed", 0.0); + set_state(PART:"effect_bg_clip", "pressed", 0.0); + run_program(PROGRAM:"start_persp"); + timer(0.1, "timer0", 1); + } + else if(get_int(click_cnt) == 1) { + set_state(PART:"effect_bg2", "pressed", 0.0); + set_state(PART:"effect_bg_clip2", "pressed", 0.0); + run_program(PROGRAM:"start_persp2"); + timer(0.1, "timer0", 2); + } + else if(get_int(click_cnt) == 2) { + set_state(PART:"effect_bg3", "pressed", 0.0); + set_state(PART:"effect_bg_clip3", "pressed", 0.0); + run_program(PROGRAM:"start_persp3"); + timer(0.1, "timer0", 3); + } + else { + set_state(PART:"effect_bg4", "pressed", 0.0); + set_state(PART:"effect_bg_clip4", "pressed", 0.0); + run_program(PROGRAM:"start_persp4"); + timer(0.1, "timer0", 4); + } + } + } + } + program { name: "unpressed"; + signal: "mouse,up,1"; + source: "event"; + script { + if (get_int(mouse_down) == 1) { + set_int(mouse_down, 0); + run_program(PROGRAM:"button_unpress1"); + } + } + } + program { name: "button_unpress1"; + script { + new st[31]; + new Float:vl; + get_state(PART:"effect_bg", st, 30, vl); + if (strcmp(st, "disabled")) { + set_state(PART:"elm.swallow.content.clip", "default", 0.0); + emit("elm,action,unpress", ""); + if(get_int(click_cnt) == 0) + set_int(click_cnt, 1); + else if(get_int(click_cnt) == 1) + set_int(click_cnt, 2); + else if(get_int(click_cnt) == 2) + set_int(click_cnt, 3); + else + set_int(click_cnt, 0); + } + } + } + program { name: "touch_snd"; + signal: "mouse,clicked,1"; + source: "event"; + script { + new st[31]; + new Float:vl; + if (get_int(multi_down) == 0) { + get_state(PART:"effect_bg", st, 30, vl); + if (strcmp(st, "disabled")) { + run_program(PROGRAM:"play_sample"); + emit("elm,action,click", ""); + set_int(mouse_click, 0); + } + } + } + } + program { + name: "play_sample"; + action: RUN_PLUGIN "touch_sound"; + } + program { name: "disable"; + signal: "elm,state,disabled"; + source: "elm"; + action: STATE_SET "disabled" 0.0; + target: "effect_bg"; + target: "elm.swallow.content.clip"; + } + program { name: "enable"; + signal: "elm,state,enabled"; + source: "elm"; + action: STATE_SET "default" 0.0; + target: "effect_bg"; + target: "elm.swallow.content.clip"; + } + program { name: "multi_down"; + signal: "elm,action,multi,down"; + source: "elm"; + script { + set_int(multi_down, 1); + } + } + program { name: "multi_up"; + signal: "elm,action,multi,up"; + source: "elm"; + script { + set_int(multi_down, 0); + } + } + program { name: "start_persp"; + action: STATE_SET "start_persp" 0.0; + transition: CUBIC_BEZIER 0.3 0.45 0.03 0.41 1.0; + target: "effect_bg"; + } + program { name: "change_opacity"; + action: STATE_SET "default" 0.0; + transition: CUBIC_BEZIER 0.3 0.39 0.575 0.565 1.0; + target: "effect_bg_clip"; + } + program { name: "start_persp2"; + action: STATE_SET "start_persp" 0.0; + transition: CUBIC_BEZIER 0.3 0.45 0.03 0.41 1.0; + target: "effect_bg2"; + } + program { name: "change_opacity2"; + action: STATE_SET "default" 0.0; + transition: CUBIC_BEZIER 0.3 0.39 0.575 0.565 1.0; + target: "effect_bg_clip2"; + } + program { name: "start_persp3"; + action: STATE_SET "start_persp" 0.0; + transition: CUBIC_BEZIER 0.3 0.45 0.03 0.41 1.0; + target: "effect_bg3"; + } + program { name: "change_opacity3"; + action: STATE_SET "default" 0.0; + transition: CUBIC_BEZIER 0.3 0.39 0.575 0.565 1.0; + target: "effect_bg_clip3"; + } + program { name: "start_persp4"; + action: STATE_SET "start_persp" 0.0; + transition: CUBIC_BEZIER 0.3 0.45 0.03 0.41 1.0; + target: "effect_bg4"; + } + program { name: "change_opacity4"; + action: STATE_SET "default" 0.0; + transition: CUBIC_BEZIER 0.3 0.39 0.575 0.565 1.0; + target: "effect_bg_clip4"; + } + } + } + group { name: "elm/button/base/pallet/sendmode_effect"; + images { + image: "b_ic_press_full_circle_bg.png" COMP; + } + script { + public mouse_down = 0; + public mouse_click = 0; + public multi_down = 0; + public click_cnt = 0; + public timer0(val) { + if(val == 1) + run_program(PROGRAM:"change_opacity"); + else if(val == 2) + run_program(PROGRAM:"change_opacity2"); + else if(val == 3) + run_program(PROGRAM:"change_opacity3"); + else + run_program(PROGRAM:"change_opacity4"); + } + } + parts { + part { name: "base"; + type: SPACER; + scale: 1; + description { state: "default" 0.0; + } + } + part { name: "bg"; + type: SWALLOW; + scale: 1; + clip_to: "bg_clipper"; + description { state: "default" 0.0; + rel1.to: "base"; + rel2.to: "base"; + } + } + part { name: "bg_clipper"; + scale: 1; + description { state: "default" 0.0; + rel1.to: "bg"; + rel2.to: "bg"; + image.normal: "b_ic_press_full_circle_bg.png"; + color: 255 255 255 255; + } + } + part { name: "elm.swallow.content"; + type: SWALLOW; + clip_to: "elm.swallow.content.clip"; + scale: 1; + mouse_events:0; + description { state: "default" 0.0; + rel1 {relative: 0.5 0.0; to_x:"base";} + rel2 {relative: 0.5 1.0; to_x:"base";} + //rel1.to: "base"; + //rel2.to: "base"; + align: 1.0 0.5; + min: 36 36 ; + max: 36 36; + fixed: 1 1; + } + } + /* + part { name: "elm.swallow.content.clip"; + scale: 1; + description { state: "default" 0.0; + image.normal: "b_ic_press_full_circle_bg.png"; + color: 255 255 255 255; + rel1.to: "elm.swallow.content"; + rel2.to: "elm.swallow.content"; + } + description { state: "pressed" 0.0; + inherit: "default" 0.0; + } + description { state: "disabled" 0.0; + inherit: "default" 0.0; + color: 0 0 0 0; + } + } + */ + part { name: "elm.swallow.content.clip"; + type: RECT; + scale: 1; + description { state: "default" 0.0; + color_class: "AO0272"; + } + description { state: "pressed" 0.0; + inherit: "default" 0.0; + color_class: "AO0272P"; + } + description { state: "disabled" 0.0; + inherit: "default" 0.0; + color_class: "AO0272D"; + } + } + part { name: "effect_bg"; + scale: 1; + clip_to: "effect_bg_clip"; + description { state: "default" 0.0; + rel1.to: "base"; + rel2.to: "base"; + image.normal: "b_ic_press_full_circle_bg.png"; + color_class: "B02111"; + map.on: 1; + } + description { state: "pressed" 0.0; + inherit: "default" 0.0; + color_class: "B02111"; + map { + zoom.x: 1.0; + zoom.y: 1.0; + } + } + description { state: "disabled" 0.0; + inherit: "default" 0.0; + } + description { state: "start_persp" 0.0; + inherit: "default" 0.0; + color_class: "B02121"; + map { + zoom.x: 1.2; + zoom.y: 1.2; + } + } + } + part { name: "effect_bg_clip"; + scale: 1; + type: RECT; + description { state: "default" 0.0; + rel1.to: "base"; + rel1.relative: -0.35 -0.35; + // rel1.relative: -0.0 -0.0; + rel2.to: "base"; + rel2.relative: 2.35 2.35; + color: 255 255 255 0; + } + description { state: "pressed" 0.0; + inherit: "default" 0.0; + color: 255 255 255 255; + } + description { state: "disabled" 0.0; + inherit: "default" 0.0; + } + } + part { name: "effect_bg2"; + scale: 1; + clip_to: "effect_bg_clip2"; + description { state: "default" 0.0; + rel1.to: "base"; + rel2.to: "base"; + // rel2.relative: 2 2; + image.normal: "b_ic_press_full_circle_bg.png"; + color_class: "transparent"; + map.on: 1; + } + description { state: "pressed" 0.0; + inherit: "default" 0.0; + color_class: "B02111"; + map { + zoom.x: 1.0; + zoom.y: 1.0; + } + } + description { state: "disabled" 0.0; + inherit: "default" 0.0; + } + description { state: "start_persp" 0.0; + inherit: "default" 0.0; + color_class: "B02121"; + map { + zoom.x: 1.2; + zoom.y: 1.2; + } + } + } + part { name: "effect_bg_clip2"; + scale: 1; + type: RECT; + description { state: "default" 0.0; + rel1.to: "base"; + rel1.relative: -0.35 -0.35; + //rel1.relative: -0.0 -0.0; + rel2.to: "base"; + rel2.relative: 2.35 2.35; + color: 255 255 255 0; + } + description { state: "pressed" 0.0; + inherit: "default" 0.0; + color: 255 255 255 255; + } + description { state: "disabled" 0.0; + inherit: "default" 0.0; + } + } + part { name: "effect_bg3"; + scale: 1; + clip_to: "effect_bg_clip3"; + description { state: "default" 0.0; + rel1.to: "base"; + rel2.to: "base"; + image.normal: "b_ic_press_full_circle_bg.png"; + color_class: "transparent"; + map.on: 1; + } + description { state: "pressed" 0.0; + inherit: "default" 0.0; + color_class: "B02111"; + map { + zoom.x: 1.0; + zoom.y: 1.0; + } + } + description { state: "disabled" 0.0; + inherit: "default" 0.0; + } + description { state: "start_persp" 0.0; + inherit: "default" 0.0; + color_class: "B02121"; + map { + zoom.x: 1.2; + zoom.y: 1.2; + } + } + } + part { name: "effect_bg_clip3"; + scale: 1; + type: RECT; + description { state: "default" 0.0; + rel1.to: "base"; + rel1.relative: -0.35 -0.35; + // rel1.relative: -0.0 -0.0; + rel2.to: "base"; + rel2.relative: 2.35 2.35; + color: 255 255 255 0; + } + description { state: "pressed" 0.0; + inherit: "default" 0.0; + color: 255 255 255 255; + } + description { state: "disabled" 0.0; + inherit: "default" 0.0; + } + } + part { name: "effect_bg4"; + scale: 1; + clip_to: "effect_bg_clip4"; + description { state: "default" 0.0; + rel1.to: "base"; + rel2.to: "base"; + image.normal: "b_ic_press_full_circle_bg.png"; + color_class: "transparent"; + map.on: 1; + } + description { state: "pressed" 0.0; + inherit: "default" 0.0; + color_class: "B02111"; + map { + zoom.x: 1.0; + zoom.y: 1.0; + } + } + description { state: "disabled" 0.0; + inherit: "default" 0.0; + } + description { state: "start_persp" 0.0; + inherit: "default" 0.0; + color_class: "B02121"; + map { + zoom.x: 1.2; + zoom.y: 1.2; + } + } + } + part { name: "effect_bg_clip4"; + scale: 1; + type: RECT; + description { state: "default" 0.0; + rel1.to: "base"; + rel1.relative: -0.35 -0.35; + // rel1.relative: -0.0 -0.0; + rel2.to: "base"; + rel2.relative: 2.35 2.35; + color: 255 255 255 0; + } + description { state: "pressed" 0.0; + inherit: "default" 0.0; + color: 255 255 255 255; + } + description { state: "disabled" 0.0; + inherit: "default" 0.0; + } + } + + part { name: "event"; + type: RECT; + scale: 1; + description { state: "default" 0.0; + color: 255 255 0 0; + rel1 { relative: 0.0 0.0; to: "base"; offset: -25 -32;} + rel2 { relative: 1.0 1.0; to: "base"; offset: 25 72;} + } + } + } + programs { + program { name: "pressed"; + signal: "mouse,down,1*"; + source: "event"; + script { + if ((get_int(multi_down) == 0) && (get_int(mouse_down) == 0)) + { + set_int(mouse_down, 1); + run_program(PROGRAM:"button_press1"); + } + } + } + program { name: "button_press1"; + script { + new st[31]; + new Float:vl; + get_state(PART:"effect_bg", st, 30, vl); + if (strcmp(st, "disabled")) { + set_state(PART:"elm.swallow.content.clip", "pressed", 0.0); + emit("elm,action,press", ""); + if(get_int(click_cnt) == 0) { + set_state(PART:"effect_bg", "pressed", 0.0); + set_state(PART:"effect_bg_clip", "pressed", 0.0); + run_program(PROGRAM:"start_persp"); + timer(0.2, "timer0", 1); + } + else if(get_int(click_cnt) == 1) { + set_state(PART:"effect_bg2", "pressed", 0.0); + set_state(PART:"effect_bg_clip2", "pressed", 0.0); + run_program(PROGRAM:"start_persp2"); + timer(0.1, "timer0", 2); + } + else if(get_int(click_cnt) == 2) { + set_state(PART:"effect_bg3", "pressed", 0.0); + set_state(PART:"effect_bg_clip3", "pressed", 0.0); + run_program(PROGRAM:"start_persp3"); + timer(0.1, "timer0", 3); + } + else { + set_state(PART:"effect_bg4", "pressed", 0.0); + set_state(PART:"effect_bg_clip4", "pressed", 0.0); + run_program(PROGRAM:"start_persp4"); + timer(0.1, "timer0", 4); + } + } + } + } + program { name: "unpressed"; + signal: "mouse,up,1"; + source: "event"; + script { + if (get_int(mouse_down) == 1) { + set_int(mouse_down, 0); + run_program(PROGRAM:"button_unpress1"); + } + } + } + program { name: "button_unpress1"; + script { + new st[31]; + new Float:vl; + get_state(PART:"effect_bg", st, 30, vl); + if (strcmp(st, "disabled")) { + set_state(PART:"elm.swallow.content.clip", "default", 0.0); + emit("elm,action,unpress", ""); + if(get_int(click_cnt) == 0) + set_int(click_cnt, 1); + else if(get_int(click_cnt) == 1) + set_int(click_cnt, 2); + else if(get_int(click_cnt) == 2) + set_int(click_cnt, 3); + else + set_int(click_cnt, 0); + } + } + } + program { name: "touch_snd"; + signal: "mouse,clicked,1"; + source: "event"; + script { + new st[31]; + new Float:vl; + if (get_int(multi_down) == 0) { + get_state(PART:"effect_bg", st, 30, vl); + if (strcmp(st, "disabled")) { + run_program(PROGRAM:"play_sample"); + emit("elm,action,click", ""); + set_int(mouse_click, 0); + } + } + } + } + program { + name: "play_sample"; + action: RUN_PLUGIN "touch_sound"; + } + program { name: "disable"; + signal: "elm,state,disabled"; + source: "elm"; + action: STATE_SET "disabled" 0.0; + target: "effect_bg"; + target: "elm.swallow.content.clip"; + } + program { name: "enable"; + signal: "elm,state,enabled"; + source: "elm"; + action: STATE_SET "default" 0.0; + target: "effect_bg"; + target: "elm.swallow.content.clip"; + } + program { name: "multi_down"; + signal: "elm,action,multi,down"; + source: "elm"; + script { + set_int(multi_down, 1); + } + } + program { name: "multi_up"; + signal: "elm,action,multi,up"; + source: "elm"; + script { + set_int(multi_down, 0); + } + } + program { name: "start_persp"; + action: STATE_SET "start_persp" 0.0; + transition: CUBIC_BEZIER 0.3 0.45 0.03 0.41 1.0; + target: "effect_bg"; + } + program { name: "change_opacity"; + action: STATE_SET "default" 0.0; + transition: CUBIC_BEZIER 0.3 0.39 0.575 0.565 1.0; + target: "effect_bg_clip"; + } + program { name: "start_persp2"; + action: STATE_SET "start_persp" 0.0; + transition: CUBIC_BEZIER 0.3 0.45 0.03 0.41 1.0; + target: "effect_bg2"; + } + program { name: "change_opacity2"; + action: STATE_SET "default" 0.0; + transition: CUBIC_BEZIER 0.3 0.39 0.575 0.565 1.0; + target: "effect_bg_clip2"; + } + program { name: "start_persp3"; + action: STATE_SET "start_persp" 0.0; + transition: CUBIC_BEZIER 0.3 0.45 0.03 0.41 1.0; + target: "effect_bg3"; + } + program { name: "change_opacity3"; + action: STATE_SET "default" 0.0; + transition: CUBIC_BEZIER 0.3 0.39 0.575 0.565 1.0; + target: "effect_bg_clip3"; + } + program { name: "start_persp4"; + action: STATE_SET "start_persp" 0.0; + transition: CUBIC_BEZIER 0.3 0.45 0.03 0.41 1.0; + target: "effect_bg4"; + } + program { name: "change_opacity4"; + action: STATE_SET "default" 0.0; + transition: CUBIC_BEZIER 0.3 0.39 0.575 0.565 1.0; + target: "effect_bg_clip4"; + } + } + } +} diff --git a/res/edje/drawing_layout.edc b/res/edje/drawing_layout.edc new file mode 100755 index 0000000..19a0064 --- /dev/null +++ b/res/edje/drawing_layout.edc @@ -0,0 +1,216 @@ + +collections { + +#define MSG_VALUE 1 +#define GC_NAME_PADDING_X 33 +#define GC_NAME_PADDING_Y 55 +#define GC_NAME_PADDING_H 47 +base_scale: 1.3; + /* Face view */ + + group { + name: "drawing_group"; + max: 360 360; + min: 360 360; + images { + image: "wi_drawing_bg_pattern_negative.png" COMP; + image: "wi_more_option_bg.png" COMP; + image: "wi_drawing_bg_pattern.png" COMP; + } + parts{ + part { + name: "bg"; + scale: 1; + type: RECT; + mouse_events: 1; + description { + state: "default" 0.0; + color_class: "AO0117"; + } + } + part{ + name: "top_padding"; + scale: 1; + type: SPACER; + mouse_events: 1; + repeat_events: 1; + description { + state: "default" 0.0; + rel1 {relative: 0.0 0.0;} + rel2 {relative: 1.0 0.0;} + min: 0 5; + align: 0.5 0.0; + fixed: 0 1; + } + } + part{ + name: "right_padding"; + scale: 1; + type: SPACER; + mouse_events: 1; + repeat_events: 1; + description { + state: "default" 0.0; + rel1 {relative: 1.0 0.0;} + rel2 {relative: 1.0 0.0;} + min: 2 0; + align: 1.0 0.5; + fixed: 1 0; + } + } + part{ + name: "bottom_padding"; + scale: 1; + type: SPACER; + mouse_events: 1; + repeat_events: 1; + description { + state: "default" 0.0; + rel1 {relative: 0.0 1.0;} + rel2 {relative: 1.0 1.0;} + min: 0 5; + align: 0.5 1.0; + fixed: 0 1; + } + } + + part{ + name: "elm.swallow.bottom.bgimage"; + type: SWALLOW; + mouse_events: 1; + repeat_events: 1; + description{ + state: "default" 0.0; + rel1 { relative:0.0 0.0; to:"bg"; } + rel2 { relative:1.0 1.0; to:"bg"; } + } + } + part { + name: "bg_pattern_image"; + scale: 1; + mouse_events: 1; + repeat_events: 1; + type: IMAGE; + description { + state: "default" 0.0; + image.normal: "wi_drawing_bg_pattern.png"; + color_class: "AO051"; + } + description { + state: "hide" 0.0; + image.normal: "wi_more_option_bg.png"; + color: 0 0 0 0; + } + } + part{ + name: "drawing_area"; + type: SWALLOW; + mouse_events: 1; + repeat_events: 1; + description{ + state: "default" 0.0; + rel1 { relative:0.0 0.0; to:"bg"; } + rel2 { relative:1.0 1.0; to:"bg"; } + } + } + part { + name: "bg_pattern_negative_image"; + scale: 1; + mouse_events: 1; + repeat_events: 1; + type: IMAGE; + description { + state: "default" 0.0; + image.normal: "wi_drawing_bg_pattern_negative.png"; + //color_class: "AO048"; + } + description { + state: "hide" 0.0; + image.normal: "wi_more_option_bg.png"; + color: 0 0 0 0; + } + } + part{ + name: "part_stage"; + type: SPACER; + mouse_events: 1; + repeat_events: 1; + description { + state: "default" 0.0; + rel1 {relative: 0.0 0.0; } + rel1.offset: -125 -125; + rel2 { relative: 1.0 1.0;} + rel2.offset: 125 125; + } + description{ + state: "shown" 0.0; + rel1.relative: 0.0 0.0; + rel1.offset: 0 0; + rel2.relative: 1.0 1.0; + rel2.offset: 0 0; + } + } + + part { name: "button"; + type: SWALLOW; + scale: 1; + mouse_events: 1; + repeat_events: 1; + description { + state: "default" 0.0; + min: 90 90; + max: 90 90; + fixed: 1 1; + align: 0.5 0.5; + rel1.to: "bg"; + rel1.relative: 0.0 0.0; + rel2.to: "bg"; + rel2.relative: 1.0 1.0; + } + } + } + + programs{ + program { + name: "stage-default"; + action: STATE_SET "default" 0.0; + target: "part_stage"; + } + program { + name: "hidden-state"; + signal: "stage,hide"; + source: ""; + action: STATE_SET "default" 0.0; + transition: ACCEL 0.5; + target: "part_stage"; + + } + program { + name: "shown-state"; + signal: "stage,show"; + source: ""; + action: STATE_SET "shown" 0.0; + transition: ACCEL 0.5; + target: "part_stage"; + + } + program { + name: "show.pattern.negative.bg"; + signal: "pattern,negative,bg,show"; + source: "*"; + action: STATE_SET "default" 0.0; + target: "bg_pattern_negative_image"; + } + program { + name: "hide.pattern.negative.bg"; + signal: "pattern,negative,bg,hide"; + source: "*"; + action: STATE_SET "hide" 0.0; + target: "bg_pattern_negative_image"; + } + } //programs + } +} + + + diff --git a/res/edje/drawing_popup.edc b/res/edje/drawing_popup.edc new file mode 100755 index 0000000..74774b1 --- /dev/null +++ b/res/edje/drawing_popup.edc @@ -0,0 +1,153 @@ + +#define BG_COLOR 0 0 0 255 + +#define POPUP_2BUTTON_LEFT_RIGHT_PADDING_WIDTH_INC 68 +#define POPUP_TOP_PADDING_HEIGHT_INC 60 +#define POPUP_TOP_PADDING_NOTITLE_HEIGHT_INC 76 +#define POPUP_BOTTOM_PADDING_HEIGHT_INC 100 +#define POPUP_IMAGE_WIDTH_INC 224 +#define POPUP_IMAGE_HEIGHT_INC 100 +#define POPUP_IMAGE_BOTTOM_PADDING_HEIGHT_INC 5 +#define POPUP_CONNECTING_IMAGE_BOTTOM_PADDING_HEIGHT_INC 32 +#define POPUP_TITLE_BOTTOM_PADDING_HEIGHT_INC 8 +#define POPUP_BASE_DEFAULT_MIN_INC 360 360 +#define POPUP_TITLE_TEXT_SIZE_INC 30 +#define POPUP_BODY_TEXT_SIZE_INC 34 + +#define POPUP_NO_BUTTON_LEFT_RIGHT_PADDING_WIDTH_INC 33 +#define POPUP_NO_BUTTON_BOTTOM_PADDING_HEIGHT_INC 95 +#define POPUP_NO_BUTTON_IMG_BOTTOM_PADDING_HEIGHT_INC 169 + +collections { +base_scale: 1.3; + +#define PART(TYPE, NAME, DESCRIPION) \ + part { \ + name: NAME; \ + scale: 1; \ + type: TYPE; \ + DESCRIPION \ + } + + +#define NOBUTTON_BUTTONS2_PROGRAM(program_name, signal_name) \ + program { \ + name: program_name; \ + signal: signal_name; \ + source: ""; \ + script { \ + set_state(PART:"top.left.padding", "default", 0.0); \ + emit("size,eval", "elm"); \ + } \ + } \ + + group { + name: "close_popup"; + styles{ + style { + name: "popup_title_style"; + base: "font=Tizen:style=Bold font_size="POPUP_TITLE_TEXT_SIZE_INC" color=#FFFFFF color_class=T091 align=center ellipsis=1.0 text_class=T091"; + } + style { + name: "popup_body_default_font_style"; + base: "font=Tizen:style=Regular font_size="POPUP_BODY_TEXT_SIZE_INC" color=#FFFFFF color_class=T092 align=center wrap=mixed text_class=T092"; + } + } + + limits { + vertical: "content_area" "360"; + } + parts { + part { + name: "bg"; + type: SPACER; + scale: 1; + description { + state: "default" 0.0; + min: POPUP_BASE_DEFAULT_MIN_INC; + } + } + part { + name: "top.left.padding"; + type: SPACER; + scale: 1; + description { + state: "default" 0.0; + min: POPUP_2BUTTON_LEFT_RIGHT_PADDING_WIDTH_INC POPUP_TOP_PADDING_NOTITLE_HEIGHT_INC; + rel1.to: "bg"; + rel2 { + to: "bg"; + relative: 0.0 0.0; + } + align: 0.0 0.0; + fixed: 1 1; + } + } + + part { + name: "bottom.right.content.padding"; + type: SPACER; + scale: 1; + description { + state: "default" 0.0; + min: POPUP_2BUTTON_LEFT_RIGHT_PADDING_WIDTH_INC POPUP_TOP_PADDING_NOTITLE_HEIGHT_INC; + rel1 { + to: "bg"; + relative: 1.0 1.0; + } + rel2.to: "bg"; + align: 1.0 1.0; + fixed: 1 1; + } + description { + state: "center_align" 0.0; + inherit: "default" 0.0; + min: POPUP_2BUTTON_LEFT_RIGHT_PADDING_WIDTH_INC POPUP_TOP_PADDING_NOTITLE_HEIGHT_INC; + } + } + + part { + name: "bottom.right.padding"; + type: SPACER; + scale: 1; + description { + state: "default" 0.0; + min: POPUP_2BUTTON_LEFT_RIGHT_PADDING_WIDTH_INC POPUP_TOP_PADDING_NOTITLE_HEIGHT_INC; + rel1 { + to: "bg"; + relative: 1.0 1.0; + } + rel2.to: "bg"; + align: 1.0 1.0; + fixed: 1 1; + } + } + + part { name: "discard.text.content"; + type: TEXTBLOCK; + scale: 1; + description { + state: "default" 0.0; + rel1 { + to: "top.left.padding"; + relative: 1.0 1.0; + } + rel2 { + to: "bottom.right.padding"; + relative: 0.0 0.0; + } + text { + align: 0.5 0.5; + style: "popup_body_default_font_style"; + min: 0 1; + } + } + } + } + programs { + NOBUTTON_BUTTONS2_PROGRAM("show", "show"); + NOBUTTON_BUTTONS2_PROGRAM("content_area,over", "limit,content_area,over"); + NOBUTTON_BUTTONS2_PROGRAM("content_area,below", "limit,content_area,below"); + } + } +} diff --git a/res/edje/drawing_stroke.edc b/res/edje/drawing_stroke.edc new file mode 100755 index 0000000..a6456ec --- /dev/null +++ b/res/edje/drawing_stroke.edc @@ -0,0 +1,205 @@ + +/* Circle display */ +group { name: "drawing/stroke_layout/circle"; + styles{ + style { name: "circle_title_style"; + base: "font=Tizen:style=Light font_size="28" align=center color=""#FFFFFF"" color_class=ATO032 text_class=ATO032"; + tag: "br" "\n"; + tag: "hilight" "+ font_weight=Bold"; + tag: "b" "+ font_weight=Bold"; + tag: "tab" "\t"; + } + style { name: "circle_level_style2"; + base: "font=Tizen:style=Regular font_size="40" align=center color=""#FFFFFF"" color_class=ATO032 text_class=ATO032"; + tag: "br" "\n"; + tag: "hilight" "+ font_weight=Bold"; + tag: "b" "+ font_weight=Bold"; + tag: "tab" "\t"; + } + style { name: "circle_level_dim_style"; + base: "font=Tizen:style=Regular font_size="40" align=center color=""#808080"" text_class=ATO032"; + tag: "br" "\n"; + tag: "hilight" "+ font_weight=Bold"; + tag: "b" "+ font_weight=Bold"; + tag: "tab" "\t"; + } + style { name: "circle_outdoor_style"; + base: "font=Tizen:style=Regular font_size="28" align=center color=""#FFFFFF"" color_class=ATO032 text_class=ATO032"; + tag: "br" "\n"; + tag: "hilight" "+ font_weight=Bold"; + tag: "b" "+ font_weight=Bold"; + tag: "tab" "\t"; + } + } + + parts { + part { name: "bg"; + type: RECT; + scale: 1; + description { state: "default"; + rel1 { relative: 0.0 0.0; } + rel2 { relative: 1.0 1.0; } + color: 0 0 0 0; + } + } + part { name: "top_padding"; + type: SPACER; + scale: 1; + description { state: "default" 0.0; + min: 0 5; + max: -1 5; + fixed: 0 1; + align: 0.5 0.0; + rel2.relative: 1.0 0.0; + } + } + part { name: "bottom_padding"; + type: SPACER; + scale: 1; + description { state: "default" 0.0; + min: 0 28; + max: -1 28; + fixed: 0 1; + align: 0.5 1.0; + rel1.relative: 0.0 1.0; + } + } + part { name: "left_padding"; + type: SPACER; + scale: 1; + description { state: "default" 0.0; + min: 13 0; + max: 13 -1; + fixed: 1 0; + align: 0.0 0.5; + rel2.relative: 0.0 1.0; + } + } + part { name: "right_padding"; + type: SPACER; + scale: 1; + description { state: "default" 0.0; + min: 13 0; + max: 13 -1; + fixed: 1 0; + align: 1.0 0.5; + rel1.relative: 1.0 0.0; + } + } + part { name: "elm.swallow.content"; + type: SWALLOW; + scale: 1; + description { state: "default" 0.0;} + } + part { name: "elm.text.title"; + type: TEXTBLOCK; + scale: 1; + description { state: "default" 0.0; + min: 334 74; + max: -1 74; + align: 0.5 0.0; + rel1 { + to_x: "left_padding"; + to_y: "left_padding"; + relative: 1 0.5; + } + rel2 { + to_x: "right_padding"; + to_y: "right_padding"; + relative: 0 0.5; + } + text { + style: "circle_title_style"; + align: 0.5 0.5; + min: 1 1; + } + } + description { state: "outdoor" 0.0; + inherit: "default" 0.0; + text { + style: "circle_title_style"; + align: 0.5 0.0; + } + } + } + part { name: "elm.text"; + type: TEXTBLOCK; + scale: 1; + mouse_events: 0; + description { state: "default" 0.0; + min: 70 52; + max: 70 52; + align: 0.5 1.0; + visible: 1; + rel1 { + to_y: "bg"; + relative: 0.5 0.5; + } + rel2 { + to_y: "bg"; + relative: 0.5 0.5; + } + text { + style: "circle_level_style2"; + //min: 0 1; + align: 0.5 0.5; + } + } + description { state: "outdoor" 0.0; + inherit: "default" 0.0; + text { + style: "circle_level_dim_style"; + align: 0.5 0.5; + } + } + } + + part { name: "btn.minus"; + type: SWALLOW; + scale: 1; + description { state: "default" 0.0; + min: 64 64; + max: 64 64; + align: 1.0 0.5; + rel1 { + relative: 0.0 0.0; + to: "elm.text"; + } + rel2 { + relative: 0.0 1.0; + to: "elm.text"; + } + } + } + + part { name: "btn.plus"; + type: SWALLOW; + scale: 1; + description { state: "default" 0.0; + min: 64 64; + max: 64 64; + align: 0.0 0.5; + rel1 { + relative: 1.0 0.0; + to: "elm.text"; + } + rel2 { + relative: 1.0 1.0; + to: "elm.text"; + } + } + } + + programs { + + program { + signal: "elm,state,normal"; + source: "*"; + action: STATE_SET "default" 0.0; + target: "elm.text.title"; + target: "elm.text"; + } + } + } +} + diff --git a/res/images/b_ic_press_full_circle_bg_a.png b/res/images/b_ic_press_full_circle_bg_a.png new file mode 100755 index 0000000000000000000000000000000000000000..2208b46f0fcdac9b7ae2e5b163b658e339496e97 GIT binary patch literal 8859 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 literal 0 HcmV?d00001 diff --git a/res/images/b_more_option_icon_select_bg.png b/res/images/b_more_option_icon_select_bg.png new file mode 100755 index 0000000000000000000000000000000000000000..e59f3c99c46fc69df864be1331c3c20a82d1fcba GIT binary patch literal 1925 zcmbVNeNYqE7LTBSfS|3E!H=?8tqLPac1c1Kh&IU*j2etF2wFfwc0*RkZrm&;qHPrc z5ud<|<%t$VDEI`yf))J0u|%Fzu+m!ENUPFPZJ$#Il~yX?b7(gTwtqPO@pg9aJ@?-8 z`<-*o$LwBBeB2D*Ile3wYldnCqGe{p{rPw?qv-Vmru~I53xj5{VwT%2dP62g1L;@>PDsIr z?Vo}Gj!MBqftshbC@>SgB8S4(<;3d@Ihh7A3NBv;#MmVaff=LqfZd!$SS5BT_>5P= z$nI?}2s~4vGo|2jr;^kfKtWO%AmBts7U@nh&g%J>6A`nX8 zC}83N8EX`3lxPvy-kYu8)25QoP#o89+%rfsFQ z*k5kERNJcCX2G~x%t~fc1|}cI1(RSVcCR+%R%E=9tf6owDf%pgG-R7Gf>t3?kU8O? zI4Th;l&}Dbf?+YNh!sGP92ScZW|YZAQG7WfpX7KMmWjGjCXyqtI935cu>z4eQYhy` zN&%!4@*@%6BvwUOX+2@UChg*k-3hGXl~{>_!t^vr=}0nbvH~8a z3L?P?Ec*Y%jLSH~br;9qie++(sX({*qV$=?i{`-yrei3kHS#NdxXE-}s|u0n>^BB0 zR++xh%r01CtgdO(Hv7rKi*|$Ss|_hDQVPMMgy4%EP2lml(dSE@l?j@mUAdh9w3_-y zlT5)y8)xoFSgLDjx^1}QxvwoKF8|l%J%`Fe7FT|&>RmW8K9v22I&x%Oy7=5V@yMKW z$;BR}Q~sN))C4-x7M1%pI8iY%bBAY@GxM6~`3}X9$LRM-opFjqxyI&z#;L7AM;^Xz z@=kPS4@tudYCDML?#ERl8|SIa1C2Y$eG%&|R7fLVG?;K@u;gsWjoOlvGrGGJ8}XH zI#*Ix_?tt=16F@mnt#K4)$h}{m4AJzZgu5jXYX*{t=+9?%%uVy9=bH)S98>=fUj}i zdl~ZWnk7Q??VD-%+jF(Yop~`&HXnL&so;WZSyIlI1;d*|m;T<&{_=F-zs`SK>dkP@ zADdoNg02rb(fH$Zuz2PXjOcU9&OGvrydHGlJLOL36G2}6`>6{5e{Kk@X*m0E!}cr9 zUo6S$692C=CG~0Q$gy0br7H9woabsd%HC5H`iGy_BJ^aqCQRacPrtHE_ZBAlSgvw; zzz18zN}uj2akC4HKe}ub#ro{KoAmI&hNj@SEnBWSo;F?I&u$b2KcFsaHq~z`=67E$ zyLdBfXI=G_@Wt=mvr3NMYK-p7`>cK@SFzxma|c(2w8xk3E1SyhQ&BAqo%gpNI$goL zVyx|-S3X*D%U}yc1`j(92+y1~kC@hDzg@ccX!dxv?ZTdpHmc8`>#yIU?w;m50=t^( zyi!x^R=140ruAKZBx&2khHsxaU61pPy4ToSf2n&Ad)uqg>vLy6#LNBEnt!^wz4yRa zONv*b;6ZI6aq!2x1>rIJ9+xv2zW*~LMt?E4!GG*4(}IBr+Z(&b(gMoavvi95cODFX pes}JW4 literal 0 HcmV?d00001 diff --git a/res/images/b_slider_icon_minus.png b/res/images/b_slider_icon_minus.png new file mode 100755 index 0000000000000000000000000000000000000000..35affbeb8f2cb93ce27b032a3397254ffa7c00a1 GIT binary patch literal 2894 zcmZ{mcRUq-7stPTWUuUzvRAmaZ0@yZxVqQMc1beJimp9>B-ve2*&~swYh-V(ka>;l z5T1-E>(TT7b6&4=KCjm~?|;tc{BsiSn&{F{a!>*QX!P~8%&%1AZ<3Q<)p8Htg)5=( z(X;XgfQs>N5`o-TYyeQ2dca_J@49;jc>BA1`*7>SVB9`_-fkWbT>%K1#aN)=7Mm=p z#|wv0!+7*dLvM3ta&B{I5}GMZP?U#)-XNZ*aE95e{kpa`31?qHJaI}2I+@u_j5?8W znrxNlO-j_;_{4$JrO>yYlg-EL!x!~aY8#aYn7R?NHgf7rJsC4OG<6yD=Jjt;y9z`p1jV5$N!v<2%LngsNCjlBl`@9g2t)HL7Q=2o8*nSOS&y+jx7;7ny4)x z?T#Tinh9uxq(F;-h7J)LlPzcg3P^y%ptI8oxGN4Egr2RB12pC&CzJ@-yyRgfDo6v| zjIQxoz+D+sj@(Ps21rT3q&~t;57ab(HatC5Eg+``l4kKSB7h_mIP~%H z1%c=sz@)Q}Q2BYgntns{%Bh@M6&$~!c7zSNxGxz3A#qa}ug`j$N#5}v$6O7Gj^G@2 z=?Gc6ZwEsF6r?dtgWt28+1W!90w3#7pM;V zHpKbE-{C4}$4B2jFY`x8+ePS-oP6sTIy5S}G4g^U+G%b*Rrjoc>hg?hoVQEg35OJA zS}|krP0`9tK9DZrO@O`-=@uBfbXi^$J0(_Ilmj&n)QCdU#7pg*iGLXi(IW%emX870 zZ}M*cDojp{c8^*b3B24>Ki4e~0BAS;7rp@8*W#Ce57epmk^`Vs5FuKl$$8k$Ce}uJ zqy5@kJJp$kd^D85s{=|8rF22x@N*EUjD!lu4%cvrIzYZ^aLKlrxyPpa&`NYzexg>%*+uB^)`A zdk#5iFE#uq*m(VS7n_r` zR2))IjBk=5l@UT88V~DI;AcpHNekhg|D*rm9ej*oOlRzoIp3yOS)QyO2VZ*stczzY znc_<^?%RDatC-c!Rhd=JRi1qtN{o|+@4FL=WnuGy2L|kG^lP$fq^{Z0nwD>K&F4!C z;n(F-t)W$gSo8O0aixs1k8>4=qgeC}i>lsajB~iNx*vPI{~pkIeLmx+N!Ay{*x;t_ z_pI;4hk?{IvCL7u@hD;TJT@{m6nh}s`)s3P_VFb4Ubv)!)OPkp4qcA7B~lbC`jk0s zfHK1%LokC=6ap_RFD_pwr?Nb-9E7Kq-M0v<*0GeaSSh3Unpt64j=8&S!D)diQ!b4w zN0oZR)!&6%ohOi5bsBY=!rqw`e6U|>?%}3#X0Hnp|9l^vZ{%IF5Ztoy=SCRh9DeTgr{qYN8cAA5%}+|8#*aij|F&je3WNhTjZN=E&u#N=->`Lt&6R8vCWTS ztQD<_ke1eVbvjj;DuKzSs-}|bB{-9GlZyOFRAcZqMTS! z4c*n9yXh_IVU1z`o~x44#LduFa9MMO`+xLfQo5(Kkc)q{s~*;Un7Ii-AxG#(re#*J zjDsRw9vF+faa|NE3g;hn5TBG_7&$1Br6!Tb*)!kQvT6`;P$<-%7^+OJ^VKo7vi^I@Rk8NzcW~a8sCR1gd_658@0-LsU)GG!zAv zA3N@`s{K;)d%dEzqN1=My>78#Mvj}^}cjOl}kKO znN?_%ZB*}(aI+ekKw^;k4-Ic9N{Cj=KYI9i@oeWHZW*&owGzsj4e7J<2`Y znA(f(M@bEkn;B&No^{VFuUUyxVxh&~;nu=aqGYuwSA<*ZaKeCMW<~z(;hmwn0m5^I zS9`B7cNjVtmR?|sVhs`ET*&p7$_I+ID!#!4$`$5ow`1>-R;qkT#EN=Nm{#l{vZ}*d z1VfBHBks2kM7Gxxd2Ul#Qm(~>ZO={Z*qI_BR*UtHe_}D5YRn0V)l3A|Eaqp^!gE1u zoN?X*tvPcqKbBQ=;ao=C#@sg77sT^zXfw;R*0X3I(ag+#q*=W8ap&llHUW|~EKF#M z!oqNGTU9yFi{6UsMFGEcqis!Y6mcY2A(h|kIRXt7hcuM=Ejs&Mnv$=lnyw7s`J zUtsnE#cAYeEdPDgv&`qC6}-B6OtE-;lSXOwNpfiA6505zCtN5l$OCBZey&cQMeeDM zlTD-PklN_v)AksU5846?4o2s6k4a;qMlRBhQt4pVQgc!VV`*Zy^Y5rBDlV)0 zoo}9%z(!m~1oK%h-dqe;v$88)N*i_W*&w%OkkdOCV;e(n#F zk-C3)?{udFQJNXTq26zdsyVd?`6iXHQSRBq7c|ICGW}CtUrT+|GLD z#sGu}0Dz7H;P>T~ZUXRF5`ZlS0F<%;VD)}s->q}S2J35S!h>di%(PPgNpc`1zS~-h zfzl7reB+D1RoArQ2T38j!v24tIVakNHUs@+4hS3=}1jr>3G)*sUb# zpU}=wtqHtLjeV8)Wawl$;+4--D{*7wym4A}PtrJZvF0i0iEzvXerP!AVXtvL~KA21#lU5cUuKFq=1X)qm2oG#vJEHkO7D10_42ZrBT)}{se|g#n@{usQWmgzn)axI87UxZjPNu9bxoiH&rDYjsOf>MRbretpojo2 z1A>B~;BhWsGuTIH{E(<+-h^Bvm0PcY6H?WWcA%CDph6&|`NZ(XoDyuxu7A1a=}32l z<#NeKD>8jK_y|BzI{U@82WO#p##%gHITg$3EVbQENxJ6dwtBukTIGLnxaHuev2#h8 z25z)ECEEA=rSKkw*DboD`^03=dM2GlP_#9NIPm|IjehY{-0bZ7+S-gs57fbR2oZUX z>T>QtoZbBurEy9;`to5#C|cer+K}S-OV`Ikvy!W$&uAXI&2OX`o;J~uPI)J;^%%S1 zkPx<2E0%y%y}XnI`I2i%&}ZVk!sDddD@&3m(s%7M!y;jT_B4JL0KhFhA!+zfgLXeP0D48ykUCwS!_F&` z9h6r)FU@z-ow_JLh6?p`L7Abnx6xMvUBs(npknbOb-WN4na?`BiXB#7@frS%(p|Ri z88!Wxe!Ef^c8aw|(@^LRP_w!U%q5b!JwXblQgi0U9Sd|CQLrQn@ed}lSzR+tS2B{b zegfyWHR9dZ4E#$q!O@^OU3~z^$DGEu8p=J7uD82|POUK&SH z{-?lq+?pxM#hah1yqMcP(fS=U$`m0`epfzSBcvJ9V#cVP|EiGU33HGG_9++h5kwcwUyMZTgDw_wKL z+-;wFD%Izb{1O9kYnZj}HH9^vHGzExT8x`c!0Th16*23fJ0@J~%tX9x`&Z@Gl#N61i;juwg zsFx>HqRRc?+OMPR&XOqYy3M*RVXv)<-a4JfQ6GW+lW zq$TH!wmmjC&#x!0{8vJ9xl;YjzxGJ>j+vnT&N`z8GK*ZF1 z+k7w2+8kFZUaD@UZq`5YapdL5RIXCKrrfmrX8vaWbpBG4i+!lQB(@y;-ovA9sS%!Psc9*@T!ypAu&64WLUq^uzz$+7nz-uLXDA7^SYK?U zE6R-%)zn+ty_eCJ5!oF1&zU9_L&7X$6|X&SRM5LXHnp2-i+T8hJ?+Te!>lbC6mpb# zbVgwn%Q`IH;1JbeoTZEGgMM*&XD;p0b`{D%Cl z-EzX4J>@;`y@dG}9~EDS7uqQVed->7eX&{})24foDeJRT9c2l#j7BwX3d*?4q$6sk z>zYbJDv7S&IkkRj1-@9-TGdcllwY)S{;1N?G|)6`+3i>89Jd5}BuKhV3MY+$GPE!m ziaaS=H`?K^ljHD*0_~~VY6Op;^|QOWDMdJ4cHOj?nwa&@8Ue3?Z%=Ckh?_b1bi6lX z+>NNOQ=h0@H(Zmuqv%EB65_xPbgL1ZIWhxI{$a)V zuEV%8jtXfONwq8;vqX#Q&;O^(3@PVG5#DDF5l*EI>*DP~U6UD89!s2oIYRg>_KhIs z;m^LMwcv!4WX(>c_2L7N0NqAv#JUuMs`0o z3=y8H6nuX{+GXitS$>8si8n<^@gg_cs_&@QYXpQ5Xjj=UNyOiztk!t{1Pk${*K4+Xt5_fsbwQ@X0tz< z5t|QP=SlDzYR{d2{;r~`2X}kabKG-lV^ONmfibHxdn23i9>eV1JBFp3?{<%V>JwzL zN5lv%u~-=HRlCOfR*$kl{D`_X{5AX#{u{2mH@?v5I(>X^Y>y|R^{3*uNrFQw@l0#* z1HqQe)_l@)(&NPVq=Bein^d`VoOR;sRAb>Au-i{QPJTuu$cUZBeV*hU*MwWAO-bw+ zGWP%d;T-clM2bO~!S^j5TjM-q!m_`mpe3&s z=jemm3vX+T@FZ^W6sq7C4%@(ew19G$z=kwA{4ec!v0$!s}Y9 zsw>)oXIrObu+iJ2B88miFVBZ-IXPsajwg4f@nbn-#o7DW8STCgOU|}CcDUXU`nvk~ zJ`9E`$lW@;d9vFXG9SYG{nZka<=R93M`9$eUvH0WK9!whaAjnWD9CdTPTdux2p9h* zzq^sOIRN3p0H9+5_(i(lEdcJz0J?()tD^D745i&Q{UgSg zK&W(3tU}XJ+!M8ai%lo&+Gi3DuPg5Xe1IjICEyb>BQ&r P?vKS--$Jhz>JsyRR3=ui literal 0 HcmV?d00001 diff --git a/res/images/drawing_popup_btn_check.png b/res/images/drawing_popup_btn_check.png new file mode 100755 index 0000000000000000000000000000000000000000..3dce121f149a712e08bb120b9fbcba6dc6c392d0 GIT binary patch literal 1331 zcmeAS@N?(olHy`uVBq!ia0vp^Mj*_=1|;R|J2nC-$r9IylHmNblJdl&R0hYC{G?O` z&)mfH)S%SFl*+=BsWuD@%qp275hW46K32*3xq68pHF_1f1wh>l3^w)^1&PVosU-?Y zsp*+{wo31J?^jaDOtDo8H}y5}EpSfF$n>ZxN)4{^3rViZPPR-@vbR&PsjvbXkegbP zs8ErclUHn2VXFi-*9yo63F|8hm3bwJ6}oxF$}kgLQj3#|G7CyF^YauyCMG83 zmzLNn0bL65LT&-v*t}wBFaZNhzap_f-%!s00+w{G(#^lGsVi;%)-dj(Z#~a&CuM?(AC7z+|1I|*~GxY z(ACt;%+(2|*Cju>G&eP`1g19yq1O_pUQlAlEdbi=l3J8mmYU*Ll%J~r_Ow+dZnv1> zG!Lpb1-Dzwaq86vIz}H9wMbD769T3m5EGtofgE_!Pt60S_ab1z&fjl7kAZ=4si%u$ zNX4x;H_xXtJBqM>Sh6yp>h0Dke^hP1Udh&6I%U!c%{Q7YLZ{|=X)J7+S_fNk&GyCs}e>3i0X%*P2wPkOVtCX|EA%Ql77DXOS z!6z%YCYYsgTDn%BbWJ|=vTOggwmB<*E$caP#`U$HvUPi+bB9=pSX-XOPTdxM}6eTZIfiUDS3LI`~Z3#lNj| z<6I$QceTBybJjR26ittx`AWf1{=}15<|862i{Dr6dQ~!MMmalAtHiGzl`qPscsH9r zNvJxpL((Yk!E3#YOObL{w2J~}DlU5ed1i{0!}kY17cVMW&9Htn>s4#Ss~dbv^b)S` zjxp)rT_#(^`ZlVe>cmYuo5jv6Qrq9RrWJTxbTW`qIA&h(iad!N;NV+w-HeHcVYN3$%G!;GuYrm&Pgg&ebxsLQ0Hu@OaR2}S literal 0 HcmV?d00001 diff --git a/res/images/drawing_popup_btn_delete.png b/res/images/drawing_popup_btn_delete.png new file mode 100755 index 0000000000000000000000000000000000000000..58de36c9192d1dc72e3689fd31d3338faa624cff GIT binary patch literal 1457 zcmeAS@N?(olHy`uVBq!ia0vp^Mj*_=1|;R|J2nC-$r9IylHmNblJdl&R0hYC{G?O` z&)mfH)S%SFl*+=BsWuD@%qp275hW46K32*3xq68pHF_1f1wh>l3^w)^1&PVosU-?Y zsp*+{wo31J?^jaDOtDo8H}y5}EpSfF$n>ZxN)4{^3rViZPPR-@vbR&PsjvbXkegbP zs8ErclUHn2VXFi-*9yo63F|8hm3bwJ6}oxF$}kgLQj3#|G7CyF^YauyCMG83 zmzLNn0bL65LT&-v*t}wBFaZNhzap_f-%!s00+w{G(#^lGsVi;%)-dj(Z$)x&CuM?(AC7z+|1I|*~GxY z(ACt;%+(2|*Cju>G&eP`1g19yq1OecUQlAlEdbi=l3J8mmYU*Ll%J~r_Ow+dZnrq% zG!Lpb1-DzAaO%|uIz}H9wMbD769T3m5EGtofgE_!Pt60S_ab1zel}6*Cj$eMvZsq< zNX4x;H!r$72gC`a8Gy-QT%)Z(G^#^S`_KT>9?a&*$7f)U)w|%@wB%KQCt! z7ZCc#qQd^tA*kzlX#15VZW7wN6FyB~{Jly}Mb|J)t@K-L^`gfq0?ywyzY|H|yYc?k z@+KFB@SLi<&PFT^9n6PTDP2{c)cQsCpXYt$w)Pc)_o9?$tnogg*mPs*zrKi*Gqzve zQZ?a7LI=NOi*yHvntF$Yn}GGE&qdYo%g-*qwneJIp!*7kz5w@SXM;+1m&1u?q?bG@ zvx}3Tt;v$S#=4dBNGBHy>yblulx8gIv~U%Oj(hI7RVjIfx`(^!A&(gwx+k@4QDi;% z`uK$06Ok9Tee9oLdgALELAO@XFI$D4sRz3V%%1Rhf&7|#itFd>?{BVi>T!;mu<3y5 z(gjXEoMx=*62c6>nGW82y74fxLfWBB1D5k2Se{%;oGalNrcii-^|@5MxC_rmCe7RH zdJ7F!*Evo)Ay^@lc)TPuAw*%GqH0Rcl;+6!qDLI=D0HMYUhh!)tsgG&>g>ZwN3tbn zm~EPQCxCUK%MC-_uDOOsGYd2>l|M?D6=ztd>|!X&<-zXwg!A^&8=6H&vYB?}p5g5f zysiIPV&0d5{buU99PxNx%t&UUuuye5dG)>qG0Qk T^Uv(91Qnv5u6{1-oD!MI6Tal{E@8IPYwSh2!*Xv9nYkoR^%T!MUZb&-Kk<<2 z`E7PqM*k}hwyccT_5AtahuonXDlvySk8FNE(SS=$Ti7r$SugTkeN#@gOxy#uvIH@u zp3H@^Eth2`6=hxH(wa51r*nDY{6((~^y+n9w6LwX=o)%4J>=KH#X84w-7CxjMFO{b z3a(t5VSMJ`-sy`MaZ7NxOiB8>fnoZtub%pos_KL{NxOWEr|x;eA5y0=U*~U9qqo()&4(o|U8+KVoOznOG0-Sb^!4@Rg6=na?p*%^@{2VejI literal 0 HcmV?d00001 diff --git a/res/images/wi_drawing_bg_01.png b/res/images/wi_drawing_bg_01.png new file mode 100755 index 0000000000000000000000000000000000000000..c1cfc2c50c727e38ad0fb1fa42948da2a8bb7d11 GIT binary patch literal 40493 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 it$F-k<39S200RJKqAj*1F~Rx(0000n4 literal 0 HcmV?d00001 diff --git a/res/images/wi_drawing_bg_02.png b/res/images/wi_drawing_bg_02.png new file mode 100755 index 0000000000000000000000000000000000000000..0470f9584aece79946a27b9c8092717995a0f297 GIT binary patch literal 58234 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 literal 0 HcmV?d00001 diff --git a/res/images/wi_drawing_bg_03.png b/res/images/wi_drawing_bg_03.png new file mode 100755 index 0000000000000000000000000000000000000000..6b94347b1d9976afde39c400e1508017d349bbcf GIT binary patch literal 45464 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 LNkvXXu0mjfBb+sd literal 0 HcmV?d00001 diff --git a/res/images/wi_drawing_bg_04.png b/res/images/wi_drawing_bg_04.png new file mode 100755 index 0000000000000000000000000000000000000000..2a3cefb9c8708ab1ddd47866abc77d4a65111c3f GIT binary patch literal 66637 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�vOWs@-Z7j_2q`rlg(OXXdwru!c38u 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 literal 0 HcmV?d00001 diff --git a/res/images/wi_drawing_bg_pattern_negative.png b/res/images/wi_drawing_bg_pattern_negative.png new file mode 100644 index 0000000000000000000000000000000000000000..200d8d333284e59efa1fb1e8ef750281edbe6170 GIT binary patch literal 2183 zcmeAS@N?(olHy`uVBq!ia0y~yV9Wqv4mO}j)zieQKuWU2HKHUqKdq!Zu_%?nF(p4K zRlzeiF+DXXH8G{K@MNkD0|SSqr;B4q#jQ6tHWo5F3NSm`d_Es(6uRW-Rui}FmW+26 ze!Dq;{@&`6*y~^azh2Kc;Y-b)8+E!sp2zkDjEA_Z!0b3M`xbB1_0qe%QVpk@=EZwo zFWq}xH>2T0Q(5!1(%AB5wg;OQJimUaH1>Tdx0J%31$P&e#$La>fN_V;i=SJ8##i5M zV&l-yFwcm+UTU7fpf_stXn>5SkkKqNT84}ks-v~c0N0KAf4K}8{yFyES1)940Jba` NJYD@<);T3K0RVaDE_?t0 literal 0 HcmV?d00001 diff --git a/res/images/wi_drawing_more_options_erase.png b/res/images/wi_drawing_more_options_erase.png new file mode 100755 index 0000000000000000000000000000000000000000..4a810709a70824672ce15b452e1a4a0b1ebab858 GIT binary patch literal 1527 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 literal 0 HcmV?d00001 diff --git a/shared/res/tables/org.tizen.w-drawing_color.xml b/shared/res/tables/org.tizen.w-drawing_color.xml new file mode 100755 index 0000000..4d9cb15 --- /dev/null +++ b/shared/res/tables/org.tizen.w-drawing_color.xml @@ -0,0 +1,166 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/shared/res/tables/org.tizen.w-drawing_font.xml b/shared/res/tables/org.tizen.w-drawing_font.xml new file mode 100755 index 0000000..22978f8 --- /dev/null +++ b/shared/res/tables/org.tizen.w-drawing_font.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/CDrUtil.cpp b/src/CDrUtil.cpp new file mode 100644 index 0000000..4378137 --- /dev/null +++ b/src/CDrUtil.cpp @@ -0,0 +1,519 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +//#include +#include "DrDebug.h" +#include "CDrUtil.h" +//#include + +bool +CDrUtil::_bLockLcdOff = false; + +#define DBUS_REPLY_TIMEOUT (120 * 1000) + +#define VE_LOW_MEMORY_LIMIT_VALUE (1048576) +#define SDMEMORY_FOLDER "/opt/storage/sdcard" + + +bool +CDrUtil::checkIfLowStorageMem(int usageSize) +{ + unsigned long long size = 0; + struct statvfs dst_fs; + if (storage_get_internal_memory_size (&dst_fs) < 0) + { + size = 0; + WINFO("storage_get_internal_memory_size fail\n"); + return true; + } + + size = + ((unsigned long long) (dst_fs.f_bsize) * + (unsigned long long) (dst_fs.f_bavail)); + WINFO("valid storage size is %lld\n", size); + if (size < (unsigned long long) usageSize) + { + return true; + } + return false; +} + +void +CDrUtil::timeFormat(int nSeconds, std::string & str) +{ + char cText[256]; + int hour = (int) ((nSeconds) / 3600.0); + int min = (int) (((nSeconds - hour * 3600)) / 60.0); + int sec = (nSeconds) % 60; + snprintf (cText, sizeof (cText), "%.2d:%.2d:%.2d", hour, min, sec); + str = cText; +} + +void +CDrUtil::timeFormat(std::string & sSeconds, std::string & str) +{ + /* + sSeconds ("15") + */ + int nSeconds = atoi(sSeconds.c_str()); + timeFormat(nSeconds, str); +} + +int +CDrUtil::timeToInt(std::string & sTime) +{ + /* sTime is 01:02:03 + sTime.substr(0,2) is hour integer + sTime.substr(3,2) is min integer + sTime.substr(6,2) is sec integer + */ + int nSeconds = + atoi(sTime.substr(0, 2).c_str()) * 3600 + + atoi(sTime.substr(3, 2).c_str()) * 60 + + atoi(sTime.substr(6, 2).c_str()); + return nSeconds; +} + +bool +CDrUtil::makeDir(const char *path) +{ + if (path == nullptr) + { + WERROR("Invalid input path"); + return false; + } + + struct stat st; + if (stat(path, &st) < 0) + { + if (!ecore_file_mkpath (path)) + { + WSERROR("Failed to mkdir[%s]!", path); + return false; + } + } + return true; +} + +GDBusMessage * +CDrUtil::_gdbusInvokeMethodSync(const char *dest, const char *path, + const char *interface, const char *method, + GVariant * arg_variant) +{ + WENTER(); + + GDBusConnection *conn; + GDBusMessage *msg; + GDBusMessage *reply; + GError *error = nullptr; + + conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, nullptr, nullptr); + if (conn == nullptr) + { + WERROR("g_bus_get_sync() is failed."); + return nullptr; + } + + msg = g_dbus_message_new_method_call(dest, path, interface, method); + if (msg == nullptr) + { + WERROR("g_dbus_message_new_method_call() is failed."); + g_object_unref(conn); + return nullptr; + } + + if (arg_variant) + { + g_dbus_message_set_body(msg, arg_variant); + } + + reply = + g_dbus_connection_send_message_with_reply_sync(conn, msg, + G_DBUS_SEND_MESSAGE_FLAGS_NONE, + DBUS_REPLY_TIMEOUT, + nullptr, nullptr, &error); + if (reply == nullptr) + { + WERROR("g_dbus_connection_send_message_with_reply_sync() is failed."); + } + + if (error != nullptr) + { + if (error->message != nullptr) { + WERROR("error [%s]", error->message); + } else { + WERROR(""); + } + g_error_free(error); + error = nullptr; + } + + g_object_unref(msg); + g_object_unref(conn); + + return reply; +} + +void +CDrUtil::setBlockLcdOff() +{ + WENTER(); + GVariant *gvariant = nullptr; + gvariant = + g_variant_new("(sssi)", "lcdon", "gotostatenow", "holdkeyblock", 0); + + GDBusMessage *msg = nullptr; + msg = + _gdbusInvokeMethodSync("org.tizen.system.deviced", + "/Org/Tizen/System/DeviceD/Display", + "org.tizen.system.deviced.display", "lockstate", + gvariant); + + if (!msg) { + WERROR("invoke gdbus method failed"); + } else { + g_object_unref(msg); + msg = nullptr; + } + _bLockLcdOff = true; + WLEAVE(); +} + +void +CDrUtil::setUnblockLcdOff() +{ + WENTER(); + GVariant *gvariant = nullptr; + gvariant = g_variant_new("(ss)", "lcdon", "resettimer"); + + GDBusMessage *msg = nullptr; + msg = + _gdbusInvokeMethodSync("org.tizen.system.deviced", + "/Org/Tizen/System/DeviceD/Display", + "org.tizen.system.deviced.display", "unlockstate", + gvariant); + + if (msg == nullptr) { + WERROR("invoke gdbus method failed"); + } else { + g_object_unref(msg); + msg = nullptr; + } + _bLockLcdOff = false; + WLEAVE(); +} + +bool +CDrUtil::getLcdState() +{ + return _bLockLcdOff; +} + +int +CDrUtil::getVideoClipRotate(const char *strInputFile) +{ + metadata_extractor_h meta_h; + int nRet = METADATA_EXTRACTOR_ERROR_NONE; + int nRotate = 0; + char *szVal = NULL; + nRet = metadata_extractor_create(&(meta_h)); + if (nRet != METADATA_EXTRACTOR_ERROR_NONE) + { + WERROR("metadata_extractor_create is fail : [0x%x]", nRet); + goto FAILED_EXIT; + } + + nRet = metadata_extractor_set_path(meta_h, strInputFile); + if (nRet != METADATA_EXTRACTOR_ERROR_NONE) + { + WERROR("metadata_extractor_set_path is fail : [0x%x]", nRet); + goto FAILED_EXIT; + } + + + nRet = metadata_extractor_get_metadata(meta_h, METADATA_ROTATE, &szVal); + if (nRet != METADATA_EXTRACTOR_ERROR_NONE) + { + WERROR("metadata_extractor_get_metadata is fail : [0x%x]", nRet); + } + + if (szVal == NULL) { + nRotate = 0; + } else { + nRotate = atoi(szVal); + free(szVal); + } + +FAILED_EXIT: + nRet = metadata_extractor_destroy(meta_h); + if (nRet != METADATA_EXTRACTOR_ERROR_NONE) + { + WERROR("metadata_extractor_destroy is fail : [0x%x]", nRet); + } + + return nRotate; +} + +void +CDrUtil::initResourceManager() +{ +#if 0 + int err = APP_RESOURCE_ERROR_NONE; + err = app_resource_manager_init(); + if (err != APP_RESOURCE_ERROR_NONE) + { + WERROR("app_resource_manager_init failed[%d]", err); + } +#endif +} + +void +CDrUtil::releaseResourceManager() +{ +#if 0 + int err = APP_RESOURCE_ERROR_NONE; + err = app_resource_manager_release(); + if (err != APP_RESOURCE_ERROR_NONE) + { + WERROR("app_resource_manager_release failed[%d]", err); + } +#endif +} + +char * +CDrUtil::getEdjPath(const char *name) +{ + char *path = nullptr; +#if 0 + int err = APP_RESOURCE_ERROR_NONE; + + err = app_resource_manager_get(APP_RESOURCE_TYPE_LAYOUT, name, &path); + if (err != APP_RESOURCE_ERROR_NONE || path == nullptr) + { + WERROR("app_resource_manager_get failed[%d]", err); + if (path != nullptr) + { + free(path); + path = nullptr; + } + return nullptr; + } +#endif + return path; +} + +char * +CDrUtil::getImagePath(const char *name) +{ + char *path = nullptr; +#if 0 + int err = APP_RESOURCE_ERROR_NONE; + + err = app_resource_manager_get(APP_RESOURCE_TYPE_IMAGE, name, &path); + if (err != APP_RESOURCE_ERROR_NONE || path == nullptr) + { + WERROR("app_resource_manager_get failed[%d]", err); + WSINFO("image file name : [%s]", name); + if (path != nullptr) + { + free(path); + path = nullptr; + } + return nullptr; + } + +#endif + return path; +} + +char * +CDrUtil::getSharedResPath() +{ + char *path = nullptr; + path = app_get_shared_resource_path(); + if (path == nullptr) + { + WERROR("app_get_shared_resource_path failed"); + } + return path; +} + +char * +CDrUtil::getResourcePath() +{ + char *path = nullptr; + path = app_get_resource_path(); + if (path == nullptr) + { + WERROR("app_get_resource_path failed"); + } + return path; +} + +void +CDrUtil::getVideoClipWidthHeight(const char *strInputFile, int &iWidth, + int &iHeight) +{ + metadata_extractor_h meta_h; + int nRet = METADATA_EXTRACTOR_ERROR_NONE; + char *szVal = NULL; + nRet = metadata_extractor_create(&(meta_h)); + if (nRet != METADATA_EXTRACTOR_ERROR_NONE) + { + WERROR("metadata_extractor_create is fail : [0x%x]", nRet); + goto FAILED_EXIT; + } + + nRet = metadata_extractor_set_path(meta_h, strInputFile); + if (nRet != METADATA_EXTRACTOR_ERROR_NONE) + { + WERROR("metadata_extractor_set_path is fail : [0x%x]", nRet); + goto FAILED_EXIT; + } + + nRet = + metadata_extractor_get_metadata(meta_h, METADATA_VIDEO_WIDTH, &szVal); + if (nRet != METADATA_EXTRACTOR_ERROR_NONE) + { + WERROR("metadata_extractor_get_metadata is fail : [0x%x]", nRet); + goto FAILED_EXIT; + } + + if (szVal == NULL) { + iWidth = 0; + } else { + iWidth = atoi(szVal); + free(szVal); + } + + nRet = + metadata_extractor_get_metadata(meta_h, METADATA_VIDEO_HEIGHT, &szVal); + if (nRet != METADATA_EXTRACTOR_ERROR_NONE) + { + WERROR("metadata_extractor_get_metadata is fail : [0x%x]", nRet); + goto FAILED_EXIT; + } + + if (szVal == NULL) { + iHeight = 0; + } else { + iHeight = atoi(szVal); + free(szVal); + } + +FAILED_EXIT: + nRet = metadata_extractor_destroy(meta_h); + if (nRet != METADATA_EXTRACTOR_ERROR_NONE) + { + WERROR("metadata_extractor_destroy is fail : [0x%x]", nRet); + } +} + + +bool +CDrUtil::getStorageState(bool bExternal) +{ + int ret; + struct statvfs info; + if (bExternal) { + /* it is external memory card */ + //ret = statvfs(SDMEMORY_FOLDER, &info); + ret = storage_get_external_memory_size(&info); + } else { + /* it is internal memory */ + ret = storage_get_internal_memory_size(&info); + } + if (ret < 0) + { + WERROR("fail to get memory size"); + return false; + } + + if (((info.f_bsize) * info.f_bavail) < VE_LOW_MEMORY_LIMIT_VALUE) + { + WERROR("Memory is almost full < 1MB"); + return false; + } + return true; +} + +void +CDrUtil::getTimeName(long long time, std::string & strName) +{ + std::stringstream ss; + + ss << time; + + strName = ss.str(); +} + +long long +CDrUtil::getTimeStamp() +{ + struct timeval times; + gettimeofday(×, NULL); + long long interval = times.tv_sec; + interval = interval * 1000; + interval += times.tv_usec / 1000; + return interval; +} + +int +CDrUtil::atoi(const char *number) +{ + if (number == NULL) + { + WERROR("Input Number is NULL"); + return 0; + } + + char *endptr = NULL; + long val = 0; + + errno = 0; + + val = strtol(number, &endptr, 10); + + if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN)) + || (errno != 0 && val == 0)) + { + WERROR("strtol, val = %d", val); + return -1; + } + + if (endptr == number) + { + WERROR("No digits were found, number = %s", number); + return -1; + } + + return (int)val; +} + +bool +CDrUtil::isOperator(const char *opCode) +{ + char *operator_code = NULL; + bool result = false; +// operator_code = vconf_get_str(VCONFKEY_CSC_TEXT_STRING_CUSTOMER); + if (operator_code != NULL) + { + if (!strncmp(operator_code, opCode, strlen(operator_code))) + { + result = true; + } + free(operator_code); + } + return result; +} diff --git a/src/CDrUtil.h b/src/CDrUtil.h new file mode 100644 index 0000000..55f801b --- /dev/null +++ b/src/CDrUtil.h @@ -0,0 +1,52 @@ +#ifndef _C_DR_UTIL_H_ +#define _C_DR_UTIL_H_ + +#include +#include +#include +#include +#include +#include + +// *********************************************************** +// declare and define methods which is a little complicated inside class body +// *********************************************************** + +class CDrUtil +{ +public: + + static bool checkIfLowStorageMem(int usageSize); + static void timeFormat(int nSeconds, std::string & str); + static void timeFormat(std::string & sSeconds, std::string & str); + static int timeToInt(std::string & sTime); + static bool makeDir(const char *path); + static void setUnblockLcdOff(); + static void setBlockLcdOff(); + static bool getLcdState(); + static int getVideoClipRotate(const char *strInputFile); + static void getVideoClipWidthHeight(const char *strInputFile, int &iWidth, + int &iHeight); + static void initResourceManager(); + static void releaseResourceManager(); + static char *getEdjPath(const char *name); + static char *getImagePath(const char *name); + static char *getSharedResPath(); + static char *getResourcePath(); + static bool getStorageState(bool bExternal); + static void getTimeName(long long time, std::string & strName); + static long long getTimeStamp(); + static int atoi(const char *number); + static bool isOperator(const char *opCode); + +private: + static GDBusMessage *_gdbusInvokeMethodSync(const char *dest, + const char *path, + const char *interface, + const char *method, + GVariant * arg_variant); +private: + static bool _bLockLcdOff; +}; + +#endif diff --git a/src/EventManager/CDrEvent.h b/src/EventManager/CDrEvent.h new file mode 100755 index 0000000..04e093e --- /dev/null +++ b/src/EventManager/CDrEvent.h @@ -0,0 +1,50 @@ +#ifndef _CDR_EVENT_H_ +#define _CDR_EVENT_H_ + +#include "WDefine.h" + +class WAPP_ASSIST_EXPORT CDrEvent { + public: + enum EType { + NONE = 0, + DB_CHANGED, + LANGUAGE_CHANGED, + SETTING_CHANGED, + WIN_ROTATED, + LOW_MEMORY, + APP_PAUSED, + APP_RESUMED, + TYPE_MAX, + } mType; + enum ESource { + LOCAL = 0, + REMOTE, + SOURCE_MAX, + } mSource; + void *mData; + public: + CDrEvent() { + mType = NONE; + mSource = LOCAL; + mData = NULL; + }; + CDrEvent(EType _type, ESource _source, void *_data = NULL):mType(_type), mSource(_source), mData(_data) { + }; + virtual ~CDrEvent() { + }; + CDrEvent(const CDrEvent & obj) { + mType = obj.mType; + mSource = obj.mSource; + mData = obj.mData; + }; + CDrEvent & operator=(const CDrEvent & obj) { + if (this != &obj) { + mType = obj.mType; + mSource = obj.mSource; + mData = obj.mData; + } + return *(CDrEvent *)this; + }; +}; + +#endif /* _CVE_EVENT_H_ */ diff --git a/src/EventManager/CDrEventListener.h b/src/EventManager/CDrEventListener.h new file mode 100755 index 0000000..37b2457 --- /dev/null +++ b/src/EventManager/CDrEventListener.h @@ -0,0 +1,12 @@ +#ifndef _CDR_EVENT_LISTENER_H_ +#define _CDR_EVENT_LISTENER_H_ + +#include "WDefine.h" +#include "CDrEvent.h" + +class WAPP_ASSIST_EXPORT CDrEventListener { + public: + virtual void onEvent(const CDrEvent & event) = 0; +}; + +#endif //_CVE_EVENT_LISTENER_H_ diff --git a/src/EventManager/CDrEventManager.cpp b/src/EventManager/CDrEventManager.cpp new file mode 100644 index 0000000..db7e1e5 --- /dev/null +++ b/src/EventManager/CDrEventManager.cpp @@ -0,0 +1,319 @@ +#include "CDrEventManager.h" +#include "DrDefine.h" +//#include + +#define CAL_TIMEOUT_MAX 8 +#define CAL_TIMEOUT_MAX_FOR_KIES 2 + + CDrEventManager::CDrEventManager(): + _timerForPeindingEvents(NULL), _timeout(0), _timeoutMax(CAL_TIMEOUT_MAX), _pendingEvents(false), _isSuspended(false) +{ + WENTER(); +} + +CDrEventManager::~CDrEventManager() +{ + WENTER(); + _removeTimerForPendingEvents(); + clear(); +} + +void CDrEventManager::attach(CDrEventListener * listener) +{ + //WENTER(); + ListenerNode *node = new ListenerNode; + node->isBlocked = false; + node->listener = listener; + _resetEventTable(node); + _listenerMap.insert(std::pair < CDrEventListener *, ListenerNode * >(listener, node)); +} + +void CDrEventManager::detach(CDrEventListener * listener) +{ + //WENTER(); + auto finder = _listenerMap.find(listener); + if (finder == _listenerMap.end()) { + //WDEBUG("null"); + return; + } + auto node = finder->second; + _clearEventTable(node); + delete node; + + _listenerMap.erase(finder); + WLEAVE(); +} + +void CDrEventManager::block(CDrEventListener * listener) +{ + WENTER(); + WDEBUG("%p", listener); + auto finder = _listenerMap.find(listener); + if (finder == _listenerMap.end()) { + WDEBUG("null"); + return; + } + auto node = finder->second; + node->isBlocked = true; +} + +void CDrEventManager::unblock(CDrEventListener * listener) +{ + WENTER(); + WDEBUG("%p", listener); + auto finder = _listenerMap.find(listener); + if (finder == _listenerMap.end()) { + WDEBUG("null"); + return; + } + auto node = finder->second; + node->isBlocked = false; + _notifyFromEventTable(node); +} + +void CDrEventManager::notify(const CDrEvent & event) +{ + WENTER(); + if (_isSuspended) { + for (auto it = _listenerMap.begin(); it != _listenerMap.end();) { + auto node = it->second; + it++; + WINFO("is suspend-addtoEventTable"); + _addtoEventTable(node, event); + } + return; + } + + for (auto it = _listenerMap.begin(); it != _listenerMap.end();) { + auto node = it->second; + it++; + if (node->isBlocked) { + WINFO("node->isBlocked EVENT %d", event.mType); + _addtoEventTable(node, event); + } else { + if (event.mSource == CDrEvent::REMOTE) { + int timeout = _getTimeoutForTimerForPendingEvents(); + WDEBUG("an event from a remote one, timeout = %d", timeout); + /* + if (timeout == 0) { + node->listener->onEvent(event); + } else { + WINFO("for-addtoEventTable"); + _addtoEventTable(node, event); + } + */ + node->listener->onEvent(event); + } else { + node->listener->onEvent(event); + } + } + } + + //if (event.mSource == CDrEvent::REMOTE) { + // WINFO("_addTimerForPendingEvents"); + //_addTimerForPendingEvents(); + //} + WLEAVE(); +} + +void CDrEventManager::clear() +{ + for (auto it = _listenerMap.begin(); it != _listenerMap.end();) { + auto node = it->second; + _clearEventTable(node); + delete node; + + it = _listenerMap.erase(it); + } +} + +void CDrEventManager::suspend() +{ + WENTER(); + _isSuspended = true; + + _removeTimerForPendingEvents(); +} + +void CDrEventManager::resume() +{ + WENTER(); + _isSuspended = false; + + for (auto it = _listenerMap.begin(); it != _listenerMap.end();) { + auto node = it->second; + it++; + if (node->isBlocked) { + WDEBUG("node->isBlocked"); + continue; + } else { + _notifyFromEventTable(node); + } + } +} + +bool CDrEventManager::isDetached(CDrEventListener * listener) +{ + WENTER(); + auto finder = _listenerMap.find(listener); + if (finder == _listenerMap.end()) + return true; + else + return false; +} + +void CDrEventManager::_resetEventTable(ListenerNode * node) +{ + // reset the event table + for (int i = 1; i < CDrEvent::TYPE_MAX; i++) { + for (int j = 0; j < CDrEvent::SOURCE_MAX; j++) { + node->eventTable[i][j] = NULL; + } + } +} + +void CDrEventManager::_addtoEventTable(ListenerNode * node, const CDrEvent & event) +{ + // add it to the event table + if (node->eventTable[event.mType][event.mSource]) + delete node->eventTable[event.mType][event.mSource]; + node->eventTable[event.mType][event.mSource] = new CDrEvent(event); +} + +void CDrEventManager::_notifyFromEventTable(ListenerNode * node) +{ + // notify events from the event table + for (int i = 1; i < CDrEvent::TYPE_MAX; i++) { + for (int j = 0; j < CDrEvent::SOURCE_MAX; j++) { + if (node->eventTable[i][j]) { + CDrEventListener *listener = node->listener; + node->listener->onEvent(*(node->eventTable[i][j])); + + auto finder = _listenerMap.find(listener); + if (finder == _listenerMap.end()) { + WDEBUG("null"); + return; + } + + delete node->eventTable[i][j]; + node->eventTable[i][j] = NULL; + } + } + } +} + +void CDrEventManager::_notifyFromEventTable(ListenerNode * node, CDrEvent::ESource source) +{ + // notify events from the event table + for (int i = 1; i < CDrEvent::TYPE_MAX; i++) { + if (node->eventTable[i][source]) { + CDrEventListener *listener = node->listener; + node->listener->onEvent(*(node->eventTable[i][source])); + + auto finder = _listenerMap.find(listener); + if (finder == _listenerMap.end()) { + WDEBUG("null"); + return; + } + + delete node->eventTable[i][source]; + node->eventTable[i][source] = NULL; + } + } +} + +void CDrEventManager::_clearEventTable(ListenerNode * node) +{ + // clear the event table + for (int i = 1; i < CDrEvent::TYPE_MAX; i++) { + for (int j = 0; j < CDrEvent::SOURCE_MAX; j++) { + if (node->eventTable[i][j]) { + delete node->eventTable[i][j]; + node->eventTable[i][j] = NULL; + } + } + } +} + +void CDrEventManager::_processTimerForPendingEvents() +{ + //WENTER(); + for (auto it = _listenerMap.begin(); it != _listenerMap.end();) { + auto node = it->second; + it++; + if (node->isBlocked) { + WDEBUG("node->isBlocked"); + continue; + } else { + _notifyFromEventTable(node, CDrEvent::REMOTE); + } + } + _timerForPeindingEvents = NULL; + if (_pendingEvents) { + _addTimerForPendingEvents(); + } else { + //WDEBUG("expired"); + _resetTimeoutForTimerForPendingEvents(); + } +} + +void CDrEventManager::_addTimerForPendingEvents() +{ + //WENTER(); + if (_timerForPeindingEvents) { + //a request before timed out, just set the flag + _pendingEvents = true; + return; + } + + _updateTimeoutForTimerForPendingEvents(); + int timeout = _getTimeoutForTimerForPendingEvents(); + WDEBUG("timeout = %d", timeout); + _timerForPeindingEvents = ecore_timer_add(timeout, [](void *data) { + CDrEventManager * self = (CDrEventManager *) data; + self->_processTimerForPendingEvents(); + self->_timerForPeindingEvents = nullptr; + return ECORE_CALLBACK_CANCEL; + }, this); +} + +void CDrEventManager::_removeTimerForPendingEvents() +{ + //WENTER(); + if (_timerForPeindingEvents) + ecore_timer_del(_timerForPeindingEvents); + _timerForPeindingEvents = nullptr; + _resetTimeoutForTimerForPendingEvents(); +} + +int CDrEventManager::_getTimeoutForTimerForPendingEvents() +{ + //WENTER(); + // get the timeout for update + return _timeout; +} + +void CDrEventManager::_updateTimeoutForTimerForPendingEvents() +{ + //WENTER(); + // check if there is any request before timed out, if it's true, update the next timeout for update (x2) + if (_timeout == 0) { + _timeout = 2; + } else { + if (_timeout >= _timeoutMax) + _timeout = _timeoutMax; + else + _timeout *= 2; + } + WDEBUG("The next timeout = %d", _timeout); + _pendingEvents = false; +} + +void CDrEventManager::_resetTimeoutForTimerForPendingEvents() +{ + //WENTER(); + // reset the timeout and the pending flag + //WDEBUG("timeout(%d) will be reset", _timeout); + _timeout = 0; + _pendingEvents = false; +} diff --git a/src/EventManager/CDrEventManager.h b/src/EventManager/CDrEventManager.h new file mode 100755 index 0000000..c5926e0 --- /dev/null +++ b/src/EventManager/CDrEventManager.h @@ -0,0 +1,59 @@ +#ifndef _CDR_EVENT_MANAGER_H_ +#define _CDR_EVENT_MANAGER_H_ + +#include +#include +#include "WDefine.h" +#include "CDrSingleton.h" +#include "CDrEvent.h" +#include "CDrEventListener.h" +#include + +class WAPP_ASSIST_EXPORT CDrEventManager:public CDrSingleton < CDrEventManager > { + public: + void attach(CDrEventListener * listener); + void detach(CDrEventListener * listener); + bool isDetached(CDrEventListener * listener); + void block(CDrEventListener * listener); + void unblock(CDrEventListener * listener); + void notify(const CDrEvent & event); + void clear(); /*clear all listener */ + void suspend(); + void resume(); + + protected: + friend class CDrSingleton < CDrEventManager >; + CDrEventManager(); + ~CDrEventManager(); + private: + + WDISABLE_COPY_AND_ASSIGN(CDrEventManager); + private: + struct ListenerNode { + bool isBlocked; + CDrEvent *eventTable[CDrEvent::TYPE_MAX][CDrEvent::SOURCE_MAX]; + CDrEventListener *listener; + }; + + void _resetEventTable(ListenerNode * node); + void _addtoEventTable(ListenerNode * node, const CDrEvent & event); + void _notifyFromEventTable(ListenerNode * node); + void _notifyFromEventTable(ListenerNode * node, CDrEvent::ESource soruce); + void _clearEventTable(ListenerNode * node); + void _processTimerForPendingEvents(); + void _addTimerForPendingEvents(); + void _removeTimerForPendingEvents(); + int _getTimeoutForTimerForPendingEvents(); + void _updateTimeoutForTimerForPendingEvents(); + void _resetTimeoutForTimerForPendingEvents(); + + private: + std::map < CDrEventListener *, ListenerNode * >_listenerMap; + Ecore_Timer *_timerForPeindingEvents; + int _timeout; + int _timeoutMax; + bool _pendingEvents; + bool _isSuspended; +}; + +#endif /* _CVE_EVENT_MANAGER_H_ */ diff --git a/src/EventManager/CDrSingleton.h b/src/EventManager/CDrSingleton.h new file mode 100755 index 0000000..7f4c910 --- /dev/null +++ b/src/EventManager/CDrSingleton.h @@ -0,0 +1,34 @@ +#ifndef _CVE_SINGLETON_H_ +#define _CVE_SINGLETON_H_ + +#include "WDefine.h" + +template < typename TYPE > class WAPP_ASSIST_EXPORT CDrSingleton { + public: + static TYPE & getInstance() { + if (_instance == NULL) + _instance = new TYPE; + return *_instance; + }; + static void destroy() { + delete _instance; + _instance = NULL; + }; + + protected: + CDrSingleton() { + }; + virtual ~CDrSingleton() { + }; + + private: + CDrSingleton(const CDrSingleton & obj); + CDrSingleton & operator=(const CDrSingleton & obj); + + private: + static TYPE *_instance; +}; + +template < typename TYPE > TYPE * CDrSingleton < TYPE >::_instance = NULL; + +#endif /* _CVE_SINGLETON_H_ */ diff --git a/src/MediaDB/CDrMediaContent.cpp b/src/MediaDB/CDrMediaContent.cpp new file mode 100755 index 0000000..6af5905 --- /dev/null +++ b/src/MediaDB/CDrMediaContent.cpp @@ -0,0 +1,69 @@ +#include "CDrMediaContent.h" +#include "DrDefine.h" +#include + +CDrMediaContent *CDrMediaContent::_instance = NULL; + +CDrMediaContent::CDrMediaContent() +{ + _bMediaDBConnect = false; + if (!_mediaContentConnect()) { + WERROR("media content connnect failed"); + } +} + +CDrMediaContent::~CDrMediaContent() +{ + if (!_mediaContentDisconnect()) { + WERROR("media content disconnnect failed"); + } +} + +CDrMediaContent *CDrMediaContent::getInstance() +{ + if (_instance == NULL) { + _instance = new CDrMediaContent(); + } + + return _instance; +} + +void CDrMediaContent::destroyInstance() +{ + if (_instance != NULL) { + delete _instance; + _instance = NULL; + } +} + +bool CDrMediaContent::isMediaDbConnect() +{ + return _bMediaDBConnect; +} + +bool CDrMediaContent::_mediaContentConnect() +{ + int nRet = MEDIA_CONTENT_ERROR_NONE; + + nRet = media_content_connect(); + if (nRet != MEDIA_CONTENT_ERROR_NONE) { + WINFO("media_content_connect is fail : 0x%x", nRet); + return false; + } + _bMediaDBConnect = true; + return true; +} + +bool CDrMediaContent::_mediaContentDisconnect() +{ + int nRet = MEDIA_CONTENT_ERROR_NONE; + + nRet = media_content_disconnect(); + if (nRet != MEDIA_CONTENT_ERROR_NONE) { + WINFO("media_content_connect is fail : 0x%x", nRet); + return false; + } + _bMediaDBConnect = false; + return true; +} + diff --git a/src/MediaDB/CDrMediaContent.h b/src/MediaDB/CDrMediaContent.h new file mode 100755 index 0000000..3677447 --- /dev/null +++ b/src/MediaDB/CDrMediaContent.h @@ -0,0 +1,29 @@ +#ifndef _C_DR_MEDIACONTENT_H +#define _C_DR_MEDIACONTENT_H + +#include +#include + +class CDrMediaContent { + public: + static CDrMediaContent *getInstance(); + static void destroyInstance(); + + public: + bool isMediaDbConnect(); + //bool moveRenamedFileToDB(const char *szOldFilePath, const char *szNewFilePath); + //bool removeFileFromDB(std::string& strFile); + + private: + CDrMediaContent(); + ~CDrMediaContent(); + + bool _mediaContentConnect(); + bool _mediaContentDisconnect(); + + private: + static CDrMediaContent *_instance; + bool _bMediaDBConnect; +}; + +#endif diff --git a/src/Singleton.h b/src/Singleton.h new file mode 100644 index 0000000..ba19efe --- /dev/null +++ b/src/Singleton.h @@ -0,0 +1,51 @@ + +#ifndef FRSINGLETON_H_ +#define FRSINGLETON_H_ + +template < typename TYPE > class FRSingleton +{ +public: + static TYPE *getInstance() + { + if (__instance == NULL) + __instance = new TYPE; + return __instance; + }; + static void destroy() + { + if (__instance) + { + delete __instance; + } + __instance = NULL; + }; + + static TYPE *getInstanceWithoutNew() + { + return __instance; + }; + + static void setInstanceNULL() + { + __instance = NULL; + }; + +protected: + FRSingleton() + { + }; + virtual ~FRSingleton() + { + }; + +private: + FRSingleton(const FRSingleton & obj); + FRSingleton & operator = (const FRSingleton & obj); + +private: + static TYPE *__instance; +}; + +template < typename TYPE > TYPE * FRSingleton < TYPE >::__instance = NULL; + +#endif /* FRSINGLETON_H_ */ diff --git a/src/View/CDrMainView.cpp b/src/View/CDrMainView.cpp new file mode 100755 index 0000000..eebbef2 --- /dev/null +++ b/src/View/CDrMainView.cpp @@ -0,0 +1,795 @@ + +#include +#include "CDrMainView.h" +#include "DrDefine.h" +#include "CDrDrawingView.h" +#include "CDrAppData.h" +#include "CDrUtil.h" +#include "WWindowController.h" +#include "WNaviframeController.h" +#include "CDrClosePopup.h" +#include "WUiTimer.h" +#include "CDrStrokeView.h" +#include "CDrTutorialView.h" + + +#define COLOR_BG_SAME_PATH_NUMBER 10 + +CDrMainView::CDrMainView() +{ + _layout = nullptr; + _btnPalette = nullptr; + _drawingIcon = nullptr; + _rotarySelector = nullptr; + _animSave = nullptr; + _btnStroke = nullptr; + + _bSaveBtnShow = false; + _bIndicatorTextShow = true; + _bPalletShowed = false; + _bPalletButtonShowed = false; + _bTutorialShowing = false; + _bHistoryCtrlShow = false; + _nItemSelected = 8; + _dStrokeWidth = SAVE_MODE_STROKE_LINE_WIDTH; + + _palletIconNormalBgPath.push_back(DRAWING_MORE_OPTION_ICON_BG); + + _palletIconSelBgPath.push_back(DRAWING_MORE_OPTION_ICON_SELECTED_BG); + + _palletIconPath.push_back(DRAWING_PALLET_COLOR_PICKER_ERASER_ICON); + + _palletIconCenterPath.push_back(DRAWING_PALLET_COLOR_PICKER_SELECTOR_ICON); + + _palletIconName.push_back("Green"); + _palletIconName.push_back("Light Green"); + _palletIconName.push_back("Yellow"); + _palletIconName.push_back("Orange"); + _palletIconName.push_back("Red"); + _palletIconName.push_back("Pink"); + _palletIconName.push_back("Purple"); + _palletIconName.push_back("Blue"); + _palletIconName.push_back("Turquoise"); + _palletIconName.push_back("White"); + _palletIconName.push_back("Eraser"); + + _palletColorCode.push_back("AO040"); + _palletColorCode.push_back("AO041"); + _palletColorCode.push_back("AO042"); + _palletColorCode.push_back("AO043"); + _palletColorCode.push_back("AO044"); + _palletColorCode.push_back("AO045"); + _palletColorCode.push_back("AO046"); + _palletColorCode.push_back("AO047"); + _palletColorCode.push_back("AO048"); + _palletColorCode.push_back("AO049"); + _palletColorCode.push_back(""); +} + +CDrMainView::~CDrMainView() +{ + _stopSaveAnimation(); + _palletIconNormalBgPath.clear(); + _palletIconSelBgPath.clear(); + _palletIconPath.clear(); + _palletIconName.clear(); + _palletColorCode.clear(); + _palletIconCenterPath.clear(); +} + +Evas_Object * CDrMainView::onCreateView(Evas_Object * parent, void *viewParam) +{ + WENTER(); + + char* _path = app_get_resource_path(); + std::string path(_path); + path += EDJ_FILE; + + _layout = elm_layout_add(parent); + elm_layout_file_set(_layout, path.c_str(), "bg"); + free(_path); + evas_object_size_hint_weight_set(_layout, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_size_hint_align_set(_layout, EVAS_HINT_FILL, EVAS_HINT_FILL); + //evas_object_resize(_layout, 360, 360); + + if (CDrAppData::getInstance()->getLaunchMode() == DRAWING_SAVE) { + _createPalletButton(); + _createStrokeButton(); + } else { + #ifdef SKETCH_DRAW_COLORS_CHANGABLE + _createPalletButton(); + #endif + elm_object_signal_emit(_layout, "elm.state.pallet.button.sendmode", "*"); + } + + /* create history index */ + _cHistoryCtrl.createControl(_layout); + _showHistoryIndex(false); + + /* create draw sub view */ + CDrDrawingView* pDrawView = new (std::nothrow)CDrDrawingView(); + pDrawView->setHistoryControlHandle(&_cHistoryCtrl); + _controlManager.attach(_layout, pDrawView, "pre-view"); + + pDrawView->setShowSaveButtonCb([&](bool bShow){ + _showSaveButton(bShow); + }); + pDrawView->setDrawedCb([&](){ + _hideGuide(); + }); + pDrawView->setShowGuideCb([&](){ + _showGuide(); + }); + pDrawView->setHideGuideCb([&](){ + _hideGuide(); + }); + pDrawView->setShowHistoryIndexCb([&](bool bShow){ + _showHistoryIndex(bShow); + }); + pDrawView->setShowPanelCb([&](){ + _showPanel(); + }); + pDrawView->setUnRedoCb([&](bool bUndo){ + _updateTutorialView(bUndo); + }); + pDrawView->setStrokeWidth(_dStrokeWidth); + pDrawView->setColorCode(_palletColorCode[_nItemSelected]); + + if (CDrAppData::getInstance()->getLaunchMode() == DRAWING_SEND) { + //elm_object_part_text_set(_layout, "elm.txt.indicator", DRAWING_TEXT_SEND_DRAW_START_INDICATOR); + if (CDrUtil::isOperator("ATT")){ + elm_object_domain_translatable_part_text_set(_layout, "elm.txt.indicator", LOCALE_DOMAIN, DRAWING_STRING_ID_SEND_DRAW_START_INDICATOR_ATNT); + } else { + elm_object_domain_translatable_part_text_set(_layout, "elm.txt.indicator", LOCALE_DOMAIN, DRAWING_STRING_ID_SEND_DRAW_START_INDICATOR); + } + + elm_object_domain_translatable_part_text_set(_layout, "elm.txt.mms", LOCALE_DOMAIN, DRAWING_STRING_ID_MMS_TITLE_TEXT); + } else { + elm_object_part_text_set(_layout, "elm.txt.indicator", DRAWING_TEXT_SAVE_DRAW_START_INDICATOR); + } + + _showHistoryIndex(false); + elm_object_signal_emit(_layout, "elm.state.show.indicator", "*"); + _bPalletButtonShowed = true; + return _layout; +} + +void CDrMainView::_createPalletButton() +{ + char* share_path = app_get_resource_path(); + std::string drawing_icon_path(share_path); + drawing_icon_path += DRAWING_MORE_OPTIONS_ICON; + + _btnPalette = elm_button_add(_layout); + if (CDrAppData::getInstance()->getLaunchMode() == DRAWING_SEND) { + elm_object_signal_emit(_layout, "elm.state.pallet.button.sendmode", "*"); + elm_object_style_set(_btnPalette, DRAWING_BUTTON_SEND_MODE_STYLE); + } else { + elm_object_style_set(_btnPalette, DRAWING_BUTTON_SAVE_MODE_STYLE); + } + + _drawingIcon = elm_image_add(_btnPalette); + elm_image_resizable_set(_drawingIcon, EINA_TRUE, EINA_TRUE); + elm_image_file_set(_drawingIcon, drawing_icon_path.c_str(), NULL); + evas_object_size_hint_weight_set(_drawingIcon, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); +// ea_theme_object_color_set(_drawingIcon, _palletColorCode[_nItemSelected].c_str()); + elm_object_content_set(_btnPalette, _drawingIcon); + evas_object_size_hint_fill_set(_btnPalette, EVAS_HINT_FILL, EVAS_HINT_FILL); + evas_object_show(_drawingIcon); + free(share_path); + elm_object_part_content_set(_layout, "elm.button.pallet", _btnPalette); + evas_object_smart_callback_add(_btnPalette, "clicked", _onColorPickerBtnClicked, this); +} + +void CDrMainView::_createStrokeButton() +{ + char* share_path = app_get_resource_path(); + std::string drawing_icon_path(share_path); + drawing_icon_path += DRAWING_STROKE_OPTIONS_ICON; + + _btnStroke = elm_button_add(_layout); + elm_object_style_set(_btnStroke, DRAWING_BUTTON_SAVE_MODE_STYLE); + + //elm_object_style_set(_btnPalette, "fastscroll"); + Evas_Object *icon = elm_image_add(_btnStroke); + elm_image_resizable_set(icon, EINA_TRUE, EINA_TRUE); + elm_image_file_set(icon, drawing_icon_path.c_str(), NULL); + evas_object_size_hint_weight_set(icon, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); +// ea_theme_object_color_set(icon, _palletColorCode[_nItemSelected].c_str()); + elm_object_content_set(_btnStroke, icon); + evas_object_size_hint_fill_set(_btnStroke, EVAS_HINT_FILL, EVAS_HINT_FILL); + evas_object_show(icon); + free(share_path); + elm_object_part_content_set(_layout, "elm.button.stroke", _btnStroke); + evas_object_smart_callback_add(_btnStroke, "clicked", _onStrokeBtnClickCb, this); +} + +void CDrMainView::onCreated() +{ +} + +void CDrMainView::onDestroy() +{ + int x, y, w, h; + evas_object_geometry_get(_layout, &x, &y, &w, &h); + WINFO("x=%d y=%d W=%d H=%d", x, y, w, h); +} + +void CDrMainView::onPushed(Elm_Object_Item * naviItem) +{ + eext_object_event_callback_add(getEvasObj(), EEXT_CALLBACK_BACK, _onBackBtnClicked, this); +} + +Elm_Object_Item* CDrMainView::onPushToNaviframe(Evas_Object* naviFrame) +{ + Elm_Object_Item* item = elm_naviframe_item_push(naviFrame, getTitle(), nullptr, nullptr, getEvasObj(), "empty"); + return item; +} + +void CDrMainView::onEvent(const CDrEvent & event) +{ +} + +void CDrMainView::_showSaveButton(bool bShow) +{ + if (bShow && !_bSaveBtnShow && !_bPalletShowed) { + CDrDrawingView *pDrawingView = getControlObject < CDrDrawingView* >(_controlManager.find("pre-view")); + if (pDrawingView == nullptr) { + WERROR("pDrawingView none"); + return; + } + if (pDrawingView) { + if (pDrawingView->checkIsFirstHistory()) { + return; + } + } + + Evas_Object *btn = elm_object_part_content_unset(_layout, "elm.button.send"); + if (btn != NULL) { + evas_object_del(btn); + } + + char* res_path = app_get_resource_path(); + + btn = elm_button_add(_layout); + //elm_object_style_set(btn, "effect/default"); + elm_object_style_set(btn, "popup/circle"); + evas_object_size_hint_weight_set(btn, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + if (CDrAppData::getInstance()->getLaunchMode() == DRAWING_SEND) { + elm_object_domain_translatable_text_set(btn, LOCALE_DOMAIN, DRAWING_STRING_ID_TEXT_SEND); + } else { + elm_object_domain_translatable_text_set(btn, LOCALE_DOMAIN, DRAWING_TEXT_SAVE); + } + + evas_object_smart_callback_add(btn, "pressed", _onPressed, this); + evas_object_smart_callback_add(btn, "unpressed", _onUnPressed, this); + + elm_object_part_content_set(_layout, "elm.button.send", btn); + elm_layout_signal_emit(_layout, "elm,state,button,send.moveup", "elm"); + evas_object_show(btn); + free(res_path); + evas_object_smart_callback_add(btn, "clicked", _onSaveBtnClicked, this); + _bSaveBtnShow = true; + + /* show tutorial popup */ + if (pDrawingView && pDrawingView->checkHasHistory() && 0 == CDrAppData::getInstance()->getTutorialStatus()) { + CDrTutorialView *pTutorialView = getControlObject < CDrTutorialView* >(_controlManager.find("elm.swallow.tutorial")); + if (pTutorialView == nullptr) { + CDrTutorialView *pTutorialView = new(std::nothrow) CDrTutorialView(); + _controlManager.attach(_layout, pTutorialView, "elm.swallow.tutorial"); + if (pTutorialView == NULL) { + WERROR("CDrTutorialView new failed"); + return; + } + _bTutorialShowing = true; + CDrAppData::getInstance()->setTutorialStatus(1); + pTutorialView->showUndoGuide(); + pTutorialView->setOnCancelResult([&] () { + _bTutorialShowing = false; + WUiTimer::addJob([&](void *data) { + WINFO("Add job"); + CDrMainView * pThis = (CDrMainView *) data; + pThis->_updateTutorialView(false); + }, this, getEvasObj()); + }); + } + } + } else if (_bSaveBtnShow && !bShow) { + //elm_object_signal_emit(_layout, "elm.state.hide.mms", "*"); + elm_layout_signal_emit(_layout, "movedown,rect,button_send", "elm"); + Evas_Object *btn = elm_object_part_content_unset(_layout, "elm.button.send"); + if (btn != nullptr) { + evas_object_del(btn); + } + _bSaveBtnShow = false; + } +} + +void CDrMainView::_onPressed(void *data, Evas_Object * obj, void *event_info) +{ + WINFO("OnPressedCb"); + + Evas_Object *bg = elm_object_part_content_get(obj, "bg"); +// uxt_theme_object_set_color(bg, "AO029P"); + + Evas_Object *ic = elm_object_content_get(obj); +// uxt_theme_object_set_color(ic, "AO031P"); +} + +void CDrMainView::_onUnPressed(void *data, Evas_Object * obj, void *event_info) +{ + WINFO("OnUnPressedCb"); + + Evas_Object *bg = elm_object_part_content_get(obj, "bg"); +// uxt_theme_object_set_color(bg, "AO029"); + + Evas_Object *ic = elm_object_content_get(obj); +// uxt_theme_object_set_color(ic, "AO031"); +} + +void CDrMainView::_onSaveBtnClicked(void *data, Evas_Object * obj, void *event_info) +{ + CDrMainView* pThis = (CDrMainView*)data; + WINFO("save"); + std::string strFilePath; + + if (CDrAppData::getInstance()->getLaunchMode() == DRAWING_SEND) { + char* dataPath = app_get_shared_data_path(); + WINFO("dataPath = %s", dataPath); + if (dataPath == nullptr) { + WINFO("DATA path is null"); + return; + } + + strFilePath = dataPath; + free(dataPath); + + std::string strFileName ; + long long time = CDrUtil::getTimeStamp(); + CDrUtil::getTimeName(time, strFileName); + strFilePath += strFileName; + strFilePath += DRAWING_OUTPUT_FILE_FORMAT_MMS; + /* issue when send png thru MMS */ + //WSINFO("save path %s",strFilePath.c_str()); + } else { + strFilePath = DRAWING_SAVE_FILE_DIRECTORY; + std::string strFileName ; + long long time = CDrUtil::getTimeStamp(); + CDrUtil::getTimeName(time, strFileName); + strFilePath += strFileName; + strFilePath += DRAWING_OUTPUT_FILE_FORMAT_MMS; + //WSINFO("save path %s",strFilePath.c_str()); + } + pThis->_showSaveButton(false); + if (pThis->_bPalletShowed) { + pThis->_hideOption(); + } + /* fade out animation */ + pThis->_startSaveAnimation(); + + /* save image */ + CDrDrawingView *pDrawingView = getControlObject < CDrDrawingView* >(pThis->_controlManager.find("pre-view")); + if (pDrawingView) { + if (CDrAppData::getInstance()->getLaunchMode() == DRAWING_SEND) { + /* Save to temp directory & send it */ + pDrawingView->saveImage(strFilePath, false); + pThis->_sendImage(strFilePath); + } else { + /* Save on media storage & register file in media db */ + pDrawingView->saveImage(strFilePath, true); + } + } +} + +void CDrMainView::_sendImage(std::string strFilePath) +{ + app_control_h reply = NULL; + if (app_control_create(&reply) != APP_CONTROL_ERROR_NONE) { + WERROR("app_control_create failed!"); + return; + } + app_control_h appService = CDrAppData::getInstance()->getAppService(); + + int ret = app_control_add_extra_data(reply, APP_CONTROL_DATA_PATH, strFilePath.c_str()); + if (ret != APP_CONTROL_ERROR_NONE) { + WERROR("add return file failed!"); + } + if (strFilePath.empty()) { + ret = app_control_reply_to_launch_request(reply, appService, + APP_CONTROL_RESULT_FAILED); + app_control_destroy(reply); + } else { + ret = app_control_reply_to_launch_request(reply, appService, + APP_CONTROL_RESULT_SUCCEEDED); + app_control_destroy(reply); + } + if (ret != 0) { + WERROR("send file failed!"); + } else { + WINFO("send file successfully!"); + } +} + +void CDrMainView::_hideGuide() +{ + if (_bIndicatorTextShow) { + elm_object_signal_emit(_layout, "elm.state.hide.indicator", "*"); + _bIndicatorTextShow = false; + _bPalletButtonShowed = false; + + CDrDrawingView *pDrawingView = getControlObject < CDrDrawingView* >(_controlManager.find("pre-view")); + if (pDrawingView) { + if (pDrawingView->checkIsFirstHistory() && !pDrawingView->checkHasHistory()) { + _showHistoryIndex(true); + } + } + } +} + +void CDrMainView::_showGuide() +{ + if (!_bIndicatorTextShow) { + elm_object_signal_emit(_layout, "elm.state.show.indicator", "*"); + _bIndicatorTextShow = true; + _bPalletButtonShowed = true; + } +} + +void CDrMainView::_onBackBtnClicked(void *data, Evas_Object * obj, void *eventInfo) +{ + WENTER(); + CDrMainView *pThis = (CDrMainView *) data; + if (pThis->_bPalletShowed) { + pThis->_hideOption(); + return; + } + if (pThis->_bTutorialShowing) { + pThis->_updateTutorialView(false); + return; + } + CDrDrawingView *pDrawingView = getControlObject < CDrDrawingView* >(pThis->_controlManager.find("pre-view")); + if (pDrawingView == nullptr) { + return; + } + if (!pDrawingView->checkHasHistory()) { + pThis->_exitView(); + return; + } + + CDrClosePopup *pClosePopup = new(std::nothrow) CDrClosePopup(); + if (pClosePopup == NULL) { + WERROR("Close popup new failed"); + return; + } + pClosePopup->setCaption(DRAWING_POPUP_DISCARD_TITLE); + pClosePopup->setOnDiscardResult([pThis] () { + pThis->_exitView(); + }); + pClosePopup->setOnCancelResult([pThis] () { + CDrDrawingView *pDrawingView = getControlObject < CDrDrawingView* >(pThis->_controlManager.find("pre-view")); + if (pDrawingView) { + pDrawingView->activateUpdateAnimator(true); + pDrawingView->activateUndoRedoRotary(true); + } + }); + pDrawingView->activateUndoRedoRotary(false); + pDrawingView->activateUpdateAnimator(false); + pThis->attachPopup(pClosePopup); +} + +void CDrMainView::_exitView() +{ + this->popOut(); +} + +void CDrMainView::_onColorPickerBtnClicked(void *data, Evas_Object *obj, void *event_info) +{ + WINFO("_onColorPickerBtnClicked"); + + CDrMainView * pThis = (CDrMainView*)data; + pThis->_hideGuide(); + + pThis->_showOption(); +} + +void CDrMainView::_showOption() +{ + elm_object_signal_emit(_layout, "elm.state.hide.btnpallet", "*"); + elm_object_signal_emit(_layout, "show,pallet,view", "elm"); + + if (_rotarySelector == nullptr) { + _createOptionLayout(); + } + eext_rotary_object_event_activated_set(_rotarySelector, EINA_TRUE); + + _showSaveButton(false); + _bPalletShowed = true; + CDrDrawingView *pDrawingView = getControlObject < CDrDrawingView* >(_controlManager.find("pre-view")); + if (pDrawingView) { + pDrawingView->setColorMenuState(_bPalletShowed); + } +} +void CDrMainView::_hideOption() +{ + elm_object_signal_emit(_layout, "hide,pallet,view", "elm"); + _bPalletShowed = false; + CDrDrawingView *pDrawingView = getControlObject < CDrDrawingView* >(_controlManager.find("pre-view")); + if (pDrawingView) { + pDrawingView->setColorMenuState(_bPalletShowed); + } + + eext_rotary_object_event_activated_set(_rotarySelector, EINA_FALSE); +} + +void CDrMainView::_createOptionLayout() +{ + _rotarySelector = eext_rotary_selector_add(_layout); + evas_object_size_hint_fill_set(_rotarySelector, EVAS_HINT_FILL, EVAS_HINT_FILL); + evas_object_size_hint_weight_set(_rotarySelector, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + + evas_object_smart_callback_add(_rotarySelector, "item,selected", _onRotarySelectorItemSelected, this); + evas_object_smart_callback_add(_rotarySelector, "item,clicked", _onRotarySelectorItemClicked, this); + + _addSelectorItem(); + eext_rotary_object_event_activated_set(_rotarySelector, EINA_TRUE); + + evas_object_show(_rotarySelector); + WUiTimer::addTimer(0.1, [&](void *data)->Eina_Bool { + const Eina_List *list = eext_rotary_selector_items_get(_rotarySelector); + if (list) { + Eext_Object_Item *curItem = (Eext_Object_Item *)eina_list_nth(list, _nItemSelected); + if (curItem) { + WINFO("set item"); + eext_rotary_selector_selected_item_set(_rotarySelector, curItem); + } + } + return EINA_FALSE; + }, this); + + + elm_object_part_content_set(_layout, "circle_menu", _rotarySelector); + WLEAVE(); +} + +void CDrMainView::_addSelectorItem() +{ + char* share_path = app_get_resource_path(); + std::string iconPath(share_path); + + for (int i = 0; i < _palletColorCode.size(); i++) { + Eext_Object_Item *item = eext_rotary_selector_item_append(_rotarySelector); + + // normal item bg img + iconPath = share_path; + if (i <= COLOR_BG_SAME_PATH_NUMBER) { + iconPath += _palletIconNormalBgPath[0]; + } + WINFO("normal img %s", iconPath.c_str()); + + Evas_Object* icon = elm_image_add(_rotarySelector); + elm_image_file_set(icon, iconPath.c_str(), NULL); + + int code_r = 0, code_g = 0, code_b = 0, code_a = 255; + + edje_color_class_get(_palletColorCode[i].c_str(), &code_r, &code_g, &code_b, &code_a, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); + if (i == COLOR_BG_SAME_PATH_NUMBER) { + code_r = 255; + code_g = 255; + code_b = 255; + code_a = 255; + } + + WINFO("%d %d %d %d", code_r, code_g, code_b, code_a); + evas_object_color_set(icon, code_r, code_g, code_b, code_a); + eext_rotary_selector_item_part_content_set(item, "item,bg_image", EEXT_ROTARY_SELECTOR_ITEM_STATE_NORMAL, icon); + + //selected item bg img + Evas_Object* iconSelected = elm_image_add(_rotarySelector); + iconPath = share_path; + if (i <= COLOR_BG_SAME_PATH_NUMBER) { + iconPath += _palletIconSelBgPath[0]; + } + elm_image_file_set(iconSelected, iconPath.c_str(), NULL); + + code_r = 0; + code_g = 0; + code_b = 0; + code_a = 255; + edje_color_class_get(_palletColorCode[i].c_str(), &code_r, &code_g, &code_b, &code_a, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); + if (i == COLOR_BG_SAME_PATH_NUMBER) { + code_r = 255; + code_g = 255; + code_b = 255; + code_a = 255; + } + evas_object_color_set(iconSelected, code_r, code_g, code_b, code_a); + eext_rotary_selector_item_part_content_set(item, "item,bg_image", EEXT_ROTARY_SELECTOR_ITEM_STATE_PRESSED, iconSelected); + + //item icon + if (i == COLOR_BG_SAME_PATH_NUMBER) { + Evas_Object* iconEraser = elm_image_add(_rotarySelector); + iconPath = share_path; + iconPath += _palletIconPath[0]; + + elm_image_file_set(iconEraser, iconPath.c_str(), NULL); + eext_rotary_selector_item_part_content_set(item, "item,icon", EEXT_ROTARY_SELECTOR_ITEM_STATE_NORMAL, iconEraser); + } + + //center part + Evas_Object *img = elm_image_add(_rotarySelector); + iconPath = share_path; + if (i < COLOR_BG_SAME_PATH_NUMBER) { + iconPath += _palletIconCenterPath[0]; + } + elm_image_file_set(img, iconPath.c_str(), NULL); + + if (i != COLOR_BG_SAME_PATH_NUMBER) { + int code_r = 0, code_g = 0, code_b = 0, code_a = 255; + int r, g, b, a; + edje_color_class_get(_palletColorCode[i].c_str(), &code_r, &code_g, &code_b, &code_a, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); + evas_object_color_set(img, code_r, code_g, code_b, code_a); + eext_rotary_selector_item_part_content_set(item, "selector,icon", EEXT_ROTARY_SELECTOR_ITEM_STATE_NORMAL, img); + } else { + eext_more_option_item_domain_translatable_part_text_set(item, "selector,main_text", textdomain(NULL), "Eraser"); + } + } + + free(share_path); +} + +void CDrMainView::_onRotarySelectorItemSelected(void *data, Evas_Object *obj, void *event_info) +{ + WENTER(); +} + +void CDrMainView::_onRotarySelectorItemClicked(void *data, Evas_Object *obj, void *event_info) +{ + WENTER(); + CDrMainView *pThis = (CDrMainView *) data; + + const Eina_List *rotary_selector_list = eext_rotary_selector_items_get(obj); + + int i = 0; + Eina_List *l = NULL; + void *item = NULL; + + EINA_LIST_FOREACH((Eina_List *)rotary_selector_list, l, item) { + if (event_info == item) + { + break; + } + i++; + } + + pThis->_nItemSelected = i; +// ea_theme_object_color_set(pThis->_drawingIcon, pThis->_palletColorCode[pThis->_nItemSelected].c_str()); + CDrDrawingView *pDrawingView = getControlObject < CDrDrawingView* >(pThis->_controlManager.find("pre-view")); + if (pDrawingView) { + pDrawingView->setColorCode(pThis->_palletColorCode[pThis->_nItemSelected]); + } + + pThis->_hideOption(); +} + +void CDrMainView::_onStrokeBtnClickCb(void *data, Evas_Object *obj, void *event_info) +{ + WINFO("strokeButtonClickCb"); + + CDrMainView * pThis = (CDrMainView*)data; + WNaviframeController *naviframe = (WNaviframeController *) (CDrAppData::getInstance()->getWindowController()->getBaseViewController()); + if (naviframe == nullptr) { + return; + } + WINFO("stroke width %.1f", pThis->_dStrokeWidth); + elm_object_signal_emit(pThis->_layout, "elm.state.hide.btnpallet", "*"); + + CDrStrokeView* pView = new CDrStrokeView(); + pView->setStrokeWidth(pThis->_dStrokeWidth); + pView->setStrokeWidthCb([pThis](double dWidth) { + pThis->_dStrokeWidth = dWidth; + WINFO("stroke width %.1f", pThis->_dStrokeWidth); + + CDrDrawingView *pDrawingView = getControlObject < CDrDrawingView* >(pThis->_controlManager.find("pre-view")); + if (pDrawingView) { + pDrawingView->setStrokeWidth(dWidth); + } + }); + naviframe->push(pView, "StrokeView"); +} + +void CDrMainView::_showPanel() +{ + WINFO("Panel"); + if (_btnPalette == nullptr && _btnStroke == nullptr) { + return; + } + if (!_bPalletButtonShowed && !_bPalletShowed) { + WINFO("show Panel"); + + elm_object_signal_emit(_layout, "elm.state.show.btnpallet", "*"); + + _bPalletButtonShowed = true; + + } else if (_bPalletButtonShowed ) { + WINFO("hide Panel"); + + elm_object_signal_emit(_layout, "elm.state.hide.btnpallet", "*"); + + _bPalletButtonShowed = false; + } +} + +void CDrMainView::_startSaveAnimation() +{ + _stopSaveAnimation(); + + ecore_animator_frametime_set(1.0 /60); + _animSave = ecore_animator_timeline_add(0.75, _onAnimatorSave, this); +} +void CDrMainView::_stopSaveAnimation() +{ + if (_animSave) { + ecore_animator_del(_animSave); + _animSave = nullptr; + } +} + +Eina_Bool CDrMainView::_onAnimatorSave(void *data, double pos) +{ + CDrMainView *pThis = (CDrMainView *) data; + + if (pos == 1) { + CDrDrawingView *pDrawingView = getControlObject < CDrDrawingView* >(pThis->_controlManager.find("pre-view")); + if (pDrawingView != nullptr) { + pDrawingView->activateUndoRedoRotary(false); + } + + /* animation end,exit app */ + WINFO("exit "); + pThis->_exitView(); + + pThis->_animSave = nullptr; + + return ECORE_CALLBACK_DONE; + } else { + /* update fade out effect */ + int alpha = 255 * (1 - pos); + pThis->_saveAnimationUpdate(alpha); + + return ECORE_CALLBACK_RENEW; + } +} + +void CDrMainView::_saveAnimationUpdate(int nStep) +{ + CDrDrawingView *pDrawingView = getControlObject < CDrDrawingView* >(_controlManager.find("pre-view")); + if (pDrawingView) { + pDrawingView->saveAnimationUpdate(nStep); + } +} + +void CDrMainView::_showHistoryIndex(bool bShow) +{ + if (bShow && !_bHistoryCtrlShow) { + elm_object_signal_emit(_layout, "elm.state.show.index.mms", "*"); + _bHistoryCtrlShow = true; + } else if (!bShow && _bHistoryCtrlShow) { + elm_object_signal_emit(_layout, "elm.state.hide.index", "*"); + _bHistoryCtrlShow = false; + } +} + +void CDrMainView::_updateTutorialView(bool bUndo) +{ + CDrTutorialView *pTutorialView = getControlObject < CDrTutorialView* >(_controlManager.find("elm.swallow.tutorial")); + if (pTutorialView != nullptr) { + WENTER(); + if (bUndo) { + pTutorialView->showRedoGuide(); + } else { + _controlManager.detach(_layout, "elm.swallow.tutorial"); + _bTutorialShowing = false; + } + } +} + diff --git a/src/View/CDrMainView.h b/src/View/CDrMainView.h new file mode 100755 index 0000000..d625c27 --- /dev/null +++ b/src/View/CDrMainView.h @@ -0,0 +1,99 @@ +#ifndef _CDR_MAIN_VIEW_H_ +#define _CDR_MAIN_VIEW_H_ + + +#include +#include +#include +#include +//#include +#include +//#include +#include +#include +#include +//#include +#include "WContentViewController.h" +#include "CDrEventListener.h" +#include "CDrControlManager.h" +#include "CDrHistoryControl.h" + + +using namespace app_assist; + + + +class CDrMainView: public WContentViewController, public CDrEventListener { +public: + CDrMainView(); + + void onEvent(const CDrEvent & event); + + virtual Evas_Object * onCreateView(Evas_Object * parent, void *viewParam); + virtual void onDestroy(); + virtual void onPushed(Elm_Object_Item * naviItem); + virtual Elm_Object_Item* onPushToNaviframe(Evas_Object* naviFrame); + void onCreated(); + +protected: + + virtual ~CDrMainView(); +private: + void _showSaveButton(bool bShow); + + static void _onPressed(void *data, Evas_Object * obj, void *event_info); + static void _onUnPressed(void *data, Evas_Object * obj, void *event_info); + static void _onSaveBtnClicked(void *data, Evas_Object * obj, void *event_info); + static void _onBackBtnClicked(void *data, Evas_Object * obj, void *eventInfo); + static void _onColorPickerBtnClicked(void *data, Evas_Object *obj, void *event_info); + static void _onRotarySelectorItemClicked(void *data, Evas_Object *obj, void *event_info); + static void _onRotarySelectorItemSelected(void *data, Evas_Object *obj, void *event_info); + static Eina_Bool _onAnimatorSave(void *data, double pos); + static void _onStrokeBtnClickCb(void *data, Evas_Object *obj, void *event_info); + + void _sendImage(std::string strFilePath); + void _hideGuide(); + void _showGuide(); + void _exitView(); + void _createPalletButton(); + void _createOptionLayout(); + void _createStrokeButton(); + void _addSelectorItem(); + void _showOption(); + void _hideOption(); + void _showPanel(); + void _startSaveAnimation(); + void _stopSaveAnimation(); + void _saveAnimationUpdate(int nStep); + void _showHistoryIndex(bool bShow); + void _updateTutorialView(bool bUndo); + + +private: + Evas_Object *_layout; + Evas_Object* _btnPalette; + Evas_Object* _drawingIcon; + Evas_Object *_rotarySelector; + Ecore_Animator *_animSave; + Evas_Object *_btnStroke; + + CDrControlManager _controlManager; + CDrHistoryControl _cHistoryCtrl; + bool _bSaveBtnShow; + bool _bIndicatorTextShow; + bool _bPalletShowed; + bool _bPalletButtonShowed; + bool _bTutorialShowing; + bool _bHistoryCtrlShow; + int _nItemSelected; + double _dStrokeWidth; + + std::vector _palletIconNormalBgPath; + std::vector _palletIconSelBgPath; + std::vector _palletIconPath; + std::vector _palletIconCenterPath; + std::vector _palletIconName; + std::vector _palletColorCode; +}; +#endif /* _CDR_MAIN_VIEW_H_ end */ + diff --git a/src/View/CDrStrokeView.cpp b/src/View/CDrStrokeView.cpp new file mode 100755 index 0000000..637a4d5 --- /dev/null +++ b/src/View/CDrStrokeView.cpp @@ -0,0 +1,299 @@ + +#include +#include "CDrStrokeView.h" +#include "DrDefine.h" +#include "CDrAppData.h" +#include "CDrUtil.h" + + +#define STROKE_LINE_WIDTH_LEVEL_MIN 2.0 +#define STROKE_LINE_WIDTH_LEVEL_MAX 10.0 + +CDrStrokeView::CDrStrokeView() +{ + _layout = nullptr; + _strokeSlider = nullptr; + _circleSurface = nullptr; + _plusButton = nullptr; + _minusButton = nullptr; + _setStrokeWidthCb = nullptr; + _levelIndex = 3.0; +} + +CDrStrokeView::~CDrStrokeView() +{ +} + +Evas_Object * CDrStrokeView::onCreateView(Evas_Object * parent, void *viewParam) +{ + WENTER(); + + char* _path = app_get_resource_path(); + std::string path(_path); + path += EDJ_FILE; + + _layout = elm_layout_add(parent); + elm_layout_file_set(_layout, path.c_str(), "drawing/stroke_layout/circle"); + free(_path); + evas_object_size_hint_weight_set(_layout, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_size_hint_align_set(_layout, EVAS_HINT_FILL, EVAS_HINT_FILL); + + + WNaviframeController *naviframe = (WNaviframeController *) (CDrAppData::getInstance()->getWindowController()->getBaseViewController()); + if (naviframe == nullptr) { + return _layout; + } + _circleSurface = eext_circle_surface_naviframe_add(naviframe->getEvasObj() ); + + _strokeSlider = eext_circle_object_slider_add(_layout, _circleSurface); + eext_circle_object_value_min_max_set(_strokeSlider, STROKE_LINE_WIDTH_LEVEL_MIN, STROKE_LINE_WIDTH_LEVEL_MAX); /* Outdoor mode UI removed temporary(07/07) */ + eext_circle_object_value_set(_strokeSlider, _levelIndex); + eext_rotary_object_event_activated_set(_strokeSlider, EINA_TRUE); +// uxt_slider_set_touch_enabled(_strokeSlider, EINA_TRUE); + elm_layout_content_set(_layout, "elm.swallow.content", _strokeSlider); + + evas_object_smart_callback_add(_strokeSlider, "value,changed", _strokeRotaryChanged, this); + + evas_object_smart_callback_add(_strokeSlider, "clicked", _strokeSliderClicked, this); + + evas_object_smart_callback_add(_layout, "language,changed", _strokeLanguageChanged, this); + + _createPlusMinusButton(); + + std::string strLevel; + char text[100]; + memset(text, 0, 100); + snprintf(text, sizeof(text), "%.1f", _levelIndex); + strLevel = text; + WINFO("%s", strLevel.c_str()); + elm_object_part_text_set(_layout, "elm.text", strLevel.c_str()); + elm_object_part_text_set(_layout, "elm.text.title", "stroke width"); + + return _layout; +} + +void CDrStrokeView::onCreated() +{ +} + +void CDrStrokeView::onDestroy() +{ +} + +void CDrStrokeView::onPushed(Elm_Object_Item * naviItem) +{ + eext_object_event_callback_add(getEvasObj(), EEXT_CALLBACK_BACK, _backButtonClickedCb, this); +} + +Elm_Object_Item* CDrStrokeView::onPushToNaviframe(Evas_Object* naviFrame) +{ + Elm_Object_Item* item = elm_naviframe_item_push(naviFrame, getTitle(), nullptr, nullptr, getEvasObj(), "empty"); + return item; +} + +void CDrStrokeView::onEvent(const CDrEvent & event) +{ +} + +void CDrStrokeView::setStrokeWidth(double dWidth) +{ + _levelIndex = dWidth; +} + +void CDrStrokeView::setStrokeWidthCb(std::function < void(double) > handlerFunc) +{ + _setStrokeWidthCb = handlerFunc; +} + +void CDrStrokeView::_backButtonClickedCb(void *data, Evas_Object * obj, void *eventInfo) +{ + WENTER(); + CDrStrokeView *pThis = (CDrStrokeView *) data; + pThis->_exitView(); +} + +void CDrStrokeView::_exitView() +{ + this->popOut(); +} + +void CDrStrokeView::_createPlusMinusButton() +{ + char* resPath = app_get_resource_path(); + std::string path(resPath); + + _minusButton = elm_button_add(_layout); + elm_object_style_set(_minusButton, "drawing/stroke_effect/default"); + evas_object_size_hint_weight_set(_minusButton, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + elm_object_part_content_set(_layout, "btn.minus", _minusButton); + evas_object_smart_callback_add(_minusButton, "clicked", _minusButtonCb, this); + + elm_access_info_set(_minusButton, ELM_ACCESS_INFO, "Minus"); + + Evas_Object* icon = elm_image_add(_minusButton); + elm_image_resizable_set(icon, EINA_FALSE, EINA_FALSE); + path += DRAWING_STROKE_SLIDER_ICON_MINUS; + elm_image_file_set(icon, path.c_str(), nullptr); + evas_object_size_hint_weight_set(icon, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + elm_object_content_set(_minusButton, icon); + evas_object_show(icon); + + _plusButton = elm_button_add(_layout); + elm_object_style_set(_plusButton, "drawing/stroke_effect/default"); + evas_object_size_hint_weight_set(_plusButton, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + elm_object_part_content_set(_layout, "btn.plus", _plusButton); + evas_object_smart_callback_add(_plusButton, "clicked", _plusButtonCb, this); + + elm_access_info_set(_plusButton, ELM_ACCESS_INFO, "Plus"); + + Evas_Object* icon2 = elm_image_add(_plusButton); + path = resPath; + path += DRAWING_STROKE_SLIDER_ICON_PLUS; + //WINFO("- PATH %s",path.c_str()); + elm_image_file_set(icon2, path.c_str(), nullptr); + elm_image_resizable_set(icon2, EINA_FALSE, EINA_FALSE); + evas_object_size_hint_weight_set(icon2, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + elm_object_content_set(_plusButton, icon2); + evas_object_show(icon2); + free(resPath); + + if (_levelIndex == STROKE_LINE_WIDTH_LEVEL_MAX ) { + elm_object_disabled_set(_plusButton, EINA_TRUE); + //edje_object_signal_emit(elm_layout_edje_get(_layout), "elm,state,disabled", "elm"); + } else if (_levelIndex == STROKE_LINE_WIDTH_LEVEL_MIN ) { + elm_object_disabled_set(_minusButton, EINA_TRUE); + } +} + +void CDrStrokeView::_strokeRotaryChanged(void *data, Evas_Object *obj, void *event_info) +{ + CDrStrokeView* pThis = (CDrStrokeView*)data; + + double circle_level = eext_circle_object_value_get(obj); + WINFO("circle level: %.1f", circle_level); + + /* Update level text */ + std::string strLevel; + char text[100]; + memset(text, 0, 100); + snprintf(text, sizeof(text), "%.1f", circle_level); + strLevel = text; + elm_object_part_text_set(pThis->_layout, "elm.text", strLevel.c_str()); + + if(circle_level == pThis->_levelIndex) + { + WINFO("same with old value"); + return; + } + + //setting_display_update_brightness_icon(bd->brightness_layout, circle_level); + pThis->_levelIndex = circle_level; + + if (pThis->_levelIndex == STROKE_LINE_WIDTH_LEVEL_MIN) { + elm_object_disabled_set(pThis->_minusButton, EINA_TRUE); + elm_object_disabled_set(pThis->_plusButton, EINA_FALSE); + } else if (pThis->_levelIndex == STROKE_LINE_WIDTH_LEVEL_MAX) { + elm_object_disabled_set(pThis->_minusButton, EINA_FALSE); + elm_object_disabled_set(pThis->_plusButton, EINA_TRUE); + } else { + elm_object_disabled_set(pThis->_minusButton, EINA_FALSE); + elm_object_disabled_set(pThis->_plusButton, EINA_FALSE); + } + /* set to drawing part */ + if (pThis->_setStrokeWidthCb) { + pThis->_setStrokeWidthCb(pThis->_levelIndex); + } +} +void CDrStrokeView::_strokeSliderClicked(void *data, Evas_Object *obj, void *event_info) +{ +} +void CDrStrokeView::_strokeLanguageChanged(void *data, Evas_Object *obj, void *event_info) +{ +} + +void CDrStrokeView::_plusButtonCb(void* data, Evas_Object* obj, void* event_info) +{ + CDrStrokeView* pThis = (CDrStrokeView*)data; + + double level = eext_circle_object_value_get(pThis->_strokeSlider); + if(level > STROKE_LINE_WIDTH_LEVEL_MAX) { + return; + } + + double circle_level = level + 1; + /* set to drawing part */ + if (pThis->_setStrokeWidthCb) { + pThis->_setStrokeWidthCb(circle_level); + } + + /* Update level text */ + std::string strLevel; + char text[100]; + memset(text, 0, 100); + snprintf(text, sizeof(text), "%.1f", circle_level); + strLevel = text; + elm_object_part_text_set(pThis->_layout, "elm.text", strLevel.c_str()); + + //if(uxt_slider_set_value(pThis->_strokeSlider, (double)(eext_circle_object_value_get(pThis->_strokeSlider) + 1.0), EINA_TRUE) != UXT_ERROR_NONE) + { + WERROR("uxt_slider_set_value is fail!"); + } + + //setting_display_update_brightness_icon(bd->brightness_layout, circle_level); + + pThis->_levelIndex = circle_level; + + elm_object_disabled_set(pThis->_minusButton, EINA_FALSE); + + if(pThis->_plusButton) + { + if(circle_level == STROKE_LINE_WIDTH_LEVEL_MAX) + elm_object_disabled_set(pThis->_plusButton, EINA_TRUE); + else + elm_object_disabled_set(pThis->_plusButton, EINA_FALSE); + } +} +void CDrStrokeView::_minusButtonCb(void* data, Evas_Object* obj, void* event_info) +{ + CDrStrokeView* pThis = (CDrStrokeView*)data; + + double level = eext_circle_object_value_get(pThis->_strokeSlider); + if(level < STROKE_LINE_WIDTH_LEVEL_MIN) { + return; + } + + double circle_level = level - 1; + /* set to drawing part */ + if (pThis->_setStrokeWidthCb) { + pThis->_setStrokeWidthCb(circle_level); + } + + /* Update level text */ + std::string strLevel; + char text[100]; + memset(text, 0, 100); + snprintf(text, sizeof(text), "%.1f", circle_level); + strLevel = text; + elm_object_part_text_set(pThis->_layout, "elm.text", strLevel.c_str()); + + //if(uxt_slider_set_value(pThis->_strokeSlider, (double)(eext_circle_object_value_get(pThis->_strokeSlider) - 1.0), EINA_TRUE) != UXT_ERROR_NONE) + { + WERROR("uxt_slider_set_value is fail!"); + } + + //setting_display_update_brightness_icon(bd->brightness_layout, circle_level); + + pThis->_levelIndex = circle_level; + + elm_object_disabled_set(pThis->_plusButton, EINA_FALSE); + + if(pThis->_minusButton) + { + if(circle_level == STROKE_LINE_WIDTH_LEVEL_MIN) + elm_object_disabled_set(pThis->_minusButton, EINA_TRUE); + else + elm_object_disabled_set(pThis->_minusButton, EINA_FALSE); + } +} + + diff --git a/src/View/CDrStrokeView.h b/src/View/CDrStrokeView.h new file mode 100755 index 0000000..5211f8d --- /dev/null +++ b/src/View/CDrStrokeView.h @@ -0,0 +1,64 @@ +#ifndef _CDR_STROKE_VIEW_H_ +#define _CDR_STROKE_VIEW_H_ + + +#include +#include +#include +#include +//#include +#include +//#include +#include +#include +#include +#include "WContentViewController.h" +#include "CDrEventListener.h" +#include "CDrControlManager.h" + + +using namespace app_assist; + + + +class CDrStrokeView: public WContentViewController, public CDrEventListener { +public: + CDrStrokeView(); + + void onEvent(const CDrEvent & event); + + virtual Evas_Object * onCreateView(Evas_Object * parent, void *viewParam); + virtual void onDestroy(); + virtual void onPushed(Elm_Object_Item * naviItem); + virtual Elm_Object_Item* onPushToNaviframe(Evas_Object* naviFrame); + void onCreated(); + void setStrokeWidthCb(std::function < void(double) > handlerFunc); + void setStrokeWidth(double dWidth); + +protected: + + virtual ~CDrStrokeView(); +private: + static void _backButtonClickedCb(void *data, Evas_Object * obj, void *eventInfo); + static void _strokeRotaryChanged(void *data, Evas_Object *obj, void *event_info); + static void _strokeSliderClicked(void *data, Evas_Object *obj, void *event_info); + static void _strokeLanguageChanged(void *data, Evas_Object *obj, void *event_info); + static void _plusButtonCb(void* data, Evas_Object* obj, void* event_info); + static void _minusButtonCb(void* data, Evas_Object* obj, void* event_info); + void _exitView(); + void _createPlusMinusButton(); + +private: + Evas_Object *_layout; + Evas_Object* _strokeSlider; + Evas_Object* _plusButton; + Evas_Object *_minusButton; + Eext_Circle_Surface *_circleSurface; + CDrControlManager _controlManager; + + double _levelIndex; + + std::function < void(double) > _setStrokeWidthCb; +}; +#endif /* _CDR_MAIN_VIEW_H_ end */ + diff --git a/src/app-assist-efl/WApp.cpp b/src/app-assist-efl/WApp.cpp new file mode 100644 index 0000000..dd6e7a5 --- /dev/null +++ b/src/app-assist-efl/WApp.cpp @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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 "WApp.h" + +#include + +#include "WDebugInternal.h" +#include "WWindowController.h" +#include "WMenuPopupControllerImpl.h" + +using namespace app_assist; + +namespace app_assist +{ + +class _WAppImpl +{ +public: + _WAppImpl(): __window(nullptr), __firstLaunch(true) {} + ~_WAppImpl(); +public: + WWindowController* __window; + bool __firstLaunch; + // + static bool __onCreate(void* data); + static void __onTerminate(void* data); + static void __onPause(void* data); + static void __onResume(void* data); + static void __onAppControl(app_control_h request, void* data); +}; +} + +_WAppImpl::~_WAppImpl() +{ +} + +bool _WAppImpl::__onCreate(void* data) +{ + WHIT(); + + auto app = (WApp*)data; + return app->onCreate(); +} + +void _WAppImpl::__onTerminate(void* data) +{ + WHIT(); + + auto app = (WApp*)data; + app->onTerminate(); + + // To reverse destruction order + // It will destroy View and then Naviframe instance before the window is destroyed. + if (app->__pv->__window) + app->__pv->__window->destroyBaseViewController(); + + // window evas object "del" callback will be called by system. +} + +void _WAppImpl::__onPause(void* data) +{ + WHIT(); + + _WMenuPopupControllerImpl::destroyLastMenuPopup(); + + auto app = (WApp*)data; + app->onPause(); +} + +void _WAppImpl::__onResume(void* data) +{ + WHIT(); + + auto app = (WApp*)data; + app->onResume(); +} + +void _WAppImpl::__onAppControl(app_control_h request, void* data) +{ + WHIT(); + + auto app = (WApp*)data; + app->onAppControl(request, app->__pv->__firstLaunch); + // + app->__pv->__firstLaunch = false; +} + + +WApp::WApp() +{ + WDEBUG("app-assist version=%s", WVersion_get()); + + __pv = new _WAppImpl(); +} + +WApp::~WApp() +{ + WHIT(); + delete __pv; +} + +int WApp::start(int argc, char* argv[]) +{ + return onStart(argc, argv); +} + +app_assist::WWindowController* WApp::getWindowController() +{ + return __pv->__window; +} + +bool WApp::attachWindowController(app_assist::WWindowController* win) +{ + WASSERT(__pv->__window == nullptr); + __pv->__window = win; + return win->create(); +} + +void WApp::onAppControl(app_control_h request, bool firstLaunch) +{ +} + +int WApp::onStart(int argc, char* argv[]) +{ + ui_app_lifecycle_callback_s cb; + memset(&cb, 0, sizeof(cb)); + cb.create = _WAppImpl::__onCreate; + cb.terminate = _WAppImpl::__onTerminate; + cb.pause = _WAppImpl::__onPause; + cb.resume = _WAppImpl::__onResume; + cb.app_control = _WAppImpl::__onAppControl; + + return ui_app_main(argc, argv, &cb, this); +} diff --git a/src/app-assist-efl/WAppEventHandler.cpp b/src/app-assist-efl/WAppEventHandler.cpp new file mode 100644 index 0000000..6b86c41 --- /dev/null +++ b/src/app-assist-efl/WAppEventHandler.cpp @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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 "WAppEventHandler.h" +#include +#include "WDebugInternal.h" +#include "WDefineInternal.h" + +using namespace app_assist; + +namespace app_assist +{ + +class _WAppEventHandlerImpl +{ +public: + _WAppEventHandlerImpl(); + ~_WAppEventHandlerImpl(); +public: + // + app_event_handler_h __handle; + // + void* __userData; + std::function __eventHandlerFunc; + + static void __eventCb(app_event_info_h eventInfo, void* userData); + void __removeEventHandler(); +}; +} + +_WAppEventHandlerImpl::_WAppEventHandlerImpl(): + __handle(nullptr), + __userData(nullptr) +{ +} + +_WAppEventHandlerImpl::~_WAppEventHandlerImpl() +{ + __removeEventHandler(); +} + + +void _WAppEventHandlerImpl::__eventCb(app_event_info_h eventInfo, void* userData) +{ + auto p = (_WAppEventHandlerImpl*)userData; + p->__eventHandlerFunc(eventInfo, p->__userData); +} + +void _WAppEventHandlerImpl::__removeEventHandler() +{ + if (__handle) { + ui_app_remove_event_handler(__handle); + __handle = nullptr; + __userData = nullptr; + } +} + +WAppEventHandler::WAppEventHandler() +{ + __pv = new _WAppEventHandlerImpl(); +} + +WAppEventHandler::~WAppEventHandler() +{ + delete __pv; +} + + +int WAppEventHandler::addEventHandler(app_event_type_e eventType, const std::function& handlerFunc, void* userData) +{ + removeEventHandler(); + + __pv->__eventHandlerFunc = handlerFunc; + __pv->__userData = userData; + + return ui_app_add_event_handler(&__pv->__handle, eventType, __pv->__eventCb, __pv); +} + +void WAppEventHandler::removeEventHandler() +{ + __pv->__removeEventHandler(); +} + +app_event_handler_h WAppEventHandler::getHandle() +{ + return __pv->__handle; +} + + diff --git a/src/app-assist-efl/WContentViewController.cpp b/src/app-assist-efl/WContentViewController.cpp new file mode 100644 index 0000000..f76bbb4 --- /dev/null +++ b/src/app-assist-efl/WContentViewController.cpp @@ -0,0 +1,228 @@ +/* + * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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 "WContentViewController.h" +#include +#include +#include +#include +#include +#include "IWWindowController.h" +#include "WDebugInternal.h" +#include "WDefineInternal.h" +#include "WContentViewControllerImpl.h" + +using namespace app_assist; + +#define _CLASS_NAME "WContentViewController" + +WContentViewController::WContentViewController() +{ + WHIT(); + __pv = new _WContentViewControllerImpl(); +} + +WContentViewController::WContentViewController(const char* name) : __pv(new _WContentViewControllerImpl()) +{ + WHIT(); + setName(name); +} + +WContentViewController::~WContentViewController() +{ + WHIT(); + delete __pv; +} + +const char* WContentViewController::getClassName() const +{ + return _CLASS_NAME; +} + +bool WContentViewController::create(Evas_Object* parent, void* param) +{ + return WViewController::create(parent, param); +} + +void WContentViewController::destroy() +{ + if (getEvasObj()) { + if (__pv->__naviItem && __pv->__isViewNaviItem) { + elm_object_item_del(__pv->__naviItem); + } else { + evas_object_del(getEvasObj()); + } + // Do not leave any code here. + // After executing upper statement "evas_object_del", this object will be deleted at evas object deletion callback! + } else { + onDestroy(); + delete this; + } +} + +void WContentViewController::setTitle(const char* title) +{ + if (__pv->__title) { + free(__pv->__title); + __pv->__title = nullptr; + } + if (title) { + __pv->__title = (char*)malloc(strlen(title) + 1); + strcpy(__pv->__title, title); + } +} +const char* WContentViewController::getTitle() +{ + return __pv->__title; +} + +void WContentViewController::setOnPushed(const std::function& delegateFunc) +{ + __pv->__pushedDelegate = delegateFunc; +} + +bool WContentViewController::popOut() +{ + if (getEvasObj() == nullptr) { + WWARNING("Not created view! No Evas Object!"); + return false; + } + if (getNaviframeController() == nullptr) { + WWARNING("Not pushed to naviframe!"); + return false; + } + + if (__pv->__naviItem != elm_naviframe_top_item_get(getNaviframeController()->getEvasObj())) { + WASSERT_EX(0, "This view is not on Top of Naviframe!"); + return false; + } + + destroyPopup(); // Before popping out view, pop-up is destroyed, if it has.Because pop-up is disappeared too late. + + elm_naviframe_item_pop(getNaviframeController()->getEvasObj()); + return true; +} + +bool WContentViewController::onPop() +{ + return true; +} + +void WContentViewController::onBecomeTop() +{ +} + +WNaviframeController* WContentViewController::getNaviframeController() +{ + if (__pv->__naviframe == nullptr) { + WWARNING("naviframe does not exist!"); + } + + return __pv->__naviframe; +} + +Elm_Object_Item* WContentViewController::getNaviItem() +{ + if (__pv->__naviItem == nullptr) { + WWARNING("naviItem does not exist!"); + } + + return __pv->__naviItem; +} + +void WContentViewController::onPushed(Elm_Object_Item* naviItem) +{ +} + +Elm_Object_Item* WContentViewController::onPushToNaviframe(Evas_Object* naviFrame) +{ + return nullptr; +} + + +Evas_Object* WContentViewController::onCreateView(Evas_Object* parent, void* param) +{ + Evas_Object* layout = elm_layout_add(parent); + evas_object_size_hint_weight_set(layout, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + + char* path = app_get_resource_path(); + if (path == nullptr) { + WERROR("Failed to get resource path=nullptr"); + return layout; + } + std::string edjPath(path); + free(path); + edjPath += "edje/app-assist-efl.edj"; + + if (elm_layout_file_set(layout, edjPath.c_str(), "default-view") == EINA_TRUE) { + Evas_Object* rect = evas_object_rectangle_add(evas_object_evas_get(layout)); + evas_object_color_set(rect, rand() % 256, rand() % 256, rand() % 256, 255); + evas_object_size_hint_weight_set(rect, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_size_hint_align_set(rect, EVAS_HINT_FILL, EVAS_HINT_FILL); + + elm_object_part_content_set(layout, "rect", rect); + if (getName() != nullptr) + elm_object_part_text_set(layout, "name", getName()); + + } else { + WERROR("Fail to set layout. Check EDJ file(%s)", edjPath.c_str()); + } + + evas_object_show(layout); + + return layout; +} + +void WContentViewController::onSetContainerProperties(WNaviframeController* naviframe, Elm_Object_Item* item) +{ +} + +void WContentViewController::onSetAsPageContent(Elm_Object_Item* parentNaviItem) +{ +} + +void WContentViewController::onSetMoreButton(Elm_Object_Item* naviItem, Evas_Smart_Cb clickedCb, void* userData) +{ + eext_object_event_callback_add(getEvasObj(), EEXT_CALLBACK_MORE, clickedCb, userData); +// Evas_Object *btn = elm_button_add( getNaviframeController()->getEvasObj() ); +// elm_object_style_set(btn, "naviframe/more/default"); +// evas_object_show(btn); +// evas_object_smart_callback_add(btn, "clicked", clickedCb, userData); +// elm_object_item_part_content_set(naviItem, "toolbar_more_btn", btn); +} + +bool WContentViewController::setMoreButton(Elm_Object_Item* naviItem, Evas_Smart_Cb clickedCb, void* userData) +{ + onSetMoreButton(naviItem, clickedCb, userData); + return true; +} + +void app_assist::wcontentviewcontroller_set_container_properties(WContentViewController* view, WNaviframeController* naviframe) +{ + _WContentViewControllerImpl::setContainerProperties(view, naviframe); +} + +void app_assist::wcontentviewcontroller_set_container_naviitem_property(WContentViewController* view, Elm_Object_Item* item, bool isViewNaviItem) +{ + _WContentViewControllerImpl::setContainerNaviitemProperty(view, item, isViewNaviItem); +} + +void app_assist::wcontentviewcontroller_propagate_container_properties_to_childviews(WContentViewController* view) +{ + _WContentViewControllerImpl::propagateContainerPropertiesToChildViews(view); +} diff --git a/src/app-assist-efl/WContentViewControllerImpl.cpp b/src/app-assist-efl/WContentViewControllerImpl.cpp new file mode 100644 index 0000000..562fdcc --- /dev/null +++ b/src/app-assist-efl/WContentViewControllerImpl.cpp @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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 "WContentViewControllerImpl.h" +#include "WContentViewController.h" + +using namespace app_assist; + +_WContentViewControllerImpl::_WContentViewControllerImpl(): + __title(nullptr), + __naviItem(nullptr), + __isViewNaviItem(true), + __naviframe(nullptr) +{ +} + +_WContentViewControllerImpl::~_WContentViewControllerImpl() +{ + free(__title); +} + +bool _WContentViewControllerImpl::callPushedHandlerFunc(Elm_Object_Item* naviItem) +{ + if (__pushedDelegate) { + __pushedDelegate(naviItem); + return true; + } + return false; +} + +void _WContentViewControllerImpl::setContainerProperties(WContentViewController* view, WNaviframeController* naviframe) +{ + view->__pv->__naviframe = naviframe; +} + +void _WContentViewControllerImpl::setContainerNaviitemProperty(WContentViewController* view, Elm_Object_Item* item, bool isViewNaviItem) +{ + view->__pv->__isViewNaviItem = isViewNaviItem; + view->__pv->__naviItem = item; +} + +void _WContentViewControllerImpl::propagateContainerPropertiesToChildViews(WContentViewController* view) +{ + view->onSetContainerProperties(view->getNaviframeController(), view->getNaviItem()); +} + + diff --git a/src/app-assist-efl/WEvasObject.cpp b/src/app-assist-efl/WEvasObject.cpp new file mode 100644 index 0000000..0acde59 --- /dev/null +++ b/src/app-assist-efl/WEvasObject.cpp @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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 "WEvasObject.h" +#include "WDebugInternal.h" + +using namespace app_assist; + +namespace app_assist +{ + +class _WEvasObjectImpl : public IWEvasObject +{ +public: + _WEvasObjectImpl(Evas_Object* obj): __evasObj(obj) {} + _WEvasObjectImpl() = delete; + +public: + virtual Evas_Object* getEvasObj() { + return __evasObj; + } + + static void __objDelCb(void* data, Evas* evas, Evas_Object* obj, void* event_info) { + auto p = (_WEvasObjectImpl*)data; + delete p; + } + + std::shared_ptr __selfPtr; + Evas_Object* __evasObj; +}; +} + +std::weak_ptr app_assist::wevasobject_get_weak_ptr(Evas_Object* obj) +{ + auto pImpl = new _WEvasObjectImpl(obj); + std::shared_ptr sp(pImpl, [](IWEvasObject * p) {}); + pImpl->__selfPtr = sp; + + evas_object_event_callback_add(obj, EVAS_CALLBACK_DEL, _WEvasObjectImpl::__objDelCb, pImpl); + + return std::weak_ptr(pImpl->__selfPtr); +} + diff --git a/src/app-assist-efl/WGengridItem.cpp b/src/app-assist-efl/WGengridItem.cpp new file mode 100644 index 0000000..cd54430 --- /dev/null +++ b/src/app-assist-efl/WGengridItem.cpp @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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 "WGengridItem.h" +#include +#include +#include "WDebugInternal.h" +#include "WDefineInternal.h" +#include "WViewController.h" + +using namespace app_assist; + +namespace app_assist +{ + +class _WGengridItemImpl +{ +public: + _WGengridItemImpl(): __objectItem(nullptr) {}; + ~_WGengridItemImpl() {}; + static void __selectCb(void *data, Evas_Object *obj, void *event_info); +public: + Elm_Object_Item* __objectItem; +}; +} + +WGengridItem::WGengridItem() : __pv(new _WGengridItemImpl()) +{ +} + +WGengridItem::~WGengridItem() +{ + delete __pv; +} + +Elm_Gengrid_Item_Class* WGengridItem::getItemClassStatic() +{ + return nullptr; +} + +Elm_Gengrid_Item_Class* WGengridItem::getItemClassNew() +{ + return nullptr; +} + +void WGengridItem::onSelect(Elm_Object_Item* objItem) +{ +} + +void WGengridItem::onSetElmObjectItem(Elm_Object_Item* objItem) +{ +} + +Elm_Object_Item* WGengridItem::getElmObjectItem() +{ + return __pv->__objectItem; +} + +void WGengridItem::setElmObjectItem(Elm_Object_Item* objItem) +{ + __pv->__objectItem = objItem; + onSetElmObjectItem(objItem); +} + +void _WGengridItemImpl::__selectCb(void *data, Evas_Object *obj, void *event_info) +{ + Elm_Object_Item* gengridItem = (Elm_Object_Item*) event_info; + elm_gengrid_item_selected_set(gengridItem, EINA_FALSE); + + auto item = (WGengridItem*)data; + item->onSelect(gengridItem); +} + +Evas_Smart_Cb WGengridItem::getSelectCb() +{ + return _WGengridItemImpl::__selectCb; +} + +bool WGengridItem::attachToParentViewController(WViewController* popup) +{ + if (__pv->__objectItem == nullptr) { + WERROR("object item is not created!"); + return false; + } + + Evas_Object* obj = elm_object_item_widget_get(__pv->__objectItem); + while (obj != nullptr) { + WViewController* view = wviewcontroller_get_instance_from_evasobj(obj); + if (view != nullptr) { + view->attachPopup(popup); + return true; + } + obj = elm_object_parent_widget_get(obj); + } + WERROR("Can not find view instance!"); + return false; +} + +Elm_Object_Item* app_assist::wgengrid_item_append(Evas_Object* gengrid, const Elm_Gengrid_Item_Class* itc, app_assist::WGengridItem* item) +{ + Elm_Object_Item* obj = elm_gengrid_item_append(gengrid, itc, item, item->getSelectCb(), item); + item->setElmObjectItem(obj); + return obj; +} + +Elm_Object_Item* app_assist::wgengrid_item_append_with_callback(Evas_Object* gengrid, const Elm_Gengrid_Item_Class* itc, app_assist::WGengridItem* item, Evas_Smart_Cb selectCb, const void* userData) +{ + Elm_Object_Item* obj = elm_gengrid_item_append(gengrid, itc, item, selectCb, userData); + if (item) + item->setElmObjectItem(obj); + return obj; +} diff --git a/src/app-assist-efl/WGenlistItem.cpp b/src/app-assist-efl/WGenlistItem.cpp new file mode 100644 index 0000000..501897d --- /dev/null +++ b/src/app-assist-efl/WGenlistItem.cpp @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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 "WGenlistItem.h" +#include +#include +#include "WDebugInternal.h" +#include "WDefineInternal.h" +#include "WViewController.h" + +using namespace app_assist; + +namespace app_assist +{ + +class _WGenlistItemImpl +{ +public: + _WGenlistItemImpl(): __objectItem(nullptr) {}; + ~_WGenlistItemImpl() {}; + static void __selectCb(void *data, Evas_Object *obj, void *event_info); +public: + Elm_Object_Item* __objectItem; +}; +} + +WGenlistItem::WGenlistItem() : __pv(new _WGenlistItemImpl()) +{ +} + +WGenlistItem::~WGenlistItem() +{ + delete __pv; +} + +Elm_Genlist_Item_Class* WGenlistItem::getItemClassStatic() +{ + return nullptr; +} + +Elm_Genlist_Item_Class* WGenlistItem::getItemClassNew() +{ + return nullptr; +} + +void WGenlistItem::onSelect(Elm_Object_Item* objItem) +{ +} + +void WGenlistItem::onSetElmObjectItem(Elm_Object_Item* objItem) +{ +} + +Elm_Object_Item* WGenlistItem::getElmObjectItem() +{ + return __pv->__objectItem; +} + +void WGenlistItem::setElmObjectItem(Elm_Object_Item* objItem) +{ + __pv->__objectItem = objItem; + onSetElmObjectItem(objItem); +} + + +void _WGenlistItemImpl::__selectCb(void *data, Evas_Object *obj, void *event_info) +{ + Elm_Object_Item* genlistItem = (Elm_Object_Item*) event_info; + elm_genlist_item_selected_set(genlistItem, EINA_FALSE); + + auto item = (WGenlistItem*)data; + item->onSelect(genlistItem); +} + +Evas_Smart_Cb WGenlistItem::getSelectCb() +{ + return _WGenlistItemImpl::__selectCb; +} + +bool WGenlistItem::attachToParentViewController(WViewController* popup) +{ + if (__pv->__objectItem == nullptr) { + WERROR("object item has not been set! call setElmObjectItem"); + return false; + } + + Evas_Object* obj = elm_object_item_widget_get(__pv->__objectItem); + while (obj != nullptr) { + WViewController* view = wviewcontroller_get_instance_from_evasobj(obj); + if (view != nullptr) { + view->attachPopup(popup); + return true; + } + obj = elm_object_parent_widget_get(obj); + } + WERROR("Can not find view instance!"); + return false; +} + +Elm_Object_Item* app_assist::wgenlist_item_append(Evas_Object* genlist, const Elm_Genlist_Item_Class* itc, WGenlistItem* item, Elm_Genlist_Item_Type type) +{ + Elm_Object_Item* obj = elm_genlist_item_append(genlist, itc, item, nullptr, type, item->getSelectCb(), item); + item->setElmObjectItem(obj); + return obj; +} + +Elm_Object_Item* app_assist::wgenlist_item_append_with_callback(Evas_Object* genlist, const Elm_Genlist_Item_Class* itc, WGenlistItem* item, Elm_Genlist_Item_Type type, Evas_Smart_Cb selectCb, const void* userData) +{ + Elm_Object_Item* obj = elm_genlist_item_append(genlist, itc, item, nullptr, type, selectCb, userData); + if (item) + item->setElmObjectItem(obj); + return obj; +} diff --git a/src/app-assist-efl/WMenuPopupController.cpp b/src/app-assist-efl/WMenuPopupController.cpp new file mode 100644 index 0000000..49748cf --- /dev/null +++ b/src/app-assist-efl/WMenuPopupController.cpp @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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 "WMenuPopupController.h" +#include "WMenuPopupControllerImpl.h" +#include "WDebugInternal.h" + +using namespace app_assist; + +WMenuPopupController::WMenuPopupController(): __pv(new _WMenuPopupControllerImpl()) +{ + WHIT(); +} + +WMenuPopupController::~WMenuPopupController() +{ + WHIT(); + if (__pv->__resizableBaseObj) + evas_object_event_callback_del(__pv->__resizableBaseObj, EVAS_CALLBACK_RESIZE, _WMenuPopupControllerImpl::__popupResizeCb); + + if (__pv->__win) + evas_object_smart_callback_del(__pv->__win, "rotation,changed", _WMenuPopupControllerImpl::__popupWinRotateCb); + + delete __pv; +} + +Elm_Object_Item* WMenuPopupController::appendItem(const char* label, const std::function< void()>& selectCb) +{ + if (getEvasObj() == nullptr) { + WERROR("Create pop-up first!"); + return nullptr; + } + + __pv->__vSelectItemCb.push_back(selectCb); + return elm_ctxpopup_item_append(getEvasObj(), label, nullptr, _WMenuPopupControllerImpl::__popupSelectCb, (void*)(__pv->__vSelectItemCb.size() - 1)); +} + +bool WMenuPopupController::createMenu(Evas_Object* win, Evas_Object* resizableObj) +{ + __pv->__init(win, resizableObj); + return WViewController::create(nullptr, nullptr); +} + +bool WMenuPopupController::showMenu() +{ + if (getEvasObj() == nullptr) { + WERROR("Pop-up is Not created!"); + return false; + } + + __pv->__popupMove(); + evas_object_show(getEvasObj()); + return true; +} + +Evas_Object* WMenuPopupController::onCreateView(Evas_Object* parent, void* param) +{ + return __pv->__create(); +} + +void WMenuPopupController::onDestroy() +{ + WENTER(); +} + diff --git a/src/app-assist-efl/WMenuPopupControllerImpl.cpp b/src/app-assist-efl/WMenuPopupControllerImpl.cpp new file mode 100644 index 0000000..296f28c --- /dev/null +++ b/src/app-assist-efl/WMenuPopupControllerImpl.cpp @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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 "WMenuPopupControllerImpl.h" +#include +#include +#include "WMenuPopupController.h" +#include "WDebugInternal.h" + +using namespace app_assist; + +Evas_Object* _WMenuPopupControllerImpl::__lastMenuPopup = nullptr; + +_WMenuPopupControllerImpl::_WMenuPopupControllerImpl(): + __win(nullptr), + __resizableBaseObj(nullptr), + __popup(nullptr) +{ +} + +_WMenuPopupControllerImpl::~_WMenuPopupControllerImpl() +{ + if (__popup == __lastMenuPopup) + __lastMenuPopup = nullptr; +} + +void _WMenuPopupControllerImpl::destroyLastMenuPopup() +{ + if (__lastMenuPopup) + evas_object_del(__lastMenuPopup); + __lastMenuPopup = nullptr; +} + +void _WMenuPopupControllerImpl::__init(Evas_Object* win, Evas_Object* resizableObj) +{ + __win = win; + __resizableBaseObj = resizableObj; +} + +void _WMenuPopupControllerImpl:: __popupMove() +{ + WENTER(); + int w1, h1; + int rotate; + // + elm_win_screen_size_get(__win, nullptr, nullptr, &w1, &h1); + rotate = elm_win_rotation_get(__win); + + if (rotate == 90) + evas_object_move(__popup, h1 / 2, w1); + else if (rotate == 270) + evas_object_move(__popup, h1 / 2, w1); + else + evas_object_move(__popup, w1 / 2, h1); + + evas_object_show(__popup); +} + +Evas_Object* _WMenuPopupControllerImpl::__create() +{ + if (__win == nullptr) { + WERROR("Call createMenu first!"); + return nullptr; + } + Evas_Object* popup = nullptr; + popup = elm_ctxpopup_add(__win); + elm_object_style_set(popup, "more/default"); + elm_ctxpopup_auto_hide_disabled_set(popup, EINA_TRUE); + + eext_object_event_callback_add(popup, EEXT_CALLBACK_BACK, eext_ctxpopup_back_cb, nullptr); + eext_object_event_callback_add(popup, EEXT_CALLBACK_MORE, eext_ctxpopup_back_cb, nullptr); + evas_object_event_callback_add(__resizableBaseObj, EVAS_CALLBACK_RESIZE, _WMenuPopupControllerImpl::__popupResizeCb, this); + evas_object_smart_callback_add(__win, "rotation,changed", _WMenuPopupControllerImpl::__popupWinRotateCb, this); + elm_ctxpopup_direction_priority_set(popup, ELM_CTXPOPUP_DIRECTION_DOWN, ELM_CTXPOPUP_DIRECTION_UP, ELM_CTXPOPUP_DIRECTION_UNKNOWN, ELM_CTXPOPUP_DIRECTION_UNKNOWN); + evas_object_smart_callback_add(popup, "dismissed", _WMenuPopupControllerImpl::__popupDismissedCb, this); + evas_object_smart_callback_add(popup, "language,changed", _WMenuPopupControllerImpl::__popupDismissedCb, this); + + __popup = popup; + __lastMenuPopup = popup; + + return popup; +} + +void _WMenuPopupControllerImpl::__popupSelectCb(void* data, Evas_Object* obj, void* event_info) +{ + WENTER(); + auto p = (WMenuPopupController*)wviewcontroller_get_instance_from_evasobj(obj); + const unsigned int itemIndex = (unsigned int)data; + p->__pv->__vSelectItemCb[itemIndex](); + evas_object_del(obj); +} + +void _WMenuPopupControllerImpl::__popupResizeCb(void* data, Evas* e, Evas_Object* obj, void* event_info) +{ + WENTER(); + auto pImpl = (_WMenuPopupControllerImpl*)data; + pImpl->__popupMove(); +} + +void _WMenuPopupControllerImpl::__popupWinRotateCb(void* data, Evas_Object* obj, void* event_info) +{ + WENTER(); + auto pImpl = (_WMenuPopupControllerImpl*)data; + pImpl->__popupMove(); +} + +void _WMenuPopupControllerImpl::__popupDismissedCb(void* data, Evas_Object* obj, void* event_info) +{ + WENTER(); + auto pImpl = (_WMenuPopupControllerImpl*)data; + evas_object_del(pImpl->__popup); +} + diff --git a/src/app-assist-efl/WNaviframeController.cpp b/src/app-assist-efl/WNaviframeController.cpp new file mode 100644 index 0000000..04c87bb --- /dev/null +++ b/src/app-assist-efl/WNaviframeController.cpp @@ -0,0 +1,245 @@ +/* + * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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 "WNaviframeController.h" +#include +#include +#include "WDebugInternal.h" +#include "IWWindowController.h" +#include "WDefineInternal.h" +#include "WContentViewController.h" +#include "WContentViewControllerImpl.h" +//#include "uxt_theme_object.h" + +using namespace app_assist; + +#define _CLASS_NAME "WNaviframeController" + +namespace app_assist +{ + +class _WNaviframeControllerImpl +{ +public: + _WNaviframeControllerImpl() {}; + ~_WNaviframeControllerImpl() {}; +public: + + std::function __lastItemPopDelegate; + + static Eina_Bool __popCb(void* data, Elm_Object_Item* item); +}; +} + +Eina_Bool _WNaviframeControllerImpl::__popCb(void* data, Elm_Object_Item* item) +{ + auto vc = (WContentViewController*)data; + // +// WASSERT( vc->getNaviItem() == item ); + // + Evas_Object* naviObj = elm_object_item_widget_get(item); + auto nf = (WNaviframeController*)evas_object_data_get(naviObj, WKEY_FRAME_INSTANCE); + // + if (nf->onItemPop(vc, item)) + return EINA_TRUE; + else + return EINA_FALSE; +} + +WNaviframeController::WNaviframeController() : __pv(new _WNaviframeControllerImpl()) +{ + WHIT(); +} + +WNaviframeController::~WNaviframeController() +{ + WHIT(); + delete __pv; +} + +const char* WNaviframeController::getClassName() const +{ + return _CLASS_NAME; +} + +bool WNaviframeController::create(Evas_Object* parent, void* param) +{ + if (WViewController::create(parent, param)) { + evas_object_data_set(getEvasObj(), WKEY_FRAME_INSTANCE, this); + return true; + } + return false; +} + +void WNaviframeController::destroy() +{ + WHIT(); + if (getEvasObj()) { + destroyAllViewControllers(); + evas_object_del(getEvasObj()); + // Do not leave any code here. + // After executing upper statement "evas_object_del", this object will be deleted at evas object deletion callback! + } else { + onDestroy(); + delete this; + } +} + +bool WNaviframeController::push(WContentViewController* vc, const char* viewName, void* viewCreationParam) +{ + if (viewName) + vc->setName(viewName); + return onPush(vc, viewCreationParam); + // +} + +bool WNaviframeController::push(WContentViewController* vc, const char* viewName) +{ + return push(vc, viewName, nullptr); +} + +bool WNaviframeController::push(WContentViewController* vc) +{ + return push(vc, nullptr, nullptr); +} + + +void WNaviframeController::destroyAllViewControllers() +{ + WHIT(); + + Eina_List* list = elm_naviframe_items_get(getEvasObj()); + Eina_List* temp = nullptr; + void* it = nullptr; + EINA_LIST_FOREACH(list, temp, it) { + elm_object_item_del((Elm_Object_Item*)it); + } +} + +bool WNaviframeController::isTopContentViewController(WContentViewController* vc) +{ + if (getEvasObj() == nullptr) return false; + + Elm_Object_Item* item = elm_naviframe_top_item_get(getEvasObj()); + if (item && vc->getNaviItem() == item) + return true; + else + return false; +} + +WContentViewController* WNaviframeController::getTopContentViewController() +{ + if (getEvasObj() == nullptr) return nullptr; + + Elm_Object_Item* item = elm_naviframe_top_item_get(getEvasObj()); + return (WContentViewController*)elm_object_item_data_get(item); +} + +void WNaviframeController::setOnLastItemPop(const std::function& delegateFunc) +{ + __pv->__lastItemPopDelegate = delegateFunc; +} + + + +Evas_Object* WNaviframeController::onCreateView(Evas_Object* parent, void* param) +{ + Evas_Object* obj = elm_naviframe_add(parent); +// uxt_theme_object_replace_color(obj, "B012L4", "ATO001"); + eext_object_event_callback_add(obj, EEXT_CALLBACK_BACK, eext_naviframe_back_cb, nullptr); + eext_object_event_callback_add(obj, EEXT_CALLBACK_MORE, eext_naviframe_more_cb, nullptr); + + evas_object_show(obj); + + return obj; +} + +void WNaviframeController::onDestroy() +{ +} + +void WNaviframeController::onLastItemPop(bool* popOut) +{ + WHIT(); + *popOut = false; + elm_win_lower(getWindowController()->getEvasObj()); +} + +bool WNaviframeController::onPush(WContentViewController* vc, void* viewParam) +{ + WASSERT(getEvasObj() != nullptr); + // + if (vc->create(getEvasObj(), viewParam) == false) { + WERROR("Failed to create a vc!"); + return false; + } + + wcontentviewcontroller_set_container_properties(vc, this); + // + Elm_Object_Item* item = vc->onPushToNaviframe(getEvasObj()); + if (item == nullptr) + item = elm_naviframe_item_push(getEvasObj(), vc->getTitle(), nullptr, nullptr, vc->getEvasObj(), nullptr); + // + elm_object_item_data_set(item, vc); + wcontentviewcontroller_set_container_naviitem_property(vc, item, true); + wcontentviewcontroller_propagate_container_properties_to_childviews(vc); + + // + if (vc->__pv->callPushedHandlerFunc(item) == false) + vc->onPushed(item); + + elm_naviframe_item_pop_cb_set(item, _WNaviframeControllerImpl::__popCb, vc); + + return true; +} + +bool WNaviframeController::onItemPop(WContentViewController* vc, Elm_Object_Item* item) +{ + WNaviframeController* nf = vc->getNaviframeController(); + + if (item == elm_naviframe_bottom_item_get(nf->getEvasObj())) { + if (!vc->onPop()) + return false; + + bool popOut = true; + + if (nf->__pv->__lastItemPopDelegate) + nf->__pv->__lastItemPopDelegate(&popOut); + else + nf->onLastItemPop(&popOut); + return popOut; + } else { + if (vc->onPop()) { + Eina_List* itemList = elm_naviframe_items_get(getEvasObj()); + + int nth = eina_list_count(itemList) - 2; + if (nth >= 0) { + Elm_Object_Item* tempItem = (Elm_Object_Item*)eina_list_nth(itemList, nth); + WContentViewController* targetView = (WContentViewController*)elm_object_item_data_get(tempItem); + WASSERT(targetView); + targetView->onBecomeTop(); + } + eina_list_free(itemList); + + return true; + } else { + return false; + } + } +} + diff --git a/src/app-assist-efl/WPageSlideViewController.cpp b/src/app-assist-efl/WPageSlideViewController.cpp new file mode 100644 index 0000000..aa51ed8 --- /dev/null +++ b/src/app-assist-efl/WPageSlideViewController.cpp @@ -0,0 +1,528 @@ +/* + * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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 "WPageSlideViewController.h" +#include +#include +#include +#include "WDebugInternal.h" +#include "WDefineInternal.h" +#include "WContentViewController.h" +#include "WUiTimer.h" + +using namespace app_assist; + +#define _CLASS_NAME "WPageSlideViewController" + +namespace app_assist +{ + +class _WPageSlideViewControllerImpl +{ +public: + _WPageSlideViewControllerImpl(WPageSlideViewController* host); + _WPageSlideViewControllerImpl() = delete; + ~_WPageSlideViewControllerImpl(); +public: + WPageSlideViewController* __b; + // + struct PageContent { + WViewController* uiObj; + Evas_Object* evasObj; + bool isContentView; + }; + + Evas_Object* __scroller; + Evas_Object* __box; + int __currentPage; + int __previousPage; + int __pageWidth; + int __pageHeight; + std::list* __listPageContent; + bool __showScroll; + // + std::function __initScrollerHandler; + std::function __scrollAnimStopCb; + + bool __appendPage(WViewController* uiObj, bool isContentView); + bool __appendPage(); + bool __setPageContent(int index, WViewController* uiObj, bool isContentView); + + static void __scrollCallback(void *data, Evas_Object *obj, void *event_info); + static void __scrollAnimStartCallback(void *data, Evas_Object *obj, void *event_info); + static void __scrollAnimStopCallback(void *data, Evas_Object *obj, void *event_info); + static Eina_Bool __onTimer(void* data); + + static void __layoutResizeCallback(void *data, Evas *e, Evas_Object *obj, void *event_info); +}; +} + +static Evas_Object* __createPageBase(Evas_Object* parent) +{ + Evas_Object* pageBase = elm_layout_add(parent); + evas_object_size_hint_weight_set(pageBase, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + + char* path = app_get_resource_path(); + if (path == nullptr) { + WERROR("Failed to get resource path=nullptr!!!"); + return pageBase; + } + std::string edjPath(path); + free(path); + edjPath += "edje/app-assist-efl.edj"; + + if (elm_layout_file_set(pageBase, edjPath.c_str(), "page") == EINA_FALSE) { + WERROR("Fail to set layout. Check EDJ file(%s)", edjPath.c_str()); + return pageBase; + } + + Evas_Object* rect = evas_object_rectangle_add(evas_object_evas_get(pageBase)); + evas_object_size_hint_weight_set(rect, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_color_set(rect, 0, 0, 0, 0); // make it transparent to show bg + evas_object_show(rect); + + elm_object_part_content_set(pageBase, "sizer", rect); + + evas_object_show(pageBase); + return pageBase; +} + +_WPageSlideViewControllerImpl::_WPageSlideViewControllerImpl(WPageSlideViewController* host): + __b(nullptr), + __scroller(nullptr), + __box(nullptr), + __currentPage(0), + __previousPage(0), + __pageWidth(0), + __pageHeight(0), + __listPageContent(nullptr), + __showScroll(true) +{ + __b = host; + __listPageContent = new std::list; +} + +_WPageSlideViewControllerImpl::~_WPageSlideViewControllerImpl() +{ + delete __listPageContent; +} + +bool _WPageSlideViewControllerImpl::__appendPage(WViewController* uiObj, bool isContentView) +{ + if (__scroller == nullptr) { + WASSERT("First, create page slide view!"); + return false; + } + + Evas_Object* pageBase = __createPageBase(__box); + + uiObj->create(pageBase, nullptr); + + elm_object_part_content_set(pageBase, "sw", uiObj->getEvasObj()); + + elm_box_pack_end(__box, pageBase); + + __listPageContent->push_back(PageContent {uiObj, pageBase, isContentView}); + + return true; +} + +bool _WPageSlideViewControllerImpl::__appendPage() +{ + if (__scroller == nullptr) { + WASSERT("First, create page slide view!"); + return false; + } + + Evas_Object* pageBase = __createPageBase(__box); + + elm_box_pack_end(__box, pageBase); + + __listPageContent->push_back(PageContent {nullptr, pageBase, false}); + + return true; +} + +bool _WPageSlideViewControllerImpl::__setPageContent(int index, WViewController* uiObj, bool isContentView) +{ + int count = 0; + Evas_Object* pageBase = nullptr; + for (PageContent& it : *__listPageContent) { + if (index == count) { + if (it.uiObj) { + WERROR("Index is already occupied(index=%d)", index); + return false; + } + it.uiObj = uiObj; + it.isContentView = isContentView; + pageBase = it.evasObj; + break; + } + count++; + } + + if (count != index) { + WERROR("Index is not in range(index=%d,count=%d)", index, count); + return false; + } + + Evas_Object *content = elm_object_part_content_get(pageBase, "sw"); + if (content == nullptr) { + uiObj->create(pageBase, nullptr); + elm_object_part_content_set(pageBase, "sw", uiObj->getEvasObj()); + return true; + } + + return false; +} + + +void _WPageSlideViewControllerImpl::__scrollCallback(void *data, Evas_Object *obj, void *event_info) +{ + _WPageSlideViewControllerImpl* pageViewImpl = ((WPageSlideViewController *)data)->__pv; + int x; + + evas_object_geometry_get(pageViewImpl->__box, &x, nullptr, nullptr, nullptr); + + if (x % pageViewImpl->__pageWidth == 0) { + int page; + elm_scroller_current_page_get(obj, &page, nullptr); + pageViewImpl->__currentPage = page; + } +} + +void _WPageSlideViewControllerImpl::__scrollAnimStartCallback(void *data, Evas_Object *obj, void *event_info) +{ + _WPageSlideViewControllerImpl* pageViewImpl = ((WPageSlideViewController *)data)->__pv; + pageViewImpl->__previousPage = pageViewImpl->__currentPage; +} + +void _WPageSlideViewControllerImpl::__scrollAnimStopCallback(void *data, Evas_Object *obj, void *event_info) +{ + _WPageSlideViewControllerImpl* pageViewImpl = ((WPageSlideViewController *)data)->__pv; + if (pageViewImpl->__scrollAnimStopCb) + pageViewImpl->__scrollAnimStopCb(pageViewImpl->__currentPage - pageViewImpl->__previousPage); +} + +Eina_Bool _WPageSlideViewControllerImpl::__onTimer(void* data) +{ + _WPageSlideViewControllerImpl* pageViewImpl = ((WPageSlideViewController *)data)->__pv; + __layoutResizeCallback(data, nullptr, pageViewImpl->__scroller, nullptr); + return ECORE_CALLBACK_CANCEL; +} + + +void _WPageSlideViewControllerImpl::__layoutResizeCallback(void *data, Evas *e, Evas_Object *obj, void *event_info) +{ + WHIT(); + + WPageSlideViewController* pageView = (WPageSlideViewController *)data; + _WPageSlideViewControllerImpl* pv = pageView->__pv; + int w, h; + + evas_object_geometry_get(obj, nullptr, nullptr, &w, &h); + + pv->__pageWidth = w; + pv->__pageHeight = h; + + for (PageContent& it : *pv->__listPageContent) { + Evas_Object* pageBase = it.evasObj; + evas_object_size_hint_min_set(elm_object_part_content_get(pageBase, "sizer"), w, h); + } + + elm_scroller_page_size_set(pv->__scroller, w, h); + elm_scroller_page_show(pv->__scroller, pv->__currentPage, 0); + +// sometimes layout resize callback is called when UG is destroyed. so do not use timer! or care the timer handle. +// ecore_timer_add(0.0, [](void* data) { +// WPageSlideViewController* self = (WPageSlideViewController*)data; +// elm_scroller_page_show(self->__pv->__scroller, self->__pv->__currentPage, 0); +// return ECORE_CALLBACK_CANCEL; +// }, pageView); +} + + +WPageSlideViewController::WPageSlideViewController() +{ + __pv = new _WPageSlideViewControllerImpl(this); +} + +WPageSlideViewController::~WPageSlideViewController() +{ + delete __pv; +} + +void WPageSlideViewController::setOnScrollAnimStop(const std::function& handlerFunc) +{ + __pv->__scrollAnimStopCb = handlerFunc; +} + +const char* WPageSlideViewController::getClassName() const +{ + return _CLASS_NAME; +} + +bool WPageSlideViewController::appendPage(WViewController* content) +{ + if (__pv->__appendPage(content, false) == false) { + WERROR("Fail to attach the page!"); + return false; + } + + return true; +} + +bool WPageSlideViewController::appendPage(WContentViewController* content) +{ + if (__pv->__appendPage(content, true) == false) { + WERROR("Fail to attach the page!"); + return false; + } + + wcontentviewcontroller_set_container_properties(content, getNaviframeController()); + wcontentviewcontroller_set_container_naviitem_property(content, getNaviItem(), false); + wcontentviewcontroller_propagate_container_properties_to_childviews(content); + + content->onSetAsPageContent(getNaviItem()); + + return true; +} + +bool WPageSlideViewController::appendPage() +{ + if (__pv->__appendPage() == false) { + WERROR("Fail to attach the page!"); + return false; + } + + return true; +} + +bool WPageSlideViewController::removePage(int index) +{ + int pageNum = getPageCount(); + if (index < 0 || index >= pageNum) { + WERROR("Out of page number(%d), index=%d", pageNum, index); + return false; + } + + int cur = 0; + for (auto it = __pv->__listPageContent->begin(); it != __pv->__listPageContent->end(); it++) { + if (cur == index) { + elm_box_unpack(__pv->__box, it->evasObj); + evas_object_del(it->evasObj); + __pv->__listPageContent->erase(it); + return true; + } + cur++; + } + return false; +} + +void WPageSlideViewController::resizePageSlideLayout() +{ + _WPageSlideViewControllerImpl::__layoutResizeCallback(this, nullptr, __pv->__scroller, nullptr); +} + +bool WPageSlideViewController::setPageContent(int index, WContentViewController* content) +{ + if (__pv->__setPageContent(index, content, true) == false) { + WERROR("Fail to set page content %d!", index); + return false; + } + + wcontentviewcontroller_set_container_properties(content, getNaviframeController()); + wcontentviewcontroller_set_container_naviitem_property(content, getNaviItem(), false); + wcontentviewcontroller_propagate_container_properties_to_childviews(content); + + content->onSetAsPageContent(getNaviItem()); + + return true; +} + +bool WPageSlideViewController::setPageContent(int index, WViewController* content) +{ + if (__pv->__setPageContent(index, content, false) == false) { + WERROR("Fail to set page content %d!", index); + return false; + } + return true; +} + + +int WPageSlideViewController::getPageCount() +{ + return __pv->__listPageContent->size(); +} + +WViewController* WPageSlideViewController::getPageContent(int index) +{ + int count = 0; + for (_WPageSlideViewControllerImpl::PageContent& it : *__pv->__listPageContent) { + if (count == index) + return it.uiObj; + count++; + } + + return nullptr; +} + +int WPageSlideViewController::getCurrentPageIndex() +{ + return __pv->__currentPage; +} + +Evas_Object* WPageSlideViewController::getScroller() +{ + return __pv->__scroller; +} + +void WPageSlideViewController::setScrollerShowState(bool show) +{ + __pv->__showScroll = show; +} + +void WPageSlideViewController::showPage(int index, bool withAnimation) +{ + int pageNum = getPageCount(); + if (index < 0 || index >= pageNum) { + WERROR("Out of page number(%d), index=%d", pageNum, index); + return; + } + __pv->__currentPage = index; + if (withAnimation) + elm_scroller_page_bring_in(__pv->__scroller, __pv->__currentPage, 0); + else + elm_scroller_page_show(__pv->__scroller, __pv->__currentPage, 0); +} + +void WPageSlideViewController::showPage(int index) +{ + return showPage(index, false); +} + +WViewController* WPageSlideViewController::unsetPageContent(int index) +{ + int pageNum = getPageCount(); + if (index < 0 || index >= pageNum) { + WERROR("Out of page number(%d), index=%d", pageNum, index); + return nullptr; + } + + auto it = __pv->__listPageContent->begin(); + for (int i = 0; i < index; i++) + it++; + + Evas_Object* obj = elm_object_part_content_unset((*it).evasObj, "sw"); + (*it).uiObj = nullptr; + if (obj == nullptr) { + WERROR("elm_object_part_content_unset obj is nullptr"); + return nullptr; + } else { + WViewController* uiObj = nullptr; + if ((uiObj = (WViewController*)evas_object_data_get(obj, WKEY_VIEW_INSTANCE)) != nullptr) { + return uiObj; + } + return nullptr; + } +} + +void WPageSlideViewController::setOnInitScroller(const std::function& delegateFunc) +{ + __pv->__initScrollerHandler = delegateFunc; +} + +Evas_Object* WPageSlideViewController::onCreateView(Evas_Object* parent, void* viewParam) +{ + WHIT(); + + Evas_Object* layout = onCreateLayout(parent); + Evas_Object* scroller = nullptr; + if (layout) { + scroller = elm_scroller_add(layout); + evas_object_event_callback_add(layout, EVAS_CALLBACK_RESIZE, _WPageSlideViewControllerImpl::__layoutResizeCallback, this); + } else { + scroller = elm_scroller_add(parent); + evas_object_event_callback_add(scroller, EVAS_CALLBACK_RESIZE, _WPageSlideViewControllerImpl::__layoutResizeCallback, this); + } + + evas_object_smart_callback_add(scroller, "scroll", _WPageSlideViewControllerImpl::__scrollCallback, this); + evas_object_smart_callback_add(scroller, "scroll,anim,start", _WPageSlideViewControllerImpl::__scrollAnimStartCallback, this); + evas_object_smart_callback_add(scroller, "scroll,anim,stop", _WPageSlideViewControllerImpl::__scrollAnimStopCallback, this); + + elm_scroller_loop_set(scroller, EINA_FALSE, EINA_FALSE); + evas_object_size_hint_weight_set(scroller, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_size_hint_align_set(scroller, EVAS_HINT_FILL, EVAS_HINT_FILL); + elm_scroller_page_relative_set(scroller, 1.0, 0.0); + elm_scroller_policy_set(scroller, + __pv->__showScroll ? ELM_SCROLLER_POLICY_AUTO : ELM_SCROLLER_POLICY_OFF, + ELM_SCROLLER_POLICY_OFF); + elm_scroller_page_scroll_limit_set(scroller, 1, 0); + elm_object_scroll_lock_y_set(scroller, EINA_TRUE); + elm_scroller_single_direction_set(scroller, ELM_SCROLLER_SINGLE_DIRECTION_HARD); + // + if (__pv->__initScrollerHandler) + __pv->__initScrollerHandler(scroller); + else + onInitScroller(scroller); + // + if (layout) { + elm_object_part_content_set(layout, "scroller", scroller); + } + + Evas_Object* box = elm_box_add(scroller); + + __pv->__scroller = scroller; + __pv->__box = box; + + elm_box_horizontal_set(box, EINA_TRUE); + elm_object_content_set(scroller, box); + evas_object_show(scroller); + evas_object_show(box); + + + if (layout) { + WUiTimer::addTimer(0.0, _WPageSlideViewControllerImpl::__onTimer, this, layout); + return layout; + } else { + WUiTimer::addTimer(0.0, _WPageSlideViewControllerImpl::__onTimer, this, scroller); + return scroller; + } +} + +void WPageSlideViewController::onSetContainerProperties(WNaviframeController* naviframe, Elm_Object_Item* item) +{ + for (_WPageSlideViewControllerImpl::PageContent& it : *__pv->__listPageContent) { + if (it.uiObj && it.isContentView) { + auto view = (WContentViewController*)wviewcontroller_get_instance_from_evasobj(it.uiObj->getEvasObj()); + wcontentviewcontroller_set_container_properties(view , naviframe); + wcontentviewcontroller_set_container_naviitem_property(view, item, false); + wcontentviewcontroller_propagate_container_properties_to_childviews(view); + } + } +} + +void WPageSlideViewController::onInitScroller(Evas_Object* scroller) +{ +} + +Evas_Object* WPageSlideViewController::onCreateLayout(Evas_Object* parent) +{ + WHIT(); + return nullptr; +} diff --git a/src/app-assist-efl/WPopupController.cpp b/src/app-assist-efl/WPopupController.cpp new file mode 100644 index 0000000..610dca7 --- /dev/null +++ b/src/app-assist-efl/WPopupController.cpp @@ -0,0 +1,278 @@ +/* + * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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 "WPopupController.h" +#include +#include +#include +#include "WDebugInternal.h" + + +using namespace app_assist; + +#define _MAX_BUTTON_NUM 3 + +namespace app_assist +{ + +class _WPopupControllerImpl +{ +public: + _WPopupControllerImpl(); + ~_WPopupControllerImpl(); +public: + // + std::string __title; + std::string __text; + std::string __textDomain; + WViewController* __content; + std::string __listButtonLabel[_MAX_BUTTON_NUM]; + int __count; + bool __isTranslatable; + + std::function __contentCreator; + std::function __addPropertiesCb; + std::function __backCb; + + std::function __vButtonCb[_MAX_BUTTON_NUM]; + std::function* buttonPropertyCb[_MAX_BUTTON_NUM]; + + void __setTextPart(Evas_Object* obj, const char* part, const char* text); +}; +} + +_WPopupControllerImpl::_WPopupControllerImpl(): + __content(nullptr), + __count(0), + __isTranslatable(false) +{ + for (int i = 0; i < _MAX_BUTTON_NUM; i++) { + buttonPropertyCb[i] = nullptr; + } +} + +_WPopupControllerImpl::~_WPopupControllerImpl() +{ + for (int i = 0; i < _MAX_BUTTON_NUM; i++) { + delete buttonPropertyCb[i]; + } +} + +void _WPopupControllerImpl::__setTextPart(Evas_Object* obj, const char* part, const char* text) +{ + if (!__textDomain.empty()) { + elm_object_domain_translatable_part_text_set(obj, part, __textDomain.c_str(), text); + } else { + if (__isTranslatable) + elm_object_translatable_part_text_set(obj, part, text); + else + elm_object_part_text_set(obj, part, text); + } +} + + +WPopupController::WPopupController() : __pv(new _WPopupControllerImpl()) +{ + WHIT(); +} +WPopupController::WPopupController(const char* title, const char* textContent) : __pv(new _WPopupControllerImpl()) +{ + if (title) + __pv->__title = title; + if (textContent) + __pv->__text = textContent; +} + +WPopupController::~WPopupController() +{ + WHIT(); + delete __pv; +} + +void WPopupController::setTitle(const char* title) +{ + if (title) + __pv->__title = title; + else + __pv->__title.clear(); +} + +void WPopupController::setContent(const char* text) +{ + if (text) + __pv->__text = text; + else + __pv->__text.clear(); + if (__pv->__content) { + __pv->__content->destroy(); + __pv->__content = nullptr; + } +} + +void WPopupController::setContent(WViewController* control) +{ + __pv->__text = ""; + __pv->__content = control; +} + +void WPopupController::setContent(const std::function& contentCreateCb) +{ + __pv->__text = ""; + if (__pv->__content) { + __pv->__content->destroy(); + __pv->__content = nullptr; + } + __pv->__contentCreator = contentCreateCb; +} + +void WPopupController::setTextTranslatable() +{ + __pv->__isTranslatable = true; +} + +void WPopupController::setTextTranslatable(const char* textDomain) +{ + if (textDomain) + __pv->__textDomain = textDomain; + else + __pv->__textDomain.clear(); +} + +// Popup can be destroyed in button callback, so check its validity by calling expired of weak pointer. +#define BUTTON_CALLBACK(_buttonIndex) \ +[](void* data, Evas_Object* obj, void* eventInfo) {\ + WPopupController* self = (WPopupController*)data;\ + if (self->__pv->__vButtonCb[_buttonIndex]) { \ + bool destroyPopup = true; \ + auto selfWeakPtr = self->getWeakPtr(); \ + self->__pv->__vButtonCb[_buttonIndex](&destroyPopup); \ + if (!selfWeakPtr.expired() && destroyPopup) \ + evas_object_del(self->getEvasObj());\ + }\ + else \ + evas_object_del(self->getEvasObj());\ +} + +bool WPopupController::addButton(const char* buttonText, const std::function& buttonCb, const std::function& setPropertyCb) +{ + if (__pv->__count >= _MAX_BUTTON_NUM) { + WERROR("Over the max button number! =%d", __pv->__count); + return false; + } + __pv->__listButtonLabel[__pv->__count] = buttonText; + __pv->__vButtonCb[__pv->__count] = buttonCb; + if (setPropertyCb) + __pv->buttonPropertyCb[__pv->__count] = new std::function(setPropertyCb); + + __pv->__count++; + return true; +} + +bool WPopupController::addButton(const char* buttonText, const std::function& buttonCb) +{ + return addButton(buttonText, buttonCb, nullptr); +} + +void WPopupController::setOnBack(const std::function& backCb) +{ + __pv->__backCb = backCb; +} + +void WPopupController::setOnAddProperties(const std::function& addPropertiesCb) +{ + __pv->__addPropertiesCb = addPropertiesCb; +} + +Evas_Object* WPopupController::onCreateView(Evas_Object* parent, void* param) +{ + WHIT(); + + Evas_Object* popup = elm_popup_add(parent); + + // It make the width to fit to screen width in portrait mode. 2014.09.30 modified as EFL notice. + elm_popup_align_set(popup, ELM_NOTIFY_ALIGN_FILL, 1.0); + + if (__pv->__backCb) + eext_object_event_callback_add(popup, EEXT_CALLBACK_BACK, [](void *data, Evas_Object * obj, void *event_info) { + WPopupController* self = (WPopupController*)data; + bool destroyPopup = true; + auto selfWeakPtr = self->getWeakPtr(); + self->__pv->__backCb(&destroyPopup); + if (!selfWeakPtr.expired() && destroyPopup) { + self->destroy(); + } + }, this); + else + eext_object_event_callback_add(popup, EEXT_CALLBACK_BACK, eext_popup_back_cb, nullptr); + + if (__pv->__addPropertiesCb) + __pv->__addPropertiesCb(popup); + + if (!__pv->__title.empty()) { + __pv->__setTextPart(popup, "title,text", __pv->__title.c_str()); + } + + if (!__pv->__text.empty()) { + __pv->__setTextPart(popup, nullptr, __pv->__text.c_str()); + } else if (__pv->__content) { + __pv->__content->create(popup, nullptr); + elm_object_content_set(popup, __pv->__content->getEvasObj()); + } else if (__pv->__contentCreator) { + Evas_Object* obj = __pv->__contentCreator(popup); + elm_object_content_set(popup, obj); + } + + for (int i = 0; i < __pv->__count; i++) { + Evas_Object* button = elm_button_add(popup); + elm_object_style_set(button, "popup/circle"); + if (__pv->buttonPropertyCb[i]) { + (*__pv->buttonPropertyCb[i])(button); + } + + __pv->__setTextPart(button, nullptr, __pv->__listButtonLabel[i].c_str()); + + char partname[100] = {0}; + snprintf(partname, sizeof(partname) - 1, "button%d", i + 1); + elm_object_part_content_set(popup, partname, button); + // + switch (i) { + case 0: + evas_object_smart_callback_add(button, "clicked", BUTTON_CALLBACK(0), this); + break; + case 1: + evas_object_smart_callback_add(button, "clicked", BUTTON_CALLBACK(1), this); + break; + case 2: + evas_object_smart_callback_add(button, "clicked", BUTTON_CALLBACK(2), this); + break; + default: + break; + } + + + evas_object_show(button); + } + + evas_object_show(popup); + + return popup; +} + +void WPopupController::onDestroy() +{ +} diff --git a/src/app-assist-efl/WSignalIdGenerator.cpp b/src/app-assist-efl/WSignalIdGenerator.cpp new file mode 100644 index 0000000..f85723c --- /dev/null +++ b/src/app-assist-efl/WSignalIdGenerator.cpp @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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 "WSignalIdGenerator.h" + +using namespace app_assist; + +static unsigned int gid = 0; + +unsigned int WSignalIdGenerator::generate() +{ + return ++gid; +} diff --git a/src/app-assist-efl/WUiThread.cpp b/src/app-assist-efl/WUiThread.cpp new file mode 100644 index 0000000..158a528 --- /dev/null +++ b/src/app-assist-efl/WUiThread.cpp @@ -0,0 +1,330 @@ +/* + * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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 "WUiThread.h" +#include +#include +#include +#include "WDebugInternal.h" +#include "WDefineInternal.h" + +const char* const SIGNAL_DATA_KEY_STRING = "__@WSIGNAL_DATA"; +const static int _CANCEL_TIMEOUT = 30; //seconds + +using namespace app_assist; + +namespace app_assist +{ + +class _WUiThreadImpl : public WUiThread::IStatus +{ +public: + _WUiThreadImpl(): __workerThread(nullptr), __stopFlag(false) {}; + ~_WUiThreadImpl() {}; +public: + // + Ecore_Thread* __workerThread; + bool __stopFlag; + Eina_Lock __mutex; + Eina_Condition __notifyCbEndCondition; + + std::function __workerFunc; + std::function __workerEndCb; + std::function __workerCancelCb; + std::function __workerNotifyCb; + // + virtual bool isCancelRequested(Ecore_Thread* thread); //override; + virtual int getThreadGlobalDataInt(); //override; + virtual int getThreadGlobalDataInt(const char* key); //override; + virtual bool sendFeedback(Ecore_Thread* thread, void* msgData); //override; + + void __setThreadGlobalDataInt(int data); + void __setThreadGlobalDataInt(const char* key, int data); + static void __threadWorkerFunc(void* data, Ecore_Thread* thread); + static void __threadEndCb(void* data, Ecore_Thread* thread); + static void __threadCancelCb(void* data, Ecore_Thread* thread); + static void __threadNotifyCb(void* data, Ecore_Thread* thread, void* msgData); +}; +} + + +bool _WUiThreadImpl::isCancelRequested(Ecore_Thread* thread) +{ + WHIT(); + if (ecore_thread_check(thread) == EINA_TRUE) + return true; + else + return false; +} +int _WUiThreadImpl::getThreadGlobalDataInt() +{ + return getThreadGlobalDataInt(SIGNAL_DATA_KEY_STRING); +} + +int _WUiThreadImpl::getThreadGlobalDataInt(const char* key) +{ + void* data = ecore_thread_global_data_find(key); + if (data == nullptr) { + return -1; + } else { + ecore_thread_global_data_del(key); + return (int)data; + } +} + +void _WUiThreadImpl::__setThreadGlobalDataInt(int data) +{ + __setThreadGlobalDataInt(SIGNAL_DATA_KEY_STRING, data); +} + +void _WUiThreadImpl::__setThreadGlobalDataInt(const char* key, int data) +{ + ecore_thread_global_data_set(key, (void*)data, nullptr); +} + +bool _WUiThreadImpl::sendFeedback(Ecore_Thread* thread, void* msgData) +{ + if (!__workerNotifyCb) { + WERROR("No notify callback was set!"); + return false; + } + if (isCancelRequested(thread)) { + return false; + } + WHIT(); + + eina_lock_take(&__mutex); + Eina_Bool ret = ecore_thread_feedback(thread, msgData); + eina_condition_wait(&__notifyCbEndCondition); + eina_lock_release(&__mutex); + + if (ret == EINA_TRUE) return true; + else return false; +} + +void _WUiThreadImpl::__threadWorkerFunc(void* data, Ecore_Thread* thread) +{ + WENTER(); + auto self = static_cast(data); + if (self->__pv->__workerFunc) { + self->__pv->__workerFunc(self->__pv, thread); + } else { + WERROR("No worker function was set!"); + } + WLEAVE(); +} + +void _WUiThreadImpl::__threadEndCb(void* data, Ecore_Thread* thread) +{ + WHIT(); + auto self = static_cast(data); + if (self->__pv->__stopFlag == false && self->__pv->__workerEndCb) + self->__pv->__workerEndCb(); + + if (self->__pv->__workerNotifyCb) { + eina_lock_free(&self->__pv->__mutex); + eina_condition_free(&self->__pv->__notifyCbEndCondition); + } + self->__pv->__workerThread = nullptr; +} + +void _WUiThreadImpl::__threadCancelCb(void* data, Ecore_Thread* thread) +{ + WHIT(); + auto self = static_cast(data); + + if (self->__pv->__stopFlag == false && self->__pv->__workerCancelCb) + self->__pv->__workerCancelCb(); + + if (self->__pv->__workerNotifyCb) { + eina_lock_free(&self->__pv->__mutex); + eina_condition_free(&self->__pv->__notifyCbEndCondition); + } + self->__pv->__workerThread = nullptr; +} + +void _WUiThreadImpl::__threadNotifyCb(void* data, Ecore_Thread* thread, void* msgData) +{ + WHIT(); + auto self = static_cast(data); + self->__pv->__workerNotifyCb(self, msgData); + // + eina_lock_take(&self->__pv->__mutex); + eina_condition_signal(&self->__pv->__notifyCbEndCondition); + eina_lock_release(&self->__pv->__mutex); +} + +WUiThread::WUiThread() +{ + WHIT(); + __pv = new _WUiThreadImpl(); +} + +WUiThread::~WUiThread() +{ + WHIT(); + cancelWithoutCallback(_CANCEL_TIMEOUT); + delete __pv; +} + +bool WUiThread::setWorker(const std::function& func) +{ + if (__pv->__workerThread) { + WERROR("Already created thread exists!"); + return false; + } + __pv->__workerFunc = func; + return true; +} + +bool WUiThread::setEndCb(const std::function& endCb) +{ + if (__pv->__workerThread) { + WERROR("Already created thread exists!"); + return false; + } + __pv->__workerEndCb = endCb; + return true; +} + +bool WUiThread::setCancelCb(const std::function& cancelCb) +{ + if (__pv->__workerThread) { + WERROR("Already created thread exists!"); + return false; + } + __pv->__workerCancelCb = cancelCb; + return true; +} + +bool WUiThread::setNotifyCb(const std::function& notifyCb) +{ + if (__pv->__workerThread) { + WERROR("Already created thread exists!"); + return false; + } + __pv->__workerNotifyCb = notifyCb; + return true; +} + +bool WUiThread::run(void) +{ + WHIT(); + + if (__pv->__workerThread) { + WERROR("Already started!"); + return false; + } + if (!__pv->__workerFunc) { + WERROR("Set worker function first!"); + return false; + } + + __pv->__stopFlag = false; + if (__pv->__workerNotifyCb) { + eina_lock_new(&__pv->__mutex); + eina_condition_new(&__pv->__notifyCbEndCondition, &__pv->__mutex); + __pv->__workerThread = ecore_thread_feedback_run(_WUiThreadImpl::__threadWorkerFunc, _WUiThreadImpl::__threadNotifyCb, _WUiThreadImpl::__threadEndCb, _WUiThreadImpl::__threadCancelCb, this, EINA_TRUE); + } else { + __pv->__workerThread = ecore_thread_run(_WUiThreadImpl::__threadWorkerFunc, _WUiThreadImpl::__threadEndCb, _WUiThreadImpl::__threadCancelCb, this); + } + + if (__pv->__workerThread == nullptr) { + WERROR("thread create fail"); + return false; + } + return true; +} + +bool WUiThread::cancel(double waitSeconds) +{ + WHIT(); + if (__pv->__workerThread == nullptr) { + return true; + } + + // Synchronize a thread not to call cancel while feedback notify callback is processing! + // If ecore_thread_cancel is called, the data pointer parameter of notify callback becomes invalid. 2015.09.09 + if (__pv->__workerNotifyCb) { + eina_lock_take(&__pv->__mutex); + eina_lock_release(&__pv->__mutex); + } + + if (ecore_thread_cancel(__pv->__workerThread) == EINA_FALSE) { + if (waitSeconds == 0) + return false; +#ifndef WUSING_SDK_2_3 +#ifndef WUSING_PUBLIC_SDK + if (ecore_thread_wait(__pv->__workerThread, waitSeconds) == EINA_TRUE) { + return true; + } + WERROR("The thread is not yet canceled! But waiting time(%d ms) is over", waitSeconds); +#else + WERROR("On public SDK, waiting time-out is not supported! Check cancel callback!"); +#endif /* WUSING_PUBLIC_SDK */ +#else + WERROR("On 2.3 SDK, waiting time-out is not supported! Check cancel callback!"); +#endif /* WUSING_SDK_2_3 */ + return false; + } + return true; +} + +bool WUiThread::wait(double waitSeconds) +{ + WHIT(); + if (__pv->__workerThread == nullptr) { + return true; + } + +#ifndef WUSING_SDK_2_3 +#ifndef WUSING_PUBLIC_SDK + if (ecore_thread_wait(__pv->__workerThread, waitSeconds) == EINA_TRUE) { + return true; + } + WERROR("The thread is not yet completed! But waiting time(%d ms) is over", waitSeconds); +#else + WERROR("On public SDK, it is not supported!"); +#endif /* WUSING_PUBLIC_SDK */ +#else + WERROR("On 2.3 SDK, it is not supported!"); +#endif /* WUSING_SDK_2_3 */ + + return false; +} + +bool WUiThread::cancelWithoutCallback(double waitSeconds) +{ + WHIT(); + __pv->__stopFlag = true; + if (cancel(waitSeconds) == false) { + WERROR("Failed to cancel!"); + return false; + } + return true; +} + +void WUiThread::setThreadGlobalDataInt(int data) +{ + __pv->__setThreadGlobalDataInt(data); +} + +void WUiThread::setThreadGlobalDataInt(const char* key, int data) +{ + __pv->__setThreadGlobalDataInt(key, data); +} diff --git a/src/app-assist-efl/WUiTimer.cpp b/src/app-assist-efl/WUiTimer.cpp new file mode 100644 index 0000000..36bd6de --- /dev/null +++ b/src/app-assist-efl/WUiTimer.cpp @@ -0,0 +1,204 @@ +/* + * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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 "WUiTimer.h" +#include "WDebugInternal.h" +#include "WDefineInternal.h" +#include "WUiTimerImpl.h" + +using namespace app_assist; + +WUiTimer::WUiTimer() +{ + WHIT(); + __pv = new _WUiTimerImpl(); +} + +WUiTimer::~WUiTimer() +{ + WHIT(); + if (__pv->__ownerObj) { + evas_object_event_callback_del_full(__pv->__ownerObj, EVAS_CALLBACK_DEL, _WUiTimerImpl::__ownerObjDelCb, this); + } + delete __pv; +} + +WUiTimer::Type WUiTimer::getType() +{ + return __pv->__type; +} + +void WUiTimer::destroy(WUiTimerWeakPtr& timer) +{ + if (auto p = timer.lock()) { + delete p.get(); + } + timer.reset(); +} + +WUiTimerWeakPtr WUiTimer::addIdler(const std::function& timerFunc, void* userData, Evas_Object* ownerObj) +{ + WASSERT_EX(ownerObj != nullptr, "ownerObj is null."); + + WUiTimerWeakPtr timerPtr = WUiTimer::addIdler(timerFunc, userData); + std::shared_ptr timer = timerPtr.lock(); + timer->__pv->__ownerObj = ownerObj; + + evas_object_event_callback_add(ownerObj, EVAS_CALLBACK_DEL, _WUiTimerImpl::__ownerObjDelCb, timer.get()); + + timer.reset(); + + return timerPtr; +} + +WUiTimerWeakPtr WUiTimer::addIdler(const std::function& timerFunc, void* userData) +{ + WUiTimer* timer = new WUiTimer(); + timer->__pv->__selfPtr = new std::shared_ptr(timer, [](WUiTimer * p) {}); + timer->__pv->__type = WUiTimer::Type::IDLER; + timer->__pv->__timerFunc = timerFunc; + timer->__pv->__userData = userData; + Ecore_Idler* ecoreIdler = ecore_idler_add(_WUiTimerImpl::__timerCb, timer); + if (ecoreIdler == nullptr) { + WERROR("failed to add ecore idler!"); + delete timer; + return std::weak_ptr(); + } + timer->__pv->__timer = ecoreIdler; + + return std::weak_ptr(*timer->__pv->__selfPtr); +} + +WUiTimerWeakPtr WUiTimer::addAnimator(const std::function& timerFunc, void* userData, Evas_Object* ownerObj) +{ + WASSERT_EX(ownerObj != nullptr, "ownerObj is null."); + + WUiTimerWeakPtr timerPtr = WUiTimer::addAnimator(timerFunc, userData); + std::shared_ptr timer = timerPtr.lock(); + timer->__pv->__ownerObj = ownerObj; + + evas_object_event_callback_add(ownerObj, EVAS_CALLBACK_DEL, _WUiTimerImpl::__ownerObjDelCb, timer.get()); + + timer.reset(); + + return timerPtr; +} + +WUiTimerWeakPtr WUiTimer::addAnimator(const std::function& timerFunc, void* userData) +{ + WUiTimer* timer = new WUiTimer(); + timer->__pv->__selfPtr = new std::shared_ptr(timer, [](WUiTimer * p) {}); + timer->__pv->__type = WUiTimer::Type::ANIMATOR; + timer->__pv->__timerFunc = timerFunc; + timer->__pv->__userData = userData; + Ecore_Animator* ecoreAnimator = ecore_animator_add(_WUiTimerImpl::__timerCb, timer); + if (ecoreAnimator == nullptr) { + WERROR("failed to add ecore animator!"); + delete timer; + return std::weak_ptr(); + } + timer->__pv->__timer = ecoreAnimator; + + return std::weak_ptr(*timer->__pv->__selfPtr); +} + +WUiTimerWeakPtr WUiTimer::addTimer(double interval, const std::function& timerFunc, void* userData, Evas_Object* ownerObj) +{ + WASSERT_EX(ownerObj != nullptr, "ownerObj is null."); + + WUiTimerWeakPtr timerPtr = WUiTimer::addTimer(interval, timerFunc, userData); + std::shared_ptr timer = timerPtr.lock(); + timer->__pv->__ownerObj = ownerObj; + + evas_object_event_callback_add(ownerObj, EVAS_CALLBACK_DEL, _WUiTimerImpl::__ownerObjDelCb, timer.get()); + + timer.reset(); + + return timerPtr; +} + +WUiTimerWeakPtr WUiTimer::addTimer(double interval, const std::function& timerFunc, void* userData) +{ + WUiTimer* timer = new WUiTimer(); + timer->__pv->__selfPtr = new std::shared_ptr(timer, [](WUiTimer * p) {}); + timer->__pv->__type = WUiTimer::Type::TIMER; + timer->__pv->__timerFunc = timerFunc; + timer->__pv->__userData = userData; + Ecore_Timer* ecoreTimer = ecore_timer_add(interval, _WUiTimerImpl::__timerCb, timer); + if (ecoreTimer == nullptr) { + WERROR("failed to add ecore timer!"); + delete timer; + return std::weak_ptr(); + } + timer->__pv->__timer = ecoreTimer; + + return std::weak_ptr(*timer->__pv->__selfPtr); +} + +WUiTimerWeakPtr WUiTimer::addJob(const std::function& timerFunc, void* userData, Evas_Object* ownerObj) +{ + WASSERT_EX(ownerObj != nullptr, "ownerObj is null."); + + WUiTimerWeakPtr timerPtr = WUiTimer::addJob(timerFunc, userData); + std::shared_ptr timer = timerPtr.lock(); + timer->__pv->__ownerObj = ownerObj; + + evas_object_event_callback_add(ownerObj, EVAS_CALLBACK_DEL, _WUiTimerImpl::__ownerObjDelCb, timer.get()); + + timer.reset(); + + return timerPtr; +} + +WUiTimerWeakPtr WUiTimer::addJob(const std::function& timerFunc, void* userData) +{ + WUiTimer* timer = new WUiTimer(); + timer->__pv->__selfPtr = new std::shared_ptr(timer, [](WUiTimer * p) {}); + timer->__pv->__type = WUiTimer::Type::JOB; + timer->__pv->__jobFunc = timerFunc; + timer->__pv->__userData = userData; + Ecore_Job* ecoreJob = ecore_job_add(_WUiTimerImpl::__jobCb, timer); + if (ecoreJob == nullptr) { + WERROR("failed to add ecore job!"); + delete timer; + return std::weak_ptr(); + } + timer->__pv->__timer = ecoreJob; + + return std::weak_ptr(*timer->__pv->__selfPtr); +} + +Ecore_Idler* app_assist::wuitimer_get_idler_handle(const WUiTimerWeakPtr& uiTimer) +{ + return _WUiTimerImpl::getIdlerHandle(uiTimer); +} + +Ecore_Animator* app_assist::wuitimer_get_animator_handle(const WUiTimerWeakPtr& uiTimer) +{ + return _WUiTimerImpl::getAnimatorHandle(uiTimer); +} + +Ecore_Timer* app_assist::wuitimer_get_timer_handle(const WUiTimerWeakPtr& uiTimer) +{ + return _WUiTimerImpl::getTimerHandle(uiTimer); +} + +Ecore_Job* app_assist::wuitimer_get_job_handle(const WUiTimerWeakPtr& uiTimer) +{ + return _WUiTimerImpl::getJobHandle(uiTimer); +} + diff --git a/src/app-assist-efl/WUiTimerImpl.cpp b/src/app-assist-efl/WUiTimerImpl.cpp new file mode 100644 index 0000000..6816458 --- /dev/null +++ b/src/app-assist-efl/WUiTimerImpl.cpp @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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 "WUiTimerImpl.h" +#include +#include "WDefine.h" +#include "WDebugInternal.h" +#include "WUiTimer.h" + +using namespace app_assist; + +_WUiTimerImpl::_WUiTimerImpl(): + __timer(nullptr), + __type(WUiTimer::Type::IDLER), + __userData(nullptr), + __selfPtr(nullptr), + __ownerObj(nullptr) +{ +} + +_WUiTimerImpl::~_WUiTimerImpl() +{ + __deleteTimer(); + delete __selfPtr; +} + +void _WUiTimerImpl::__deleteTimer() +{ + if (__timer) { + switch (__type) { + case WUiTimer::Type::IDLER: + ecore_idler_del((Ecore_Idler*)__timer); + break; + case WUiTimer::Type::ANIMATOR: + ecore_animator_del((Ecore_Animator*)__timer); + break; + case WUiTimer::Type::TIMER: + ecore_timer_del((Ecore_Timer*)__timer); + break; + case WUiTimer::Type::JOB: + ecore_job_del((Ecore_Job*)__timer); + break; + default: + break; + } + __timer = nullptr; + } +} + +void _WUiTimerImpl::__ownerObjDelCb(void* data, Evas* evas, Evas_Object* obj, void* event_info) +{ + WHIT(); + + auto timer = (WUiTimer*)data; + timer->__pv->__ownerObj = nullptr; + delete timer; +} + +Eina_Bool _WUiTimerImpl::__timerCb(void* data) +{ + auto timer = (WUiTimer*)data; + std::weak_ptr timerWeakPtr(*(timer->__pv->__selfPtr)); + + Eina_Bool ret = timer->__pv->__timerFunc(timer->__pv->__userData); + if (ret == ECORE_CALLBACK_CANCEL && !timerWeakPtr.expired()) { + timer->__pv->__timer = nullptr; + delete timer; + } + + return ret; +} + +void _WUiTimerImpl::__jobCb(void* data) +{ + auto timer = (WUiTimer*)data; + std::weak_ptr timerWeakPtr(*(timer->__pv->__selfPtr)); + + timer->__pv->__jobFunc(timer->__pv->__userData); + if (!timerWeakPtr.expired()) { + timer->__pv->__timer = nullptr; + delete timer; + } +} + +Ecore_Idler* _WUiTimerImpl::getIdlerHandle(const WUiTimerWeakPtr& uiTimer) +{ + if (auto p = uiTimer.lock()) { + if (p->__pv->__type != WUiTimer::Type::IDLER) { + WERROR("This is not Idler type timer!"); + return nullptr; + } + return (Ecore_Idler*)p->__pv->__timer; + } + return nullptr; +} + +Ecore_Animator* _WUiTimerImpl::getAnimatorHandle(const WUiTimerWeakPtr& uiTimer) +{ + if (auto p = uiTimer.lock()) { + if (p->__pv->__type != WUiTimer::Type::ANIMATOR) { + WERROR("This is not Animator type timer!"); + return nullptr; + } + return (Ecore_Animator*)p->__pv->__timer; + } + return nullptr; +} + +Ecore_Timer* _WUiTimerImpl::getTimerHandle(const WUiTimerWeakPtr& uiTimer) +{ + if (auto p = uiTimer.lock()) { + if (p->__pv->__type != WUiTimer::Type::TIMER) { + WERROR("This is not Timer type timer!"); + return nullptr; + } + return (Ecore_Timer*)p->__pv->__timer; + } + return nullptr; +} + +Ecore_Job* _WUiTimerImpl::getJobHandle(const WUiTimerWeakPtr& uiTimer) +{ + if (auto p = uiTimer.lock()) { + if (p->__pv->__type != WUiTimer::Type::JOB) { + WERROR("This is not Job type timer!"); + return nullptr; + } + return (Ecore_Job*)p->__pv->__timer; + } + return nullptr; +} diff --git a/src/app-assist-efl/WUiTimerImpl.h b/src/app-assist-efl/WUiTimerImpl.h new file mode 100644 index 0000000..effb0bb --- /dev/null +++ b/src/app-assist-efl/WUiTimerImpl.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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 _APP_ASSIST_WUI_TIMER_IMPL_H_ +#define _APP_ASSIST_WUI_TIMER_IMPL_H_ + +#include +#include "WUiTimer.h" + +namespace app_assist +{ + +class _WUiTimerImpl +{ +public: + _WUiTimerImpl(); + ~_WUiTimerImpl(); +private: + // + void* __timer; + WUiTimer::Type __type; + + void* __userData; + std::shared_ptr* __selfPtr; + Evas_Object* __ownerObj; + + std::function __timerFunc; + std::function __jobFunc; + // + void __deleteTimer(); + + static void __ownerObjDelCb(void* data, Evas* evas, Evas_Object* obj, void* event_info); + static Eina_Bool __timerCb(void* data); + static void __jobCb(void* data); + + static Ecore_Idler* getIdlerHandle(const WUiTimerWeakPtr& uiTimer); + static Ecore_Animator* getAnimatorHandle(const WUiTimerWeakPtr& uiTimer); + static Ecore_Timer* getTimerHandle(const WUiTimerWeakPtr& uiTimer); + static Ecore_Job* getJobHandle(const WUiTimerWeakPtr& uiTimer); + // + friend class WUiTimer; + friend Ecore_Idler* wuitimer_get_idler_handle(const WUiTimerWeakPtr& uiTimer); + friend Ecore_Animator* wuitimer_get_animator_handle(const WUiTimerWeakPtr& uiTimer); + friend Ecore_Timer* wuitimer_get_timer_handle(const WUiTimerWeakPtr& uiTimer); + friend Ecore_Job* wuitimer_get_job_handle(const WUiTimerWeakPtr& uiTimer); +}; + +} // namespace + +#endif /* __APP_ASSIST_WUI_TIMER_IMPL_H__ */ diff --git a/src/app-assist-efl/WVersion.cpp b/src/app-assist-efl/WVersion.cpp new file mode 100644 index 0000000..a8052b1 --- /dev/null +++ b/src/app-assist-efl/WVersion.cpp @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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 "WDefine.h" +#include +#include + +int app_assist::WVersion_getMajor() +{ + return WAPP_ASSIST_VERSION_MAJOR; +} +int app_assist::WVersion_getMinor() +{ + return WAPP_ASSIST_VERSION_MINOR; +} +int app_assist::WVersion_getPatch() +{ + return WAPP_ASSIST_VERSION_PATCH; +} +const char* app_assist::WVersion_getPre() +{ + return WAPP_ASSIST_VERSION_PRE; +} +const char* app_assist::WVersion_get() +{ + static char ver[24] = {0, }; + if (ver[0] == '\0') { + if (strlen(WAPP_ASSIST_VERSION_PRE)) + snprintf(ver, sizeof(ver), "%d.%d.%d.%s", WAPP_ASSIST_VERSION_MAJOR, WAPP_ASSIST_VERSION_MINOR, WAPP_ASSIST_VERSION_PATCH, WAPP_ASSIST_VERSION_PRE); + else + snprintf(ver, sizeof(ver), "%d.%d.%d", WAPP_ASSIST_VERSION_MAJOR, WAPP_ASSIST_VERSION_MINOR, WAPP_ASSIST_VERSION_PATCH); + } + + return ver; +} diff --git a/src/app-assist-efl/WViewController.cpp b/src/app-assist-efl/WViewController.cpp new file mode 100644 index 0000000..e34d35d --- /dev/null +++ b/src/app-assist-efl/WViewController.cpp @@ -0,0 +1,206 @@ +/* + * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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 "WViewController.h" +#include +#include +#include "WDebugInternal.h" +#include "WDefineInternal.h" +#include "IWWindowController.h" +#include "WViewControllerImpl.h" + +using namespace app_assist; + +#define _CLASS_NAME "WViewController" + +WViewController::WViewController() +{ + __pv = new _WViewControllerImpl(); +} + +WViewController::~WViewController() +{ + if (__pv->__name) { + WDEBUG("name=%s", __pv->__name); + } else { + WHIT(); + } + // + delete __pv; +} +const char* WViewController::getClassName() const +{ + return _CLASS_NAME; +} + +bool WViewController::create(Evas_Object* parent, void* param) +{ + if (__pv->__name) + WDEBUG("name=%s", __pv->__name); + else + WHIT(); + + if (__pv->__obj) { + WDEBUG("Already created!"); + return true; + } + if (!onCreate(param)) { + WDEBUG("Failed to create!"); + return false; + } + + if (__pv->__createViewDelegate) + __pv->__obj = (*__pv->__createViewDelegate)(parent, param); + else + __pv->__obj = onCreateView(parent, param); + + if (__pv->__obj == nullptr) { + WERROR("No view object created!"); + return false; + } + + // get window controller + Evas_Object* obj = __pv->__obj; + while ((obj = elm_object_parent_widget_get(obj)) != nullptr) { + if ((__pv->__windowController = (IWWindowController*)evas_object_data_get(obj, WKEY_WINDOW_INSTANCE)) != nullptr) { + break; + } + } + WASSERT_EX(__pv->__windowController != nullptr, "Cannot find window controll."); + + if (__pv->__name) { // for easy debugging + evas_object_name_set(__pv->__obj, __pv->__name); + } + + evas_object_data_set(__pv->__obj, WKEY_VIEW_INSTANCE, this); + evas_object_event_callback_add(__pv->__obj, EVAS_CALLBACK_DEL, _WViewControllerImpl::__objDelCb, this); + // + // Do not place this before "evas_object_event_callback_add", + // The reason is that if additional del callback is added at child class, it should be called first to keep state the class object is still alive. + onCreated(); + + return true; +} + +void WViewController::destroy() +{ + if (__pv->__obj) { + evas_object_del(__pv->__obj); + // Do not leave any code here. + // After executing upper statement "evas_object_del", this object will be deleted at evas object deletion callback! + + } else { + onDestroy(); + delete this; + } +} + +Evas_Object* WViewController::getEvasObj() const +{ + return __pv->__obj; +} + +void WViewController::setName(const char* name) +{ + if (__pv->__name) { + free(__pv->__name); + __pv->__name = nullptr; + } + if (name) { + __pv->__name = (char*)malloc(strlen(name) + 1); + strcpy(__pv->__name, name); + } +} + +const char* WViewController::getName() const +{ + return __pv->__name; +} + +void WViewController::setOnCreateView(const std::function& delegateFunc) +{ + if (__pv->__createViewDelegate == nullptr) + __pv->__createViewDelegate = new std::function; + *__pv->__createViewDelegate = delegateFunc; +} + +std::weak_ptr WViewController::getWeakPtr() +{ + if (__pv->__selfPtr) { + return std::weak_ptr(*__pv->__selfPtr); + } + __pv->__selfPtr = new std::shared_ptr(this, [](WViewController * p) {}); + return std::weak_ptr(*__pv->__selfPtr); +} + +void WViewController::attachPopup(WViewController* popup) +{ + Evas_Object* parent = nullptr; + Evas_Object* obj = getEvasObj(); + while ((obj = elm_object_parent_widget_get(obj)) != nullptr) { + if (evas_object_data_get(obj, WKEY_BASELAYOUT_TAG) != nullptr) { + parent = obj; + break; + } + } + + if (parent == nullptr) { + WERROR("Cannot find parent View!"); + // If the pop-up has been already created, the following statement will just return without creating pop-up. + popup->create(elm_object_top_widget_get(getEvasObj()), nullptr); + } else { + // If the pop-up has been already created, the following statement will just return without creating pop-up. + popup->create(parent, nullptr); + } + + // destroy old popup after new popup created + destroyPopup(); + + if (__pv->__popupMonitor == nullptr) + __pv->__popupMonitor = new std::weak_ptr; + *__pv->__popupMonitor = popup->getWeakPtr(); +} + +void WViewController::destroyPopup() +{ + if (__pv->__popupMonitor == nullptr) return; + + if (auto p = __pv->__popupMonitor->lock()) { + p->destroy(); + __pv->__popupMonitor->reset(); + } +} + +IWWindowController* WViewController::getWindowController() +{ + return __pv->__windowController; +} + +WViewController* app_assist::wviewcontroller_get_instance_from_evasobj(Evas_Object* obj) +{ + return (WViewController*)evas_object_data_get(obj, WKEY_VIEW_INSTANCE); +} + +Evas_Object* app_assist::wviewcontroller_get_window_baselayout_evasobj(WViewController* view) +{ + return _WViewControllerImpl::getWindowBaseLayoutEvasObj(view); +} + +Evas_Object* app_assist::wviewcontroller_get_window_evasobj(WViewController* view) +{ + return _WViewControllerImpl::getWindowEvasObj(view); +} diff --git a/src/app-assist-efl/WViewControllerImpl.cpp b/src/app-assist-efl/WViewControllerImpl.cpp new file mode 100644 index 0000000..ed28734 --- /dev/null +++ b/src/app-assist-efl/WViewControllerImpl.cpp @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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 "WViewControllerImpl.h" +#include +#include "WViewController.h" +#include "IWWindowController.h" +#include "WDebugInternal.h" + +using namespace app_assist; + +_WViewControllerImpl::_WViewControllerImpl(): + __obj(nullptr), + __name(nullptr), + __selfPtr(nullptr), + __popupMonitor(nullptr), + __createViewDelegate(nullptr), + __windowController(nullptr) +{ +} + +_WViewControllerImpl::~_WViewControllerImpl() +{ + free(__name); + + if (__popupMonitor) { + if (auto p = __popupMonitor->lock()) { + p->destroy(); + } + } + delete __popupMonitor; + delete __createViewDelegate; + delete __selfPtr; +} + +void _WViewControllerImpl::__objDelCb(void* data, Evas* evas, Evas_Object* obj, void* event_info) +{ + auto ctrl = (WViewController*)data; + ctrl->onDestroy(); + + delete ctrl; +} + +Evas_Object* _WViewControllerImpl::getWindowBaseLayoutEvasObj(WViewController* view) +{ + if (view->getWindowController()) { + return view->getWindowController()->getBaseLayoutEvasObj(); + } else { + WERROR("Fail to get base layout!"); + return nullptr; + } +} + +Evas_Object* _WViewControllerImpl::getWindowEvasObj(WViewController* view) +{ + if (view->getWindowController()) { + return view->getWindowController()->getEvasObj(); + } else { + WERROR("Fail to get window evas object!"); + return nullptr; + } +} + diff --git a/src/app-assist-efl/WViewControllerImpl.h b/src/app-assist-efl/WViewControllerImpl.h new file mode 100644 index 0000000..17d10a1 --- /dev/null +++ b/src/app-assist-efl/WViewControllerImpl.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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 _APP_ASSIST_WVIEW_CONTROLLER_IMPL_H_ +#define _APP_ASSIST_WVIEW_CONTROLLER_IMPL_H_ + +//#include +#include +#include "IWWindowController.h" + +namespace app_assist +{ + +class WViewController; + +class _WViewControllerImpl +{ +public: + _WViewControllerImpl(); + ~_WViewControllerImpl(); +private: + + Evas_Object* __obj; + char* __name; + std::shared_ptr* __selfPtr; + std::weak_ptr* __popupMonitor; + std::function* __createViewDelegate; + IWWindowController* __windowController; + + static void __objDelCb(void* data, Evas* evas, Evas_Object* obj, void* event_info); + static Evas_Object* getWindowBaseLayoutEvasObj(WViewController* view); + static Evas_Object* getWindowEvasObj(WViewController* view); + // + friend class WViewController; + friend Evas_Object* wviewcontroller_get_window_baselayout_evasobj(WViewController* view); + friend Evas_Object* wviewcontroller_get_window_evasobj(WViewController* view); +}; + +} // namespace + +#endif /* __APP_ASSIST_WVIEW_CONTROLLER_IMPL_H__ */ diff --git a/src/app-assist-efl/WWindowController.cpp b/src/app-assist-efl/WWindowController.cpp new file mode 100644 index 0000000..ff8fc53 --- /dev/null +++ b/src/app-assist-efl/WWindowController.cpp @@ -0,0 +1,366 @@ +/* + * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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 "WWindowController.h" +#include +#include + +#ifndef WUSING_PUBLIC_SDK + +//#ifndef WUSING_SDK_2_3 +//#include +//#else +#include +//#endif + +#endif + +#include "WViewController.h" +#include "WDebugInternal.h" +#include "WDefineInternal.h" + +using namespace app_assist; + +#ifndef WUSING_PUBLIC_SDK +#define _USE_PROCESS_POOL 0 +#else +#define _USE_PROCESS_POOL 0 +#endif + +#define _CLASS_NAME "WWindowController" + +namespace app_assist +{ + +class _WWindowControllerImpl +{ +public: + _WWindowControllerImpl(const char* inName, Elm_Win_Type inWinType); + _WWindowControllerImpl() = delete; + ~_WWindowControllerImpl(); +public: + // + Evas_Object* __win; + Evas_Object* __baseLayout; + Evas_Object* __conformant; + WViewController* __baseViewController; + char* __name; + Elm_Win_Type __winType; + // + std::function __createWinDelegate; + std::function __createBaseLayoutDelegate; + std::function __backHandler; + + static void __delReqCb(void* data, Evas_Object* obj, void* event_info); + static void __objDelCb(void* data, Evas* evas, Evas_Object* obj, void* event_info); +}; +} + +_WWindowControllerImpl::_WWindowControllerImpl(const char* name, Elm_Win_Type winType): + __win(nullptr), + __baseLayout(nullptr), + __conformant(nullptr), + __baseViewController(nullptr), + __name(nullptr), + __winType(ELM_WIN_BASIC) +{ + WASSERT(name); + __name = (char*)malloc(strlen(name) + 1); + strcpy(__name, name); + __winType = winType; +} + +_WWindowControllerImpl::~_WWindowControllerImpl() +{ + free(__name); +} + + +void _WWindowControllerImpl::__delReqCb(void* data, Evas_Object* obj, void* event_info) +{ + WHIT(); + elm_exit(); +} +void _WWindowControllerImpl::__objDelCb(void* data, Evas* evas, Evas_Object* obj, void* event_info) +{ + WHIT(); + + auto win = (WWindowController*)data; + + win->onDestroy(); + delete win; +} + + +WWindowController::WWindowController(const char* name, Elm_Win_Type winType) +{ + __pv = new _WWindowControllerImpl(name, winType); +} + +WWindowController::~WWindowController() +{ + WHIT(); + delete __pv; +} + +const char* WWindowController::getClassName() +{ + return _CLASS_NAME; +} + +bool WWindowController::create() +{ + if (__pv->__win) { + WDEBUG("Already created!"); + return true; + } + + if (precreate()) { + evas_object_show(__pv->__win); + return true; + } else { + return false; + } +} + +bool WWindowController::precreate() +{ + if (__pv->__win) { + WDEBUG("Already created!"); + return true; + } + + Evas_Object* win = nullptr; + if (__pv->__createWinDelegate) + win = __pv->__createWinDelegate(); + else + win = onCreateWin(); + __pv->__win = win; + if (win) { + Evas_Object* cf = nullptr; + if (__pv->__createBaseLayoutDelegate) + __pv->__baseLayout = __pv->__createBaseLayoutDelegate(win, &cf); + else + __pv->__baseLayout = onCreateBaseLayout(win, &cf); + __pv->__conformant = cf; + evas_object_data_set(win, WKEY_WINDOW_INSTANCE, this); + if (__pv->__baseLayout) + evas_object_data_set(__pv->__baseLayout, WKEY_BASELAYOUT_TAG, this); + // This callback function is called when 'x' close button on the window at desktop mode. In mobile, it will not be called. + evas_object_smart_callback_add(win, "delete,request", _WWindowControllerImpl::__delReqCb, this); + evas_object_event_callback_add(win, EVAS_CALLBACK_DEL, _WWindowControllerImpl::__objDelCb, this); + + if (__pv->__backHandler) { + eext_object_event_callback_add(win, EEXT_CALLBACK_BACK, + [](void *data, Evas_Object *obj, void *event_info)->void { + auto wc = (WWindowController*)data; + wc->__pv->__backHandler(); + }, this); + } + + return true; + } else { + return false; + } +} + +void WWindowController::destroy() +{ + if (__pv->__win) { + evas_object_del(__pv->__win); + // Do not leave any code here. + // After executing upper statement "evas_object_del", this object will be deleted at evas object deletion callback! + + } else { + onDestroy(); + delete this; + } +} + +Evas_Object* WWindowController::getEvasObj() const +{ + return __pv->__win; +} + +Evas_Object* WWindowController::getBaseLayoutEvasObj() +{ + return __pv->__baseLayout; +} + +Evas_Object* WWindowController::getConformantEvasObj() +{ + return __pv->__conformant; +} + +bool WWindowController::attachBaseViewController(WViewController* vc, void* creationParam) +{ + WASSERT(__pv->__baseViewController == nullptr); + + // If baseLayout is nullptr, the vc should be already created before attaching. + if (__pv->__baseLayout) { + if (vc->create(__pv->__baseLayout, creationParam) == false) { + return false; + } + } + + onAttachBaseViewController(vc); + + __pv->__baseViewController = vc; + +// evas_object_data_set( vc->getEvasObj(), WKEY_WINDOW_INSTANCE, this ); + + return true; +} + +bool WWindowController::attachBaseViewController(WViewController* vc) +{ + return attachBaseViewController(vc, nullptr); +} + +WViewController* WWindowController::getBaseViewController() +{ + return __pv->__baseViewController; +} + +WViewController* WWindowController::detachBaseViewController() +{ + WViewController* vc = __pv->__baseViewController; + + onDetachBaseViewController(vc); + + __pv->__baseViewController = nullptr; + + return vc; +} + +void WWindowController::destroyBaseViewController() +{ + if (__pv->__baseViewController) + __pv->__baseViewController->destroy(); + + __pv->__baseViewController = nullptr; +} + +const char* WWindowController::getName() +{ + return __pv->__name; +} +Elm_Win_Type WWindowController::getWinType() +{ + return __pv->__winType; +} +void WWindowController::setOnCreateWin(const std::function& delegateFunc) +{ + __pv->__createWinDelegate = delegateFunc; +} +void WWindowController::setOnCreateBaseLayout(const std::function& delegateFunc) +{ + __pv->__createBaseLayoutDelegate = delegateFunc; +} + +void WWindowController::setOnBack(const std::function& backHandlerFunc) +{ + __pv->__backHandler = backHandlerFunc; +} + +Evas_Object* WWindowController::onCreateWin() +{ +#if _USE_PROCESS_POOL == 1 + Evas_Object* win = (Evas_Object*)app_get_preinitialized_window(getName()); // for launch performance + if (win == nullptr) { + WDEBUG("Process pool not used"); + win = elm_win_add(nullptr, getName(), getWinType()); + } else { + WDEBUG("Process pool used"); + } +#else + Evas_Object* win = elm_win_add(nullptr, getName(), getWinType()); +#endif + + if (win == nullptr) { + WERROR("Fail to create win!"); + return nullptr; + } + + elm_win_title_set(win, getName()); + elm_win_conformant_set(win, EINA_TRUE); + elm_win_autodel_set(win, EINA_TRUE); + if (elm_win_wm_rotation_supported_get(win)) { + int rotation[4] = {0, 90, 180, 270}; + elm_win_wm_rotation_available_rotations_set(win, (const int*)(&rotation), 4); + } + elm_win_indicator_mode_set(win, ELM_WIN_INDICATOR_SHOW); + elm_win_indicator_opacity_set(win, ELM_WIN_INDICATOR_OPAQUE); + + return win; +} + +Evas_Object* WWindowController::onCreateBaseLayout(Evas_Object* win, Evas_Object** outConformant) +{ +#if _USE_PROCESS_POOL == 1 + Evas_Object* bg = (Evas_Object*)app_get_preinitialized_background(); // for launch performance + if (bg == nullptr) + bg = elm_bg_add(win); +#else + Evas_Object* bg = elm_bg_add(win); +#endif + + evas_object_size_hint_weight_set(bg, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + elm_win_resize_object_add(win, bg); + evas_object_show(bg); + + // If window has no conformant object, ug creation is failed. +#if _USE_PROCESS_POOL == 1 + Evas_Object* cf = (Evas_Object*)app_get_preinitialized_conformant(); // for launch performance + if (cf == nullptr) + cf = elm_conformant_add(win); +#else + Evas_Object* cf = elm_conformant_add(win); +#endif + + evas_object_size_hint_weight_set(cf, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + elm_win_resize_object_add(win, cf); + evas_object_show(cf); +// + Evas_Object* layout = elm_layout_add(cf); + elm_layout_theme_set(layout, "layout", "application", "default"); + evas_object_size_hint_weight_set(layout, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + elm_object_content_set(cf, layout); + + evas_object_show(layout); + + *outConformant = cf; + + return layout; +} + +void WWindowController::onAttachBaseViewController(WViewController* vc) +{ + if (getBaseLayoutEvasObj() == nullptr) { + WWARNING("base layout does not exist!"); + return; + } + elm_object_part_content_set(getBaseLayoutEvasObj(), "elm.swallow.content", vc->getEvasObj()); +} + +void WWindowController::onDetachBaseViewController(WViewController* vc) +{ +} + +void WWindowController::onDestroy() +{ +} diff --git a/src/app-assist-efl/inc/WContentViewControllerImpl.h b/src/app-assist-efl/inc/WContentViewControllerImpl.h new file mode 100644 index 0000000..0f864b3 --- /dev/null +++ b/src/app-assist-efl/inc/WContentViewControllerImpl.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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 _APP_ASSIST_WCONTENT_VIEW_CONTROLLER_IMPL_H_ +#define _APP_ASSIST_WCONTENT_VIEW_CONTROLLER_IMPL_H_ + +#include +#include + +namespace app_assist +{ + +class WContentViewController; +class WNaviframeController; + +class _WContentViewControllerImpl +{ +public: + _WContentViewControllerImpl(); + ~_WContentViewControllerImpl(); +public: + bool callPushedHandlerFunc(Elm_Object_Item* naviItem); +private: + // + char* __title; + Elm_Object_Item* __naviItem; + bool __isViewNaviItem; + // + WNaviframeController* __naviframe; + // + std::function __pushedDelegate; + + static void setContainerProperties(WContentViewController* view, WNaviframeController* naviframe); + static void setContainerNaviitemProperty(WContentViewController* view, Elm_Object_Item* item, bool isViewNaviItem); + static void propagateContainerPropertiesToChildViews(WContentViewController* view); + // + friend class WContentViewController; + friend void wcontentviewcontroller_set_container_properties(WContentViewController* view, WNaviframeController* naviframe); + friend void wcontentviewcontroller_set_container_naviitem_property(WContentViewController* view, Elm_Object_Item* item, bool isViewNaviItem); + friend void wcontentviewcontroller_propagate_container_properties_to_childviews(WContentViewController* view); +}; + +} // namespace + +#endif /* _APP_ASSIST_WCONTENT_VIEW_CONTROLLER_IMPL_H_ */ diff --git a/src/app-assist-efl/inc/WDebugInternal.h b/src/app-assist-efl/inc/WDebugInternal.h new file mode 100755 index 0000000..3fbc512 --- /dev/null +++ b/src/app-assist-efl/inc/WDebugInternal.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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 _APP_ASSIST_WDEBUG_INTERNAL_H_ +#define _APP_ASSIST_WDEBUG_INTERNAL_H_ + +#ifdef LOG_TAG +#undef LOG_TAG +#endif + +#define LOG_TAG "WAPP" + +#include "WDebugBase.h" + + +#endif /* _APP_ASSIST_WDEBUG_INTERNAL_H_ */ diff --git a/src/app-assist-efl/inc/WDefineInternal.h b/src/app-assist-efl/inc/WDefineInternal.h new file mode 100755 index 0000000..048f3f5 --- /dev/null +++ b/src/app-assist-efl/inc/WDefineInternal.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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 _APP_ASSIST_WDEFINE_INTERNAL_H_ +#define _APP_ASSIST_WDEFINE_INTERNAL_H_ + + +#define WKEY_WINDOW_INSTANCE "__@WWindowInstance" +#define WKEY_FRAME_INSTANCE "__@WNaviframeInstance" +#define WKEY_VIEW_INSTANCE "__@WViewInstance" +#define WKEY_BASELAYOUT_TAG "__@WBaselayoutTag" + +#endif /*_APP_ASSIST_WDEFINE_INTERNAL_H_ */ diff --git a/src/app-assist-efl/inc/WMenuPopupControllerImpl.h b/src/app-assist-efl/inc/WMenuPopupControllerImpl.h new file mode 100644 index 0000000..5c959be --- /dev/null +++ b/src/app-assist-efl/inc/WMenuPopupControllerImpl.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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 _APP_ASSIST_WMENU_POPUP_CONTROLLER_IMPL_H_ +#define _APP_ASSIST_WMENU_POPUP_CONTROLLER_IMPL_H_ + +#include +#include +#include + +namespace app_assist +{ + +class _WMenuPopupControllerImpl +{ +public: + _WMenuPopupControllerImpl(); + ~_WMenuPopupControllerImpl(); +public: + static void destroyLastMenuPopup(); + +private: + // + static Evas_Object* __lastMenuPopup; + + Evas_Object* __win; + Evas_Object* __resizableBaseObj; + Evas_Object* __popup; + std::vector> __vSelectItemCb; + + void __init(Evas_Object* win, Evas_Object* naviframe); + void __popupMove(); + Evas_Object* __create(); + + static void __popupSelectCb(void* data, Evas_Object* obj, void* event_info); + static void __popupResizeCb(void* data, Evas* e, Evas_Object* obj, void* event_info); + static void __popupWinRotateCb(void* data, Evas_Object* obj, void* event_info); + static void __popupDismissedCb(void* data, Evas_Object* obj, void* event_info); + + friend class WMenuPopupController; +}; + +} // namespace + +#endif /* _APP_ASSIST_WMENU_POPUP_CONTROLLER_IMPL_H_ */ diff --git a/src/app/CDrApp.cpp b/src/app/CDrApp.cpp new file mode 100755 index 0000000..17186ae --- /dev/null +++ b/src/app/CDrApp.cpp @@ -0,0 +1,315 @@ +#include +#include +#include +#include +#include +#include "CDrApp.h" +#include "WWindowController.h" +#include "WNaviframeController.h" +#include "WContentViewController.h" +#include "DrDefine.h" +#include "CDrAppData.h" +#include "CDrDrawingView.h" +#include "CDrEventManager.h" +#include "CDrMainView.h" +#include "CDrMediaContent.h" +#include "CDrUtil.h" + + + +Ecore_Timer *CDrApp::_closeTimer = nullptr; + +CDrApp::CDrApp() +{ + _appControlOperation = nullptr; +} + +CDrApp::~CDrApp() +{ + if (_appControlOperation){ + free(_appControlOperation); + _appControlOperation = nullptr; + } + + CDrEventManager::destroy(); + CDrMediaContent::destroyInstance(); +} + +/* * + * The basic policy of Tizen applications for OOM case is "silent exit" as Android. + * Kernel will send SIGTERM signal (standard unix signal) to background application + * when OOM happens. + * Application should register SIGTERM handler and silently free every critical resource and exit. +*/ +void CDrApp::_onSigtermHanlder(int signum) +{ + /* do something for signal handling */ + WINFO("SIGTERM CDrApp "); + notification_status_message_post(DRAWING_SYATEM_TERMINATE_APP); + _closeTimer = ecore_timer_add(2, _onCloseTimer, nullptr); + ui_app_exit(); +} + +Eina_Bool CDrApp::_onCloseTimer(void *data) +{ + return ECORE_CALLBACK_CANCEL; +} + +bool CDrApp::onCreate() +{ + /* regitering sigterm */ + if (signal(SIGTERM, CDrApp::_onSigtermHanlder) == SIG_IGN) { + WINFO("SIG_IGN SIGTERM"); + signal(SIGTERM, SIG_IGN); + } + + elm_app_base_scale_set(1.3); + elm_config_accel_preference_set("opengl"); + + char *resPath = app_get_resource_path(); + if (resPath == nullptr) { + WERROR("Failed to get res path"); + return false; + } + std::string localeDir(resPath); + free(resPath); + + localeDir.append("locale"); + /* Bind text domain for internalization */ + bindtextdomain(LOCALE_DOMAIN, localeDir.c_str()); + + WDEBUG("init app"); + CDrEventManager::getInstance(); + + _languageChangedHandler.addEventHandler(APP_EVENT_LANGUAGE_CHANGED, [](app_event_info_h eventInfo, void *userData) { + char *locale = NULL; + system_settings_get_value_string(SYSTEM_SETTINGS_KEY_LOCALE_LANGUAGE, &locale); + elm_language_set(locale); + free(locale); + CDrEvent event(CDrEvent::LANGUAGE_CHANGED, CDrEvent::REMOTE); + CDrEventManager::getInstance().notify(event); + }, this); + + _lowMemoryHandler.addEventHandler(APP_EVENT_LOW_MEMORY, [](app_event_info_h eventInfo, void *userData) { + WINFO("Low memory"); + CDrEvent event(CDrEvent::LOW_MEMORY, CDrEvent::REMOTE); + CDrEventManager::getInstance().notify(event); + }, this); + + CDrAppData::getInstance(); + //Create window + WWindowController *win = new WWindowController(PACKAGE_NAME, ELM_WIN_BASIC); + + +/* + win->setOnCreateWin([&]()->Evas_Object * { + return _createWin(); + }); + + win->setOnCreateBaseLayout( [&](Evas_Object* win, Evas_Object** outConformant)-> Evas_Object*{ + return _createBaseLayout(win,outConformant); + } ); +*/ + + attachWindowController(win); + + CDrAppData::getInstance()->setWindow(win); + CDrAppData::getInstance()->setTheme(); + CDrAppData::getInstance()->setColorTable(); + CDrAppData::getInstance()->setFontTable(); + CDrMediaContent::getInstance(); + + //set property of indicator that is status bar + //elm_win_indicator_mode_set(win->getEvasObj(), ELM_WIN_INDICATOR_HIDE); + elm_win_indicator_opacity_set(win->getEvasObj(), ELM_WIN_INDICATOR_TRANSPARENT); + + Evas_Object *conformant = win->getConformantEvasObj(); + elm_object_signal_emit(conformant, "elm,state,indicator,overlap", ""); + evas_object_data_set(conformant, "overlap", (void *)EINA_TRUE); + elm_object_signal_emit(conformant, "elm,state,virtualkeypad,disable", ""); + elm_object_signal_emit(conformant, "elm,state,clipboard,disable", ""); + + WDEBUG("init app"); + + WNaviframeController *navi = new WNaviframeController(); + + // Add following statements, if you want to terminate application instead of going background + navi->setOnLastItemPop([&](bool * popOut) { + _appExit(popOut); + }); + + getWindowController()->attachBaseViewController(navi); + evas_object_smart_callback_add(getWindowController()->getEvasObj(), "wm,rotation,changed", _onRotateWin, this); + + CDrAppData::getInstance()->readData(); + return true; +} + +void CDrApp::onAppControl(app_control_h request, bool firstLaunch) +{ + WENTER(); + if (_appControlOperation){ + free(_appControlOperation); + _appControlOperation = nullptr; + } + char *caller_id = nullptr; + app_control_get_caller(request, &caller_id); + + if (caller_id != nullptr) { + if(strcmp(caller_id, "com.samsung.w-home") != 0 && strcmp(caller_id, "com.samsung.w-gallery") != 0) + { + CDrAppData::getInstance()->setAppControlService(request); + } + } + + app_control_get_operation(request, &_appControlOperation); + WINFO("operation [%s]", _appControlOperation); + + if (firstLaunch) { + _setTransient(request); + + _getAppControlRequest(request); + + } else { + WINFO("not first launch"); + } + + WApp::onAppControl(request, firstLaunch); + WLEAVE(); +} + + +void CDrApp::onTerminate() +{ + CDrAppData::getInstance()->writeData(); + + if (_closeTimer) { + ecore_timer_del(_closeTimer); + _closeTimer = nullptr; + } + + WENTER(); + CDrAppData::destroy(); + WINFO("ON TERMINATE end"); +} + +void CDrApp::onPause() +{ + WENTER(); + + CDrEvent event(CDrEvent::APP_PAUSED, CDrEvent::REMOTE); + CDrEventManager::getInstance().notify(event); +} + +void CDrApp::onResume() +{ + CDrEvent event(CDrEvent::APP_RESUMED, CDrEvent::REMOTE); + CDrEventManager::getInstance().notify(event); +} + +Eina_Bool CDrApp::onCallerDestroy(void *data, int nType, void *pEvent) +{ + if (!data) { + WERROR("[ERR] No exist pUserData."); + return ECORE_CALLBACK_PASS_ON; + } + + if (!pEvent) { + WERROR("[ERR] No exist pEvent."); + return ECORE_CALLBACK_PASS_ON; + } + WINFO(" "); + + CDrApp* app = (CDrApp*)data; + +// Ecore_X_Event_Window_Destroy *ev = (Ecore_X_Event_Window_Destroy *)pEvent; + +// Ecore_X_Window callerXWin; + + const char *id_str = app->_strWinId.c_str(); + + + if(id_str == NULL){ + WINFO("window id is not set"); + return ECORE_CALLBACK_PASS_ON; + } + WINFO("caller id %s", id_str); + +// callerXWin = (Ecore_X_Window)CDrUtil::atoi(id_str); + +// if (ev->win == callerXWin) { + /* + If it's from caller win then destroy. + */ +// WINFO("caller window destroyed!. Destroy app. callerXWin=0x%08x",callerXWin); +// elm_exit(); +// return ECORE_CALLBACK_DONE; +// } + + return ECORE_CALLBACK_PASS_ON; +} + + + +void CDrApp::_setTransient(const app_control_h hCaller) +{ + Evas_Object *lWin = getWindowController()->getEvasObj(); + Ecore_X_Window lXWin = elm_win_xwindow_get(lWin); + Ecore_X_Window uXWin; + + char *id_str = NULL; + app_control_get_extra_data(hCaller, "WindowID", &id_str); + + if(id_str == NULL){ + WINFO("window id is not set"); + return; + } + this->_strWinId = std::string(id_str); + uXWin = (Ecore_X_Window)CDrUtil::atoi(id_str); + + WINFO("Set Transient. Lower: 0x%08x Upper: 0x%08x ", lXWin, uXWin); + + if ( uXWin == 0 ) + { + WERROR("Cannot get upper X-window. cancel transient"); + return; + } + +// TODO : Use app_group instead +// if(app_control_request_transient_app(hCaller, (unsigned int)lXWin, [](void *data) -> int { return 0;}, this) != APP_CONTROL_ERROR_NONE) { +// WINFO("Failed to transient app_control_request_transient_app failed, use ecore_x to set transient"); +// ecore_x_icccm_transient_for_set(lXWin, uXWin/* Foreground win*/); +// ecore_x_window_client_manage(uXWin); +// } +// else + { + WINFO("Set Transient Success."); + } + +// CDrAppData::getInstance()->setCallerWinEventHandler(ecore_event_handler_add(ECORE_X_EVENT_WINDOW_DESTROY, onCallerDestroy, this)); +} + + + +void CDrApp::_getAppControlRequest(app_control_h request) +{ + WNaviframeController *frame = (WNaviframeController *) getWindowController()->getBaseViewController(); + CDrMainView* pView = new CDrMainView(); + frame->push(pView); +} + +void CDrApp::_onRotateWin(void *data, Evas_Object * obj, void *event_info) +{ + int nDegree = -1; + nDegree = elm_win_rotation_get(obj); + + CDrEvent event(CDrEvent::WIN_ROTATED, CDrEvent::REMOTE, &nDegree); + CDrEventManager::getInstance().notify(event); +} + +void CDrApp::_appExit(bool * popOut) +{ + *popOut = true; + + ui_app_exit(); +} diff --git a/src/app/CDrApp.h b/src/app/CDrApp.h new file mode 100755 index 0000000..9513bf7 --- /dev/null +++ b/src/app/CDrApp.h @@ -0,0 +1,51 @@ +#ifndef _CDR_APP_H_ +#define _CDR_APP_H_ + + +#include "WApp.h" +#include "WAppEventHandler.h" +#include +#include +#include +#include +#include +#include +#include "DrDefine.h" + + +using namespace app_assist; + + +class CDrApp:public WApp { + public: + CDrApp(); + ~CDrApp(); + + private: + virtual bool onCreate(); + virtual void onTerminate(); + virtual void onAppControl(app_control_h request, bool firstLaunch); + virtual void onPause(); + virtual void onResume(); + +private: + static void _onSigtermHanlder(int signum); + static Eina_Bool onCallerDestroy(void *data, int nType, void *pEvent); + void _getAppControlRequest(app_control_h request); + static void _onRotateWin(void *data, Evas_Object * obj, void *event_info); + static Eina_Bool _onCloseTimer(void *data); + void _appExit(bool * popOut); + Evas_Object* _createBaseLayout(Evas_Object* win, Evas_Object** outConformant); + Evas_Object* _createWin(); + void _setTransient(const app_control_h hCaller); + + private: + WAppEventHandler _languageChangedHandler; + WAppEventHandler _lowMemoryHandler; + static Ecore_Timer *_closeTimer; + char* _appControlOperation; + + std::string _strWinId; +}; + +#endif // _CVE_APP_H_ diff --git a/src/app/CDrAppData.cpp b/src/app/CDrAppData.cpp new file mode 100755 index 0000000..6198fb9 --- /dev/null +++ b/src/app/CDrAppData.cpp @@ -0,0 +1,226 @@ + +#include "CDrAppData.h" +#include +//#include +#include +#include +#include +#include +#include "CDrUtil.h" + +using namespace std; + +CDrAppData *CDrAppData::_instance = NULL; + +CDrAppData::CDrAppData():_callerWinEventHandler(NULL), + _viewType(VIEW_TYPE_MAIN), + _mainWindow(NULL), + _colorTable(NULL), + _fontTable(NULL), + _appService(nullptr), + _launchMode(DRAWING_SAVE), + _nBgIndex(0), + _nTutorialStatus(0) +{ + //CDrUtil::initResourceManager(); +} + +CDrAppData::~CDrAppData() +{ + std::string strEdjPath; + + if ( _callerWinEventHandler ) + ecore_event_handler_del(_callerWinEventHandler); + _callerWinEventHandler = NULL; + + + char* resPath = app_get_resource_path(); + std::string path(resPath); + path += EDJ_THEME_FILE; + if (resPath) { + elm_theme_extension_del(NULL, path.c_str()); + free(resPath); + } + + if (_colorTable) { +// uxt_theme_delete_color_table(_colorTable); + _colorTable = NULL; + } + if (_fontTable) { +// uxt_theme_delete_font_table(_fontTable); + _fontTable = NULL; + } + if (_appService) { + app_control_destroy(_appService); + } + //CDrUtil::releaseResourceManager(); + WLEAVE(); +} + +CDrAppData *CDrAppData::getInstance() +{ + if (_instance == NULL) { + _instance = new CDrAppData(); + } + return _instance; +} + +void CDrAppData::destroy() +{ + if (_instance) { + delete _instance; + _instance = NULL; + } +} + +WWindowController *CDrAppData::getWindowController() +{ + return _mainWindow; +} + +void CDrAppData::setWindow(WWindowController * wWindow) +{ + _mainWindow = wWindow; +} + +void CDrAppData::setCallerWinEventHandler(Ecore_Event_Handler *h) +{ + _callerWinEventHandler = h; +} + +void CDrAppData::setTheme() +{ + char* resPath = app_get_resource_path(); + std::string path(resPath); + path += EDJ_THEME_FILE; + if (resPath) { + WINFO("Theme EDJ : %s", path.c_str()); + elm_theme_extension_add(NULL, path.c_str()); + /* Default state is off, need to turn in on manually */ +// uxt_theme_set_changeable_ui_enabled(EINA_TRUE); + free(resPath); + } +} + +Eina_Bool CDrAppData::setColorTable() +{ + Eina_Bool bret = EINA_FALSE; + + if (!_colorTable) { + char* sharedResPath = app_get_shared_resource_path(); + if (sharedResPath == nullptr) { + WERROR("sharedResPath is nullptr"); + return EINA_FALSE; + } + std::string colorTablePath(sharedResPath); + colorTablePath += "tables/org.tizen.w-drawing_color.xml"; + //char *codeFile = CDrUtil::getImagePath("tables/org.tizen.w-drawing_color.xml"); +// _colorTable = uxt_theme_add_color_table(colorTablePath.c_str()); + WPRET_VM(!_colorTable, bret, "Failed to get color table"); + + /* Block redundant API call */ + // uxt_theme_set_style(UXT_THEME_STYLE_DEFAULT); +// bret = uxt_theme_set_color_table(_colorTable); + free(sharedResPath); + } + + return bret; +} + +Eina_Bool CDrAppData::setFontTable() +{ + Eina_Bool bret = EINA_FALSE; + + if (!_fontTable) { + char* sharedResPath = app_get_shared_resource_path(); + if (sharedResPath == nullptr) { + WERROR("sharedResPath is nullptr"); + return EINA_FALSE; + } + std::string fontTablePath(sharedResPath); + fontTablePath += "tables/org.tizen.w-drawing_font.xml"; + //char *fontFile = CDrUtil::getImagePath("tables/org.tizen.w-drawing_font.xml"); +// _fontTable = uxt_theme_add_font_table(fontTablePath.c_str()); + WPRET_VM(!_fontTable, bret, "Failed to get font table"); +// bret = uxt_theme_set_font_table(_fontTable); + free(sharedResPath); + } + + return bret; +} + +Eina_List *CDrAppData::getColorTable() +{ + return _colorTable; +} + +Eina_List *CDrAppData::getFontTable() +{ + return _fontTable; +} + +void CDrAppData::setAppControlService(app_control_h hRequest) +{ + app_control_clone(&(_appService), hRequest); + _launchMode = DRAWING_SEND; +} + +app_control_h CDrAppData::getAppService() +{ + return _appService; +} + +LaunchMode CDrAppData::getLaunchMode() +{ + return _launchMode; +} + +void CDrAppData::readData() +{ + int ret; + ret = preference_get_int(PREFERENCE_KEY_APP_BG_INDEX, &_nBgIndex); + if (ret != PREFERENCE_ERROR_NONE) { + WERROR("get tutorial key failed"); + } + ret = preference_get_int(PREFERENCE_KEY_TUTORIAL_IS_SHOWED, &_nTutorialStatus); + if (ret != PREFERENCE_ERROR_NONE) { + WERROR("get tutorial key failed"); + } + WINFO("read bg index is %d", _nBgIndex); + WINFO("read tutorial status is %d", _nTutorialStatus); +} + +void CDrAppData::writeData() +{ + _nBgIndex++; + if (_nBgIndex > 3) { + _nBgIndex = 0; + } + + int ret; + ret = preference_set_int(PREFERENCE_KEY_APP_BG_INDEX, _nBgIndex); + if (ret != PREFERENCE_ERROR_NONE) { + WERROR("set tutorial key failed"); + } + ret = preference_set_int(PREFERENCE_KEY_TUTORIAL_IS_SHOWED, _nTutorialStatus); + if (ret != PREFERENCE_ERROR_NONE) { + WERROR("set tutorial key failed"); + } + WINFO("write bg index is %d", _nBgIndex); + WINFO("write tutorial status is %d", _nTutorialStatus); +} + +int CDrAppData::getBgIndex() +{ + return _nBgIndex; +} + +void CDrAppData::setTutorialStatus(int nTutorialShowed) +{ + _nTutorialStatus = nTutorialShowed; +} + +int CDrAppData::getTutorialStatus() +{ + return _nTutorialStatus; +} diff --git a/src/app/CDrAppData.h b/src/app/CDrAppData.h new file mode 100755 index 0000000..1947afe --- /dev/null +++ b/src/app/CDrAppData.h @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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 _CDR_APP_DATA_H_ +#define _CDR_APP_DATA_H_ + + +//#include +#include +#include "WDefine.h" +#include "WWindowController.h" +#include "DrDefine.h" + + +using namespace app_assist; + +class CDrAppData { + public: + static CDrAppData *getInstance(); + static void destroy(); + + void setTheme(); + Eina_Bool setColorTable(); + Eina_Bool setFontTable(); + + WWindowController *getWindowController(); + Eina_List *getColorTable(); + Eina_List *getFontTable(); + void setAppControlService(app_control_h hRequest); + app_control_h getAppService(); + LaunchMode getLaunchMode(); + + void setCallerWinEventHandler(Ecore_Event_Handler *h); + void setWindow(WWindowController * wWindow); + void readData(); + void writeData(); + int getBgIndex(); + void setTutorialStatus(int nTutorialShowed); + int getTutorialStatus(); + + public: + typedef enum { + VIEW_TYPE_UNKNOWN = 0, + VIEW_TYPE_MAIN, + VIEW_TYPE_ALARM, + } ViewType; + + private: + CDrAppData(); + ~CDrAppData(); + WDISABLE_COPY_AND_ASSIGN(CDrAppData); + + private: + static CDrAppData *_instance; + + ViewType _viewType; + WWindowController *_mainWindow; + Eina_List *_colorTable; + Eina_List *_fontTable; + app_control_h _appService; + LaunchMode _launchMode; + int _nBgIndex; + int _nTutorialStatus; + + Ecore_Event_Handler *_callerWinEventHandler; +}; + +#endif // _CVE_APP_DATA_H_ diff --git a/src/controls/CDrCairoImage.cpp b/src/controls/CDrCairoImage.cpp new file mode 100755 index 0000000..66a8f57 --- /dev/null +++ b/src/controls/CDrCairoImage.cpp @@ -0,0 +1,1459 @@ +#include "Drawing.h" +#include "CDrDrawingView.h" +#include "CDrAppData.h" +#include "WUiTimer.h" + + + +#define MAX_OPTIMIZED_POINTS_COUNT 4 +#define POINTS_ARRARY_ABANDON_NUM 14 //60 +#define ERASER_LINE_WIDTH 40.0 +#define PATTERN_BG_COLOR_CODE "AO051" +#define DRAWING_REFER_POINTS_NUM 2 + +using namespace std; + + +void DrawingColor::drawingColorSet(std::string colorCode, bool isEraser) +{ + WINFO("index is %s, is_eraser: %d", colorCode.c_str(), isEraser); + + int code_r = 0, code_g = 0, code_b = 0, code_a = 255; + edje_color_class_get(colorCode.c_str(), &code_r, &code_g, &code_b, &code_a, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); + is_eraser = isEraser; + + r = code_r/255.0; + g = code_g/255.0; + b = code_b/255.0; + a = code_a/255.0; +} + +CLasso::CLasso() +{ + _pointsList[0].reserve(100); + _originalPointsList[0].reserve(100); + _strokeList[0].reserve(100); + _originalStrokeList.reserve(100); + _nDrawedIndex = 0; + _bMouseUp = true; +} + +CLasso::~CLasso() +{ + for(int i = 0; i < MAX_POINTS_LIST_COUNT; i++) { + _pointsList[i].clear(); + _optimizedPointsList[i].clear(); + _strokeList[i].clear(); + _originalPointsList[i].clear(); + } + _oldPointsList.clear(); + + _oldStrokeList.clear(); + _originalStrokeList.clear(); +} + +void CLasso::AddPoint(const CPoint &pt, int strokeWidth) +{ + _pointsList[0].push_back(pt); + + _strokeList[0].push_back(strokeWidth); + _originalPointsList[0].push_back(pt); + _originalStrokeList.push_back(strokeWidth); + /* when first point is added, alos add related alpha value to alpha list */ + if (_originalPointsList[0].size() == 1) { + WINFO("updateAlphaList add"); + drawlinesInfo info; + info.alpha = 0.5; + info.index = GetCount()-1; + _alphaList[0].push_back(info); + } + /* because the first point's stroke width value has not reference factor, + so use default, but when the second point is added, keep same with the second point */ + if (_originalStrokeList.size() == 2) { + _strokeList[0][0] = strokeWidth; + _originalStrokeList[0] = strokeWidth; + } + _bMouseUp = false; +} + +void CLasso::addEndPoint() +{ +// _pointsList[0].push_back(_pointsList[0][_pointsList[0].size()-1]); + _bMouseUp = true; +} + +int CLasso::getLastStrokeWidth() +{ + int lastStrokeWidth = -1; + if (_originalStrokeList.size() > 1) { + lastStrokeWidth = _originalStrokeList[_originalStrokeList.size()-1]; + } + return lastStrokeWidth; +} + +int CLasso::GetCount() +{ + return _pointsList[0].size(); +} + +bool CLasso::IsEmpty() +{ + return _pointsList[0].empty(); +} + +void CLasso::Clear() +{ + _pointsList[0].clear(); + _strokeList[0].clear(); + _originalPointsList[0].clear(); + _originalStrokeList.clear(); +} + +void CLasso::increaseListIndex() +{ +#ifdef SKETCH_DRAW_ENABLE_DRAWING_EFFECT + for(int i = MAX_POINTS_LIST_COUNT -1; i > 0; i--) { + _pointsList[i].clear(); + _pointsList[i] = _pointsList[i-1]; + _alphaList[i].clear(); + _alphaList[i] = _alphaList[i-1]; + _optimizedPointsList[i].clear(); + _optimizedPointsList[i] = _optimizedPointsList[i-1]; + + _strokeList[i].clear(); + _strokeList[i] = _strokeList[i-1]; + + _originalPointsList[i].clear(); + _originalPointsList[i] = _originalPointsList[i-1]; + } +#endif + _pointsList[0].clear(); + _alphaList[0].clear(); + _oldPointsList.clear(); + _optimizedPointsList[0].clear(); + _originalPointsList[0].clear(); + _strokeList[0].clear(); + _oldStrokeList.clear(); + _originalStrokeList.clear(); + _nDrawedIndex = 0; +} + +void CLasso::saveOldPointsList() +{ + _oldPointsList.clear(); + _oldPointsList = _optimizedPointsList[0]; + _oldStrokeList.clear(); + _oldStrokeList = _strokeList[0]; +} + +std::vector >* CLasso::GetInterpolatedPoints(int index) +{ +#ifdef SKETCH_DRAW_ENABLE_DRAWING_EFFECT + if (0 == _alphaList[index].size() && _pointsList[index].size() == 0) { + WERROR(" ALPHA LIST IS 0 index =%d", index); + _optimizedPointsList[index].clear(); + return &(_optimizedPointsList[index]); + } + + if (0 < _alphaList[index].size()) { + int i = _alphaList[index].size()-1; + if (!_alphaList[index][i].bDraw) { + WERROR(" ALPHA LIST draw done %d", index); + if (index > 0) { + _pointsList[index].clear(); + _alphaList[index].clear(); + } + _optimizedPointsList[index].clear(); + return &(_optimizedPointsList[index]); + } + /* when moving points are too many, and points are drawed completed, delete them */ + for (; i >= 0; i--) { + if (_pointsList[index].size() > (POINTS_ARRARY_ABANDON_NUM + MAX_OPTIMIZED_POINTS_COUNT) && _alphaList[index][i].index < POINTS_ARRARY_ABANDON_NUM && (!_alphaList[index][i].bDraw)) { + int nRemoveIndex = _alphaList[index][i].index; + WERROR("remove drawed index %d %d", index, nRemoveIndex); + //WERROR("next first draw value %d",_pointsList[index][nRemoveIndex+1]); + std::vector::iterator iter = _pointsList[index].begin(); + _pointsList[index].erase(iter, iter + nRemoveIndex + 1); + std::deque::iterator iter0 = _alphaList[index].begin(); + _alphaList[index].erase(iter0, iter0 + i + 1); + iter0 = _alphaList[index].begin(); + for (; iter0 != _alphaList[index].end(); iter0++) { + (*iter0).index -= nRemoveIndex; + } + + std::vector::iterator iter1 = _strokeList[index].begin(); + _strokeList[index].erase(iter1, iter1 + nRemoveIndex + 1); + } + } + } +#else + /* when moving points are too many, and points are drawed completed, delete them */ + if (_pointsList[index].size() > (POINTS_ARRARY_ABANDON_NUM+MAX_OPTIMIZED_POINTS_COUNT) && _nDrawedIndex > POINTS_ARRARY_ABANDON_NUM ) { + int nRemoveIndex = POINTS_ARRARY_ABANDON_NUM; + WERROR("remove drawed index %d (%d,%d)", nRemoveIndex, _pointsList[index][nRemoveIndex].x, _pointsList[index][nRemoveIndex].y); + //WERROR("next first draw value %d",_pointsList[index][nRemoveIndex+1]); + std::vector::iterator iter = _pointsList[index].begin(); + _pointsList[index].erase(iter, iter + nRemoveIndex + 1); + } +#endif + + int nCount = _pointsList[index].size(); + _optimizedPointsList[index].resize(((nCount +DRAWING_REFER_POINTS_NUM))); + int j = 0; + for (int i = 0; i < nCount; i++) + { + if ( i == 0) { + int k = _originalPointsList[index].size() - _pointsList[index].size() -2; + std::pair& point = _optimizedPointsList[index][j]; + point.first = 0; + point.second = 0; + if ( k >= 0 ) { + point.first = _originalPointsList[index][k].x; + point.second = _originalPointsList[index][k].y; + WINFO("%.1f %.1f", point.first, point.second); + } + j++; + k = _originalPointsList[index].size() - _pointsList[index].size() -1; + std::pair& point2 = _optimizedPointsList[index][j]; + point2.first = 0; + point2.second = 0; + if ( k >= 0 ) { + point2.first = _originalPointsList[index][k].x; + point2.second = _originalPointsList[index][k].y; + WINFO("%.1f %.1f", point2.first, point2.second); + } + j++; + //WERROR(" use preve pt j=%d add two points",j); + } + + // + std::pair& point3 = _optimizedPointsList[index][j]; + point3.first = _pointsList[index][i].x; + point3.second = _pointsList[index][i].y; + j++; + } +#ifndef SKETCH_DRAW_ENABLE_DRAWING_EFFECT + _nDrawedIndex = nCount-1-2; +#endif + return &(_optimizedPointsList[index]); +} + + + +std::vector >* CLasso::GetOptimizedPointsList(int nListIndex) +{ + return &_optimizedPointsList[nListIndex]; +} + +bool CLasso::updateAlphaList() +{ + //WINFO("updateAlphaList"); + /* update alpha */ + int lastIndex = -1; + bool bChanged = false; + for(int k = 0;k< MAX_POINTS_LIST_COUNT;k++) { + if (0 < _alphaList[k].size()) { + int i = _alphaList[k].size()-1; + if (k == 0) { + lastIndex = _alphaList[k][i].index; + } + for(; i >= 0; i--) { + /* + change 4 times + */ + _alphaList[k][i].alpha -= 0.2; + if (_alphaList[k][i].alpha < -0.15) { + _alphaList[k][i].bDraw = false; + } else { + bChanged = true; + } + if (_alphaList[k][i].alpha < 0) { + _alphaList[k][i].alpha = 0; + } + } + } + } + if (lastIndex < (GetCount()-1)) { +// WINFO("updateAlphaList add"); + bChanged = true; + drawlinesInfo info; + info.alpha = 0.5; + info.index = GetCount()-1; + _alphaList[0].push_back(info); + } + return bChanged; +} + +int CLasso::getAlphaListIndex(int nListIndex, int nDrawIndex, drawlinesInfo& lineInfo) +{ + if (0 == _alphaList[nListIndex].size()) { + if (nDrawIndex < _strokeList[nListIndex].size()) { + lineInfo.strokeWidth = _strokeList[nListIndex][nDrawIndex]; + } + return -1; + } + if (nDrawIndex != 0 && nDrawIndex <= lineInfo.index) { + /* alpha is not changed */ + //WINFO("alpha not changed"); + if (nDrawIndex < _strokeList[nListIndex].size()) { + lineInfo.strokeWidth = _strokeList[nListIndex][nDrawIndex]; + } + return 0; + } + for (int i = 0; i <_alphaList[nListIndex].size(); i++) { + if ( nDrawIndex <= _alphaList[nListIndex][i].index) { + lineInfo.alpha = _alphaList[nListIndex][i].alpha; + if (nDrawIndex < _strokeList[nListIndex].size()) { + lineInfo.strokeWidth = _strokeList[nListIndex][nDrawIndex]; + } + lineInfo.index = _alphaList[nListIndex][i].index; + return 0; + } + } + if (nDrawIndex < _strokeList[nListIndex].size()) { + lineInfo.strokeWidth = _strokeList[nListIndex][nDrawIndex]; + } + return -1; +} + +int CLasso::getStrokeWidth(int nListIndex, int nDrawIndex, drawlinesInfo& lineInfo) +{ + if (0 == _strokeList[nListIndex].size()) { + return -1; + } + + if (nDrawIndex < _strokeList[nListIndex].size()) { + lineInfo.strokeWidth = _strokeList[nListIndex][nDrawIndex]; + return 0; + } + return -1; +} + +CPoint &CLasso::operator[](int i) +{ + return _pointsList[0][i]; +} + +void CLasso::restorePoints(std::vector > &pt) +{ + for(int i = MAX_POINTS_LIST_COUNT-1; i >=0;i--) { + _pointsList[i].clear(); + _alphaList[i].clear(); + _strokeList[i].clear(); + _optimizedPointsList[i].clear(); + _originalPointsList[i].clear(); + } + _oldPointsList.clear(); + _originalStrokeList.clear(); +} +/* for undo redo points */ +std::vector > CLasso::GetOriginalPoints() +{ + std::vector > ret_points; + int count = _originalPointsList[0].size(); + for (int i = 0; i < count; i++) + { + ret_points.push_back(std::make_pair(_originalPointsList[0][i].x, _originalPointsList[0][i].y)); + } + return ret_points; +} + +std::vector* CLasso::GetOriginalstrokeList() +{ + return &_originalStrokeList; +} + +std::vector > CLasso::GetHistoryPoints(std::vector > &pt) +{ + int nCount = pt.size(); + std::vector > ret_points(pt.size()+DRAWING_REFER_POINTS_NUM); + int j = 0; + for (int i = 0; i < nCount; i++) + { + if ( i == 0) { + std::pair& point = ret_points[j]; + point.first = 0; + point.second = 0; + j++; + std::pair& point2 = ret_points[j]; + point2.first = 0; + point2.second = 0; + j++; + } + std::pair& point3 = ret_points[j]; + point3.first = pt[i].first; + point3.second = pt[i].second; + j++; + } + + return ret_points; +} + +std::vector >* CLasso::getOldPointsList() +{ + return &_oldPointsList; +} + +int CLasso::getOldStrokeWidth(int i, double& strokeWidth) +{ + if ( i < _oldStrokeList.size()) { + strokeWidth = _oldStrokeList[i]; + return 0; + } + return -1; +} + +bool CLasso::lineAlphaIsOpacity(int lineIndex) +{ + if (0 < _alphaList[lineIndex].size()) { + int i = _alphaList[lineIndex].size()-1; + if (!_alphaList[lineIndex][i].bDraw) { + return false; + } + return true; + } + /*bug: when draw some points and do rotary quickly, these points maybe not be drawed + solution: only alphalist array and points list are all empty, and then no need to draw + */ + if (_alphaList[lineIndex].size() == 0 && _pointsList[lineIndex].size() == 0) { + WINFO("no draw"); + return false; + } + return true; +} + +bool CLasso::isDrawStopped() +{ + return _bMouseUp; +} + +bool CLasso::lastBufferIsCompleted() +{ + if (0 < _alphaList[2].size()) { + if (_alphaList[2][_alphaList[2].size()-1].bDraw) { + WERROR("not done ,delete"); + return false; + } + } + return true; +} + + + + + + + +CCairoImage::CCairoImage() + : _nWidth(0), + _nHeight(0), + _strokeWidth(MMS_MODE_STROKE_LINE_WIDTH), + _image(nullptr), + _imgBuf(nullptr), + _tempBuf(nullptr), + _surface(nullptr), + _cr(nullptr), + _evas(nullptr), + _BgImgFile(SKETCH_DRAWING_COLOR_BG_01), + _bStopNormalDrawing(false) +{ +} + +void CCairoImage::clearImage() +{ + cairo_set_source_rgba(_cr, 0, 0, 0, 1); + cairo_set_operator(_cr, CAIRO_OPERATOR_SOURCE); + cairo_paint(_cr); + evas_object_image_data_update_add(_image, 0, 0, 360, 360); +} + + +void CCairoImage::clearMask() +{ + cairo_set_source_rgba(_maskCr, 0, 0, 0, 1); + cairo_set_operator(_maskCr, CAIRO_OPERATOR_SOURCE); + cairo_paint(_maskCr); +} + +void CCairoImage::clearSource() +{ + cairo_set_source_rgba(_sourceCr, 0, 0, 0, 1); + cairo_set_operator(_sourceCr, CAIRO_OPERATOR_SOURCE); + cairo_paint(_sourceCr); +} + +void CCairoImage::clearBuffer() +{ + cairo_set_source_rgba(_bufferCr, 0, 0, 0, 1); + cairo_set_operator(_bufferCr, CAIRO_OPERATOR_SOURCE); + cairo_paint(_bufferCr); +} + +void CCairoImage::sourceUpdate(drawMode mode) +{ + WINFO(""); + if (mode == REDO_DRAW) { + cairo_set_operator(_cr, CAIRO_OPERATOR_SOURCE); + cairo_set_source_surface(_cr, _maskSurface, 0, 0); + cairo_paint(_cr); + evas_object_image_data_update_add(_image, 0, 0, 360, 360); + } + if (mode == UNDO_DRAW) { + cairo_set_operator(_sourceCr, CAIRO_OPERATOR_SOURCE); + cairo_set_source_surface(_sourceCr, _maskSurface, 0, 0); + cairo_paint(_sourceCr); + cairo_save(_sourceCr); + } +} + +void CCairoImage::maskUpdate(drawMode mode) +{ + WINFO(""); + if (mode == REDO_DRAW) { + cairo_set_operator(_maskCr, CAIRO_OPERATOR_SOURCE); + cairo_set_source_surface(_maskCr, _surface, 0, 0); + cairo_paint(_maskCr); + } else if (mode == UNDO_DRAW) { + cairo_set_operator(_maskCr, CAIRO_OPERATOR_SOURCE); + cairo_set_source_surface(_maskCr, _bufferSurface, 0, 0); + cairo_paint(_maskCr); + } +} + +Eina_Bool CCairoImage::animationUpdateImage(void *data, double pos) +{ + struct animationData *pAnimationData = (animationData *)data; + if (pAnimationData->mode == UNDO_DRAW) { + evas_object_color_set(pAnimationData->bgPattern, 0, 0, 0, 255*pos); + if (pos == 1) { + pAnimationData->isDrawing = false; + } + } else if (pAnimationData->mode == REDO_DRAW) { + evas_object_color_set(pAnimationData->bgPattern, 0, 0, 0, 255*pos); + } + pAnimationData->nBgPatternAlpha = 255*pos; + return EINA_TRUE; +} + +void CCairoImage::reUpdateImage(cairo_t *cr, cairo_surface_t *maskSurface, cairo_surface_t *sourceSurface, Evas_Object *image) +{ + cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); + cairo_set_source_surface(cr, sourceSurface, 0, 0); + cairo_paint(cr); + evas_object_image_data_update_add(image, 0, 0, 360, 360); +} + +void CCairoImage::updateImage(cairo_t *cr, cairo_surface_t *maskSurface, cairo_surface_t *sourceSurface, Evas_Object *image) +{ +// WINFO(""); + cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); + cairo_set_source_surface(cr, sourceSurface, 0, 0); + cairo_mask_surface(cr, maskSurface, 0, 0); + cairo_fill(cr); + evas_object_image_data_update_add(image, 0, 0, 360, 360); +} + +Evas_Object *CCairoImage::createMaskImage(Evas *evas, int width, int height) +{ + _maskImage = evas_object_image_filled_add(evas); + evas_object_image_colorspace_set(_maskImage, EVAS_COLORSPACE_ARGB8888); + evas_object_image_alpha_set(_maskImage, EINA_TRUE); + evas_object_image_size_set(_maskImage, width, height); + evas_object_repeat_events_set(_maskImage, EINA_TRUE); + + unsigned char *imgBuf = (unsigned char*)evas_object_image_data_get(_maskImage, EINA_TRUE); + + _maskSurface = cairo_image_surface_create_for_data(imgBuf, + CAIRO_FORMAT_ARGB32, width, height, + cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width)); + WINFO("transparentSurface created"); + _maskCr = cairo_create(_maskSurface); + + cairo_new_path(_maskCr); + cairo_set_source_rgba(_maskCr, 0, 0, 0, 1); + cairo_rectangle(_maskCr, 0, 0, width, height); + cairo_fill(_maskCr); + + //cairo_set_operator(_maskCr, CAIRO_OPERATOR_SOURCE); + return _maskImage; +} + +Evas_Object *CCairoImage::createSource(Evas *evas, int width, int height) +{ + _sourceImage = evas_object_image_filled_add(evas); + evas_object_image_colorspace_set(_sourceImage, EVAS_COLORSPACE_ARGB8888); + evas_object_image_alpha_set(_sourceImage, EINA_TRUE); + evas_object_image_size_set(_sourceImage, width, height); + evas_object_repeat_events_set(_sourceImage, EINA_TRUE); + + unsigned char *imgBuf = (unsigned char*)evas_object_image_data_get(_sourceImage, EINA_TRUE); + + _sourceSurface = cairo_image_surface_create_for_data(imgBuf, + CAIRO_FORMAT_ARGB32, width, height, + cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width)); + WINFO("transparentSurface created"); + _sourceCr = cairo_create(_sourceSurface); + + cairo_new_path(_sourceCr); + cairo_set_source_rgba(_sourceCr, 0, 0, 0, 1); + cairo_rectangle(_sourceCr, 0, 0, width, height); + cairo_fill(_sourceCr); + return _sourceImage; +} +void CCairoImage::createBufferImage(Evas *evas, int width, int height) +{ + _bufferImage = evas_object_image_filled_add(evas); + evas_object_image_colorspace_set(_bufferImage, EVAS_COLORSPACE_ARGB8888); + evas_object_image_alpha_set(_bufferImage, EINA_TRUE); + evas_object_image_size_set(_bufferImage, width, height); + evas_object_repeat_events_set(_bufferImage, EINA_TRUE); + + unsigned char *imgBuf = (unsigned char*)evas_object_image_data_get(_bufferImage, EINA_TRUE); + + _bufferSurface = cairo_image_surface_create_for_data(imgBuf, + CAIRO_FORMAT_ARGB32, width, height, + cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width)); + _bufferCr = cairo_create(_bufferSurface); + + cairo_new_path(_bufferCr); + cairo_set_source_rgba(_bufferCr, 0, 0, 0, 1); + cairo_rectangle(_bufferCr, 0, 0, width, height); + cairo_fill(_bufferCr); + return; +} + +Evas_Object *CCairoImage::CreateImage(Evas *evas, int width, int height) +{ + _image = evas_object_image_filled_add(evas); + evas_object_image_colorspace_set(_image, EVAS_COLORSPACE_ARGB8888); + evas_object_image_alpha_set(_image, EINA_TRUE); + evas_object_image_size_set(_image, width, height); + evas_object_repeat_events_set(_image, EINA_TRUE); + + _imgBuf = (unsigned char*)evas_object_image_data_get(_image, EINA_TRUE); + + _surface = cairo_image_surface_create_for_data(_imgBuf, + CAIRO_FORMAT_ARGB32, width, height, + cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width)); + WINFO("surface created"); + _cr = cairo_create(_surface); + + _tempBuf = (unsigned char *)calloc(1, width * height * 4); + + _nWidth = width; + _nHeight = height; + _evas = evas; + + cairo_set_source_rgba(_cr, 0, 0, 0, 1); + cairo_save(_cr); + setClip(0, 0, width, height); + + return _image; +} + +void CCairoImage::DeleteImage() +{ + if(_image) { + cairo_surface_destroy(_surface); + cairo_destroy(_cr); + + evas_object_image_data_set(_image, _imgBuf); + _imgBuf = NULL; + evas_object_del(_image); + _image = NULL; + free(_tempBuf); + } + + if(_maskImage) { + cairo_surface_destroy(_maskSurface); + cairo_destroy(_maskCr); + + evas_object_del(_maskImage); + _maskImage = NULL; + } + + if(_sourceImage) { + cairo_surface_destroy(_sourceSurface); + cairo_destroy(_sourceCr); + + evas_object_del(_sourceImage); + _sourceImage = NULL; + } + if(_bufferImage) { + cairo_surface_destroy(_bufferSurface); + cairo_destroy(_bufferCr); + + evas_object_del(_bufferImage); + _bufferImage = NULL; + } +} + +void CCairoImage::MoveImage(int x, int y, int w, int h) +{ + evas_object_move(_image, x, y); + evas_object_resize(_image, w, h); + evas_object_show(_image); +} + +void CCairoImage::saveImageBuffer(int w, int h) +{ + WINFO("saveImageBuffer"); + _imgBuf = (unsigned char*)evas_object_image_data_get(_image, EINA_FALSE); + memcpy(_tempBuf, _imgBuf, w * h * 4); +} + +void CCairoImage::setClip(int x, int y, int w, int h) +{ + cairo_new_path(_cr); + cairo_arc(_cr, x+w/2, y+h/2, w/2+2, 0, 2*M_PI); + cairo_clip(_cr); + + cairo_new_path(_cr); + //cairo_set_source_rgb(_cr, 0, 1, 0); + cairo_rectangle(_cr, 0, 0, w, w); + cairo_fill(_cr); +} +#ifdef ENABLE_DRAGING +void CCairoImage::dragImage(int dx, int dy) +{ + int x, y, w, h; + int fx, fy; + + evas_object_geometry_get(_image, &x, &y, &w, &h); + int screen_x = 180;//screen center + int screen_y = 180; + int screen_radius = 220;//add 40 offset for convenient to drawing edge of screen. + + int cycle_x = x + 360 + dx; + int cycle_y = y + 360 + dy; + + double final_cycle_x; + double final_cycle_y; + + double dis = sqrt((cycle_x - screen_x)*(cycle_x - screen_x) + + (cycle_y - screen_y) * (cycle_y - screen_y)); + + if (dis > screen_radius) + { + final_cycle_x = screen_radius / dis * (cycle_x - screen_x) + screen_x; + final_cycle_y = screen_radius / dis * (cycle_y - screen_y) + screen_y; + + fx = (int)final_cycle_x - 360; + fy = (int)final_cycle_y - 360; + } else { + fx = dx + x; + fy = dy + y; + } + + MoveImage(fx, fy, w, h); + return; +} +#endif + +void CCairoImage::Clear(DrawingColor* pColor) +{ + if(_cr) { + if (CDrAppData::getInstance()->getLaunchMode() == DRAWING_SEND) { + cairo_restore(_cr); + cairo_paint(_cr); + evas_object_image_data_update_add(_image, 0, 0, _nWidth, _nHeight); + cairo_save(_cr); + } else { + cairo_set_operator(_cr, CAIRO_OPERATOR_CLEAR); + cairo_paint(_cr); + evas_object_image_data_update_add(_image, 0, 0, _nWidth, _nHeight); + } + SetDrawingProperty(pColor);//Revert back default + } +}; + +void CCairoImage::SetDrawingProperty(DrawingColor* pColor) +{ + double lineWidth = _strokeWidth; + LaunchMode launchMode = CDrAppData::getInstance()->getLaunchMode(); + + if ( pColor->is_eraser == true) { + cairo_set_operator(_cr, CAIRO_OPERATOR_CLEAR); + lineWidth = ERASER_LINE_WIDTH; + } else { + cairo_set_operator(_cr, CAIRO_OPERATOR_SOURCE); + cairo_set_source_rgba(_cr, pColor->r, pColor->g, pColor->b, pColor->a); + } + + if (launchMode == DRAWING_SEND ) { + lineWidth = _strokeWidth = MMS_MODE_STROKE_LINE_WIDTH; + } + +#ifndef SKETCH_DRAW_COLORS_CHANGABLE + if (launchMode == DRAWING_SEND ) { + if ( pColor->is_eraser == true) { + cairo_set_operator(_cr, CAIRO_OPERATOR_SOURCE); + cairo_set_source_rgba(_cr, 0, 0, 0, 1); + } else { + cairo_set_operator(_cr, CAIRO_OPERATOR_SOURCE); +#ifdef SKETCH_DRAW_ENABLE_DRAWING_EFFECT + cairo_set_source_rgba(_cr, 1, 1, 1, 1); +#else + cairo_set_source_rgba(_cr, 0, 0, 0, 0); +#endif + //WINFO("normal draw ,send mode"); + } + } +#endif + + cairo_set_line_width(_cr, lineWidth); + cairo_set_line_cap(_cr, CAIRO_LINE_CAP_ROUND); + cairo_set_line_join(_cr, CAIRO_LINE_JOIN_ROUND); +} + +void CCairoImage::SetHistoryDrawingProperty(cairo_t *cr, DrawingColor pColor, double strokeWidth) +{ + double lineWidth = strokeWidth; + LaunchMode launchMode = CDrAppData::getInstance()->getLaunchMode(); + cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); + cairo_set_source_rgba(cr, pColor.r, pColor.g, pColor.b, pColor.a); +#ifndef SKETCH_DRAW_COLORS_CHANGABLE + if (launchMode == DRAWING_SEND ) { + if ( pColor.is_eraser == true) { + cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); + cairo_set_source_rgba(cr, 0, 0, 0, 1); + } else { + cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); + cairo_set_source_rgba(cr, 0, 0, 0, 0); + } + } +#endif + + cairo_set_line_width(cr, lineWidth); + cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND); + cairo_set_line_join(cr, CAIRO_LINE_JOIN_ROUND); +} + +void CCairoImage::setStrokeWidth(double dWidth) +{ + _strokeWidth = dWidth; +} + +double CCairoImage::getStrokeWidth() +{ + return _strokeWidth; +} + +void CCairoImage::setBgType(std::string& bgType) +{ + _BgImgFile = bgType; +} + +void CCairoImage::setStrokeAlpha(cairo_t* cr, drawlinesInfo& info) +{ + cairo_stroke(cr); + //cairo_stroke_preserve(_cr); + LaunchMode launchMode = CDrAppData::getInstance()->getLaunchMode(); + +#ifndef SKETCH_DRAW_COLORS_CHANGABLE + if (launchMode == DRAWING_SEND ) { + cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); + cairo_set_source_rgba(cr, 0.8, 0.8, 0.8, info.alpha); + } + +#endif + + cairo_set_line_width(cr, info.strokeWidth); + cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND); + cairo_set_line_join(cr, CAIRO_LINE_JOIN_ROUND); +} + +void CCairoImage::eraseDraw(CLasso &lasso, double rw, double rh, int w, int h, int specIndex) +{ + WINFO(""); + int nStartIndex = MAX_POINTS_LIST_COUNT-1; + int nEndIndex = 0; + if (specIndex != -1) { + nStartIndex = specIndex; + nEndIndex = nStartIndex; + } + for(int j =nStartIndex;j>= nEndIndex;j--) { + CPoint Min, Max; + Min.x = 2*w; + Min.y = 2*h; + Max.x = -w; + Max.y = -h; + if (!lasso.lineAlphaIsOpacity(j)) { + continue; + } + /* must recreate optimized points, maybe previous optimized points are empty or not whole */ + std::vector> *pt1 = lasso.GetInterpolatedPoints(j); + WINFO("index =%d use new opti,size %d", j, pt1->size()); + + std::vector>::const_iterator iter = pt1->begin(); + + if (pt1->size() == 0) { + continue; + } + WINFO("erase draw"); + _drawPoints(lasso, NORMAL_DRAW_ERASE_UNCOMPLETED_LINE, j, rw, rh, Min, Max); + } +} + + +void CCairoImage::_eraseOldLine(CLasso &lasso, double rw, double rh, int w, int h) +{ + if(_bStopNormalDrawing) { + return; + } + CPoint Min, Max; + Min.x = 2*w; + Min.y = 2*h; + Max.x = -w; + Max.y = -h; + + //WINFO("_eraseOldLine "); + std::vector> *ptList = lasso.getOldPointsList(); + std::vector>::const_iterator iter = ptList->begin(); + + if (ptList->size() == 0) { + return; + } + _drawPoints(lasso, NORMAL_DRAW_ERASE_OLD_LINE, 0, rw, rh, Min, Max); +} + +void CCairoImage::_setStrokeProperty(CLasso &lasso, NormaldrawMode mode, int nLineIndex, int nPointIndex, drawlinesInfo& lineInfo) +{ + if (mode == NORMAL_DRAW_TOUCHING) { +#ifdef SKETCH_DRAW_ENABLE_DRAWING_EFFECT +#ifndef SKETCH_DRAW_COLORS_CHANGABLE + int ret = lasso.getAlphaListIndex(nLineIndex, nPointIndex, lineInfo); + if (ret == -1) { + if (nLineIndex != 0) { + lineInfo.alpha = 0; + } + } + /* multi-draw same points, line will be thin, so use -1 to draw for normal drawing*/ + if (lineInfo.alpha < 0) { + lineInfo.alpha = 1; + } + if(lineInfo.alpha > 0.05) { + lineInfo.strokeWidth -= 2; + } else { + lineInfo.strokeWidth -= 1; + } + if (ret == -1 || lineInfo.oldAlpha != lineInfo.alpha || (lineInfo.dOldStrokeWidth != lineInfo.strokeWidth)) { + setStrokeAlpha(_cr, lineInfo); + cairo_new_path(_cr); + } +#endif +#endif + } else if (mode == NORMAL_DRAW_ERASE_OLD_LINE) { + int ret = lasso.getOldStrokeWidth(nPointIndex, lineInfo.strokeWidth); + lineInfo.strokeWidth -= 1; + if (ret== -1 || lineInfo.dOldStrokeWidth != lineInfo.strokeWidth) { + setStrokeAlpha(_cr, lineInfo); + cairo_new_path(_cr); + } + } else if (mode == NORMAL_DRAW_ERASE_UNCOMPLETED_LINE) { +#ifdef SKETCH_DRAW_ENABLE_DRAWING_EFFECT +#ifndef SKETCH_DRAW_COLORS_CHANGABLE + int ret = lasso.getStrokeWidth(nLineIndex, nPointIndex, lineInfo); + lineInfo.strokeWidth -= 1; + if (ret == -1 || (lineInfo.dOldStrokeWidth != lineInfo.strokeWidth)) { + setStrokeAlpha(_cr, lineInfo); + cairo_new_path(_cr); + } +#endif +#endif + } +} + +void CCairoImage::_drawPoints(CLasso &lasso, NormaldrawMode mode, int nLineIndex, double rw, double rh, CPoint& ptMin, CPoint& ptMax) +{ + std::vector> *ptList = nullptr; + + if(mode == NORMAL_DRAW_ERASE_OLD_LINE) { + ptList = lasso.getOldPointsList(); + } else if (mode == NORMAL_DRAW_TOUCHING) { + ptList = lasso.GetInterpolatedPoints(nLineIndex); + if (ptList->size() == 0) { + return; + } +#ifdef SKETCH_DRAW_ENABLE_DRAWING_EFFECT + if (nLineIndex == 0) { + if (ptList->size() <= (DRAWING_REFER_POINTS_NUM + 1) && !lasso.isDrawStopped()) { + WINFO("continue index %d", nLineIndex); + return; + } + lasso.saveOldPointsList(); + } +#endif + } else { + ptList = lasso.GetOptimizedPointsList(nLineIndex); + } + std::vector>::const_iterator iter = ptList->begin(); + + int i = 0; + drawlinesInfo lineInfo; + lineInfo.index = 0; + lineInfo.alpha = -1; + lineInfo.strokeWidth = MMS_MODE_STROKE_LINE_WIDTH; + CPoint pt0, pt1, pt; + CPoint midPt0, prevPt1, midPt2; + if (mode == NORMAL_DRAW_ERASE_OLD_LINE) { + lineInfo.alpha = 0; + lineInfo.strokeWidth = 0; + } else if (mode == NORMAL_DRAW_ERASE_UNCOMPLETED_LINE) { + lineInfo.alpha = 0; + lineInfo.strokeWidth = MMS_MODE_STROKE_LINE_WIDTH - 1; + } + + pt0.x = iter->first * rw; + pt0.y = iter->second * rh; + iter++; + pt1.x = (iter)->first * rw; + pt1.y = (iter)->second * rh; + iter++; + + for (; iter != ptList->end(); iter++) + { + if(_bStopNormalDrawing && mode != NORMAL_DRAW_ERASE_UNCOMPLETED_LINE) { + WLEAVE(); + return; + } + + if (mode == NORMAL_DRAW_ERASE_OLD_LINE && i > POINTS_ARRARY_ABANDON_NUM * 2) { + WLEAVE(); + break; + } + pt.x = (iter)->first * rw; + pt.y = (iter)->second * rh; + if(i == 0) { + cairo_new_path(_cr); + } + _setStrokeProperty(lasso, mode, nLineIndex, i, lineInfo); + //WINFO("strokeWidth=%.1f",lineInfo.strokeWidth); + + midPt0.x = (pt0.x + pt1.x) * 0.5; + midPt0.y = (pt0.y + pt1.y) * 0.5; + prevPt1 = pt1; + midPt2.x = (pt1.x + pt.x) * 0.5; + midPt2.y = (pt1.y + pt.y) * 0.5; + + if (pt1.x == 0 && pt1.y == 0) { + midPt0 = pt; + prevPt1 = pt; + midPt2 = pt; + } else if (pt0.x == 0 && pt0.y == 0){ + midPt0 = prevPt1; + } + + cairo_move_to(_cr, midPt0.x, midPt0.y); + _pathDrawCurve(_cr, prevPt1.x, prevPt1.y, midPt2.x, midPt2.y); + + ptMin.x = MIN(ptMin.x, MIN(midPt0.x, MIN(prevPt1.x, MIN(pt.x, midPt2.x)))); + ptMax.x = MAX(ptMax.x, MAX(midPt0.x, MAX(prevPt1.x, MAX(pt.x, midPt2.x))));; + ptMin.y = MIN(ptMin.y, MIN(midPt0.y, MIN(prevPt1.y, MIN(pt.y, midPt2.y)))); + ptMax.y = MAX(ptMax.y, MAX(midPt0.y, MAX(prevPt1.y, MAX(pt.y, midPt2.y)))); + + i++; + lineInfo.oldAlpha = lineInfo.alpha; + lineInfo.dOldStrokeWidth = lineInfo.strokeWidth; + pt0 = pt1; + pt1 = pt; + } + cairo_stroke(_cr); +} + +void CCairoImage::_pathDrawCurve(cairo_t *_cairo, double x1, double y1, double x2, double y2) +{ + double x0, y0; + cairo_get_current_point(_cairo, &x0, &y0); + //WINFO("(%.1f %.1f) (%.1f %.1f) (%.1f %.1f)",x0, y0,x1,y1,x2,y2); + cairo_curve_to(_cairo, + 2.0 / 3.0 * x1 + 1.0 / 3.0 * x0, 2.0 / 3.0 * y1 + 1.0 / 3.0 * y0, + 2.0 / 3.0 * x1 + 1.0 / 3.0 * x2, 2.0 / 3.0 * y1 + 1.0 / 3.0 * y2, + x2, y2); +} + +void CCairoImage::Draw(CLasso &lasso, double rw, double rh, int w, int h) +{ + if(_bStopNormalDrawing) { + return; + } + for(int j = MAX_POINTS_LIST_COUNT-1; j >= 0; j--) { + CPoint Min, Max; + Min.x = 2 * w; + Min.y = 2 * h; + Max.x = -w; + Max.y = -h; + if(_bStopNormalDrawing) { + return; + } + +#ifdef SKETCH_DRAW_ENABLE_DRAWING_EFFECT + if (j == 0) { + _eraseOldLine(lasso, rw, rh, w, h); + } +#endif + + _drawPoints(lasso, NORMAL_DRAW_TOUCHING, j, rw, rh, Min, Max); + + Min.x -= _strokeWidth / 2; + if (Min.x < 0) { + Min.x = 0; + } + Min.y -= _strokeWidth / 2; + if (Min.y < 0) { + Min.y = 0; + } + Max.x += _strokeWidth / 2; + if ((Max.x - Min.x) > w ) { + Max.x = w + Min.x; + } + Max.y += _strokeWidth / 2; + if ((Max.y - Min.y) > h) { + Max.y = h + Min.y; + } + if ( Min.x < 0 || Min.y < 0 || Max.x < 0 || Max.y < 0 || (Max.x - Min.x) > w || (Max.y - Min.y) >h) { + WERROR("overflow"); + evas_object_image_data_update_add(_image, 0, 0, 360, 360); + } else { + evas_object_image_data_update_add(_image, Min.x, Min.y, Max.x - Min.x, Max.y - Min.y); + //evas_object_image_data_update_add(_image, 0, 0, 360, 360); + } + } +} + + +/* undo /redo drawing */ +void CCairoImage::_animateDrawPoints(CPoint& ptMin, CPoint& ptMax, double pos, void* pData) +{ + struct animationData *pAnimationData = (animationData *)pData; + int count = (pAnimationData->pt).size(); + int nStart, nEnd; + int i = 0; + double alpha = 0; + drawlinesInfo info; + info.alpha = 0; + info.strokeWidth = -1; + double dStrokeWidth = 0; + CPoint pt0, pt1, pt; + CPoint midPt0, prevPt1, midPt2; + + if (pAnimationData->mode == UNDO_DRAW ) { + if (pAnimationData->isMaxAnimation) { + nStart = (int)((count - 1) - (int)(DRAW_POINTS * pos)); + nEnd = DRAWING_REFER_POINTS_NUM; + } else { + nStart = (int)((count - 1 - DRAWING_REFER_POINTS_NUM) * (1 - pos) + DRAWING_REFER_POINTS_NUM); + nEnd = 1; + } + + if (nStart -2 < 0 && nStart > nEnd) { + WERROR(" start %d count %d", nStart, count); + } + if (nStart < nEnd) { + WERROR(" start %d nEnd %d", nStart, nEnd); + } + if (nStart -2 >= 0) { + pt0.x = pAnimationData->pt[nStart-2].first * pAnimationData->rw; + pt0.y = pAnimationData->pt[nStart-2].second * pAnimationData->rh; + } + if (nStart -1 >= 0) { + pt1.x = pAnimationData->pt[nStart-1].first * pAnimationData->rw; + pt1.y = pAnimationData->pt[nStart-1].second * pAnimationData->rh; + } + alpha = pos; + + } else if (pAnimationData->mode == REDO_DRAW) { + if (pAnimationData->isMaxAnimation) { + nStart = DRAWING_REFER_POINTS_NUM; + nEnd = (int)((pAnimationData->pt.size() - DRAW_POINTS) + (int)(DRAW_POINTS * pos)); + } else { + nStart = DRAWING_REFER_POINTS_NUM; + nEnd = (int)((pAnimationData->pt.size() - DRAWING_REFER_POINTS_NUM) * pos + DRAWING_REFER_POINTS_NUM); + } + if (nStart > nEnd) { + WERROR(" start %d nEnd %d", nStart, nEnd); + } + + pt0.x = pAnimationData->pt[0].first * pAnimationData->rw; + pt0.y = pAnimationData->pt[0].second * pAnimationData->rh; + pt1.x = pAnimationData->pt[1].first * pAnimationData->rw; + pt1.y = pAnimationData->pt[1].second * pAnimationData->rh; + alpha = 1 - pos; + } + + /* draw points */ + int ix = nStart; + while((pAnimationData->mode == UNDO_DRAW && ix > nEnd) || (pAnimationData->mode == REDO_DRAW && ix < nEnd)) + { + pt.x = pAnimationData->pt[ix].first * pAnimationData->rw; + pt.y = pAnimationData->pt[ix].second * pAnimationData->rh; + + /* set stroke width */ + if ((ix-DRAWING_REFER_POINTS_NUM) < pAnimationData->strokeList.size()) { + dStrokeWidth = pAnimationData->strokeList[(ix-DRAWING_REFER_POINTS_NUM)]; + } else { + WERROR("not found %d %d", ix, pAnimationData->strokeList.size()); + } + if (dStrokeWidth != info.strokeWidth) { + info.strokeWidth = dStrokeWidth; + pAnimationData->pCairo->setStrokeAlpha(pAnimationData->sourceCr, info); + cairo_set_source_rgba(pAnimationData->sourceCr, 0, 0, 0, alpha); + cairo_new_path(pAnimationData->sourceCr); + } + + midPt0.x = (pt0.x + pt1.x)* 0.5; + midPt0.y = (pt0.y + pt1.y)* 0.5; + prevPt1 = pt1; + midPt2.x = (pt1.x + pt.x) * 0.5; + midPt2.y = (pt1.y + pt.y) * 0.5; + + if (pt1.x == 0 && pt1.y == 0) { + midPt0 = pt; + prevPt1 = pt; + midPt2 = pt; + //WINFO("draw point"); + } else if (pt0.x == 0 && pt0.y == 0){ + midPt0 = prevPt1; + //WINFO("draw line"); + } + + cairo_move_to(pAnimationData->sourceCr, midPt0.x, midPt0.y); + _pathDrawCurve(pAnimationData->sourceCr, prevPt1.x, prevPt1.y, midPt2.x, midPt2.y); + + i++; + if (pAnimationData->mode == UNDO_DRAW) { + pt1 = pt0; + if (ix - 3 >= 0) { + pt0.x = pAnimationData->pt[ix-3].first * pAnimationData->rw; + pt0.y = pAnimationData->pt[ix-3].second * pAnimationData->rh; + } + ix--; + } else if (pAnimationData->mode == REDO_DRAW){ + ix++; + pt0 = pt1; + pt1 = pt; + } + } + cairo_stroke(_cr); +} + +Eina_Bool CCairoImage::animationDraw(void *data, double pos) +{ + struct animationData *pAnimationData = (animationData *)data; + CPoint Min, Max; + Min.x = 2 * pAnimationData->w; + Min.y = 2 * pAnimationData->h; + Max.x = -pAnimationData->w; + Max.y = -pAnimationData->h; + + if (pAnimationData->pt.size() == 0) { + return EINA_TRUE; + } + + cairo_restore(pAnimationData->sourceCr); + cairo_paint(pAnimationData->sourceCr); + cairo_save(pAnimationData->sourceCr); + + cairo_set_operator(pAnimationData->sourceCr, CAIRO_OPERATOR_SOURCE); + cairo_set_line_width(pAnimationData->sourceCr, pAnimationData->strokeWidth); + cairo_set_line_cap(pAnimationData->sourceCr, CAIRO_LINE_CAP_ROUND); + cairo_set_line_join(pAnimationData->sourceCr, CAIRO_LINE_JOIN_ROUND); + + + pAnimationData->pCairo->_animateDrawPoints(Min, Max, pos, data); + cairo_stroke(pAnimationData->sourceCr); + + updateImage(pAnimationData->cr, pAnimationData->maskSurface, pAnimationData->sourceSurface, pAnimationData->image); + if (pos == 1.0) { + pAnimationData->isDrawing = false; + pAnimationData->drawingAnimator = nullptr; + if (pAnimationData->mode == REDO_DRAW) { + //Prevent same path in source and mask composite inconsistent when redo. + reUpdateImage(pAnimationData->cr, pAnimationData->maskSurface, pAnimationData->sourceSurface, pAnimationData->image); + } + return EINA_FALSE; + } + return EINA_TRUE; +} +void CCairoImage::Draw(cairo_t *cr, std::vector> &ptList, std::vector& strokeList, double rw, double rh, int w, int h) +{ + WINFO("undo draw points"); + + std::vector>::const_iterator iter = ptList.begin(); + + cairo_set_source_rgba(cr, 0, 0, 0, 0); + + drawlinesInfo info; + info.alpha = 0; + info.strokeWidth = -1; + double dStrokeWidth = 0; + int i = 0; + CPoint pt0, pt1, pt; + CPoint midPt0, prevPt1, midPt2; + + pt0.x = iter->first *rw; + pt0.y = iter->second * rh; + iter++; + pt1.x = (iter)->first * rw; + pt1.y = (iter)->second * rh; + iter++; + + for (iter; iter != ptList.end(); iter++) + { + pt.x = (iter)->first * rw; + pt.y = (iter)->second * rh; + if(i == 0) { + cairo_new_path(cr); + } + + if (i < strokeList.size()) { + dStrokeWidth = strokeList[i]; + } else { + WERROR("not found"); + } + if (dStrokeWidth != info.strokeWidth) { + info.strokeWidth = dStrokeWidth; + + setStrokeAlpha(cr, info); + cairo_new_path(cr); + } + //WINFO("strokeWidth=%.1f", info.strokeWidth); + + midPt0.x = (pt0.x + pt1.x) * 0.5; + midPt0.y = (pt0.y + pt1.y) * 0.5; + prevPt1 = pt1; + midPt2.x = (pt1.x + pt.x) * 0.5; + midPt2.y = (pt1.y + pt.y) * 0.5; + + if (pt1.x == 0 && pt1.y == 0) { + midPt0 = pt; + prevPt1 = pt; + midPt2 = pt; + } else if (pt0.x == 0 && pt0.y == 0){ + midPt0 = prevPt1; + } + + cairo_move_to(cr, midPt0.x, midPt0.y); + _pathDrawCurve(cr, prevPt1.x, prevPt1.y, midPt2.x, midPt2.y); + + i++; + pt0 = pt1; + pt1 = pt; + } + cairo_stroke(cr); + ptList.clear(); + strokeList.clear(); +} + +void CCairoImage::GetDimensions(int *width, int *height) +{ + *width = _nWidth; + *height = _nHeight; +} + +void CCairoImage::SaveDrawingImage(std::string& filePath) +{ + if(_image) + { + WINFO("save smart object to file"); + if ( CDrAppData::getInstance()->getLaunchMode() == DRAWING_SEND) { + _createSaveCario(filePath); + } else { + evas_object_image_save(_image, filePath.c_str(), NULL, NULL); + } + } +} + +const char *quality_str = "quality=100 compress=9"; + +void CCairoImage::_createSaveCario(std::string& filePath) +{ +#ifndef SKETCH_DRAW_COLORS_CHANGABLE + char* resPath = app_get_resource_path(); + std::string bgPath(resPath); + bgPath += _BgImgFile.c_str(); + std::string patternBgPath(resPath); + patternBgPath += SKETCH_DRAWING_PATTERN_BG; + free(resPath); + + Evas_Object *image; + image = evas_object_image_filled_add(_evas); + evas_object_image_colorspace_set(image, EVAS_COLORSPACE_ARGB8888); + evas_object_image_alpha_set(image, EINA_TRUE); + evas_object_image_size_set(image, _nWidth, _nHeight); + unsigned char* buf = (unsigned char*)evas_object_image_data_get(image, EINA_TRUE); + cairo_surface_t * surface = cairo_image_surface_create_for_data(buf, + CAIRO_FORMAT_ARGB32, _nWidth, _nHeight, + cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, _nWidth)); + + cairo_t* cr = cairo_create(surface); + cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); + cairo_surface_t * surface2 = cairo_image_surface_create_from_png(bgPath.c_str()); + + cairo_new_path(cr); + cairo_arc(cr, 180, 180, 180, 0, 2 * M_PI); + cairo_clip(cr); + cairo_set_source_surface(cr, surface2, 0, 0); + cairo_paint(cr); + //cairo_fill(cr); + //cairo_set_source_rgba(cr, 0, 0, 0, 1); + //cairo_mask_surface(cr, surface2, 0, 0); + //cairo_fill(cr); + + int code_r = 0, code_g = 0, code_b = 0, code_a = 255; + double r, g, b, a; + edje_color_class_get(PATTERN_BG_COLOR_CODE, &code_r, &code_g, &code_b, &code_a, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); + r = code_r /255.0; + g = code_g / 255.0; + b = code_b / 255.0; + a = code_a / 255.0; + cairo_surface_t * surface3 = cairo_image_surface_create_from_png(patternBgPath.c_str()); + cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); + cairo_set_source_rgba(cr, r, g, b, a); + cairo_mask_surface(cr, surface3, 0, 0); + cairo_fill(cr); + + cairo_reset_clip(cr); + cairo_set_operator(cr, CAIRO_OPERATOR_ATOP); + cairo_set_source_surface(cr, _surface, 0, 0); + cairo_paint(cr); + + evas_object_image_save(image, filePath.c_str(), NULL, quality_str); + + WINFO("destroy"); + cairo_surface_destroy(surface); + cairo_surface_destroy(surface2); + cairo_surface_destroy(surface3); + cairo_destroy(cr); + evas_object_del(image); +#else + char* resPath = app_get_resource_path(); + std::string bgPath(resPath); + bgPath += DRAWING_DRAWING_PATTERN_BG; + free(resPath); + + cairo_surface_t * surface2 = cairo_image_surface_create_from_png(bgPath.c_str()); + + cairo_set_operator(_cr, CAIRO_OPERATOR_ATOP); + cairo_set_source_surface(_cr, surface2, 0, 0); + cairo_paint(_cr); + WINFO("surface paint"); + + evas_object_image_save(_image, filePath.c_str(), NULL, quality_str); + + WINFO("destroy"); + cairo_surface_destroy(surface2); +#endif + + WLEAVE(); +} + +void CCairoImage::setStopNormalDrawing(bool bDoding) +{ + _bStopNormalDrawing = bDoding; +} + +bool CCairoImage::getNormalDrawingStatus() +{ + return _bStopNormalDrawing; +} diff --git a/src/controls/CDrCairoImage.h b/src/controls/CDrCairoImage.h new file mode 100755 index 0000000..cb81a04 --- /dev/null +++ b/src/controls/CDrCairoImage.h @@ -0,0 +1,278 @@ +#ifndef __CDRCAIRO_IMAGE_H__ +#define __CDRCAIRO_IMAGE_H__ + + +#include +#include +#include +#include +#include +#include +#include +#include +//#include +#include +#include +#include "DrDefine.h" + + + +#ifndef REDO_UNDO +#define REDO_UNDO +#endif + +#ifndef ENABLE_DRAGING +//#define ENABLE_DRAGING +#endif +#ifndef ENABLE_ZOOM +//#define ENABLE_ZOOM +#endif + + +#define MAX_POINTS_LIST_COUNT 3 + +typedef struct _LinesInfo{ + bool bDraw; + int index; + double strokeWidth; + double alpha; + double oldAlpha; + double dOldStrokeWidth; + _LinesInfo() { + bDraw = true; + alpha = 0.5; + index = 0; + strokeWidth = MMS_MODE_STROKE_LINE_WIDTH; + oldAlpha = -1; + dOldStrokeWidth = 0; + } +}drawlinesInfo; + +struct rect { + int x; + int y; + int w; + int h; +} ; +typedef struct rect Rect; +typedef enum { + NORMAL_DRAW = 0, + UNDO_DRAW, + REDO_DRAW +} drawMode; + +typedef enum { + NORMAL_DRAW_TOUCHING = 0, + NORMAL_DRAW_ERASE_OLD_LINE, + NORMAL_DRAW_ERASE_UNCOMPLETED_LINE +} NormaldrawMode; + + +class DrawingColor +{ +public: + DrawingColor() { + r = 0.; + g = 0.; + b = 0.; + a = 0.; + is_eraser = false; + } + + void drawingColorSet(std::string colorCode, bool isEraser); + + double r; + double g; + double b; + double a; + bool is_eraser; +}; + +class CPoint +{ +public: + CPoint(int _x = 0, int _y = 0) : x(_x), y(_y) {}; +public: + int x; + int y; + CPoint &operator =(const CPoint &rhs) { + if (this == &rhs) { + return *this; + } + + x = rhs.x; + y = rhs.y; + return *this; + }; +}; + +class CLasso +{ +public: + CLasso(); + ~CLasso(); + void AddPoint(const CPoint &pt, int strokeWidth = MMS_MODE_STROKE_LINE_WIDTH); + void addEndPoint(); + int GetCount(); + bool IsEmpty(); + void Clear(); + int getListCount(); + std::vector >* GetInterpolatedPoints(int index); + CPoint &operator[](int i); + void increaseListIndex(); + bool updateAlphaList(); + int getAlphaListIndex(int nListIndex, int nDrawIndex, drawlinesInfo& lineInfo); + int getStrokeWidth(int nListIndex, int nDrawIndex, drawlinesInfo& lineInfo); + std::vector > GetHistoryPoints(std::vector > &pt); + std::vector > GetOriginalPoints(); + void restorePoints(std::vector > &pt); + std::vector >* getOldPointsList(); + std::vector* GetOriginalstrokeList(); + std::vector >* GetOptimizedPointsList(int nListIndex); + int getOldStrokeWidth(int i, double& strokeWidth); + void saveOldPointsList(); + int getLastStrokeWidth(); + bool lineAlphaIsOpacity(int lineIndex); + bool isDrawStopped(); + bool lastBufferIsCompleted(); +private: + CLasso(const CLasso&) = delete; + const CLasso& operator = (const CLasso&) = delete; +private: + int _nDrawedIndex; // draw completed index + bool _bMouseUp; + std::vector _pointsList[MAX_POINTS_LIST_COUNT]; // latest moving points, is part of _originalPointsList + std::vector _originalPointsList[MAX_POINTS_LIST_COUNT]; // current moving points + std::vector > _oldPointsList; // last drawed optimized points + std::vector > _optimizedPointsList[MAX_POINTS_LIST_COUNT]; // current optimized points + std::deque _alphaList[MAX_POINTS_LIST_COUNT]; + std::vector _strokeList[MAX_POINTS_LIST_COUNT]; + std::vector _oldStrokeList; + std::vector _originalStrokeList; // current moving points stroke width +}; + +class CCairoImage +{ +public: + CCairoImage(); + Evas_Object *CreateImage(Evas *evas, int width, int height); + Evas_Object *createMaskImage(Evas *evas, int width, int height); + Evas_Object *createSource(Evas *evas, int width, int height); + void createBufferImage(Evas *evas, int width, int height); + void sourceUpdate(drawMode mode); + void maskUpdate(drawMode mode); + void DeleteImage(); + void MoveImage(int x, int y, int w, int h); + void saveImageBuffer(int w, int h); + void Clear(DrawingColor* pColor); + void SetDrawingProperty(DrawingColor* pColor); + /* normal drawing + effect: stroke alpha and strke width changes */ + void Draw(CLasso &lasso, double rw, double rh, int w, int h); + /* animation draw when undoing or redoing */ + static Eina_Bool animationDraw(void *data, double pos); + static Eina_Bool animationUpdateImage(void *data, double pos); + void GetDimensions(int *width, int *height); + void SaveDrawingImage(std::string& fileName); + void setClip(int x, int y, int w, int h); + void setProperty(int i, int j); + void clearSource(); + void clearBuffer(); + void clearMask(); + void clearImage(); + /* erase uncompleted white lines when do undo or redo */ + void eraseDraw(CLasso &lasso, double rw, double rh, int w, int h, int specIndex = -1); +#ifdef ENABLE_DRAGING + void dragImage(int dx, int dy); +#endif + + void setStrokeWidth(double dWidth); + double getStrokeWidth(); + void setBgType(std::string& bgType); + void SetHistoryDrawingProperty(cairo_t *cr, DrawingColor pColor, double strokeWidth); + /* normal drawing when undoing or redoing */ + void Draw(cairo_t *cr, std::vector> &pt1, std::vector& strokeList, double rw, double rh, int w, int h); + void setStopNormalDrawing(bool bDoding); + bool getNormalDrawingStatus(); + static void updateImage(cairo_t *cr, cairo_surface_t *maskSurface, cairo_surface_t *sourceSurface, Evas_Object *image); + static void reUpdateImage(cairo_t *cr, cairo_surface_t *maskSurface, cairo_surface_t *sourceSurface, Evas_Object *image); + + Evas_Object *_image; + Evas_Object *_maskImage; + Evas_Object *_sourceImage; + Evas_Object *_bufferImage; + double _strokeWidth; + cairo_t *_cr; + cairo_t *_maskCr; + cairo_t *_sourceCr; + cairo_t *_bufferCr; + cairo_surface_t *_maskSurface; + cairo_surface_t *_sourceSurface; + cairo_surface_t *_bufferSurface; +private: + void _createSaveCario(std::string& filePath); + void setStrokeAlpha(cairo_t* cr, drawlinesInfo& info); + void _eraseOldLine(CLasso &lasso, double rw, double rh, int w, int h); + void _drawPoints(CLasso &lasso, NormaldrawMode mode, int nLineIndex, double rw, double rh, CPoint& ptMin, CPoint& ptMax); + void _setStrokeProperty(CLasso &lasso, NormaldrawMode mode, int nLineIndex, int nPointIndex, drawlinesInfo& lineInfo); + void _pathDrawCurve(cairo_t *_cairo, double x1, double y1, double x2, double y2); + void _animateDrawPoints(CPoint& ptMin, CPoint& ptMax, double pos, void* pData); + +private: + int _nWidth; + int _nHeight; + bool _bStopNormalDrawing; + + unsigned char *_imgBuf; + unsigned char *_tempBuf; + cairo_surface_t *_surface; + Evas * _evas; + std::string _BgImgFile; + std::vector _palletColorCode; +}; + + + +struct animationUpdateData { + Ecore_Animator *updateAnimator; + cairo_t *cr; + cairo_t *sourceCr; + cairo_surface_t *sourceSurface; + Evas_Object *image; + Evas_Object *bgPattern; + drawMode mode; + bool isDrawing; +}; + +struct animationData { + //CLasso lasso; + std::vector> pt; + std::vector strokeList; + double rw; + double rh; + double imgUpdatePos; + int w; + int h; + int imgUpdateCount; + int nBgPatternAlpha; + bool isImgAnimateDraw; + drawMode mode; + cairo_t *cr; + cairo_t *sourceCr; + Evas_Object *image; + double strokeWidth; + DrawingColor pColor; + bool isDrawing; + bool isMaxAnimation; + Ecore_Animator *drawingAnimator; + double animationTime; + cairo_surface_t *maskSurface; + cairo_surface_t *sourceSurface; + Evas_Object *bgPattern; + CCairoImage* pCairo; +}; + + + +#endif // __CDRCAIRO_IMAGE_H__ + + diff --git a/src/controls/CDrControl.h b/src/controls/CDrControl.h new file mode 100755 index 0000000..a9bbc84 --- /dev/null +++ b/src/controls/CDrControl.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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 _CVE_CONTROLER_H_ +#define _CVE_CONTROLER_H_ + +#include +#include +#include +#include "WViewController.h" +#include "CDrEventListener.h" +#include "CDrEvent.h" +#include "WDefine.h" + + +using namespace app_assist; + + +class CDrControl:public WViewController, public CDrEventListener { + public: + + CDrControl() {}; + + public: + virtual void onEvent(const CDrEvent & event) {}; + + protected: + virtual ~CDrControl() {}; + + private: + WDISABLE_COPY_AND_ASSIGN(CDrControl); +}; + +#endif // _CVE_CONTROLER_H_ diff --git a/src/controls/CDrControlManager.cpp b/src/controls/CDrControlManager.cpp new file mode 100755 index 0000000..e056a6f --- /dev/null +++ b/src/controls/CDrControlManager.cpp @@ -0,0 +1,145 @@ +#include "CDrControlManager.h" +#include "DrDebug.h" +#include + +CDrControlManager::CDrControlManager() +{ +} + +CDrControlManager::~CDrControlManager() +{ + WDEBUG("size :%d", _mControlsMonitor.size()); + if (!_mControlsMonitor.empty()) { + for_each(_mControlsMonitor.begin(), _mControlsMonitor.end(), [](ControlObjPair controlObj) { + if (controlObj.second) { + if (auto p = controlObj.second->lock()) { + p->destroy(); + } + delete controlObj.second; WDEBUG("Destroy a control"); + } + }) ; + } +} + +ControlPWPtr CDrControlManager::find(const char *position) +{ + auto iter = _mControlsMonitor.find(position); + if (iter == _mControlsMonitor.end()) { + WERROR("Failed to get control"); + return nullptr; + } + + return (*iter).second; +} + +bool CDrControlManager::isDetached(const char *position) +{ + auto iter = _mControlsMonitor.find(position); + if (iter == _mControlsMonitor.end()) { + return true; + } else { + return false; + } +} + +// create new object and swallow it to layout +// use this method to set an evasObject to layout +void CDrControlManager::attach(Evas_Object * parent, CDrControl * control, const char *position, bool isSwallow2Parent, bool bdetach) +{ + WENTER(); + + // layout of view + if (parent == NULL) { + WERROR("Parent is NULL! Fail to attach control"); + return; + } + // delete old object first + if (bdetach) { + detach(parent, position); + } + // Base layout should be parent. + + control->create(parent, NULL); + if (isSwallow2Parent) { + Evas_Object *controlEvasObj = control->getEvasObj(); + elm_object_part_content_set(parent, position, controlEvasObj); + WINFO("set part %s--", position); + } + std::string keyString(position); + auto iterCur = _mControlsMonitor.find(keyString); + std::pair < ControlObjMap::iterator, bool > ret; + if (iterCur == _mControlsMonitor.end()) { + ret = _mControlsMonitor.insert(std::make_pair(keyString, new WViewControllerWeakPtr)); + if (ret.second == false) { + WERROR("Failed to insert control to map"); + return; + } else { + iterCur = ret.first; + } + WDEBUG("Insert a control"); + } else { + destroy((*iterCur).second); + } + *((*iterCur).second) = control->getWeakPtr(); + + WLEAVE(); +} + +// detach swallow content from parent and then destory Control object +// use this method to unset an evasObject from layout +void CDrControlManager::detach(Evas_Object * parent, const char *position, bool isSwallow2Parent) +{ + //WENTER(); + + // layout of view + if (parent == NULL) { + WERROR("Parent is NULL! Fail to attach control"); + return; + } + if (isSwallow2Parent) { + Evas_Object *evasObj = elm_object_part_content_unset(parent, position); + if (evasObj) { + WDEBUG("Evas Object unset"); + } + } + + std::string keyString(position); + auto iterCur = _mControlsMonitor.find(keyString); + if (iterCur != _mControlsMonitor.end()) { + destroy((*iterCur).second); + } + + //WLEAVE(); +} + +// destroy control object +void CDrControlManager::destroy(ControlPWPtr controlMonitor) +{ + if (controlMonitor == NULL) { + return; + } + + if (auto p = controlMonitor->lock()) { + p->destroy(); + controlMonitor->reset(); + } + WDEBUG("Destroy a control"); +} + +//refine me with manager +void CDrControlManager::forEach(std::function < void(ControlPWPtr) > fn) +{ + for_each(_mControlsMonitor.begin(), _mControlsMonitor.end(), [&](ControlObjPair controlObj) { + fn(controlObj.second); + }); +} + +void CDrControlManager::notify(const CDrEvent & event) +{ + for_each(_mControlsMonitor.begin(), _mControlsMonitor.end(), [&](ControlObjPair controlObj) { + CDrControl * control = getControlObject < CDrControl * >(controlObj.second); + if (control) { + control->onEvent(event); + } + }) ; +} diff --git a/src/controls/CDrControlManager.h b/src/controls/CDrControlManager.h new file mode 100755 index 0000000..e51fe51 --- /dev/null +++ b/src/controls/CDrControlManager.h @@ -0,0 +1,63 @@ +#ifndef _CDR_CONTROL_MANAGER_H_ +#define _CDR_CONTROL_MANAGER_H_ + +#include +#include +#include "WWindowController.h" +#include +#include +#include +#include "CDrControl.h" +#include "CDrEventListener.h" +#include "CDrEvent.h" +#include "WDefine.h" +#include "DrDebug.h" + + +using namespace app_assist; + +typedef WViewControllerWeakPtr *ControlPWPtr; +typedef std::pair < std::string, ControlPWPtr > ControlObjPair; +typedef std::map < std::string, ControlPWPtr > ControlObjMap; + +template < typename TYPE > TYPE getControlObject(ControlPWPtr monitorObj) +{ + if (monitorObj == nullptr || monitorObj->expired()) { + //WERROR("Control pointer is expired"); + return nullptr; + } + + Evas_Object *evasObj = NULL; + if (auto p = monitorObj->lock()) { + evasObj = p->getEvasObj(); + } + if (!evasObj) { + //WERROR("Invalid evas object"); + return nullptr; + } + + return dynamic_cast < TYPE > (wviewcontroller_get_instance_from_evasobj(evasObj)); +} + +/** + * Used to manager Controls derived from CCsControl + * + */ +class CDrControlManager { + public: + CDrControlManager(); + ~CDrControlManager(); + + ControlPWPtr find(const char *position); + bool isDetached(const char *position); + void attach(Evas_Object * parent, CDrControl * control, const char *position, bool isSwallow2Parent = true, bool bdetach = true); + void detach(Evas_Object * parent, const char *position, bool isSwallow2Parent = true); + void destroy(ControlPWPtr controlMonitor); + void forEach(std::function < void(ControlPWPtr) > fn); + void notify(const CDrEvent & event); + + private: + ControlObjMap _mControlsMonitor; +}; + +#endif // _CVE_CONTROL_MANAGER_H_ diff --git a/src/controls/CDrDrawingView.cpp b/src/controls/CDrDrawingView.cpp new file mode 100755 index 0000000..ebb8a13 --- /dev/null +++ b/src/controls/CDrDrawingView.cpp @@ -0,0 +1,852 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "CDrAppData.h" +#include "CDrDrawingView.h" +#include "DrDefine.h" +#include "CDrEventManager.h" + +CDrDrawingView::CDrDrawingView() +: _drawingLayout(nullptr), + _edjeObj(nullptr), + _DrawingSaveTimer(nullptr), + _botmBgImg(nullptr), + _pDrawing(nullptr), +#ifdef REDO_UNDO + _history(nullptr), +#endif + _pHistoryCtrl(nullptr), + _NeedSaveDrawing(false), + _bCreateSaveTimer(false), + _bEraser(false), + _bColorMenuShowed(false), + _previousIndex(-1), + _colorIndex(0), + _showSaveButtonCb(nullptr), + _drawedCb(nullptr), + _showTimer(nullptr), + _showStatus(NONE_SHOW) +{ + _botmBgImgType = 0; + _colorCode = ""; + _oldColorCode = ""; + CDrEventManager::getInstance().attach(this); + + _bgFileList.push_back(SKETCH_DRAWING_COLOR_BG_01); + _bgFileList.push_back(SKETCH_DRAWING_COLOR_BG_02); + _bgFileList.push_back(SKETCH_DRAWING_COLOR_BG_03); + _bgFileList.push_back(SKETCH_DRAWING_COLOR_BG_04); + _pDrawing = new Drawing(); +#ifdef REDO_UNDO + _history = new History(); +#endif +} + +CDrDrawingView::~CDrDrawingView() +{ + WENTER(); + CDrEventManager::getInstance().detach(this); + _bgFileList.clear(); + if (_pDrawing) { + delete _pDrawing; + } +#ifdef REDO_UNDO + if (_history) { + delete _history; + } +#endif + if (_drawingLayout) + { + evas_object_del(_drawingLayout); + _drawingLayout = nullptr; + } +} + +#ifdef REDO_UNDO +Eina_Bool CDrDrawingView::_showIndicator(void *data) +{ + CDrDrawingView *pThis = (CDrDrawingView*)data; + if(pThis->_showStatus == UNDO_SHOW) { + if (pThis->_pDrawing->checkFirstIndexCb) { + if (pThis->_pDrawing->checkFirstIndexCb() && !pThis->_pDrawing->isDrawingStatus()) { + if (pThis->_showGuideCb) + pThis->_showGuideCb(); + } + } + pThis->_showStatus = NONE_SHOW; + } + pThis->_pDrawing->setStopNormalDrawing(false); + pThis->deleteSaveTimer(); + pThis->addSaveTimer(); + pThis->setSaveStatus(true); + + return ECORE_CALLBACK_CANCEL; +} + +void CDrDrawingView::_isOnRedoing(void *data, Eext_Rotary_Event_Info *ev) { + std::vector> pt; + std::vector strokeList; + DrawingColor pColor; + double strokeWidth; + int undoStart, undoEnd; + int redoStart, redoEnd; + CDrDrawingView *pThis = (CDrDrawingView*)data; + double time; + if (ev->direction == EEXT_ROTARY_DIRECTION_CLOCKWISE) {//redo + WINFO("CLOCKWISE, redo"); + if (!pThis->_history->checkLastIndex()) { + pThis->_showStatus = REDO_SHOW; + if (pThis->_pDrawing->pAnimationData->drawingAnimator) { + ecore_animator_del(pThis->_pDrawing->pAnimationData->drawingAnimator); + pThis->_pDrawing->pAnimationData->drawingAnimator = nullptr; + } + pThis->_pDrawing->resetIsDrawing(); + if(pThis->_pHistoryCtrl) { + pThis->_pHistoryCtrl->redoItem(); + } + + pThis->_pDrawing->setStopNormalDrawing(true); + pThis->_pDrawing->restorePoints(pt); + pThis->_pDrawing->clearSource(); + pThis->_pDrawing->sourceUpdate(REDO_DRAW); + int index = (pThis->_history->getCurIndex())%MAX_HISTORY; + pt.clear(); + pThis->_history->_getOutputBuffer(index, pt, strokeList, &pColor, &strokeWidth); + if (!pt.empty()) { + pThis->_pDrawing->updateBuffer(pt, strokeList, pColor, strokeWidth, NORMAL_DRAW); + } + pThis->_pDrawing->sourceUpdate(REDO_DRAW); + pt.clear(); + if (pThis->_history->redo(pt, strokeList, &pColor, &strokeWidth)) { + pThis->_pDrawing->updateBuffer(pt, strokeList, pColor, strokeWidth, REDO_DRAW); + if (pThis->_unReDoCb) { + pThis->_unReDoCb(false); + } + } + } + + if (pThis->_pDrawing->checkFirstIndexCb) { + if (!pThis->_pDrawing->checkFirstIndexCb()) { + if (pThis->_hideGuideCb) + pThis->_hideGuideCb(); + } + } + pThis->_pDrawing->getAnimatorTime(&time); + pThis->deleteShowTimer(); + pThis->addShowTimer(time); + } else { + WINFO("COUNTER_CLOCKWISE, undo");//undo + pThis->_showStatus = UNDO_SHOW; + + if (pThis->_pDrawing->pAnimationData->drawingAnimator) { + ecore_animator_del(pThis->_pDrawing->pAnimationData->drawingAnimator); + pThis->_pDrawing->pAnimationData->drawingAnimator = nullptr; + } + pThis->_pDrawing->animationUpdateImage(NORMAL_DRAW, nullptr); + + pThis->_pDrawing->resetIsDrawing(); + if(pThis->_pHistoryCtrl) { + pThis->_pHistoryCtrl->undoItem(); + } + + pThis->_pDrawing->setStopNormalDrawing(true); + pThis->_pDrawing->restorePoints(pt); + if (!pThis->_history->undo(&undoStart, &undoEnd) && pThis->_history->getMaxHistory()) { + Evas_Object* bgPattern = pThis->getBgPattern(); + pThis->_pDrawing->animationUpdateImage(UNDO_DRAW, bgPattern); + } else { + pThis->_pDrawing->clearSource(); + pThis->_pDrawing->sourceUpdate(REDO_DRAW); + } + if (pThis->_unReDoCb) { + pThis->_unReDoCb(true); + } + pThis->_pDrawing->getAnimatorTime(&time); + pThis->deleteShowTimer(); + pThis->addShowTimer(time); + } + return; +} + +void CDrDrawingView::_isOnUndoing(void *data, Eext_Rotary_Event_Info *ev) { + CDrDrawingView *pThis = (CDrDrawingView*)data; + int redoStart, redoEnd; + int undoStart, undoEnd; + DrawingColor pColor; + double strokeWidth; + double time; + std::vector> pt; + std::vector strokeList; + if (ev->direction == EEXT_ROTARY_DIRECTION_CLOCKWISE) {//redo + WINFO("CLOCKWISE, redo"); + pThis->_showStatus = REDO_SHOW; + if (pThis->_pDrawing->pAnimationData->drawingAnimator) { + ecore_animator_del(pThis->_pDrawing->pAnimationData->drawingAnimator); + pThis->_pDrawing->pAnimationData->drawingAnimator = nullptr; + } + pThis->_pDrawing->animationUpdateImage(NORMAL_DRAW, nullptr); + + if (pThis->_pHistoryCtrl) { + pThis->_pHistoryCtrl->redoItem(); + } + pThis->_pDrawing->resetIsDrawing(); + if (pThis->_pDrawing->checkFirstIndexCb) { + pThis->_pDrawing->setStopNormalDrawing(true); + pThis->_pDrawing->restorePoints(pt); + if (pThis->_history->getMaxHistory() && pThis->_pDrawing->checkFirstIndexCb()) { + Evas_Object* bgPattern = pThis->getBgPattern(); + pThis->_pDrawing->animationUpdateImage(REDO_DRAW, bgPattern); + if (pThis->_history->redo(pt, strokeList, &pColor, &strokeWidth)) { + pThis->_pDrawing->updateBuffer(pt, strokeList, pColor, strokeWidth, REDO_DRAW); + if (pThis->_unReDoCb) { + pThis->_unReDoCb(false); + } + } + } else { + pThis->_pDrawing->clearSource(); + pThis->_pDrawing->sourceUpdate(REDO_DRAW); + if (pThis->_history->redo(pt, strokeList, &pColor, &strokeWidth)) { + pThis->_pDrawing->updateBuffer(pt, strokeList, pColor, strokeWidth, REDO_DRAW); + if (pThis->_unReDoCb) { + pThis->_unReDoCb(false); + } + } + } + } + + if (pThis->_pDrawing->checkFirstIndexCb) { + if (!pThis->_pDrawing->checkFirstIndexCb()) { + if (pThis->_hideGuideCb) + pThis->_hideGuideCb(); + } + } + pThis->_pDrawing->getAnimatorTime(&time); + pThis->deleteShowTimer(); + pThis->addShowTimer(time); + } else { + WINFO("COUNTER_CLOCKWISE, undo");//undo + + if (pThis->_pDrawing->checkFirstIndexCb && !pThis->_pDrawing->checkFirstIndexCb()) { + pThis->_showStatus = UNDO_SHOW; + if (pThis->_pDrawing->pAnimationData->drawingAnimator) { + WINFO("del timeline anim"); + ecore_animator_del(pThis->_pDrawing->pAnimationData->drawingAnimator); + pThis->_pDrawing->pAnimationData->drawingAnimator = nullptr; + } + pThis->_pDrawing->animationUpdateImage(NORMAL_DRAW, nullptr); + pThis->_pDrawing->resetIsDrawing(); + if (pThis->_pHistoryCtrl) { + pThis->_pHistoryCtrl->undoItem(); + } + + pThis->_pDrawing->setStopNormalDrawing(true); + pThis->_pDrawing->restorePoints(pt); + pThis->_pDrawing->clearSource(); + pThis->_pDrawing->sourceUpdate(REDO_DRAW); + + if (pThis->_history->getMaxHistory()) { + pThis->_pDrawing->clearSource(); + pThis->_pDrawing->clearMask(); + pThis->_pDrawing->maskUpdate(UNDO_DRAW); + if (pThis->_history->undo(&undoStart, &undoEnd)) { + for (int cnt = undoStart; cnt % MAX_HISTORY != undoEnd % MAX_HISTORY; cnt++) { + pt.clear(); + pThis->_history->_getOutputBuffer(cnt % MAX_HISTORY, pt, strokeList, &pColor, &strokeWidth); + if (!pt.empty()) { + pThis->_pDrawing->updateBuffer(pt, strokeList, pColor, strokeWidth, NORMAL_DRAW); + } + } + pThis->_pDrawing->sourceUpdate(UNDO_DRAW); + pt.clear(); + pThis->_history->_getOutputBuffer(undoEnd % MAX_HISTORY, pt, strokeList, &pColor, &strokeWidth); + if (!pt.empty()) { + WINFO("undo draw"); + pThis->_pDrawing->updateBuffer(pt, strokeList, pColor, strokeWidth, UNDO_DRAW); + } + } else { + Evas_Object* bgPattern = pThis->getBgPattern(); + WINFO("undo draw bg"); + pThis->_pDrawing->animationUpdateImage(UNDO_DRAW, bgPattern); + } + } else { + pThis->_pDrawing->clearSource(); + pThis->_pDrawing->clearMask(); + if (pThis->_history->undo(&undoStart, &undoEnd)) { + for (int cnt = undoStart; cnt % MAX_HISTORY != undoEnd % MAX_HISTORY; cnt++) { + pt.clear(); + pThis->_history->_getOutputBuffer(cnt % MAX_HISTORY, pt, strokeList, &pColor, &strokeWidth); + if (!pt.empty()) { + pThis->_pDrawing->updateBuffer(pt, strokeList, pColor, strokeWidth, NORMAL_DRAW); + } + } + pThis->_pDrawing->sourceUpdate(UNDO_DRAW); + pt.clear(); + pThis->_history->_getOutputBuffer(undoEnd % MAX_HISTORY, pt, strokeList, &pColor, &strokeWidth); + if (!pt.empty()) { + pThis->_pDrawing->updateBuffer(pt, strokeList, pColor, strokeWidth, UNDO_DRAW); + } + } else { + WINFO("no did undo"); + pThis->_pDrawing->sourceUpdate(REDO_DRAW); + } + } + + if (pThis->_unReDoCb) { + pThis->_unReDoCb(true); + } + } + pThis->_pDrawing->getAnimatorTime(&time); + pThis->deleteShowTimer(); + pThis->addShowTimer(time); + } + return; +} + +showStatus CDrDrawingView::getDrawStatus() +{ + return _showStatus; +} + +Eina_Bool CDrDrawingView::_onRotaryHandler(void *data, Evas_Object *obj, Eext_Rotary_Event_Info *ev) +{ + int cnt = 0; + double strokeWidth; + int undoStart = 0; + int undoEnd = 0; + int redoStart = 0; + int redoEnd = 0; + std::vector> pt; + std::vector strokeList; + DrawingColor pColor; + double time; + CDrDrawingView *pThis = (CDrDrawingView*)data; + + if(pThis->_bColorMenuShowed == true) { + WINFO("color menu show, return"); + return EINA_TRUE; + } + if (pThis->_pDrawing->isMouseMoving()) { + WERROR("isMouseMoving, return"); + return EINA_FALSE; + } + pThis->deleteSaveTimer(); + if (pThis->_pDrawing->getDrawingStatus()) + { + if (pThis->getDrawStatus() == REDO_SHOW) {//redo + _isOnRedoing(data, ev); + } else if (pThis->getDrawStatus() == UNDO_SHOW){ + _isOnUndoing(data, ev); + } + return EINA_FALSE; + } + + if (pThis->_showHistoryIndexCb) { + pThis->_showHistoryIndexCb(true); + } + + if (ev->direction == EEXT_ROTARY_DIRECTION_CLOCKWISE) { + WINFO("CLOCKWISE"); + pThis->_pDrawing->animationUpdateImage(NORMAL_DRAW, nullptr); + pThis->_showStatus = REDO_SHOW; + if(pThis->_pHistoryCtrl) { + pThis->_pHistoryCtrl->redoItem(); + } + + if (pThis->_pDrawing->checkFirstIndexCb) { + pThis->_pDrawing->setStopNormalDrawing(true); + pThis->_pDrawing->restorePoints(pt); + + if (pThis->_pDrawing->getPatternBgAlpha() != 0) { + WINFO("bg alpha > 0"); + Evas_Object* bgPattern = pThis->getBgPattern(); + pThis->_pDrawing->animationUpdateImage(REDO_DRAW, bgPattern); + } + + if (pThis->_history->getMaxHistory() && pThis->_pDrawing->checkFirstIndexCb()) { + pThis->_pDrawing->clearSource(); + pThis->_pDrawing->clearMask(); + pThis->_pDrawing->maskUpdate(UNDO_DRAW); + pThis->_pDrawing->sourceUpdate(REDO_DRAW); + if (pThis->_history->redo(pt, strokeList, &pColor, &strokeWidth)) { + pThis->_pDrawing->updateBuffer(pt, strokeList, pColor, strokeWidth, REDO_DRAW); + if (pThis->_unReDoCb) { + pThis->_unReDoCb(false); + } + } + } else { + pThis->_pDrawing->clearSource(); + pThis->_pDrawing->clearMask(); + pThis->_pDrawing->maskUpdate(REDO_DRAW); + pThis->_pDrawing->sourceUpdate(REDO_DRAW); + if (pThis->_history->redo(pt, strokeList, &pColor, &strokeWidth)) { + pThis->_pDrawing->updateBuffer(pt, strokeList, pColor, strokeWidth, REDO_DRAW); + if (pThis->_unReDoCb) { + pThis->_unReDoCb(false); + } + } + } + } + + if (pThis->_pDrawing->checkFirstIndexCb) { + if (!pThis->_pDrawing->checkFirstIndexCb()) { + if (pThis->_hideGuideCb) + pThis->_hideGuideCb(); + } + } + pThis->_pDrawing->getAnimatorTime(&time); + pThis->deleteShowTimer(); + pThis->addShowTimer(time); + } else { + WINFO("COUNTER_CLOCKWISE");//undo + if (pThis->_pDrawing->checkFirstIndexCb && !pThis->_pDrawing->checkFirstIndexCb()) { + pThis->_pDrawing->animationUpdateImage(NORMAL_DRAW, nullptr); + pThis->_showStatus = UNDO_SHOW; + if(pThis->_pHistoryCtrl) { + pThis->_pHistoryCtrl->undoItem(); + } + pThis->_pDrawing->setStopNormalDrawing(true); + pThis->_pDrawing->restorePoints(pt); + if (pThis->_history->getMaxHistory()) { + pThis->_pDrawing->clearSource(); + pThis->_pDrawing->clearMask(); + pThis->_pDrawing->maskUpdate(UNDO_DRAW); + if (pThis->_history->undo(&undoStart, &undoEnd)) { + for (cnt = undoStart; cnt % MAX_HISTORY != undoEnd % MAX_HISTORY; cnt++) { + pt.clear(); + pThis->_history->_getOutputBuffer(cnt % MAX_HISTORY, pt, strokeList, &pColor, &strokeWidth); + if (!pt.empty()) { + pThis->_pDrawing->updateBuffer(pt, strokeList, pColor, strokeWidth, NORMAL_DRAW); + } + } + pThis->_pDrawing->sourceUpdate(UNDO_DRAW); + pt.clear(); + pThis->_history->_getOutputBuffer(undoEnd % MAX_HISTORY, pt, strokeList, &pColor, &strokeWidth); + if (!pt.empty()) { + pThis->_pDrawing->updateBuffer(pt, strokeList, pColor, strokeWidth, UNDO_DRAW); + } + } else { + WINFO("> max undo to first,change bg"); + Evas_Object* bgPattern = pThis->getBgPattern(); + pThis->_pDrawing->animationUpdateImage(UNDO_DRAW, bgPattern); + } + } else { + pThis->_pDrawing->clearSource(); + pThis->_pDrawing->clearMask(); + if (pThis->_history->undo(&undoStart, &undoEnd)) { + for (cnt = undoStart; cnt % MAX_HISTORY != undoEnd % MAX_HISTORY; cnt++) { + pt.clear(); + pThis->_history->_getOutputBuffer(cnt % MAX_HISTORY, pt, strokeList, &pColor, &strokeWidth); + if (!pt.empty()) { + pThis->_pDrawing->updateBuffer(pt, strokeList, pColor, strokeWidth, NORMAL_DRAW); + } + } + pThis->_pDrawing->sourceUpdate(UNDO_DRAW); + pt.clear(); + pThis->_history->_getOutputBuffer(undoEnd % MAX_HISTORY, pt, strokeList, &pColor, &strokeWidth); + if (!pt.empty()) { + pThis->_pDrawing->updateBuffer(pt, strokeList, pColor, strokeWidth, UNDO_DRAW); + } + } else { + WINFO("< max, no did undo"); + pThis->_pDrawing->sourceUpdate(UNDO_DRAW); + pt.clear(); + pThis->_history->_getOutputBuffer(undoEnd % MAX_HISTORY, pt, strokeList, &pColor, &strokeWidth); + if (!pt.empty()) { + pThis->_pDrawing->updateBuffer(pt, strokeList, pColor, strokeWidth, UNDO_DRAW); + } + } + } + if (pThis->_unReDoCb) { + pThis->_unReDoCb(true); + } + } + + pThis->_pDrawing->getAnimatorTime(&time); + pThis->deleteShowTimer(); + pThis->addShowTimer(time); + } + return EINA_FALSE; +} +#endif + +Evas_Object * CDrDrawingView::onCreateView(Evas_Object * parent, void *viewParam) +{ + WENTER(); + + if (!_drawingLayout) { + WINFO("create drawing layout"); + _drawingLayout = elm_layout_add(parent); + WASSERT(_drawingLayout); + + char* _path = app_get_resource_path(); + std::string path(_path); + path += "/edje/drawing_layout.edj"; + + elm_layout_file_set(_drawingLayout, path.c_str(), DRAWING_LAYOUT_GROUP_NAME); + evas_object_size_hint_weight_set(_drawingLayout, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_size_hint_align_set(_drawingLayout, EVAS_HINT_FILL, EVAS_HINT_FILL); + evas_object_resize(_drawingLayout, 360, 360); + //elm_object_part_content_set(parent, "pre-view", _drawingLayout); + evas_object_show(_drawingLayout); + + _edjeObj = (Evas_Object *)elm_layout_edje_get(_drawingLayout); + free(_path); + } + if (CDrAppData::getInstance()->getLaunchMode() == DRAWING_SAVE) { + elm_object_signal_emit(_drawingLayout, "pattern,negative,bg,hide", "*"); + } +#ifndef SKETCH_DRAW_COLORS_CHANGABLE + if (CDrAppData::getInstance()->getLaunchMode() == DRAWING_SEND) { + elm_object_signal_emit(_drawingLayout, "pattern,negative,bg,hide", "*"); + /* create bottom bg image */ + char* resPath = app_get_resource_path(); + std::string bgPath(resPath); + free(resPath); + + _botmBgImg = elm_image_add(_drawingLayout); + _botmBgImgType = CDrAppData::getInstance()->getBgIndex(); + WINFO("BG %s", _bgFileList[_botmBgImgType].c_str()); + bgPath +=_bgFileList[_botmBgImgType]; + elm_image_file_set(_botmBgImg, bgPath.c_str(), NULL); + elm_image_no_scale_set(_botmBgImg, EINA_FALSE); + elm_object_part_content_set(_drawingLayout, "elm.swallow.bottom.bgimage", _botmBgImg); + evas_object_show(_botmBgImg); + } +#endif + +#ifdef REDO_UNDO + _pDrawing->setSaveBufferCb([&](std::vector> pt1, std::vector* pStrokeList, DrawingColor* pColor, double strokeWidth, bool increaseIndex){ + _history->saveBuffer(pt1, pStrokeList, pColor, strokeWidth, increaseIndex); + int nCurIndex = _history->getCurIndex(); + if(_pHistoryCtrl) { + if (increaseIndex) { + _pHistoryCtrl->addItem(_history->getCount()); + } else { + _pHistoryCtrl->deleteItem(_history->getCount()); + } + WINFO("CNT:%d", _history->getCount()); + } + }); + + _pDrawing->setCheckFirstIndexCb([&](void)->bool { + return _history->checkFirstIndex(); + }); + _pDrawing->setGetBufferCb([&](int curIndex, std::vector> &buffer, std::vector& strokeList, DrawingColor* pColor, double *width) { + _history->_getOutputBuffer(curIndex, buffer, strokeList, pColor, width); + }); +#endif + + Evas_Object* select = _pDrawing->drawingAdd(_drawingLayout); + Evas_Object* bg_image = (Evas_Object *)edje_object_part_object_get(_edjeObj, "bg"); + +#ifdef REDO_UNDO +// eext_rotary_event_handler_add(_onRotaryHandler, this); +#endif + + _pDrawing->drawingAttach(bg_image); + _pDrawing->drawingColorSet(_colorCode, _bEraser); + elm_object_part_content_set(_drawingLayout, "drawing_area", select); + + evas_object_show(select); + + _pDrawing->setBgType(_bgFileList[_botmBgImgType]); + + _pDrawing->setDeleteSaveTimerCb([&](void){ + deleteSaveTimer(); + if (_drawedCb) { + _drawedCb(); + } + deleteHistoryIndexTimer(); + }); + _pDrawing->setColorMenuStateCb([&](void)->bool { + return _bColorMenuShowed; + }); + _pDrawing->setSaveStateCb([&](bool bState) { + setSaveStatus(bState); + }); + _pDrawing->setAddSaveTimerCb([&](void){ + addSaveTimer(); + }); + _history->setClearCb([&](void){ + _pDrawing->clearImage(); + }); + + _history->setUpdateBufferImageCb([&](int index){ + _pDrawing->updateBufferImage(index); + }); + _pDrawing->setSetMaxHistoryCb([&](bool status) { + _history->setMaxHistory(status); + }); + addSaveTimer(); + WLEAVE(); + return _drawingLayout; +} + +void CDrDrawingView::onCreated() +{ +} + +void CDrDrawingView::onDestroy() +{ + WENTER(); + deleteShowTimer(); + deleteSaveTimer(); +#ifdef REDO_UNDO + eext_rotary_object_event_callback_del(_drawingLayout, _onRotaryHandler); +#endif + WLEAVE(); +} + +void CDrDrawingView::onEvent(const CDrEvent & event) +{ +#ifdef REDO_UNDO + if (event.mType == CDrEvent::APP_PAUSED) { + eext_rotary_object_event_callback_del(_drawingLayout, _onRotaryHandler); + } else if (event.mType == CDrEvent::APP_RESUMED) { + eext_rotary_object_event_callback_add(_drawingLayout, _onRotaryHandler, this); + eext_rotary_object_event_activated_set(_drawingLayout, EINA_TRUE); + } +#endif +} + +void CDrDrawingView::setColorCode(std::string& strColor) +{ + _oldColorCode = _colorCode; + + _colorCode = strColor; + if (_colorCode == "") { + _bEraser = true; + } else { + _bEraser = false; + } + _pDrawing->drawingColorSet(_colorCode, _bEraser); +} + + +void CDrDrawingView::deleteSaveTimer() +{ + if(_DrawingSaveTimer) { + ecore_timer_del(_DrawingSaveTimer); + _DrawingSaveTimer = nullptr; + } + if (_showSaveButtonCb) { + _showSaveButtonCb(false); + } +} + +void CDrDrawingView::addSaveTimer() +{ + WINFO("addSaveTimer"); + + if (!_DrawingSaveTimer) { + _DrawingSaveTimer = ecore_timer_add(1.0, + CDrDrawingView::_onSaveDrawingImage, + this); + } else { + ecore_timer_reset(_DrawingSaveTimer); + } +} + +void CDrDrawingView::deleteShowTimer() +{ + if(_showTimer) { + ecore_timer_del(_showTimer); + _showTimer = nullptr; + } +} + +void CDrDrawingView::addShowTimer(double time) +{ + if (!_showTimer) { + _showTimer = ecore_timer_add(time, + CDrDrawingView::_showIndicator, + this); + } else { + ecore_timer_reset(_showTimer); + } +} + +void CDrDrawingView::deleteHistoryIndexTimer() +{ + if ( _showHistoryIndexCb) { + _showHistoryIndexCb(false); + } +} + +void CDrDrawingView::setSaveStatus(bool need) +{ + _NeedSaveDrawing = need; +} + +Eina_Bool CDrDrawingView::_onSaveDrawingImage(void *data) +{ + CDrDrawingView *pThis = (CDrDrawingView*)data; + //pThis->deleteSaveTimer(); + + if(pThis->_NeedSaveDrawing == true) + { + WINFO("need_save_drawing"); + pThis->_NeedSaveDrawing = false; + + if (pThis->_showSaveButtonCb) { + pThis->_showSaveButtonCb(true); + } + if (pThis->_showHistoryIndexCb) { + pThis->_showHistoryIndexCb(true); + } + } + if (pThis->_pDrawing->checkFirstIndexCb) { + if (pThis->_pDrawing->checkFirstIndexCb()) { + if (pThis->_hideGuideCb) + pThis->_hideGuideCb(); + } + } + + return EINA_FALSE; +} + +void CDrDrawingView::setShowSaveButtonCb(std::function < void(bool) > handlerFunc) +{ + _showSaveButtonCb = handlerFunc; +} + +void CDrDrawingView::saveImage(std::string& strFilePath, const bool media_scan_file) +{ + _pDrawing->saveDrawingImage(strFilePath); + + if (media_scan_file == false) return; + + int nRet = MEDIA_CONTENT_ERROR_NONE; + nRet = media_content_connect(); + if (nRet != MEDIA_CONTENT_ERROR_NONE) { + WINFO("media_content_connect is fail : 0x%x", nRet); + return ; + } + + nRet = media_content_scan_file(strFilePath.c_str()); + if (nRet != MEDIA_CONTENT_ERROR_NONE) { + WERROR("Fail to register new edited file to DB : %d", nRet); + } + nRet = media_content_disconnect(); + if (nRet != MEDIA_CONTENT_ERROR_NONE) { + WINFO("media_content_connect is fail : 0x%x", nRet); + } +} + +void CDrDrawingView::setDrawedCb(std::function < void(void) > handlerFunc) +{ + _drawedCb = handlerFunc; +} + +void CDrDrawingView::setShowGuideCb(std::function < void(void) > handlerFunc) +{ + _showGuideCb = handlerFunc; +} + +void CDrDrawingView::setHideGuideCb(std::function < void(void) > handlerFunc) +{ + _hideGuideCb = handlerFunc; +} + +void CDrDrawingView::setShowHistoryIndexCb(std::function < void(bool) > handlerFunc) +{ + _showHistoryIndexCb = handlerFunc; +} + +void CDrDrawingView::setColorMenuState(bool bShow) +{ + if (!bShow && _bColorMenuShowed) { + setSaveStatus(true); + addSaveTimer(); + } + + _bColorMenuShowed = bShow; +} + +void CDrDrawingView::setStrokeWidth(double dStrokeWidth) +{ + WINFO("set stroke width"); + _pDrawing->setStrokeWidth(dStrokeWidth); +} + +void CDrDrawingView::setShowPanelCb(std::function < void(void) > handlerFunc) +{ + _pDrawing->setShowPanelCb(handlerFunc); +} + +void CDrDrawingView::saveAnimationUpdate(int nStep) +{ +#ifndef SKETCH_DRAW_COLORS_CHANGABLE + Evas_Object* bgPattern = (Evas_Object *)edje_object_part_object_get(_edjeObj, "bg_pattern_negative_image"); + + if (CDrAppData::getInstance()->getLaunchMode() == DRAWING_SEND) { + evas_object_color_set(bgPattern, 0, 0, 0, 255 - nStep); + } else { + evas_object_color_set(_pDrawing->getDrawImgObj(), 255, 255, 255, nStep); + } +#else + evas_object_color_set(_pDrawing->getDrawImgObj(), 255, 255, 255, nStep); +#endif +} + +Evas_Object* CDrDrawingView::getBgPattern() +{ + Evas_Object* bgPattern = (Evas_Object *)edje_object_part_object_get(_edjeObj, "bg_pattern_negative_image"); + return bgPattern; +} + + +void CDrDrawingView::setHistoryControlHandle(CDrHistoryControl* pHandle) +{ + _pHistoryCtrl = pHandle; +} + +bool CDrDrawingView::checkIsFirstHistory() +{ +#ifdef REDO_UNDO + if (_history) { + return _history->checkFirstIndex(); + } +#endif + return false; +} + +bool CDrDrawingView::checkHasHistory() +{ +#ifdef REDO_UNDO + if (_history) { + return _history->getCount() == 1 ? false: true; + } +#endif + return false; +} + +void CDrDrawingView::activateUndoRedoRotary(bool bActivate) +{ +#ifdef REDO_UNDO + if (bActivate) { + eext_rotary_object_event_activated_set(_drawingLayout, EINA_TRUE); + } else { + eext_rotary_object_event_activated_set(_drawingLayout, EINA_FALSE); + } +#endif +} + +void CDrDrawingView::activateUpdateAnimator(bool bActivate) +{ + _pDrawing->activateUpdateAnimator(bActivate); +} + +void CDrDrawingView::setUnRedoCb(std::function < void(bool) > handlerFunc) +{ + _unReDoCb = handlerFunc; +} diff --git a/src/controls/CDrDrawingView.h b/src/controls/CDrDrawingView.h new file mode 100755 index 0000000..bc228a2 --- /dev/null +++ b/src/controls/CDrDrawingView.h @@ -0,0 +1,110 @@ +#ifndef _CDR_DRAWING_VIEW_H_ +#define _CDR_DRAWING_VIEW_H_ + +//#include "sphysics_pba.h" +#include +#include +#include +#include +//#include +#include +#include +#include +#include "Drawing.h" +#include "WViewController.h" +#include "CDrEventListener.h" +#include "CDrControl.h" +#include "CDrHistoryControl.h" +#include "WUiTimer.h" + +#ifdef REDO_UNDO +#include "History.h" +#endif +using namespace app_assist; + +typedef enum { + NONE_SHOW = -1, + REDO_SHOW, + UNDO_SHOW +} showStatus; + +class CDrDrawingView: public CDrControl { +public: + CDrDrawingView(); + + virtual void deleteSaveTimer(); + virtual void addSaveTimer(); + void deleteShowTimer(); + void addShowTimer(double time); + void setSaveStatus(bool need); + void onEvent(const CDrEvent & event); + + virtual Evas_Object * onCreateView(Evas_Object * parent, void *viewParam); + virtual void onDestroy(); + virtual void onCreated(); + void setShowSaveButtonCb(std::function < void(bool) > handlerFunc); + void setShowPanelCb(std::function < void(void) > handlerFunc); + void setShowGuideCb(std::function < void(void) > handlerFunc); + void setHideGuideCb(std::function < void(void) > handlerFunc); + void setShowHistoryIndexCb(std::function < void(bool) > handlerFunc); + void saveImage(std::string& strFilePath, const bool media_scan_file); + void setDrawedCb(std::function < void(void) > handlerFunc); + void setColorCode(std::string& strColor); + void setColorMenuState(bool bShow); + void saveAnimationUpdate(int nStep); + + void setStrokeWidth(double dStrokeWidth); + void setHistoryControlHandle(CDrHistoryControl* pHandle); + void deleteHistoryIndexTimer(); + bool checkIsFirstHistory(); + bool checkHasHistory(); + void activateUndoRedoRotary(bool bActivate); + void activateUpdateAnimator(bool bActivate); + void setUnRedoCb(std::function < void(bool) > handlerFunc); + Evas_Object *getBgPattern(); + showStatus getDrawStatus(); + +protected: + virtual ~CDrDrawingView(); + +private: + static Eina_Bool _onSaveDrawingImage(void *data); +#ifdef REDO_UNDO + static Eina_Bool _onRotaryHandler(void *data, Evas_Object *obj, Eext_Rotary_Event_Info *ev); +#endif + static Eina_Bool _showIndicator(void *data); + static void _isOnRedoing(void *data, Eext_Rotary_Event_Info *ev); + static void _isOnUndoing(void *data, Eext_Rotary_Event_Info *ev); + +private: + Evas_Object *_drawingLayout; + Evas_Object *_edjeObj; + Ecore_Timer *_DrawingSaveTimer; + Ecore_Timer *_showTimer; + Evas_Object *_botmBgImg; + Drawing *_pDrawing; +#ifdef REDO_UNDO + History * _history; +#endif + showStatus _showStatus; + CDrHistoryControl* _pHistoryCtrl; + bool _NeedSaveDrawing; + bool _bCreateSaveTimer; + bool _bEraser; + bool _bColorMenuShowed; + int _previousIndex; + int _colorIndex; + int _botmBgImgType; + + std::string _colorCode; + std::string _oldColorCode; + std::function < void(bool) > _showSaveButtonCb; + std::function < void(void) > _drawedCb; + std::vector _bgFileList; + std::function < void(void) > _showGuideCb; + std::function < void(void) > _hideGuideCb; + std::function < void(bool) > _showHistoryIndexCb; + std::function < void(bool) > _unReDoCb; +}; +#endif /* _DRAWING_VIEW_H_ end */ + diff --git a/src/controls/CDrHistoryControl.cpp b/src/controls/CDrHistoryControl.cpp new file mode 100755 index 0000000..de412cc --- /dev/null +++ b/src/controls/CDrHistoryControl.cpp @@ -0,0 +1,233 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "CDrAppData.h" +#include "CDrHistoryControl.h" +#include "DrDefine.h" + +#define INDEX_ITEM_START_POS 5 +#define INDEX_ITEM_POS_CENTER 9 //11 +#define INDEX_ITEM_EVEN_POS_CENTER 11 //11 + +CDrHistoryControl::CDrHistoryControl() +{ + _oIndex = nullptr; + _parent = nullptr; + _nStartIndexPos = INDEX_ITEM_START_POS; + _nCurIndex = -1; + _nSelectedIndex = 0; + + //_itemOddStyleList.push_back(""); + _itemOddStyleList.push_back("item/odd_1"); + _itemOddStyleList.push_back("item/odd_2"); + _itemOddStyleList.push_back("item/odd_3"); + _itemOddStyleList.push_back("item/odd_4"); + _itemOddStyleList.push_back("item/odd_5"); + _itemOddStyleList.push_back("item/odd_6"); + _itemOddStyleList.push_back("item/odd_7"); + _itemOddStyleList.push_back("item/odd_8"); + _itemOddStyleList.push_back("item/odd_9"); + _itemOddStyleList.push_back("item/odd_10"); + _itemOddStyleList.push_back("item/odd_11"); + _itemOddStyleList.push_back("item/odd_12"); + _itemOddStyleList.push_back("item/odd_13"); + _itemOddStyleList.push_back("item/odd_14"); + _itemOddStyleList.push_back("item/odd_15"); + _itemOddStyleList.push_back("item/odd_16"); + _itemOddStyleList.push_back("item/odd_17"); + _itemOddStyleList.push_back("item/odd_18"); + _itemOddStyleList.push_back("item/odd_19"); + + _itemEvenStyleList.push_back(""); + _itemEvenStyleList.push_back(""); + _itemEvenStyleList.push_back("item/even_2"); + _itemEvenStyleList.push_back("item/even_3"); + _itemEvenStyleList.push_back("item/even_4"); + _itemEvenStyleList.push_back("item/even_5"); + _itemEvenStyleList.push_back("item/even_6"); + _itemEvenStyleList.push_back("item/even_7"); + _itemEvenStyleList.push_back("item/even_8"); + _itemEvenStyleList.push_back("item/even_9"); + _itemEvenStyleList.push_back("item/even_10"); + _itemEvenStyleList.push_back("item/even_11"); + _itemEvenStyleList.push_back("item/even_12"); + _itemEvenStyleList.push_back("item/even_13"); + _itemEvenStyleList.push_back("item/even_14"); + _itemEvenStyleList.push_back("item/even_15"); + _itemEvenStyleList.push_back("item/even_16"); + _itemEvenStyleList.push_back("item/even_17"); + _itemEvenStyleList.push_back("item/even_18"); + _itemEvenStyleList.push_back("item/even_19"); + _itemEvenStyleList.push_back("item/even_20"); +} + +CDrHistoryControl::~CDrHistoryControl() +{ + WENTER(); + _itemList.clear(); + _itemOddStyleList.clear(); + _itemEvenStyleList.clear(); +} + +void CDrHistoryControl::createControl(Evas_Object * parent) +{ + WENTER(); + _oIndex = elm_index_add(parent); + if (_oIndex == nullptr) { + WERROR("create failed"); + } + elm_object_style_set(_oIndex, "circle"); + evas_object_size_hint_weight_set(_oIndex, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_size_hint_align_set(_oIndex, EVAS_HINT_FILL, EVAS_HINT_FILL); + elm_index_horizontal_set(_oIndex, EINA_TRUE); + elm_index_autohide_disabled_set(_oIndex, EINA_TRUE); + elm_object_part_content_set(parent, "elm.swallow.history.index", _oIndex); + _parent = parent; +} +void CDrHistoryControl::deleteControl() +{ + _itemList.clear(); + _nStartIndexPos = INDEX_ITEM_START_POS; + elm_index_level_go(_oIndex, 0); + elm_object_part_content_unset(_parent, "elm.swallow.history.index"); + if (_oIndex != nullptr) { + evas_object_del(_oIndex); + _oIndex = nullptr; + } +} + +void CDrHistoryControl::addItem(int HistoryCount) +{ + Elm_Object_Item* item = nullptr; + if (_itemList.size() >= (MAX_HISTORY) && (_nCurIndex+1) >= (MAX_HISTORY)) { + WINFO("> max count"); + return; + } + if (HistoryCount <= 1) { + WINFO("1 dots not create"); + return; + } + if (HistoryCount != _itemList.size()) { + /* delete item */ + deleteControl(); + createControl(_parent); + /* add item */ + _nCurIndex = HistoryCount-1; + _nSelectedIndex = _nCurIndex; + WINFO("add index %d", _nCurIndex); + int nStartIndex = 0; + bool bUseOdd = true; + if (HistoryCount % 2 == 0) { + nStartIndex = INDEX_ITEM_EVEN_POS_CENTER - (HistoryCount)/2; + bUseOdd = false; + } else { + nStartIndex = INDEX_ITEM_POS_CENTER - (HistoryCount)/2; + } + WINFO("SET start style %d", nStartIndex); + for (int i =0; i < HistoryCount; i++) { + item = elm_index_item_append(_oIndex, NULL, NULL, (void *) i); + if (bUseOdd) { + elm_object_item_style_set(item, _itemOddStyleList[nStartIndex++].c_str()); + } else { + elm_object_item_style_set(item, _itemEvenStyleList[nStartIndex++].c_str()); + } + + _itemList.push_back(item); + } + } else { + WINFO("history count same"); + _nCurIndex = HistoryCount-1; + _nSelectedIndex = _nCurIndex; + item = _itemList[_nCurIndex]; + } + + elm_index_level_go(_oIndex, 0); + elm_index_item_selected_set(item, EINA_TRUE); +} + +void CDrHistoryControl::deleteItem(int HistoryCount) +{ + Elm_Object_Item* item = nullptr; + if (_itemList.size() >= (MAX_HISTORY) && (_nCurIndex+1) >= (MAX_HISTORY)) { + WINFO("> max count"); + return; + } + + /* delete item */ + deleteControl(); + createControl(_parent); + + if (HistoryCount <= 1) { + WINFO("1 dots not create"); + return; + } + + /* add item */ + _nCurIndex = HistoryCount-1; + _nSelectedIndex = _nCurIndex; + WINFO("add index %d", _nCurIndex); + int nStartIndex = 0; + bool bUseOdd = true; + if (HistoryCount % 2 == 0) { + nStartIndex = INDEX_ITEM_EVEN_POS_CENTER - (HistoryCount)/2; + bUseOdd = false; + } else { + nStartIndex = INDEX_ITEM_POS_CENTER - (HistoryCount)/2; + } + WINFO("SET start style %d", nStartIndex); + for (int i =0; i < HistoryCount; i++) { + item = elm_index_item_append(_oIndex, NULL, NULL, (void *) i); + if (bUseOdd) { + elm_object_item_style_set(item, _itemOddStyleList[nStartIndex++].c_str()); + } else { + elm_object_item_style_set(item, _itemEvenStyleList[nStartIndex++].c_str()); + } + + _itemList.push_back(item); + } + + elm_index_level_go(_oIndex, 0); + elm_index_item_selected_set(item, EINA_TRUE); +} + +void CDrHistoryControl::redoItem() +{ +// WINFO("redo item %d",_nCurIndex); + Elm_Object_Item* item = nullptr; + + if ((_nCurIndex + 1) >= _itemList.size()) { + WERROR("%d+1 >= count", _nCurIndex); + return; + } else { + _nCurIndex++; + _nSelectedIndex = _nCurIndex; + item = _itemList[_nCurIndex]; + } + + elm_index_item_selected_set(item, EINA_TRUE); +} + +void CDrHistoryControl::undoItem() +{ +// WINFO("undo item %d",_nCurIndex); + Elm_Object_Item* item = nullptr; + if (_nCurIndex -1 < 0) { + WERROR("%d-1 < 0", _nCurIndex); + return; + } + item = _itemList[_nCurIndex-1]; + _nSelectedIndex = _nCurIndex -1; + //elm_index_level_go(_oIndex, 0); + elm_index_item_selected_set(item, EINA_TRUE); + _nCurIndex--; +} + diff --git a/src/controls/CDrHistoryControl.h b/src/controls/CDrHistoryControl.h new file mode 100755 index 0000000..efdc913 --- /dev/null +++ b/src/controls/CDrHistoryControl.h @@ -0,0 +1,47 @@ +#ifndef _CDR_HISTORY_CONTROL_H_ +#define _CDR_HISTORY_CONTROL_H_ + +//#include "sphysics_pba.h" +#include +#include +#include +#include +//#include +#include +#include +#include +#include +#include "CDrEventListener.h" +#ifdef REDO_UNDO +#include "History.h" +#endif + + +class CDrHistoryControl { +public: + CDrHistoryControl(); + virtual ~CDrHistoryControl(); + + void createControl(Evas_Object * parent); + void deleteControl(); + + void redoItem(); + void undoItem(); + void addItem(int HistoryCount); + void deleteItem(int HistoryCount); +private: + CDrHistoryControl(const CDrHistoryControl&) = delete; + const CDrHistoryControl& operator = (const CDrHistoryControl&) = delete; + +private: + Evas_Object *_oIndex; + Evas_Object *_parent; + std::deque _itemList; + std::deque _itemOddStyleList; + std::deque _itemEvenStyleList; + int _nStartIndexPos; + int _nCurIndex; + int _nSelectedIndex; +}; +#endif /* _DRAWING_VIEW_H_ end */ + diff --git a/src/controls/CDrTutorialView.cpp b/src/controls/CDrTutorialView.cpp new file mode 100755 index 0000000..a935e33 --- /dev/null +++ b/src/controls/CDrTutorialView.cpp @@ -0,0 +1,107 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "CDrAppData.h" +#include "CDrTutorialView.h" +#include "DrDefine.h" +#include "CDrEventManager.h" + + +CDrTutorialView::CDrTutorialView() +: _layout(nullptr), +_cancelButton(nullptr) +{ +} + +CDrTutorialView::~CDrTutorialView() +{ +} + + +Evas_Object * CDrTutorialView::onCreateView(Evas_Object * parent, void *viewParam) +{ + WENTER(); + + _layout = elm_layout_add(parent); + + char* _path = app_get_resource_path(); + std::string path(_path); + path += EDJ_FILE; + + elm_layout_file_set(_layout, path.c_str(), DRAWING_TUTORIAL_LAYOUT_GROUP_NAME); + evas_object_size_hint_weight_set(_layout, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_size_hint_align_set(_layout, EVAS_HINT_FILL, EVAS_HINT_FILL); + evas_object_resize(_layout, 360, 360); + evas_object_show(_layout); + + elm_object_domain_translatable_part_text_set(_layout, "elm.text", LOCALE_DOMAIN, DRAWING_TUTORIAL_POPUP_CONTENTS_1); + elm_object_domain_translatable_part_text_set(_layout, "elm.text.title", LOCALE_DOMAIN, DRAWING_TUTORIAL_POPUP_TITLE); + + _cancelButton = elm_button_add(_layout); + elm_object_style_set(_cancelButton , "focus"); + + elm_object_part_content_set(_layout, "actionbtn1", _cancelButton); + + evas_object_smart_callback_add(_cancelButton, "clicked", _onCancelBtnClicked, this); + free(_path); + + WLEAVE(); + return _layout; +} + +void CDrTutorialView::onCreated() +{ +} + +void CDrTutorialView::onDestroy() +{ +} + +void CDrTutorialView::onEvent(const CDrEvent & event) +{ +} + +void CDrTutorialView::setOnCancelResult(std::function < void() > handlerFunc) +{ + _cancelResultHandler = handlerFunc; +} + +void CDrTutorialView::_onCancelBtnClicked(void *data, Evas_Object *obj, void *event_info) +{ + CDrTutorialView * pThis = (CDrTutorialView*)data; + if (pThis->_cancelResultHandler) { + pThis->_cancelResultHandler(); + } +} + +void CDrTutorialView::showRedoGuide() +{ + elm_object_signal_emit(_layout, "elm,image,ccw,hide", "*"); + elm_object_signal_emit(_layout, "elm,image,cw,show", "*"); + + elm_object_domain_translatable_part_text_set(_layout, "elm.text", LOCALE_DOMAIN, DRAWING_TUTORIAL_POPUP_CONTENTS_2); + elm_object_domain_translatable_part_text_set(_layout, "elm.text.title", LOCALE_DOMAIN, ""); + elm_object_part_content_unset(_layout, "actionbtn1"); + if (_cancelButton != nullptr) { + evas_object_del(_cancelButton); + _cancelButton = nullptr; + } + elm_object_signal_emit(_layout, "elm,image,btn,hide", "*"); +} +void CDrTutorialView::showUndoGuide() +{ + elm_object_signal_emit(_layout, "elm,image,ccw,show", "*"); + elm_object_signal_emit(_layout, "elm,image,cw,hide", "*"); + elm_object_domain_translatable_part_text_set(_layout, "elm.text", LOCALE_DOMAIN, DRAWING_TUTORIAL_POPUP_CONTENTS_1); + elm_object_domain_translatable_part_text_set(_layout, "elm.text.title", LOCALE_DOMAIN, DRAWING_TUTORIAL_POPUP_TITLE); +} + diff --git a/src/controls/CDrTutorialView.h b/src/controls/CDrTutorialView.h new file mode 100755 index 0000000..f9d1cd5 --- /dev/null +++ b/src/controls/CDrTutorialView.h @@ -0,0 +1,49 @@ +#ifndef _CDR_TUTORIAL_VIEW_H_ +#define _CDR_TUTORIAL_VIEW_H_ + +//#include "sphysics_pba.h" +#include +#include +#include +#include +//#include +#include +#include +#include +#include "Drawing.h" +#include "WViewController.h" +#include "CDrEventListener.h" +#include "CDrControl.h" +#include "CDrHistoryControl.h" +#include "WUiTimer.h" + +#ifdef REDO_UNDO +#include "History.h" +#endif +using namespace app_assist; + + +class CDrTutorialView: public CDrControl { +public: + CDrTutorialView(); + + void onEvent(const CDrEvent & event); + + virtual Evas_Object * onCreateView(Evas_Object * parent, void *viewParam); + virtual void onDestroy(); + virtual void onCreated(); + void setOnCancelResult(std::function < void() > handlerFunc); + void showRedoGuide(); + void showUndoGuide(); + +protected: + static void _onCancelBtnClicked(void *data, Evas_Object *obj, void *event_info); + virtual ~CDrTutorialView(); + +private: + Evas_Object *_layout; + Evas_Object* _cancelButton; + std::function < void() > _cancelResultHandler; +}; +#endif /* _DRAWING_VIEW_H_ end */ + diff --git a/src/controls/Drawing.cpp b/src/controls/Drawing.cpp new file mode 100755 index 0000000..99c5aaa --- /dev/null +++ b/src/controls/Drawing.cpp @@ -0,0 +1,1324 @@ +#include "Drawing.h" +#include "CDrDrawingView.h" +#include "CDrAppData.h" +#include "WUiTimer.h" + + +#define POINT_SKIP_OFFSET 4 +#define MAX_ZOOM_FACTOR (2) +#define MAX_ALPHA_ANIMATION_TIMER_COUNT 5 //update animation is 1/60, request alpha animation timer is 1/10,so +#define STROKE_WIDTH_DRAWING_CHANGES_MIN 6 + +using namespace std; + +const double RESAMPLE_MAX_DELAY = 20; + + + +int Drawing::_mTouchMode = 0; + +Drawing::Drawing() + :_pDrawingObj(NULL) +{ + _deleteSaveTimerCb = nullptr; + _colorMenuStateCb = nullptr; + _saveStateCb = nullptr; + setMaxHistoryCb = nullptr; + _addSaveTimerCb = nullptr; + _showPanelCb = nullptr; +#ifdef REDO_UNDO + _saveBufferCb = nullptr; + checkFirstIndexCb = nullptr; + pAnimationData = nullptr; + _getBufferCb = nullptr; +#endif +} + +Drawing::~Drawing() +{ + if (pAnimationData != nullptr) { + free(pAnimationData); + pAnimationData = nullptr; + } +} + +#ifdef ENABLE_ZOOM +void Drawing::_Draw(void *data, int fx, int fy, int fw, int fh) +{ + Drawing *pThis = (Drawing*)data; + if (pThis == nullptr) { + return; + } + + Evas_Object *select = static_cast(pThis->_pDrawingObj); + evas_object_resize(pThis->_pDrawingObj, fw, fh); + evas_object_move(pThis->_pDrawingObj, fx, fy); +} + +Eina_Bool Drawing::_DoZoom(void *data, double pos) +{ + int x, y, w, h; + int ix, iy; // New center + double zoom; + Drawing *pThis = (Drawing*)data; + if (pThis == nullptr) { + return EINA_TRUE; + } + + Evas_Object *select = static_cast(pThis->_pDrawingObj); + struct Smart_Data *sd = (struct Smart_Data *) evas_object_smart_data_get(select); + + evas_object_geometry_get(sd->img, &x, &y, &w, &h); + + ix = sd->xClick - x; + iy = sd->yClick - y; + double frame = pos; + frame = ecore_animator_pos_map(pos, ECORE_POS_MAP_ACCELERATE, 0, 0); + int new_ix, new_iy, rw, rh; // Resized + + if (sd->isAutofit) + zoom = 1 + frame; + else + zoom = 2 - frame; + rw = sd->bufW * zoom; + rh = sd->bufH * zoom; + + if(w == 0 || h == 0) return EINA_TRUE; + + new_ix = (ix * rw) / (double)w; // Moved + new_iy = (iy * rh) / (double)h; + + int fx, fy, fw, fh; // Final position + + fx = sd->xClick - new_ix; + fy = sd->yClick - new_iy; + fw = rw; + fh = rh; + + if (sd->cRect.w < fw) + { + if (fx > sd->cRect.x) + { + fx = sd->cRect.x; + } + + if (fw + fx < sd->cRect.x + sd->cRect.w) // Reach to right side + { + fx = sd->cRect.x + sd->cRect.w - fw; + } + } else { + fx = sd->cRect.x + ((sd->cRect.w - fw) / 2); + } + + if (sd->cRect.h < fh) + { + if (fy > sd->cRect.y) // Reach to Top side + { + fy = sd->cRect.y; + } + + if( fy + fh < sd->cRect.y + sd->cRect.h) // Reach to Bottom side + { + fy = sd->cRect.y + sd->cRect.h - fh; + } + } else { + fy = sd->cRect.y + ((sd->cRect.h - fh) / 2); + } + _Draw(data, fx, fy, fw, fh); + return EINA_TRUE; +} + +double Drawing::_getAutoFitZoom(struct Smart_Data *sd) +{ + int cw, ch; // Swallowed Rect + WINFO(""); + cw = sd->cRect.w; + ch = sd->cRect.h; + + int width, height; + + width = sd->bufW; + height = sd->bufH; + + int ph, pw; + + ph = (height * cw) / width; + + if (ph > ch) + { + pw = (width * ch) / height; + ph = ch; + } else { + pw = cw; + } + double zx, zy; + + zx = (double)pw / (double)width; + zy = (double)ph / (double)height; + + return zx > zy ? zx : zy; +} + +Evas_Event_Flags Drawing::_onDblClickStart(void *data , void *event_info) +{ + Elm_Gesture_Taps_Info *p = (Elm_Gesture_Taps_Info *) event_info; + Drawing *pThis = (Drawing*)data; + if (pThis == nullptr) { + return EVAS_EVENT_FLAG_NONE; + } + + Evas_Object *select = static_cast(pThis->_pDrawingObj); + struct Smart_Data *sd = (struct Smart_Data *) evas_object_smart_data_get(select); + + sd->isZoomed = EINA_TRUE; + + if (p->n != 1) return EVAS_EVENT_FLAG_NONE; + + return EVAS_EVENT_FLAG_NONE; +} + +Evas_Event_Flags Drawing::_onDblClickEnd(void *data , void *event_info) +{ + Elm_Gesture_Taps_Info *p = (Elm_Gesture_Taps_Info *) event_info; + Drawing *pThis = (Drawing*)data; + if (pThis == nullptr) { + return EVAS_EVENT_FLAG_NONE; + } + + Evas_Object *select = static_cast(pThis->_pDrawingObj); + struct Smart_Data *sd = (struct Smart_Data *) evas_object_smart_data_get(select); + double max = _getAutoFitZoom(sd) * MAX_ZOOM_FACTOR; + sd->xClick = p->x; + sd->yClick = p->y; + if (sd->Zoom > _getAutoFitZoom(sd)) { + sd->Zoom = _getAutoFitZoom(sd); + sd->isAutofit = false; + ecore_animator_timeline_add(0.15, _DoZoom, data); + } else { + sd->Zoom = max; + sd->isAutofit = true; + ecore_animator_timeline_add(0.15, _DoZoom, data); + } + + sd->m_selected.Clear(); + sd->isZoomed = EINA_FALSE; + + return EVAS_EVENT_FLAG_NONE; +} + +Evas_Event_Flags Drawing::_onDblClickAbort(void *data , void *event_info) +{ + Elm_Gesture_Taps_Info *p = (Elm_Gesture_Taps_Info *) event_info; + Drawing *pThis = (Drawing*)data; + if (pThis == nullptr) { + return EVAS_EVENT_FLAG_NONE; + } + + Evas_Object *select = static_cast(pThis->_pDrawingObj); + struct Smart_Data *sd = (struct Smart_Data *) evas_object_smart_data_get(select); + + sd->isZoomed = EINA_FALSE; + int x, y, w, h; + evas_object_geometry_get(sd->img, &x, &y, &w, &h); + //To prevent draw double tap point,only draw point when normal drawing. + std::vector> pt = sd->m_selected.getOldPointsList(); + sd->m_cairo.Draw(sd->m_selected, sd->m_selected.GetHistoryPoints(pt);, + (double)sd->bufW / (double)w, + (double)sd->bufH / (double)h, + w, h); + + if (pThis->_saveBufferCb) + { + std::vector> pt = sd->m_selected.GetOriginalPoints(); + double strokeWidth = sd->m_cairo.getStrokeWidth(); + //Save image info when draw point.If draw a line,it will be update when mouse up again. + pThis->_saveBufferCb(pt, sd->m_selected.GetOriginalstrokeList(), &(pThis->_cCurrentColor), strokeWidth, true); + } + if (p->n != 1 ) return EVAS_EVENT_FLAG_NONE; + return EVAS_EVENT_FLAG_NONE; +} +#endif + +Evas_Event_Flags Drawing::_onTapEnd(void *data , void *event_info) +{ + if (data == nullptr || event_info == nullptr) { + return EVAS_EVENT_FLAG_NONE; + } + + Elm_Gesture_Taps_Info *p = (Elm_Gesture_Taps_Info *) event_info; + if (p->n != 1) { + return EVAS_EVENT_FLAG_NONE; + } + Drawing *pThis = (Drawing*)data; + if (pThis->_showPanelCb) { + pThis->_showPanelCb(); + } + return EVAS_EVENT_FLAG_NONE; +} + +#ifdef ENABLE_DRAGING +void Drawing::_onMultiDown(void *data, Evas *e, Evas_Object *evas_obj, void *event_info) +{ + Drawing *pThis = (Drawing*)data; + if (pThis == nullptr) { + return; + } + + Evas_Object *select = static_cast(pThis->_pDrawingObj); + struct Smart_Data *sd = (struct Smart_Data *) evas_object_smart_data_get(select); + sd->mutilDown = true; + _Evas_Event_Multi_Down *ev = (_Evas_Event_Multi_Down *) event_info; + + sd->xMutilPrev = ev->output.x; + sd->yMutilPrev = ev->output.y; + WLEAVE(); +} +#endif + +void Drawing::_onMultiMove(void *data, Evas *e, Evas_Object *evas_obj, void *event_info) +{ + int dx, dy; + Drawing *pThis = (Drawing*)data; + if (pThis == nullptr) { + return; + } + + Evas_Object *select = static_cast(pThis->_pDrawingObj); + struct Smart_Data *sd = (struct Smart_Data *) evas_object_smart_data_get(select); + sd->bMultiMove = true; + +#ifdef ENABLE_DRAGING + if (!sd->mutilDown) + { + return; + } + _Evas_Event_Multi_Move *ev = (_Evas_Event_Multi_Move *) event_info; + dx = ev->cur.output.x - sd->xMutilPrev; + dy = ev->cur.output.y - sd->yMutilPrev; + sd->xMutilPrev = ev->cur.output.x; + sd->yMutilPrev = ev->cur.output.y; + if (sd->isAutofit) + { + sd->m_cairo.dragImage(dx, dy); + } + WLEAVE(); +#endif +} + +void Drawing::_onMultiUp(void *data, Evas *e, Evas_Object *evas_obj, void *event_info) +{ + Drawing *pThis = (Drawing*)data; + if (pThis == nullptr) { + return; + } + Evas_Object *select = static_cast(pThis->_pDrawingObj); + struct Smart_Data *sd = (struct Smart_Data *) evas_object_smart_data_get(select); + sd->bMultiMove = false; +#ifdef ENABLE_DRAGING + sd->mutilDown = false; + WLEAVE(); +#endif +} + + +void Drawing::_onMouseDown(void *data, Evas *e, Evas_Object *evas_obj, void *event_info) +{ + WINFO("_onMouseDown"); + Drawing *pThis = (Drawing*)data; + if (pThis == nullptr) { + return; + } + + Drawing::_mTouchMode = 2; + if (pThis->_deleteSaveTimerCb) { + pThis->_deleteSaveTimerCb(); + } + if (pThis->_colorMenuStateCb) { + bool color_menu = pThis->_colorMenuStateCb(); + if(color_menu == true) + { + WINFO("color menu show, return"); + return; + } + } + + Evas_Object *select = static_cast(pThis->_pDrawingObj); + + struct Smart_Data *sd = (struct Smart_Data *) evas_object_smart_data_get(select); + + Evas_Event_Mouse_Down *ev = (Evas_Event_Mouse_Down *) event_info; + if (ev->button > 1) { + WERROR("> 1"); + return; + } + + int x, y; + x = ev->output.x; + y = ev->output.y; + + int img_x, img_y; + int img_w, img_h; + + evas_object_geometry_get(sd->img, &img_x, &img_y, &img_w, &img_h); + + if(!((x > img_x) && (x < img_x + img_w) && + (y > img_y) && (y < img_y + img_h))) { + WINFO("PRESSED OUTSIDE IMAGE REGION"); + return; + } + sd->mouseDownX = abs(x - img_x); + sd->mouseDownY = abs(y - img_y); + //WINFO("mouse down %d %d",sd->mouseDownX,sd->mouseDownY); + if (!sd->m_selected.lastBufferIsCompleted()) { + sd->m_cairo.eraseDraw(sd->m_selected, (double)sd->bufW / (double)sd->oRect.w, + (double)sd->bufH/ (double)sd->oRect.h, + sd->oRect.w, sd->oRect.h, MAX_POINTS_LIST_COUNT-1); + } + sd->m_selected.increaseListIndex(); + + sd->bMouseDown = true; + sd->bFirstMove = true; + sd->latestTimestamp = sd->prevTimestamp = ev->timestamp; + sd->m_cairo.SetDrawingProperty(&pThis->_cCurrentColor); +#ifdef REDO_UNDO + sd->isMoved = false; +#endif + WLEAVE(); +} + +void Drawing::_onMouseMove(void *data, Evas *e, Evas_Object *evas_obj, void *event_info) +{ + //WENTER(); + Drawing *pThis = (Drawing*)data; + bool bChange = false; + if (pThis == nullptr) { + return; + } + + if (Drawing::_mTouchMode != 2) + { + return; + } + Evas_Object *select = static_cast(pThis->_pDrawingObj); + struct Smart_Data *sd = (struct Smart_Data *) evas_object_smart_data_get(select); + +#ifdef ENABLE_DRAGING + if (sd->mutilDown) + return; +#endif +// Move event is coming once before down event. we can check useless move event by using m_grasp. + Evas_Event_Mouse_Move *ev = (Evas_Event_Mouse_Move *) event_info; +// WINFO("Mouse move, dx=%d dy=%d", ev->cur.output.x, ev->cur.output.y); + if (ev->buttons > 1) { + WERROR("> 1"); + return; + } + + if (!sd->bMouseDown) + { + // Skip move event before down + return; + } + if (sd->bMultiMove) { + WINFO("multi move, stop"); + return; + } + if (sd->m_cairo.getNormalDrawingStatus()) { + WERROR("doing rotary"); + return; + } + + if (sd->bFirstMove) + { + //WINFO("x, y: %d %d",sd->mouseDownX,sd->mouseDownY); + sd->m_selected.AddPoint(CPoint(sd->mouseDownX, sd->mouseDownY)); + sd->bFirstMove = false; + if (pThis->_saveStateCb) { + pThis->_saveStateCb(true); + } + if (pThis->checkFirstIndexCb) { + if ((pThis->checkFirstIndexCb())) { + sd->m_cairo.clearImage(); + //sd->m_cairo.clearBuffer(); + } + sd->isUndoRedoAnimator = false; + if (pThis->pAnimationData->nBgPatternAlpha != 0) { + evas_object_color_set(pThis->pAnimationData->bgPattern, 0, 0, 0, 0); + pThis->pAnimationData->nBgPatternAlpha = 0; + } + } + bChange = true; + } + + sd->xPrev = ev->prev.output.x; + sd->yPrev = ev->prev.output.y; + + sd->xLatest = ev->cur.output.x; + sd->yLatest = ev->cur.output.y; + + sd->prevTimestamp = sd->latestTimestamp; + sd->latestTimestamp = ev->timestamp; + + // + + bool bret = pThis->_addDrawPoint(); + if (bChange || bret) { + sd->is_changed = true; +#ifdef REDO_UNDO + sd->isMoved = true; +#endif + } + //WLEAVE(); +} + +void Drawing::_onMouseUp(void *data, Evas *e, Evas_Object *evas_obj, void *event_info) +{ + WINFO("_onMouseUp"); + int index = 0; + Drawing *pThis = (Drawing*)data; + if (pThis == nullptr) { + return; + } + + if (Drawing::_mTouchMode != 2) + { + return; + } + Drawing::_mTouchMode = 0; + Evas_Object *select = static_cast(pThis->_pDrawingObj); + + struct Smart_Data *sd = (struct Smart_Data *) evas_object_smart_data_get(select); + + sd->bMouseDown = false; + sd->is_changed = false; +#ifdef REDO_UNDO + +#ifdef ENABLE_ZOOM + if (!sd->isZoomed) +#endif + { + if (sd->isMoved && (sd->m_selected.GetCount() > 0)) + { + WINFO("drawed"); + if (pThis->_saveBufferCb) + { + if (pThis->checkFirstIndexCb) { + if ((pThis->checkFirstIndexCb())) { + sd->m_cairo.clearBuffer(); + if (pThis->setMaxHistoryCb) { + pThis->setMaxHistoryCb(false); + } + } + } + + std::vector> pt = sd->m_selected.GetOriginalPoints(); + double strokeWidth = sd->m_cairo.getStrokeWidth(); +#ifdef ENABLE_ZOOM + pThis->_saveBufferCb(pt, sd->m_selected.GetOriginalstrokeList(), &(pThis->_cCurrentColor), strokeWidth, false); +#else + pThis->_saveBufferCb(pt, sd->m_selected.GetOriginalstrokeList(), &(pThis->_cCurrentColor), strokeWidth, true); +#endif + } + } + sd->isMoved = false; + } +#endif + + if (sd->bFirstMove) { + sd->bFirstMove = false; + +#ifdef REDO_UNDO + if (pThis->checkFirstIndexCb) { + if (!(pThis->checkFirstIndexCb())) { + if (pThis->_saveStateCb) { + pThis->_saveStateCb(true); + } + } + } +#else + if (pThis->_saveStateCb) { + pThis->_saveStateCb(true); + } +#endif + } + + if (pThis->_addSaveTimerCb) { + pThis->_addSaveTimerCb(); + } + sd->m_selected.addEndPoint(); + if (sd->m_selected.GetCount() < 2) { + WINFO("refresh only 1 pt"); + evas_object_smart_changed(sd->obj); + } +} + + +bool Drawing::_addDrawPoint() +{ + struct Smart_Data *sd = (struct Smart_Data *) evas_object_smart_data_get(_pDrawingObj); + static int xprev = 0, yprev = 0; + int resample_x = 0; + int resample_y = 0; + int img_x, img_y; + int img_w, img_h; + int x, y; + double tx, ty, speedStrokeWidth; + int previousStrokeWidth = 0; + + if (xprev == 0 && yprev == 0) { + xprev = sd->xPrev; + yprev = sd->yPrev; + } + resample_x = sd->xLatest; + resample_y = sd->yLatest; + + evas_object_geometry_get(sd->img, &img_x, &img_y, &img_w, &img_h); + + + if (sd->m_selected.GetCount() <= 0) { + //WINFO("GetCount <= 0"); + return false; + } else { + xprev = sd->m_selected[sd->m_selected.GetCount()-1].x + img_x; + yprev = sd->m_selected[sd->m_selected.GetCount()-1].y + img_y; + } + if ( sqrt((resample_x - xprev)*(resample_x - xprev) +(resample_y - yprev)*(resample_y - yprev)) < 12) { + WINFO("SKIP Offset %d", 12); + return false; + } + + if(!((resample_x > img_x) && (resample_x < img_x + img_w) && + (resample_y > img_y) && (resample_y < img_y + img_h))) { + WINFO("PRESSED OUTSIDE IMAGE REGION"); + return false; + } + + x = abs(resample_x - img_x); + y = abs(resample_y - img_y); + + tx = sd->xLatest-sd->xPrev; + ty = sd->yLatest-sd->yPrev; + speedStrokeWidth = (int)(6 * asin(-(sqrt(tx*tx + ty*ty))/23+1)+8); + + previousStrokeWidth = sd->m_selected.getLastStrokeWidth(); + if (previousStrokeWidth != -1) { + if (speedStrokeWidth > 1.20 * previousStrokeWidth) { + speedStrokeWidth = 1.20 * previousStrokeWidth; + } + + if (speedStrokeWidth < previousStrokeWidth / 1.20) { + speedStrokeWidth = previousStrokeWidth / 1.20; + } + } + + if (speedStrokeWidth > MMS_MODE_STROKE_LINE_WIDTH) { + speedStrokeWidth = MMS_MODE_STROKE_LINE_WIDTH; + } + + if (speedStrokeWidth < STROKE_WIDTH_DRAWING_CHANGES_MIN) { + speedStrokeWidth = STROKE_WIDTH_DRAWING_CHANGES_MIN; + } + sd->m_selected.AddPoint(CPoint(x, y), (int) (speedStrokeWidth+0.5)); + WINFO("add point"); + return true; +} + +bool Drawing::isMouseMoving() +{ + /* bug: mouse moving, and then run rotary event, and then run mouse up event, + error: current drawed point are not saved in history + solution: terminate current rotary event + */ + struct Smart_Data *sd = (struct Smart_Data *) evas_object_smart_data_get(_pDrawingObj); + if (sd->bMouseDown && sd->isMoved) { + return true; + } + return false; +} + +void Drawing::_smartAdd(Evas_Object *obj) +{ + WENTER(); + + struct Smart_Data *sd = new struct Smart_Data; + sd->target = nullptr; + sd->bShow = EINA_FALSE; + + evas_object_smart_data_set(obj, sd); + + sd->obj = obj; + WLEAVE(); +} + +void Drawing::_smartDel(Evas_Object *obj) +{ + WENTER(); + WINFO(" _smartDel called"); + struct Smart_Data *sd = (struct Smart_Data *) evas_object_smart_data_get(obj); + + evas_object_del(sd->m_event); + ecore_animator_del(sd->anim); + + sd->m_selected.Clear(); + sd->m_cairo.DeleteImage(); + + delete sd; + WLEAVE(); +} + +void Drawing::_smartMove(Evas_Object *obj, Evas_Coord x, Evas_Coord y) +{ + struct Smart_Data *sd = (struct Smart_Data *) evas_object_smart_data_get(obj); + + /* Below line is commetned to enable selection of lasso crop region for the first time, if the code returns from here so called are not called */ + + /* if ((sd->cRect.x == x) && (sd->cRect.y == y)) return; */ + + WINFO("_smartMove Image Move to XY(%d,%d)", x, y); + sd->oRect.x = x; + sd->oRect.y = y; + + evas_object_move(sd->m_event, x, y); + evas_object_move(sd->img, x, y); + evas_object_smart_changed(sd->obj); +} + +void Drawing::_smartResize(Evas_Object *obj, Evas_Coord w, Evas_Coord h) +{ + struct Smart_Data *sd = (struct Smart_Data *) evas_object_smart_data_get(obj); + + /* Below line is commetned to enable selection of lasso crop region for the first time, if the code returns from here so called are not called */ + + /* if ((sd->cRect.w == w) && (sd->cRect.h == h)) return; */ + + WINFO("_smartResize Image Resize to WH(%d,%d)", w, h); + + sd->oRect.w = w; + sd->oRect.h = h; + evas_object_resize(sd->m_event, w, h); + evas_object_resize(sd->img, w, h); + evas_object_smart_changed(sd->obj); +} + +void Drawing::_smartShow(Evas_Object *obj) +{ +// WENTER(); + + struct Smart_Data *sd = (struct Smart_Data *) evas_object_smart_data_get(obj); + + if ( sd->bShow == EINA_TRUE) return; + + sd->bShow = EINA_TRUE; + + evas_object_show(sd->m_event); +// WLEAVE(); +} + +void Drawing::_smartHide(Evas_Object *obj) +{ + WENTER(); + + struct Smart_Data *sd = (struct Smart_Data *) evas_object_smart_data_get(obj); + + if ( sd->bShow == EINA_FALSE) return; + + sd->bShow = EINA_FALSE; + + evas_object_hide(sd->m_event); + WLEAVE(); +} + +void Drawing::_smartCalculate(Evas_Object *obj) +{ + struct Smart_Data *sd = (struct Smart_Data *) evas_object_smart_data_get(obj); + int x, y, w, h; + if (sd->target == NULL ) return; + evas_object_geometry_get(sd->img, &x, &y, &w, &h); + if ( (sd->oRect.w != w) || (sd->oRect.h != h) ) { + WINFO(" w,h <%d %d> oRect w ,h <%d %d>", w, h, sd->oRect.w, sd->oRect.h); + WINFO(" x,y <%d %d> oRect x,y <%d %d>", x, y, sd->oRect.x, sd->oRect.y); + for ( int i = 0; i < sd->m_selected.GetCount(); i++) { + CPoint &pt = sd->m_selected[i]; + pt.x = ((pt.x * w) / sd->oRect.w) ; + pt.y = ((pt.y * h) / sd->oRect.h) ; + sd->m_selected[i] = pt; + } + + sd->oRect.x = x; + sd->oRect.y = y; + sd->oRect.w = w; + sd->oRect.h = h; + } + sd->m_cairo.Draw(sd->m_selected, + (double)sd->bufW / (double)w, + (double)sd->bufH/ (double)h, + w, h); +} + +Evas_Smart *Drawing::_smartInit(void) +{ + WENTER(); + static Evas_Smart *smart = NULL; + if (smart) + return (smart); + + const char* name = eina_stringshare_add("ie-selectlasso"); + static Evas_Smart_Class sc = + { + NULL, + EVAS_SMART_CLASS_VERSION, + _smartAdd, + _smartDel, + _smartMove, + _smartResize, + _smartShow, + _smartHide, + NULL, + NULL, + NULL, + _smartCalculate, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL + }; //Evas_smart_Class + sc.name = name; + smart = evas_smart_class_new(&sc); + + WLEAVE(); + return smart; +} + +Eina_Bool Drawing::_onAnimatorUpdate(void *data) +{ + bool isFirstPoint = false; + bool bChange = false; + Evas_Object *select = nullptr; + struct Smart_Data *sd = nullptr; + static int xprev = 0, yprev = 0; + int resample_x = 0; + int resample_y = 0; + int img_x, img_y; + int img_w, img_h; + int x, y; + double tx, ty, speedStrokeWidth; + int previousStrokeWidth = 0; + + if(nullptr == data) + { + return EINA_TRUE; + } + Drawing *pThis = (Drawing*)data; + sd = (struct Smart_Data *) evas_object_smart_data_get(pThis->_pDrawingObj); + + if(nullptr == sd) + { + return EINA_TRUE; + } + sd->nAlphaTimer++; + + if (sd->isUndoRedoAnimator) { + pThis->pAnimationData->imgUpdatePos = (double)pThis->pAnimationData->imgUpdateCount /(MAX_ANIMATION_TIME *60.0); + if (pThis->pAnimationData->imgUpdatePos > 1.0) { + pThis->pAnimationData->imgUpdatePos = 1.0; + } else if (pThis->pAnimationData->imgUpdatePos < 0) { + pThis->pAnimationData->imgUpdatePos = 0.0; + } + sd->m_cairo.animationUpdateImage(pThis->pAnimationData, pThis->pAnimationData->imgUpdatePos); + pThis->pAnimationData->imgUpdateCount++; + if (pThis->pAnimationData->imgUpdateCount > (pThis->pAnimationData->animationTime *60.0)) { + sd->isUndoRedoAnimator = false; + } + return EINA_TRUE; + } + + /* check moved point */ + if (!sd->is_changed) + { + xprev = 0; + yprev = 0; + goto end; + } else { + bChange = true; + } + //WENTER(); + +#ifdef ENABLE_ZOOM + if (sd->isZoomed) + bChange = false; +#endif + +end: +#ifdef SKETCH_DRAW_ENABLE_DRAWING_EFFECT + /* animation for changing stroke color */ + if(sd->nAlphaTimer >= MAX_ALPHA_ANIMATION_TIMER_COUNT) { + int nIndex1 = sd->m_selected.GetCount(); + if (!sd->m_cairo.getNormalDrawingStatus()) { + if (sd->m_selected.updateAlphaList()) { + bChange = true; + } + } + sd->nAlphaTimer = 0; + } +#endif + if (bChange) { + // Draw again + evas_object_smart_changed(sd->obj); + } + return EINA_TRUE; +} + +Evas_Object *Drawing::drawingAdd(Evas_Object *parent) +{ + WENTER(); + Evas_Smart *smart_obj = _smartInit(); + Evas_Object *obj; + + obj = evas_object_smart_add(evas_object_evas_get(parent), smart_obj); //create smart object. + evas_object_name_set(obj, "SelectLasso"); + _pDrawingObj = obj; + + WLEAVE(); + return obj; +} + +void Drawing::drawingAttach(Evas_Object *target) +{ + WENTER(); + + struct Smart_Data *sd = (struct Smart_Data *) evas_object_smart_data_get(_pDrawingObj); + + if ( target == NULL ) + { + WINFO("Target is NULL"); + return ; + } + if ( sd->target != target) + sd->target = target; + +// Moved from smart add in here to improve the performance + WINFO("Creating ie_selectlasso"); + + Evas_Coord x, y, w, h; + evas_object_geometry_get(sd->target, &x, &y, &w, &h); + + Evas *evas = evas_object_evas_get(_pDrawingObj); + + // Event receiver. + sd->cRect.x = x; + sd->cRect.y = y; + sd->cRect.w = w; + sd->cRect.h = h; + sd->bufW = w; + sd->bufH = h; +#ifdef ENABLE_ZOOM + sd->isZoomed = EINA_FALSE; + sd->Zoom = _getAutoFitZoom(sd); +#endif + sd->isAutofit = false; + sd->nAlphaTimer = 0; + + sd->maskImg = sd->m_cairo.createMaskImage(evas_object_evas_get(_pDrawingObj), w, h); // Create 360x360 image. + sd->img = sd->m_cairo.CreateImage(evas_object_evas_get(_pDrawingObj), w, h); // Create 360x360 image. + sd->sourceImg = sd->m_cairo.createSource(evas_object_evas_get(_pDrawingObj), w, h); // Create 360x360 image. + sd->m_cairo.createBufferImage(evas_object_evas_get(_pDrawingObj), w, h); // Create 360x360 image. + +#ifdef REDO_UNDO + if (_saveBufferCb) + { + std::vector> pt = sd->m_selected.GetOriginalPoints(); + double strokeWidth = sd->m_cairo.getStrokeWidth(); + _saveBufferCb(pt, sd->m_selected.GetOriginalstrokeList(), &(_cCurrentColor), strokeWidth, true); + } +#endif +#ifdef ENABLE_DRAGING + sd->mutilDown = false; +#endif + WINFO(" target x,y w ,h %d %d %d %d", x, y, w, h); + evas_object_move(sd->img, x, y); + evas_object_resize(sd->img, w, h); + evas_object_show(sd->img); + + evas_object_smart_member_add(sd->img, _pDrawingObj); + + sd->m_event = evas_object_rectangle_add(evas); + evas_object_color_set(sd->m_event, 0, 0, 0, 0); + evas_object_pass_events_set(sd->m_event, EINA_FALSE); + evas_object_show(sd->m_event); + + evas_object_smart_member_add(sd->m_event, _pDrawingObj); + + evas_object_event_callback_add(sd->m_event, EVAS_CALLBACK_MOUSE_DOWN, _onMouseDown, this); + evas_object_event_callback_add(sd->m_event, EVAS_CALLBACK_MOUSE_UP, _onMouseUp, this); + evas_object_event_callback_add(sd->m_event, EVAS_CALLBACK_MOUSE_MOVE, _onMouseMove, this); + +#ifdef ENABLE_DRAGING + evas_object_event_callback_priority_add(sd->m_event, EVAS_CALLBACK_MULTI_DOWN, -100, _onMultiDown, this); +#endif + evas_object_event_callback_add(sd->m_event, EVAS_CALLBACK_MULTI_MOVE, _onMultiMove, this); + evas_object_event_callback_add(sd->m_event, EVAS_CALLBACK_MULTI_UP, _onMultiUp, this); + + sd->gesture = elm_gesture_layer_add(sd->m_event); + elm_gesture_layer_hold_events_set(sd->gesture, EINA_FALSE); + +#ifdef ENABLE_ZOOM + elm_gesture_layer_cb_set(sd->gesture, ELM_GESTURE_N_DOUBLE_TAPS, ELM_GESTURE_STATE_START, _onDblClickStart, this); + elm_gesture_layer_cb_set(sd->gesture, ELM_GESTURE_N_DOUBLE_TAPS, ELM_GESTURE_STATE_END, _onDblClickEnd, this); + elm_gesture_layer_cb_set(sd->gesture, ELM_GESTURE_N_DOUBLE_TAPS, ELM_GESTURE_STATE_ABORT, _onDblClickAbort, this); +#endif + + elm_gesture_layer_cb_set(sd->gesture, ELM_GESTURE_N_TAPS, ELM_GESTURE_STATE_END, _onTapEnd, this); + + if (elm_gesture_layer_attach(sd->gesture, sd->m_event) == EINA_FALSE) { + WERROR("error to attach"); + } + + ecore_animator_frametime_set(1.0/60.0); + sd->anim = ecore_animator_add(_onAnimatorUpdate, this); + pAnimationData = (animationData *)calloc(1, sizeof(animationData)); + if (pAnimationData == nullptr) + { + WINFO("Memory Allocation Failed!!"); + return; + } + pAnimationData->isDrawing = false; + pAnimationData->nBgPatternAlpha = 0; + pAnimationData->drawingAnimator = nullptr; + sd->isUndoRedoAnimator = false; + // Set initial position + sd->oRect.x = x ; + sd->oRect.y = y; + sd->oRect.w = w; + sd->oRect.h = h; + sd->is_changed = false; + sd->bMultiMove = false; + evas_object_smart_changed(sd->obj); + + WLEAVE(); +} + +void Drawing::clearImage() +{ + struct Smart_Data *sd = (struct Smart_Data *) evas_object_smart_data_get(_pDrawingObj); + sd->m_cairo.clearImage(); +} + +void Drawing::drawingColorSet(std::string colorCode, bool isEraser) +{ + WENTER(); + + _cCurrentColor.drawingColorSet(colorCode, isEraser); + struct Smart_Data *sd = (struct Smart_Data *) evas_object_smart_data_get(_pDrawingObj); + + sd->m_cairo.SetDrawingProperty(&_cCurrentColor); + WLEAVE(); +} + +DrawingColor Drawing::getCurrentColor() +{ + return _cCurrentColor; +} + +void Drawing::saveDrawingImage(std::string& filePath) +{ + struct Smart_Data *sd = (struct Smart_Data *) evas_object_smart_data_get(_pDrawingObj); + + sd->m_cairo.SaveDrawingImage(filePath); +} + +void Drawing::addMouseEvent() +{ + struct Smart_Data *sd = (struct Smart_Data *) evas_object_smart_data_get(_pDrawingObj); + + WINFO("Remove mouse event"); + evas_object_event_callback_add(sd->m_event, EVAS_CALLBACK_MOUSE_DOWN, _onMouseDown, this); + evas_object_event_callback_add(sd->m_event, EVAS_CALLBACK_MOUSE_UP, _onMouseUp, this); + evas_object_event_callback_add(sd->m_event, EVAS_CALLBACK_MOUSE_MOVE, _onMouseMove, this); +#ifdef ENABLE_DRAGING + evas_object_event_callback_priority_add(sd->m_event, EVAS_CALLBACK_MULTI_DOWN, -100, _onMultiDown, this); + evas_object_event_callback_add(sd->m_event, EVAS_CALLBACK_MULTI_MOVE, _onMultiMove, this); + evas_object_event_callback_add(sd->m_event, EVAS_CALLBACK_MULTI_UP, _onMultiUp, this); +#endif +} + +void Drawing::delMouseEvent() +{ + struct Smart_Data *sd = (struct Smart_Data *) evas_object_smart_data_get(_pDrawingObj); + + WINFO("Remove mouse event"); + /* Remove Mouse Event Callbacks */ + evas_object_event_callback_del(sd->m_event, EVAS_CALLBACK_MOUSE_DOWN, _onMouseDown); + evas_object_event_callback_del(sd->m_event, EVAS_CALLBACK_MOUSE_UP, _onMouseUp); + evas_object_event_callback_del(sd->m_event, EVAS_CALLBACK_MOUSE_MOVE, _onMouseMove); +#ifdef ENABLE_DRAGING + evas_object_event_callback_del(sd->m_event, EVAS_CALLBACK_MULTI_DOWN, _onMultiDown); + evas_object_event_callback_del(sd->m_event, EVAS_CALLBACK_MULTI_MOVE, _onMultiMove); + evas_object_event_callback_del(sd->m_event, EVAS_CALLBACK_MULTI_UP, _onMultiUp); +#endif +} + +void Drawing::setDeleteSaveTimerCb(std::function < void(void) > handlerFunc) +{ + _deleteSaveTimerCb = handlerFunc; +} + +void Drawing::setColorMenuStateCb(std::function < bool(void) > handlerFunc) +{ + _colorMenuStateCb = handlerFunc; +} + +void Drawing::setSaveStateCb(std::function < void(bool) > handlerFunc) +{ + _saveStateCb = handlerFunc; +} + +void Drawing::setSetMaxHistoryCb(std::function < void(bool) > handlerFunc) +{ + setMaxHistoryCb = handlerFunc; +} + + +void Drawing::setAddSaveTimerCb(std::function < void(void) > handlerFunc) +{ + _addSaveTimerCb = handlerFunc; +} + +void Drawing::setStrokeWidth(double dWidth) +{ + struct Smart_Data *sd = (struct Smart_Data *) evas_object_smart_data_get(_pDrawingObj); + + sd->m_cairo.setStrokeWidth(dWidth); +} + +void Drawing::setShowPanelCb(std::function < void(void) > handlerFunc) +{ + _showPanelCb = handlerFunc; +} + +void Drawing::setGetBufferCb(std::function < void(int curIndex, std::vector> &buffer, std::vector& strokeList, DrawingColor* pColor, double *width) > handlerFunc) +{ + _getBufferCb = handlerFunc; +} + +#ifdef REDO_UNDO +void Drawing::setCheckFirstIndexCb(std::function < bool(void) > handlerFunc) +{ + checkFirstIndexCb = handlerFunc; +} + +void Drawing::setSaveBufferCb(std::function < void(std::vector> pt1, std::vector* pStrokeList, DrawingColor* pColor, double strokeWidth, bool increaseIndex) > handlerFunc) +{ + _saveBufferCb = handlerFunc; +} + +bool Drawing::getDrawingStatus() +{ + return pAnimationData->isDrawing; +} + +drawMode Drawing::getDrawingMode() +{ + return pAnimationData->mode; +} + +void Drawing::getAnimatorTime(double *time) +{ + *time = pAnimationData->animationTime; +} + +bool Drawing::updateBuffer(std::vector> &pt1, std::vector& strokeList, DrawingColor pColor, double strokeWidth, drawMode mode) +{ + struct Smart_Data *sd = (struct Smart_Data *) evas_object_smart_data_get(_pDrawingObj); + int x, y, w, h; + + std::vector> pt = sd->m_selected.GetHistoryPoints(pt1); + + evas_object_geometry_get(sd->img, &x, &y, &w, &h); + + if (mode == NORMAL_DRAW) { + sd->m_cairo.SetHistoryDrawingProperty(sd->m_cairo._maskCr, pColor, strokeWidth); + pAnimationData->isDrawing = false; + sd->m_cairo.Draw(sd->m_cairo._maskCr, pt, strokeList, + (double)sd->bufW / (double)w, + (double)sd->bufH/ (double)h, + w, h); + } else { + pAnimationData->rw = (double)sd->bufW / (double)w; + pAnimationData->rh = (double)sd->bufH / (double)h; + pAnimationData->w = w; + pAnimationData->h = h; + pAnimationData->cr = sd->m_cairo._cr; + pAnimationData->image = sd->m_cairo._image; + pAnimationData->strokeWidth = sd->m_cairo._strokeWidth; + pAnimationData->pColor = pColor; + pAnimationData->pt = pt; + pAnimationData->strokeList = strokeList; + pAnimationData->mode = mode; + pAnimationData->isDrawing = true; + pAnimationData->sourceCr = sd->m_cairo._sourceCr; + pAnimationData->sourceSurface = sd->m_cairo._sourceSurface; + pAnimationData->maskSurface = sd->m_cairo._maskSurface; + pAnimationData->pCairo = &sd->m_cairo; + + double drawSpeed = DRAW_SPEED; + pAnimationData->animationTime = (double)pt.size() / drawSpeed; + sd->m_cairo.SetHistoryDrawingProperty(sd->m_cairo._sourceCr, pColor, strokeWidth); + if (pt.size() <= DRAW_POINTS) { + pAnimationData->isMaxAnimation = false; + pAnimationData->animationTime += MIN_ANIMATION_TIME; + pAnimationData->drawingAnimator = ecore_animator_timeline_add(pAnimationData->animationTime, sd->m_cairo.animationDraw, (void *)pAnimationData); + } else { + pAnimationData->isMaxAnimation = true; + pAnimationData->animationTime = MAX_ANIMATION_TIME; + pAnimationData->drawingAnimator = ecore_animator_timeline_add(MAX_ANIMATION_TIME, sd->m_cairo.animationDraw, (void *)pAnimationData); + } + } + return true; +} + +#endif + +void Drawing::sourceUpdate(drawMode mode) +{ + struct Smart_Data *sd = (struct Smart_Data *) evas_object_smart_data_get(_pDrawingObj); + sd->m_cairo.sourceUpdate(mode); +} + +void Drawing::maskUpdate(drawMode mode) +{ + struct Smart_Data *sd = (struct Smart_Data *) evas_object_smart_data_get(_pDrawingObj); + sd->m_cairo.maskUpdate(mode); +} + +void Drawing::clearMask() +{ + struct Smart_Data *sd = (struct Smart_Data *) evas_object_smart_data_get(_pDrawingObj); + sd->m_cairo.clearMask(); +} + +void Drawing::clearSource() +{ + struct Smart_Data *sd = (struct Smart_Data *) evas_object_smart_data_get(_pDrawingObj); + sd->m_cairo.clearSource(); +} + +void Drawing::resetIsDrawing() +{ + pAnimationData->isDrawing = false; +} + +void Drawing::animationUpdateImage(drawMode mode, Evas_Object *bgPattern) +{ + struct Smart_Data *sd = (struct Smart_Data *) evas_object_smart_data_get(_pDrawingObj); + + if (mode == NORMAL_DRAW) { + sd->isUndoRedoAnimator = false; + return; + } + + pAnimationData->mode = mode; + pAnimationData->sourceCr = sd->m_cairo._sourceCr; + pAnimationData->sourceSurface = sd->m_cairo._sourceSurface; + pAnimationData->cr = sd->m_cairo._cr; + pAnimationData->image = sd->m_cairo._image; + pAnimationData->bgPattern = bgPattern; + if (mode == UNDO_DRAW) { + pAnimationData->isDrawing = true; + pAnimationData->animationTime = MAX_ANIMATION_TIME; + pAnimationData->imgUpdatePos = 0; + pAnimationData->imgUpdateCount = 0; + pAnimationData->isImgAnimateDraw = true; + sd->isUndoRedoAnimator = true; + //pAnimationData->drawingAnimator = ecore_animator_timeline_add(MAX_ANIMATION_TIME,sd->m_cairo.animationUpdateImage,pAnimationData); + } else if (mode == REDO_DRAW) { + sd->isUndoRedoAnimator = false; + pAnimationData->isDrawing = false; + pAnimationData->animationTime = 0; + sd->m_cairo.animationUpdateImage(pAnimationData, 0); + } +} + +void Drawing::updateBufferImage(int index) +{ + struct Smart_Data *sd = (struct Smart_Data *) evas_object_smart_data_get(_pDrawingObj); + std::vector> pt1; + std::vector strokeList; + DrawingColor pColor; + double strokeWidth; + pt1.clear(); + if (_getBufferCb) { + _getBufferCb(index, pt1, strokeList, &pColor, &strokeWidth); + } + //sd->m_cairo.updateBufferImage(pt1,pColor,strokeWidth,sd); + if (!pt1.empty()) { + int x, y, w, h; + evas_object_geometry_get(sd->img, &x, &y, &w, &h); + std::vector> pt = sd->m_selected.GetHistoryPoints(pt1); + sd->m_cairo.SetHistoryDrawingProperty(sd->m_cairo._bufferCr, pColor, strokeWidth); + sd->m_cairo.Draw(sd->m_cairo._bufferCr, pt, strokeList, + (double)sd->bufW / (double)w, + (double)sd->bufH / (double)h, + w, h); + } +} + + +Evas_Object* Drawing::getDrawImgObj() +{ + struct Smart_Data *sd = (struct Smart_Data *) evas_object_smart_data_get(_pDrawingObj); + return sd->img; +} + +void Drawing::setBgType(std::string& bgType) +{ + struct Smart_Data *sd = (struct Smart_Data *) evas_object_smart_data_get(_pDrawingObj); + sd->m_cairo.setBgType(bgType); +} + +void Drawing::setStopNormalDrawing(bool bDoding) +{ + struct Smart_Data *sd = (struct Smart_Data *) evas_object_smart_data_get(_pDrawingObj); + sd->m_cairo.setStopNormalDrawing(bDoding); +} + +void Drawing::restorePoints(std::vector > &pt) +{ + struct Smart_Data *sd = (struct Smart_Data *) evas_object_smart_data_get(_pDrawingObj); + /* erase uncompleted white lines */ + sd->m_cairo.eraseDraw(sd->m_selected, (double)sd->bufW / (double)sd->oRect.w, + (double)sd->bufH / (double)sd->oRect.h, + sd->oRect.w, sd->oRect.h); + + sd->m_selected.restorePoints(pt); +} + +void Drawing::activateUpdateAnimator(bool bActivate) +{ + struct Smart_Data *sd = (struct Smart_Data *) evas_object_smart_data_get(_pDrawingObj); + if (sd == nullptr) { + return; + } + + if (!bActivate) { + ecore_animator_freeze(sd->anim); + } else { + ecore_animator_thaw(sd->anim); + } +} + +bool Drawing::isDrawingStatus() +{ + struct Smart_Data *sd = (struct Smart_Data *) evas_object_smart_data_get(_pDrawingObj); + if (sd == nullptr) { + return false; + } + return sd->bMouseDown; +} + +int Drawing::getPatternBgAlpha() +{ + return pAnimationData->nBgPatternAlpha; +} + diff --git a/src/controls/Drawing.h b/src/controls/Drawing.h new file mode 100755 index 0000000..d6c31f1 --- /dev/null +++ b/src/controls/Drawing.h @@ -0,0 +1,159 @@ +#ifndef __DRAWING_H__ +#define __DRAWING_H__ + + +#include "CDrCairoImage.h" + + + + +struct Smart_Data { + Evas_Object *obj; // Smart object itself + Evas_Object *target; // Attached object. + Evas_Object *m_event; + Evas_Object *gesture; + Rect cRect; + Rect oRect; + Evas_Object *img; + Evas_Object *maskImg; + Evas_Object *sourceImg; +#ifdef ENABLE_ZOOM + Eina_Bool isZoomed; + double Zoom; // Current zoom level + int xClick; + int yClick; +#endif + CCairoImage m_cairo; + CLasso m_selected; + bool bMouseDown; // Indicator for mouse down + bool bFirstMove; + bool bShow; + bool is_changed; + bool isUndoRedoAnimator; +#ifdef REDO_UNDO + bool isMoved; +#endif +#ifdef ENABLE_DRAGING + bool mutilDown; + int xMutilPrev, yMutilPrev; +#endif + bool bMultiMove; + int bufW, bufH; // Image buffer size + Ecore_Animator *anim; + int xPrev, yPrev; + int xLatest, yLatest; + int mouseDownX, mouseDownY; + unsigned int prevTimestamp, latestTimestamp; + double vsyncTimestamp; + bool isAutofit; + int nAlphaTimer; +}; + + +class Drawing +{ +public: + Drawing(); + ~Drawing(); + Evas_Object *drawingAdd(Evas_Object *parent); + void drawingAttach(Evas_Object *target); + void drawingColorSet(std::string colorCode, bool isEraser); + DrawingColor getCurrentColor(); + void saveDrawingImage(std::string& fileName); + void addMouseEvent(); + void delMouseEvent(); + void setDeleteSaveTimerCb(std::function < void(void) > handlerFunc); + void setColorMenuStateCb(std::function < bool(void) > handlerFunc); + void setSaveStateCb(std::function < void(bool) > handlerFunc); + void setSetMaxHistoryCb(std::function < void(bool) > handlerFunc); + void setAddSaveTimerCb(std::function < void(void) > handlerFunc); + void setShowPanelCb(std::function < void(void) > handlerFunc); + void setGetBufferCb(std::function < void(int curIndex, std::vector> &buffer, std::vector& strokeList, DrawingColor* pColor, double *width) > handlerFunc); + Evas_Object* getDrawImgObj(); + + void setStrokeWidth(double dWidth); + void setBgType(std::string& bgType); + void activateUpdateAnimator(bool bActivate); + drawMode getDrawingMode(); + void getAnimatorTime(double *time); + void sourceUpdate(drawMode mode); + void maskUpdate(drawMode mode); + void clearSource(); + void clearMask(); + void updateBufferImage(int index); + void resetIsDrawing(); + bool isDrawingStatus(); + + std::function < void(int curIndex, std::vector> &buffer, std::vector& strokeList, DrawingColor* pColor, double *width) > _getBufferCb; +#ifdef REDO_UNDO + void setSaveBufferCb(std::function < void(std::vector> pt1, std::vector* pStrokeList, DrawingColor* pColor, double strokeWidth, bool increaseIndex) > handlerFunc); + bool updateBuffer(std::vector> &pt1, std::vector& strokeList, DrawingColor pColor, double strokeWidth, drawMode mode); + void setCheckFirstIndexCb(std::function < bool() > handlerFunc); + std::function < bool(void) > checkFirstIndexCb; + bool getDrawingStatus(); + bool getAnimationStatus(); +#endif + void clearImage(); + + void setStopNormalDrawing(bool bDoding); + void restorePoints(std::vector > &pt); + void animationUpdateImage(drawMode mode, Evas_Object *bgPattern); + int getPatternBgAlpha(); + bool isMouseMoving(); + +private: + static void _onMouseDown(void *data, Evas *e, Evas_Object *evas_obj, void *event_info); + static void _onMouseMove(void *data, Evas *e, Evas_Object *evas_obj, void *event_info); + static void _onMouseUp(void *data, Evas *e, Evas_Object *evas_obj, void *event_info); + bool _addDrawPoint(); + +#ifdef ENABLE_ZOOM + static Evas_Event_Flags _onDblClickStart(void *data , void *event_info); + static Evas_Event_Flags _onDblClickEnd(void *data , void *event_info); + static Evas_Event_Flags _onDblClickAbort(void *data , void *event_info); +#endif + +#ifdef ENABLE_DRAGING + static void _onMultiDown(void *data, Evas *e, Evas_Object *evas_obj, void *event_info); +#endif + static void _onMultiMove(void *data, Evas *e, Evas_Object *evas_obj, void *event_info); + static void _onMultiUp(void *data, Evas *e, Evas_Object *evas_obj, void *event_info); + static Evas_Event_Flags _onTapEnd(void *data , void *event_info); + + static void _smartAdd(Evas_Object *obj); + static void _smartDel(Evas_Object *obj); + static void _smartMove(Evas_Object *obj, Evas_Coord x, Evas_Coord y); + static void _smartResize(Evas_Object *obj, Evas_Coord w, Evas_Coord h); + static void _smartShow(Evas_Object *obj); + static void _smartHide(Evas_Object *obj); + static void _smartCalculate(Evas_Object *obj); + static Evas_Smart *_smartInit(void); + static Eina_Bool _onAnimatorUpdate(void *data); + +#ifdef ENABLE_ZOOM + static void _Draw(void *data, int fx, int fy, int fw, int fh); + static Eina_Bool _DoZoom(void *data, double pos); + static double _getAutoFitZoom(struct Smart_Data *sd); +#endif + +public: + struct animationData *pAnimationData; +private: + Evas_Object *_pDrawingObj; + DrawingColor _cCurrentColor; + + static int _mTouchMode; + std::function < void(void) > _deleteSaveTimerCb; + std::function < bool(void) > _colorMenuStateCb; + std::function < void(bool) > _saveStateCb; + std::function < void(bool) > setMaxHistoryCb; + std::function < void(void) > _addSaveTimerCb; + std::function < void(void) > _showPanelCb; +#ifdef REDO_UNDO + std::function < void(std::vector> pt1, std::vector* strokeList, DrawingColor* pColor, double strokeWidth, bool increaseIndex) > _saveBufferCb; +#endif +}; + +#endif // __DRAWING_H__ + + diff --git a/src/controls/History.cpp b/src/controls/History.cpp new file mode 100755 index 0000000..de790e7 --- /dev/null +++ b/src/controls/History.cpp @@ -0,0 +1,234 @@ +#include "History.h" +#include "DrDefine.h" +#include + + +History::History() +: _pcycleQueue(nullptr), + index(-1), + isMaxHistory(false), + firstIndex(0), + _updateBufferImageCb(nullptr) +{ + _initBufferPooling(); +} + +History::~History() +{ + _deleteBufferPooling(); +} + +bool History::getMaxHistory() +{ + return isMaxHistory; +} + +void History::setMaxHistory(bool status) +{ + structImage *intermediateBuffer; + isMaxHistory = status; + _pcycleQueue->front = index % MAX_HISTORY; + firstIndex = _pcycleQueue->front; + intermediateBuffer = &(_pcycleQueue->_bufferPooling[_pcycleQueue->front]); + intermediateBuffer->point.clear(); +} + +bool History::checkFirstIndex() +{ + if ((index % MAX_HISTORY == firstIndex) /*|| index == 0*/) { + return true; + } else { + return false; + } +} + +bool History::checkLastIndex() +{ + if (((index % MAX_HISTORY)) == _pcycleQueue->rear - 1) { + return true; + } else { + return false; + } +} + + +void History::saveBuffer(std::vector> &pt1, std::vector* pStrokeList, DrawingColor* pColor, double drawingWidth, bool increaseIndex) +{ + structImage *intermediateBuffer; + + if (increaseIndex && _fullQueue()) + { + isMaxHistory = true; + if (_updateBufferImageCb) { + _updateBufferImageCb(_pcycleQueue->front); + } + firstIndex = _pcycleQueue->front; + _pcycleQueue->front = (_pcycleQueue->front + 1) % MAX_HISTORY; + } + if (increaseIndex) + index++; + + intermediateBuffer = &(_pcycleQueue->_bufferPooling[index % MAX_HISTORY]); + intermediateBuffer->point.clear(); + _pcycleQueue->rear = (index + 1) % MAX_HISTORY; + for (std::vector>::const_iterator iter = pt1.begin(); + iter != pt1.end(); ++iter) { + intermediateBuffer->point.push_back(std::make_pair(iter->first, iter->second)); + } + intermediateBuffer->strokeWidthList.clear(); + intermediateBuffer->strokeWidthList = (*pStrokeList); + + intermediateBuffer->_cCurrentColor.r = pColor->r; + intermediateBuffer->_cCurrentColor.g = pColor->g; + intermediateBuffer->_cCurrentColor.b = pColor->b; + intermediateBuffer->_cCurrentColor.a = pColor->a; + intermediateBuffer->_cCurrentColor.is_eraser = pColor->is_eraser; + intermediateBuffer->strokeWidth = drawingWidth; + + WINFO("Set history front:%d index:%d rear:%d first:%d", _pcycleQueue->front, index, _pcycleQueue->rear, firstIndex); +} + +bool History::redo(std::vector> &buffer, std::vector& strokeList, DrawingColor* pColor, double *strokeWidth) +{ + if (((index + 1) % MAX_HISTORY) == _pcycleQueue->rear) { + WINFO("Already in last index,can not redo"); + return false; + } + index++; + WINFO("Redo index:%d", index); + _getOutputBuffer(buffer, strokeList, pColor, strokeWidth); + return true; +} + +bool History::undo(int *undoStart, int *undoEnd) +{ + if (index % MAX_HISTORY == firstIndex) { + WINFO("Already in first index,clear all"); + return false; + } + *undoStart = _pcycleQueue->front; + *undoEnd = index; + index--; + WINFO("Undo index:%d", index); + if (index % MAX_HISTORY == firstIndex) { + WINFO("Already in first index,clear all"); + return false; + } + return true; +} + +bool History::_fullQueue() +{ + if (_pcycleQueue->front == (index + 2) % MAX_HISTORY) + return true; + else + return false; +} + +void History::_deleteBufferPooling() +{ + if (_pcycleQueue == nullptr) { + WINFO("Memory Allocation Failed!!"); + return; + } + + free(_pcycleQueue->_bufferPooling); + _pcycleQueue->_bufferPooling = nullptr; + + free(_pcycleQueue); + _pcycleQueue = nullptr; +} + +void History::_getOutputBuffer(int curIndex, std::vector> &buffer, std::vector& strokeList, DrawingColor* pColor, double *width) +{ + structImage *lastestSavedImage = nullptr; + int num_bytes; + lastestSavedImage = &(_pcycleQueue->_bufferPooling[curIndex]); + if (lastestSavedImage == nullptr) { + WINFO("get buffer failed"); + } + for (std::vector>::const_iterator iter1 = lastestSavedImage->point.begin(); + iter1 != lastestSavedImage->point.end(); ++iter1) { + buffer.push_back(std::make_pair(iter1->first, iter1->second)); + } + strokeList = lastestSavedImage->strokeWidthList; + + (*pColor).r = lastestSavedImage->_cCurrentColor.r; + (*pColor).g = lastestSavedImage->_cCurrentColor.g; + (*pColor).b = lastestSavedImage->_cCurrentColor.b; + (*pColor).a = lastestSavedImage->_cCurrentColor.a; + (*pColor).is_eraser = lastestSavedImage->_cCurrentColor.is_eraser; + *width = lastestSavedImage->strokeWidth; +} + +void History::_getOutputBuffer(std::vector> &buffer, std::vector& strokeList, DrawingColor* pColor, double *width) +{ + structImage *lastestSavedImage = nullptr; + int num_bytes; + lastestSavedImage = &(_pcycleQueue->_bufferPooling[index % MAX_HISTORY]); + if (lastestSavedImage == nullptr) { + WINFO("get buffer failed"); + } + for (std::vector>::const_iterator iter1 = lastestSavedImage->point.begin(); + iter1 != lastestSavedImage->point.end(); ++iter1) { + buffer.push_back(std::make_pair(iter1->first, iter1->second)); + } + strokeList = lastestSavedImage->strokeWidthList; + + (*pColor).r = lastestSavedImage->_cCurrentColor.r; + (*pColor).g = lastestSavedImage->_cCurrentColor.g; + (*pColor).b = lastestSavedImage->_cCurrentColor.b; + (*pColor).a = lastestSavedImage->_cCurrentColor.a; + (*pColor).is_eraser = lastestSavedImage->_cCurrentColor.is_eraser; + *width = lastestSavedImage->strokeWidth; +} + +void History::_initBufferPooling() +{ + _pcycleQueue = (cycleQueue *)calloc(1, sizeof(cycleQueue)); + + if (_pcycleQueue == nullptr) + { + WINFO("Memory Allocation Failed!!"); + return; + } + + _pcycleQueue->_bufferPooling = (structImage *)calloc(1, sizeof(structImage) * MAX_HISTORY); + if (_pcycleQueue->_bufferPooling == nullptr) + { + WINFO("Memory Allocation Failed!!"); + free(_pcycleQueue); + _pcycleQueue = nullptr; + return; + } + _pcycleQueue->front = 0; + _pcycleQueue->rear = 0; +} + +void History::setClearCb(std::function < void(void) > handlerFunc) +{ + _clearCb = handlerFunc; +} + +void History::setUpdateBufferImageCb(std::function < void(int index) > handlerFunc) +{ + _updateBufferImageCb = handlerFunc; +} + +int History::getCurIndex() +{ + return index; +} + +int History::getCount() +{ + if (_pcycleQueue == nullptr) + { + WINFO("Memory Allocation Failed!!"); + return 0; + } + if (index % MAX_HISTORY >= firstIndex) + return index % MAX_HISTORY - firstIndex + 1; + else + return MAX_HISTORY - firstIndex + index % MAX_HISTORY + 1; +} diff --git a/src/controls/History.h b/src/controls/History.h new file mode 100755 index 0000000..8c638b1 --- /dev/null +++ b/src/controls/History.h @@ -0,0 +1,59 @@ +#ifndef __HISTORY_H__ +#define __HISTORY_H__ +#include +#include "Drawing.h" + +typedef struct +{ + double strokeWidth; + DrawingColor _cCurrentColor; + std::vector> point; + std::vector strokeWidthList; +} structImage; + +typedef struct +{ + structImage *_bufferPooling; + int front; + int rear; +}cycleQueue; + +class History +{ +public: + History(); + ~History(); + void saveBuffer(std::vector> &pt1, std::vector* pStrokeList, DrawingColor* pColor, double drawingWidth, bool increaseIndex); + bool redo(std::vector> &buffer, std::vector& strokeList, DrawingColor* pColor, double *strokeWidth); + bool redo(int *redoStart, int *redoEnd); + bool undo(int *undoStart, int *undoEnd); + + bool checkFirstIndex(); + bool checkLastIndex(); + void setClearCb(std::function < void(void) > handlerFunc); + void setUpdateBufferImageCb(std::function < void(int index) > handlerFunc); + int getCurIndex(); + int getCount(); + void _getOutputBuffer(int curIndex, std::vector> &buffer, std::vector& strokeList, DrawingColor* pColor, double *width); + bool getMaxHistory(); + void setMaxHistory(bool status); + +private: + void _initBufferPooling(); + void _deleteBufferPooling(); + void _getOutputBuffer(std::vector> &buffer, std::vector& strokeList, DrawingColor* pColor, double *width); + bool _fullQueue(); + bool isMaxHistory; + int firstIndex; +private: + History(const History&) = delete; + const History& operator = (const History&) = delete; + + cycleQueue *_pcycleQueue; + int index; + std::function < void(void) > _clearCb; + std::function < void(int index) > _updateBufferImageCb; +}; + +#endif // __HISTORY_H__ + diff --git a/src/main.cpp b/src/main.cpp new file mode 100755 index 0000000..3dccccc --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,15 @@ + +#include "DrDebug.h" +#include "CDrApp.h" + +WAPP_ASSIST_EXPORT int main(int argc, char *argv[]) +{ + WENTER(); + CDrApp app; + int ret = app.start(argc, argv); + + WDEBUG("app return=%d", ret); + WLEAVE(); + return ret; +} + diff --git a/src/popup/CDrClosePopup.cpp b/src/popup/CDrClosePopup.cpp new file mode 100755 index 0000000..3e1c5d7 --- /dev/null +++ b/src/popup/CDrClosePopup.cpp @@ -0,0 +1,121 @@ +#include +#include +//#include +#include +#include "CDrClosePopup.h" +#include "DrDefine.h" +#include "DrDebug.h" + +CDrClosePopup::CDrClosePopup() +{ + _discardResultHandler = nullptr; + _cancelResultHandler = nullptr; +} + +CDrClosePopup::~CDrClosePopup() +{ +} + +void CDrClosePopup::setCaption(const char *title) +{ + setTitle(title); +} + +void CDrClosePopup::setOnDiscardResult(std::function < void() > handlerFunc) +{ + _discardResultHandler = handlerFunc; +} + +void CDrClosePopup::setOnCancelResult(std::function < void() > handlerFunc) +{ + _cancelResultHandler = handlerFunc; +} + + +Evas_Object *CDrClosePopup::onCreateView(Evas_Object * parent, void *viewParam) +{ + WENTER(); + setTextTranslatable(LOCALE_DOMAIN); + setContent([this] (Evas_Object * parent)->Evas_Object * { + return _createContent(parent); + } + ); + + setOnAddProperties([&](Evas_Object* popup){ + elm_object_style_set(popup, "circle"); +// uxt_popup_set_rotary_event_enabled(popup, EINA_FALSE); + }); + + addButton(DRAWING_POPUP_DISCARD_CANCEL_BUTTON, [this] (bool * destroyPopup) { + if (_cancelResultHandler) { + _cancelResultHandler(); + } + *destroyPopup = true; + }, [&](Evas_Object* button) { + elm_object_style_set(button , "popup/circle/left"); + Evas_Object* icon = elm_image_add(button); + char* res_path = app_get_resource_path(); + std::string strIcon(res_path); + strIcon += CLOSE_POPUP_CANCEL_ICON; + elm_image_file_set(icon, strIcon.c_str(), NULL); + free(res_path); + evas_object_size_hint_weight_set(icon, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + elm_object_part_content_set(button, "elm.swallow.content", icon); + evas_object_show(icon); + }); + + addButton(DRAWING_POPUP_DISCARD_DISCARD_BUTTON, [&](bool * destroyPopup) { + if (_discardResultHandler) { + _discardResultHandler(); + } + *destroyPopup = true; + }, [&](Evas_Object* button) { + elm_object_style_set(button , "popup/circle/right"); + Evas_Object* icon = elm_image_add(button); + char* res_path = app_get_resource_path(); + std::string strIcon(res_path); + strIcon += CLOSE_POPUP_DISCARD_ICON; + elm_image_file_set(icon, strIcon.c_str(), NULL); + free(res_path); + evas_object_size_hint_weight_set(icon, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + elm_object_part_content_set(button, "elm.swallow.content", icon); + evas_object_show(icon); + }); + + setOnBack([this] (bool * destroyPopup) { + if (_cancelResultHandler) { + _cancelResultHandler(); + } + *destroyPopup = true;} + ); + + + Evas_Object *popup = WPopupController::onCreateView(parent, viewParam); + + return popup; +} + +void CDrClosePopup::onDestroy() +{ +} + +Evas_Object *CDrClosePopup::_createContent(Evas_Object * parent) +{ + char* _path = app_get_resource_path(); + std::string path(_path); + path += EDJ_POPUP_CUSTOM_FILE; + + Evas_Object* layout = elm_layout_add(parent); + elm_layout_file_set(layout, path.c_str(), "close_popup"); + free(_path); + + elm_object_domain_translatable_part_text_set(layout, "discard.text.content", LOCALE_DOMAIN, DRAWING_STRING_ID_POPUP_DISCARD_CONTENT); + //elm_object_part_text_set(layout, "discard.text.content", DRAWING_POPUP_DISCARD_CONTENT); + + elm_object_content_set(parent, layout); + + evas_object_show(parent); + + return layout; +} + diff --git a/src/popup/CDrClosePopup.h b/src/popup/CDrClosePopup.h new file mode 100755 index 0000000..caf035a --- /dev/null +++ b/src/popup/CDrClosePopup.h @@ -0,0 +1,34 @@ + +#ifndef _CDR_CLOSE_POPUP_H_ +#define _CDR_CLOSE_POPUP_H_ +#include "WPopupController.h" +#include +#include +#include +#include + +using namespace app_assist; + +class CDrClosePopup:public WPopupController { + public: + CDrClosePopup(); + protected: + ~CDrClosePopup(); + + public: + void setCaption(const char *title); + void setOnDiscardResult(std::function < void() > handlerFunc); + void setOnCancelResult(std::function < void() > handlerFunc); + + private: + virtual Evas_Object * onCreateView(Evas_Object * parent, void *viewParam); + virtual void onDestroy(); + + Evas_Object *_createContent(Evas_Object * parent); + + private: + std::function < void() > _discardResultHandler; + std::function < void() > _cancelResultHandler; +}; + +#endif diff --git a/tizen-manifest.xml b/tizen-manifest.xml new file mode 100755 index 0000000..d66d625 --- /dev/null +++ b/tizen-manifest.xml @@ -0,0 +1,17 @@ + + + + + + org.tizen.sketch.png + + + http://tizen.org/privilege/mediastorage + http://tizen.org/privilege/appmanager.launch + http://tizen.org/privilege/haptic + http://tizen.org/privilege/display + http://tizen.org/privilege/power + http://tizen.org/privilege/content.write + + + -- 2.34.1