From e2a55772ba0bac5ffdeb567f928bb16e22dc3929 Mon Sep 17 00:00:00 2001 From: sachiel Date: Sun, 9 Oct 2011 22:10:45 +0000 Subject: [PATCH] The Force is weak on me. Crappy zoom and region_show code. If anyone wants to fix it before I get back to it, discomfitor will buy you a beer. It's intended to mimic as much as possible photocam's zoom api, but webkit doesn't always help with that. git-svn-id: svn+ssh://svn.enlightenment.org/var/svn/e/trunk/elementary@63936 7cbeb6ba-43b4-40fd-8cce-4c39aea84d33 --- src/bin/test_web.c | 106 ++++++++++++++++++ src/lib/Elementary.h.in | 86 ++++++++++++++ src/lib/elm_web.c | 289 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 481 insertions(+) diff --git a/src/bin/test_web.c b/src/bin/test_web.c index f7441a1..ecf8dc8 100644 --- a/src/bin/test_web.c +++ b/src/bin/test_web.c @@ -258,6 +258,68 @@ _js_popup_hooks_set(void *data, Evas_Object *obj __UNUSED__, void *event_info __ } static void +_zoom_out_cb(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__) +{ + Web_Test *wt = data; + double zoom; + + zoom = elm_web_zoom_get(wt->web); + if (zoom > 1) + zoom -= .5; + else + zoom /= 2; + if (zoom < .05) + zoom = .05; + elm_web_zoom_set(wt->web, zoom); +} + +static void +_zoom_in_cb(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__) +{ + Web_Test *wt = data; + double zoom; + + zoom = elm_web_zoom_get(wt->web); + + if (zoom < 1) + zoom *= 2; + else + zoom += .5; + if (zoom > 4) + zoom = 4; + elm_web_zoom_set(wt->web, zoom); +} + +static void +_zoom_mode_cb(void *data, Evas_Object *obj __UNUSED__, void *event_info) +{ + Web_Test *wt = data; + Elm_Hoversel_Item *it = event_info; + const char *lbl = elm_hoversel_item_label_get(it); + + if (!strcmp(lbl, "Manual")) + elm_web_zoom_mode_set(wt->web, ELM_WEB_ZOOM_MODE_MANUAL); + else if (!strcmp(lbl, "Fit")) + elm_web_zoom_mode_set(wt->web, ELM_WEB_ZOOM_MODE_AUTO_FIT); + else + elm_web_zoom_mode_set(wt->web, ELM_WEB_ZOOM_MODE_AUTO_FILL); +} + +static void +_show_region_cb(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__) +{ + Web_Test *wt = data; + elm_web_region_show(wt->web, 300, 300, 1, 1); +} + +static void +_bring_in_region_cb(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__) +{ + Web_Test *wt = data; + elm_web_region_bring_in(wt->web, 50, 0, 1, 1); +} + +static void _main_web_del_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__) { Web_Test *wt = data; @@ -361,6 +423,50 @@ test_web(void *data __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __ evas_object_smart_callback_add(bt, "clicked", _js_popup_hooks_set, wt); + bt = elm_button_add(win); + elm_object_text_set(bt, "-"); + elm_box_pack_end(bx2, bt); + evas_object_show(bt); + + evas_object_smart_callback_add(bt, "clicked", _zoom_out_cb, wt); + + bt = elm_button_add(win); + elm_object_text_set(bt, "+"); + elm_box_pack_end(bx2, bt); + evas_object_show(bt); + + evas_object_smart_callback_add(bt, "clicked", _zoom_in_cb, wt); + + bt = elm_hoversel_add(win); + elm_object_text_set(bt, "Zoom Mode"); + elm_box_pack_end(bx2, bt); + evas_object_show(bt); + + elm_hoversel_item_add(bt, "Manual", NULL, ELM_ICON_NONE, _zoom_mode_cb, wt); + elm_hoversel_item_add(bt, "Fit", NULL, ELM_ICON_NONE, _zoom_mode_cb, wt); + elm_hoversel_item_add(bt, "Fill", NULL, ELM_ICON_NONE, _zoom_mode_cb, wt); + + bx2 = elm_box_add(win); + elm_box_horizontal_set(bx2, EINA_TRUE); + evas_object_size_hint_weight_set(bx2, EVAS_HINT_EXPAND, 0); + evas_object_size_hint_align_set(bx2, EVAS_HINT_FILL, 0); + elm_box_pack_end(bx, bx2); + evas_object_show(bx2); + + bt = elm_button_add(win); + elm_object_text_set(bt, "Show 300, 300"); + elm_box_pack_end(bx2, bt); + evas_object_show(bt); + + evas_object_smart_callback_add(bt, "clicked", _show_region_cb, wt); + + bt = elm_button_add(win); + elm_object_text_set(bt, "Bring in 50, 0"); + elm_box_pack_end(bx2, bt); + evas_object_show(bt); + + evas_object_smart_callback_add(bt, "clicked", _bring_in_region_cb, wt); + evas_object_smart_callback_add(web, "title,changed", _title_changed_cb, win); evas_object_smart_callback_add(web, "uri,changed", _uri_changed_cb, wt); diff --git a/src/lib/Elementary.h.in b/src/lib/Elementary.h.in index a3ed7b9..49028c7 100644 --- a/src/lib/Elementary.h.in +++ b/src/lib/Elementary.h.in @@ -13061,6 +13061,16 @@ extern "C" { }; /** + * Types of zoom available. + */ + typedef enum _Elm_Web_Zoom_Mode + { + ELM_WEB_ZOOM_MODE_MANUAL = 0, /**< Zoom controled normally by elm_web_zoom_set */ + ELM_WEB_ZOOM_MODE_AUTO_FIT, /**< Zoom until content fits in web object */ + ELM_WEB_ZOOM_MODE_AUTO_FILL, /**< Zoom until content fills web object */ + ELM_WEB_ZOOM_MODE_LAST + } Elm_Web_Zoom_Mode; + /** * Opaque handler containing the features (such as statusbar, menubar, etc) * that are to be set on a newly requested window. */ @@ -13605,6 +13615,59 @@ extern "C" { */ EAPI void elm_web_history_enable_set(Evas_Object *obj, Eina_Bool enable); /** + * Sets the zoom level of the web object + * + * Zoom level matches the Webkit API, so 1.0 means normal zoom, with higher + * values meaning zoom in and lower meaning zoom out. This function will + * only affect the zoom level if the mode set with elm_web_zoom_mode_set() + * is ::ELM_WEB_ZOOM_MODE_MANUAL. + * + * @param obj The web object + * @param zoom The zoom level to set + */ + EAPI void elm_web_zoom_set(Evas_Object *obj, double zoom); + /** + * Gets the current zoom level set on the web object + * + * Note that this is the zoom level set on the web object and not that + * of the underlying Webkit one. In the ::ELM_WEB_ZOOM_MODE_MANUAL mode, + * the two zoom levels should match, but for the other two modes the + * Webkit zoom is calculated internally to match the chosen mode without + * changing the zoom level set for the web object. + * + * @param obj The web object + * + * @return The zoom level set on the object + */ + EAPI double elm_web_zoom_get(const Evas_Object *obj); + /** + * Sets the zoom mode to use + * + * The modes can be any of those defined in ::Elm_Web_Zoom_Mode, except + * ::ELM_WEB_ZOOM_MODE_LAST. The default is ::ELM_WEB_ZOOM_MODE_MANUAL. + * + * ::ELM_WEB_ZOOM_MODE_MANUAL means the zoom level will be controlled + * with the elm_web_zoom_set() function. + * ::ELM_WEB_ZOOM_MODE_AUTO_FIT will calculate the needed zoom level to + * make sure the entirety of the web object's contents are shown. + * ::ELM_WEB_ZOOM_MODE_AUTO_FILL will calculate the needed zoom level to + * fit the contents in the web object's size, without leaving any space + * unused. + * + * @param obj The web object + * @param mode The mode to set + */ + EAPI void elm_web_zoom_mode_set(Evas_Object *obj, Elm_Web_Zoom_Mode mode); + /** + * Gets the currently set zoom mode + * + * @param obj The web object + * + * @return The current zoom mode set for the object, or + * ::ELM_WEB_ZOOM_MODE_LAST on error + */ + EAPI Elm_Web_Zoom_Mode elm_web_zoom_mode_get(const Evas_Object *obj); + /** * Gets whether text-only zoom is set * * @param obj The web object @@ -13627,6 +13690,29 @@ extern "C" { */ EAPI void elm_web_zoom_text_only_set(Evas_Object *obj, Eina_Bool setting); /** + * Shows the given region in the web object + * + * @param obj The web object + * @param x The x coordinate of the region to show + * @param y The y coordinate of the region to show + * @param w The width of the region to show + * @param h The height of the region to show + */ + EAPI void elm_web_region_show(Evas_Object *obj, int x, int y, int w, int h); + /** + * Brings in the region to the visible area + * + * Like elm_web_region_show(), but it animates the scrolling of the object + * to show the area + * + * @param obj The web object + * @param x The x coordinate of the region to show + * @param y The y coordinate of the region to show + * @param w The width of the region to show + * @param h The height of the region to show + */ + EAPI void elm_web_region_bring_in(Evas_Object *obj, int x, int y, int w, int h); + /** * Sets the default dialogs to use an Inwin instead of a normal window * * If set, then the default implementation for the JavaScript dialogs and diff --git a/src/lib/elm_web.c b/src/lib/elm_web.c index 3f0c2aa..64e72bb 100644 --- a/src/lib/elm_web.c +++ b/src/lib/elm_web.c @@ -49,6 +49,19 @@ struct _Widget_Data void *console_message_data; } hook; Elm_Win_Keyboard_Mode input_method; + struct { + Elm_Web_Zoom_Mode mode; + float current; + float min, max; + Eina_Bool no_anim; + Ecore_Timer *timer; + } zoom; + struct { + struct { + int x, y; + } start, end; + Ecore_Animator *animator; + } bring_in; Eina_Bool tab_propagate : 1; Eina_Bool inwin_mode : 1; #else @@ -767,6 +780,66 @@ _ewk_view_load_started_cb(void *data, Evas_Object *obj, void *event_info __UNUSE } static void +_ewk_view_load_finished_cb(void *data, Evas_Object *obj __UNUSED__, void *event_info) +{ + Widget_Data *wd = data; + + if (event_info) + return; + + if (wd->zoom.mode != ELM_WEB_ZOOM_MODE_MANUAL) + { + float tz = wd->zoom.current; + wd->zoom.current = 0.0; + elm_web_zoom_set(wd->self, tz); + } +} + +static void +_ewk_view_viewport_changed_cb(void *data, Evas_Object *obj, void *event_info __UNUSED__) +{ + Widget_Data *wd = data; + + if (wd->zoom.mode != ELM_WEB_ZOOM_MODE_MANUAL) + { + ewk_view_zoom_set(obj, 1.0, 0, 0); + wd->zoom.no_anim = EINA_TRUE; + } +} + +static Eina_Bool +_restore_zoom_mode_timer_cb(void *data) +{ + Widget_Data *wd = data; + float tz = wd->zoom.current; + wd->zoom.timer = NULL; + wd->zoom.current = 0.0; + wd->zoom.no_anim = EINA_TRUE; + elm_web_zoom_set(wd->self, tz); + return EINA_FALSE; +} + +static Eina_Bool +_reset_zoom_timer_cb(void *data) +{ + Widget_Data *wd = data; + wd->zoom.timer = ecore_timer_add(0.0, _restore_zoom_mode_timer_cb, wd); + ewk_view_zoom_set(wd->ewk_view, 1.0, 0, 0); + return EINA_FALSE; +} + +static void +_ewk_view_resized_cb(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__) +{ + Widget_Data *wd = data; + if (!(wd->zoom.mode != ELM_WEB_ZOOM_MODE_MANUAL)) + return; + if (wd->zoom.timer) + ecore_timer_del(wd->zoom.timer); + wd->zoom.timer = ecore_timer_add(0.5, _reset_zoom_timer_cb, wd); +} + +static void _popup_del_job(void *data) { evas_object_del(data); @@ -902,6 +975,30 @@ _view_smart_callback_proxy(Evas_Object *view, Evas_Object *parent) _view_smart_callback_proxy_cb, ctxt); } } + +static Eina_Bool +_bring_in_anim_cb(void *data, double pos) +{ + Widget_Data *wd = data; + Evas_Object *frame = ewk_view_frame_main_get(wd->ewk_view); + int sx, sy, rx, ry; + + sx = wd->bring_in.start.x; + sy = wd->bring_in.start.y; + rx = (wd->bring_in.end.x - sx) * pos; + ry = (wd->bring_in.end.y - sy) * pos; + + ewk_frame_scroll_set(frame, rx + sx, ry + sy); + + if (pos == 1.0) + { + wd->bring_in.end.x = wd->bring_in.end.y = wd->bring_in.start.x = + wd->bring_in.start.y = 0; + wd->bring_in.animator = NULL; + } + + return EINA_TRUE; +} #endif #ifdef HAVE_ELEMENTARY_WEB @@ -972,11 +1069,20 @@ elm_web_add(Evas_Object *parent) _ewk_view_load_started_cb, wd); evas_object_smart_callback_add(wd->ewk_view, "popup,create", _ewk_view_popup_create_cb, wd); + evas_object_smart_callback_add(wd->ewk_view, "load,finished", + _ewk_view_load_finished_cb, wd); + evas_object_smart_callback_add(wd->ewk_view, "viewport,changed", + _ewk_view_viewport_changed_cb, wd); + evas_object_smart_callback_add(wd->ewk_view, "view,resized", + _ewk_view_resized_cb, wd); elm_widget_resize_object_set(obj, wd->ewk_view); wd->tab_propagate = EINA_FALSE; wd->inwin_mode = _elm_config->inwin_dialogs_enable; + wd->zoom.min = ewk_view_zoom_range_min_get(wd->ewk_view); + wd->zoom.max = ewk_view_zoom_range_max_get(wd->ewk_view); + wd->zoom.current = 1.0; _view_smart_callback_proxy(wd->ewk_view, wd->self); evas_object_smart_callbacks_descriptions_set(obj, _elm_web_callback_names); @@ -1468,6 +1574,130 @@ elm_web_history_enable_set(Evas_Object *obj, Eina_Bool enable) //EAPI Ewk_History *ewk_view_history_get(const Evas_Object *obj); // TODO: +EAPI void +elm_web_zoom_set(Evas_Object *obj, double zoom) +{ + ELM_CHECK_WIDTYPE(obj, widtype); +#ifdef HAVE_ELEMENTARY_WEB + Widget_Data *wd = elm_widget_data_get(obj); + int vw, vh, cx, cy; + float z = 1.0; + evas_object_geometry_get(wd->ewk_view, NULL, NULL, &vw, &vh); + cx = vw / 2; + cy = vh / 2; + if (zoom > wd->zoom.max) + zoom = wd->zoom.max; + else if (zoom < wd->zoom.min) + zoom = wd->zoom.min; + if (zoom == wd->zoom.current) return; + wd->zoom.current = zoom; + if (wd->zoom.mode == ELM_WEB_ZOOM_MODE_MANUAL) + z = zoom; + else if (wd->zoom.mode == ELM_WEB_ZOOM_MODE_AUTO_FIT) + { + Evas_Object *frame = ewk_view_frame_main_get(wd->ewk_view); + Evas_Coord fw, fh, pw, ph; + if (!ewk_frame_contents_size_get(frame, &fw, &fh)) + return; + z = ewk_frame_zoom_get(frame); + fw /= z; + fh /= z; + if ((fw > 0) && (fh > 0)) + { + ph = (fh * vw) / fw; + if (ph > vh) + { + pw = (fw * vh) / fh; + ph = vh; + } + else + pw = vw; + if (fw > fh) + z = (float)pw / fw; + else + z = (float)ph / fh; + } + } + else if (wd->zoom.mode == ELM_WEB_ZOOM_MODE_AUTO_FILL) + { + Evas_Object *frame = ewk_view_frame_main_get(wd->ewk_view); + Evas_Coord fw, fh, pw, ph; + if (!ewk_frame_contents_size_get(frame, &fw, &fh)) + return; + z = ewk_frame_zoom_get(frame); + fw /= z; + fh /= z; + if ((fw > 0) && (fh > 0)) + { + ph = (fh * vw) / fw; + if (ph < vh) + { + pw = (fw * vh) / fh; + ph = vh; + } + else + pw = vw; + if (fw > fh) + z = (float)pw / fw; + else + z = (float)ph / fh; + } + } + if (wd->zoom.no_anim) + ewk_view_zoom_set(wd->ewk_view, z, cx, cy); + else + ewk_view_zoom_animated_set(wd->ewk_view, z, _elm_config->zoom_friction, + cx, cy); + wd->zoom.no_anim = EINA_FALSE; +#else + (void)zoom; +#endif +} + +EAPI double +elm_web_zoom_get(const Evas_Object *obj) +{ + ELM_CHECK_WIDTYPE(obj, widtype) -1.0; +#ifdef HAVE_ELEMENTARY_WEB + Widget_Data *wd = elm_widget_data_get(obj); + return wd->zoom.current; +#else + return -1.0; +#endif +} + +EAPI void +elm_web_zoom_mode_set(Evas_Object *obj, Elm_Web_Zoom_Mode mode) +{ + ELM_CHECK_WIDTYPE(obj, widtype); +#ifdef HAVE_ELEMENTARY_WEB + Widget_Data *wd = elm_widget_data_get(obj); + float tz; + if (mode >= ELM_WEB_ZOOM_MODE_LAST) + return; + if (mode == wd->zoom.mode) + return; + wd->zoom.mode = mode; + tz = wd->zoom.current; + wd->zoom.current = 0.0; + elm_web_zoom_set(obj, tz); +#else + (void)mode; +#endif +} + +EAPI Elm_Web_Zoom_Mode +elm_web_zoom_mode_get(const Evas_Object *obj) +{ + ELM_CHECK_WIDTYPE(obj, widtype) ELM_WEB_ZOOM_MODE_LAST; +#ifdef HAVE_ELEMENTARY_WEB + Widget_Data *wd = elm_widget_data_get(obj); + return wd->zoom.mode; +#else + return ELM_WEB_ZOOM_MODE_LAST; +#endif +} + EAPI Eina_Bool elm_web_zoom_text_only_get(const Evas_Object *obj) { @@ -1495,6 +1725,65 @@ elm_web_zoom_text_only_set(Evas_Object *obj, Eina_Bool setting) } EAPI void +elm_web_region_show(Evas_Object *obj, int x, int y, int w __UNUSED__, int h __UNUSED__) +{ + ELM_CHECK_WIDTYPE(obj, widtype); +#ifdef HAVE_ELEMENTARY_WEB + Widget_Data *wd = elm_widget_data_get(obj); + Evas_Object *frame = ewk_view_frame_main_get(wd->ewk_view); + int fw, fh, zw, zh, rx, ry; + float zoom; + ewk_frame_contents_size_get(frame, &fw, &fh); + zoom = ewk_frame_zoom_get(frame); + zw = fw / zoom; + zh = fh / zoom; + rx = (x * fw) / zw; + ry = (y * fh) / zh; + if (wd->bring_in.animator) + { + ecore_animator_del(wd->bring_in.animator); + wd->bring_in.animator = NULL; + } + ewk_frame_scroll_set(frame, rx, ry); +#else + (void)x; + (void)y; +#endif +} + +EAPI void +elm_web_region_bring_in(Evas_Object *obj, int x, int y, int w __UNUSED__, int h __UNUSED__) +{ + ELM_CHECK_WIDTYPE(obj, widtype); +#ifdef HAVE_ELEMENTARY_WEB + Widget_Data *wd = elm_widget_data_get(obj); + Evas_Object *frame = ewk_view_frame_main_get(wd->ewk_view); + int fw, fh, zw, zh, rx, ry, sx, sy; + float zoom; + ewk_frame_contents_size_get(frame, &fw, &fh); + ewk_frame_scroll_pos_get(frame, &sx, &sy); + zoom = ewk_frame_zoom_get(frame); + zw = fw / zoom; + zh = fh / zoom; + rx = (x * fw) / zw; + ry = (y * fh) / zh; + if ((wd->bring_in.end.x == rx) && (wd->bring_in.end.y == ry)) + return; + wd->bring_in.start.x = sx; + wd->bring_in.start.y = sy; + wd->bring_in.end.x = rx; + wd->bring_in.end.y = ry; + if (wd->bring_in.animator) + ecore_animator_del(wd->bring_in.animator); + wd->bring_in.animator = ecore_animator_timeline_add( + _elm_config->bring_in_scroll_friction, _bring_in_anim_cb, wd); +#else + (void)x; + (void)y; +#endif +} + +EAPI void elm_web_inwin_mode_set(Evas_Object *obj, Eina_Bool value) { ELM_CHECK_WIDTYPE(obj, widtype); -- 2.7.4