incoming sexiness... links, file paths, email addresses found in text
authorraster <raster@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Wed, 4 Jul 2012 14:44:43 +0000 (14:44 +0000)
committerraster <raster@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Wed, 4 Jul 2012 14:44:43 +0000 (14:44 +0000)
on mousover. highlight with a subtley animated underline and on
click.. do something sensible. the inline handler is the sexiest of
all. try local file pahts for now (full paths). as they work best.
remote urls for video files SHOULd work if they have http:// etc.
before them - no adjusting of loose ones. u may want to look at the
helpers config panel. internal handling of remote urls for media
doesnt download currently. still needs to be done. anyway. enjoy!

git-svn-id: http://svn.enlightenment.org/svn/e/trunk/terminology@73288 7cbeb6ba-43b4-40fd-8cce-4c39aea84d33

19 files changed:
data/themes/default.edc
data/themes/images/Makefile.am
data/themes/images/lk_bottom.png [new file with mode: 0644]
data/themes/images/lk_left.png [new file with mode: 0644]
data/themes/images/lk_right.png [new file with mode: 0644]
data/themes/images/pm_fill.png [new file with mode: 0644]
data/themes/images/pm_overlay.png [new file with mode: 0644]
data/themes/images/pm_shadow.png [new file with mode: 0644]
src/bin/Makefile.am
src/bin/config.c
src/bin/config.h
src/bin/main.c
src/bin/media.c
src/bin/media.h
src/bin/options.c
src/bin/options_helpers.c [new file with mode: 0644]
src/bin/options_helpers.h [new file with mode: 0644]
src/bin/termio.c
src/bin/termio.h

index 9221890..c9d4c9a 100644 (file)
@@ -12,6 +12,9 @@ collections {
         image: "bg_led_base.png" COMP;
         image: "bg_led.png" COMP;
         image: "bg_led_strobe.png" COMP;
+        image: "pm_shadow.png" COMP;
+        image: "pm_overlay.png" COMP;
+        image: "pm_fill.png" COMP;
       }
       parts {
 // other signals sent not handled here         
@@ -321,6 +324,317 @@ collections {
          }
          
          ////////////////////////////////////////////////////////////////////
+         // popup media over the terminal (until dismissed)
+         part { name: "popmedia_clip"; type: RECT;
+            mouse_events: 1;
+            description { state: "default" 0.0;
+               fixed: 1 1;
+               visible: 0;
+               color: 255 255 255 0;
+            }
+            description { state: "visible" 0.0;
+               inherit: "default" 0.0;
+               visible: 1;
+               color: 255 255 255 255;
+            }
+         }
+         part { name: "popmedia_shadow";
+            mouse_events: 0;
+            description { state: "default" 0.0;
+               fixed: 1 1;
+               rel1 {
+                  to: "terminology.popmedia";
+               }
+               rel2 {
+                  to: "terminology.popmedia";
+               }
+               image.normal: "pm_shadow.png";
+               image.border: 64 64 64 64;
+               image.border_scale_by: 0.1;
+               fill.smooth: 0;
+               visible: 0;
+            }
+            description { state: "visible" 0.0;
+               inherit: "default" 0.0;
+               rel1.offset: -32 -32;
+               rel2.offset: 31 31;
+               image.border_scale_by: 1.0;
+               visible: 1;
+            }
+         }
+         part { name: "popmedia_fill";
+            mouse_events: 0;
+            description { state: "default" 0.0;
+               fixed: 1 1;
+               rel1.to: "terminology.popmedia";
+               rel2.to: "terminology.popmedia";
+               image.normal: "pm_fill.png";
+               fill {
+                  size.relative: 0.0 0.0;
+                  size.offset: 64 64;
+               }
+            }
+         }
+         part { name: "terminology.popmedia"; type: SWALLOW;
+            clip_to: "popmedia_clip";
+            description { state: "default" 0.0;
+               fixed: 1 1;
+               rel1.relative: 0.5 0.5;
+               rel2.relative: 0.5 0.5;
+               visible: 0;
+            }
+            description { state: "image" 0.0;
+               inherit: "default" 0.0;
+               rel1.relative: 0.1 0.1;
+               rel2.relative: 0.9 0.9;
+               visible: 1;
+            }
+            description { state: "scale" 0.0;
+               inherit: "default" 0.0;
+               rel1.relative: 0.1 0.1;
+               rel2.relative: 0.9 0.9;
+               visible: 1;
+            }
+            description { state: "edje" 0.0;
+               inherit: "default" 0.0;
+               rel1.relative: 0.1 0.1;
+               rel2.relative: 0.9 0.9;
+               visible: 1;
+            }
+            description { state: "movie" 0.0;
+               inherit: "default" 0.0;
+               rel1.relative: 0.1 0.1;
+               rel2.relative: 0.9 0.9;
+               visible: 1;
+            }
+         }
+         part { name: "popmedia_overlay";
+            mouse_events: 0;
+            description { state: "default" 0.0;
+               fixed: 1 1;
+               rel1.to: "terminology.popmedia";
+               rel2.to: "terminology.popmedia";
+               image.normal: "pm_overlay.png";
+               fill.smooth: 0;
+               visible: 0;
+            }
+            description { state: "visible" 0.0;
+               inherit: "default" 0.0;
+               visible: 1;
+            }
+         }
+         part { name: "popmedia_bevel";
+            mouse_events: 0;
+            description { state: "default" 0.0;
+               fixed: 1 1;
+               rel1.to: "terminology.popmedia";
+               rel2.to: "terminology.popmedia";
+               image.normal: "bg_bevel.png";
+               image.border: 3 3 5 3;
+               image.middle: 0;
+               fill.smooth: 0;
+               visible: 0;
+            }
+            description { state: "visible" 0.0;
+               inherit: "default" 0.0;
+               visible: 1;
+            }
+         }
+         part { name: "popmedia_glintclip"; type: RECT;
+            mouse_events: 0;
+            description { state: "default" 0.0;
+               fixed: 1 1;
+               visible: 0;
+            }
+            description { state: "visible" 0.0;
+               inherit: "default" 0.0;
+               visible: 1;
+            }
+         }
+         part { name: "popmedia_glint";
+            mouse_events: 0;
+            clip_to: "popmedia_glintclip";
+            description { state: "default" 0.0;
+               fixed: 1 1;
+               min: 79 5;
+               max: 79 5;
+               rel1 {
+                  to: "terminology.popmedia";
+                  relative: 0.0 0.0;
+                  offset: 0 0;
+               }
+               rel2 {
+                  to: "terminology.popmedia";
+                  relative: 1.0 0.0;
+                  offset: -1 0;
+               }
+               image.normal: "bg_glint.png";
+               visible: 0;
+            }
+            description { state: "visible" 0.0;
+               inherit: "default" 0.0;
+               visible: 1;
+            }
+         }
+         part { name: "popmedia_shine";
+            mouse_events: 0;
+            description { state: "default" 0.0;
+               fixed: 1 1;
+               rel1.to: "terminology.popmedia";
+               rel2.to: "terminology.popmedia";
+               image.normal: "bg_shine.png";
+               fill.smooth: 0;
+               align: 0.5 0.0;
+               aspect: (255/120) (255/120);
+               aspect_preference: HORIZONTAL;
+               visible: 0;
+            }
+            description { state: "visible" 0.0;
+               inherit: "default" 0.0;
+               visible: 1;
+            }
+         }
+         part { name: "popmedia_dismiss"; type: RECT;
+            mouse_events: 1;
+            description { state: "default" 0.0;
+               fixed: 1 1;
+               color: 0 0 0 0;
+               visible: 0;
+               rel1.to: "terminology.popmedia";
+               rel2.to: "terminology.popmedia";
+            }
+            description { state: "visible" 0.0;
+               inherit: "default" 0.0;
+               visible: 1;
+            }
+         }
+         program { name: "popmedia_dismiss";
+            signal: "mouse,clicked,*";
+            source: "popmedia_dismiss";
+            action: STATE_SET "default" 0.0;
+            transition: DECELERATE 0.5;
+            target: "terminology.popmedia";
+            target: "popmedia_clip";
+            target: "popmedia_dismiss";
+            target: "popmedia_shadow";
+            target: "popmedia_fill";
+            target: "popmedia_overlay";
+            target: "popmedia_bevel";
+            target: "popmedia_glint";
+            target: "popmedia_glintclip";
+            target: "popmedia_shine";
+            after: "popmedia_dismiss2";
+         }
+         program { name: "popmedia_dismiss2";
+            action: SIGNAL_EMIT "popmedia,done" "terminology";
+         }
+         program { name: "popmedia_off";
+            signal: "popmedia,off";
+            source: "terminology";
+            action: STATE_SET "default" 0.0;
+            transition: DECELERATE 0.2;
+            target: "terminology.popmedia";
+            target: "popmedia_clip";
+            target: "popmedia_dismiss";
+            target: "popmedia_shadow";
+            target: "popmedia_fill";
+            target: "popmedia_overlay";
+            target: "popmedia_bevel";
+            target: "popmedia_glint";
+            target: "popmedia_glintclip";
+            target: "popmedia_shine";
+            after: "popmedia_dismiss2";
+         }
+         program { name: "popmedia_img";
+            signal: "popmedia,image";
+            source: "terminology";
+            action: STATE_SET "image" 0.0;
+            transition: DECELERATE 0.2;
+            target: "terminology.popmedia";
+         }
+         program { name: "popmedia_scale";
+            signal: "popmedia,scale";
+            source: "terminology";
+            action: STATE_SET "scale" 0.0;
+            transition: DECELERATE 0.2;
+            target: "terminology.popmedia";
+         }
+         program { name: "popmedia_edje";
+            signal: "popmedia,edje";
+            source: "terminology";
+            action: STATE_SET "edje" 0.0;
+            transition: DECELERATE 0.2;
+            target: "terminology.popmedia";
+         }
+         program { name: "popmedia_mov";
+            signal: "popmedia,movie";
+            source: "terminology";
+            action: STATE_SET "movie" 0.0;
+            transition: DECELERATE 0.2;
+            target: "terminology.popmedia";
+         }
+         program { name: "popmedia_img2";
+            signal: "popmedia,image";
+            source: "terminology";
+            action: STATE_SET "visible" 0.0;
+            transition: DECELERATE 0.2;
+            target: "popmedia_clip";
+            target: "popmedia_dismiss";
+            target: "popmedia_shadow";
+            target: "popmedia_fill";
+            target: "popmedia_overlay";
+            target: "popmedia_bevel";
+            target: "popmedia_glint";
+            target: "popmedia_glintclip";
+            target: "popmedia_shine";
+         }
+         program { name: "popmedia_scale2";
+            signal: "popmedia,scale";
+            source: "terminology";
+            action: STATE_SET "visible" 0.0;
+            transition: DECELERATE 0.2;
+            target: "popmedia_clip";
+            target: "popmedia_dismiss";
+            target: "popmedia_shadow";
+            target: "popmedia_fill";
+            target: "popmedia_overlay";
+            target: "popmedia_bevel";
+            target: "popmedia_glint";
+            target: "popmedia_glintclip";
+            target: "popmedia_shine";
+         }
+         program { name: "popmedia_edje2";
+            signal: "popmedia,edje";
+            source: "terminology";
+            action: STATE_SET "visible" 0.0;
+            transition: DECELERATE 0.2;
+            target: "popmedia_clip";
+            target: "popmedia_dismiss";
+            target: "popmedia_shadow";
+            target: "popmedia_fill";
+            target: "popmedia_overlay";
+            target: "popmedia_bevel";
+            target: "popmedia_glint";
+            target: "popmedia_glintclip";
+            target: "popmedia_shine";
+         }
+         program { name: "popmedia_mov2";
+            signal: "popmedia,movie";
+            source: "terminology";
+            action: STATE_SET "visible" 0.0;
+            transition: DECELERATE 0.2;
+            target: "popmedia_clip";
+            target: "popmedia_dismiss";
+            target: "popmedia_shadow";
+            target: "popmedia_fill";
+            target: "popmedia_overlay";
+            target: "popmedia_bevel";
+            target: "popmedia_glint";
+            target: "popmedia_glintclip";
+            target: "popmedia_shine";
+         }
+         
+         ////////////////////////////////////////////////////////////////////
          // overlayed options and controls
          part { name: "terminology.about"; type: SWALLOW;
             scale: 1;
@@ -631,6 +945,118 @@ collections {
    }
 
 //////////////////////////////////////////////////////////////////////////////
+   //// an object overlayd on text that is a link
+   group { name: "terminology/link";
+      images {
+        image: "lk_bottom.png" COMP;
+        image: "lk_left.png" COMP;
+        image: "lk_right.png" COMP;
+      }
+      parts {
+         part { name: "bottom";
+            mouse_events: 0;
+            description { state: "default" 0.0;
+               image.normal: "lk_bottom.png";
+               image.border: 9 9 0 0;
+               align: 0.5 1.0;
+               min: 20 8;
+               rel1.offset: -6 0;
+               rel1.relative: 0.0 1.0;
+               rel2.offset: 5 0;
+               color: 100 200 255 255;
+               fill.smooth: 0;
+            }
+         }
+         part { name: "l";
+            mouse_events: 0;
+            description { state: "default" 0.0;
+               image.normal: "lk_left.png";
+               align: 0.0 1.0;
+               min: 4 4;
+               rel1.offset: 16 -1;
+               rel1.relative: 0.0 1.0;
+               rel2.offset: 16 -1;
+               rel2.relative: 0.0 1.0;
+               color: 100 200 255 0;
+            }
+            description { state: "out" 0.0;
+               inherit: "default" 0.0;
+               min: 16 16;
+               rel1.offset: -10 -1;
+               rel2.offset: -10 -1;
+               color: 180 220 255 255;
+            }
+            description { state: "out2" 0.0;
+               inherit: "default" 0.0;
+               min: 32 32;
+               rel1.offset: -26 -1;
+               rel2.offset: -26 -1;
+               color: 100 200 255 0;
+            }
+         }
+         part { name: "r";
+            mouse_events: 0;
+            description { state: "default" 0.0;
+               image.normal: "lk_right.png";
+               align: 1.0 1.0;
+               min: 4 4;
+               rel1.offset: -15 0;
+               rel1.relative: 1.0 1.0;
+               rel2.offset: -15 0;
+               rel2.relative: 1.0 1.0;
+               color: 100 200 255 0;
+            }
+            description { state: "out" 0.0;
+               inherit: "default" 0.0;
+               min: 16 16;
+               rel1.offset: 9 -1;
+               rel2.offset: 9 -1;
+               color: 180 220 255 255;
+            }
+            description { state: "out2" 0.0;
+               inherit: "default" 0.0;
+               min: 32 32;
+               rel1.offset: 25 -1;
+               rel2.offset: 25 -1;
+               color: 100 200 255 0;
+            }
+         }
+         part { name: "event"; type: RECT;
+            mouse_events: 1;
+            repeat_events: 1;
+            description { state: "default" 0.0;
+               color: 0 0 0 0;
+            }
+         }
+         programs {
+            program { name: "show";
+               signal: "show";
+               source: "";
+               action: STATE_SET "out" 0.0;
+               transition: LINEAR 0.3;
+               target: "l";
+               target: "r";
+               after: "show2";
+            }
+            program { name: "show2";
+               action: STATE_SET "default" 0.0;
+               action: STATE_SET "out2" 0.0;
+               transition: LINEAR 0.3;
+               target: "l";
+               target: "r";
+               after: "show3";
+            }
+            program { name: "show3";
+               action: STATE_SET "default" 0.0;
+               target: "l";
+               target: "r";
+               after: "show";
+            }
+         }
+      }
+   }
+
+//////////////////////////////////////////////////////////////////////////////
    //// the multimedia controls
    group { name: "terminology/mediactrl";
       images {
index 86d3d0f..4491429 100644 (file)
@@ -21,4 +21,10 @@ media_pause.png \
 media_play.png \
 media_stop.png \
 media_knob_pos.png \
-media_knob_vol.png
+media_knob_vol.png \
+pm_fill.png \
+pm_overlay.png \
+pm_shadow.png \
+lk_bottom.png \
+lk_left.png \
+lk_right.png
diff --git a/data/themes/images/lk_bottom.png b/data/themes/images/lk_bottom.png
new file mode 100644 (file)
index 0000000..7b7007d
Binary files /dev/null and b/data/themes/images/lk_bottom.png differ
diff --git a/data/themes/images/lk_left.png b/data/themes/images/lk_left.png
new file mode 100644 (file)
index 0000000..3db09dc
Binary files /dev/null and b/data/themes/images/lk_left.png differ
diff --git a/data/themes/images/lk_right.png b/data/themes/images/lk_right.png
new file mode 100644 (file)
index 0000000..715bdc3
Binary files /dev/null and b/data/themes/images/lk_right.png differ
diff --git a/data/themes/images/pm_fill.png b/data/themes/images/pm_fill.png
new file mode 100644 (file)
index 0000000..8ef098f
Binary files /dev/null and b/data/themes/images/pm_fill.png differ
diff --git a/data/themes/images/pm_overlay.png b/data/themes/images/pm_overlay.png
new file mode 100644 (file)
index 0000000..3c25c73
Binary files /dev/null and b/data/themes/images/pm_overlay.png differ
diff --git a/data/themes/images/pm_shadow.png b/data/themes/images/pm_shadow.png
new file mode 100644 (file)
index 0000000..cde4f73
Binary files /dev/null and b/data/themes/images/pm_shadow.png differ
index 8aedb06..2bb6c90 100644 (file)
@@ -19,6 +19,7 @@ main.c main.h \
 media.c media.h \
 options.c options.h \
 options_behavior.c options_behavior.h \
+options_helpers.c options_helpers.h \
 options_font.c options_font.h \
 options_video.c options_video.h \
 options_theme.c options_theme.h \
index 8a51b18..ef8dc5b 100644 (file)
@@ -49,6 +49,22 @@ config_init(void)
    EET_DATA_DESCRIPTOR_ADD_BASIC
      (edd_base, Config, "font.bitmap", font.bitmap, EET_T_UCHAR);
    EET_DATA_DESCRIPTOR_ADD_BASIC
+     (edd_base, Config, "helper.email", helper.email, EET_T_STRING);
+   EET_DATA_DESCRIPTOR_ADD_BASIC
+     (edd_base, Config, "helper.url.general", helper.url.general, EET_T_STRING);
+   EET_DATA_DESCRIPTOR_ADD_BASIC
+     (edd_base, Config, "helper.url.video", helper.url.video, EET_T_STRING);
+   EET_DATA_DESCRIPTOR_ADD_BASIC
+     (edd_base, Config, "helper.url.image", helper.url.image, EET_T_STRING);
+   EET_DATA_DESCRIPTOR_ADD_BASIC
+     (edd_base, Config, "helper.local.general", helper.local.general, EET_T_STRING);
+   EET_DATA_DESCRIPTOR_ADD_BASIC
+     (edd_base, Config, "helper.local.video", helper.local.video, EET_T_STRING);
+   EET_DATA_DESCRIPTOR_ADD_BASIC
+     (edd_base, Config, "helper.local.image", helper.local.image, EET_T_STRING);
+   EET_DATA_DESCRIPTOR_ADD_BASIC
+     (edd_base, Config, "helper.inline_please", helper.inline_please, EET_T_UCHAR);
+   EET_DATA_DESCRIPTOR_ADD_BASIC
      (edd_base, Config, "theme", theme, EET_T_STRING);
    EET_DATA_DESCRIPTOR_ADD_BASIC
      (edd_base, Config, "background", background, EET_T_STRING);
@@ -192,6 +208,14 @@ config_load(const char *key)
              config->font.bitmap = EINA_TRUE;
              config->font.name = eina_stringshare_add("nexus.pcf");
              config->font.size = 10;
+             config->helper.email = eina_stringshare_add("xdg-email");;
+             config->helper.url.general = eina_stringshare_add("xdg-open");
+             config->helper.url.video = eina_stringshare_add("xdg-open");
+             config->helper.url.image = eina_stringshare_add("xdg-open");
+             config->helper.local.general = eina_stringshare_add("xdg-open");
+             config->helper.local.video = eina_stringshare_add("xdg-open");
+             config->helper.local.image = eina_stringshare_add("xdg-open");
+             config->helper.inline_please = EINA_TRUE;
              config->scrollback = 2000;
              config->theme = eina_stringshare_add("default.edj");
              config->background = NULL;
index e54f1f4..9bb2068 100644 (file)
@@ -12,6 +12,15 @@ struct _Config
       int            size;
       unsigned char  bitmap;
    } font;
+   struct {
+      const char    *email;
+      struct {
+         const char    *general;
+         const char    *video;
+         const char    *image;
+      } url, local;
+      Eina_Bool      inline_please;
+   } helper;
    const char       *theme;
    const char       *background;
    const char       *wordsep;
index c7ce5db..92a79c9 100644 (file)
@@ -13,6 +13,7 @@
 int _log_domain = -1;
 
 static Evas_Object *win = NULL, *bg = NULL, *term = NULL, *media = NULL;
+static Evas_Object *popmedia = NULL;
 static Evas_Object *conform = NULL;
 static Ecore_Timer *flush_timer = NULL;
 static Eina_Bool focused = EINA_FALSE;
@@ -94,6 +95,43 @@ _cb_bell(void *data __UNUSED__, Evas_Object *obj __UNUSED__, void *event __UNUSE
      }
 }
 
+static void
+_cb_popmedia_done(void *data __UNUSED__, Evas_Object *obj __UNUSED__, const char *sig __UNUSED__, const char *src __UNUSED__)
+{
+   if (popmedia)
+     {
+        evas_object_del(popmedia);
+        popmedia = NULL;
+        termio_mouseover_suspend_pushpop(term, -1);
+     }
+}
+
+static void
+_cb_popup(void *data __UNUSED__, Evas_Object *obj __UNUSED__, void *event __UNUSED__)
+{
+   Evas_Object *o;
+   Config *config = termio_config_get(term);
+   const char *src;
+   int type = 0;
+   
+   if (!config) return;
+   src = termio_link_get(term);
+   if (!src) return;
+   if (popmedia) evas_object_del(popmedia);
+   if (!popmedia) termio_mouseover_suspend_pushpop(term, 1);
+   popmedia = o = media_add(win, src, config, MEDIA_POP, &type);
+   edje_object_part_swallow(bg, "terminology.popmedia", o);
+   evas_object_show(o);
+   if (type == TYPE_IMG)
+     edje_object_signal_emit(bg, "popmedia,image", "terminology");
+   else if (type == TYPE_SCALE)
+     edje_object_signal_emit(bg, "popmedia,scale", "terminology");
+   else if (type == TYPE_EDJE)
+     edje_object_signal_emit(bg, "popmedia,edje", "terminology");
+   else if (type == TYPE_MOV)
+     edje_object_signal_emit(bg, "popmedia,movie", "terminology");
+}
+
 void
 main_trans_update(const Config *config)
 {
@@ -120,6 +158,7 @@ main_media_update(const Config *config)
         if (media) evas_object_del(media);
         o = media = media_add(win, config->background, config, MEDIA_BG, &type);
         edje_object_part_swallow(bg, "terminology.background", o);
+        evas_object_show(o);
         if (type == TYPE_IMG)
           edje_object_signal_emit(bg, "media,image", "terminology");
         else if (type == TYPE_SCALE)
@@ -128,7 +167,6 @@ main_media_update(const Config *config)
           edje_object_signal_emit(bg, "media,edje", "terminology");
         else if (type == TYPE_MOV)
           edje_object_signal_emit(bg, "media,movie", "terminology");
-        evas_object_show(o);
      }
    else
      {
@@ -378,6 +416,9 @@ elm_main(int argc, char **argv)
    theme_auto_reload_enable(o);
    elm_object_content_set(conform, o);
    evas_object_show(o);
+   
+   edje_object_signal_callback_add(o, "popmedia,done", "terminology",
+                                   _cb_popmedia_done, NULL);
 
    if (pos_set)
      {
@@ -399,6 +440,7 @@ elm_main(int argc, char **argv)
    evas_object_smart_callback_add(o, "change", _cb_change, NULL);
    evas_object_smart_callback_add(o, "exited", _cb_exited, NULL);
    evas_object_smart_callback_add(o, "bell", _cb_bell, NULL);
+   evas_object_smart_callback_add(o, "popup", _cb_popup, NULL);
    evas_object_show(o);
 
    main_trans_update(config);
index d9e8750..30277dd 100644 (file)
@@ -143,13 +143,32 @@ _type_img_calc(Evas_Object *obj, Evas_Coord x, Evas_Coord y, Evas_Coord w, Evas_
      {
         int iw, ih;
         
-        iw = w;
-        ih = (sd->ih * w) / sd->iw;
-        if (ih < h)
+        if (sd->mode == MEDIA_BG)
           {
-             ih = h;
-             iw = (sd->iw * h) / sd->ih;
-             if (iw < w) iw = w;
+             iw = w;
+             ih = (sd->ih * w) / sd->iw;
+             if (ih < h)
+               {
+                  ih = h;
+                  iw = (sd->iw * h) / sd->ih;
+                  if (iw < w) iw = w;
+               }
+          }
+        else if (sd->mode == MEDIA_POP)
+          {
+             iw = w;
+             ih = (sd->ih * w) / sd->iw;
+             if (ih > h)
+               {
+                  ih = h;
+                  iw = (sd->iw * h) / sd->ih;
+                  if (iw > w) iw = w;
+               }
+             if ((iw > sd->iw) || (ih > sd->ih))
+               {
+                  iw = sd->iw;
+                  ih = sd->ih;
+               }
           }
         x += ((w - iw) / 2);
         y += ((h - ih) / 2);
@@ -208,13 +227,27 @@ _type_scale_calc(Evas_Object *obj, Evas_Coord x, Evas_Coord y, Evas_Coord w, Eva
      {
         int iw, ih;
         
-        iw = w;
-        ih = (sd->ih * w) / sd->iw;
-        if (ih < h)
+        if (sd->mode == MEDIA_BG)
+          {
+             iw = w;
+             ih = (sd->ih * w) / sd->iw;
+             if (ih < h)
+               {
+                  ih = h;
+                  iw = (sd->iw * h) / sd->ih;
+                  if (iw < w) iw = w;
+               }
+          }
+        else if (sd->mode == MEDIA_POP)
           {
-             ih = h;
-             iw = (sd->iw * h) / sd->ih;
-             if (iw < w) iw = w;
+             iw = w;
+             ih = (sd->ih * w) / sd->iw;
+             if (ih > h)
+               {
+                  ih = h;
+                  iw = (sd->iw * h) / sd->ih;
+                  if (iw > w) iw = w;
+               }
           }
         x += ((w - iw) / 2);
         y += ((h - ih) / 2);
@@ -502,14 +535,28 @@ _type_mov_calc(Evas_Object *obj, Evas_Coord x, Evas_Coord y, Evas_Coord w, Evas_
         ratio = emotion_object_ratio_get(sd->o_img);
         if (ratio > 0.0) sd->iw = (sd->ih * ratio) + 0.5;
         else ratio = (double)sd->iw / (double)sd->ih;
-        
-        iw = w;
-        ih = w / ratio;
-        if (ih < h)
+
+        if (sd->mode == MEDIA_BG)
           {
-             ih = h;
-             iw = h * ratio;
-             if (iw < w) iw = w;
+             iw = w;
+             ih = w / ratio;
+             if (ih < h)
+               {
+                  ih = h;
+                  iw = h * ratio;
+                  if (iw < w) iw = w;
+               }
+          }
+        else if (sd->mode == MEDIA_POP)
+          {
+             iw = w;
+             ih = w / ratio;
+             if (ih > h)
+               {
+                  ih = h;
+                  iw = h * ratio;
+                  if (iw > w) iw = w;
+               }
           }
         x += ((w - iw) / 2);
         y += ((h - ih) / 2);
@@ -706,3 +753,15 @@ media_volume_set(Evas_Object *obj, double vol)
    emotion_object_audio_volume_set(sd->o_img, vol);
    edje_object_part_drag_value_set(sd->o_ctrl, "terminology.voldrag", vol, vol);
 }
+
+int
+media_src_type_get(const char *src)
+{
+   int type = TYPE_UNKNOWN;
+   
+   if      (_is_fmt(src, extn_img))   type = TYPE_IMG;
+   else if (_is_fmt(src, extn_scale)) type = TYPE_SCALE;
+   else if (_is_fmt(src, extn_edj))   type = TYPE_EDJE;
+   else if (_is_fmt(src, extn_mov))   type = TYPE_MOV;
+   return type;
+}
index 1aa8779..8d99e93 100644 (file)
@@ -2,11 +2,13 @@
 #define _MEDIA_H__ 1
 
 #define MEDIA_BG 0
+#define MEDIA_POP 1
 
-#define TYPE_IMG   0
-#define TYPE_SCALE 1
-#define TYPE_EDJE  2
-#define TYPE_MOV   3
+#define TYPE_UNKNOWN -1
+#define TYPE_IMG      0
+#define TYPE_SCALE    1
+#define TYPE_EDJE     2
+#define TYPE_MOV      3
 
 #include "config.h"
 
@@ -16,5 +18,6 @@ void media_play_set(Evas_Object *obj, Eina_Bool play);
 void media_position_set(Evas_Object *obj, double pos);
 void media_volume_set(Evas_Object *obj, double vol);
 void media_stop(Evas_Object *obj);
+int media_src_type_get(const char *src);
 
 #endif
index 6733266..c58bdec 100644 (file)
@@ -3,6 +3,7 @@
 #include <Elementary.h>
 #include "options.h"
 #include "options_font.h"
+#include "options_helpers.h"
 #include "options_behavior.h"
 #include "options_video.h"
 #include "options_theme.h"
@@ -56,6 +57,13 @@ _cb_op_behavior(void *data, Evas_Object *obj __UNUSED__, void *event __UNUSED__)
 }
 
 static void
+_cb_op_helpers(void *data, Evas_Object *obj __UNUSED__, void *event __UNUSED__)
+{
+   elm_box_clear(op_opbox);
+   options_helpers(op_opbox, data);
+}
+
+static void
 _cb_op_tmp_chg(void *data, Evas_Object *obj __UNUSED__, void *event __UNUSED__)
 {
    Config *config = data;
@@ -136,6 +144,8 @@ options_toggle(Evas_Object *win, Evas_Object *bg, Evas_Object *term)
                                 "Video", _cb_op_video, term);
         elm_toolbar_item_append(o, "system-run",
                                 "Behavior", _cb_op_behavior, term);
+        elm_toolbar_item_append(o, "document-open",
+                                "Helpers", _cb_op_helpers, term);
 
         elm_box_pack_end(op_tbox, o);
         evas_object_show(o);
diff --git a/src/bin/options_helpers.c b/src/bin/options_helpers.c
new file mode 100644 (file)
index 0000000..7f300f5
--- /dev/null
@@ -0,0 +1,373 @@
+#include "private.h"
+
+#include <Elementary.h>
+#include "config.h"
+#include "termio.h"
+#include "options.h"
+#include "options_helpers.h"
+#include "main.h"
+
+static void
+_cb_op_helper_inline_chg(void *data, Evas_Object *obj, void *event __UNUSED__)
+{
+   Evas_Object *term = data;
+   Config *config = termio_config_get(term);
+   config->helper.inline_please = elm_check_state_get(obj);
+   config_save(config, NULL);
+}
+
+static void
+_cb_op_helper_email_chg(void *data, Evas_Object *obj, void *event __UNUSED__)
+{
+   Evas_Object *term = data;
+   Config *config = termio_config_get(term);
+   char *txt;
+
+   if (config->helper.email)
+     {
+        eina_stringshare_del(config->helper.email);
+        config->helper.email = NULL;
+     }
+   txt = elm_entry_markup_to_utf8(elm_object_text_get(obj));
+   if (txt)
+     {
+        config->helper.email = eina_stringshare_add(txt);
+        free(txt);
+     }
+   config_save(config, NULL);
+}
+
+static void
+_cb_op_helper_url_image_chg(void *data, Evas_Object *obj, void *event __UNUSED__)
+{
+   Evas_Object *term = data;
+   Config *config = termio_config_get(term);
+   char *txt;
+
+   if (config->helper.url.image)
+     {
+        eina_stringshare_del(config->helper.url.image);
+        config->helper.email = NULL;
+     }
+   txt = elm_entry_markup_to_utf8(elm_object_text_get(obj));
+   if (txt)
+     {
+        config->helper.url.image = eina_stringshare_add(txt);
+        free(txt);
+     }
+   config_save(config, NULL);
+}
+
+static void
+_cb_op_helper_url_video_chg(void *data, Evas_Object *obj, void *event __UNUSED__)
+{
+   Evas_Object *term = data;
+   Config *config = termio_config_get(term);
+   char *txt;
+
+   if (config->helper.url.video)
+     {
+        eina_stringshare_del(config->helper.url.video);
+        config->helper.email = NULL;
+     }
+   txt = elm_entry_markup_to_utf8(elm_object_text_get(obj));
+   if (txt)
+     {
+        config->helper.url.video = eina_stringshare_add(txt);
+        free(txt);
+     }
+   config_save(config, NULL);
+}
+
+static void
+_cb_op_helper_url_general_chg(void *data, Evas_Object *obj, void *event __UNUSED__)
+{
+   Evas_Object *term = data;
+   Config *config = termio_config_get(term);
+   char *txt;
+
+   if (config->helper.url.general)
+     {
+        eina_stringshare_del(config->helper.url.general);
+        config->helper.email = NULL;
+     }
+   txt = elm_entry_markup_to_utf8(elm_object_text_get(obj));
+   if (txt)
+     {
+        config->helper.url.general = eina_stringshare_add(txt);
+        free(txt);
+     }
+   config_save(config, NULL);
+}
+
+static void
+_cb_op_helper_local_image_chg(void *data, Evas_Object *obj, void *event __UNUSED__)
+{
+   Evas_Object *term = data;
+   Config *config = termio_config_get(term);
+   char *txt;
+
+   if (config->helper.local.image)
+     {
+        eina_stringshare_del(config->helper.local.image);
+        config->helper.email = NULL;
+     }
+   txt = elm_entry_markup_to_utf8(elm_object_text_get(obj));
+   if (txt)
+     {
+        config->helper.local.image = eina_stringshare_add(txt);
+        free(txt);
+     }
+   config_save(config, NULL);
+}
+
+static void
+_cb_op_helper_local_video_chg(void *data, Evas_Object *obj, void *event __UNUSED__)
+{
+   Evas_Object *term = data;
+   Config *config = termio_config_get(term);
+   char *txt;
+
+   if (config->helper.local.video)
+     {
+        eina_stringshare_del(config->helper.local.video);
+        config->helper.email = NULL;
+     }
+   txt = elm_entry_markup_to_utf8(elm_object_text_get(obj));
+   if (txt)
+     {
+        config->helper.local.video = eina_stringshare_add(txt);
+        free(txt);
+     }
+   config_save(config, NULL);
+}
+
+static void
+_cb_op_helper_local_general_chg(void *data, Evas_Object *obj, void *event __UNUSED__)
+{
+   Evas_Object *term = data;
+   Config *config = termio_config_get(term);
+   char *txt;
+
+   if (config->helper.local.general)
+     {
+        eina_stringshare_del(config->helper.local.general);
+        config->helper.email = NULL;
+     }
+   txt = elm_entry_markup_to_utf8(elm_object_text_get(obj));
+   if (txt)
+     {
+        config->helper.local.general = eina_stringshare_add(txt);
+        free(txt);
+     }
+   config_save(config, NULL);
+}
+
+void
+options_helpers(Evas_Object *opbox, Evas_Object *term)
+{
+   Config *config = termio_config_get(term);
+   Evas_Object *o, *bx, *sc;
+   char *txt;
+
+   o = elm_check_add(opbox);
+   evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, 0.0);
+   evas_object_size_hint_align_set(o, EVAS_HINT_FILL, 0.5);
+   elm_object_text_set(o, "Inline if possible");
+   elm_check_state_set(o, config->helper.inline_please);
+   elm_box_pack_end(opbox, o);
+   evas_object_show(o);
+   evas_object_smart_callback_add(o, "changed",
+                                  _cb_op_helper_inline_chg, term);
+
+   o = elm_separator_add(opbox);
+   evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, 0.0);
+   evas_object_size_hint_align_set(o, EVAS_HINT_FILL, 0.5);
+   elm_separator_horizontal_set(o, EINA_TRUE);
+   elm_box_pack_end(opbox, o);
+   evas_object_show(o);
+   
+   sc = o = elm_scroller_add(opbox);
+   evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+   evas_object_size_hint_align_set(o, EVAS_HINT_FILL, EVAS_HINT_FILL);
+   elm_box_pack_end(opbox, o);
+   evas_object_show(o);
+
+   bx = o = elm_box_add(opbox);
+   evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, 0.0);
+   evas_object_size_hint_align_set(o, EVAS_HINT_FILL, 0.0);
+   elm_object_content_set(sc, o);
+   evas_object_show(o);
+   
+   o = elm_label_add(bx);
+   evas_object_size_hint_weight_set(o, 0.0, 0.0);
+   evas_object_size_hint_align_set(o, 0.0, 0.5);
+   elm_object_text_set(o, "E-mail:");
+   elm_box_pack_end(bx, o);
+   evas_object_show(o);
+
+   o = elm_entry_add(bx);
+   evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, 0.0);
+   evas_object_size_hint_align_set(o, EVAS_HINT_FILL, 0.5);
+   elm_entry_single_line_set(o, EINA_TRUE);
+   elm_entry_scrollable_set(o, EINA_TRUE);
+   elm_entry_scrollbar_policy_set(o, ELM_SCROLLER_POLICY_OFF, ELM_SCROLLER_POLICY_OFF);
+   txt = elm_entry_utf8_to_markup(config->helper.email);
+   if (txt)
+     {
+        elm_object_text_set(o, txt);
+        free(txt);
+     }
+   elm_box_pack_end(bx, o);
+   evas_object_show(o);
+   evas_object_smart_callback_add(o, "changed",
+                                  _cb_op_helper_email_chg, term);
+
+   o = elm_label_add(bx);
+   evas_object_size_hint_weight_set(o, 0.0, 0.0);
+   evas_object_size_hint_align_set(o, 0.0, 0.5);
+   elm_object_text_set(o, "URL (Images):");
+   elm_box_pack_end(bx, o);
+   evas_object_show(o);
+
+   o = elm_entry_add(bx);
+   evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, 0.0);
+   evas_object_size_hint_align_set(o, EVAS_HINT_FILL, 0.5);
+   elm_entry_single_line_set(o, EINA_TRUE);
+   elm_entry_scrollable_set(o, EINA_TRUE);
+   elm_entry_scrollbar_policy_set(o, ELM_SCROLLER_POLICY_OFF, ELM_SCROLLER_POLICY_OFF);
+   txt = elm_entry_utf8_to_markup(config->helper.url.image);
+   if (txt)
+     {
+        elm_object_text_set(o, txt);
+        free(txt);
+     }
+   elm_box_pack_end(bx, o);
+   evas_object_show(o);
+   evas_object_smart_callback_add(o, "changed",
+                                  _cb_op_helper_url_image_chg, term);
+   
+   o = elm_label_add(bx);
+   evas_object_size_hint_weight_set(o, 0.0, 0.0);
+   evas_object_size_hint_align_set(o, 0.0, 0.5);
+   elm_object_text_set(o, "URL (Video):");
+   elm_box_pack_end(bx, o);
+   evas_object_show(o);
+
+   o = elm_entry_add(bx);
+   evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, 0.0);
+   evas_object_size_hint_align_set(o, EVAS_HINT_FILL, 0.5);
+   elm_entry_single_line_set(o, EINA_TRUE);
+   elm_entry_scrollable_set(o, EINA_TRUE);
+   elm_entry_scrollbar_policy_set(o, ELM_SCROLLER_POLICY_OFF, ELM_SCROLLER_POLICY_OFF);
+   txt = elm_entry_utf8_to_markup(config->helper.url.video);
+   if (txt)
+     {
+        elm_object_text_set(o, txt);
+        free(txt);
+     }
+   elm_box_pack_end(bx, o);
+   evas_object_show(o);
+   evas_object_smart_callback_add(o, "changed",
+                                  _cb_op_helper_url_video_chg, term);
+   
+   o = elm_label_add(bx);
+   evas_object_size_hint_weight_set(o, 0.0, 0.0);
+   evas_object_size_hint_align_set(o, 0.0, 0.5);
+   elm_object_text_set(o, "URL (All):");
+   elm_box_pack_end(bx, o);
+   evas_object_show(o);
+
+   o = elm_entry_add(bx);
+   evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, 0.0);
+   evas_object_size_hint_align_set(o, EVAS_HINT_FILL, 0.5);
+   elm_entry_single_line_set(o, EINA_TRUE);
+   elm_entry_scrollable_set(o, EINA_TRUE);
+   elm_entry_scrollbar_policy_set(o, ELM_SCROLLER_POLICY_OFF, ELM_SCROLLER_POLICY_OFF);
+   txt = elm_entry_utf8_to_markup(config->helper.url.general);
+   if (txt)
+     {
+        elm_object_text_set(o, txt);
+        free(txt);
+     }
+   elm_box_pack_end(bx, o);
+   evas_object_show(o);
+   evas_object_smart_callback_add(o, "changed",
+                                  _cb_op_helper_url_general_chg, term);
+
+   o = elm_label_add(bx);
+   evas_object_size_hint_weight_set(o, 0.0, 0.0);
+   evas_object_size_hint_align_set(o, 0.0, 0.5);
+   elm_object_text_set(o, "Local (Images):");
+   elm_box_pack_end(bx, o);
+   evas_object_show(o);
+
+   o = elm_entry_add(bx);
+   evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, 0.0);
+   evas_object_size_hint_align_set(o, EVAS_HINT_FILL, 0.5);
+   elm_entry_single_line_set(o, EINA_TRUE);
+   elm_entry_scrollable_set(o, EINA_TRUE);
+   elm_entry_scrollbar_policy_set(o, ELM_SCROLLER_POLICY_OFF, ELM_SCROLLER_POLICY_OFF);
+   txt = elm_entry_utf8_to_markup(config->helper.local.image);
+   if (txt)
+     {
+        elm_object_text_set(o, txt);
+        free(txt);
+     }
+   elm_box_pack_end(bx, o);
+   evas_object_show(o);
+   evas_object_smart_callback_add(o, "changed",
+                                  _cb_op_helper_local_image_chg, term);
+   
+   o = elm_label_add(bx);
+   evas_object_size_hint_weight_set(o, 0.0, 0.0);
+   evas_object_size_hint_align_set(o, 0.0, 0.5);
+   elm_object_text_set(o, "Local (Video):");
+   elm_box_pack_end(bx, o);
+   evas_object_show(o);
+
+   o = elm_entry_add(bx);
+   evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, 0.0);
+   evas_object_size_hint_align_set(o, EVAS_HINT_FILL, 0.5);
+   elm_entry_single_line_set(o, EINA_TRUE);
+   elm_entry_scrollable_set(o, EINA_TRUE);
+   elm_entry_scrollbar_policy_set(o, ELM_SCROLLER_POLICY_OFF, ELM_SCROLLER_POLICY_OFF);
+   txt = elm_entry_utf8_to_markup(config->helper.local.video);
+   if (txt)
+     {
+        elm_object_text_set(o, txt);
+        free(txt);
+     }
+   elm_box_pack_end(bx, o);
+   evas_object_show(o);
+   evas_object_smart_callback_add(o, "changed",
+                                  _cb_op_helper_local_video_chg, term);
+   
+   o = elm_label_add(bx);
+   evas_object_size_hint_weight_set(o, 0.0, 0.0);
+   evas_object_size_hint_align_set(o, 0.0, 0.5);
+   elm_object_text_set(o, "Local (All):");
+   elm_box_pack_end(bx, o);
+   evas_object_show(o);
+
+   o = elm_entry_add(bx);
+   evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, 0.0);
+   evas_object_size_hint_align_set(o, EVAS_HINT_FILL, 0.5);
+   elm_entry_single_line_set(o, EINA_TRUE);
+   elm_entry_scrollable_set(o, EINA_TRUE);
+   elm_entry_scrollbar_policy_set(o, ELM_SCROLLER_POLICY_OFF, ELM_SCROLLER_POLICY_OFF);
+   txt = elm_entry_utf8_to_markup(config->helper.local.general);
+   if (txt)
+     {
+        elm_object_text_set(o, txt);
+        free(txt);
+     }
+   elm_box_pack_end(bx, o);
+   evas_object_show(o);
+   evas_object_smart_callback_add(o, "changed",
+                                  _cb_op_helper_local_general_chg, term);
+   
+   evas_object_size_hint_weight_set(opbox, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+   evas_object_size_hint_align_set(opbox, EVAS_HINT_FILL, EVAS_HINT_FILL);
+   evas_object_show(o);
+}
diff --git a/src/bin/options_helpers.h b/src/bin/options_helpers.h
new file mode 100644 (file)
index 0000000..da422e4
--- /dev/null
@@ -0,0 +1 @@
+void options_helpers(Evas_Object *opbox, Evas_Object *term);
index 3813b69..9bf7437 100644 (file)
@@ -10,6 +10,7 @@
 #include "keyin.h"
 #include "config.h"
 #include "utils.h"
+#include "media.h"
 
 typedef struct _Termio Termio;
 
@@ -43,6 +44,12 @@ struct _Termio
       } sel1, sel2;
       Eina_Bool sel : 1;
    } backup;
+   struct {
+      char *string;
+      int x1, y1, x2, y2;
+      int suspend;
+      Eina_List *objs;
+   } link;
    int zoom_fontsize_start;
    int scroll;
    unsigned int last_keyup;
@@ -51,6 +58,7 @@ struct _Termio
    Termpty *pty;
    Ecore_Animator *anim;
    Ecore_Timer *delayed_size_timer;
+   Ecore_Timer *link_do_timer;
    Ecore_Job *mouse_move_job;
    Evas_Object *win;
    Config *config;
@@ -59,6 +67,7 @@ struct _Termio
    Eina_Bool have_sel : 1;
    Eina_Bool noreqsize : 1;
    Eina_Bool composing : 1;
+   Eina_Bool didclick : 1;
 };
 
 static Evas_Smart *_smart = NULL;
@@ -100,8 +109,8 @@ coord_forward(Termio *sd, int *x, int *y)
    return EINA_TRUE;
 }
 
-static void
-_smart_mouseover_apply(Evas_Object *obj)
+static char *
+_magic_string_find(Evas_Object *obj, int cx, int cy, int *x1r, int *y1r, int *x2r, int *y2r)
 {
    Termio *sd = evas_object_smart_data_get(obj);
    char *s;
@@ -109,11 +118,11 @@ _smart_mouseover_apply(Evas_Object *obj)
    int x1, x2, y1, y2, len;
    Eina_Bool goback = EINA_TRUE, goforward = EINA_FALSE, extend = EINA_FALSE;
    
-   if (!sd) return;
-   x1 = sd->mouse.cx;
-   y1 = sd->mouse.cy;
-   x2 = sd->mouse.cx;
-   y2 = sd->mouse.cy;
+   if (!sd) return NULL;
+   x1 = cx;
+   y1 = cy;
+   x2 = cx;
+   y2 = cy;
    if (!coord_back(sd, &x1, &y1)) goback = EINA_FALSE;
    for (;;)
      {
@@ -125,6 +134,7 @@ _smart_mouseover_apply(Evas_Object *obj)
           {
              if      ((!strncasecmp(s, "http://", 7))||
                       (!strncasecmp(s, "https://", 8)) ||
+                      (!strncasecmp(s, "file://", 7)) ||
                       (!strncasecmp(s, "ftp://", 6)))
                {
                   goback = EINA_FALSE;
@@ -154,7 +164,8 @@ _smart_mouseover_apply(Evas_Object *obj)
                   else if (s[0] == '\'') endmatch = '\'';
                   else if (s[0] == '<') endmatch = '>';
                   if ((!strncasecmp((s + 1), "www.", 4)) ||
-                      (!strncasecmp((s + 1), "ftp.", 4)))
+                      (!strncasecmp((s + 1), "ftp.", 4)) ||
+                      (!strncasecmp((s + 1), "/", 1)))
                     {
                        goback = EINA_FALSE;
                        coord_forward(sd, &x1, &y1);
@@ -164,6 +175,9 @@ _smart_mouseover_apply(Evas_Object *obj)
                        goback = EINA_FALSE;
                        coord_forward(sd, &x1, &y1);
                     }
+                  else if (s[0] == '=')
+                    {
+                    }
                   else
                     {
                        free(s);
@@ -178,7 +192,9 @@ _smart_mouseover_apply(Evas_Object *obj)
              if (len > 1)
                {
                   if (((endmatch) && (s[len - 1] == endmatch)) ||
-                      ((!endmatch) && (isspace(s[len - 1]))))
+                      ((!endmatch) && 
+                          ((isspace(s[len - 1])) || (s[len - 1] == '>'))
+                      ))
                     {
                        goforward = EINA_FALSE;
                        coord_back(sd, &x2, &y2);
@@ -194,7 +210,7 @@ _smart_mouseover_apply(Evas_Object *obj)
           {
              if (!coord_back(sd, &x1, &y1)) goback = EINA_FALSE;
           }
-        else if (!extend)
+        if ((!extend) && (!goback))
           {
              goforward = EINA_TRUE;
              extend = EINA_TRUE;
@@ -222,21 +238,307 @@ _smart_mouseover_apply(Evas_Object *obj)
                }
              else break;
           }
-        if (!isspace(s[0]))
+        if ((!isspace(s[0])) && (len > 1))
           {
              if ((strchr(s, '@')) ||
                  (!strncasecmp(s, "http://", 7))||
                  (!strncasecmp(s, "https://", 8)) ||
                  (!strncasecmp(s, "ftp://", 6)) ||
+                 (!strncasecmp(s, "file://", 7)) ||
                  (!strncasecmp(s, "www.", 4)) ||
-                 (!strncasecmp(s, "ftp.", 4)))
+                 (!strncasecmp(s, "ftp.", 4)) ||
+                 (!strncasecmp(s, "/", 1))
+                )
+               {
+                  if (x1r) *x1r = x1;
+                  if (y1r) *y1r = y1;
+                  if (x2r) *x2r = x2;
+                  if (y2r) *y2r = y2;
+                  return s;
+               }
+          }
+        free(s);
+     }
+   return NULL;
+}
+
+static void
+_activate_link(Evas_Object *obj)
+{
+   Termio *sd = evas_object_smart_data_get(obj);
+   Config *config = termio_config_get(obj);
+   char buf[PATH_MAX], *s;
+   const char *path = NULL, *cmd = NULL;
+   Eina_Bool url = EINA_FALSE, email = EINA_FALSE, handled = EINA_FALSE;
+   int type;
+   
+   if (!sd) return;
+   if (!config) return;
+   if (!sd->link.string) return;
+   if      ((!strncasecmp(sd->link.string, "http://", 7))||
+            (!strncasecmp(sd->link.string, "https://", 8)) ||
+            (!strncasecmp(sd->link.string, "ftp://", 6)) ||
+            (!strncasecmp(sd->link.string, "www.", 4)) ||
+            (!strncasecmp(sd->link.string, "ftp.", 4)))
+     {
+        url = EINA_TRUE;
+     }
+   else if ((!strncasecmp(sd->link.string, "file://", 7)) ||
+            (!strncasecmp(sd->link.string, "/", 1)))
+     {
+        path = sd->link.string;
+        if (!strncasecmp(sd->link.string, "file://", 7)) path = path + 7;
+     }
+   else if (strchr(sd->link.string, '@'))
+     {
+        email = EINA_TRUE;
+     }
+   
+   s = eina_str_escape(sd->link.string);
+   if (!s) return;
+   if (email)
+     {
+        // run mail client
+        cmd = "xdg-email";
+        
+        if ((config->helper.email) &&
+            (config->helper.email[0]))
+          cmd = config->helper.email;
+        snprintf(buf, sizeof(buf), "%s %s", cmd, s);
+     }
+   else if (path)
+     {
+        // locally accessible file
+        cmd = "xdg-open";
+        
+        type = media_src_type_get(sd->link.string);
+        if (config->helper.inline_please)
+          {
+             if ((type == TYPE_IMG) ||
+                 (type == TYPE_SCALE) ||
+                 (type == TYPE_EDJE))
+               {
+                  evas_object_smart_callback_call(obj, "popup", NULL);
+                  handled = EINA_TRUE;
+               }
+             else if (type == TYPE_MOV)
+               {
+                  evas_object_smart_callback_call(obj, "popup", NULL);
+                  handled = EINA_TRUE;
+               }
+          }
+        if (!handled)
+          {
+             if ((type == TYPE_IMG) ||
+                 (type == TYPE_SCALE) ||
+                 (type == TYPE_EDJE))
+               {
+                  if ((config->helper.local.image) &&
+                      (config->helper.local.image[0]))
+                    cmd = config->helper.local.image;
+               }
+             else if (type == TYPE_MOV)
+               {
+                  if ((config->helper.local.video) &&
+                      (config->helper.local.video[0]))
+                    cmd = config->helper.local.video;
+               }
+             else
+               {
+                  if ((config->helper.local.general) &&
+                      (config->helper.local.general[0]))
+                    cmd = config->helper.local.general;
+               }
+             snprintf(buf, sizeof(buf), "%s %s", cmd, s);
+          }
+     }
+   else if (url)
+     {
+        // remote file needs ecore-con-url
+        cmd = "xdg-open";
+        
+        type = media_src_type_get(sd->link.string);
+        if (config->helper.inline_please)
+          {
+             if ((type == TYPE_IMG) ||
+                 (type == TYPE_SCALE) ||
+                 (type == TYPE_EDJE))
+               {
+                  // XXX: begin fetch of url, once done, show
+                  evas_object_smart_callback_call(obj, "popup", NULL);
+                  handled = EINA_TRUE;
+               }
+             else if (type == TYPE_MOV)
+               {
+                  // XXX: if no http:// add
+                  evas_object_smart_callback_call(obj, "popup", NULL);
+                  handled = EINA_TRUE;
+               }
+          }
+        if (!handled)
+          {
+             if ((type == TYPE_IMG) ||
+                 (type == TYPE_SCALE) ||
+                 (type == TYPE_EDJE))
                {
-                  printf("FOUND: '%s' @ %i,%i -> %i,%i\n", s, x1, y1, x2, y2);
-                  // XXX: record coords and url string
+                  if ((config->helper.url.image) &&
+                      (config->helper.url.image[0]))
+                    cmd = config->helper.url.image;
                }
+             else if (type == TYPE_MOV)
+               {
+                  if ((config->helper.url.video) &&
+                      (config->helper.url.video[0]))
+                    cmd = config->helper.url.video;
+               }
+             else
+               {
+                  if ((config->helper.url.general) &&
+                      (config->helper.url.general[0]))
+                    cmd = config->helper.url.general;
+               }
+             snprintf(buf, sizeof(buf), "%s %s", cmd, s);
           }
+     }
+   else
+     {
         free(s);
+        return;
      }
+   free(s);
+   if (!handled) ecore_exe_run(buf, NULL);
+}
+
+static Eina_Bool
+_cb_link_up_delay(void *data)
+{
+   Termio *sd = evas_object_smart_data_get(data);
+   
+   if (!sd) return EINA_FALSE;
+   sd->link_do_timer = NULL;
+   if (!sd->didclick) _activate_link(data);
+   sd->didclick = EINA_FALSE;
+   return EINA_FALSE;
+}
+
+static void
+_cb_link_up(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event)
+{
+   Evas_Event_Mouse_Up *ev = event;
+   Termio *sd = evas_object_smart_data_get(data);
+   
+   if (!sd) return;
+   if (ev->button == 1)
+     {
+        if (sd->link_do_timer) ecore_timer_del(sd->link_do_timer);
+        sd->link_do_timer = ecore_timer_add(0.2, _cb_link_up_delay, data);
+     }
+}
+
+static void
+_update_link(Evas_Object *obj, Eina_Bool same_link, Eina_Bool same_geom)
+{
+   Termio *sd = evas_object_smart_data_get(obj);
+   
+   if (!sd) return;
+   
+   if (!same_link)
+     {
+        // check link and re-probe/fetch create popup preview
+     }
+   
+   if (!same_geom)
+     {
+        Evas_Coord ox, oy, ow, oh;
+        Evas_Object *o;
+        // fix up edje objects "underlining" the link
+        int y;
+        
+        evas_object_geometry_get(obj, &ox, &oy, &ow, &oh);
+        EINA_LIST_FREE(sd->link.objs, o) evas_object_del(o);
+        if ((sd->link.string) && (sd->link.suspend == 0))
+          {
+             for (y = sd->link.y1; y <= sd->link.y2; y++)
+               {
+                  o = edje_object_add(evas_object_evas_get(obj));
+                  evas_object_smart_member_add(o, obj);
+                  theme_apply(o, sd->config, "terminology/link");
+                  
+                  if (y == sd->link.y1)
+                    {
+                       evas_object_move(o, ox + (sd->link.x1 * sd->font.chw),
+                                        oy + (y * sd->font.chh));
+                       if (sd->link.y1 == sd->link.y2)
+                         evas_object_resize(o,
+                                            ((sd->link.x2 - sd->link.x1 + 1) * sd->font.chw),
+                                            sd->font.chh);
+                       else
+                         evas_object_resize(o,
+                                            ((sd->grid.w - sd->link.x1) * sd->font.chw),
+                                            sd->font.chh);
+                    }
+                  else if (y == sd->link.y2)
+                    {
+                       evas_object_move(o, ox, oy + (y * sd->font.chh));
+                       evas_object_resize(o,
+                                          ((sd->link.x2 + 1) * sd->font.chw),
+                                          sd->font.chh);
+                    }
+                  else
+                    {
+                       evas_object_move(o, ox, oy + (y * sd->font.chh));
+                       evas_object_resize(o, (sd->grid.w * sd->font.chw),
+                                          sd->font.chh);
+                    }
+                  
+                  sd->link.objs = eina_list_append(sd->link.objs, o);
+                  evas_object_show(o);
+                  evas_object_event_callback_add(o, EVAS_CALLBACK_MOUSE_UP,
+                                                 _cb_link_up, obj);
+               }
+          }
+     }
+}
+
+static void
+_smart_mouseover_apply(Evas_Object *obj)
+{
+   char *s;
+   int x1 = 0, y1 = 0, x2 = 0, y2 = 0;
+   Eina_Bool same_link = EINA_FALSE, same_geom = EINA_FALSE;
+   Termio *sd = evas_object_smart_data_get(obj);
+   
+   if (!sd) return;
+
+   s = _magic_string_find(obj, sd->mouse.cx, sd->mouse.cy,
+                         &x1, &y1, &x2, &y2);
+   if (!s)
+     {
+        if (sd->link.string) free(sd->link.string);
+        sd->link.string = NULL;
+        sd->link.x1 = -1;
+        sd->link.y1 = -1;
+        sd->link.x2 = -1;
+        sd->link.y2 = -1;
+        _update_link(obj, same_link, same_geom);
+        return;
+     }
+   
+   if ((sd->link.string) && (!strcmp(sd->link.string, s)))
+     same_link = EINA_TRUE;
+   if (sd->link.string) free(sd->link.string);
+   sd->link.string = s;
+   if ((x1 == sd->link.x1) && (y1 == sd->link.y1) &&
+       (x2 == sd->link.x2) && (y2 == sd->link.y2))
+     same_geom = EINA_TRUE;
+   if (((sd->link.suspend != 0) && (sd->link.objs)) ||
+       ((sd->link.suspend == 0) && (!sd->link.objs)))
+     same_geom = EINA_FALSE;
+   sd->link.x1 = x1;
+   sd->link.y1 = y1;
+   sd->link.x2 = x2;
+   sd->link.y2 = y2;
+   _update_link(obj, same_link, same_geom);
 }
 
 static void
@@ -1272,12 +1574,14 @@ _smart_cb_mouse_down(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__
    if (!sd) return;
    _smart_xy_to_cursor(data, ev->canvas.x, ev->canvas.y, &cx, &cy);
    _rep_mouse_down(data, ev, cx, cy);
+   sd->didclick = EINA_FALSE;
    if (ev->button == 1)
      {
         if (ev->flags & EVAS_BUTTON_TRIPLE_CLICK)
           {
              _sel_line(data, cx, cy - sd->scroll);
              if (sd->cur.sel) _take_selection(data, ELM_SEL_TYPE_PRIMARY);
+             sd->didclick = EINA_TRUE;
           }
         else if (ev->flags & EVAS_BUTTON_DOUBLE_CLICK)
           {
@@ -1296,6 +1600,7 @@ _smart_cb_mouse_down(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__
                   _sel_word(data, cx, cy - sd->scroll);
                }
              if (sd->cur.sel) _take_selection(data, ELM_SEL_TYPE_PRIMARY);
+             sd->didclick = EINA_TRUE;
           }
         else
           {
@@ -1304,7 +1609,11 @@ _smart_cb_mouse_down(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__
              sd->backup.sel1.y = sd->cur.sel1.y;
              sd->backup.sel2.x = sd->cur.sel2.x;
              sd->backup.sel2.y = sd->cur.sel2.y;
-             if (sd->cur.sel) sd->cur.sel = 0;
+             if (sd->cur.sel)
+               {
+                  sd->cur.sel = 0;
+                  sd->didclick = EINA_TRUE;
+               }
              sd->cur.makesel = 1;
              sd->cur.sel1.x = cx;
              sd->cur.sel1.y = cy - sd->scroll;
@@ -1336,6 +1645,7 @@ _smart_cb_mouse_up(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
         sd->cur.makesel = 0;
         if (sd->cur.sel)
           {
+             sd->didclick = EINA_TRUE;
              sd->cur.sel2.x = cx;
              sd->cur.sel2.y = cy - sd->scroll;
              _selection_dbl_fix(data);
@@ -1381,6 +1691,18 @@ _smart_cb_mouse_move(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__
 }
 
 static void
+_smart_cb_mouse_in(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event __UNUSED__)
+{
+   termio_mouseover_suspend_pushpop(data, -1);
+}
+
+static void
+_smart_cb_mouse_out(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event __UNUSED__)
+{
+   termio_mouseover_suspend_pushpop(data, 1);
+}
+
+static void
 _smart_cb_mouse_wheel(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event)
 {
    Evas_Event_Mouse_Wheel *ev = event;
@@ -1468,6 +1790,7 @@ _smart_cb_gest_long_move(void *data, void *event __UNUSED__)
    
    if (!sd) return EVAS_EVENT_FLAG_ON_HOLD;
    evas_object_smart_callback_call(data, "options", NULL);
+   sd->didclick = EINA_TRUE;
    return EVAS_EVENT_FLAG_ON_HOLD;
 }
 
@@ -1484,6 +1807,7 @@ _smart_cb_gest_zoom_start(void *data, void *event)
         sd->zoom_fontsize_start = config->font.size;
         _font_size_set(data, (double)sd->zoom_fontsize_start * p->zoom);
      }
+   sd->didclick = EINA_TRUE;
    return EVAS_EVENT_FLAG_ON_HOLD;
 }
 
@@ -1500,6 +1824,7 @@ _smart_cb_gest_zoom_move(void *data, void *event)
         sd->zoom_fontsize_start = config->font.size;
         _font_size_set(data, (double)sd->zoom_fontsize_start * p->zoom);
      }
+   sd->didclick = EINA_TRUE;
    return EVAS_EVENT_FLAG_ON_HOLD;
 }
 
@@ -1516,6 +1841,7 @@ _smart_cb_gest_zoom_end(void *data, void *event)
         sd->zoom_fontsize_start = config->font.size;
         _font_size_set(data, (double)sd->zoom_fontsize_start * p->zoom);
      }
+   sd->didclick = EINA_TRUE;
    return EVAS_EVENT_FLAG_ON_HOLD;
 }
 
@@ -1532,6 +1858,7 @@ _smart_cb_gest_zoom_abort(void *data, void *event __UNUSED__)
         sd->zoom_fontsize_start = config->font.size;
         _font_size_set(data, sd->zoom_fontsize_start);
      }
+   sd->didclick = EINA_TRUE;
    return EVAS_EVENT_FLAG_ON_HOLD;
 }
 
@@ -1631,6 +1958,10 @@ _smart_add(Evas_Object *obj)
                                   _smart_cb_mouse_up, obj);
    evas_object_event_callback_add(o, EVAS_CALLBACK_MOUSE_MOVE,
                                   _smart_cb_mouse_move, obj);
+   evas_object_event_callback_add(o, EVAS_CALLBACK_MOUSE_IN,
+                                  _smart_cb_mouse_in, obj);
+   evas_object_event_callback_add(o, EVAS_CALLBACK_MOUSE_OUT,
+                                  _smart_cb_mouse_out, obj);
    evas_object_event_callback_add(o, EVAS_CALLBACK_MOUSE_WHEEL,
                                   _smart_cb_mouse_wheel, obj);
 
@@ -1643,6 +1974,8 @@ _smart_add(Evas_Object *obj)
    evas_object_event_callback_add(obj, EVAS_CALLBACK_FOCUS_OUT,
                                   _smart_cb_focus_out, obj);
 
+   sd->link.suspend = 1;
+   
    if (ecore_imf_init())
      {
         const char *imf_id = ecore_imf_context_default_id_get();
@@ -1699,7 +2032,9 @@ static void
 _smart_del(Evas_Object *obj)
 {
    char *str;
+   Evas_Object *o;
    Termio *sd = evas_object_smart_data_get(obj);
+   
    if (!sd) return;
    if (sd->imf)
      {
@@ -1714,9 +2049,12 @@ _smart_del(Evas_Object *obj)
    if (sd->cur.selo3) evas_object_del(sd->cur.selo3);
    if (sd->anim) ecore_animator_del(sd->anim);
    if (sd->delayed_size_timer) ecore_timer_del(sd->delayed_size_timer);
+   if (sd->link_do_timer) ecore_timer_del(sd->link_do_timer);
    if (sd->mouse_move_job) ecore_job_del(sd->mouse_move_job);
    if (sd->font.name) eina_stringshare_del(sd->font.name);
    if (sd->pty) termpty_free(sd->pty);
+   if (sd->link.string) free(sd->link.string);
+   EINA_LIST_FREE(sd->link.objs, o) evas_object_del(o);
    EINA_LIST_FREE(sd->seq, str) eina_stringshare_del(str);
    sd->cur.obj = NULL;
    sd->event = NULL;
@@ -1993,6 +2331,7 @@ termio_selection_get(Evas_Object *obj, int c1x, int c1y, int c2x, int c2y)
         w = 0;
         last0 = -1;
         cells = termpty_cellrow_get(sd->pty, y, &w);
+        if (!cells) continue;
         if (w > sd->grid.w) w = sd->grid.w;
         start_x = c1x;
         end_x = c2x;
@@ -2165,3 +2504,21 @@ termio_paste_clipboard(Evas_Object *obj)
 {
    _paste_selection(obj, ELM_SEL_TYPE_CLIPBOARD);
 }
+
+const char  *
+termio_link_get(const Evas_Object *obj)
+{
+   Termio *sd = evas_object_smart_data_get(obj);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(sd, NULL);
+   return sd->link.string;
+}
+
+void
+termio_mouseover_suspend_pushpop(Evas_Object *obj, int dir)
+{
+   Termio *sd = evas_object_smart_data_get(obj);
+   if (!sd) return;
+   sd->link.suspend += dir;
+   if (sd->link.suspend < 0) sd->link.suspend = 0;
+   _smart_update_queue(obj, sd);
+}
index d727468..108d535 100644 (file)
@@ -10,5 +10,6 @@ void         termio_config_update(Evas_Object *obj);
 Config      *termio_config_get(const Evas_Object *obj);
 void         termio_copy_clipboard(Evas_Object *obj);
 void         termio_paste_clipboard(Evas_Object *obj);
-
+const char  *termio_link_get(const Evas_Object *obj);
+void         termio_mouseover_suspend_pushpop(Evas_Object *obj, int dir);
 #endif