Clean up a lot of ephoto.. Things that weren't necessary, things that are no longer necessary, etc... Add a true flow view that is a work in progress. Currently ephoto will only open images in the current working directory or in a directory supplied in an argument when started, but this will change when directory stuff is added back in. This gives ephoto more direction and provides a solid base to move forward from. Also, yes, I removed edje externals and I am not using them. There are multiple reasons for this that are all of my opinion and if you would like to discuss it, see me on irc or send out a mail on the list.

SVN revision: 56640
v-1.6.0
titan 13 years ago committed by titan
parent 3f51d392eb
commit c478bfdeee
  1. 598
      data/themes/default/ephoto.edc
  2. 8
      src/bin/Makefile.am
  3. 94
      src/bin/ephoto.c
  4. 186
      src/bin/ephoto.h
  5. 158
      src/bin/ephoto_config.c
  6. 176
      src/bin/ephoto_directory_thumb.c
  7. 1145
      src/bin/ephoto_flow_browser.c
  8. 548
      src/bin/ephoto_main.c
  9. 189
      src/bin/ephoto_preferences.c
  10. 691
      src/bin/ephoto_thumb_browser.c

@ -1,313 +1,289 @@
externals {
external: "elm";
}
collections {
images {
image: "up-128.png" COMP;
image: "directory-128.png" COMP;
image: "raise.png" COMP;
}
group { name: "elm/layout/ephoto/orient";
parts {
part { name: "elm.swallow.content";
type: SWALLOW;
description { state: "default" 0.0;
}
description { state: "rotate_0" 0.0;
inherit: "default" 0.0;
map {
on: 1;
rotation.z: 0;
}
}
description { state: "rotate_90" 0.0;
inherit: "default" 0.0;
map {
on: 1;
rotation.z: 90;
}
}
description { state: "rotate_180" 0.0;
inherit: "default" 0.0;
map {
on: 1;
rotation.z: 180;
}
}
description { state: "rotate_270" 0.0;
inherit: "default" 0.0;
map {
on: 1;
rotation.z: 270;
}
}
description { state: "flip_horiz" 0.0;
inherit: "default" 0.0;
map {
on: 1;
rotation.y: 180;
}
}
description { state: "flip_vert" 0.0;
inherit: "default" 0.0;
map {
on: 1;
rotation.x: 180;
}
}
description { state: "flip_horiz_90" 0.0;
inherit: "default" 0.0;
map {
on: 1;
rotation {
z: 90;
y: 180;
}
}
}
description { state: "flip_vert_90" 0.0;
inherit: "default" 0.0;
map {
on: 1;
rotation {
z: 90;
x: 180;
}
}
}
}
programs {
program {
signal: "state,rotate,0";
source: "ephoto";
action: STATE_SET "rotate_0" 0.0;
target: "elm.swallow.content";
}
program {
signal: "state,rotate,90";
source: "ephoto";
action: STATE_SET "rotate_90" 0.0;
target: "elm.swallow.content";
}
program {
signal: "state,rotate,180";
source: "ephoto";
action: STATE_SET "rotate_180" 0.0;
target: "elm.swallow.content";
}
program {
signal: "state,rotate,270";
source: "ephoto";
action: STATE_SET "rotate_270" 0.0;
target: "elm.swallow.content";
}
program {
signal: "state,flip,horiz";
source: "ephoto";
action: STATE_SET "flip_horiz" 0.0;
target: "elm.swallow.content";
}
program {
signal: "state,flip,vert";
source: "ephoto";
action: STATE_SET "flip_vert" 0.0;
target: "elm.swallow.content";
}
program {
signal: "state,flip,horiz,90";
source: "ephoto";
action: STATE_SET "flip_horiz_90" 0.0;
target: "elm.swallow.content";
}
program {
signal: "state,flip,vert,90";
source: "ephoto";
action: STATE_SET "flip_vert_90" 0.0;
target: "elm.swallow.content";
}
}
}
}
group { name: "ephoto,thumb,grid";
parts {
part { name: "ephoto.swallow.content.thumb";
type: SWALLOW;
mouse_events: 1;
description {
state: "default" 0.0;
rel1.relative: 0.0 0.0;
rel1.offset: 0 0;
rel2.relative: 1.0 1.0;
rel2.offset: -1 -1;
}
}
part { name: "overlay";
type: RECT;
mouse_events: 1;
description {
min: 1 40;
max: 9999 40;
fixed: 0 1;
state: "default" 0.0;
rel1.to: "ephoto.swallow.content.thumb";
rel1.relative: 0.0 0.0;
rel1.offset: 5 45;
rel2.to: "ephoto.swallow.content.thumb";
rel2.relative: 1.0 0.0;
rel2.offset: -5 0;
color: 0 0 0 120;
}
description {
state: "lowered" 0.0;
rel1.to: "ephoto.swallow.content.thumb";
rel1.relative: 0.0 0.0;
rel1.offset: 5 5;
rel2.to: "ephoto.swallow.content.thumb";
rel2.relative: 1.0 1.0;
rel2.offset: -5 -5;
color: 255 255 255 255;
}
}
part { name: "ephoto.swallow.content.dir";
type: SWALLOW;
mouse_events: 1;
description {
state: "default" 0.0;
visible: 0;
rel1.to: "ephoto.swallow.content.thumb";
rel1.relative: 0.0 0.0;
rel1.offset: 0 0;
rel1.to: "ephoto.swallow.content.thumb";
rel2.relative: 1.0 1.0;
rel2.offset: -1 -1;
}
description {
state: "lowered" 0.0;
inherit: "default" 0.0;
visible: 1;
}
}
part { name: "up";
type: IMAGE;
mouse_events: 1;
description
{
min: 32 32;
max: 32 32;
fixed: 1 1;
state: "default" 0.0;
rel1.to: "overlay";
rel1.relative: 0.0 0.0;
rel1.offset: 20 20;
rel2.to: "overlay";
rel2.relative: 0.0 0.0;
rel2.offset: 20 20;
image.normal: "up-128.png";
}
description {
state: "lowered" 0.0;
inherit: "default" 0.0;
visible: 0;
}
}
part { name: "directory";
type: IMAGE;
mouse_events: 1;
description
{
min: 32 32;
max: 32 32;
fixed: 1 1;
state: "default" 0.0;
visible: 1;
rel1.to: "overlay";
rel1.relative: 1.0 0.0;
rel1.offset: -20 20;
rel2.to: "overlay";
rel2.relative: 1.0 0.0;
rel2.offset: -20 20;
image.normal: "directory-128.png";
}
description
{
state: "lowered" 0.0;
inherit: "default" 0.0;
visible: 0;
}
}
part { name: "raise";
type: IMAGE;
mouse_events: 1;
description
{
min: 32 32;
max: 32 32;
fixed: 1 1;
visible: 0;
state: "default" 0.0;
rel1.to: "overlay";
rel1.relative: 1.0 0.0;
rel1.offset: -20 20;
rel2.to: "overlay";
rel2.relative: 1.0 0.0;
rel2.offset: -20 20;
image.normal: "raise.png";
}
description
{
state: "lowered" 0.0;
inherit: "default" 0.0;
visible: 1;
}
}
}
programs {
program { name: "up_clicked";
source: "up";
signal: "mouse,up,*";
action: SIGNAL_EMIT "ephoto.signal.up" "ephoto";
}
program { name: "dir_clicked";
source: "directory";
signal: "mouse,up,*";
action: SIGNAL_EMIT "ephoto.signal.dir" "ephoto";
after: "lower2";
}
program { name: "raise_clicked";
source: "raise";
signal: "mouse,up,*";
action: SIGNAL_EMIT "ephoto.signal.raise" "ephoto";
after: "raise2";
}
program { name: "lower";
action: STATE_SET "lowered" 0.0;
transition: ACCELERATE 0.6;
target: "overlay";
after: "lower3";
}
program { name: "lower2";
action: STATE_SET "lowered" 0.0;
target: "directory";
target: "raise";
after: "lower";
}
program { name: "lower3";
action: STATE_SET "lowered" 0.0;
target: "ephoto.swallow.content.dir";
}
program { name: "raise";
action: STATE_SET "default" 0.0;
transition: ACCELERATE 0.6;
target: "overlay";
}
program { name: "raise2";
action: STATE_SET "default" 0.0;
target: "directory";
target: "raise";
target: "ephoto.swallow.content.dir";
after: "raise";
}
}
}
group
{
name: "flow";
parts
{
part
{
name: "flow";
type: RECT;
mouse_events: 1;
description
{
state: default 0.0;
rel1.relative: 0.0 0.0;
rel1.offset: 0 0;
rel2.relative: 1.0 1.0;
rel2.offset: -1 -1;
color: 0 0 0 255;
}
}
part
{
name: "offscreen_left";
type: SWALLOW;
mouse_events: 1;
description
{
state: default 0.0;
visible: 0;
rel1.relative: 0.0 0.4;
rel1.offset: 0 0;
rel2.relative: 0.0 0.6;
rel2.offset: 0 0;
color: 255 255 255 255;
}
description
{
state: right 0.0;
visible: 1;
rel1.relative: 0.0 0.3;
rel1.offset: 0 0;
rel2.relative: 0.1 0.7;
rel2.offset: 0 0;
color: 255 255 255 255;
}
description
{
state: left 0.0;
visible: 0;
rel1.relative: 1.0 0.4;
rel1.offset: 0 0;
rel2.relative: 1.0 0.6;
rel2.offset: 0 0;
color: 255 255 255 255;
}
}
part
{
name: "left";
type: SWALLOW;
mouse_events: 1;
description
{
state: default 0.0;
visible: 1;
rel1.relative: 0.0 0.3;
rel1.offset: 0 0;
rel2.relative: 0.1 0.7;
rel2.offset: 0 0;
color: 255 255 255 255;
}
description
{
state: right 0.0;
rel1.relative: 0.2 0.2;
rel1.offset: 0 0;
rel2.relative: 0.8 0.8;
rel2.offset: 0 0;
color: 255 255 255 255;
}
description
{
state: left 0.0;
rel1.relative: 0.0 0.4;
rel1.offset: 0 0;
rel2.relative: 0.0 0.6;
rel2.offset: 0 0;
color: 255 255 255 255;
}
description
{
state: full 0.0;
inherit: default 0.0;
visible: 0;
color: 255 255 255 0;
}
}
part
{
name: "right";
type: SWALLOW;
mouse_events: 1;
description
{
state: default 0.0;
visible: 1;
rel1.relative: 0.9 0.3;
rel1.offset: 0 0;
rel2.relative: 1.0 0.7;
rel2.offset: 0 0;
color: 255 255 255 255;
}
description
{
state: right 0.0;
rel1.relative: 1.0 0.4;
rel1.offset: 0 0;
rel2.relative: 1.0 0.6;
rel2.offset: 0 0;
color: 255 255 255 255;
}
description
{
state: left 0.0;
rel1.relative: 0.2 0.2;
rel1.offset: 0 0;
rel2.relative: 0.8 0.8;
rel2.offset: 0 0;
color: 255 255 255 255;
}
description
{
state: full 0.0;
inherit: default 0.0;
visible: 0;
color: 255 255 255 0;
}
}
part
{
name: "center";
type: SWALLOW;
mouse_events: 1;
description
{
state: default 0.0;
rel1.relative: 0.2 0.2;
rel1.offset: 0 0;
rel2.relative: 0.8 0.8;
rel2.offset: 0 0;
color: 255 255 255 255;
}
description
{
state: right 0.0;
rel1.relative: 0.9 0.3;
rel1.offset: 0 0;
rel2.relative: 1.0 0.7;
rel2.offset: 0 0;
color: 255 255 255 255;
}
description
{
state: left 0.0;
rel1.relative: 0.0 0.3;
rel1.offset: 0 0;
rel2.relative: 0.1 0.7;
rel2.offset: 0 0;
color: 255 255 255 255;
}
description
{
state: full 0.0;
rel1.relative: 0.0 0.0;
rel1.offset: 0 0;
rel2.relative: 1.0 1.0;
rel2.offset: -1 -1;
}
}
part
{
name: "offscreen_right";
type: SWALLOW;
mouse_events: 1;
description
{
state: default 0.0;
visible: 0;
rel1.relative: 1.0 0.4;
rel1.offset: 0 0;
rel2.relative: 1.0 0.6;
rel2.offset: 0 0;
color: 255 255 255 255;
}
description
{
state: right 0.0;
visible: 0;
rel1.relative: 0.0 0.4;
rel1.offset: 0 0;
rel2.relative: 0.0 0.6;
rel2.offset: 0 0;
color: 255 255 255 255;
}
description
{
state: left 0.0;
visible: 1;
rel1.relative: 0.9 0.3;
rel1.offset: 0 0;
rel2.relative: 1.0 0.7;
rel2.offset: 0 0;
color: 255 255 255 255;
}
}
}
programs
{
program
{
name: "right";
signal: "right";
source: "ephoto";
action: STATE_SET right 0.0;
transition: LINEAR 0.4;
target: "offscreen_left";
target: "left";
target: "center";
target: "right";
target: "offscreen_right";
after: "done";
}
program
{
name: "left";
signal: "left";
source: "ephoto";
action: STATE_SET left 0.0;
transition: LINEAR 0.4;
target: "offscreen_left";
target: "left";
target: "center";
target: "right";
target: "offscreen_right";
after: "done";
}
program
{
name: "full";
signal: "full";
source: "ephoto";
action: STATE_SET full 0.0;
transition: LINEAR 0.4;
target: "left";
target: "right";
target: "center";
}
program
{
name: "full_reset";
signal: "full_reset";
source: "ephoto";
action: STATE_SET default 0.0;
transition: LINEAR 0.4;
target: "left";
target: "right";
target: "center";
}
program
{
name: "done";
action: SIGNAL_EMIT "done" "ephoto";
}
program
{
name: "reset";
signal: "reset";
source: "ephoto";
action: STATE_SET default 0.0;
target: "offscreen_left";
target: "left";
target: "center";
target: "right";
target: "offscreen_right";
}
}
}
}

@ -16,12 +16,8 @@ endif
_sources = \
ephoto.c \
ephoto_main.c \
ephoto_config.c \
ephoto_preferences.c \
ephoto_thumb_browser.c \
ephoto_flow_browser.c \
ephoto_slideshow.c \
ephoto_directory_thumb.c
ephoto_flow_browser.c \
ephoto_thumb_browser.c
_libs = @ELEMENTARY_LIBS@ @EFREET_MIME_LIBS@ @EIO_LIBS@ @EXIF_LIBS@

@ -1,15 +1,9 @@
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <Elementary.h>
#ifndef ELM_LIB_QUICKLAUNCH
#include "ephoto.h"
static void _ephoto_display_usage(void);
#ifndef ELM_LIB_QUICKLAUNCH
/* Global log domain pointer */
int __log_domain = -1;
static void _ephoto_display_usage(void);
Ephoto *ephoto;
EAPI int
elm_main(int argc, char **argv)
@ -29,94 +23,86 @@ elm_main(int argc, char **argv)
elm_need_ethumb();
elm_init(argc, argv);
elm_theme_extension_add(NULL, PACKAGE_DATA_DIR"/themes/default/ephoto.edj");
elm_theme_extension_add(NULL, PACKAGE_DATA_DIR "/themes/default/ephoto.edj");
if (!efreet_mime_init())
fprintf(stderr, "Could not init efreet_mime!\n");
printf("Ephoto could not init efreet_mime!\n");
client = elm_thumb_ethumb_client_get();
if (!client)
{
ERR("could not get ethumb_client");
printf("Ephoto could not get ethumb_client; Terminating...\n");
r = 1;
goto end_log_domain;
goto end;
}
ethumb_client_crop_align_set(client, 0.5, 0.5);
ethumb_client_aspect_set(client, ETHUMB_THUMB_CROP);
ethumb_client_orientation_set(client, ETHUMB_THUMB_ORIENT_ORIGINAL);
__log_domain = eina_log_domain_register("ephoto", EINA_COLOR_ORANGE);
if (!__log_domain)
{
EINA_LOG_ERR("Could not register log domain: Ephoto");
r = 1;
goto end_log_domain;
}
elm_policy_set(ELM_POLICY_QUIT, ELM_POLICY_QUIT_LAST_WINDOW_CLOSED);
DBG("Logging initialized");
ephoto = calloc(1, sizeof(Ephoto));
ephoto->client = client;
if (argc > 2)
{
printf("Too Many Arguments!\n");
printf("Too many arguments; Terminating...\n");
_ephoto_display_usage();
r = 1;
goto end;
}
else if (argc < 2)
if (argc == 2)
{
Evas_Object *win = ephoto_window_add(NULL);
if (!win)
if (!strncmp(argv[1], "--help", 6) || !strncmp(argv[1], "-h", 2))
{
r = 1;
_ephoto_display_usage();
r = 0;
goto end;
}
else if (argc == 2)
{
char *real = ecore_file_realpath(argv[1]);
if (!real)
{
printf("Invalid file or directory: '%s'; Terminating...\n", argv[1]);
r = 1;
goto end;
}
if (ecore_file_is_dir(real))
ephoto->directory = eina_stringshare_add(real);
else if (ecore_file_exists(real))
ephoto->file = eina_stringshare_add(real);
free(real);
}
}
else if (!strncmp(argv[1], "--help", 6))
if (!ephoto_window_add())
{
_ephoto_display_usage();
r = 0;
printf("Could not create the main window; Terminating...\n");
r = 1;
goto end;
}
else
{
char *real = ecore_file_realpath(argv[1]);
if (!real)
{
printf("invalid file or directory: '%s'\n", argv[1]);
r = 1;
goto end;
}
Evas_Object *win = ephoto_window_add(real);
free(real);
if (!win)
{
r = 1;
goto end;
}
}
elm_run();
end:
eina_log_domain_unregister(__log_domain);
end_log_domain:
if (ephoto)
free(ephoto);
efreet_mime_shutdown();
elm_shutdown();
eio_shutdown();
return r;
}
/*Display useage commands for ephoto*/
static void
_ephoto_display_usage(void)
{
printf("Ephoto Usage: \n"
"ephoto --help : This page\n"
"ephoto filename : Specifies a file to open\n"
"ephoto dirname : Specifies a directory to open\n");
"ephoto --help | -h : This page\n"
"ephoto filename : Specifies a file to open\n"
"ephoto directory : Specifies a directory to open\n");
}
#endif
ELM_MAIN()

@ -7,7 +7,6 @@
#include <Eet.h>
#include <Ecore.h>
#include <Ecore_Evas.h>
#include <Ecore_File.h>
#include <Efreet_Mime.h>
#include <Elementary.h>
@ -16,185 +15,68 @@
#include <Evas.h>
#include <Eio.h>
#include <Ethumb_Client.h>
#include <libgen.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#define THEME_FILE PACKAGE_DATA_DIR"/themes/default/ephoto.edj"
/*Ephoto Typedefs*/
typedef struct _Ephoto Ephoto;
typedef enum _Ephoto_State Ephoto_State;
typedef struct _Ephoto_Config Ephoto_Config;
typedef struct _Ephoto Ephoto;
typedef struct _Ephoto_Entry Ephoto_Entry;
typedef struct _Ephoto_Event_Entry_Create Ephoto_Event_Entry_Create;
/*Main Functions*/
Evas_Object *ephoto_window_add(void);
void ephoto_title_set(const char *title);
void ephoto_thumb_size_set(int size);
void ephoto_directory_set(const char *path);
typedef enum _Ephoto_State Ephoto_State;
typedef enum _Ephoto_Orient Ephoto_Orient;
/*Main Children*/
Evas_Object *ephoto_flow_browser_add(void);
void ephoto_flow_browser_image_set(void);
void ephoto_flow_browser_del(void);
void ephoto_flow_browser_show(void);
Evas_Object *ephoto_window_add(const char *path);
void ephoto_title_set(Ephoto *ephoto, const char *title);
void ephoto_thumb_size_set(Ephoto *ephoto, int size);
Evas_Object *ephoto_thumb_add(Ephoto *ephoto, Evas_Object *parent, const char *path);
void ephoto_thumb_path_set(Evas_Object *o, const char *path);
void ephoto_directory_set(Ephoto *ephoto, const char *path);
Evas_Object *ephoto_slideshow_add(void);
void ephoto_slideshow_del(void);
Ephoto_Orient ephoto_file_orient_get(const char *path);
Eina_Bool ephoto_config_init(Ephoto *em);
void ephoto_config_save(Ephoto *em, Eina_Bool instant);
void ephoto_config_free(Ephoto *em);
Evas_Object *ephoto_flow_browser_add(Ephoto *ephoto, Evas_Object *parent);
void ephoto_flow_browser_entry_set(Evas_Object *obj, Ephoto_Entry *entry);
void ephoto_flow_browser_path_pending_set(Evas_Object *obj, const char *path);
/* smart callbacks called:
* "back" - the user want to go back to the previous screen.
*/
Evas_Object *ephoto_slideshow_add(Ephoto *ephoto, Evas_Object *parent);
void ephoto_slideshow_entry_set(Evas_Object *obj, Ephoto_Entry *entry);
/* smart callbacks called:
* "back" - the user want to go back to the previous screen.
*/
Evas_Object *ephoto_directory_thumb_add(Evas_Object *parent, Ephoto_Entry *e);
Evas_Object *ephoto_thumb_browser_add(Ephoto *ephoto, Evas_Object *parent);
/* smart callbacks called:
* "selected" - an item in the thumb browser is selected. The selected Ephoto_Entry is passed as event_info argument.
*/
Evas_Object *ephoto_thumb_browser_add(void);
void ephoto_thumb_browser_thumb_append(const char *file);
void ephoto_thumb_browser_del(void);
void ephoto_thumb_browser_show(void);
/*Ephoto States*/
enum _Ephoto_State
{
EPHOTO_STATE_THUMB,
EPHOTO_STATE_FLOW,
EPHOTO_STATE_SLIDESHOW
};
enum _Ephoto_Orient /* matches with exif orientation tag */
{
EPHOTO_ORIENT_0 = 1,
EPHOTO_ORIENT_FLIP_HORIZ = 2,
EPHOTO_ORIENT_180 = 3,
EPHOTO_ORIENT_FLIP_VERT = 4,
EPHOTO_ORIENT_FLIP_VERT_90 = 5,
EPHOTO_ORIENT_90 = 6,
EPHOTO_ORIENT_FLIP_HORIZ_90 = 7,
EPHOTO_ORIENT_270 = 8
};
/* TODO: split into window & global config, allow multi window
*
* This also requires single instance, as 2 instances changing the
* same configuration will lead to problems.
*
* Single instance is better done as DBus, using FDO standard methods.
*/
struct _Ephoto_Config
{
int config_version;
const char *editor;
double slideshow_timeout;
const char *slideshow_transition;
/* these should be per-window */
int thumb_size;
int thumb_gen_size;
const char *directory;
EPHOTO_STATE_THUMB,
EPHOTO_STATE_FLOW,
EPHOTO_STATE_SLIDESHOW
};
/*Ephoto Main Structure*/
struct _Ephoto
{
/*Main Objects*/
Evas_Object *win;
Evas_Object *bg;
Evas_Object *pager;
/*Main Children*/
Evas_Object *thumb_browser;
Evas_Object *flow_browser;
Evas_Object *slideshow;
Eina_List *entries;
Eina_List *thumbs; /* live thumbs that need to be regenerated on changes */
int thumb_gen_size; /* pending value for thumb_regen */
struct {
Ecore_Timer *thumb_regen;
} timer;
struct {
Ecore_Job *change_dir;
} job;
/*Main Variables*/
const char *directory;
const char *file;
Eio_File *ls;
Evas_Object *prefs_win;
Eina_List *images;
Eina_List *current_index;
Ephoto_State state, prev_state;
Ephoto_Config *config;
};
struct _Ephoto_Entry
{
const char *path;
const char *basename; /* pointer inside path */
const char *label;
Ephoto *ephoto;
Elm_Gengrid_Item *item;
Eina_List *free_listeners;
Eina_List *dir_files; /* if dir, here contain files with preview */
Eina_Bool dir_files_checked : 1;
Eina_Bool is_dir : 1;
Eina_Bool is_up : 1;
};
struct _Ephoto_Event_Entry_Create
{
Ephoto_Entry *entry;
Ethumb_Client *client;
};
Ephoto_Entry *ephoto_entry_new(Ephoto *ephoto, const char *path, const char *label);
void ephoto_entry_free(Ephoto_Entry *entry);
void ephoto_entry_free_listener_add(Ephoto_Entry *entry, void (*cb)(void *data, const Ephoto_Entry *entry), const void *data);
void ephoto_entry_free_listener_del(Ephoto_Entry *entry, void (*cb)(void *data, const Ephoto_Entry *entry), const void *data);
void ephoto_entries_free(Ephoto *ephoto);
extern int __log_domain;
#define DBG(...) EINA_LOG_DOM_DBG(__log_domain, __VA_ARGS__)
#define INF(...) EINA_LOG_DOM_INFO(__log_domain, __VA_ARGS__)
#define ERR(...) EINA_LOG_DOM_ERR(__log_domain, __VA_ARGS__)
static inline Eina_Bool
_ephoto_eina_file_direct_info_image_useful(const Eina_File_Direct_Info *info)
{
const char /* *type, */ *bname, *ext;
bname = info->path + info->name_start;
if (bname[0] == '.') return EINA_FALSE;
if ((info->type != EINA_FILE_REG) && (info->type != EINA_FILE_UNKNOWN))
return EINA_FALSE;
ext = info->path + info->path_length - 1;
for (; ext > bname; ext--) if (*ext == '.') break;
if (*ext == '.')
{
ext++;
if ((strcasecmp(ext, "jpg") == 0) ||
(strcasecmp(ext, "jpeg") == 0) ||
(strcasecmp(ext, "png") == 0))
return EINA_TRUE;
}
return EINA_FALSE;
/* seems that this does not play nice with threads */
//if (!(type = efreet_mime_type_get(info->path))) return EINA_FALSE;
//return strncmp(type, "image/", sizeof("image/") - 1) == 0;
}
extern int EPHOTO_EVENT_ENTRY_CREATE;
extern int EPHOTO_EVENT_POPULATE_START;
extern int EPHOTO_EVENT_POPULATE_END;
extern int EPHOTO_EVENT_POPULATE_ERROR;
extern Ephoto *ephoto;
#endif

@ -1,158 +0,0 @@
#include "ephoto.h"
#define CONFIG_VERSION 5
static int _ephoto_config_load(Ephoto *ephoto);
static Eina_Bool _ephoto_on_config_save(void *data);
static Eet_Data_Descriptor *edd = NULL;
static Ecore_Timer *save_timer = NULL;
Eina_Bool
ephoto_config_init(Ephoto *ephoto)
{
Eet_Data_Descriptor_Class eddc;
if (!eet_eina_stream_data_descriptor_class_set(&eddc, sizeof (eddc), "Ephoto_Config", sizeof(Ephoto_Config)))
{
ERR("Unable to create the config data descriptor!");
return EINA_FALSE;
}
if (!edd) edd = eet_data_descriptor_stream_new(&eddc);
#undef T
#undef D
#define T Ephoto_Config
#define D edd
#define C_VAL(edd, type, member, dtype) EET_DATA_DESCRIPTOR_ADD_BASIC(edd, type, #member, member, dtype)
C_VAL(D, T, config_version, EET_T_INT);
C_VAL(D, T, thumb_size, EET_T_INT);
C_VAL(D, T, thumb_gen_size, EET_T_INT);
C_VAL(D, T, directory, EET_T_STRING);
C_VAL(D, T, slideshow_timeout, EET_T_DOUBLE);
C_VAL(D, T, slideshow_transition, EET_T_STRING);
C_VAL(D, T, editor, EET_T_STRING);
switch (_ephoto_config_load(ephoto))
{
case 0:
/* Start a new config */
ephoto->config->config_version = CONFIG_VERSION;
ephoto->config->thumb_size = 256;
ephoto->config->thumb_gen_size = 256;
ephoto->config->slideshow_timeout = 4.0;
ephoto->config->slideshow_transition = eina_stringshare_add("fade");
ephoto->config->editor = eina_stringshare_add("gimp %s");
break;
case -1:
/* Incremental additions */
if (ephoto->config->config_version < 2)
{
ephoto->config->slideshow_timeout = 4.0;
ephoto->config->slideshow_transition = eina_stringshare_add("fade");
}
if (ephoto->config->config_version < 3)
ephoto->config->editor = eina_stringshare_add("gimp %s");
if (ephoto->config->config_version < 5)
ephoto->config->thumb_gen_size = 256;
ephoto->config->config_version = CONFIG_VERSION;
break;
default:
return EINA_TRUE;
}
ephoto_config_save(ephoto, EINA_FALSE);
return EINA_TRUE;
}
void
ephoto_config_save(Ephoto *ephoto, Eina_Bool instant)
{
if (save_timer)
{
ecore_timer_del(save_timer);
save_timer = NULL;
}
if (instant)
_ephoto_on_config_save(ephoto);
else
save_timer = ecore_timer_add(5.0, _ephoto_on_config_save, ephoto);
}
void
ephoto_config_free(Ephoto *ephoto)
{
free(ephoto->config);
ephoto->config = NULL;
}
static int
_ephoto_config_load(Ephoto *ephoto)
{
Eet_File *ef;
char buf[4096], buf2[4096];
snprintf(buf2, sizeof(buf2), "%s/.config/ephoto", getenv("HOME"));
ecore_file_mkpath(buf2);
snprintf(buf, sizeof(buf), "%s/ephoto.cfg", buf2);
ef = eet_open(buf, EET_FILE_MODE_READ);
if (!ef)
{
ephoto_config_free(ephoto);
ephoto->config = calloc(1, sizeof(Ephoto_Config));
return 0;
}
ephoto->config = eet_data_read(ef, edd, "config");
eet_close(ef);
if (ephoto->config->config_version > CONFIG_VERSION)
{
ephoto_config_free(ephoto);
ephoto->config = calloc(1, sizeof(Ephoto_Config));
return 0;
}
if (ephoto->config->config_version < CONFIG_VERSION)
return -1;
return 1;
}
static Eina_Bool
_ephoto_on_config_save(void *data)
{
Ephoto *ephoto = data;
Eet_File *ef;
char buf[4096], buf2[4096];
snprintf(buf, sizeof(buf), "%s/.config/ephoto/ephoto.cfg", getenv("HOME"));
snprintf(buf2, sizeof(buf2), "%s.tmp", buf);
ef = eet_open(buf2, EET_FILE_MODE_WRITE);
if (!ef) goto save_end;
eet_data_write(ef, edd, "config", ephoto->config, 1);
if (eet_close(ef)) goto save_end;
if (!ecore_file_mv(buf2, buf)) goto save_end;
INF("Config saved");
save_end:
ecore_file_unlink(buf2);
if (save_timer)
{
ecore_timer_del(save_timer);
save_timer = NULL;
}
return ECORE_CALLBACK_CANCEL;
}

@ -1,176 +0,0 @@
#include "ephoto.h"
typedef struct _Ephoto_Directory_Thumb Ephoto_Directory_Thumb;
struct _Ephoto_Directory_Thumb
{
Eio_File *ls;
Eina_List *objs;
Ephoto_Entry *entry;
Eina_Bool canceled:1;
};
static Eina_Hash *_pending_dirs = NULL;
static void
_entry_free(void *data, const Ephoto_Entry *entry __UNUSED__)
{
Ephoto_Directory_Thumb *dt = data;
dt->entry = NULL;
}
static void
_ephoto_directory_thumb_free(Ephoto_Directory_Thumb *dt)
{
if (dt->entry)
{
ephoto_entry_free_listener_del(dt->entry, _entry_free, dt);
eina_hash_del(_pending_dirs, dt->entry->path, dt);
dt->entry = NULL;
}
if (dt->ls)
{
dt->canceled = EINA_TRUE;
eio_file_cancel(dt->ls);
return;
}
free(dt);
if (_pending_dirs)
{
if (!eina_hash_population(_pending_dirs))
{
eina_hash_free(_pending_dirs);
_pending_dirs = NULL;
}
}
}
static void
_obj_del(void *data, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
{
Ephoto_Directory_Thumb *dt = data;
dt->objs = eina_list_remove(dt->objs, obj);
if (!dt->objs)
{
dt->canceled = EINA_TRUE;
_ephoto_directory_thumb_free(dt);
}
}
static Eina_Bool
_populate_filter(void *data __UNUSED__, Eio_File *handler __UNUSED__, const Eina_File_Direct_Info *info)
{
return _ephoto_eina_file_direct_info_image_useful(info);
}
static void
_populate_end(void *data, Eio_File *handler __UNUSED__)
{
Ephoto_Directory_Thumb *dt = data;
Evas_Object *obj;
dt->ls = NULL;
EINA_LIST_FREE(dt->objs, obj)
evas_object_event_callback_del_full(obj, EVAS_CALLBACK_DEL, _obj_del, dt);
if (dt->entry)
{
dt->entry->dir_files_checked = EINA_TRUE;
if ((dt->entry->item) && (!dt->canceled))
elm_gengrid_item_update(dt->entry->item);
}
_ephoto_directory_thumb_free(dt);
}
static void
_populate_error(void *data, Eio_File *handler, int error)
{
Ephoto_Directory_Thumb *dt = data;
if (error) ERR("could not populate: %s", strerror(error));
_populate_end(dt, handler);
}
static void
_populate_main(void *data, Eio_File *handler __UNUSED__, const Eina_File_Direct_Info *info)
{
Ephoto_Directory_Thumb *dt = data;
Evas_Object *obj;
const char *file;
if (!dt->objs) return;
if (!dt->entry) return;
obj = dt->objs->data;
file = eina_stringshare_add(info->path);
DBG("populate thumbnail %p with path '%s'", obj, file);
dt->objs = eina_list_remove_list(dt->objs, dt->objs);
dt->entry->dir_files = eina_list_append(dt->entry->dir_files, file);
ephoto_thumb_path_set(obj, file);
evas_object_event_callback_del_full(obj, EVAS_CALLBACK_DEL, _obj_del, dt);
if ((!dt->objs) && (dt->ls))
{
eio_file_cancel(dt->ls);
dt->ls = NULL;
}
}
Evas_Object *
ephoto_directory_thumb_add(Evas_Object *parent, Ephoto_Entry *entry)
{
Ephoto_Directory_Thumb *dt;
Evas_Object *obj;
if (_pending_dirs)
dt = eina_hash_find(_pending_dirs, entry->path);
else
{
dt = NULL;
_pending_dirs = eina_hash_stringshared_new(NULL);
EINA_SAFETY_ON_NULL_RETURN_VAL(_pending_dirs, NULL);
}
obj = ephoto_thumb_add(entry->ephoto, parent, NULL);
EINA_SAFETY_ON_NULL_RETURN_VAL(obj, NULL);
if (!dt)
{
dt = calloc(1, sizeof(Ephoto_Directory_Thumb));
if (!dt)
{
ERR("could not allocate memory for Ephoto_Directory_Thumb");
evas_object_del(obj);
return NULL;
}
ephoto_entry_free_listener_add(entry, _entry_free, dt);
dt->entry = entry;
dt->ls = eio_file_direct_ls(entry->path,
_populate_filter,
_populate_main,
_populate_end,
_populate_error,
dt);
if (!dt->ls)
{
ERR("could not create eio_file_direct_ls(%s)", entry->path);
evas_object_del(obj);
free(dt);
return NULL;
}
eina_hash_add(_pending_dirs, entry->path, dt);
DBG("start thread to lookup inside '%s' for thumbnails.", entry->path);
}
else
DBG("thread already started, wait for thumbnails in '%s'", entry->path);
dt->objs = eina_list_append(dt->objs, obj);
evas_object_event_callback_add(obj, EVAS_CALLBACK_DEL, _obj_del, dt);
return obj;
}

File diff suppressed because it is too large Load Diff

@ -1,160 +1,23 @@
#include "ephoto.h"
int EPHOTO_EVENT_ENTRY_CREATE = 0;
int EPHOTO_EVENT_POPULATE_START = 0;
int EPHOTO_EVENT_POPULATE_END = 0;
int EPHOTO_EVENT_POPULATE_ERROR = 0;
typedef struct _Ephoto_Entry_Free_Listener Ephoto_Entry_Free_Listener;
struct _Ephoto_Entry_Free_Listener
{
void (*cb)(void *data, const Ephoto_Entry *dead);
const void *data;
};
static void
_ephoto_state_set(Ephoto *ephoto, Ephoto_State state)
{
ephoto->prev_state = ephoto->state;
ephoto->state = state;
}
static void
_ephoto_thumb_browser_show(Ephoto *ephoto, Ephoto_Entry *entry)
{
DBG("entry '%s'", entry ? entry->path : "");
ephoto_flow_browser_entry_set(ephoto->flow_browser, NULL);
ephoto_slideshow_entry_set(ephoto->slideshow, NULL);
elm_pager_content_promote(ephoto->pager, ephoto->thumb_browser);
_ephoto_state_set(ephoto, EPHOTO_STATE_THUMB);
if ((entry) && (entry->item)) elm_gengrid_item_bring_in(entry->item);
}
static void
_ephoto_flow_browser_show(Ephoto *ephoto, Ephoto_Entry *entry)
{
DBG("entry '%s'", entry->path);
ephoto_flow_browser_entry_set(ephoto->flow_browser, entry);
elm_pager_content_promote(ephoto->pager, ephoto->flow_browser);
_ephoto_state_set(ephoto, EPHOTO_STATE_FLOW);
}
static void
_ephoto_slideshow_show(Ephoto *ephoto, Ephoto_Entry *entry)
{
DBG("entry '%s'", entry->path);
ephoto_slideshow_entry_set(ephoto->slideshow, entry);
elm_pager_content_promote(ephoto->pager, ephoto->slideshow);
_ephoto_state_set(ephoto, EPHOTO_STATE_SLIDESHOW);
}
static void
_ephoto_flow_browser_back(void *data, Evas_Object *obj __UNUSED__, void *event_info)
{
Ephoto *ephoto = data;
Ephoto_Entry *entry = event_info;
_ephoto_thumb_browser_show(ephoto, entry);
}
static void
_ephoto_slideshow_back(void *data, Evas_Object *obj __UNUSED__, void *event_info)
{
Ephoto *ephoto = data;
Ephoto_Entry *entry = event_info;
switch (ephoto->prev_state)
{
case EPHOTO_STATE_FLOW:
_ephoto_flow_browser_show(ephoto, entry);
break;
case EPHOTO_STATE_THUMB:
_ephoto_thumb_browser_show(ephoto, entry);
break;
default:
ERR("unhandled previous state %d", ephoto->prev_state);
}
elm_win_fullscreen_set(ephoto->win, EINA_FALSE);
}
static void
_ephoto_thumb_browser_view(void *data, Evas_Object *obj __UNUSED__, void *event_info)
{
Ephoto *ephoto = data;
Ephoto_Entry *entry = event_info;
_ephoto_flow_browser_show(ephoto, entry);
}
static void
_ephoto_thumb_browser_changed_directory(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
{
Ephoto *ephoto = data;
ephoto_flow_browser_entry_set(ephoto->flow_browser, NULL);
ephoto_slideshow_entry_set(ephoto->slideshow, NULL);
}
static void
_ephoto_thumb_browser_slideshow(void *data, Evas_Object *obj __UNUSED__, void *event_info)
{
Ephoto *ephoto = data;
Ephoto_Entry *entry = event_info;
_ephoto_slideshow_show(ephoto, entry);
}
static void
_ephoto_flow_browser_slideshow(void *data, Evas_Object *obj __UNUSED__, void *event_info)
{
Ephoto *ephoto = data;
Ephoto_Entry *entry = event_info;
_ephoto_slideshow_show(ephoto, entry);
}
static void
_win_free(void *data, Evas *e __UNUSED__, Evas_Object *o __UNUSED__, void *event_info __UNUSED__)
{
Ephoto *ephoto = data;
if (ephoto->timer.thumb_regen) ecore_timer_del(ephoto->timer.thumb_regen);
free(ephoto);
}
static void _ephoto_window_del(void *data __UNUSED__, Evas_Object *obj __UNUSED__, void *event __UNUSED__);
static void _ephoto_thumb_populate(void);
static Eina_Bool _ephoto_thumb_populate_filter(void *data __UNUSED__, Eio_File *handler __UNUSED__, const Eina_File_Direct_Info *info);
static void _ephoto_thumb_populate_main(void *data __UNUSED__, Eio_File *handler __UNUSED__, const Eina_File_Direct_Info *info);
static void _ephoto_thumb_populate_end(void *data __UNUSED__, Eio_File *handler __UNUSED__);
static void _ephoto_thumb_populate_error(void *data __UNUSED__, Eio_File *handler __UNUSED__, int error);
Evas_Object *
ephoto_window_add(const char *path)
ephoto_window_add(void)
{
Ephoto *ephoto = calloc(1, sizeof(Ephoto));
Ethumb_Client *client = elm_thumb_ethumb_client_get();
char buf[PATH_MAX];
EINA_SAFETY_ON_NULL_RETURN_VAL(ephoto, NULL);
EPHOTO_EVENT_ENTRY_CREATE = ecore_event_type_new();
EPHOTO_EVENT_POPULATE_START = ecore_event_type_new();
EPHOTO_EVENT_POPULATE_END = ecore_event_type_new();
EPHOTO_EVENT_POPULATE_ERROR = ecore_event_type_new();
ephoto->win = elm_win_add(NULL, "ephoto", ELM_WIN_BASIC);
if (!ephoto->win)
{
free(ephoto);
return NULL;
}
evas_object_event_callback_add
(ephoto->win, EVAS_CALLBACK_FREE, _win_free, ephoto);
elm_win_autodel_set(ephoto->win, EINA_TRUE);
if (!ephoto_config_init(ephoto))
{
evas_object_del(ephoto->win);
return NULL;
}
if ((ephoto->config->thumb_gen_size != 128) &&
(ephoto->config->thumb_gen_size != 256) &&