The Force is weak on me.
authorsachiel <sachiel@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Sun, 9 Oct 2011 22:10:45 +0000 (22:10 +0000)
committersachiel <sachiel@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Sun, 9 Oct 2011 22:10:45 +0000 (22:10 +0000)
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
src/lib/Elementary.h.in
src/lib/elm_web.c

index f7441a1..ecf8dc8 100644 (file)
@@ -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);
 
index a3ed7b9..49028c7 100644 (file)
@@ -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
index 3f0c2aa..64e72bb 100644 (file)
@@ -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);