bu5hm4n pushed a commit to branch master.

http://git.enlightenment.org/core/efl.git/commit/?id=1a517b4c2db78cf9666f3ffbb10ebb7903654308

commit 1a517b4c2db78cf9666f3ffbb10ebb7903654308
Author: Mike Blumenkrantz <[email protected]>
Date:   Tue Aug 20 13:11:21 2019 -0400

    efl_ui: add scrollable_content mixin
    
    this allows content to be set with a scroller that automatically handles
    its own sizing calcs so that widgets/apps don't have to
    
    @feature
    
    Reviewed-by: Marcel Hollerbach <[email protected]>
    Differential Revision: https://phab.enlightenment.org/D9674
---
 src/lib/elementary/Efl_Ui.h                        |   1 +
 .../elementary/efl_ui_widget_scrollable_content.c  | 192 +++++++++++++++++++++
 .../elementary/efl_ui_widget_scrollable_content.eo |  54 ++++++
 src/lib/elementary/meson.build                     |   2 +
 4 files changed, 249 insertions(+)

diff --git a/src/lib/elementary/Efl_Ui.h b/src/lib/elementary/Efl_Ui.h
index 0f377b7aec..a77a95e333 100644
--- a/src/lib/elementary/Efl_Ui.h
+++ b/src/lib/elementary/Efl_Ui.h
@@ -172,6 +172,7 @@ EAPI void efl_ui_focus_relation_free(Efl_Ui_Focus_Relations 
*rel);
 # include <efl_ui_theme.eo.h>
 # include <efl_config_global.eo.h>
 # include <efl_ui_widget.eo.h>
+# include <efl_ui_widget_scrollable_content.eo.h>
 # include <efl_ui_widget_common.h>
 # include <efl_ui_widget_part.eo.h>
 # include <efl_ui_layout_base.eo.h>
diff --git a/src/lib/elementary/efl_ui_widget_scrollable_content.c 
b/src/lib/elementary/efl_ui_widget_scrollable_content.c
new file mode 100644
index 0000000000..03672fb7a5
--- /dev/null
+++ b/src/lib/elementary/efl_ui_widget_scrollable_content.c
@@ -0,0 +1,192 @@
+#ifdef HAVE_CONFIG_H
+# include "elementary_config.h"
+#endif
+#define EFL_UI_WIDGET_SCROLLABLE_CONTENT_PROTECTED
+#include "elm_priv.h"
+
+#define MY_CLASS EFL_UI_WIDGET_SCROLLABLE_CONTENT_MIXIN
+
+#define MY_CLASS_NAME "Efl_Ui_Widget_Scrollable_Content"
+
+typedef struct Efl_Ui_Widget_Scrollable_Content_Data
+{
+   Eo *scroller;
+   Eina_Bool did_group_calc : 1;
+} Efl_Ui_Widget_Scrollable_Content_Data;
+
+static void
+_scroller_sizing_eval(Eo *obj, Efl_Ui_Widget_Scrollable_Content_Data *pd,
+                      Eina_Size2D obj_min, Eina_Size2D scr_min)
+{
+   Eina_Size2D max_size, min_size, size;
+   max_size = efl_gfx_hint_size_max_get(obj);
+
+   if (max_size.w != -1)
+     max_size.w = (obj_min.w > max_size.w) ? obj_min.w : max_size.w;
+   if (max_size.h != -1)
+     max_size.h = (obj_min.h > max_size.h) ? obj_min.h : max_size.h;
+
+   min_size = efl_gfx_hint_size_min_get(obj);
+
+   size.w = (obj_min.w > min_size.w) ? obj_min.w : min_size.w;
+   size.h = (obj_min.h > min_size.h) ? obj_min.h : min_size.h;
+
+   Eina_Size2D new_min = obj_min;
+
+   if ((max_size.w == -1) && (max_size.h == -1))
+     {
+        efl_ui_scrollable_match_content_set(pd->scroller, EINA_FALSE, 
EINA_FALSE);
+     }
+   else if ((max_size.w == -1) && (max_size.h != -1))
+     {
+        if (max_size.h < scr_min.h)
+          {
+             efl_ui_scrollable_match_content_set(pd->scroller, EINA_FALSE, 
EINA_FALSE);
+             size = EINA_SIZE2D(size.w, max_size.h);
+          }
+        else
+          {
+             new_min.h = scr_min.h;
+             efl_ui_scrollable_match_content_set(pd->scroller, EINA_FALSE, 
EINA_TRUE);
+             size = EINA_SIZE2D(size.w, scr_min.h);
+          }
+     }
+   else if ((max_size.w != -1) && (max_size.h == -1))
+     {
+        if (max_size.w < scr_min.w)
+          {
+             efl_ui_scrollable_match_content_set(pd->scroller, EINA_FALSE, 
EINA_FALSE);
+             size = EINA_SIZE2D(max_size.w, size.h);
+          }
+        else
+          {
+             new_min.w = scr_min.w;
+             efl_ui_scrollable_match_content_set(pd->scroller, EINA_TRUE, 
EINA_FALSE);
+             size = EINA_SIZE2D(scr_min.w, size.h);
+          }
+     }
+   else if ((max_size.w != -1) && (max_size.h != -1))
+     {
+        Eina_Bool min_limit_w = EINA_FALSE;
+        Eina_Bool min_limit_h = EINA_FALSE;
+
+        if (max_size.w < scr_min.w)
+          {
+             size.w = max_size.w;
+          }
+        else
+          {
+             min_limit_w = EINA_TRUE;
+             new_min.w = scr_min.w;
+             size.w = scr_min.w;
+          }
+
+        if (max_size.h < scr_min.h)
+          {
+             size.h = max_size.h;
+          }
+        else
+          {
+             min_limit_h = EINA_TRUE;
+             new_min.h = scr_min.h;
+             size.h = scr_min.h;
+          }
+
+        efl_ui_scrollable_match_content_set(pd->scroller, min_limit_w, 
min_limit_h);
+     }
+   /* this event must come before the scroller recalc in order to ensure the 
scroller has the correct viewport size */
+   efl_event_callback_call(obj, 
EFL_UI_WIDGET_SCROLLABLE_CONTENT_EVENT_OPTIMAL_SIZE_CALC, &size);
+   efl_canvas_group_calculate(pd->scroller);
+
+   efl_gfx_hint_size_restricted_min_set(obj, new_min);
+}
+
+static void
+_sizing_eval(Eo *obj, Efl_Ui_Widget_Scrollable_Content_Data *pd)
+{
+   ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd);
+   Evas_Coord obj_minw = -1, obj_minh = -1;
+   Evas_Coord scr_minw = -1, scr_minh = -1;
+
+   //Calculate popup's min size including scroller's min size
+     {
+        efl_ui_scrollable_match_content_set(pd->scroller, EINA_TRUE, 
EINA_TRUE);
+        efl_canvas_group_calculate(pd->scroller);
+
+        elm_coords_finger_size_adjust(1, &scr_minw, 1, &scr_minh);
+        edje_object_size_min_restricted_calc
+           (wd->resize_obj, &scr_minw, &scr_minh, scr_minw, scr_minh);
+     }
+
+   //Calculate popup's min size except scroller's min size
+     {
+        efl_ui_scrollable_match_content_set(pd->scroller, EINA_FALSE, 
EINA_FALSE);
+        efl_canvas_group_calculate(pd->scroller);
+
+        elm_coords_finger_size_adjust(1, &obj_minw, 1, &obj_minh);
+        edje_object_size_min_restricted_calc
+           (wd->resize_obj, &obj_minw, &obj_minh, obj_minw, obj_minh);
+     }
+   _scroller_sizing_eval(obj, pd, EINA_SIZE2D(obj_minw, obj_minh), 
EINA_SIZE2D(scr_minw, scr_minh));
+}
+
+EOLIAN static void
+_efl_ui_widget_scrollable_content_efl_canvas_group_calculate(Eo *obj, 
Efl_Ui_Widget_Scrollable_Content_Data *pd)
+{
+   pd->did_group_calc = EINA_FALSE;
+   if (!pd->scroller)
+     {
+        efl_canvas_group_calculate(efl_super(obj, MY_CLASS));
+        return;
+     }
+   pd->did_group_calc = EINA_TRUE;
+   _sizing_eval(obj, pd);
+   efl_canvas_group_need_recalculate_set(pd->scroller, EINA_FALSE);
+   efl_canvas_group_need_recalculate_set(obj, EINA_FALSE);
+}
+
+static void
+_scroller_setup(Eo *obj, Efl_Ui_Widget_Scrollable_Content_Data *pd)
+{
+   pd->scroller = efl_add(EFL_UI_SCROLLER_CLASS, obj,
+     efl_ui_widget_style_set(efl_added, "popup/no_inset_shadow")
+     );
+   efl_wref_add(pd->scroller, &pd->scroller);
+   efl_content_set(obj, pd->scroller);
+}
+
+EOLIAN static Eina_Bool
+_efl_ui_widget_scrollable_content_scrollable_content_did_group_calc_get(const 
Eo *obj EINA_UNUSED, Efl_Ui_Widget_Scrollable_Content_Data *pd)
+{
+   return pd->did_group_calc;
+}
+
+EOLIAN static Eina_Bool
+_efl_ui_widget_scrollable_content_scrollable_content_set(Eo *obj, 
Efl_Ui_Widget_Scrollable_Content_Data *pd, Eo *content)
+{
+   Eina_Bool ret;
+
+   if (!pd->scroller)
+     _scroller_setup(obj, pd);
+   ret = efl_content_set(pd->scroller, content);
+   if (ret) efl_canvas_group_change(obj);
+   return ret;
+}
+
+EOLIAN static Eo *
+_efl_ui_widget_scrollable_content_scrollable_content_get(const Eo *obj 
EINA_UNUSED, Efl_Ui_Widget_Scrollable_Content_Data *pd)
+{
+   return efl_content_get(pd->scroller);
+}
+
+EOLIAN static void
+_efl_ui_widget_scrollable_content_efl_object_destructor(Eo *obj, 
Efl_Ui_Widget_Scrollable_Content_Data *pd)
+{
+   if (pd->scroller) efl_wref_del(pd->scroller, &pd->scroller);
+   efl_destructor(efl_super(obj, MY_CLASS));
+}
+
+#define EFL_UI_WIDGET_SCROLLABLE_CONTENT_EXTRA_OPS \
+   EFL_CANVAS_GROUP_CALC_OPS(efl_ui_widget_scrollable_content)
+
+#include "efl_ui_widget_scrollable_content.eo.c"
diff --git a/src/lib/elementary/efl_ui_widget_scrollable_content.eo 
b/src/lib/elementary/efl_ui_widget_scrollable_content.eo
new file mode 100644
index 0000000000..d110f3eaa9
--- /dev/null
+++ b/src/lib/elementary/efl_ui_widget_scrollable_content.eo
@@ -0,0 +1,54 @@
+import eina_types;
+
+mixin @beta Efl.Ui.Widget.Scrollable_Content requires Efl.Object
+{
+   [[Efl widget scrollable content mixin
+
+     This can be used to provide scrollable contents and text for widgets.
+
+     Widgets can set the "__efl_scrollable_content_scroller_style" key data 
during
+     their constructor to apply a style to the internal scroller widget.
+   ]]
+   c_prefix: efl_ui_widget;
+   event_prefix: efl_ui_widget_scrollable_content;
+   data: Efl_Ui_Widget_Scrollable_Content_Data;
+   methods {
+      @property scrollable_content_did_group_calc @protected @beta {
+         [[Widgets can call this function during their 
@Efl.Canvas.Group.group_calculate
+           implementation after the super call to determine whether the 
internal scroller
+           has performed sizing calculations.
+
+           The @.optimal_size,calc event will have been emitted during the 
super call if
+           this method returns $true.
+
+           In the case that this returns $true, it's likely that the widget 
should be completing
+           its internal sizing calculations from the @.optimal_size,calc 
callback using
+
+           `efl_canvas_group_calculate(efl_super(ev->object, 
EFL_UI_WIDGET_SCROLLABLE_CONTENT_MIXIN));`
+
+           in order to skip the scrollable sizing calc.
+         ]]
+         get {}
+         values {
+            did_group_calc: bool; [[Whether the internal scroller has done 
sizing calcs.]]
+         }
+      }
+      @property scrollable_content {
+         [[This is the content which will be placed in the internal scroller.
+         ]]
+         set {
+            return: bool; [[True on success]]
+         }
+         get {}
+         values {
+            content: Efl.Canvas.Object; [[The content object.]]
+         }
+      }
+   }
+   events {
+      optimal_size,calc: Eina.Size2D; [[The optimal size for the widget based 
on scrollable content.]]
+   }
+   implements {
+      Efl.Object.destructor;
+   }
+}
diff --git a/src/lib/elementary/meson.build b/src/lib/elementary/meson.build
index 6e82c93f84..536f00bbde 100644
--- a/src/lib/elementary/meson.build
+++ b/src/lib/elementary/meson.build
@@ -38,6 +38,7 @@ endforeach
 
 pub_eo_files = [
   'efl_ui_widget.eo',
+  'efl_ui_widget_scrollable_content.eo',
   'efl_ui_animation_view.eo',
   'efl_ui_bg.eo',
   'efl_ui_button.eo',
@@ -851,6 +852,7 @@ elementary_src = [
   'elm_view_form.c',
   'elm_web2.c',
   'efl_ui_widget.c',
+  'efl_ui_widget_scrollable_content.c',
   'efl_ui_widget_common.c',
   'efl_ui_win.c',
   'efl_ui_win_inlined.c',

-- 


Reply via email to