history: implement deletion of items.
authorGustavo Sverzut Barbieri <barbieri@profusion.mobi>
Tue, 7 Aug 2012 19:49:53 +0000 (16:49 -0300)
committerGustavo Sverzut Barbieri <barbieri@profusion.mobi>
Tue, 7 Aug 2012 21:26:14 +0000 (18:26 -0300)
now we can delete individual items or clear everything.

Makefile.am
data/themes/images/bt_del.png [new file with mode: 0644]
data/themes/images/bt_edit.png [new file with mode: 0644]
data/themes/includes/history-bg.edc
data/themes/includes/history.edc
dialer/history.c

index 28d8573..5cbd4e9 100644 (file)
@@ -73,6 +73,8 @@ data/themes/images/bt_call_pressed.png \
 data/themes/images/bt_call_released.png \
 data/themes/images/bt_contacts_pressed.png \
 data/themes/images/bt_contacts_released.png \
+data/themes/images/bt_del.png \
+data/themes/images/bt_edit.png \
 data/themes/images/bt_history_pressed.png \
 data/themes/images/bt_history_released.png \
 data/themes/images/bt_keypad_pressed.png \
diff --git a/data/themes/images/bt_del.png b/data/themes/images/bt_del.png
new file mode 100644 (file)
index 0000000..fae9957
Binary files /dev/null and b/data/themes/images/bt_del.png differ
diff --git a/data/themes/images/bt_edit.png b/data/themes/images/bt_edit.png
new file mode 100644 (file)
index 0000000..6c58e22
Binary files /dev/null and b/data/themes/images/bt_edit.png differ
index 6ba91e8..2a9735c 100644 (file)
@@ -3,6 +3,7 @@ group {
 
    images {
       image: "bg_keypad.jpg" COMP;
+      image: "bt_edit.png" COMP;
    }
 
    parts {
@@ -26,24 +27,109 @@ group {
       }
 
       part {
+         name: "button.area.clipper";
+         type: RECT;
+         description {
+            state: "default" 0.0;
+            rel1.to: "bg.buttons";
+            rel2 {
+               to: "bg.buttons";
+               offset: -1 SEPARATOR_HEIGHT;
+            }
+         }
+      }
+
+
+      part {
+         name: "button.clipper";
+         type: RECT;
+         clip_to: "button.area.clipper";
+         description {
+            state: "default" 0.0;
+            rel1.to: "button.area.clipper";
+            rel2.to: "button.area.clipper";
+         }
+         description {
+            state: "alternate" 0.0;
+            color: 255 255 255 0;
+            visible: 0;
+         }
+      }
+
+      part {
+         name: "edit-button.clipper";
+         type: RECT;
+         clip_to: "button.area.clipper";
+         description {
+            state: "default" 0.0;
+            color: 255 255 255 0;
+            visible: 0;
+            rel1.to: "button.area.clipper";
+            rel2.to: "button.area.clipper";
+         }
+         description {
+            state: "alternate" 0.0;
+            color: 255 255 255 255;
+            visible: 1;
+         }
+      }
+
+      part {
+         name: "edit.clipper";
+         type: RECT;
+         description {
+            state: "default" 0.0;
+            rel1.to: "bg.edit";
+            rel2 {
+               to: "bg.edit";
+               offset: -1 SEPARATOR_HEIGHT;
+            }
+         }
+      }
+
+      part {
          name: "bg.buttons";
          type: RECT;
          mouse_events: 0;
+         clip_to: "button.clipper";
          description {
             state: "default" 0.0;
             color: 0 0 0 0;
-            min: WIDTH (ACTION_HEIGHT / 2);
+            min: 0 (ACTION_HEIGHT / 2);
+            rel2 {
+               to_x: "bg.edit";
+               relative: 0.0 0.0;
+               offset: (-ITEM_PADDING - 1) (ACTION_HEIGHT / 2 - 1);
+            }
+         }
+      }
+
+      part {
+         name: "bg.edit";
+         type: RECT;
+         mouse_events: 0;
+         clip_to: "edit.clipper";
+         description {
+            state: "default" 0.0;
+            color: 0 0 0 0;
+            min: 0 (ACTION_HEIGHT / 2);
+            rel1 {
+               relative: 1.0 0.0;
+               offset: (-LIST_ICON_SIZE - ITEM_PADDING - BORDER_PADDING) 0;
+            }
             rel2 {
                relative: 1.0 0.0;
-               offset: -1.0 (ACTION_HEIGHT / 2 - 1);
+               offset: -1 (ACTION_HEIGHT / 2 - 1);
             }
          }
       }
-#define SEPARATOR(id, rely, offy, relto)                                \
+
+#define SEPARATOR(id, clip, rely, offy, relto)                          \
       part {                                                            \
          name: "separator.dark."##id;                                   \
          type: RECT;                                                    \
          mouse_events: 0;                                               \
+         clip_to: clip;                                                 \
          description {                                                  \
             state: "default" 0.0;                                       \
             color: 255 255 255 255;                                     \
@@ -64,6 +150,7 @@ group {
          name: "separator.bg."##id;                                     \
          type: RECT;                                                    \
          mouse_events: 0;                                               \
+         clip_to: clip;                                                 \
          description {                                                  \
             state: "default" 0.0;                                       \
             color: 255 255 255 255;                                     \
@@ -81,7 +168,9 @@ group {
          }                                                              \
       }
 
-      SEPARATOR("button", 1.0, 0, "bg.buttons");
+      SEPARATOR("button", "button.area.clipper", 1.0, 0, "bg.buttons");
+      SEPARATOR("edit-button", "button.area.clipper", 1.0, 0, "bg.buttons");
+      SEPARATOR("edit", "edit.clipper", 1.0, 0, "bg.edit");
 #undef SEPARATOR
 
       part {
@@ -120,11 +209,12 @@ group {
          }
       }
 
-#define BUTTON(id, label, ccls, r1, r2)                                 \
+#define BUTTON(id, label, ccls, clip, r1, r2)                           \
       part {                                                            \
          name: "button."##id;                                           \
          type: RECT;                                                    \
          mouse_events: 1;                                               \
+         clip_to: clip;                                                 \
          description {                                                  \
             state: "default" 0.0;                                       \
             color: 255 255 255 0;                                       \
@@ -148,6 +238,7 @@ group {
          name: "label."##id;                                            \
          type: TEXT;                                                    \
          mouse_events: 0;                                               \
+         clip_to: clip;                                                 \
          description {                                                  \
             state: "default" 0.0;                                       \
             color: 255 255 255 255;                                     \
@@ -158,8 +249,8 @@ group {
             }                                                           \
             text {                                                      \
                text: label;                                             \
-               font: FONT_NORMAL;                                         \
-               size: SIZE_MEDIUM;                                                \
+               font: FONT_NORMAL;                                       \
+               size: SIZE_MEDIUM;                                       \
                align: 0.5 0.5;                                          \
             }                                                           \
          }                                                              \
@@ -193,12 +284,132 @@ group {
          }                                                              \
       }
 
-      BUTTON("all",    "All",    "action", 0.0 0.0, 0.5 1.0);
-      BUTTON("missed", "Missed", "action", 0.5 0.0, 1.0 1.0);
+      BUTTON("all",    "All",    "action", "button.clipper", 0.0 0.0, 0.5 1.0);
+      BUTTON("missed", "Missed", "action", "button.clipper", 0.5 0.0, 1.0 1.0);
+
+      BUTTON("clear",     "Clear", "caution", "edit-button.clipper", 0.0 0.0, 0.5 1.0);
+      BUTTON("edit,done", "Done",  "action", "edit-button.clipper", 0.5 0.0, 1.0 1.0);
 #undef BUTTON
+
+      part {
+         name: "button.edit";
+         type: RECT;
+         mouse_events: 1;
+         clip_to: "edit.clipper";
+         description {
+            state: "default" 0.0;
+            color: 255 255 255 0;
+            color_class: "action";
+            rel1.to: "bg.edit";
+            rel2.to: "bg.edit";
+         }
+         description {
+            state: "pressed" 0.0;
+            inherit: "default" 0.0;
+            color: 255 255 255 255;
+         }
+      }
+      part {
+         name: "ico.edit";
+         type: IMAGE;
+         mouse_events: 0;
+         clip_to: "edit.clipper";
+         description {
+            state: "default" 0.0;
+            min: LIST_ICON_SIZE LIST_ICON_SIZE;
+            max: LIST_ICON_SIZE LIST_ICON_SIZE;
+            align: 0.0 0.5;
+            color: 255 255 255 255;
+            color_class: "action";
+            rel1 {
+               to: "button.edit";
+               offset: ITEM_PADDING 0;
+            }
+            rel2 {
+               to: "button.edit";
+               offset: (-BORDER_PADDING - 1) -1;
+            }
+            image {
+               normal: "bt_edit.png";
+               scale_hint: STATIC;
+            }
+         }
+         description {
+            state: "pressed" 0.0;
+            inherit: "default" 0.0;
+            color: 16 16 16 255;
+         }
+      }
+      part {
+         name: "button.over.edit";
+         type: RECT;
+         mouse_events: 1;
+         clip_to: "edit.clipper";
+         description {
+            state: "default" 0.0;
+            color: 0 0 0 0;
+            visible: 0;
+            rel1.to: "bg.edit";
+            rel2.to: "bg.edit";
+         }
+         description {
+            state: "pressed" 0.0;
+            inherit: "default" 0.0;
+            visible: 1;
+         }
+      }
+
+      programs {
+         program {
+            signal: "toggle,on,edit";
+            source: "gui";
+            action: STATE_SET "pressed" 0.0;
+            target: "button.edit";
+            target: "button.over.edit";
+            target: "ico.edit";
+            after: "show_edit_buttons";
+         }
+         program {
+            name: "show_edit_buttons";
+            action: STATE_SET "alternate" 0.0;
+            transition: ACCELERATE 0.3;
+            target: "button.clipper";
+            target: "edit-button.clipper";
+         }
+
+         program {
+            signal: "toggle,off,edit";
+            source: "gui";
+            action: STATE_SET "default" 0.0;
+            target: "button.edit";
+            target: "button.over.edit";
+            target: "ico.edit";
+            after: "hide_edit_buttons";
+         }
+         program {
+            name: "hide_edit_buttons";
+            action: STATE_SET "default" 0.0;
+            transition: ACCELERATE 0.3;
+            target: "button.clipper";
+            target: "edit-button.clipper";
+         }
+
+         program {
+            signal: "mouse,clicked,1";
+            source: "button.edit";
+            action: SIGNAL_EMIT "clicked,edit" "gui";
+            api: "edit was clicked";
+         }
+         program {
+            signal: "mouse,clicked,1";
+            source: "button.over.edit";
+            action: SIGNAL_EMIT "clicked,edit,done" "gui";
+            api: "edit_done was clicked";
+         }
+      }
    }
-   programs {
 
+   programs {
       program {
          name: "show_all";
          signal: "show,all";
index 1d4bd3d..c50bc06 100644 (file)
@@ -89,7 +89,10 @@ group {
       }
    }
 
-   images.image: "bt_arrow_right.png" COMP;
+   images {
+      image: "bt_arrow_right.png" COMP;
+      image: "bt_del.png" COMP;
+   }
 
    parts{
       part {
@@ -202,7 +205,7 @@ group {
             rel2 {
                to_x: "call.swallow.more";
                relative: 0.0 1.0;
-               offset: -ITEM_PADDING (-ITEM_PADDING - 1);
+               offset: (-ITEM_PADDING - ITEM_PADDING) (-ITEM_PADDING - 1);
             }
             text {
                font: FONT_NORMAL;
@@ -362,3 +365,189 @@ group {
       }
    }
 }
+
+group {
+   name: "elm/genlist/item/history-delete/default";
+   alias: "elm/genlist/item_odd/history-delete/default";
+
+   data {
+      item: "contents" "call.swallow.delete";
+      item: "mode_part" "elm.swallow.decorate.content";
+   }
+
+   parts {
+      part {
+         name: "content.clipper";
+         type: RECT;
+         description {
+            state: "default" 0.0;
+         }
+         description {
+            state: "decorated" 0.0;
+            inherit: "default" 0.0;
+            rel2 {
+               offset: (-BORDER_PADDING - LIST_ICON_SIZE - ITEM_PADDING - 1) -1;
+            }
+         }
+      }
+
+      part {
+         name: "elm.swallow.decorate.content";
+         type: SWALLOW;
+         mouse_events: 1;
+         scale: 1;
+         clip_to: "content.clipper";
+         description {
+            state: "default" 0.0;
+         }
+      }
+
+      part {
+         name: "call.swallow.delete";
+         type: SWALLOW;
+         mouse_events: 1;
+         scale: 1;
+         description {
+            state: "default" 0.0;
+            visible: 0;
+            fixed: 1 0;
+            align: 0.0 0.5;
+            rel1 {
+               relative: 1.0 0.0;
+            }
+         }
+         description {
+            state: "decorated" 0.0;
+            inherit: "default" 0.0;
+            visible: 1;
+            align: 1.0 0.5;
+            rel1 {
+               relative: 1.0 0.0;
+               offset: -BORDER_PADDING 0;
+            }
+            rel2 {
+               relative: 1.0 1.0;
+               offset: -BORDER_PADDING -1;
+            }
+         }
+      }
+
+      programs {
+         program {
+            name: "animate_decorated";
+            signal: "elm,state,decorate,enabled,effect";
+            source: "elm";
+            action: STATE_SET "decorated" 0.0;
+            target: "content.clipper";
+            after: "animate_decorated2";
+         }
+         program {
+            name: "animate_decorated2";
+            action: STATE_SET "decorated" 0.0;
+            transition: ACCELERATE 0.15;
+            target: "call.swallow.delete";
+         }
+
+         program {
+            name: "animate_default";
+            signal: "elm,state,decorate,disabled,effect";
+            source: "elm";
+            action: STATE_SET "default" 0.0;
+            transition: ACCELERATE 0.15;
+            target: "call.swallow.delete";
+            after: "animate_default2";
+         }
+         program {
+            name: "animate_default2";
+            action: STATE_SET "default" 0.0;
+            target: "content.clipper";
+         }
+
+         program {
+            signal: "elm,state,decorate,enabled";
+            source: "elm";
+            action: STATE_SET "decorated" 0.0;
+            target: "content.clipper";
+            target: "call.swallow.delete";
+         }
+         program {
+            signal: "elm,state,decorate,disabled";
+            source: "elm";
+            action: STATE_SET "default" 0.0;
+            target: "content.clipper";
+            target: "call.swallow.delete";
+         }
+
+         program {
+            signal: "elm,state,slide,active";
+            source: "elm";
+            after: "animate_decorated";
+         }
+         program {
+            signal: "elm,state,slide,passive";
+            source: "elm";
+            after: "animate_default";
+         }
+      }
+   }
+}
+
+group {
+   name: "elm/button/base/history-delete";
+
+   parts {
+      part {
+         name: "area";
+         type: IMAGE;
+         description {
+            state: "default" 0.0;
+            min: LIST_ICON_SIZE LIST_ICON_SIZE;
+            max: LIST_ICON_SIZE LIST_ICON_SIZE;
+            color: 255 255 255 255;
+            color_class: "caution";
+            image {
+               normal: "bt_del.png";
+               scale_hint: STATIC;
+            }
+         }
+         description {
+            state: "pressed" 0.0;
+            inherit: "default" 0.0;
+            color: 255 255 255 128;
+         }
+      }
+   }
+   programs {
+      program {
+         signal: "mouse,down,1";
+         source: "area";
+         action: SIGNAL_EMIT "elm,action,press" "";
+      }
+      program {
+         signal: "mouse,up,1";
+         source: "area";
+         action: SIGNAL_EMIT "elm,action,unpress" "";
+      }
+      program {
+         signal: "mouse,clicked,1";
+         source: "area";
+         action: SIGNAL_EMIT "elm,action,click" "";
+      }
+
+      program {
+         signal: "mouse,up,1";
+         source: "area";
+         action: STATE_SET "default" 0.0;
+         transition: ACCELERATE 0.1;
+         target: "area";
+      }
+
+      program {
+         signal: "mouse,down,1";
+         source: "area";
+         action: STATE_SET "pressed" 0.0;
+         transition: ACCELERATE 0.1;
+         target: "area";
+      }
+   }
+}
index a8f3475..8538951 100644 (file)
@@ -31,6 +31,7 @@ typedef struct _History {
        Call_Info_List *calls;
        Elm_Genlist_Item_Class *itc;
        Evas_Object *self;
+       Evas_Object *clear_popup;
        Evas_Object *genlist_all, *genlist_missed;
        Ecore_Poller *updater;
        double last_update;
@@ -45,6 +46,7 @@ typedef struct _Call_Info {
        Eina_Bool completed;
        Eina_Bool incoming;
        const OFono_Call *call; /* not in edd */
+       History *history;
        Elm_Object_Item *it_all; /*not in edd */
        Elm_Object_Item *it_missed; /*not in edd */
 } Call_Info;
@@ -81,6 +83,11 @@ static Eina_Bool _history_time_updater(void *data)
         *   uselessly update all the thousand items.
         */
 
+       if (!ctx->calls->list) {
+               ctx->updater = NULL;
+               return EINA_FALSE;
+       }
+
        if (now - ctx->last_update < interval_threshold)
                return EINA_TRUE;
        ctx->last_update = now;
@@ -144,6 +151,8 @@ static void _history_time_updater_start(History *history)
                history->updater, win_focused, obj_visible);
        if (history->updater)
                return;
+       if (!history->calls->list)
+               return;
        if ((!win_focused) || (!obj_visible))
                return;
 
@@ -341,6 +350,8 @@ static void _history_call_removed(void *data, OFono_Call *call)
                                elm_genlist_item_show
                                        (it, ELM_GENLIST_ITEM_SCROLLTO_IN);
                                call_info->it_missed = it;
+                               call_info->history = history;
+                               _history_time_updater_start(history);
                        }
                }
        }
@@ -359,6 +370,8 @@ static void _history_call_removed(void *data, OFono_Call *call)
                                                call_info->line_id);
                elm_genlist_item_show(it, ELM_GENLIST_ITEM_SCROLLTO_IN);
                call_info->it_all = it;
+               call_info->history = history;
+               _history_time_updater_start(history);
        }
 }
 
@@ -495,6 +508,7 @@ static void _history_call_log_read(History *history)
                                                _on_item_clicked,
                                                call_info->line_id);
                call_info->it_all = it;
+               call_info->history = history;
 
                if (call_info->completed)
                        continue;
@@ -505,6 +519,7 @@ static void _history_call_log_read(History *history)
                                                _on_item_clicked,
                                                call_info->line_id);
                call_info->it_missed = it;
+               call_info->history = history;
        }
 
        it = elm_genlist_first_item_get(history->genlist_all);
@@ -516,6 +531,95 @@ static void _history_call_log_read(History *history)
                elm_genlist_item_show(it, ELM_GENLIST_ITEM_SCROLLTO_TOP);
 }
 
+static void _history_call_info_del(Call_Info *call_info)
+{
+       History *ctx = call_info->history;
+
+       EINA_SAFETY_ON_NULL_RETURN(ctx);
+
+       call_info->call = NULL;
+       if (call_info->it_all)
+               elm_object_item_del(call_info->it_all);
+       if (call_info->it_missed)
+               elm_object_item_del(call_info->it_missed);
+
+       ctx->calls->list = eina_list_remove(ctx->calls->list, call_info);
+       ctx->calls->dirty = EINA_TRUE;
+       _history_call_log_save(ctx);
+
+       if ((!ctx->calls->list) && (ctx->updater)) {
+               ecore_poller_del(ctx->updater);
+               ctx->updater = NULL;
+       }
+
+       _call_info_free(call_info);
+}
+
+static void _history_clear_do(void *data, Evas_Object *obj __UNUSED__,
+                               void *event_info __UNUSED__)
+{
+       History *ctx = data;
+       Call_Info *call_info;
+
+       DBG("ctx=%p, deleting %u entries",
+               ctx, eina_list_count(ctx->calls->list));
+
+       evas_object_del(ctx->clear_popup);
+       ctx->clear_popup = NULL;
+
+       elm_genlist_clear(ctx->genlist_all);
+       elm_genlist_clear(ctx->genlist_missed);
+
+       EINA_LIST_FREE(ctx->calls->list, call_info)
+               _call_info_free(call_info);
+
+       ctx->calls->dirty = EINA_TRUE;
+       _history_call_log_save(ctx);
+
+       if (ctx->updater) {
+               ecore_poller_del(ctx->updater);
+               ctx->updater = NULL;
+       }
+
+       elm_object_signal_emit(ctx->self, "toggle,off,edit", "gui");
+}
+
+static void _history_clear_cancel(void *data, Evas_Object *obj __UNUSED__,
+                                       void *event_info __UNUSED__)
+{
+       History *ctx = data;
+
+       DBG("ctx=%p", ctx);
+
+       evas_object_del(ctx->clear_popup);
+       ctx->clear_popup = NULL;
+}
+
+static void _history_clear(History *ctx)
+{
+       Evas_Object *p, *bt;
+
+       EINA_SAFETY_ON_TRUE_RETURN(ctx->clear_popup != NULL);
+
+       ctx->clear_popup = p = elm_popup_add(ctx->self);
+       evas_object_size_hint_weight_set(p, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+       elm_object_part_text_set(p, "title,text", "Clear History");
+       elm_object_text_set(p, "Do you want to clear all history entries?");
+
+       bt = elm_button_add(p);
+       elm_object_text_set(bt, "No");
+       elm_object_part_content_set(p, "button1", bt);
+       evas_object_smart_callback_add(bt, "clicked",
+                                       _history_clear_cancel, ctx);
+
+       bt = elm_button_add(p);
+       elm_object_text_set(bt, "Yes, Clear");
+       elm_object_part_content_set(p, "button2", bt);
+       evas_object_smart_callback_add(bt, "clicked", _history_clear_do, ctx);
+
+       evas_object_show(p);
+}
+
 static char *_item_label_get(void *data, Evas_Object *obj __UNUSED__,
                                const char *part)
 {
@@ -565,16 +669,31 @@ static Eina_Bool _item_state_get(void *data, Evas_Object *obj __UNUSED__,
        return EINA_FALSE;
 }
 
-static void _on_clicked(void *data __UNUSED__, Evas_Object *obj __UNUSED__,
+static void _on_clicked(void *data, Evas_Object *obj __UNUSED__,
                        const char *emission, const char *source __UNUSED__)
 {
+       History *ctx = data;
+
        EINA_SAFETY_ON_NULL_RETURN(emission);
        emission += strlen("clicked,");
 
+       DBG("ctx=%p, signal: %s", ctx, emission);
+
        if (!strcmp(emission, "all"))
                elm_object_signal_emit(obj, "show,all", "gui");
-       else
+       else if (!strcmp(emission, "missed"))
                elm_object_signal_emit(obj, "show,missed", "gui");
+       else if (!strcmp(emission, "clear"))
+               _history_clear(ctx);
+       else if (!strcmp(emission, "edit")) {
+               elm_object_signal_emit(obj, "toggle,on,edit", "gui");
+               elm_genlist_decorate_mode_set(ctx->genlist_all, EINA_TRUE);
+               elm_genlist_decorate_mode_set(ctx->genlist_missed, EINA_TRUE);
+       } else if (!strcmp(emission, "edit,done")) {
+               elm_object_signal_emit(obj, "toggle,off,edit", "gui");
+               elm_genlist_decorate_mode_set(ctx->genlist_all, EINA_FALSE);
+               elm_genlist_decorate_mode_set(ctx->genlist_missed, EINA_FALSE);
+       }
 }
 
 static void _on_more_clicked(void *data __UNUSED__, Evas_Object *obj __UNUSED__,
@@ -584,20 +703,65 @@ static void _on_more_clicked(void *data __UNUSED__, Evas_Object *obj __UNUSED__,
        DBG("TODO");
 }
 
-static Evas_Object *_item_content_get(void *data __UNUSED__, Evas_Object *obj,
-                                       const char *part __UNUSED__)
+static void _on_del_clicked(void *data, Evas_Object *obj __UNUSED__,
+                               void *event_info __UNUSED__)
 {
-       Evas_Object *btn;
+       Call_Info *call_info = data;
+       DBG("call_info=%p, items all=%p missed=%p",
+               call_info, call_info->it_all, call_info->it_missed);
+       _history_call_info_del(call_info);
+}
 
-       btn = gui_layout_add(obj, "history/img");
-       EINA_SAFETY_ON_NULL_RETURN_VAL(obj, NULL);
-       elm_object_signal_callback_add(btn, "clicked,more", "gui",
-                                       _on_more_clicked, NULL);
-       evas_object_propagate_events_set(btn, EINA_FALSE);
+static Evas_Object *_item_content_get(void *data, Evas_Object *obj,
+                                       const char *part)
+{
+       Evas_Object *btn = NULL;
+
+       if (strcmp(part, "call.swallow.more") == 0) {
+               btn = gui_layout_add(obj, "history/img");
+               EINA_SAFETY_ON_NULL_RETURN_VAL(btn, NULL);
+               elm_object_signal_callback_add(btn, "clicked,more", "gui",
+                                               _on_more_clicked, NULL);
+               evas_object_propagate_events_set(btn, EINA_FALSE);
+       } else if (strcmp(part, "call.swallow.delete") == 0) {
+               btn = elm_button_add(obj);
+               EINA_SAFETY_ON_NULL_RETURN_VAL(btn, NULL);
+               elm_object_style_set(btn, "history-delete");
+               elm_object_text_set(btn, "delete");
+               evas_object_smart_callback_add(btn, "clicked", _on_del_clicked,
+                                               data);
+               evas_object_propagate_events_set(btn, EINA_FALSE);
+       } else
+               ERR("unknown content part '%s'", part);
 
        return btn;
 }
 
+static void _on_list_slide_enter(void *data __UNUSED__,
+                                       Evas_Object *obj,
+                                       void *event_info)
+{
+       Elm_Object_Item *it = elm_genlist_decorated_item_get(obj);
+       DBG("cancel decorated item=%p", it);
+       if (it)
+               elm_genlist_item_decorate_mode_set(it, "slide", EINA_FALSE);
+
+       it = event_info;
+       EINA_SAFETY_ON_NULL_RETURN(it);
+       DBG("it=%p", it);
+       elm_genlist_item_decorate_mode_set(it, "slide", EINA_TRUE);
+}
+
+static void _on_list_slide_cancel(void *data __UNUSED__,
+                                       Evas_Object *obj,
+                                       void *event_info __UNUSED__)
+{
+       Elm_Object_Item *it = elm_genlist_decorated_item_get(obj);
+       DBG("it=%p", it);
+       if (it)
+               elm_genlist_item_decorate_mode_set(it, "slide", EINA_FALSE);
+}
+
 Evas_Object *history_add(Evas_Object *parent)
 {
        int r;
@@ -620,10 +784,29 @@ Evas_Object *history_add(Evas_Object *parent)
        EINA_SAFETY_ON_NULL_GOTO(genlist_all, err_object_new);
        elm_object_style_set(genlist_all, "history");
 
+       /* TODO: */
+       evas_object_smart_callback_add(genlist_all, "drag,start,right",
+                                       _on_list_slide_enter, history);
+       evas_object_smart_callback_add(genlist_all, "drag,start,left",
+                                       _on_list_slide_cancel, history);
+       evas_object_smart_callback_add(genlist_all, "drag,start,down",
+                                       _on_list_slide_cancel, history);
+       evas_object_smart_callback_add(genlist_all, "drag,start,up",
+                                       _on_list_slide_cancel, history);
+
        genlist_missed = elm_genlist_add(obj);
        EINA_SAFETY_ON_NULL_GOTO(genlist_missed, err_object_new);
        elm_object_style_set(genlist_missed, "history");
 
+       evas_object_smart_callback_add(genlist_missed, "drag,start,right",
+                                       _on_list_slide_enter, history);
+       evas_object_smart_callback_add(genlist_missed, "drag,start,left",
+                                       _on_list_slide_cancel, history);
+       evas_object_smart_callback_add(genlist_missed, "drag,start,down",
+                                       _on_list_slide_cancel, history);
+       evas_object_smart_callback_add(genlist_missed, "drag,start,up",
+                                       _on_list_slide_cancel, history);
+
        itc = elm_genlist_item_class_new();
        EINA_SAFETY_ON_NULL_GOTO(itc, err_object_new);
        itc->item_style = "history";
@@ -631,6 +814,8 @@ Evas_Object *history_add(Evas_Object *parent)
        itc->func.content_get = _item_content_get;
        itc->func.state_get = _item_state_get;
        itc->func.del = NULL;
+       itc->decorate_all_item_style = "history-delete";
+       itc->decorate_item_style = "history-delete";
        history->genlist_all = genlist_all;
        history->genlist_missed = genlist_missed;
        history->itc = itc;
@@ -639,7 +824,7 @@ Evas_Object *history_add(Evas_Object *parent)
        elm_object_part_content_set(obj, "elm.swallow.missed", genlist_missed);
        elm_object_signal_emit(obj, "show,all", "gui");
        elm_object_signal_callback_add(obj, "clicked,*", "gui",
-                                       _on_clicked, NULL);
+                                       _on_clicked, history);
 
        config_path = efreet_config_home_get();
        snprintf(base_dir, sizeof(base_dir), "%s/%s", config_path,