├── .gitignore
├── README.md
├── bin
└── eluminance
├── data
├── desktop
│ └── eluminance.desktop
├── icons
│ ├── 128x128
│ │ └── apps
│ │ │ └── eluminance.png
│ ├── 48x48
│ │ └── apps
│ │ │ └── eluminance.png
│ └── scalable
│ │ └── apps
│ │ └── eluminance.svg
├── po
│ ├── LINGUAS
│ ├── POTFILES
│ ├── de.po
│ ├── eluminance.pot
│ ├── en.po
│ └── it.po
├── screenshots
│ ├── eluminance01.jpg
│ ├── eluminance02.jpg
│ └── eluminance03.jpg
└── themes
│ └── default
│ ├── cropper.edc
│ ├── elm_slideshow.edc
│ ├── images
│ ├── bevel.png
│ ├── bg_fill.png
│ ├── bg_overlay.png
│ ├── controls_bg.png
│ ├── glint.png
│ ├── icon_bookmark_add.png
│ ├── icon_bookmark_remove.png
│ ├── icon_document_save.png
│ ├── icon_document_save_as.png
│ ├── icon_edit_cut.png
│ ├── icon_go_next.png
│ ├── icon_go_previous.png
│ ├── icon_info.png
│ ├── icon_media_playback_pause.png
│ ├── icon_media_playback_start.png
│ ├── icon_object_flip_horizontal.png
│ ├── icon_object_flip_vertical.png
│ ├── icon_object_rotate_left.png
│ ├── icon_object_rotate_right.png
│ ├── icon_preferences_system.png
│ ├── icon_resize.png
│ ├── icon_rotate.png
│ ├── icon_starred.png
│ ├── icon_view_fullscreen.png
│ ├── icon_zoom.png
│ ├── icon_zoom_fit_best.png
│ ├── icon_zoom_in.png
│ ├── icon_zoom_original.png
│ ├── icon_zoom_out.png
│ ├── sel_border.png
│ ├── sel_corner1.png
│ ├── sel_corner3.png
│ ├── sel_corner5.png
│ ├── sel_corner7.png
│ └── status_bg.png
│ └── main.edc
├── eluminance
├── __init__.py
├── eluminance.py
└── utils.py
└── setup.py
/.gitignore:
--------------------------------------------------------------------------------
1 | build/
2 | installed_files.txt
3 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Eluminance
2 | ==========
3 |
4 | A fast photo browser written in python.
5 |
6 | 
7 | 
8 | 
9 |
10 | ## Usage tips ##
11 | * The ui provide 3 hotspots to show controls on mouse hover:
12 | * top of the window to show the control buttons
13 | * right to show the thumbnails in the current directory
14 | * left to show the directory tree
15 | * Right mouse button on the photo to toggle the visibility of the tree and the thumbnails
16 | * Mouse wheel to change zoom
17 | * Drag the image to pan around
18 |
19 | ## Requirements ##
20 |
21 | * Python 2.7 or higher
22 | * Python-EFL 1.14 or higher
23 | * python modules: efl, xdg
24 |
25 | ## Installation ##
26 |
27 | * For system-wide installation (needs administrator privileges):
28 |
29 | `(sudo) python setup.py install`
30 |
31 | * For user installation:
32 |
33 | `python setup.py install --user`
34 |
35 | * To install for different version of python:
36 |
37 | `pythonX setup.py install`
38 |
39 | * Install with a custom prefix:
40 |
41 | `python setup.py install --prefix=/MY_PREFIX`
42 |
43 | * To create distribution packages:
44 |
45 | `python setup.py sdist`
46 |
47 | ## License ##
48 |
49 | GNU General Public License v3 - see COPYING
50 |
--------------------------------------------------------------------------------
/bin/eluminance:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | import sys
3 | from eluminance.eluminance import main
4 |
5 | sys.exit(main())
6 |
--------------------------------------------------------------------------------
/data/desktop/eluminance.desktop:
--------------------------------------------------------------------------------
1 | [Desktop Entry]
2 | Encoding=UTF-8
3 | Type=Application
4 | Name=Eluminance
5 | GenericName=Image Viewer
6 | GenericName[it]=Visualizzatore immagini
7 | Icon=eluminance
8 | Exec=eluminance %f
9 | Terminal=false
10 | MimeType=inode/directory;image/bmp;image/jpeg;image/gif;image/png;image/tiff;image/x-bmp;image/x-ico;image/x-png;image/x-pcx;image/x-tga;image/xpm;image/svg+xml;
11 | Categories=Graphics;Viewer;Photography;
12 |
--------------------------------------------------------------------------------
/data/icons/128x128/apps/eluminance.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DaveMDS/eluminance/fe1bfceeac99fcf5b3f060f961ca0cca544a44f0/data/icons/128x128/apps/eluminance.png
--------------------------------------------------------------------------------
/data/icons/48x48/apps/eluminance.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DaveMDS/eluminance/fe1bfceeac99fcf5b3f060f961ca0cca544a44f0/data/icons/48x48/apps/eluminance.png
--------------------------------------------------------------------------------
/data/icons/scalable/apps/eluminance.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
23 |
25 |
28 |
32 |
36 |
37 |
40 |
44 |
48 |
49 |
52 |
56 |
60 |
61 |
64 |
68 |
72 |
73 |
76 |
80 |
84 |
85 |
95 |
106 |
114 |
118 |
119 |
128 |
139 |
150 |
159 |
169 |
180 |
188 |
192 |
193 |
201 |
205 |
206 |
210 |
213 |
214 |
215 |
247 |
252 |
253 |
255 |
256 |
258 | image/svg+xml
259 |
261 |
262 |
263 |
264 |
265 |
271 |
278 |
284 |
290 |
295 |
297 |
302 |
312 |
321 |
331 |
332 |
339 |
344 |
350 |
356 |
362 |
371 |
380 |
389 |
398 |
399 |
400 |
--------------------------------------------------------------------------------
/data/po/LINGUAS:
--------------------------------------------------------------------------------
1 | en
2 | it
3 | de
4 |
--------------------------------------------------------------------------------
/data/po/POTFILES:
--------------------------------------------------------------------------------
1 | eluminance/eluminance.py
2 | eluminance/utils.py
3 |
--------------------------------------------------------------------------------
/data/po/de.po:
--------------------------------------------------------------------------------
1 | # German translation for Eluminance
2 | # Copyright (C) 2015 Davide Andreoli
3 | # This file is distributed under the same license as the Eluminance package.
4 | # Davide Andreoli , 2015.
5 | # Wolfgang Morawetz , 2015.
6 | #
7 | msgid ""
8 | msgstr ""
9 | "Project-Id-Version: Eluminance 1.0\n"
10 | "Report-Msgid-Bugs-To: \n"
11 | "POT-Creation-Date: 2015-05-24 18:13+0200\n"
12 | "PO-Revision-Date: 2015-10-10 19:46+0200\n"
13 | "Last-Translator: Wolfgang Morawetz \n"
14 | "Language-Team: Deutsch <>\n"
15 | "Language: German\n"
16 | "MIME-Version: 1.0\n"
17 | "Content-Type: text/plain; charset=UTF-8\n"
18 | "Content-Transfer-Encoding: 8bit\n"
19 | "Plural-Forms: nplurals=2; plural=(n != 1);\n"
20 | "X-Generator: Gtranslator 2.91.7\n"
21 |
22 | #: eluminance/eluminance.py:174
23 | msgid "No items to show"
24 | msgstr "Keine einträge vorhanden"
25 |
26 | #: eluminance/eluminance.py:206
27 | msgid "Set as root"
28 | msgstr "Hauptverzeichnis Festlegen"
29 |
30 | #: eluminance/eluminance.py:209
31 | msgid "Remove from favorites"
32 | msgstr "Aus Favoriten entfernen"
33 |
34 | #: eluminance/eluminance.py:212
35 | msgid "Add to favorites"
36 | msgstr "Zu Favoriten hinzufügen"
37 |
38 | #: eluminance/eluminance.py:587
39 | msgid "No image selected"
40 | msgstr "Kein Bild ausgewählt"
41 |
42 | #: eluminance/eluminance.py:603
43 | #, python-brace-format
44 | msgid "File {0} of {1}"
45 | msgstr "Datei {0} von {1}"
46 |
47 | #: eluminance/eluminance.py:607
48 | msgid "Resolution"
49 | msgstr "Auflösung"
50 |
51 | #: eluminance/eluminance.py:608
52 | msgid "Size"
53 | msgstr "Größe"
54 |
55 | #: eluminance/eluminance.py:609
56 | msgid "Zoom"
57 | msgstr "Bildvergrößerung"
58 |
59 | #: eluminance/eluminance.py:626
60 | msgid "Zoom in"
61 | msgstr "Vergrößern"
62 |
63 | #: eluminance/eluminance.py:627
64 | msgid "Zoom out"
65 | msgstr "Verkleinern"
66 |
67 | #: eluminance/eluminance.py:628
68 | msgid "Zoom 1:1"
69 | msgstr "Original Göße"
70 |
71 | #: eluminance/eluminance.py:629
72 | msgid "Zoom fit"
73 | msgstr "Einpassen"
74 |
75 | #: eluminance/eluminance.py:630
76 | msgid "Zoom fill"
77 | msgstr "Anpassen"
78 |
79 | #: eluminance/eluminance.py:632
80 | msgid "Previous photo"
81 | msgstr "Vorheriges Bild"
82 |
83 | #: eluminance/eluminance.py:633
84 | msgid "Next photo"
85 | msgstr "Nächstes Bild"
86 |
87 | #: eluminance/eluminance.py:634
88 | msgid "Start/Stop slideshow"
89 | msgstr "Start/Stop Diaschau"
90 |
91 | #: eluminance/eluminance.py:635
92 | msgid "Transition time"
93 | msgstr "Übergangszeit"
94 |
95 | #: eluminance/eluminance.py:636
96 | msgid "Transition style"
97 | msgstr "Übergangsstil"
98 |
99 | #: eluminance/eluminance.py:638
100 | msgid "Toggle fullscreen mode"
101 | msgstr "Wechsle Vollbildmodus"
102 |
103 | #: eluminance/eluminance.py:639
104 | msgid "Eluminance info"
105 | msgstr "Eluminance info"
106 |
107 | #: eluminance/eluminance.py:647 eluminance/eluminance.py:696
108 | msgid "Play"
109 | msgstr "Abspielen"
110 |
111 | #: eluminance/eluminance.py:689
112 | msgid "Pause"
113 | msgstr "Pause"
114 |
115 | #: eluminance/eluminance.py:819
116 | #, python-format
117 | msgid "Version: %s"
118 | msgstr "Version: %s"
119 |
120 | #: eluminance/eluminance.py:828
121 | msgid "Eluminance"
122 | msgstr "Eluminance"
123 |
124 | #: eluminance/eluminance.py:833
125 | msgid "Website"
126 | msgstr "Webseite"
127 |
128 | #: eluminance/eluminance.py:838
129 | msgid "Authors"
130 | msgstr "Autoren"
131 |
132 | #: eluminance/eluminance.py:843
133 | msgid "License"
134 | msgstr "Lizenz"
135 |
--------------------------------------------------------------------------------
/data/po/eluminance.pot:
--------------------------------------------------------------------------------
1 | # SOME DESCRIPTIVE TITLE.
2 | # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
3 | # This file is distributed under the same license as the PACKAGE package.
4 | # FIRST AUTHOR , YEAR.
5 | #
6 | #, fuzzy
7 | msgid ""
8 | msgstr ""
9 | "Project-Id-Version: PACKAGE VERSION\n"
10 | "Report-Msgid-Bugs-To: \n"
11 | "POT-Creation-Date: 2015-05-24 18:13+0200\n"
12 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
13 | "Last-Translator: FULL NAME \n"
14 | "Language-Team: LANGUAGE \n"
15 | "Language: \n"
16 | "MIME-Version: 1.0\n"
17 | "Content-Type: text/plain; charset=CHARSET\n"
18 | "Content-Transfer-Encoding: 8bit\n"
19 |
20 | #: eluminance/eluminance.py:174
21 | msgid "No items to show"
22 | msgstr ""
23 |
24 | #: eluminance/eluminance.py:206
25 | msgid "Set as root"
26 | msgstr ""
27 |
28 | #: eluminance/eluminance.py:209
29 | msgid "Remove from favorites"
30 | msgstr ""
31 |
32 | #: eluminance/eluminance.py:212
33 | msgid "Add to favorites"
34 | msgstr ""
35 |
36 | #: eluminance/eluminance.py:587
37 | msgid "No image selected"
38 | msgstr ""
39 |
40 | #: eluminance/eluminance.py:603
41 | #, python-brace-format
42 | msgid "File {0} of {1}"
43 | msgstr ""
44 |
45 | #: eluminance/eluminance.py:607
46 | msgid "Resolution"
47 | msgstr ""
48 |
49 | #: eluminance/eluminance.py:608
50 | msgid "Size"
51 | msgstr ""
52 |
53 | #: eluminance/eluminance.py:609
54 | msgid "Zoom"
55 | msgstr ""
56 |
57 | #: eluminance/eluminance.py:626
58 | msgid "Zoom in"
59 | msgstr ""
60 |
61 | #: eluminance/eluminance.py:627
62 | msgid "Zoom out"
63 | msgstr ""
64 |
65 | #: eluminance/eluminance.py:628
66 | msgid "Zoom 1:1"
67 | msgstr ""
68 |
69 | #: eluminance/eluminance.py:629
70 | msgid "Zoom fit"
71 | msgstr ""
72 |
73 | #: eluminance/eluminance.py:630
74 | msgid "Zoom fill"
75 | msgstr ""
76 |
77 | #: eluminance/eluminance.py:632
78 | msgid "Previous photo"
79 | msgstr ""
80 |
81 | #: eluminance/eluminance.py:633
82 | msgid "Next photo"
83 | msgstr ""
84 |
85 | #: eluminance/eluminance.py:634
86 | msgid "Start/Stop slideshow"
87 | msgstr ""
88 |
89 | #: eluminance/eluminance.py:635
90 | msgid "Transition time"
91 | msgstr ""
92 |
93 | #: eluminance/eluminance.py:636
94 | msgid "Transition style"
95 | msgstr ""
96 |
97 | #: eluminance/eluminance.py:638
98 | msgid "Toggle fullscreen mode"
99 | msgstr ""
100 |
101 | #: eluminance/eluminance.py:639
102 | msgid "Eluminance info"
103 | msgstr ""
104 |
105 | #: eluminance/eluminance.py:647 eluminance/eluminance.py:696
106 | msgid "Play"
107 | msgstr ""
108 |
109 | #: eluminance/eluminance.py:689
110 | msgid "Pause"
111 | msgstr ""
112 |
113 | #: eluminance/eluminance.py:819
114 | #, python-format
115 | msgid "Version: %s"
116 | msgstr ""
117 |
118 | #: eluminance/eluminance.py:828
119 | msgid "Eluminance"
120 | msgstr ""
121 |
122 | #: eluminance/eluminance.py:833
123 | msgid "Website"
124 | msgstr ""
125 |
126 | #: eluminance/eluminance.py:838
127 | msgid "Authors"
128 | msgstr ""
129 |
130 | #: eluminance/eluminance.py:843
131 | msgid "License"
132 | msgstr ""
133 |
--------------------------------------------------------------------------------
/data/po/en.po:
--------------------------------------------------------------------------------
1 | # English translation for Eluminance
2 | # Copyright (C) 2015 Davide Andreoli
3 | # This file is distributed under the same license as the Eluminance package.
4 | # Davide Andreoli , 2015.
5 | #
6 | msgid ""
7 | msgstr ""
8 | "Project-Id-Version: Eluminance 1.0\n"
9 | "Report-Msgid-Bugs-To: \n"
10 | "POT-Creation-Date: 2015-05-24 18:13+0200\n"
11 | "PO-Revision-Date: 2015-05-24 18:14+0200\n"
12 | "Last-Translator: Davide Andreoli \n"
13 | "Language-Team: \n"
14 | "Language: English\n"
15 | "MIME-Version: 1.0\n"
16 | "Content-Type: text/plain; charset=UTF-8\n"
17 | "Content-Transfer-Encoding: 8bit\n"
18 | "Plural-Forms: nplurals=2; plural=n != 1;\n"
19 |
20 | #: eluminance/eluminance.py:174
21 | msgid "No items to show"
22 | msgstr ""
23 |
24 | #: eluminance/eluminance.py:206
25 | msgid "Set as root"
26 | msgstr ""
27 |
28 | #: eluminance/eluminance.py:209
29 | msgid "Remove from favorites"
30 | msgstr ""
31 |
32 | #: eluminance/eluminance.py:212
33 | msgid "Add to favorites"
34 | msgstr ""
35 |
36 | #: eluminance/eluminance.py:587
37 | msgid "No image selected"
38 | msgstr "No image selected"
39 |
40 | #: eluminance/eluminance.py:603
41 | #, python-brace-format
42 | msgid "File {0} of {1}"
43 | msgstr "File {0} of {1}"
44 |
45 | #: eluminance/eluminance.py:607
46 | msgid "Resolution"
47 | msgstr "Resolution"
48 |
49 | #: eluminance/eluminance.py:608
50 | msgid "Size"
51 | msgstr "Size"
52 |
53 | #: eluminance/eluminance.py:609
54 | msgid "Zoom"
55 | msgstr "Zoom"
56 |
57 | #: eluminance/eluminance.py:626
58 | msgid "Zoom in"
59 | msgstr "Zoom in"
60 |
61 | #: eluminance/eluminance.py:627
62 | msgid "Zoom out"
63 | msgstr "Zoom out"
64 |
65 | #: eluminance/eluminance.py:628
66 | msgid "Zoom 1:1"
67 | msgstr "Zoom 1:1"
68 |
69 | #: eluminance/eluminance.py:629
70 | msgid "Zoom fit"
71 | msgstr "Zoom fit"
72 |
73 | #: eluminance/eluminance.py:630
74 | msgid "Zoom fill"
75 | msgstr ""
76 |
77 | #: eluminance/eluminance.py:632
78 | msgid "Previous photo"
79 | msgstr "Previous photo"
80 |
81 | #: eluminance/eluminance.py:633
82 | msgid "Next photo"
83 | msgstr "Next photo"
84 |
85 | #: eluminance/eluminance.py:634
86 | msgid "Start/Stop slideshow"
87 | msgstr "Start/Stop slideshow"
88 |
89 | #: eluminance/eluminance.py:635
90 | msgid "Transition time"
91 | msgstr "Transition time"
92 |
93 | #: eluminance/eluminance.py:636
94 | msgid "Transition style"
95 | msgstr "Transition style"
96 |
97 | #: eluminance/eluminance.py:638
98 | msgid "Toggle fullscreen mode"
99 | msgstr "Toggle fullscreen mode"
100 |
101 | #: eluminance/eluminance.py:639
102 | msgid "Eluminance info"
103 | msgstr "Eluminance info"
104 |
105 | #: eluminance/eluminance.py:647 eluminance/eluminance.py:696
106 | msgid "Play"
107 | msgstr "Play"
108 |
109 | #: eluminance/eluminance.py:689
110 | msgid "Pause"
111 | msgstr "Pause"
112 |
113 | #: eluminance/eluminance.py:819
114 | #, python-format
115 | msgid "Version: %s"
116 | msgstr "Version: %s"
117 |
118 | #: eluminance/eluminance.py:828
119 | msgid "Eluminance"
120 | msgstr "Eluminance"
121 |
122 | #: eluminance/eluminance.py:833
123 | msgid "Website"
124 | msgstr "Website"
125 |
126 | #: eluminance/eluminance.py:838
127 | msgid "Authors"
128 | msgstr "Authors"
129 |
130 | #: eluminance/eluminance.py:843
131 | msgid "License"
132 | msgstr "License"
133 |
--------------------------------------------------------------------------------
/data/po/it.po:
--------------------------------------------------------------------------------
1 | # Traduzione italiana per Eluminance.
2 | # Copyright (C) 2015 Davide Andreoli
3 | # This file is distributed under the same license as the Eluminance package.
4 | # Davide Andreoli , 2015.
5 | #
6 | msgid ""
7 | msgstr ""
8 | "Project-Id-Version: Eluminance 1.0\n"
9 | "Report-Msgid-Bugs-To: \n"
10 | "POT-Creation-Date: 2015-05-24 18:13+0200\n"
11 | "PO-Revision-Date: 2015-05-24 18:14+0200\n"
12 | "Last-Translator: Davide Andreoli \n"
13 | "Language-Team: \n"
14 | "Language: Italiano\n"
15 | "MIME-Version: 1.0\n"
16 | "Content-Type: text/plain; charset=UTF-8\n"
17 | "Content-Transfer-Encoding: 8bit\n"
18 | "Plural-Forms: nplurals=2; plural=n != 1;\n"
19 |
20 | #: eluminance/eluminance.py:174
21 | msgid "No items to show"
22 | msgstr ""
23 |
24 | #: eluminance/eluminance.py:206
25 | msgid "Set as root"
26 | msgstr ""
27 |
28 | #: eluminance/eluminance.py:209
29 | msgid "Remove from favorites"
30 | msgstr ""
31 |
32 | #: eluminance/eluminance.py:212
33 | msgid "Add to favorites"
34 | msgstr ""
35 |
36 | #: eluminance/eluminance.py:587
37 | msgid "No image selected"
38 | msgstr "Nessuna immagine selezionata"
39 |
40 | #: eluminance/eluminance.py:603
41 | #, python-brace-format
42 | msgid "File {0} of {1}"
43 | msgstr "File {0} di {1}"
44 |
45 | #: eluminance/eluminance.py:607
46 | msgid "Resolution"
47 | msgstr "Risoluzione"
48 |
49 | #: eluminance/eluminance.py:608
50 | msgid "Size"
51 | msgstr "Dimensione"
52 |
53 | #: eluminance/eluminance.py:609
54 | msgid "Zoom"
55 | msgstr "Zoom"
56 |
57 | #: eluminance/eluminance.py:626
58 | msgid "Zoom in"
59 | msgstr "Aumenta zoom"
60 |
61 | #: eluminance/eluminance.py:627
62 | msgid "Zoom out"
63 | msgstr "Diminuisci zoom"
64 |
65 | #: eluminance/eluminance.py:628
66 | msgid "Zoom 1:1"
67 | msgstr "Zoom 1:1"
68 |
69 | #: eluminance/eluminance.py:629
70 | msgid "Zoom fit"
71 | msgstr "Adatta alla dimensione"
72 |
73 | #: eluminance/eluminance.py:630
74 | msgid "Zoom fill"
75 | msgstr ""
76 |
77 | #: eluminance/eluminance.py:632
78 | msgid "Previous photo"
79 | msgstr "Foto precedente"
80 |
81 | #: eluminance/eluminance.py:633
82 | msgid "Next photo"
83 | msgstr "Foto successiva"
84 |
85 | #: eluminance/eluminance.py:634
86 | msgid "Start/Stop slideshow"
87 | msgstr "Inizia/Interrompi presentazione"
88 |
89 | #: eluminance/eluminance.py:635
90 | msgid "Transition time"
91 | msgstr "Tempo tra le foto"
92 |
93 | #: eluminance/eluminance.py:636
94 | msgid "Transition style"
95 | msgstr "Stile della transizione"
96 |
97 | #: eluminance/eluminance.py:638
98 | msgid "Toggle fullscreen mode"
99 | msgstr "Alterna modalità schermo intero"
100 |
101 | #: eluminance/eluminance.py:639
102 | msgid "Eluminance info"
103 | msgstr "Informazioni"
104 |
105 | #: eluminance/eluminance.py:647 eluminance/eluminance.py:696
106 | msgid "Play"
107 | msgstr "Inizia"
108 |
109 | #: eluminance/eluminance.py:689
110 | msgid "Pause"
111 | msgstr "Interrompi"
112 |
113 | #: eluminance/eluminance.py:819
114 | #, python-format
115 | msgid "Version: %s"
116 | msgstr "Versione: %s"
117 |
118 | #: eluminance/eluminance.py:828
119 | msgid "Eluminance"
120 | msgstr "Eluminance"
121 |
122 | #: eluminance/eluminance.py:833
123 | msgid "Website"
124 | msgstr "Sito web"
125 |
126 | #: eluminance/eluminance.py:838
127 | msgid "Authors"
128 | msgstr "Autori"
129 |
130 | #: eluminance/eluminance.py:843
131 | msgid "License"
132 | msgstr "Licenza"
133 |
--------------------------------------------------------------------------------
/data/screenshots/eluminance01.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DaveMDS/eluminance/fe1bfceeac99fcf5b3f060f961ca0cca544a44f0/data/screenshots/eluminance01.jpg
--------------------------------------------------------------------------------
/data/screenshots/eluminance02.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DaveMDS/eluminance/fe1bfceeac99fcf5b3f060f961ca0cca544a44f0/data/screenshots/eluminance02.jpg
--------------------------------------------------------------------------------
/data/screenshots/eluminance03.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DaveMDS/eluminance/fe1bfceeac99fcf5b3f060f961ca0cca544a44f0/data/screenshots/eluminance03.jpg
--------------------------------------------------------------------------------
/data/themes/default/cropper.edc:
--------------------------------------------------------------------------------
1 |
2 | images {
3 | image: "sel_border.png" COMP;
4 | image: "sel_corner1.png" COMP;
5 | image: "sel_corner3.png" COMP;
6 | image: "sel_corner5.png" COMP;
7 | image: "sel_corner7.png" COMP;
8 | }
9 |
10 |
11 | group { name: "sel";
12 | script {
13 | public message(Msg_Type:type, id, ...) {
14 | if ((type == MSG_FLOAT_SET) && (id == 1)) {
15 | new Float:rel1x, Float:rel1y;
16 | new Float:rel2x, Float:rel2y;
17 |
18 | rel1x = getfarg(2);
19 | rel1y = getfarg(3);
20 | rel2x = getfarg(4);
21 | rel2y = getfarg(5);
22 |
23 | custom_state(PART:"selector", "default", 0.0);
24 | set_state_val(PART:"selector", STATE_REL1, rel1x, rel1y);
25 | set_state_val(PART:"selector", STATE_REL2, rel2x, rel2y);
26 | set_state(PART:"selector", "custom", 0.0);
27 | }
28 | }
29 | }
30 | parts {
31 | part { name: "shader_top"; type: RECT;
32 | repeat_events: 1;
33 | description { state: "default" 0.0;
34 | color: 0 0 0 150;
35 | rel2 {
36 | to_y: "selector";
37 | relative: 1.0 0.0;
38 | }
39 | }
40 | }
41 | part { name: "shader_bottom"; type: RECT;
42 | repeat_events: 1;
43 | description { state: "default" 0.0;
44 | color: 0 0 0 150;
45 | rel1 {
46 | to_y: "selector";
47 | relative: 0.0 1.0;
48 | }
49 | }
50 | }
51 | part { name: "shader_left"; type: RECT;
52 | repeat_events: 1;
53 | description { state: "default" 0.0;
54 | color: 0 0 0 150;
55 | rel1 {
56 | to_y: "selector";
57 | relative: 0.0 0.0;
58 | }
59 | rel2 {
60 | to: "selector";
61 | relative: 0.0 1.0;
62 | }
63 | }
64 | }
65 | part { name: "shader_right"; type: RECT;
66 | repeat_events: 1;
67 | description { state: "default" 0.0;
68 | color: 0 0 0 150;
69 | rel1 {
70 | to: "selector";
71 | relative: 1.0 0.0;
72 | }
73 | rel2 {
74 | to_y: "selector";
75 | relative: 1.0 1.0;
76 | }
77 | }
78 | }
79 | part { name: "selector"; type: IMAGE;
80 | repeat_events: 1;
81 | description { state: "default" 0.0;
82 | color: 255 255 255 200;
83 | rel1.relative: 0.2 0.2;
84 | rel2.relative: 0.8 0.8;
85 | image {
86 | normal: "sel_border.png";
87 | border: 3 3 3 3;
88 | middle: NONE;
89 | }
90 | }
91 | part { name: "h1"; type: IMAGE;
92 | repeat_events: 1;
93 | description { state: "default" 0.0;
94 | FIXED_SIZE(22, 22)
95 | rel1.offset: 1 1;
96 | align: 0.0 0.0;
97 | color: 255 255 255 0;
98 | image.normal: "sel_corner1.png";
99 | }
100 | description { state: "visible" 0.0;
101 | inherit: "default" 0.0;
102 | color: 255 255 255 200;
103 | }
104 | }
105 | part { name: "h2"; type: RECT;
106 | repeat_events: 1;
107 | description { state: "default" 0.0;
108 | color: 255 255 255 0;
109 | rel1 {
110 | to: "h1";
111 | relative: 1.0 0.0;
112 | offset: 3 2;
113 | }
114 | rel2 {
115 | to: "h3";
116 | relative: 0.0 1.0;
117 | offset: -4 -2;
118 | }
119 | }
120 | description { state: "visible" 0.0;
121 | inherit: "default" 0.0;
122 | color: 255 255 255 80;
123 | }
124 | }
125 | part { name: "h3"; type: IMAGE;
126 | repeat_events: 1;
127 | description { state: "default" 0.0;
128 | FIXED_SIZE(22, 22)
129 | rel1.offset: 0 1;
130 | rel2.offset: -2 -1;
131 | align: 1.0 0.0;
132 | color: 255 255 255 0;
133 | image.normal: "sel_corner3.png";
134 | }
135 | description { state: "visible" 0.0;
136 | inherit: "default" 0.0;
137 | color: 255 255 255 200;
138 | }
139 | }
140 | part { name: "h4"; type: RECT;
141 | repeat_events: 1;
142 | description { state: "default" 0.0;
143 | color: 255 255 255 0;
144 | rel1 {
145 | to: "h3";
146 | relative: 0.0 1.0;
147 | offset: 1 3;
148 | }
149 | rel2 {
150 | to: "h5";
151 | relative: 1.0 0.0;
152 | offset: -3 -4;
153 | }
154 | }
155 | description { state: "visible" 0.0;
156 | inherit: "default" 0.0;
157 | color: 255 255 255 80;
158 | }
159 | }
160 | part { name: "h5"; type: IMAGE;
161 | repeat_events: 1;
162 | description { state: "default" 0.0;
163 | FIXED_SIZE(22, 22)
164 | rel2.offset: -2 -2;
165 | align: 1.0 1.0;
166 | color: 255 255 255 0;
167 | image.normal: "sel_corner5.png";
168 | }
169 | description { state: "visible" 0.0;
170 | inherit: "default" 0.0;
171 | color: 255 255 255 200;
172 | }
173 | }
174 | part { name: "h6"; type: RECT;
175 | repeat_events: 1;
176 | description { state: "default" 0.0;
177 | rel1 {
178 | to: "h7";
179 | relative: 1.0 0.0;
180 | offset: 3 1;
181 | }
182 | rel2 {
183 | to: "h5";
184 | relative: 0.0 1.0;
185 | offset: -4 -3;
186 | }
187 | color: 255 255 255 0;
188 | }
189 | description { state: "visible" 0.0;
190 | inherit: "default" 0.0;
191 | color: 255 255 255 80;
192 | }
193 | }
194 | part { name: "h7"; type: IMAGE;
195 | repeat_events: 1;
196 | description { state: "default" 0.0;
197 | FIXED_SIZE(22, 22)
198 | rel1.offset: 1 0;
199 | rel2.offset: -1 -2;
200 | align: 0.0 1.0;
201 | color: 255 255 255 0;
202 | image.normal: "sel_corner7.png";
203 | }
204 | description { state: "visible" 0.0;
205 | inherit: "default" 0.0;
206 | color: 255 255 255 200;
207 | }
208 | }
209 | part { name: "h8"; type: RECT;
210 | repeat_events: 1;
211 | description { state: "default" 0.0;
212 | rel1 {
213 | to: "h1";
214 | relative: 0.0 1.0;
215 | offset: 2 3;
216 | }
217 | rel2 {
218 | to: "h7";
219 | relative: 1.0 0.0;
220 | offset: -2 -4;
221 | }
222 | color: 255 255 255 0;
223 | }
224 | description { state: "visible" 0.0;
225 | inherit: "default" 0.0;
226 | color: 255 255 255 80;
227 | }
228 | }
229 | part { name: "hm"; type: RECT;
230 | repeat_events: 1;
231 | description { state: "default" 0.0;
232 | color: 255 255 255 0;
233 | rel1 {
234 | to: "h1";
235 | relative: 1.0 1.0;
236 | }
237 | rel2 {
238 | to: "h5";
239 | relative: 0.0 0.0;
240 | }
241 | }
242 | }
243 |
244 | program { name: "show corner selectors";
245 | signal: "mouse,in"; source: "selector";
246 | action: STATE_SET "visible" 0.0;
247 | transition: LINEAR 0.3 ;
248 | targets: "h1" "h3" "h5" "h7";
249 | }
250 | program { name: "hide corner selectors";
251 | signal: "mouse,out"; source: "selector";
252 | action: STATE_SET "default" 0.0;
253 | transition: LINEAR 0.3 ;
254 | targets: "h1" "h3" "h5" "h7";
255 | }
256 |
257 | #define SHOW_HIDE_LATERALS(_NAME_) \
258 | program { signal: "mouse,in"; source: _NAME_; \
259 | action: STATE_SET "visible" 0.0; \
260 | transition: LINEAR 0.3 ; \
261 | target: _NAME_; } \
262 | program { signal: "mouse,out"; source: _NAME_; \
263 | action: STATE_SET "default" 0.0; \
264 | transition: LINEAR 0.3 ; \
265 | target: _NAME_; }
266 | SHOW_HIDE_LATERALS("h2")
267 | SHOW_HIDE_LATERALS("h4")
268 | SHOW_HIDE_LATERALS("h6")
269 | SHOW_HIDE_LATERALS("h8")
270 | #undef SHOW_HIDE_LATERALS
271 | }
272 | }
273 | }
274 |
275 |
--------------------------------------------------------------------------------
/data/themes/default/elm_slideshow.edc:
--------------------------------------------------------------------------------
1 | group { name: "elm/slideshow/base/eluminance";
2 | data {
3 | item: transitions "fade fade_fast black_fade horizontal vertical square immediate";
4 | item: layouts "fullscreen not_fullscreen";
5 | }
6 | parts {
7 | part { name: "whole"; type: RECT;
8 | description { state: "default" 0.0;
9 | color: 0 0 0 0;
10 | }
11 | description { state: "play" 0.0;
12 | color: 0 0 0 255;
13 | }
14 | }
15 | part { name: "image_1_whole"; type: RECT;
16 | description { state: "default" 0.0;
17 | }
18 | description { state: "fade_prev_next" 0.0;
19 | inherit: "default" 0.0;
20 | color: 255 255 255 0;
21 | }
22 | description { state: "black_fade_prev_next_init" 0.0;
23 | inherit: "default" 0.0;
24 | color: 255 255 255 255;
25 | }
26 | description { state: "black_fade_prev_next" 0.0;
27 | inherit: "default" 0.0;
28 | color: 0 0 0 255;
29 | }
30 | description { state: "horizontal_next_init" 0.0;
31 | inherit: "default" 0.0;
32 | }
33 | description { state: "horizontal_next" 0.0;
34 | inherit: "default" 0.0;
35 | rel1.relative: -1.0 0.0;
36 | rel2.relative: 0.0 1.0;
37 | }
38 | description { state: "horizontal_prev_init" 0.0;
39 | inherit: "default" 0.0;
40 | }
41 | description { state: "horizontal_prev" 0.0;
42 | inherit: "default" 0.0;
43 | rel1.relative: 1.0 0.0;
44 | rel2.relative: 2.0 1.0;
45 | }
46 | description { state: "vertical_next_init" 0.0;
47 | inherit: "default" 0.0;
48 | }
49 | description { state: "vertical_next" 0.0;
50 | inherit: "default" 0.0;
51 | rel1.relative: 0.0 -1.0;
52 | rel2.relative: 1.0 0.0;
53 | }
54 | description { state: "vertical_prev_init" 0.0;
55 | inherit: "default" 0.0;
56 | }
57 | description { state: "vertical_prev" 0.0;
58 | inherit: "default" 0.0;
59 | rel1.relative: 0.0 1.0;
60 | rel2.relative: 1.0 2.0;
61 | }
62 | description { state: "square_prev_next" 0.0;
63 | inherit: "default" 0.0;
64 | color: 255 255 255 0;
65 | }
66 | }
67 | part { name: "image_2_whole"; type: RECT;
68 | description { state: "default" 0.0;
69 | color: 255 255 255 0;
70 | }
71 | description { state: "fade_prev_next" 0.0;
72 | inherit: "default" 0.0;
73 | color: 255 255 255 255;
74 | }
75 | description { state: "black_fade_prev_next_init" 0.0;
76 | inherit: "default" 0.0;
77 | color: 0 0 0 0;
78 | }
79 | description { state: "black_fade_prev_next" 0.0;
80 | inherit: "default" 0.0;
81 | color: 255 255 255 255;
82 | }
83 | description { state: "horizontal_next_init" 0.0;
84 | inherit: "default" 0.0;
85 | rel1.relative: 1.0 0.0;
86 | rel2.relative: 2.0 1.0;
87 | color: 255 255 255 255;
88 | }
89 | description { state: "horizontal_next" 0.0;
90 | inherit: "default" 0.0;
91 | color: 255 255 255 255;
92 | }
93 | description { state: "horizontal_prev_init" 0.0;
94 | inherit: "default" 0.0;
95 | rel1.relative: -1.0 0.0;
96 | rel2.relative: 0.0 1.0;
97 | color: 255 255 255 255;
98 | }
99 | description { state: "horizontal_prev" 0.0;
100 | inherit: "default" 0.0;
101 | color: 255 255 255 255;
102 | }
103 | description { state: "vertical_next_init" 0.0;
104 | inherit: "default" 0.0;
105 | rel1.relative: 0.0 1.0;
106 | rel2.relative: 1.0 2.0;
107 | color: 255 255 255 255;
108 | }
109 | description { state: "vertical_next" 0.0;
110 | inherit: "default" 0.0;
111 | color: 255 255 255 255;
112 | }
113 | description { state: "vertical_prev_init" 0.0;
114 | inherit: "default" 0.0;
115 | rel1.relative: 0.0 -1.0;
116 | rel2.relative: 1.0 0.0;
117 | color: 255 255 255 255;
118 | }
119 | description { state: "vertical_prev" 0.0;
120 | inherit: "default" 0.0;
121 | color: 255 255 255 255;
122 | }
123 | description { state: "square_prev_next_init" 0.0;
124 | inherit: "default" 0.0;
125 | rel1.relative: 0.5 0.5;
126 | rel2.relative: 0.5 0.5;
127 | color: 255 255 255 255;
128 | }
129 | description { state: "square_prev_next" 0.0;
130 | inherit: "default" 0.0;
131 | rel1.relative: 0.0 0.0;
132 | rel2.relative: 1.0 1.0;
133 | color: 255 255 255 255;
134 | }
135 | }
136 | part { name: "elm.swallow.1"; type: SWALLOW;
137 | clip_to: "image_1_whole";
138 | description { state: "default" 0.0;
139 | rel1.to: "image_1_whole";
140 | rel2.to: "image_1_whole";
141 | }
142 | description { state: "not_fullscreen" 0.0;
143 | rel1.relative: 0.1 0.1;
144 | rel1.to: "image_1_whole";
145 | rel2.relative: 0.9 0.9;
146 | rel2.to: "image_1_whole";
147 | }
148 | }
149 | part { name: "elm.swallow.2"; type: SWALLOW;
150 | clip_to: "image_2_whole";
151 | description {
152 | state: "default" 0.0;
153 | rel1.to: "image_2_whole";
154 | rel2.to: "image_2_whole";
155 | }
156 | description { state: "not_fullscreen" 0.0;
157 | rel1.relative: 0.1 0.1;
158 | rel1.to: "image_2_whole";
159 | rel2.relative: 0.9 0.9;
160 | rel2.to: "image_2_whole";
161 | }
162 | }
163 | part { name: "events_catcher"; type: RECT; repeat_events: 1;
164 | description { state: "default" 0.0;
165 | color: 0 0 0 0;
166 | }
167 | }
168 | }
169 | programs {
170 | program { signal: "elm,layout,fullscreen"; source: "elm";
171 | action: STATE_SET "default" 0.0;
172 | target: "elm.swallow.1";
173 | target: "elm.swallow.2";
174 | transition: SINUSOIDAL 1.0;
175 | }
176 | program { signal: "elm,layout,not_fullscreen"; source: "elm";
177 | action: STATE_SET "not_fullscreen" 0.0;
178 | target: "elm.swallow.1";
179 | target: "elm.swallow.2";
180 | transition: SINUSOIDAL 1.0;
181 | }
182 | // Transition: fade
183 | program { signal: "elm,fade,next"; source: "elm";
184 | action: STATE_SET "default" 0.0;
185 | target: "image_1_whole";
186 | target: "image_2_whole";
187 | after: "fade_next_2";
188 | }
189 | program { name: "fade_next_2";
190 | action: STATE_SET "fade_prev_next" 0.0;
191 | target: "image_1_whole";
192 | target: "image_2_whole";
193 | transition: SINUSOIDAL 1.5;
194 | after: "end";
195 | }
196 | program { signal: "elm,fade,previous"; source: "elm";
197 | action: STATE_SET "default" 0.0;
198 | target: "image_1_whole";
199 | target: "image_2_whole";
200 | after: "fade_previous_2";
201 | }
202 | program { name: "fade_previous_2";
203 | action: STATE_SET "fade_prev_next" 0.0;
204 | target: "image_1_whole";
205 | target: "image_2_whole";
206 | transition: SINUSOIDAL 1.5;
207 | after: "end";
208 | }
209 | // Transition: fade_fast
210 | program { signal: "elm,fade_fast,next"; source: "elm";
211 | action: STATE_SET "default" 0.0;
212 | target: "image_1_whole";
213 | target: "image_2_whole";
214 | after: "fade_fast_next_2";
215 | }
216 | program { name: "fade_fast_next_2";
217 | action: STATE_SET "fade_prev_next" 0.0;
218 | target: "image_1_whole";
219 | target: "image_2_whole";
220 | transition: SINUSOIDAL 0.5;
221 | after: "end";
222 | }
223 | program { signal: "elm,fade_fast,previous"; source: "elm";
224 | action: STATE_SET "default" 0.0;
225 | target: "image_1_whole";
226 | target: "image_2_whole";
227 | after: "fade_fast_previous_2";
228 | }
229 | program { name: "fade_fast_previous_2";
230 | action: STATE_SET "fade_prev_next" 0.0;
231 | target: "image_1_whole";
232 | target: "image_2_whole";
233 | transition: SINUSOIDAL 0.5;
234 | after: "end";
235 | }
236 | // Transition: black_fade
237 | program {
238 | signal: "elm,black_fade,next"; source: "elm";
239 | action: STATE_SET "black_fade_prev_next_init" 0.0;
240 | target: "image_1_whole";
241 | target: "image_2_whole";
242 | after: "black_fade_next_2";
243 | }
244 | program { name: "black_fade_next_2";
245 | action: STATE_SET "black_fade_prev_next" 0.0;
246 | target: "image_1_whole";
247 | transition: SINUSOIDAL 0.75;
248 | after: "black_fade_next_3";
249 | }
250 | program { name: "black_fade_next_3";
251 | action: STATE_SET "black_fade_prev_next" 0.0;
252 | target: "image_2_whole";
253 | transition: SINUSOIDAL 0.75;
254 | after: "end";
255 | }
256 | program { signal: "elm,black_fade,previous"; source: "elm";
257 | action: STATE_SET "black_fade_prev_next_init" 0.0;
258 | target: "image_1_whole";
259 | target: "image_2_whole";
260 | after: "black_fade_previous_2";
261 | }
262 | program { name: "black_fade_previous_2";
263 | action: STATE_SET "black_fade_prev_next" 0.0;
264 | target: "image_1_whole";
265 | transition: SINUSOIDAL 0.75;
266 | after: "black_fade_previous_3";
267 | }
268 | program { name: "black_fade_previous_3";
269 | action: STATE_SET "black_fade_prev_next" 0.0;
270 | target: "image_2_whole";
271 | transition: SINUSOIDAL 0.75;
272 | after: "end";
273 | }
274 | // Transition: horizontal
275 | program { signal: "elm,horizontal,next"; source: "elm";
276 | action: STATE_SET "horizontal_next_init" 0.0;
277 | target: "image_1_whole";
278 | target: "image_2_whole";
279 | after: "horizontal_next_2";
280 | }
281 | program { name: "horizontal_next_2";
282 | action: STATE_SET "horizontal_next" 0.0;
283 | target: "image_1_whole";
284 | target: "image_2_whole";
285 | transition: SINUSOIDAL 1.5;
286 | after: "end";
287 | }
288 | program { name: "horizontal_previous";
289 | signal: "elm,horizontal,previous"; source: "elm";
290 | action: STATE_SET "horizontal_prev_init" 0.0;
291 | target: "image_1_whole";
292 | target: "image_2_whole";
293 | after: "horizontal_previous_2";
294 | }
295 | program { name: "horizontal_previous_2";
296 | action: STATE_SET "horizontal_prev" 0.0;
297 | target: "image_1_whole";
298 | target: "image_2_whole";
299 | transition: SINUSOIDAL 1.5;
300 | after: "end";
301 | }
302 | // Transition: vertical
303 | program { signal: "elm,vertical,next"; source: "elm";
304 | action: STATE_SET "vertical_next_init" 0.0;
305 | target: "image_1_whole";
306 | target: "image_2_whole";
307 | after: "vertical_next_2";
308 | }
309 | program { name: "vertical_next_2";
310 | action: STATE_SET "vertical_next" 0.0;
311 | target: "image_1_whole";
312 | target: "image_2_whole";
313 | transition: SINUSOIDAL 1.5;
314 | after: "end";
315 | }
316 | program { signal: "elm,vertical,previous"; source: "elm";
317 | action: STATE_SET "vertical_prev_init" 0.0;
318 | target: "image_1_whole";
319 | target: "image_2_whole";
320 | after: "vertical_previous_2";
321 | }
322 | program { name: "vertical_previous_2";
323 | action: STATE_SET "vertical_prev" 0.0;
324 | target: "image_1_whole";
325 | target: "image_2_whole";
326 | transition: SINUSOIDAL 1.5;
327 | after: "end";
328 | }
329 | // Transition: square
330 | program { signal: "elm,square,next"; source: "elm";
331 | action: STATE_SET "square_prev_next_init" 0.0;
332 | target: "image_2_whole";
333 | after: "square_next_2";
334 | }
335 | program { name: "square_next_2";
336 | action: STATE_SET "square_prev_next" 0.0;
337 | target: "image_2_whole";
338 | target: "image_1_whole";
339 | transition: SINUSOIDAL 1.5;
340 | after: "end";
341 | }
342 | program { signal: "elm,square,previous"; source: "elm";
343 | action: STATE_SET "square_prev_next_init" 0.0;
344 | target: "image_2_whole";
345 | after: "square_next_2";
346 | }
347 | program { signal: "elm,none,next"; source: "elm";
348 | action: STATE_SET "fade_prev_next" 0.0;
349 | target: "image_1_whole";
350 | target: "image_2_whole";
351 | after: "end";
352 | }
353 | program { signal: "elm,none,previous"; source: "elm";
354 | action: STATE_SET "fade_prev_next" 0.0;
355 | target: "image_1_whole";
356 | target: "image_2_whole";
357 | after: "end";
358 | }
359 | // Transition: immediate
360 | program { signal: "elm,immediate,next"; source: "elm";
361 | action: STATE_SET "fade_prev_next" 0.0;
362 | target: "image_1_whole";
363 | target: "image_2_whole";
364 | after: "end";
365 | }
366 | program { signal: "elm,immediate,previous"; source: "elm";
367 | action: STATE_SET "fade_prev_next" 0.0;
368 | target: "image_1_whole";
369 | target: "image_2_whole";
370 | after: "end";
371 | }
372 | // Anim end
373 | program { name: "end";
374 | action: SIGNAL_EMIT "elm,end" "elm";
375 | }
376 | program { signal: "elm,anim,end"; source: "elm";
377 | action: STATE_SET "default" 0.0;
378 | target: "image_1_whole";
379 | target: "image_2_whole";
380 | }
381 | // Custom eluminance play/pause mode
382 | program { signal: "eluminance,play"; source: "eluminance";
383 | action: STATE_SET "play" 0.0;
384 | transition: LINEAR 1.0;
385 | target: "whole";
386 | }
387 | program { signal: "eluminance,pause"; source: "eluminance";
388 | action: STATE_SET "default" 0.0;
389 | transition: LINEAR 1.0;
390 | target: "whole";
391 | }
392 | }
393 | }
394 |
395 | ///////////////////////////////////////////////////////////////////////////////
396 |
--------------------------------------------------------------------------------
/data/themes/default/images/bevel.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DaveMDS/eluminance/fe1bfceeac99fcf5b3f060f961ca0cca544a44f0/data/themes/default/images/bevel.png
--------------------------------------------------------------------------------
/data/themes/default/images/bg_fill.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DaveMDS/eluminance/fe1bfceeac99fcf5b3f060f961ca0cca544a44f0/data/themes/default/images/bg_fill.png
--------------------------------------------------------------------------------
/data/themes/default/images/bg_overlay.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DaveMDS/eluminance/fe1bfceeac99fcf5b3f060f961ca0cca544a44f0/data/themes/default/images/bg_overlay.png
--------------------------------------------------------------------------------
/data/themes/default/images/controls_bg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DaveMDS/eluminance/fe1bfceeac99fcf5b3f060f961ca0cca544a44f0/data/themes/default/images/controls_bg.png
--------------------------------------------------------------------------------
/data/themes/default/images/glint.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DaveMDS/eluminance/fe1bfceeac99fcf5b3f060f961ca0cca544a44f0/data/themes/default/images/glint.png
--------------------------------------------------------------------------------
/data/themes/default/images/icon_bookmark_add.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DaveMDS/eluminance/fe1bfceeac99fcf5b3f060f961ca0cca544a44f0/data/themes/default/images/icon_bookmark_add.png
--------------------------------------------------------------------------------
/data/themes/default/images/icon_bookmark_remove.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DaveMDS/eluminance/fe1bfceeac99fcf5b3f060f961ca0cca544a44f0/data/themes/default/images/icon_bookmark_remove.png
--------------------------------------------------------------------------------
/data/themes/default/images/icon_document_save.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DaveMDS/eluminance/fe1bfceeac99fcf5b3f060f961ca0cca544a44f0/data/themes/default/images/icon_document_save.png
--------------------------------------------------------------------------------
/data/themes/default/images/icon_document_save_as.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DaveMDS/eluminance/fe1bfceeac99fcf5b3f060f961ca0cca544a44f0/data/themes/default/images/icon_document_save_as.png
--------------------------------------------------------------------------------
/data/themes/default/images/icon_edit_cut.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DaveMDS/eluminance/fe1bfceeac99fcf5b3f060f961ca0cca544a44f0/data/themes/default/images/icon_edit_cut.png
--------------------------------------------------------------------------------
/data/themes/default/images/icon_go_next.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DaveMDS/eluminance/fe1bfceeac99fcf5b3f060f961ca0cca544a44f0/data/themes/default/images/icon_go_next.png
--------------------------------------------------------------------------------
/data/themes/default/images/icon_go_previous.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DaveMDS/eluminance/fe1bfceeac99fcf5b3f060f961ca0cca544a44f0/data/themes/default/images/icon_go_previous.png
--------------------------------------------------------------------------------
/data/themes/default/images/icon_info.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DaveMDS/eluminance/fe1bfceeac99fcf5b3f060f961ca0cca544a44f0/data/themes/default/images/icon_info.png
--------------------------------------------------------------------------------
/data/themes/default/images/icon_media_playback_pause.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DaveMDS/eluminance/fe1bfceeac99fcf5b3f060f961ca0cca544a44f0/data/themes/default/images/icon_media_playback_pause.png
--------------------------------------------------------------------------------
/data/themes/default/images/icon_media_playback_start.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DaveMDS/eluminance/fe1bfceeac99fcf5b3f060f961ca0cca544a44f0/data/themes/default/images/icon_media_playback_start.png
--------------------------------------------------------------------------------
/data/themes/default/images/icon_object_flip_horizontal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DaveMDS/eluminance/fe1bfceeac99fcf5b3f060f961ca0cca544a44f0/data/themes/default/images/icon_object_flip_horizontal.png
--------------------------------------------------------------------------------
/data/themes/default/images/icon_object_flip_vertical.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DaveMDS/eluminance/fe1bfceeac99fcf5b3f060f961ca0cca544a44f0/data/themes/default/images/icon_object_flip_vertical.png
--------------------------------------------------------------------------------
/data/themes/default/images/icon_object_rotate_left.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DaveMDS/eluminance/fe1bfceeac99fcf5b3f060f961ca0cca544a44f0/data/themes/default/images/icon_object_rotate_left.png
--------------------------------------------------------------------------------
/data/themes/default/images/icon_object_rotate_right.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DaveMDS/eluminance/fe1bfceeac99fcf5b3f060f961ca0cca544a44f0/data/themes/default/images/icon_object_rotate_right.png
--------------------------------------------------------------------------------
/data/themes/default/images/icon_preferences_system.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DaveMDS/eluminance/fe1bfceeac99fcf5b3f060f961ca0cca544a44f0/data/themes/default/images/icon_preferences_system.png
--------------------------------------------------------------------------------
/data/themes/default/images/icon_resize.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DaveMDS/eluminance/fe1bfceeac99fcf5b3f060f961ca0cca544a44f0/data/themes/default/images/icon_resize.png
--------------------------------------------------------------------------------
/data/themes/default/images/icon_rotate.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DaveMDS/eluminance/fe1bfceeac99fcf5b3f060f961ca0cca544a44f0/data/themes/default/images/icon_rotate.png
--------------------------------------------------------------------------------
/data/themes/default/images/icon_starred.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DaveMDS/eluminance/fe1bfceeac99fcf5b3f060f961ca0cca544a44f0/data/themes/default/images/icon_starred.png
--------------------------------------------------------------------------------
/data/themes/default/images/icon_view_fullscreen.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DaveMDS/eluminance/fe1bfceeac99fcf5b3f060f961ca0cca544a44f0/data/themes/default/images/icon_view_fullscreen.png
--------------------------------------------------------------------------------
/data/themes/default/images/icon_zoom.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DaveMDS/eluminance/fe1bfceeac99fcf5b3f060f961ca0cca544a44f0/data/themes/default/images/icon_zoom.png
--------------------------------------------------------------------------------
/data/themes/default/images/icon_zoom_fit_best.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DaveMDS/eluminance/fe1bfceeac99fcf5b3f060f961ca0cca544a44f0/data/themes/default/images/icon_zoom_fit_best.png
--------------------------------------------------------------------------------
/data/themes/default/images/icon_zoom_in.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DaveMDS/eluminance/fe1bfceeac99fcf5b3f060f961ca0cca544a44f0/data/themes/default/images/icon_zoom_in.png
--------------------------------------------------------------------------------
/data/themes/default/images/icon_zoom_original.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DaveMDS/eluminance/fe1bfceeac99fcf5b3f060f961ca0cca544a44f0/data/themes/default/images/icon_zoom_original.png
--------------------------------------------------------------------------------
/data/themes/default/images/icon_zoom_out.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DaveMDS/eluminance/fe1bfceeac99fcf5b3f060f961ca0cca544a44f0/data/themes/default/images/icon_zoom_out.png
--------------------------------------------------------------------------------
/data/themes/default/images/sel_border.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DaveMDS/eluminance/fe1bfceeac99fcf5b3f060f961ca0cca544a44f0/data/themes/default/images/sel_border.png
--------------------------------------------------------------------------------
/data/themes/default/images/sel_corner1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DaveMDS/eluminance/fe1bfceeac99fcf5b3f060f961ca0cca544a44f0/data/themes/default/images/sel_corner1.png
--------------------------------------------------------------------------------
/data/themes/default/images/sel_corner3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DaveMDS/eluminance/fe1bfceeac99fcf5b3f060f961ca0cca544a44f0/data/themes/default/images/sel_corner3.png
--------------------------------------------------------------------------------
/data/themes/default/images/sel_corner5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DaveMDS/eluminance/fe1bfceeac99fcf5b3f060f961ca0cca544a44f0/data/themes/default/images/sel_corner5.png
--------------------------------------------------------------------------------
/data/themes/default/images/sel_corner7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DaveMDS/eluminance/fe1bfceeac99fcf5b3f060f961ca0cca544a44f0/data/themes/default/images/sel_corner7.png
--------------------------------------------------------------------------------
/data/themes/default/images/status_bg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DaveMDS/eluminance/fe1bfceeac99fcf5b3f060f961ca0cca544a44f0/data/themes/default/images/status_bg.png
--------------------------------------------------------------------------------
/data/themes/default/main.edc:
--------------------------------------------------------------------------------
1 |
2 | #define DBG_SHOW(_PART, _R, _G, _B) \
3 | part { name: "dbg_show"_PART; \
4 | type: RECT; mouse_events: 0; \
5 | description { state: "default" 0.0; \
6 | rel1.to: _PART; rel2.to: _PART; \
7 | color: _R _G _B 50; } }
8 |
9 | #define SHOW(_PART) DBG_SHOW(_PART, 50, 0, 0)
10 |
11 | #define FIXED_SIZE(_W, _H) \
12 | min: _W _H; max: _W _H; fixed: 1 1;
13 |
14 |
15 | images {
16 | image: "bg_fill.png" COMP;
17 | image: "bg_overlay.png" COMP;
18 | image: "bevel.png" COMP;
19 | image: "glint.png" COMP;
20 | image: "status_bg.png" COMP;
21 | image: "controls_bg.png" COMP;
22 | }
23 |
24 | collections {
25 |
26 | /// MAIN UI ////////////////////////////////////////////////////////////////
27 | group { name: "eluminance/main";
28 | parts {
29 | //// Background -----------------------------------------------------
30 | part { name: "bg_fill"; mouse_events: 0;
31 | description { state: "default" 0.0;
32 | fixed: 1 1;
33 | image.normal: "bg_fill.png";
34 | fill {
35 | size.relative: 0.0 0.0;
36 | size.offset: 64 64;
37 | }
38 | }
39 | part { name: "bg_overlay"; mouse_events: 0;
40 | description { state: "default" 0.0;
41 | fixed: 1 1;
42 | image.normal: "bg_overlay.png";
43 | fill.smooth: 0;
44 | }
45 | }
46 | }
47 |
48 | //// Photocam -------------------------------------------------------
49 | part { name: "photo.swallow"; type: SWALLOW;
50 | description { state: "default" 0.0;
51 | }
52 | }
53 | part { name: "photo_events"; type: RECT;
54 | repeat_events: 1;
55 | description { state: "default" 0.0;
56 | color: 0 0 0 0;
57 | }
58 | description { state: "visible" 0.0; // used to implement the toggle
59 | color: 0 0 0 0;
60 | }
61 | }
62 | program { // show tree and grid (permanently)
63 | signal: "mouse,down,3"; source: "photo_events";
64 | filter: "photo_events" "default";
65 | action: STATE_SET "visible" 0.0;
66 | transition: DECEL 0.3;
67 | target: "photo_events";
68 | target: "grid_clip";
69 | target: "tree_clip";
70 | }
71 | program { // hide tree and grid
72 | signal: "mouse,down,3"; source: "photo_events";
73 | filter: "photo_events" "visible";
74 | action: STATE_SET "default" 0.0;
75 | transition: ACCELERATE 0.3;
76 | target: "photo_events";
77 | target: "grid_clip";
78 | target: "tree_clip";
79 | }
80 |
81 | //// Tree -----------------------------------------------------------
82 | part { name: "tree_clip"; type: RECT;
83 | description { state: "default" 0.0;
84 | rel2.relative: 0.0 0.0;
85 | rel2.to_y: "status";
86 | rel2.offset: -1 0;
87 | min: 200 0;
88 | fixed: 1 1;
89 | align: 1.0 0.0;
90 | color: 255 255 255 0;
91 | }
92 | description { state: "visible" 0.0;
93 | inherit: "default" 0.0;
94 | align: 0.0 0.0;
95 | color: 255 255 255 255;
96 | }
97 | }
98 | part { name: "tree.swallow"; type: SWALLOW;
99 | clip_to: "tree_clip";
100 | description { state: "default" 0.0;
101 | rel1.to: "tree_clip";
102 | rel2.to: "tree_clip";
103 | fixed: 1 1;
104 | }
105 | }
106 | part { name: "tree_event"; type: RECT;
107 | repeat_events: 1;
108 | description { state: "default" 0.0;
109 | rel1.to: "tree_clip";
110 | rel2.to: "tree_clip";
111 | rel2.offset: 50 -1;
112 | color: 0 0 0 0;
113 | fixed: 1 1;
114 | }
115 | }
116 | program { // show tree and grid
117 | signal: "mouse,in"; source: "tree_event";
118 | action: STATE_SET "visible" 0.0;
119 | transition: DECEL 0.3 CURRENT;
120 | target: "tree_clip";
121 | // target: "grid_clip";
122 | // CURRENT is broken for multiple targets, thus use after here...
123 | after: "show_grid";
124 | }
125 | program { // hide tree and grid
126 | signal: "mouse,out"; source: "tree_event";
127 | filter: "photo_events" "default"; // do not hide if fixed
128 | action: STATE_SET "default" 0.0;
129 | transition: ACCEL 0.3 CURRENT;
130 | target: "tree_clip";
131 | target: "grid_clip";
132 | }
133 |
134 | //// Grid ----------------------------------------------------------
135 | part { name: "grid_clip"; type: RECT;
136 | description { state: "default" 0.0;
137 | rel1.relative: 1.0 0.0;
138 | rel2.to_y: "status";
139 | rel2.relative: 1.0 0.0;
140 | rel2.offset: -1 0;
141 | min: 150 0;
142 | fixed: 1 1;
143 | align: 0.0 0.0;
144 | color: 255 255 255 0;
145 | }
146 | description { state: "visible" 0.0;
147 | inherit: "default" 0.0;
148 | align: 1.0 0.0;
149 | color: 255 255 255 255;
150 | }
151 | }
152 | part { name: "grid.swallow"; type: SWALLOW;
153 | clip_to: "grid_clip";
154 | description { state: "default" 0.0;
155 | rel1.to: "grid_clip";
156 | rel2.to: "grid_clip";
157 | fixed: 1 1;
158 | }
159 | }
160 | part { name: "grid_events"; type: RECT;
161 | repeat_events: 1;
162 | description { state: "default" 0.0;
163 | rel1.to: "grid_clip";
164 | rel2.to: "grid_clip";
165 | rel1.offset: -50 0;
166 | color: 0 0 0 0;
167 | fixed: 1 1;
168 | }
169 | }
170 | program { name: "show_grid";
171 | signal: "mouse,in"; source: "grid_events";
172 | action: STATE_SET "visible" 0.0;
173 | transition: DECEL 0.3 CURRENT;
174 | target: "grid_clip";
175 | }
176 | program { name: "hide grid";
177 | signal: "mouse,out"; source: "grid_events";
178 | filter: "photo_events" "default"; // do not hide if fixed
179 | action: STATE_SET "default" 0.0;
180 | transition: ACCEL 0.3 CURRENT;
181 | target: "grid_clip";
182 | }
183 |
184 | //// Controls -------------------------------------------------------
185 | part { name: "controls_bg"; type: IMAGE;
186 | description { state: "default" 0.0;
187 | rel1.to: "controls.box";
188 | rel2.to: "controls.box";
189 | rel1.offset: -13 -10;
190 | rel2.offset: 11 9;
191 | image {
192 | normal: "controls_bg.png";
193 | border: 15 15 15 15;
194 | }
195 | }
196 | }
197 | part { name: "controls.box"; type: BOX;
198 | description { state: "default" 0.0;
199 | rel1.relative: 0.5 0.0;
200 | rel2.relative: 0.5 0.0;
201 | align: 0.5 1.0;
202 | fixed: 1 1;
203 | box.min: 1 1;
204 | box.layout: "horizontal";
205 | }
206 | description { state: "visible" 0.0;
207 | inherit: "default" 0.0;
208 | align: 0.5 0.0;
209 | rel1.offset: 0 3;
210 | }
211 | }
212 | part { name: "controls_event"; type: RECT;
213 | repeat_events: 1;
214 | description { state: "default" 0.0;
215 | rel1.relative: 1.0 0.0;
216 | rel2.relative: 0.0 0.0;
217 | rel1.to_x: "tree_clip";
218 | rel2.to_x: "grid_clip";
219 | rel1.offset: 0 0;
220 | rel2.offset: 0 35;
221 | color: 0 0 0 0;
222 | }
223 | }
224 | program { name: "show_controls";
225 | signal: "mouse,in"; source: "controls_event";
226 | action: STATE_SET "visible" 0.0;
227 | transition: DECEL 0.2;
228 | target: "controls.box";
229 | after: "show status in play mode";
230 | }
231 | program { name: "show status in play mode";
232 | action: SIGNAL_EMIT "status,show" "";
233 | }
234 | program { name: "hide_controls";
235 | signal: "mouse,out"; source: "controls_event";
236 | action: STATE_SET "default" 0.0;
237 | transition: ACCEL 0.2;
238 | target: "controls.box";
239 | after: "hide status in play mode";
240 | in: 0.5 0;
241 | }
242 | program { name: "hide status in play mode";
243 | action: SIGNAL_EMIT "status,hide" "";
244 | }
245 | program { name: "stop_hiding";
246 | signal: "mouse,in"; source: "controls_event";
247 | action: ACTION_STOP;
248 | target: "hide_controls";
249 | }
250 |
251 | //// Statusbar -----------------------------------------------------
252 | part { name: "status"; type: IMAGE;
253 | description { state: "default" 0.0; // always visible (pause mode)
254 | rel1.relative: 0.0 1.0;
255 | rel1.offset: 0 -24;
256 | image.normal: "status_bg.png";
257 | fixed: 1 1;
258 | }
259 | description { state: "hidden" 0.0; // hidden in play mode
260 | inherit: "default" 0.0;
261 | rel1.offset: 0 0;
262 | rel2.offset: 0 24;
263 | }
264 | description { state: "visible" 0.0; // visible in play mode
265 | inherit: "default" 0.0;
266 | }
267 | part { name: "status.swallow"; type: SWALLOW;
268 | description { state: "default" 0.0;
269 | rel1.offset: 3 0;
270 | rel2.offset: -4 -1;
271 | }
272 | }
273 | part { name: "status_bevel"; mouse_events: 0;
274 | description { state: "default" 0.0;
275 | image.normal: "bevel.png";
276 | image.border: 0 0 1 1;
277 | image.middle: 0;
278 | fill.smooth: 0;
279 | }
280 | }
281 | part { name: "status_glint"; type: IMAGE;
282 | description { state: "default" 0.0;
283 | FIXED_SIZE(79, 5)
284 | rel2.relative: 1.0 0.0;
285 | rel2.offset: -1 0;
286 | image.normal: "glint.png";
287 | }
288 | }
289 | }
290 | program { signal: "eluminance,play"; source: "eluminance";
291 | action: STATE_SET "hidden" 0.0;
292 | transition: ACCEL 0.3;
293 | target: "status";
294 | }
295 | program { signal: "eluminance,pause"; source: "eluminance";
296 | action: STATE_SET "default" 0.0;
297 | transition: DECEL 0.3;
298 | target: "status";
299 | }
300 | program { signal: "status,show"; source: "";
301 | filter: "status" "hidden";
302 | action: STATE_SET "visible" 0.0;
303 | transition: DECEL 0.3;
304 | target: "status";
305 | }
306 | program { signal: "status,hide"; source: "";
307 | filter: "status" "visible";
308 | action: STATE_SET "hidden" 0.0;
309 | transition: ACCEL 0.3;
310 | target: "status";
311 | }
312 | }
313 | }
314 |
315 | /// TRANSPARENT SCROLLER (used in the ScrollablePhoto class) ///////////////
316 | group { name: "elm/scroller/base/trans";
317 | parts {
318 | part { name: "elm.swallow.content";
319 | type: SWALLOW;
320 | description { state: "default" 0.0;
321 | }
322 | }
323 | }
324 | }
325 |
326 | /// ELM SLIDESHOW //////////////////////////////////////////////////////////
327 | #include "elm_slideshow.edc"
328 |
329 | /// CROPPER ////////////////////////////////////////////////////////////////
330 | #include "cropper.edc"
331 |
332 |
333 | /// ICONS //////////////////////////////////////////////////////////////////
334 | #define IC(Name, File) \
335 | group { name: "elm/icon/"##Name##"/default"; \
336 | min: 16 16; max: 0 0; \
337 | images.image: File COMP; \
338 | parts { part { name: "base"; \
339 | description { \
340 | aspect: 1.0 1.0; aspect_preference: BOTH; \
341 | image.normal: File; } } } }
342 | IC("document-save", "icon_document_save.png")
343 | IC("document-save-as", "icon_document_save_as.png")
344 | IC("edit-cut", "icon_edit_cut.png")
345 | IC("go-next", "icon_go_next.png")
346 | IC("go-previous", "icon_go_previous.png")
347 | IC("media-playback-start", "icon_media_playback_start.png")
348 | IC("media-playback-pause", "icon_media_playback_pause.png")
349 | IC("zoom", "icon_zoom.png")
350 | IC("zoom-in", "icon_zoom_in.png")
351 | IC("zoom-out", "icon_zoom_out.png")
352 | IC("zoom-original", "icon_zoom_original.png")
353 | IC("zoom-fit-best", "icon_zoom_fit_best.png")
354 | IC("rotate", "icon_rotate.png")
355 | IC("resize", "icon_resize.png")
356 | IC("object-rotate-left", "icon_object_rotate_left.png")
357 | IC("object-rotate-right", "icon_object_rotate_right.png")
358 | IC("object-flip-vertical", "icon_object_flip_horizontal.png")
359 | IC("object-flip-horizontal", "icon_object_flip_vertical.png")
360 | IC("preferences-system", "icon_preferences_system.png")
361 | IC("view-fullscreen", "icon_view_fullscreen.png")
362 | IC("info", "icon_info.png")
363 | IC("bookmark-add", "icon_bookmark_add.png")
364 | IC("bookmark-remove", "icon_bookmark_remove.png")
365 | IC("starred", "icon_starred.png")
366 | #undef IC
367 |
368 | }
369 |
370 |
--------------------------------------------------------------------------------
/eluminance/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DaveMDS/eluminance/fe1bfceeac99fcf5b3f060f961ca0cca544a44f0/eluminance/__init__.py
--------------------------------------------------------------------------------
/eluminance/eluminance.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # encoding: utf-8
3 |
4 | # Copyright (C) 2015-2016 Davide Andreoli
5 | #
6 | # This file is part of Eluminance.
7 | #
8 | # Eluminance is free software; you can redistribute it and/or
9 | # modify it under the terms of the GNU Lesser General Public
10 | # License as published by the Free Software Foundation; either
11 | # version 3 of the License, or (at your option) any later version.
12 | #
13 | # Eluminance is distributed in the hope that it will be useful,
14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 | # Lesser General Public License for more details.
17 | #
18 | # You should have received a copy of the GNU Lesser General Public License
19 | # along with Eluminance. If not, see .
20 |
21 | from __future__ import absolute_import, print_function
22 |
23 | import os
24 | import sys
25 | import pickle
26 | import gettext
27 | from xdg.BaseDirectory import xdg_config_home
28 |
29 | from efl import edje
30 | from efl import elementary as elm
31 | from efl.evas import EXPAND_BOTH, EXPAND_HORIZ, EXPAND_VERT, \
32 | FILL_BOTH, FILL_HORIZ, FILL_VERT
33 |
34 | import eluminance.utils as utils
35 |
36 | __version__ = '0.9'
37 |
38 | IMG_EXTS = ('.jpg','.jpeg','.png','.gif','.tiff','.bmp')
39 |
40 | script_path = os.path.dirname(os.path.abspath(__file__))
41 | # Fix for lib64 taken from commit https://github.com/DaveMDS/egitu/commit/c92699b5e66f5d2a0ee02d5f4a5fa60afb3b21fb
42 | install_prefix = script_path[0:script_path.find('/python')]
43 | install_prefix = install_prefix[0:install_prefix.rfind('/')]
44 | data_path = os.path.join(install_prefix, 'share', 'eluminance')
45 | config_file = os.path.join(xdg_config_home, 'eluminance', 'config.pickle')
46 | THEME_FILE = os.path.join(data_path, 'themes', 'default.edj')
47 |
48 | # install the _() and ngettext() functions in the main namespace
49 | locale_dir = os.path.join(install_prefix, 'share', 'locale')
50 | gettext.install('eluminance', names='ngettext', localedir=locale_dir)
51 |
52 |
53 | class Options(object):
54 | """ Class for persistent application settings """
55 | def __init__(self):
56 | self.sshow_timeout = 5.0
57 | self.sshow_transition = 'fade_fast'
58 | self.sshow_loop = True
59 | self.favorites = []
60 |
61 | def load(self):
62 | try:
63 | # load only attributes (not methods) from the instance saved to disk
64 | saved = pickle.load(open(config_file, 'rb'))
65 | for attr in dir(self):
66 | if attr[0] != '_' and not callable(getattr(self, attr)):
67 | if hasattr(saved, attr):
68 | setattr(self, attr, getattr(saved, attr))
69 | except:
70 | pass
71 |
72 | def save(self):
73 | # create config folder if needed
74 | config_path = os.path.dirname(config_file)
75 | if not os.path.exists(config_path):
76 | os.makedirs(config_path)
77 | # save this whole class instance to file
78 | with open(config_file, 'wb') as f:
79 | pickle.dump(self, f, pickle.HIGHEST_PROTOCOL)
80 |
81 | app = None
82 | options = Options()
83 |
84 |
85 | class StdButton(elm.Button):
86 | """ A Button with a standard fdo icon """
87 | def __init__(self, parent, icon, *args, **kargs):
88 | elm.Button.__init__(self, parent, *args, **kargs)
89 | self.icon = icon
90 | self.show()
91 |
92 | @property
93 | def icon(self):
94 | return self.content
95 |
96 | @icon.setter
97 | def icon(self, name):
98 | self.content = utils.SafeIcon(self, name, size_hint_min=(18,18))
99 |
100 |
101 | class TreeView(elm.Table):
102 | def __init__(self, parent, select_cb):
103 | self._select_cb = select_cb
104 |
105 | elm.Table.__init__(self, parent, size_hint_expand=EXPAND_BOTH,
106 | size_hint_fill=FILL_BOTH)
107 |
108 | bg = elm.Background(self, size_hint_expand=EXPAND_BOTH,
109 | size_hint_fill=FILL_BOTH)
110 | self.pack(bg, 0, 0, 1, 2)
111 | bg.show()
112 |
113 | self.sc = elm.SegmentControl(self)
114 | it = self.sc.item_add(None, 'Home') # TODO: translate
115 | it.data['path'] = os.path.expanduser('~')
116 | it = self.sc.item_add(None, 'Root')
117 | it.data['path'] = '/'
118 | it = self.sc.item_add(None, 'Favs')
119 | it.data['path'] = 'favs'
120 | self.sc.callback_changed_add(self._segment_changed_cb)
121 | pad = elm.Frame(self, style='pad_small', content=self.sc,
122 | size_hint_expand=EXPAND_HORIZ)
123 | self.pack(pad, 0, 0, 1, 1)
124 | pad.show()
125 |
126 | self.itc = elm.GenlistItemClass('one_icon',
127 | text_get_func=self._gl_text_get,
128 | content_get_func=self._gl_content_get)
129 | self.li = elm.Genlist(self, size_hint_expand=EXPAND_BOTH,
130 | size_hint_fill=FILL_BOTH)
131 | self.li.callback_selected_add(self._item_selected_cb)
132 | self.li.callback_expand_request_add(self._item_expand_request_cb)
133 | self.li.callback_expanded_add(self._item_expanded_cb)
134 | self.li.callback_contract_request_add(self._item_contract_request_cb)
135 | self.li.callback_contracted_add(self._item_contracted_cb)
136 | self.li.callback_clicked_double_add(self._item_expand_request_cb)
137 | self.li.callback_clicked_right_add(self._item_clicked_right_cb)
138 | self.li.callback_longpressed_add(self._item_clicked_right_cb)
139 | self.pack(self.li, 0, 1, 1, 1)
140 | self.li.show()
141 |
142 | def _gl_text_get(self, gl, part, item_data):
143 | if item_data is None: return _('No items to show')
144 | return os.path.basename(item_data)
145 |
146 | def _gl_content_get(self, gl, part, item_data):
147 | if item_data is not None:
148 | icon = 'starred' if item_data in options.favorites else 'folder'
149 | return utils.SafeIcon(gl, icon, resizable=(False,False))
150 |
151 | def _item_selected_cb(self, gl, item):
152 | self._select_cb(item.data)
153 |
154 | def _item_expand_request_cb(self, gl, item):
155 | item.expanded = True
156 |
157 | def _item_expanded_cb(self, gl, item):
158 | self.populate(item.data, item)
159 |
160 | def _item_contract_request_cb(self, gl, item):
161 | item.expanded = False
162 |
163 | def _item_contracted_cb(self, gl, item):
164 | item.subitems_clear()
165 |
166 | def _item_clicked_right_cb(self, gl, item):
167 | if item.disabled: return
168 | item.selected = True
169 | app.win.freeze()
170 |
171 | pop = elm.Ctxpopup(app.win, direction_priority=(
172 | elm.ELM_CTXPOPUP_DIRECTION_RIGHT, elm.ELM_CTXPOPUP_DIRECTION_DOWN,
173 | elm.ELM_CTXPOPUP_DIRECTION_LEFT, elm.ELM_CTXPOPUP_DIRECTION_UP))
174 | pop.callback_dismissed_add(self._popup_dismissed_cb)
175 | pop.item_append(_('Set as root'), None,
176 | self._popup_set_root_cb, item.data)
177 | if item.data in options.favorites:
178 | label = _('Remove from favorites')
179 | icon = utils.SafeIcon(pop, 'bookmark-remove')
180 | else:
181 | label = _('Add to favorites')
182 | icon = utils.SafeIcon(pop, 'bookmark-add')
183 | pop.item_append(label, icon, self._popup_toggle_fav_cb, item.data)
184 |
185 | x, y = self.evas.pointer_canvas_xy_get()
186 | pop.move(x, y)
187 | pop.show()
188 |
189 | def _popup_set_root_cb(self, pop, item, path):
190 | self.set_root(path)
191 | pop.dismiss()
192 |
193 | def _popup_toggle_fav_cb(self, pop, item, path):
194 | if path in options.favorites:
195 | options.favorites.remove(path)
196 | else:
197 | options.favorites.append(path)
198 | pop.dismiss()
199 |
200 | def _popup_dismissed_cb(self, pop):
201 | app.win.unfreeze()
202 | pop.delete()
203 |
204 | def _segment_changed_cb(self, sc, item):
205 | self.set_root(item.data['path'], update_sc=False)
206 |
207 | def set_root(self, path, update_sc=True):
208 | if update_sc:
209 | for idx in range(self.sc.item_count):
210 | it = self.sc.item_get(idx)
211 | if it.data['path'] == path:
212 | it.selected = True
213 | return
214 | if self.sc.item_selected is not None:
215 | self.sc.item_selected.selected = False
216 |
217 | self.li.clear()
218 | self.populate(path)
219 |
220 | def populate(self, path, parent=None):
221 | it = None
222 | if path == 'favs':
223 | for path in utils.natural_sort(options.favorites):
224 | it = self.li.item_append(self.itc, path, parent,
225 | flags=elm.ELM_GENLIST_ITEM_TREE)
226 | else:
227 | for f in utils.natural_sort(os.listdir(path)):
228 | if f[0] == '.': continue
229 | fullpath = os.path.join(path, f)
230 | if os.path.isdir(fullpath):
231 | it = self.li.item_append(self.itc, fullpath, parent,
232 | flags=elm.ELM_GENLIST_ITEM_TREE)
233 | if it is None:
234 | it = self.li.item_append(self.itc, None, parent)
235 | it.disabled = True
236 |
237 | def expand_to_folder(self, path):
238 | if os.path.isfile(path):
239 | path = os.path.dirname(path)
240 | it = self.li.first_item
241 | while it:
242 | if it.data == path:
243 | it.expanded = True
244 | it.selected = True
245 | it.show()
246 | return
247 | if path.startswith(it.data + os.path.sep):
248 | it.expanded = True
249 | it = it.subitems_get()[0]
250 | else:
251 | it = it.next
252 |
253 |
254 | class PhotoGrid(elm.Gengrid):
255 | def __init__(self, parent, select_cb):
256 | self._select_cb = select_cb
257 | self.itc = elm.GengridItemClass('default',
258 | text_get_func=self._gg_text_get,
259 | content_get_func=self._gg_content_get)
260 | elm.Gengrid.__init__(self, parent,
261 | item_size=(128, 128), align=(0.5, 0.0),
262 | select_mode=elm.ELM_OBJECT_SELECT_MODE_ALWAYS)
263 | self.callback_selected_add(self._item_selected_cb)
264 | self.drag_item_container_add(0.2, 0.0,
265 | self._drag_item_get,
266 | self._drag_item_data_get)
267 |
268 | def _drag_item_get(self, obj, x, y):
269 | return self.at_xy_item_get(x, y)
270 |
271 | def _drag_item_data_get(self, obj, item, info):
272 | info.format = elm.ELM_SEL_FORMAT_TARGETS
273 | info.createicon = self._drag_create_icon
274 | info.createdata = item
275 | info.dragdone = self._drag_done
276 | info.donecbdata = item
277 | info.data = 'file://' + item.data
278 | return True
279 |
280 | def _drag_create_icon(self, win, xoff, yoff, item):
281 | item.cursor = 'fleur'
282 | ic = elm.Photo(win, file=item.data, aspect_fixed=True,
283 | fill_inside=False, size=100)
284 | mx, my = self.evas.pointer_canvas_xy
285 | return (ic, mx - 60, my - 60)
286 |
287 | def _drag_done(self, obj, accepted, item):
288 | item.cursor = None
289 |
290 | def _gg_content_get(self, gg, part, item_data):
291 | if part == 'elm.swallow.icon':
292 | return elm.Thumb(gg, style='noframe', aspect=elm.ETHUMB_THUMB_CROP,
293 | file=item_data)
294 |
295 | def _gg_text_get(self, gg, part, item_data):
296 | return os.path.basename(item_data)
297 |
298 | def _item_selected_cb(self, gg, item):
299 | self._select_cb(item.data, item.index - 1)
300 |
301 | def photo_add(self, path):
302 | self.item_append(self.itc, path)
303 |
304 | def file_select(self, path):
305 | if self.selected_item and self.selected_item.data == path:
306 | return
307 | it = self.first_item
308 | while it:
309 | if it.data == path:
310 | it.selected = True
311 | it.show() # XXX this is quite annoying if you are browsing the grid
312 | return
313 | it = it.next
314 |
315 |
316 | class ScrollablePhoto(elm.Scroller):
317 | ZOOMS = [5, 7, 10, 15, 20, 30, 50, 75, 100, 150, 200, 300,
318 | 500, 750, 1000, 1500, 2000, 3000, 5000, 7500, 10000]
319 | def __init__(self, parent, zoom_changed_cb):
320 | self._zoom_changed_cb = zoom_changed_cb
321 | self._zoom_mode = None # 'fill' or 'fit' on resize
322 | self.image_size = 0, 0 # original image pixel size
323 |
324 | elm.Scroller.__init__(self, parent, style="trans",
325 | policy=(elm.ELM_SCROLLER_POLICY_OFF, elm.ELM_SCROLLER_POLICY_OFF),
326 | movement_block=elm.ELM_SCROLLER_MOVEMENT_BLOCK_VERTICAL |
327 | elm.ELM_SCROLLER_MOVEMENT_BLOCK_HORIZONTAL)
328 | self.on_mouse_wheel_add(self._on_mouse_wheel)
329 | self.on_mouse_down_add(self._on_mouse_down)
330 | self.on_mouse_up_add(self._on_mouse_up)
331 | self.on_resize_add(self._on_resize)
332 |
333 | self.img = elm.Image(self, preload_disabled=False)
334 | self.img.show()
335 |
336 | # table help to keep the image centered in the scroller
337 | tb = elm.Table(self, size_hint_expand=EXPAND_BOTH,
338 | size_hint_fill=FILL_BOTH)
339 | tb.pack(self.img, 0, 0, 1, 1)
340 | self.content = tb
341 |
342 | def file_set(self, file):
343 | self.img.file_set(file)
344 | self.image_size = self.img.object_size
345 | if self.img.animated_available:
346 | self.img.animated = True
347 | self.img.animated_play = True
348 |
349 | def zoom_set(self, val):
350 | self._zoom_mode = None
351 | if val == 'fit' or val == 'fill':
352 | self._zoom_mode = val
353 | self._on_resize(self)
354 | elif val == '1:1':
355 | self.zoom = 100
356 | elif val == 'in':
357 | cur = self.zoom + 1
358 | for z in self.ZOOMS:
359 | if cur < z: break
360 | self.zoom_centered(z)
361 | elif val == 'out':
362 | cur = self.zoom - 1
363 | for z in reversed(self.ZOOMS):
364 | if cur > z: break
365 | self.zoom_centered(z)
366 |
367 | @property
368 | def zoom(self):
369 | return (float(self.img.size[0]) / float(self.image_size[0])) * 100
370 |
371 | @zoom.setter
372 | def zoom(self, val):
373 | z = utils.clamp(self.ZOOMS[0], val, self.ZOOMS[-1]) / 100.0
374 | w, h = self.image_size[0] * z, self.image_size[1] * z
375 | self.img.size_hint_min = w, h
376 | self.img.size_hint_max = w, h
377 | self._zoom_changed_cb(z * 100)
378 |
379 | def zoom_centered(self, val, center_on_mouse=False):
380 | iw, ih = self.img.size
381 | if ih > 0 and ih > 0:
382 | rx, ry, rw, rh = self.region
383 | cx, cy = self.evas.pointer_canvas_xy if center_on_mouse else \
384 | (rw / 2, rh / 2)
385 | dy, dx = float(cy + ry) / ih, float(cx + rx) / iw
386 |
387 | self.zoom = val
388 | if ih > 0 and ih > 0:
389 | w, h = self.img.size_hint_min
390 | rx, ry = int(w * dx) - cx, int(h * dy) - cy
391 | self.region_show(rx, ry, rw, rh)
392 |
393 | # mouse wheel: zoom
394 | def _on_mouse_wheel(self, obj, event):
395 | self._zoom_mode = None
396 | val = self.zoom * (0.9 if event.z == 1 else 1.1)
397 | self.zoom_centered(val, center_on_mouse=True)
398 |
399 | # mouse drag: pan
400 | def _on_mouse_down(self, obj, event):
401 | if event.button in (1, 2):
402 | self._drag_start_region = obj.region
403 | self._drag_start_x, self._drag_start_y = event.position.canvas
404 | obj.on_mouse_move_add(self._on_mouse_move)
405 | obj.cursor = 'fleur'
406 |
407 | def _on_mouse_up(self, obj, event):
408 | if event.button in (1, 2):
409 | obj.on_mouse_move_del(self._on_mouse_move)
410 | obj.cursor = None
411 |
412 | def _on_mouse_move(self, obj, event):
413 | x, y = event.position.canvas
414 | dx, dy = self._drag_start_x - x, self._drag_start_y - y
415 | x, y, w, h = self._drag_start_region
416 | obj.region_show(x + dx, y + dy, w, h)
417 |
418 | # scroller resize: keep the image fitted or filled
419 | def _on_resize(self, obj):
420 | if self._zoom_mode is not None:
421 | cw, ch = self.region[2], self.region[3]
422 | iw, ih = self.image_size
423 | if cw > 0 and ch > 0 and iw > 0 and ih > 0:
424 | zx, zy = float(cw) / float(iw), float(ch) / float(ih)
425 | z = min(zx, zy) if self._zoom_mode == 'fit' else max(zx, zy)
426 | self.zoom_centered(z * 100)
427 |
428 |
429 | class ScrollablePhotocam(elm.Photocam, elm.Scrollable):
430 | ZOOMS = [0.05, 0.07, 0.1, 0.15, 0.2, 0.3, 0.5, 0.75, 1.0, 1.5,
431 | 2.0, 3.0, 5.0, 7.5, 10, 15, 20, 30, 50, 75, 100]
432 | def __init__(self, parent, changed_cb):
433 | self._changed_cb = changed_cb
434 | elm.Photocam.__init__(self, parent, paused=True,
435 | zoom_mode=elm.ELM_PHOTOCAM_ZOOM_MODE_AUTO_FIT)
436 | self.policy = elm.ELM_SCROLLER_POLICY_OFF, elm.ELM_SCROLLER_POLICY_OFF
437 | self.callback_zoom_change_add(self._zoom_change_cb)
438 | self.on_mouse_wheel_add(self._on_mouse_wheel)
439 | self.on_mouse_down_add(self._on_mouse_down)
440 | self.on_mouse_up_add(self._on_mouse_up)
441 | # self.on_del_add(self._on_del) # UNUSED region selector
442 | # self._drag_start_geom = None # UNUSED region selector
443 | # self.sel = None # UNUSED region selector
444 |
445 | def zoom_set(self, val):
446 | if isinstance(val, float):
447 | self.zoom_mode = elm.ELM_PHOTOCAM_ZOOM_MODE_MANUAL
448 | self.zoom = utils.clamp(self.ZOOMS[-1] ** -1, val, self.ZOOMS[0] ** -1)
449 | self._zoom_change_cb(self)
450 | elif val == '1:1':
451 | self.zoom_set(1.0)
452 | elif val == 'fill':
453 | self.zoom_mode = elm.ELM_PHOTOCAM_ZOOM_MODE_AUTO_FILL
454 | elif val == 'fit':
455 | self.zoom_mode = elm.ELM_PHOTOCAM_ZOOM_MODE_AUTO_FIT
456 | elif val == 'in':
457 | old = self.zoom ** -1
458 | for z in self.ZOOMS:
459 | if old < z: break
460 | self.zoom_set(z ** -1)
461 | elif val == 'out':
462 | old = self.zoom ** -1
463 | for z in reversed(self.ZOOMS):
464 | if old > z: break
465 | self.zoom_set(z ** -1)
466 |
467 | # def _on_del(self, obj): # UNUSED region selector
468 | # if self.sel: self.sel.delete()
469 |
470 | # mouse wheel: zoom
471 | def _on_mouse_wheel(self, obj, event):
472 | new = self.zoom * (1.1 if event.z == 1 else 0.9)
473 | self.zoom_set(new)
474 |
475 | def _zoom_change_cb(self, obj):
476 | self._changed_cb((self.zoom ** -1) * 100)
477 |
478 | # mouse drag: pan
479 | def _on_mouse_down(self, obj, event):
480 | if event.button in (1, 2):
481 | self._drag_start_region = obj.region
482 | self._drag_start_x, self._drag_start_y = event.position.canvas
483 | self.on_mouse_move_add(self._on_mouse_move)
484 | self.cursor = 'fleur'
485 |
486 | def _on_mouse_up(self, obj, event):
487 | if event.button in (1, 2):
488 | self.on_mouse_move_del(self._on_mouse_move)
489 | self.cursor = None
490 |
491 | def _on_mouse_move(self, obj, event):
492 | # if self._drag_start_geom is None: # UNUSED region selector
493 | x, y = event.position.canvas
494 | dx, dy = self._drag_start_x - x, self._drag_start_y - y
495 | x, y, w, h = self._drag_start_region
496 | obj.region_show(x + dx, y + dy, w, h)
497 |
498 | """ UNUSED region selector stuff
499 | def region_selector_show(self):
500 | # from efl.edje import Edje
501 | self.sel = Edje(self.evas, file=THEME_FILE, group='sel')
502 | self.sel.show()
503 |
504 | internal = self.internal_image
505 | internal.on_move_add(self._internal_on_move_resize)
506 | internal.on_resize_add(self._internal_on_move_resize)
507 | self._internal_on_move_resize(internal)
508 |
509 | for part in ('h1','h2','h3','h4','h5','h6','h7','h8','hm'):
510 | h = self.sel.part_object_get(part)
511 | h.on_mouse_down_add(self._on_handler_mouse_down, part)
512 | h.on_mouse_up_add(self._on_handler_mouse_up, part)
513 |
514 | def _internal_on_move_resize(self, obj):
515 | self.sel.geometry = obj.geometry
516 |
517 | def _on_handler_mouse_down(self, obj, event, part):
518 | self._drag_start_x, self._drag_start_y = event.position.canvas
519 | self._drag_start_geom = self.sel.part_object_get('selector').geometry
520 | obj.on_mouse_move_add(self._on_handler_mouse_move, part)
521 |
522 | def _on_handler_mouse_up(self, obj, event, part):
523 | obj.on_mouse_move_del(self._on_handler_mouse_move)
524 | self._drag_start_geom = None
525 |
526 | def _on_handler_mouse_move(self, obj, event, part):
527 | x, y = event.position.canvas
528 | dx, dy = x - self._drag_start_x, y - self._drag_start_y
529 | x, y, w, h = self._drag_start_geom
530 | px, py, pw, ph = self.internal_image.geometry
531 |
532 | # calc new selection gemetry
533 | if part == 'hm':
534 | x, y = x + dx, y + dy
535 | elif part == 'h1':
536 | x, y = x + dx, y + dy
537 | w, h = w - dx, h - dy
538 | elif part == 'h2':
539 | y = y + dy
540 | h = h - dy
541 | elif part == 'h3':
542 | y = y + dy
543 | w, h = w + dx, h - dy
544 | elif part == 'h4':
545 | w = w + dx
546 | elif part == 'h5':
547 | w, h = w + dx, h + dy
548 | elif part == 'h6':
549 | h = h + dy
550 | elif part == 'h7':
551 | x, y = x + dx, y
552 | w, h = w - dx, h + dy
553 | elif part == 'h8':
554 | x = x + dx
555 | w = w - dx
556 |
557 | w, h = max(50, w), max(50, h)
558 |
559 | # calc new relative pos
560 | rel1x = float(x - px) / pw
561 | rel1y = float(y - py) / ph
562 | rel2x = float(x + w - px) / pw
563 | rel2y = float(y + h - py) / ph
564 |
565 | # constrain inside photo geometry
566 | rel1x = utils.clamp(0.0, rel1x, 1.0)
567 | rel1y = utils.clamp(0.0, rel1y, 1.0)
568 | rel2x = utils.clamp(0.0, rel2x, 1.0)
569 | rel2y = utils.clamp(0.0, rel2y, 1.0)
570 |
571 | # send signal to edje with new rels
572 | self.sel.message_send(1, (rel1x, rel1y, rel2x, rel2y))
573 | """
574 |
575 |
576 | class StatusBar(elm.Box):
577 | def __init__(self, parent):
578 | elm.Box.__init__(self, parent, horizontal=True,
579 | size_hint_expand=EXPAND_HORIZ,
580 | size_hint_fill=FILL_HORIZ)
581 |
582 | self.lb_name = elm.Label(self, ellipsis=True,
583 | size_hint_expand=EXPAND_HORIZ, size_hint_fill=FILL_HORIZ,
584 | text='{} '.format(_('No image selected')))
585 | self.pack_end(self.lb_name)
586 | self.lb_name.show()
587 |
588 | self.lb_info = elm.Label(self)
589 | self.pack_end(self.lb_info)
590 | self.lb_info.show()
591 |
592 | # edit button
593 | # bt = StdButton(self, icon='edit')
594 | # bt.callback_clicked_add(lambda b: ImageEditor(self.app))
595 | # self.pack_end(bt)
596 | # self.btn_edit = bt
597 |
598 | def update(self, img_path, img_num, tot_imgs, img_size, zoom):
599 | self.lb_name.text = '{}: {} '.format(
600 | _('File {0} of {1}').format(img_num, tot_imgs),
601 | os.path.basename(img_path))
602 | self.lb_info.text = \
603 | '{}: {}x{} {}: {} {}: {:.0f}%'.format(
604 | _('Resolution'), img_size[0], img_size[1],
605 | _('Size'), utils.file_hum_size(img_path),
606 | _('Zoom'), zoom)
607 |
608 |
609 | class SlideShow(elm.Slideshow):
610 | TRANSITIONS = ('fade', 'fade_fast', 'black_fade', 'horizontal', 'vertical',
611 | 'square', 'immediate')
612 | def __init__(self, parent, photo_changed_cb, zoom_changed_cb):
613 | self._photo_changed_cb = photo_changed_cb
614 | self._zoom_changed_cb = zoom_changed_cb
615 |
616 | self.itc = elm.SlideshowItemClass(self._item_get_func)
617 | elm.Slideshow.__init__(self, parent, style='eluminance',
618 | loop=options.sshow_loop,
619 | transition=options.sshow_transition)
620 | self.callback_changed_add(self._changed_cb)
621 |
622 | buttons = [ # (mode, tooltip, icon, action)
623 | (None, _('Zoom in'), 'zoom-in', 'in'),
624 | (None, _('Zoom out'), 'zoom-out', 'out'),
625 | (None, _('Zoom 1:1'), 'zoom-original', '1:1'),
626 | (None, _('Zoom fit'), 'zoom-fit', 'fit'),
627 | (None, _('Zoom fill'), 'zoom-fill', 'fill'),
628 | ('sep', None, None, None),
629 | (None, _('Previous photo'), 'go-previous', 'prev'),
630 | (None, _('Next photo'), 'go-next', 'next'),
631 | ('toggle', _('Start/Stop slideshow'), None, None),
632 | ('spinner', _('Transition time'), None, None),
633 | ('hover', _('Transition style'), None, None),
634 | ('sep', None, None, None),
635 | (None, _('Toggle fullscreen mode'), 'view-fullscreen', 'fs'),
636 | (None, _('Eluminance info'), 'help-about', 'info'),
637 | ]
638 |
639 | for mode, tooltip, icon, action in buttons:
640 | if mode == 'sep':
641 | w = elm.Separator(self)
642 | # Play/Pause toggle button
643 | elif mode == 'toggle':
644 | w = StdButton(self, icon='media-playback-start', text=_('Play'))
645 | w.callback_clicked_add(self._buttons_cb, 'slideshow')
646 | self.toggle_btn = w
647 | # timeout spinner
648 | elif mode == 'spinner':
649 | w = elm.Spinner(self, label_format="%2.0f secs.",
650 | step=1, min_max=(3, 60),
651 | value=options.sshow_timeout)
652 | w.callback_changed_add(self._spinner_cb)
653 | self.spinner = w
654 | # Transition selector
655 | elif mode == 'hover':
656 | w = elm.Hoversel(self, hover_parent=parent,
657 | text=_(options.sshow_transition))
658 | w.callback_clicked_add(lambda h: app.win.freeze())
659 | w.callback_dismissed_add(lambda h: app.win.unfreeze())
660 | for t in self.TRANSITIONS:
661 | w.item_add(t, None, 0, self._transition_cb, t)
662 | self.hs_transition = w
663 | # normal buttons
664 | else:
665 | w = StdButton(self, icon=icon)
666 | w.callback_clicked_add(self._buttons_cb, action)
667 |
668 | parent.layout.box_append('controls.box', w)
669 | if tooltip: w.tooltip_text_set(tooltip)
670 | w.show()
671 |
672 | def photo_add(self, path):
673 | item_data = (path, self.count + 1)
674 | item = self.item_add(self.itc, item_data)
675 | # XXX the first added item get the changed_cb called before
676 | # python-efl can do the _set_obj, so we get a null item.object in the cb
677 | if self.count == 1 and item.object:
678 | self._photo_changed_cb(path)
679 |
680 | def photo_nth_show(self, index):
681 | self.nth_item_get(index).show()
682 |
683 | def play(self):
684 | self.timeout = options.sshow_timeout
685 | self.toggle_btn.text = _('Pause')
686 | self.toggle_btn.icon = 'media-playback-pause'
687 | self.signal_emit('eluminance,play', 'eluminance')
688 | app.win.layout.signal_emit('eluminance,play', 'eluminance')
689 |
690 | def pause(self):
691 | self.timeout = 0.0
692 | self.toggle_btn.text = _('Play')
693 | self.toggle_btn.icon = 'media-playback-start'
694 | self.signal_emit('eluminance,pause', 'eluminance')
695 | app.win.layout.signal_emit('eluminance,pause', 'eluminance')
696 |
697 | @property
698 | def photo(self):
699 | return self.current_item.object
700 |
701 | @property
702 | def index(self):
703 | path, index = self.current_item.data
704 | return index
705 |
706 | def _item_get_func(self, obj, item_data):
707 | path, index = item_data
708 | # img = ScrollablePhotocam(self, self._zoom_changed_cb)
709 | img = ScrollablePhoto(self, self._zoom_changed_cb)
710 | img.file_set(path)
711 | img.zoom_set('fit')
712 | return img
713 |
714 | def _changed_cb(self, obj, item):
715 | if item.object: # XXX see below note in photo_add()
716 | path, index = item.data
717 | self._photo_changed_cb(path)
718 |
719 | def _buttons_cb(self, bt, action):
720 | if action == 'next':
721 | self.next()
722 | elif action == 'prev':
723 | self.previous()
724 | elif action == 'slideshow':
725 | self.play() if self.timeout == 0 else self.pause()
726 | elif action == 'fs':
727 | app.win.fullscreen = not app.win.fullscreen
728 | elif action == 'info':
729 | InfoWin(app.win)
730 | elif action in ('in', 'out', 'fit', 'fill', '1:1'):
731 | self.photo.zoom_set(action)
732 |
733 | def _spinner_cb(self, spinner):
734 | options.sshow_timeout = spinner.value
735 | if self.timeout != 0:
736 | self.timeout = options.sshow_timeout
737 |
738 | def _transition_cb(self, hoversel, item, transition):
739 | self.transition = options.sshow_transition = transition
740 | self.hs_transition.text = _(transition)
741 |
742 |
743 | class InfoWin(elm.DialogWindow):
744 | def __init__(self, parent):
745 | elm.DialogWindow.__init__(self, parent, 'eluminance-info', 'Eluminance',
746 | autodel=True)
747 |
748 | fr = elm.Frame(self, style='pad_large', size_hint_expand=EXPAND_BOTH,
749 | size_hint_align=FILL_BOTH)
750 | self.resize_object_add(fr)
751 | fr.show()
752 |
753 | hbox = elm.Box(self, horizontal=True, padding=(12,12))
754 | fr.content = hbox
755 | hbox.show()
756 |
757 | vbox = elm.Box(self, align=(0.0,0.0), padding=(6,6),
758 | size_hint_expand=EXPAND_VERT, size_hint_fill=FILL_VERT)
759 | hbox.pack_end(vbox)
760 | vbox.show()
761 |
762 | # icon + version
763 | ic = utils.SafeIcon(self, 'eluminance', size_hint_min=(64,64))
764 | vbox.pack_end(ic)
765 | ic.show()
766 |
767 | lb = elm.Label(self, text=_('Version: %s') % __version__)
768 | vbox.pack_end(lb)
769 | lb.show()
770 |
771 | sep = elm.Separator(self, horizontal=True)
772 | vbox.pack_end(sep)
773 | sep.show()
774 |
775 | # buttons
776 | bt = elm.Button(self, text=_('Eluminance'), size_hint_fill=FILL_HORIZ)
777 | bt.callback_clicked_add(lambda b: self.entry.text_set(utils.INFO))
778 | vbox.pack_end(bt)
779 | bt.show()
780 |
781 | bt = elm.Button(self, text=_('Website'),size_hint_align=FILL_HORIZ)
782 | bt.callback_clicked_add(lambda b: utils.xdg_open(utils.HOMEPAGE))
783 | vbox.pack_end(bt)
784 | bt.show()
785 |
786 | bt = elm.Button(self, text=_('Authors'), size_hint_align=FILL_HORIZ)
787 | bt.callback_clicked_add(lambda b: self.entry.text_set(utils.AUTHORS))
788 | vbox.pack_end(bt)
789 | bt.show()
790 |
791 | bt = elm.Button(self, text=_('License'), size_hint_align=FILL_HORIZ)
792 | bt.callback_clicked_add(lambda b: self.entry.text_set(utils.LICENSE))
793 | vbox.pack_end(bt)
794 | bt.show()
795 |
796 | # main text
797 | self.entry = elm.Entry(self, editable=False, scrollable=True,
798 | text=utils.INFO, size_hint_expand=EXPAND_BOTH,
799 | size_hint_fill=FILL_BOTH)
800 | self.entry.callback_anchor_clicked_add(lambda e,i: utils.xdg_open(i.name))
801 | hbox.pack_end(self.entry)
802 | self.entry.show()
803 |
804 | self.resize(400, 200)
805 | self.show()
806 |
807 |
808 | class MainWin(elm.StandardWindow):
809 | def __init__(self):
810 | elm.StandardWindow.__init__(self, 'eluminance', 'Eluminance',
811 | autodel=True, size=(800,600),
812 | tree_focus_allow=False)
813 | self.callback_delete_request_add(lambda o: elm.exit())
814 |
815 | self.layout = elm.Layout(self, file=(THEME_FILE, 'eluminance/main'),
816 | size_hint_expand=EXPAND_BOTH,
817 | tree_focus_allow=False)
818 | self.resize_object_add(self.layout)
819 | self.layout.show()
820 |
821 | def swallow_all(self, app):
822 | self.layout.content_set('photo.swallow', app.sshow)
823 | self.layout.content_set('grid.swallow', app.grid)
824 | self.layout.content_set('tree.swallow', app.tree)
825 | self.layout.content_set('status.swallow', app.status)
826 |
827 | def freeze(self):
828 | self.layout.edje.play_set(False)
829 |
830 | def unfreeze(self):
831 | self.layout.edje.play_set(True)
832 |
833 |
834 | class EluminanceApp(object):
835 | def __init__(self):
836 | self.win = MainWin()
837 | self.sshow = SlideShow(self.win, self.photo_changed, self.zoom_changed)
838 | self.grid = PhotoGrid(self.win, self.grid_selected)
839 | self.tree = TreeView(self.win, self.tree_selected)
840 | self.status = StatusBar(self.win)
841 | self.win.swallow_all(self)
842 |
843 | home = os.path.expanduser('~')
844 | self.current_path = home
845 | self.current_file = None
846 | request = None
847 |
848 | if len(sys.argv) > 1:
849 | request = os.path.abspath(sys.argv[1])
850 | if not os.path.exists(request):
851 | request = None
852 |
853 | if request:
854 | if request.startswith(home):
855 | self.tree.set_root(home)
856 | else:
857 | self.tree.set_root('/')
858 | self.tree.expand_to_folder(request)
859 | if os.path.isfile(request):
860 | self.grid.file_select(request)
861 | else:
862 | self.tree.set_root(home)
863 |
864 | self.win.show()
865 |
866 | def tree_selected(self, path):
867 | self.current_path = path
868 | self.sshow.clear()
869 | self.grid.clear()
870 | for f in utils.natural_sort(os.listdir(path)):
871 | if os.path.splitext(f)[-1].lower() in IMG_EXTS:
872 | full_path = os.path.join(path, f)
873 | self.grid.photo_add(full_path)
874 | self.sshow.photo_add(full_path)
875 | self.win.title = 'eluminance - ' + self.current_path
876 |
877 | def grid_selected(self, path, index):
878 | self.sshow.photo_nth_show(index)
879 |
880 | def photo_changed(self, path):
881 | self.current_file = path
882 | self.grid.file_select(path)
883 | self.status.update(self.current_file, self.sshow.index, self.sshow.count,
884 | self.sshow.photo.image_size, 0)
885 |
886 | def zoom_changed(self, zoom):
887 | # TODO update only the zoom
888 | self.status.update(self.current_file, self.sshow.index, self.sshow.count,
889 | self.sshow.photo.image_size, zoom)
890 |
891 |
892 | def main():
893 | options.load()
894 | elm.need_ethumb()
895 | elm.theme_extension_add(THEME_FILE)
896 |
897 | global app
898 | app = EluminanceApp()
899 | elm.run()
900 | options.save()
901 |
902 | if __name__ == '__main__':
903 | sys.exit(main())
904 |
905 |
906 | """
907 | class ImageEditor(object):
908 | def __init__(self, app):
909 | self.bg = Background(app.win, size_hint_expand=EXPAND_BOTH)
910 | app.win.resize_object_add(self.bg)
911 | self.bg.show()
912 |
913 | box = elm.Box(self.bg, size_hint_expand=EXPAND_BOTH,
914 | size_hint_fill=FILL_BOTH)
915 | app.win.resize_object_add(box)
916 | box.show()
917 |
918 | tb = elm.Toolbar(app.win, homogeneous=True, menu_parent=app.win,
919 | size_hint_expand=EXPAND_HORIZ,
920 | size_hint_fill=FILL_HORIZ)
921 |
922 | item = tb.item_append('rotate', 'Rotate')
923 | item.menu = True
924 | item.menu.item_add(None, 'Rotate Right', 'object-rotate-right')
925 | item.menu.item_add(None, 'Rotate Left', 'object-rotate-left')
926 | item.menu.item_add(None, 'Mirror', 'object-flip-horizontal')
927 | item.menu.item_add(None, 'Flip', 'object-flip-vertical')
928 |
929 | tb.item_append('edit-cut', 'Crop', self._crop_item_cb)
930 | tb.item_append('resize', 'Resize')
931 |
932 | sep = tb.item_append(None, None)
933 | sep.separator = True
934 |
935 | tb.item_append('document-save', 'Save')
936 | tb.item_append('document-save-as', 'Save as')
937 | tb.item_append('document-close', 'Close', self._close_item_cb)
938 |
939 | box.pack_end(tb)
940 | tb.show()
941 |
942 | self.photo = ScrollablePhotocam(app, box, file=app.photo.file,
943 | size_hint_expand=EXPAND_BOTH,
944 | size_hint_fill=FILL_BOTH)
945 | box.pack_end(self.photo)
946 | self.photo.show()
947 |
948 | def _crop_item_cb(self, tb, item):
949 | self.photo.region_selector_show()
950 |
951 | def _close_item_cb(self, tb, item):
952 | self.bg.delete()
953 | """
954 |
--------------------------------------------------------------------------------
/eluminance/utils.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # encoding: utf-8
3 |
4 | # Copyright (C) 2015-2016 Davide Andreoli
5 | #
6 | # This file is part of Eluminance.
7 | #
8 | # Eluminance is free software; you can redistribute it and/or
9 | # modify it under the terms of the GNU Lesser General Public
10 | # License as published by the Free Software Foundation; either
11 | # version 3 of the License, or (at your option) any later version.
12 | #
13 | # Eluminance is distributed in the hope that it will be useful,
14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 | # Lesser General Public License for more details.
17 | #
18 | # You should have received a copy of the GNU Lesser General Public License
19 | # along with Eluminance. If not, see .
20 |
21 | from __future__ import absolute_import, print_function, unicode_literals
22 |
23 | import os
24 | import re
25 | from efl.ecore import Exe
26 | from efl.elementary import Icon
27 |
28 |
29 | def xdg_open(url_or_file):
30 | Exe('xdg-open "%s"' % url_or_file)
31 |
32 | def clamp(low, val, high):
33 | if val < low: return low
34 | if val > high: return high
35 | return val
36 |
37 | def file_hum_size(file_path):
38 | bytes = float(os.path.getsize(file_path))
39 | if bytes >= 1099511627776:
40 | terabytes = bytes / 1099511627776
41 | size = '%.1fT' % terabytes
42 | elif bytes >= 1073741824:
43 | gigabytes = bytes / 1073741824
44 | size = '%.1fG' % gigabytes
45 | elif bytes >= 1048576:
46 | megabytes = bytes / 1048576
47 | size = '%.1fM' % megabytes
48 | elif bytes >= 1024:
49 | kilobytes = bytes / 1024
50 | size = '%.1fK' % kilobytes
51 | else:
52 | size = '%.1fb' % bytes
53 | return size
54 |
55 | def natural_sort(l):
56 | convert = lambda text: int(text) if text.isdigit() else text.lower()
57 | alphanum_key = lambda key: [convert(c) for c in re.split('([0-9]+)', key)]
58 | return sorted(l, key=alphanum_key)
59 |
60 |
61 | class SafeIcon(Icon):
62 | def __init__(self, parent, icon_name, **kargs):
63 | Icon.__init__(self, parent, **kargs)
64 | try:
65 | self.standard = icon_name
66 | except RuntimeWarning:
67 | print("ERROR: Cannot find icon: '%s'" % icon_name)
68 |
69 |
70 | HOMEPAGE = 'https://github.com/davemds/eluminance'
71 |
72 | AUTHORS = """
73 |
74 |
75 |
76 | Davide Andreoli (davemds)
77 | dave@gurumeditation.it
78 |
79 | Wolfgang Morawetz (wfx)
80 | wolfgang.morawetz@gmail.com
81 |
82 |
83 | """
84 |
85 | INFO = """
86 |
87 | Eluminance is a fast photo browser written in python.
88 |
89 | """
90 |
91 | LICENSE = """
92 |
93 |
94 | GNU GENERAL PUBLIC LICENSE
95 | Version 3, 29 June 2007
96 |
97 |
98 | This program is free software: you can redistribute it and/or modify
99 | it under the terms of the GNU General Public License as published by
100 | the Free Software Foundation, either version 3 of the License, or
101 | (at your option) any later version.
102 |
103 | This program is distributed in the hope that it will be useful,
104 | but WITHOUT ANY WARRANTY; without even the implied warranty of
105 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
106 | GNU General Public License for more details.
107 |
108 | You should have received a copy of the GNU General Public License
109 | along with this program. If not, see
110 | http://www.gnu.org/licenses/
111 |
112 | """
113 |
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | from distutils.core import setup
4 | from distutils.version import StrictVersion
5 | from efl.utils.setup import build_extra, build_edc, build_fdo, build_i18n, uninstall
6 | from efl import __version__ as efl_version
7 |
8 |
9 | MIN_EFL = '1.18'
10 | if StrictVersion(efl_version) < MIN_EFL:
11 | print('Your python-efl version is too old! Found: ' + efl_version)
12 | print('You need at least version ' + MIN_EFL)
13 | exit(1)
14 |
15 | setup(
16 | name = 'eluminance',
17 | version = '0.9',
18 | description = 'Photo browser',
19 | long_description = 'A photo browser written in python-efl',
20 | license = "GNU GPL",
21 | author = 'Dave Andreoli',
22 | author_email = 'dave@gurumeditation.it',
23 | packages = ['eluminance'],
24 | requires = ['efl (>=1.18)', 'xdg'],
25 | provides = ['eluminance'],
26 | scripts = ['bin/eluminance'],
27 | cmdclass={
28 | 'build': build_extra,
29 | 'build_edc': build_edc,
30 | 'build_fdo': build_fdo,
31 | 'build_i18n': build_i18n,
32 | 'uninstall': uninstall,
33 | },
34 | command_options={
35 | 'install': {'record': ('setup.py', 'installed_files.txt')}
36 | },
37 | )
38 |
39 |
--------------------------------------------------------------------------------