<commit_before>
#include "enna.h"
#include "scrollframe.h"

#define thumbscroll_friction 1.0
#define thumbscroll_momentum_threshhold 100
#define thumbscroll_threshhold 4

#define SMART_NAME "enna_scrollframe"
#define API_ENTRY E_Smart_Data *sd; sd = evas_object_smart_data_get(obj); if ((!obj) || (!sd) || (evas_object_type_get(obj) && strcmp(evas_object_type_get(obj), SMART_NAME)))
#define INTERNAL_ENTRY E_Smart_Data *sd; sd = evas_object_smart_data_get(obj); if (!sd) return;
typedef struct _E_Smart_Data E_Smart_Data;

struct _E_Smart_Data
{
   Evas_Coord   x, y, w, h;

   Evas_Object *smart_obj;
   Evas_Object *child_obj;
   Evas_Object *pan_obj;
   Evas_Object *edje_obj;
   Evas_Object *event_obj;

   Enna_Scrollframe_Policy hbar_flags, vbar_flags;

   struct {
      Evas_Coord x, y;
      Evas_Coord sx, sy;
      Evas_Coord dx, dy;
      struct {
	 Evas_Coord    x, y;
	 double        timestamp;
      } history[20];
      double anim_start;
      Ecore_Animator *momentum_animator;
      Evas_Coord locked_x, locked_y;
      unsigned char now : 1;
      unsigned char dragged : 1;
      unsigned char dir_x : 1;
      unsigned char dir_y : 1;
      unsigned char locked : 1;
   } down;

   struct {
      Evas_Coord w, h;
   } child;
   struct {
      Evas_Coord x, y;
   } step, page;

   struct {
      void (*set) (Evas_Object *obj, Evas_Coord x, Evas_Coord y);
      void (*get) (Evas_Object *obj, Evas_Coord *x, Evas_Coord *y);
      void (*max_get) (Evas_Object *obj, Evas_Coord *x, Evas_Coord *y);
      void (*child_size_get) (Evas_Object *obj, Evas_Coord *x, Evas_Coord *y);
   } pan_func;

   Ecore_Animator *animator;
   double scroll_start;
   double scroll_time;
   Evas_Coord scroll_start_x;
   Evas_Coord scroll_start_y;
   Evas_Coord scroll_to_x;
   Evas_Coord scroll_to_y;
   unsigned char hbar_visible : 1;
   unsigned char vbar_visible : 1;
   unsigned char extern_pan : 1;
   unsigned char one_dir_at_a_time : 1;
};

/* local subsystem functions */
static void _e_smart_child_del_hook(void *data, Evas *e, Evas_Object *obj, void *event_info);
static void _e_smart_pan_changed_hook(void *data, Evas_Object *obj, void *event_info);
static void _e_smart_pan_pan_changed_hook(void *data, Evas_Object *obj, void *event_info);
static void _e_smart_event_wheel(void *data, Evas *e, Evas_Object *obj, void *event_info);
static void _e_smart_event_mouse_down(void *data, Evas *e, Evas_Object *obj, void *event_info);
static int  _e_smart_momentum_animator(void *data);
static void _e_smart_event_mouse_up(void *data, Evas *e, Evas_Object *obj, void *event_info);
static void _e_smart_event_mouse_move(void *data, Evas *e, Evas_Object *obj, void *event_info);
static void _e_smart_event_key_down(void *data, Evas *e, Evas_Object *obj, void *event_info);
static void _e_smart_edje_drag_v(void *data, Evas_Object *obj, const char *emission, const char *source);
static void _e_smart_edje_drag_h(void *data, Evas_Object *obj, const char *emission, const char *source);
static void _e_smart_scrollbar_read(E_Smart_Data *sd);
static void _e_smart_scrollbar_reset(E_Smart_Data *sd);
static int  _e_smart_scrollbar_bar_h_visibility_adjust(E_Smart_Data *sd);
static int  _e_smart_scrollbar_bar_v_visibility_adjust(E_Smart_Data *sd);
static void _e_smart_scrollbar_bar_visibility_adjust(E_Smart_Data *sd);
static void _e_smart_scrollbar_size_adjust(E_Smart_Data *sd);
static void _e_smart_reconfigure(E_Smart_Data *sd);
static void _e_smart_add(Evas_Object *obj);
static void _e_smart_del(Evas_Object *obj);
static void _e_smart_move(Evas_Object *obj, Evas_Coord x, Evas_Coord y);
static void _e_smart_resize(Evas_Object *obj, Evas_Coord w, Evas_Coord h);
static void _e_smart_show(Evas_Object *obj);
static void _e_smart_hide(Evas_Object *obj);
static void _e_smart_color_set(Evas_Object *obj, int r, int g, int b, int a);
static void _e_smart_clip_set(Evas_Object *obj, Evas_Object * clip);
static void _e_smart_clip_unset(Evas_Object *obj);
static void _e_smart_init(void);

/* local subsystem globals */
static Evas_Smart *_e_smart = NULL;

/* externally accessible functions */
EAPI Evas_Object *
enna_scrollframe_add(Evas *evas)
{
   _e_smart_init();
   return evas_object_smart_add(evas, _e_smart);
}

EAPI void
enna_scrollframe_child_set(Evas_Object *obj, Evas_Object *child)
{
   Evas_Coord w, h;
   Evas_Object *o;

   API_ENTRY return;
   if (sd->child_obj)
     {
	enna_pan_child_set(sd->pan_obj, NULL);
	evas_object_event_callback_del(sd->child_obj, EVAS_CALLBACK_FREE, _e_smart_child_del_hook);
     }

   sd->child_obj = child;
   if (!child) return;

   if (!sd->pan_obj)
     {
	o = enna_pan_add(evas_object_evas_get(obj));
	sd->pan_obj = o;
	evas_object_smart_callback_add(o, "changed", _e_smart_pan_changed_hook, sd);
	evas_object_smart_callback_add(o, "pan_changed", _e_smart_pan_pan_changed_hook, sd);
	evas_object_show(o);
	edje_object_part_swallow(sd->edje_obj, "e.swallow.content", o);
     }

   sd->pan_func.set = enna_pan_set;
   sd->pan_func.get = enna_pan_get;
   sd->pan_func.max_get = enna_pan_max_get;
   sd->pan_func.child_size_get = enna_pan_child_size_get;

   evas_object_event_callback_add(child, EVAS_CALLBACK_FREE, _e_smart_child_del_hook, sd);
   enna_pan_child_set(sd->pan_obj, sd->child_obj);
   sd->pan_func.child_size_get(sd->pan_obj, &w, &h);
   sd->child.w = w;
   sd->child.h = h;
   _e_smart_scrollbar_size_adjust(sd);
   _e_smart_scrollbar_reset(sd);
}

EAPI void
enna_scrollframe_extern_pan_set(Evas_Object *obj, Evas_Object *pan,
				void (*pan_set) (Evas_Object *obj, Evas_Coord x, Evas_Coord y),
				void (*pan_get) (Evas_Object *obj, Evas_Coord *x, Evas_Coord *y),
				void (*pan_max_get) (Evas_Object *obj, Evas_Coord *x, Evas_Coord *y),
				void (*pan_child_size_get) (Evas_Object *obj, Evas_Coord *x, Evas_Coord *y))
{
   API_ENTRY return;

   enna_scrollframe_child_set(obj, NULL);
   if (sd->extern_pan)
     {
	if (sd->pan_obj)
	  {
	     edje_object_part_unswallow(sd->edje_obj, sd->pan_obj);
	     sd->pan_obj = NULL;
	  }
     }
   else
     {
	if (sd->pan_obj)
	  {
	     evas_object_del(sd->pan_obj);
	     sd->pan_obj = NULL;
	  }
     }
   if (!pan)
     {
	sd->extern_pan = 0;
	return;
     }

   sd->pan_obj = pan;
   sd->pan_func.set = pan_set;
   sd->pan_func.get = pan_get;
   sd->pan_func.max_get = pan_max_get;
   sd->pan_func.child_size_get = pan_child_size_get;
   sd->extern_pan = 1;
   evas_object_smart_callback_add(sd->pan_obj, "changed", _e_smart_pan_changed_hook, sd);
   evas_object_smart_callback_add(sd->pan_obj, "pan_changed", _e_smart_pan_pan_changed_hook, sd);
   edje_object_part_swallow(sd->edje_obj, "e.swallow.content", sd->pan_obj);
   evas_object_show(sd->pan_obj);
}

EAPI void
enna_scrollframe_custom_theme_set(Evas_Object *obj, char *custom_category, char *custom_group)
{
   API_ENTRY return;

   edje_object_file_set(sd->edje_obj, enna_config_theme_get(), "e/widgets/scrollframe");
   if (sd->pan_obj)
     edje_object_part_swallow(sd->edje_obj, "e.swallow.content", sd->pan_obj);
   sd->vbar_visible = !sd->vbar_visible;
   sd->hbar_visible = !sd->hbar_visible;
   _e_smart_scrollbar_bar_visibility_adjust(sd);
}

EAPI void
enna_scrollframe_custom_edje_file_set(Evas_Object *obj, char *file, char *group)
{
   API_ENTRY return;

   edje_object_file_set(sd->edje_obj, enna_config_theme_get(), "e/widgets/scrollframe");
   if (sd->pan_obj)
     edje_object_part_swallow(sd->edje_obj, "e.swallow.content", sd->pan_obj);
   sd->vbar_visible = !sd->vbar_visible;
   sd->hbar_visible = !sd->hbar_visible;
   _e_smart_scrollbar_bar_visibility_adjust(sd);
}

EAPI void
enna_scrollframe_child_pos_set(Evas_Object *obj, Evas_Coord x, Evas_Coord y)
{
   Evas_Coord mx = 0, my = 0;
   double vx, vy;

   API_ENTRY return;
   sd->pan_func.max_get(sd->pan_obj, &mx, &my);
   if (mx > 0) vx = (double)x / (double)mx;
   else vx = 0.0;
   if (vx < 0.0) vx = 0.0;
   else if (vx > 1.0) vx = 1.0;
   if (my > 0) vy = (double)y / (double)my;
   else vy = 0.0;
   if (vy < 0.0) vy = 0.0;
   else if (vy > 1.0) vy = 1.0;
   edje_object_part_drag_value_set(sd->edje_obj, "e.dragable.vbar", 0.0, vy);
   edje_object_part_drag_value_set(sd->edje_obj, "e.dragable.hbar", vx, 0.0);
   sd->pan_func.set(sd->pan_obj, x, y);
}

EAPI void
enna_scrollframe_child_pos_get(Evas_Object *obj, Evas_Coord *x, Evas_Coord *y)
{
   API_ENTRY return;
   sd->pan_func.get(sd->pan_obj, x, y);
}

static int
_e_smart_animator_cb(void *data)
{
   double t;
   E_Smart_Data *sd;
   Evas_Coord x,y;
   sd = data;
   t = (ecore_time_get() - sd->scroll_start) / sd->scroll_time;
   if (t > 1.0) t = 1.0;
   t = 1.0 - t;
   t = 1.0 - (t * t * t * t); /* more t's - more curve */
   if (t > 1.0) t = 1.0;
   x = sd->scroll_start_x + (t * (sd->scroll_to_x - sd->scroll_start_x));
   y = sd->scroll_start_y + (t * (sd->scroll_to_x - sd->scroll_start_x));

   enna_scrollframe_child_pos_set(sd->smart_obj, x, y);

   if (t >= 1.0)
     {
	sd->animator = NULL;
	return 0;
     }
   return 1;


}

EAPI void
enna_scrollframe_child_region_show(Evas_Object *obj, Evas_Coord x, Evas_Coord y, Evas_Coord w, Evas_Coord h)
{
   Evas_Coord mx = 0, my = 0, cw = 0, ch = 0, px = 0, py = 0, nx, ny;

   API_ENTRY return;
   sd->pan_func.max_get(sd->pan_obj, &mx, &my);
   sd->pan_func.child_size_get(sd->pan_obj, &cw, &ch);
   sd->pan_func.get(sd->pan_obj, &px, &py);

   nx = px;
   if (x < px) nx = x;
   else if ((x + w) > (px + (cw - mx)))
     {
	nx = x + w - (cw - mx);
	if (nx > x) nx = x;
     }
   ny = py;
   if (y < py) ny = y;
   else if ((y + h) > (py + (ch - my)))
     {
	ny = y + h - (ch - my);
	if (ny > y) ny = y;
     }
   if ((nx == px) && (ny == py)) return;

   sd->scroll_to_x = nx;
   sd->scroll_to_y = ny;
   sd->scroll_start_x = px;
   sd->scroll_start_y = py;
   sd->scroll_start = ecore_time_get();
   sd->scroll_time = 0.5;
   sd->animator = ecore_animator_add(_e_smart_animator_cb,sd);


   //enna_scrollframe_child_pos_set(obj, nx, ny);
}

EAPI void
enna_scrollframe_child_viewport_size_get(Evas_Object *obj, Evas_Coord *w, Evas_Coord *h)
{
   API_ENTRY return;
   edje_object_calc_force(sd->edje_obj);
   evas_object_geometry_get(sd->pan_obj, NULL, NULL, w, h);
}

EAPI void
enna_scrollframe_step_size_set(Evas_Object *obj, Evas_Coord x, Evas_Coord y)
{
   API_ENTRY return;
   if (x < 1) x = 1;
   if (y < 1) y = 1;
   sd->step.x = x;
   sd->step.y = y;
   _e_smart_scrollbar_size_adjust(sd);
}

EAPI void
enna_scrollframe_step_size_get(Evas_Object *obj, Evas_Coord *x, Evas_Coord *y)
{
   API_ENTRY return;
   if (x) *x = sd->step.x;
   if (y) *y = sd->step.y;
}

EAPI void
enna_scrollframe_page_size_set(Evas_Object *obj, Evas_Coord x, Evas_Coord y)
{
   API_ENTRY return;
   sd->page.x = x;
   sd->page.y = y;
   _e_smart_scrollbar_size_adjust(sd);
}

EAPI void
enna_scrollframe_page_size_get(Evas_Object *obj, Evas_Coord *x, Evas_Coord *y)
{
   API_ENTRY return;
   if (x) *x = sd->page.x;
   if (y) *y = sd->page.y;
}

EAPI void
enna_scrollframe_policy_set(Evas_Object *obj, Enna_Scrollframe_Policy hbar, Enna_Scrollframe_Policy vbar)
{
   API_ENTRY return;
   if ((sd->hbar_flags == hbar) && (sd->vbar_flags == vbar)) return;
   sd->hbar_flags = hbar;
   sd->vbar_flags = vbar;
   _e_smart_scrollbar_size_adjust(sd);
}

EAPI void
enna_scrollframe_policy_get(Evas_Object *obj, Enna_Scrollframe_Policy *hbar, Enna_Scrollframe_Policy *vbar)
{
   API_ENTRY return;
   if (hbar) *hbar = sd->hbar_flags;
   if (vbar) *vbar = sd->vbar_flags;
}

EAPI Evas_Object *
enna_scrollframe_edje_object_get(Evas_Object *obj)
{
   API_ENTRY return NULL;
   return sd->edje_obj;
}

EAPI void
enna_scrollframe_single_dir_set(Evas_Object *obj, Evas_Bool single_dir)
{
   API_ENTRY return;
   sd->one_dir_at_a_time = single_dir;
}

EAPI Evas_Bool
enna_scrollframe_single_dir_get(Evas_Object *obj)
{
   API_ENTRY return 0;
   return sd->one_dir_at_a_time;
}

/* local subsystem functions */
static void
_e_smart_edje_drag_v(void *data, Evas_Object *obj, const char *emission, const char *source)
{
   E_Smart_Data *sd;

   sd = data;
   _e_smart_scrollbar_read(sd);
}

static void
_e_smart_edje_drag_h(void *data, Evas_Object *obj, const char *emission, const char *source)
{
   E_Smart_Data *sd;

   sd = data;
   _e_smart_scrollbar_read(sd);
}

static void
_e_smart_child_del_hook(void *data, Evas *e, Evas_Object *obj, void *event_info)
{
   E_Smart_Data *sd;

   sd = data;
   sd->child_obj = NULL;
   _e_smart_scrollbar_size_adjust(sd);
   _e_smart_scrollbar_reset(sd);
}

static void
_e_smart_pan_changed_hook(void *data, Evas_Object *obj, void *event_info)
{
   Evas_Coord w, h;
   E_Smart_Data *sd;

   sd = data;
   sd->pan_func.child_size_get(sd->pan_obj, &w, &h);
   if ((w != sd->child.w) || (h != sd->child.h))
     {
	sd->child.w = w;
	sd->child.h = h;
	_e_smart_scrollbar_size_adjust(sd);
     }
}

static void
_e_smart_pan_pan_changed_hook(void *data, Evas_Object *obj, void *event_info)
{
   Evas_Coord x, y;
   E_Smart_Data *sd;

   sd = data;
   sd->pan_func.get(sd->pan_obj, &x, &y);
   enna_scrollframe_child_pos_set(sd->smart_obj, x, y);
}

static void
_e_smart_event_wheel(void *data, Evas *e, Evas_Object *obj, void *event_info)
{
   Evas_Event_Mouse_Wheel *ev;
   E_Smart_Data *sd;
   Evas_Coord x = 0, y = 0;

   sd = data;
   ev = event_info;
   enna_scrollframe_child_pos_get(sd->smart_obj, &x, &y);
   y += ev->z * sd->step.y;
   enna_scrollframe_child_pos_set(sd->smart_obj, x, y);
}

static void
_e_smart_event_mouse_down(void *data, Evas *e, Evas_Object *obj, void *event_info)
{
   Evas_Event_Mouse_Down *ev;
   E_Smart_Data *sd;
   Evas_Coord x = 0, y = 0;

   sd = data;
   ev = event_info;



   if (sd->down.momentum_animator)
     {
	ecore_animator_del(sd->down.momentum_animator);
	sd->down.momentum_animator = NULL;
     }
   if (ev->button == 1)
     {
	sd->down.now = 1;
	sd->down.dragged = 0;
	sd->down.dir_x = 0;
	sd->down.dir_y = 0;
	sd->down.x = ev->canvas.x;
	sd->down.y = ev->canvas.y;
	enna_scrollframe_child_pos_get(sd->smart_obj, &x, &y);
	sd->down.sx = x;
	sd->down.sy = y;
	sd->down.locked = 0;
	memset(&(sd->down.history[0]), 0, sizeof(sd->down.history[0]) * 20);
	sd->down.history[0].timestamp = ecore_time_get();
	sd->down.history[0].x = ev->canvas.x;
	sd->down.history[0].y = ev->canvas.y;
     }

}

static int
_e_smart_momentum_animator(void *data)
{
   E_Smart_Data *sd;
   double t, dt, p;
   Evas_Coord x, y, dx, dy;

   sd = data;
   t = ecore_time_get();
   dt = t - sd->down.anim_start;

   if (dt >= 0.0)
     {
	dt = dt / thumbscroll_friction;
	if (dt > 1.0) dt = 1.0;
	p = 1.0 - ((1.0 - dt) * (1.0 - dt) * (1.0 - dt));
	dx = (sd->down.dx * thumbscroll_friction * p);
	dy = (sd->down.dy * thumbscroll_friction * p);
	x = sd->down.sx - dx;
	y = sd->down.sy - dy;
	enna_scrollframe_child_pos_set(sd->smart_obj, x, y);
	if (dt >= 1.0)
	  {
	     sd->down.momentum_animator = NULL;
	     edje_object_signal_emit(sd->edje_obj, "e,action,hide,vbar", "e");
	     return 0;
	  }
     }
   return 1;
}

static void
_e_smart_event_mouse_up(void *data, Evas *e, Evas_Object *obj, void *event_info)
{
   Evas_Event_Mouse_Down *ev;
   E_Smart_Data *sd;
   Evas_Coord x = 0, y = 0;

   sd = data;
   ev = event_info;


   if (ev->button == 1)
     {
	x = ev->canvas.x - sd->down.x;
	y = ev->canvas.y - sd->down.y;
	if (sd->down.dragged)
	  {
	     double t, at, dt;
	     int i;
	     Evas_Coord ax, ay, dx, dy, vel;

	     t = ecore_time_get();
	     ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
	     ax = ev->canvas.x;
	     ay = ev->canvas.y;
	     at = 0.0;
	     for (i = 0; i < 20; i++)
	       {
		  dt = t - sd->down.history[i].timestamp;
		  if (dt > 0.2) break;
		  at += dt;
		  ax += sd->down.history[i].x;
		  ay += sd->down.history[i].y;
	       }
	     ax /= (i + 1);
	     ay /= (i + 1);
	     at /= (i + 1);
	     at *= 4.0;
	     dx = ev->canvas.x - ax;
	     dy = ev->canvas.y - ay;
	     if (at > 0)
	       {
		  vel = sqrt((dx * dx) + (dy * dy)) / at;
		  if ((thumbscroll_friction > 0.0) &&
		      (vel > thumbscroll_momentum_threshhold))
		    {
		       if (!sd->down.momentum_animator)
			 sd->down.momentum_animator = ecore_animator_add(_e_smart_momentum_animator, sd);
		       sd->down.dx = ((double)dx / at);
		       sd->down.dy = ((double)dy / at);
		       sd->down.anim_start = t;
		       enna_scrollframe_child_pos_get(sd->smart_obj, &x, &y);
		       sd->down.sx = x;
		       sd->down.sy = y;
		    }
	       }
	     evas_event_feed_hold(e, 0, ev->timestamp, ev->data);
	  }
	sd->down.dragged = 0;
	sd->down.now = 0;
     }

}

static void
_e_smart_event_mouse_move(void *data, Evas *e, Evas_Object *obj, void *event_info)
{
   Evas_Event_Mouse_Move *ev;
   E_Smart_Data *sd;
   Evas_Coord x = 0, y = 0;

   sd = data;
   ev = event_info;


   if (sd->down.now)
     {
	memmove(&(sd->down.history[1]), &(sd->down.history[0]),
		sizeof(sd->down.history[0]) * 19);
	sd->down.history[0].timestamp = ecore_time_get();
	sd->down.history[0].x = ev->cur.canvas.x;
	sd->down.history[0].y = ev->cur.canvas.y;

	x = ev->cur.canvas.x - sd->down.x;
	if (x < 0) x = -x;
	y = ev->cur.canvas.y - sd->down.y;<commit_msg>[svn] HBar list visibility correction<commit_after>
#include "enna.h"
#include "scrollframe.h"

#define thumbscroll_friction 1.0
#define thumbscroll_momentum_threshhold 100
#define thumbscroll_threshhold 4

#define SMART_NAME "enna_scrollframe"
#define API_ENTRY E_Smart_Data *sd; sd = evas_object_smart_data_get(obj); if ((!obj) || (!sd) || (evas_object_type_get(obj) && strcmp(evas_object_type_get(obj), SMART_NAME)))
#define INTERNAL_ENTRY E_Smart_Data *sd; sd = evas_object_smart_data_get(obj); if (!sd) return;
typedef struct _E_Smart_Data E_Smart_Data;

struct _E_Smart_Data
{
   Evas_Coord   x, y, w, h;

   Evas_Object *smart_obj;
   Evas_Object *child_obj;
   Evas_Object *pan_obj;
   Evas_Object *edje_obj;
   Evas_Object *event_obj;

   Enna_Scrollframe_Policy hbar_flags, vbar_flags;

   struct {
      Evas_Coord x, y;
      Evas_Coord sx, sy;
      Evas_Coord dx, dy;
      struct {
	 Evas_Coord    x, y;
	 double        timestamp;
      } history[20];
      double anim_start;
      Ecore_Animator *momentum_animator;
      Evas_Coord locked_x, locked_y;
      unsigned char now : 1;
      unsigned char dragged : 1;
      unsigned char dir_x : 1;
      unsigned char dir_y : 1;
      unsigned char locked : 1;
   } down;

   struct {
      Evas_Coord w, h;
   } child;
   struct {
      Evas_Coord x, y;
   } step, page;

   struct {
      void (*set) (Evas_Object *obj, Evas_Coord x, Evas_Coord y);
      void (*get) (Evas_Object *obj, Evas_Coord *x, Evas_Coord *y);
      void (*max_get) (Evas_Object *obj, Evas_Coord *x, Evas_Coord *y);
      void (*child_size_get) (Evas_Object *obj, Evas_Coord *x, Evas_Coord *y);
   } pan_func;

   Ecore_Animator *animator;
   double scroll_start;
   double scroll_time;
   Evas_Coord scroll_start_x;
   Evas_Coord scroll_start_y;
   Evas_Coord scroll_to_x;
   Evas_Coord scroll_to_y;
   unsigned char hbar_visible : 1;
   unsigned char vbar_visible : 1;
   unsigned char extern_pan : 1;
   unsigned char one_dir_at_a_time : 1;
};

/* local subsystem functions */
static void _e_smart_child_del_hook(void *data, Evas *e, Evas_Object *obj, void *event_info);
static void _e_smart_pan_changed_hook(void *data, Evas_Object *obj, void *event_info);
static void _e_smart_pan_pan_changed_hook(void *data, Evas_Object *obj, void *event_info);
static void _e_smart_event_wheel(void *data, Evas *e, Evas_Object *obj, void *event_info);
static void _e_smart_event_mouse_down(void *data, Evas *e, Evas_Object *obj, void *event_info);
static int  _e_smart_momentum_animator(void *data);
static void _e_smart_event_mouse_up(void *data, Evas *e, Evas_Object *obj, void *event_info);
static void _e_smart_event_mouse_move(void *data, Evas *e, Evas_Object *obj, void *event_info);
static void _e_smart_event_key_down(void *data, Evas *e, Evas_Object *obj, void *event_info);
static void _e_smart_edje_drag_v(void *data, Evas_Object *obj, const char *emission, const char *source);
static void _e_smart_edje_drag_h(void *data, Evas_Object *obj, const char *emission, const char *source);
static void _e_smart_scrollbar_read(E_Smart_Data *sd);
static void _e_smart_scrollbar_reset(E_Smart_Data *sd);
static int  _e_smart_scrollbar_bar_h_visibility_adjust(E_Smart_Data *sd);
static int  _e_smart_scrollbar_bar_v_visibility_adjust(E_Smart_Data *sd);
static void _e_smart_scrollbar_bar_visibility_adjust(E_Smart_Data *sd);
static void _e_smart_scrollbar_size_adjust(E_Smart_Data *sd);
static void _e_smart_reconfigure(E_Smart_Data *sd);
static void _e_smart_add(Evas_Object *obj);
static void _e_smart_del(Evas_Object *obj);
static void _e_smart_move(Evas_Object *obj, Evas_Coord x, Evas_Coord y);
static void _e_smart_resize(Evas_Object *obj, Evas_Coord w, Evas_Coord h);
static void _e_smart_show(Evas_Object *obj);
static void _e_smart_hide(Evas_Object *obj);
static void _e_smart_color_set(Evas_Object *obj, int r, int g, int b, int a);
static void _e_smart_clip_set(Evas_Object *obj, Evas_Object * clip);
static void _e_smart_clip_unset(Evas_Object *obj);
static void _e_smart_init(void);

/* local subsystem globals */
static Evas_Smart *_e_smart = NULL;

/* externally accessible functions */
EAPI Evas_Object *
enna_scrollframe_add(Evas *evas)
{
   _e_smart_init();
   return evas_object_smart_add(evas, _e_smart);
}

EAPI void
enna_scrollframe_child_set(Evas_Object *obj, Evas_Object *child)
{
   Evas_Coord w, h;
   Evas_Object *o;

   API_ENTRY return;
   if (sd->child_obj)
     {
	enna_pan_child_set(sd->pan_obj, NULL);
	evas_object_event_callback_del(sd->child_obj, EVAS_CALLBACK_FREE, _e_smart_child_del_hook);
     }

   sd->child_obj = child;
   if (!child) return;

   if (!sd->pan_obj)
     {
	o = enna_pan_add(evas_object_evas_get(obj));
	sd->pan_obj = o;
	evas_object_smart_callback_add(o, "changed", _e_smart_pan_changed_hook, sd);
	evas_object_smart_callback_add(o, "pan_changed", _e_smart_pan_pan_changed_hook, sd);
	evas_object_show(o);
	edje_object_part_swallow(sd->edje_obj, "e.swallow.content", o);
     }

   sd->pan_func.set = enna_pan_set;
   sd->pan_func.get = enna_pan_get;
   sd->pan_func.max_get = enna_pan_max_get;
   sd->pan_func.child_size_get = enna_pan_child_size_get;

   evas_object_event_callback_add(child, EVAS_CALLBACK_FREE, _e_smart_child_del_hook, sd);
   enna_pan_child_set(sd->pan_obj, sd->child_obj);
   sd->pan_func.child_size_get(sd->pan_obj, &w, &h);
   sd->child.w = w;
   sd->child.h = h;
   _e_smart_scrollbar_size_adjust(sd);
   _e_smart_scrollbar_reset(sd);
}

EAPI void
enna_scrollframe_extern_pan_set(Evas_Object *obj, Evas_Object *pan,
				void (*pan_set) (Evas_Object *obj, Evas_Coord x, Evas_Coord y),
				void (*pan_get) (Evas_Object *obj, Evas_Coord *x, Evas_Coord *y),
				void (*pan_max_get) (Evas_Object *obj, Evas_Coord *x, Evas_Coord *y),
				void (*pan_child_size_get) (Evas_Object *obj, Evas_Coord *x, Evas_Coord *y))
{
   API_ENTRY return;

   enna_scrollframe_child_set(obj, NULL);
   if (sd->extern_pan)
     {
	if (sd->pan_obj)
	  {
	     edje_object_part_unswallow(sd->edje_obj, sd->pan_obj);
	     sd->pan_obj = NULL;
	  }
     }
   else
     {
	if (sd->pan_obj)
	  {
	     evas_object_del(sd->pan_obj);
	     sd->pan_obj = NULL;
	  }
     }
   if (!pan)
     {
	sd->extern_pan = 0;
	return;
     }

   sd->pan_obj = pan;
   sd->pan_func.set = pan_set;
   sd->pan_func.get = pan_get;
   sd->pan_func.max_get = pan_max_get;
   sd->pan_func.child_size_get = pan_child_size_get;
   sd->extern_pan = 1;
   evas_object_smart_callback_add(sd->pan_obj, "changed", _e_smart_pan_changed_hook, sd);
   evas_object_smart_callback_add(sd->pan_obj, "pan_changed", _e_smart_pan_pan_changed_hook, sd);
   edje_object_part_swallow(sd->edje_obj, "e.swallow.content", sd->pan_obj);
   evas_object_show(sd->pan_obj);
}

EAPI void
enna_scrollframe_custom_theme_set(Evas_Object *obj, char *custom_category, char *custom_group)
{
   API_ENTRY return;

   edje_object_file_set(sd->edje_obj, enna_config_theme_get(), "e/widgets/scrollframe");
   if (sd->pan_obj)
     edje_object_part_swallow(sd->edje_obj, "e.swallow.content", sd->pan_obj);
   sd->vbar_visible = !sd->vbar_visible;
   sd->hbar_visible = !sd->hbar_visible;
   _e_smart_scrollbar_bar_visibility_adjust(sd);
}

EAPI void
enna_scrollframe_custom_edje_file_set(Evas_Object *obj, char *file, char *group)
{
   API_ENTRY return;

   edje_object_file_set(sd->edje_obj, enna_config_theme_get(), "e/widgets/scrollframe");
   if (sd->pan_obj)
     edje_object_part_swallow(sd->edje_obj, "e.swallow.content", sd->pan_obj);
   sd->vbar_visible = !sd->vbar_visible;
   sd->hbar_visible = !sd->hbar_visible;
   _e_smart_scrollbar_bar_visibility_adjust(sd);
}

EAPI void
enna_scrollframe_child_pos_set(Evas_Object *obj, Evas_Coord x, Evas_Coord y)
{
   Evas_Coord mx = 0, my = 0;
   double vx, vy;

   API_ENTRY return;
   sd->pan_func.max_get(sd->pan_obj, &mx, &my);
   if (mx > 0) vx = (double)x / (double)mx;
   else vx = 0.0;
   if (vx < 0.0) vx = 0.0;
   else if (vx > 1.0) vx = 1.0;
   if (my > 0) vy = (double)y / (double)my;
   else vy = 0.0;
   if (vy < 0.0) vy = 0.0;
   else if (vy > 1.0) vy = 1.0;
   edje_object_part_drag_value_set(sd->edje_obj, "e.dragable.vbar", 0.0, vy);
   edje_object_part_drag_value_set(sd->edje_obj, "e.dragable.hbar", vx, 0.0);
   sd->pan_func.set(sd->pan_obj, x, y);
}

EAPI void
enna_scrollframe_child_pos_get(Evas_Object *obj, Evas_Coord *x, Evas_Coord *y)
{
   API_ENTRY return;
   sd->pan_func.get(sd->pan_obj, x, y);
}

static int
_e_smart_animator_cb(void *data)
{
   double t;
   E_Smart_Data *sd;
   Evas_Coord x,y;
   sd = data;
   t = (ecore_time_get() - sd->scroll_start) / sd->scroll_time;
   if (t > 1.0) t = 1.0;
   t = 1.0 - t;
   t = 1.0 - (t * t * t * t); /* more t's - more curve */
   if (t > 1.0) t = 1.0;
   x = sd->scroll_start_x + (t * (sd->scroll_to_x - sd->scroll_start_x));
   y = sd->scroll_start_y + (t * (sd->scroll_to_x - sd->scroll_start_x));

   enna_scrollframe_child_pos_set(sd->smart_obj, x, y);

   if (t >= 1.0)
     {
	sd->animator = NULL;
	return 0;
     }
   return 1;


}

EAPI void
enna_scrollframe_child_region_show(Evas_Object *obj, Evas_Coord x, Evas_Coord y, Evas_Coord w, Evas_Coord h)
{
   Evas_Coord mx = 0, my = 0, cw = 0, ch = 0, px = 0, py = 0, nx, ny;

   API_ENTRY return;
   sd->pan_func.max_get(sd->pan_obj, &mx, &my);
   sd->pan_func.child_size_get(sd->pan_obj, &cw, &ch);
   sd->pan_func.get(sd->pan_obj, &px, &py);

   nx = px;
   if (x < px) nx = x;
   else if ((x + w) > (px + (cw - mx)))
     {
	nx = x + w - (cw - mx);
	if (nx > x) nx = x;
     }
   ny = py;
   if (y < py) ny = y;
   else if ((y + h) > (py + (ch - my)))
     {
	ny = y + h - (ch - my);
	if (ny > y) ny = y;
     }
   if ((nx == px) && (ny == py)) return;

   sd->scroll_to_x = nx;
   sd->scroll_to_y = ny;
   sd->scroll_start_x = px;
   sd->scroll_start_y = py;
   sd->scroll_start = ecore_time_get();
   sd->scroll_time = 0.5;
   sd->animator = ecore_animator_add(_e_smart_animator_cb,sd);


   //enna_scrollframe_child_pos_set(obj, nx, ny);
}

EAPI void
enna_scrollframe_child_viewport_size_get(Evas_Object *obj, Evas_Coord *w, Evas_Coord *h)
{
   API_ENTRY return;
   edje_object_calc_force(sd->edje_obj);
   evas_object_geometry_get(sd->pan_obj, NULL, NULL, w, h);
}

EAPI void
enna_scrollframe_step_size_set(Evas_Object *obj, Evas_Coord x, Evas_Coord y)
{
   API_ENTRY return;
   if (x < 1) x = 1;
   if (y < 1) y = 1;
   sd->step.x = x;
   sd->step.y = y;
   _e_smart_scrollbar_size_adjust(sd);
}

EAPI void
enna_scrollframe_step_size_get(Evas_Object *obj, Evas_Coord *x, Evas_Coord *y)
{
   API_ENTRY return;
   if (x) *x = sd->step.x;
   if (y) *y = sd->step.y;
}

EAPI void
enna_scrollframe_page_size_set(Evas_Object *obj, Evas_Coord x, Evas_Coord y)
{
   API_ENTRY return;
   sd->page.x = x;
   sd->page.y = y;
   _e_smart_scrollbar_size_adjust(sd);
}

EAPI void
enna_scrollframe_page_size_get(Evas_Object *obj, Evas_Coord *x, Evas_Coord *y)
{
   API_ENTRY return;
   if (x) *x = sd->page.x;
   if (y) *y = sd->page.y;
}

EAPI void
enna_scrollframe_policy_set(Evas_Object *obj, Enna_Scrollframe_Policy hbar, Enna_Scrollframe_Policy vbar)
{
   API_ENTRY return;
   if ((sd->hbar_flags == hbar) && (sd->vbar_flags == vbar)) return;
   sd->hbar_flags = hbar;
   sd->vbar_flags = vbar;
   _e_smart_scrollbar_size_adjust(sd);
}

EAPI void
enna_scrollframe_policy_get(Evas_Object *obj, Enna_Scrollframe_Policy *hbar, Enna_Scrollframe_Policy *vbar)
{
   API_ENTRY return;
   if (hbar) *hbar = sd->hbar_flags;
   if (vbar) *vbar = sd->vbar_flags;
}

EAPI Evas_Object *
enna_scrollframe_edje_object_get(Evas_Object *obj)
{
   API_ENTRY return NULL;
   return sd->edje_obj;
}

EAPI void
enna_scrollframe_single_dir_set(Evas_Object *obj, Evas_Bool single_dir)
{
   API_ENTRY return;
   sd->one_dir_at_a_time = single_dir;
}

EAPI Evas_Bool
enna_scrollframe_single_dir_get(Evas_Object *obj)
{
   API_ENTRY return 0;
   return sd->one_dir_at_a_time;
}

/* local subsystem functions */
static void
_e_smart_edje_drag_v(void *data, Evas_Object *obj, const char *emission, const char *source)
{
   E_Smart_Data *sd;

   sd = data;
   _e_smart_scrollbar_read(sd);
}

static void
_e_smart_edje_drag_h(void *data, Evas_Object *obj, const char *emission, const char *source)
{
   E_Smart_Data *sd;

   sd = data;
   _e_smart_scrollbar_read(sd);
}

static void
_e_smart_child_del_hook(void *data, Evas *e, Evas_Object *obj, void *event_info)
{
   E_Smart_Data *sd;

   sd = data;
   sd->child_obj = NULL;
   _e_smart_scrollbar_size_adjust(sd);
   _e_smart_scrollbar_reset(sd);
}

static void
_e_smart_pan_changed_hook(void *data, Evas_Object *obj, void *event_info)
{
   Evas_Coord w, h;
   E_Smart_Data *sd;

   sd = data;
   sd->pan_func.child_size_get(sd->pan_obj, &w, &h);
   if ((w != sd->child.w) || (h != sd->child.h))
     {
	sd->child.w = w;
	sd->child.h = h;
	_e_smart_scrollbar_size_adjust(sd);
     }
}

static void
_e_smart_pan_pan_changed_hook(void *data, Evas_Object *obj, void *event_info)
{
   Evas_Coord x, y;
   E_Smart_Data *sd;

   sd = data;
   sd->pan_func.get(sd->pan_obj, &x, &y);
   enna_scrollframe_child_pos_set(sd->smart_obj, x, y);
}

static void
_e_smart_event_wheel(void *data, Evas *e, Evas_Object *obj, void *event_info)
{
   Evas_Event_Mouse_Wheel *ev;
   E_Smart_Data *sd;
   Evas_Coord x = 0, y = 0;

   sd = data;
   ev = event_info;
   enna_scrollframe_child_pos_get(sd->smart_obj, &x, &y);
   y += ev->z * sd->step.y;
   enna_scrollframe_child_pos_set(sd->smart_obj, x, y);
}

static void
_e_smart_event_mouse_down(void *data, Evas *e, Evas_Object *obj, void *event_info)
{
   Evas_Event_Mouse_Down *ev;
   E_Smart_Data *sd;
   Evas_Coord x = 0, y = 0;

   sd = data;
   ev = event_info;



   if (sd->down.momentum_animator)
     {
	ecore_animator_del(sd->down.momentum_animator);
	sd->down.momentum_animator = NULL;
     }
   if (ev->button == 1)
     {
	sd->down.now = 1;
	sd->down.dragged = 0;
	sd->down.dir_x = 0;
	sd->down.dir_y = 0;
	sd->down.x = ev->canvas.x;
	sd->down.y = ev->canvas.y;
	enna_scrollframe_child_pos_get(sd->smart_obj, &x, &y);
	sd->down.sx = x;
	sd->down.sy = y;
	sd->down.locked = 0;
	memset(&(sd->down.history[0]), 0, sizeof(sd->down.history[0]) * 20);
	sd->down.history[0].timestamp = ecore_time_get();
	sd->down.history[0].x = ev->canvas.x;
	sd->down.history[0].y = ev->canvas.y;
	edje_object_signal_emit(sd->edje_obj, "e,action,show,vbar", "e");
     }

}

static int
_e_smart_momentum_animator(void *data)
{
   E_Smart_Data *sd;
   double t, dt, p;
   Evas_Coord x, y, dx, dy;

   sd = data;
   t = ecore_time_get();
   dt = t - sd->down.anim_start;

   if (dt >= 0.0)
     {
	dt = dt / thumbscroll_friction;
	if (dt > 1.0) dt = 1.0;
	p = 1.0 - ((1.0 - dt) * (1.0 - dt) * (1.0 - dt));
	dx = (sd->down.dx * thumbscroll_friction * p);
	dy = (sd->down.dy * thumbscroll_friction * p);
	x = sd->down.sx - dx;
	y = sd->down.sy - dy;
	enna_scrollframe_child_pos_set(sd->smart_obj, x, y);
	if (dt >= 1.0)
	  {
	     sd->down.momentum_animator = NULL;
	     edje_object_signal_emit(sd->edje_obj, "e,action,hide,vbar", "e");
	     return 0;
	  }
     }
   return 1;
}

static void
_e_smart_event_mouse_up(void *data, Evas *e, Evas_Object *obj, void *event_info)
{
   Evas_Event_Mouse_Down *ev;
   E_Smart_Data *sd;
   Evas_Coord x = 0, y = 0;

   sd = data;
   ev = event_info;


   if (ev->button == 1)
     {
	x = ev->canvas.x - sd->down.x;
	y = ev->canvas.y - sd->down.y;
	if (sd->down.dragged)
	  {
	     double t, at, dt;
	     int i;
	     Evas_Coord ax, ay, dx, dy, vel;

	     t = ecore_time_get();
	     ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
	     ax = ev->canvas.x;
	     ay = ev->canvas.y;
	     at = 0.0;
	     for (i = 0; i < 20; i++)
	       {
		  dt = t - sd->down.history[i].timestamp;
		  if (dt > 0.2) break;
		  at += dt;
		  ax += sd->down.history[i].x;
		  ay += sd->down.history[i].y;
	       }
	     ax /= (i + 1);
	     ay /= (i + 1);
	     at /= (i + 1);
	     at *= 4.0;
	     dx = ev->canvas.x - ax;
	     dy = ev->canvas.y - ay;
	     if (at > 0)
	       {
		  vel = sqrt((dx * dx) + (dy * dy)) / at;
		  if ((thumbscroll_friction > 0.0) &&
		      (vel > thumbscroll_momentum_threshhold))
		    {
		       if (!sd->down.momentum_animator)
			 sd->down.momentum_animator = ecore_animator_add(_e_smart_momentum_animator, sd);
		       sd->down.dx = ((double)dx / at);
		       sd->down.dy = ((double)dy / at);
		       sd->down.anim_start = t;
		       enna_scrollframe_child_pos_get(sd->smart_obj, &x, &y);
		       sd->down.sx = x;
		       sd->down.sy = y;
		    }
		  else
		    edje_object_signal_emit(sd->edje_obj, "e,action,hide,vbar", "e");
	       }
	     evas_event_feed_hold(e, 0, ev->timestamp, ev->data);
	  }
	sd->down.dragged = 0;
	sd->down.now = 0;
     }

}

static void
_e_smart_event_mouse_move(void *data, Evas *e, Evas_Object *obj, void *event_info)
{
   Evas_Event_Mouse_Move *ev;
   E_Smart_Data *sd;
   Evas_Coord x = 0, y = 0;

   sd = data;
   ev = event_info;


   if (sd->down.now)
     {
	memmove(&(sd->down.history[1]), &(sd->down.history[0]),
		sizeof(sd->down.history[0]) * 19);
	sd->down.history[0].timestamp = ecore_time_get();
	sd->down.history[0].x = ev->cur.canvas.x;
	sd->down.history[0].y = ev->cur.canvas.y;

	x = ev->cur.canvas.x - sd->down.x;
	if (x < 0) x = -x;
	y = ev->cur.canvas.y - sd->down.y;
{'fraction_non_alphanumeric': 0.1379089159717768, 'fraction_numerical': 0.00839699107819698, 'mean_word_length': 3.710754017305315, 'pattern_counts': {'":': 0, '<': 19, '<?xml version=': 0, '>': 415, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '315673', 'n_tokens_mistral': 14972, 'n_tokens_neox': 14335, 'n_words': 2912}