3
# Julien Lavergne (c) 2009 julien.lavergne@gmail.com
5
#This program is free software; you can redistribute it and/or
6
#modify it under the terms of the GNU General Public License
7
#as published by the Free Software Foundation; either version 2
8
#of the License, or (at your option) any later version.
10
#This program is distributed in the hope that it will be useful,
11
#but WITHOUT ANY WARRANTY; without even the implied warranty of
12
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
#GNU General Public License for more details.
15
#You should have received a copy of the GNU General Public License
16
#along with this program; if not, write to the Free Software
17
#Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22
#Implement mousewheel to display hidden files
25
from screenlets.options import StringOption, FontOption, BoolOption, IntOption, ColorOption, DirectoryOption
26
from screenlets.utils import xdg_open
37
screenlets.show_message(None,'You don\'t have GIO python bindings installed. \nYou need to install python-gobject >= 2.15 .')
40
log = screenlets.logger.get_default_logger()
42
class FolderViewCloneScreenlet(screenlets.Screenlet):
44
# default meta-info for Screenlets
45
__name__ = 'FolderViewClone'
47
__author__ = 'Julien Lavergne'
48
__desc__ = 'Display the content of a folder'
53
# editable options and defaults
54
__update_interval = 1 # every second
57
def __init__(self, **keyword_args):
59
screenlets.Screenlet.__init__(self, width=400, height=200, **keyword_args)
63
self.theme_name = "default"
65
#Init the theme to search for icons and default style
66
self.theme = gtk.icon_theme_get_default()
70
self.icon_size_default = 48
71
self.icon_size = self.icon_size_default
72
self.icon_in_row_default = 4
73
self.icon_in_column_default = 2
76
self.icons_in_column = 2
78
self.files_list_show = []
81
self.folder_path = os.path.join(os.path.expanduser("~"))
82
self.folder_path_current = self.folder_path
83
self.files_list = self.populate_list(self.folder_path_current)
84
self.monitor = self.monitor_path(self.folder_path_current)
86
self.font_default = "FreeSans"
87
self.banner_size_default = 40
89
self.border_size_default = 2
90
self.border_size_selected = 2
92
self.cursor_position = [-1,-1]
94
self.auto_update = False
96
# add default menu items
97
self.add_menuitem("up_folder", "Up")
98
self.add_default_menuitems()
101
self.add_options_group('Folder', 'Settings for the folder ...')
104
self.add_option(IntOption('Folder','icon_size',
105
self.icon_size_default, 'Icons Size','',
106
callback=self.update, always_trigger_callback=False))
108
self.add_option(IntOption('Folder','icons_in_row',
109
self.icon_in_row_default, 'Icons in a row','Number of icons in a row',
110
callback=self.update_path, always_trigger_callback=False))
112
self.add_option(IntOption('Folder','icons_in_column',
113
self.icon_in_column_default, 'Icons in a column','Number of icons in a column',
114
callback=self.update_path, always_trigger_callback=False))
116
self.add_option(IntOption('Folder','banner_size',
117
self.banner_size_default, 'Size of the Banner','',
118
callback=self.update, always_trigger_callback=False))
120
self.add_option(DirectoryOption('Folder', 'Path',
121
self.folder_path, 'Path', 'Default path to the folder',
122
callback=self.update_path_from_settings,
123
always_trigger_callback=False),realtime=False)
126
self.add_options_group('Look', 'Settings colors and fonts')
128
self.add_option(ColorOption('Look','color_text',
129
(0, 0, 0, 0.6), 'Text color', '',callback=self.update))
131
self.add_option(ColorOption('Look','frame_color',
132
(1,1,1,0.8), 'Background Frame color', 'Frame color',callback=self.update))
134
self.add_option(FontOption('Look','font',
135
self.font_default, 'Text Font', '',callback=self.update))
137
self.add_option(IntOption('Look','border_size',
138
self.border_size_default, 'Size of the border','',
139
callback=self.update, always_trigger_callback=False))
142
self.add_option(ColorOption('Look','color_text_selected',
143
(0, 0, 0, 0.6), 'Text color selected', 'Color of the text when selected', callback=self.update))
145
self.add_option(ColorOption('Look','frame_color_selected',
146
(1,1,1,0.8), 'Background Frame color', 'Frame color for selected background', callback=self.update))
148
self.add_option(IntOption('Look','border_size_selected',
149
self.border_size_selected, 'Size of the border selected','',
150
callback=self.update, always_trigger_callback=False))
154
def __setattr__(self, name, value):
155
# call Screenlet.__setattr__ in baseclass (ESSENTIAL!!!!)
156
screenlets.Screenlet.__setattr__(self, name, value)
159
def get_style_color(self):
160
''' Get default color for background
163
style = gtk.Style().bg[gtk.STATE_NORMAL]
166
def populate_list(self, path):
167
''' Generate the list of GFile and GFileInfos
169
parent = gio.File(path)
170
list_files = [] #List of tuble of 3
171
self.files_list_show = []
173
for elem in os.listdir(path):
174
Gfile = gio.File(os.path.join(path,elem))
175
tuble = [Gfile, Gfile.query_info("standard::*"), []]
176
if not tuble[1].get_is_hidden():
177
list_files.append(tuble)
182
self.x_position = int(0)
183
self.y_position = int(0)
185
for elem in list_files:
186
#Update the position of the file
187
elem[2] = [self.x_position, self.y_position]
189
if self.x_position == self.icons_in_row:# If we are at the end of the row,
190
# jump to the next row
192
self.x_position = int(0)
193
self.y_position = int(self.y_position) + 1
196
self.x_position = int(self.x_position) + 1
198
for elem in list_files:
199
if elem[2][0] < self.icons_in_row:
200
if elem[2][1] < self.icons_in_column:
201
self.files_list_show.append(elem)
204
def generate_icon_names(self, tuble):
205
''' Generate a list of icons names from a [GFile, GFileInfo, [x,y]]
208
Gicon = info.get_icon()
209
self.icon_names = Gicon.get_names()
210
if self.check_for_icon(self.icon_names[0]):
211
return self.icon_names
213
return ['gtk-execute']
216
def generate_file_name(self, tuble):
217
''' Generate the name of a file from a (GFile, GFileInfo)
220
info = info.get_name()
223
def monitor_path(self, path):
224
''' Monitor the path for modified files/directory
226
current_file = gio.File(self.folder_path_current)
227
mon = current_file.monitor_directory()
228
mon.connect("changed", self.monitor_callback)
231
def monitor_callback(self, monitor, Gfile, event, data=None):
233
#self.show_notification("Changes !")
236
def click_callback(self):
237
''' Callback when click
240
for elem in self.files_list_show:
241
if elem[2] == self.cursor_position:
242
if os.path.isdir(elem[0].get_path()):
243
self.folder_path_current = elem[0].get_path()
245
else: xdg_open(elem[0].get_path())
247
def set_path_to_parent(self):
248
if self.folder_path_current is not bool:
249
self.folder_path_current = os.path.split(self.folder_path_current)[0]
252
def menuitem_callback(self, widget, id):
253
screenlets.Screenlet.menuitem_callback(self, widget, id)
254
if id == "up_folder":
255
self.set_path_to_parent()
258
def on_mouse_down(self, event):
259
"""Called when a buttonpress-event occured in Screenlet's window.
260
Returning True causes the event to be not further propagated."""
261
self.set_current_cursor(event)
262
self.click_callback()
266
def set_current_cursor(self, event):
267
self.cursor_position= [int(event.x / self.scale), int(event.y / self.scale)]
268
if self.cursor_position[1] < self.banner_size:
269
self.cursor_position = [-1,-1]
271
self.cursor_position = [int(self.cursor_position[0]) / int(self.icon_size * 2),
272
int(self.cursor_position[1]) / int(self.banner_size + int(self.icon_size*2))]
274
def update_path_from_settings(self):
275
self.folder_path_current = self.Path
276
self.monitor = self.monitor_path(self.folder_path_current)
280
def update_path(self):
281
''' Update path from settings
283
if self.folder_path_current is not bool:
284
self.populate_list(self.folder_path_current)
285
self.monitor = self.monitor_path(self.folder_path_current)
293
return True # keep on running this event
295
def on_mouse_enter (self, event):
299
def on_mouse_leave (self, event):
300
"""Called when the mouse leaves the Screenlet's window."""
301
self.cursor_position = [-1,-1]
304
def on_mouse_move(self, event):
305
"""Called when the mouse moves in the Screenlet's window."""
306
before_cursor = self.cursor_position
307
self.set_current_cursor(event)
308
if before_cursor <> self.cursor_position:
311
def get_large(self, situation):
312
return situation[2][0] * self.icon_size * 2
314
def get_long(self,situation):
315
return situation[2][1] * self.icon_size * 2 + self.banner_size
318
def on_draw(self, ctx):
319
self.width = self.icon_size * 2 * self.icons_in_row
320
self.height = self.icon_size * 2 * self.icons_in_column + self.banner_size
322
ctx.scale(self.scale, self.scale)
325
ctx.set_source_rgba(*self.frame_color)
326
self.draw_rectangle_advanced (ctx, 0, 0, self.width-10, self.banner_size,
327
rounded_angles=(5,5,5,5), fill=True, border_size=2, border_color=(0,0,0,0.5),
328
shadow_size=0, shadow_color=(0,0,0,0.5))
330
ctx.set_source_rgba(*self.color_text)
331
self.draw_text(ctx, self.folder_path_current, # ctx, texte
334
self.font.split(' ')[0], # font
335
self.banner_size * 0.3 , self.width-10 , # size, width
336
alignment=pango.ALIGN_CENTER, ellipsize=pango.ELLIPSIZE_END)
338
#Draw the main widget
339
ctx.set_source_rgba(*self.frame_color)
340
self.draw_rectangle_advanced (ctx, 0, self.banner_size, self.width-10, self.height-self.banner_size-10,
341
rounded_angles=(5,5,5,5), fill=True, border_size=self.border_size, border_color=(0,0,0,0.5),
342
shadow_size=0, shadow_color=(0,0,0,0.5))
345
self.longue_init = self.banner_size
348
self.large = self.large_init
349
self.longue = self.longue_init
351
for elem in self.files_list_show:
352
#Draw the selected rextancle
353
if elem[2] == self.cursor_position:
354
ctx.set_source_rgba(*self.frame_color_selected)
355
self.draw_rectangle_advanced(ctx, # ctx
356
self.get_large(elem) , # x
357
self.get_long(elem), # y
358
self.icon_size * 1.8, self.icon_size * 1.8, # width, height
359
rounded_angles=(5,5,5,5), fill=True,
360
border_size=self.border_size_selected, border_color=(0,0,0,0.5))
363
ctx.set_source_rgba(*self.frame_color)
364
self.draw_icon(ctx, # ctx
365
self.get_large(elem) + self.icon_size * 0.5 , # x
366
self.get_long(elem) + self.icon_size * 0.2, # y
367
self.generate_icon_names(elem)[0], # icon name
368
self.icon_size, self.icon_size) # width, height
371
ctx.set_source_rgba(*self.color_text)
372
self.draw_text(ctx, self.generate_file_name(elem), # ctx, texte
373
self.get_large(elem), # x
374
self.get_long(elem) + self.icon_size * 1.2, # y
375
self.font.split(' ')[0], # font
376
self.icon_size * 0.18, self.icon_size * 1.8 , # size, width
377
alignment=pango.ALIGN_CENTER, ellipsize=pango.ELLIPSIZE_END)
381
def on_draw_shape(self, ctx):
385
# If the program is run directly or passed as an argument to the python
386
# interpreter then create a Screenlet instance and show it
387
if __name__ == "__main__":
388
import screenlets.session
389
screenlets.session.create_session(FolderViewCloneScreenlet)