~qioeujqioejqioe-deactivatedaccount/exaile/missing-signals

« back to all changes in this revision

Viewing changes to plugins/minimode.py

  • Committer: Adam Olsen
  • Date: 2007-08-31 19:36:41 UTC
  • Revision ID: arolsen@gmail.com-20070831193641-isghtp1fq2433m2m
Moving the plugins directory into the source directory

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#!/usr/bin/env python
 
2
# Copyright (C) 2006 Adam Olsen <arolsen@gmail.com>
 
3
#
 
4
# This program is free software; you can redistribute it and/or modify
 
5
# it under the terms of the GNU General Public License as published by
 
6
# the Free Software Foundation; either version 2 of the License, or
 
7
# (at your option) any later version.
 
8
#
 
9
# This program is distributed in the hope that it will be useful,
 
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
12
# GNU General Public License for more details.
 
13
#
 
14
# You should have received a copy of the GNU General Public License along
 
15
# with this program; if not, write to the Free Software Foundation, Inc.,
 
16
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 
17
 
 
18
import gtk, gobject, pango
 
19
from xl import xlmisc
 
20
import xl.plugins as plugins
 
21
 
 
22
PLUGIN_NAME = "Mini Mode"
 
23
PLUGIN_AUTHORS = ['Adam Olsen <arolsen@gmail.com>']
 
24
PLUGIN_VERSION = '0.4.4'
 
25
PLUGIN_DESCRIPTION = r"""Super groovy mini mode window!\n\nMini Mode is activated
 
26
by pressing CTRL+ALT+M\n\nYou can move the window in most cases by
 
27
ALT+drag"""
 
28
PLUGIN_ENABLED = False
 
29
PLUGIN_ICON = None
 
30
 
 
31
PLUGIN = None
 
32
MENU_ITEM = None
 
33
ACCEL_GROUP = None
 
34
MM_ACTIVE = False
 
35
 
 
36
CONS = plugins.SignalContainer()
 
37
 
 
38
def toggle_minimode(*e):
 
39
    """
 
40
        Toggles Minimode
 
41
    """
 
42
    global MM_ACTIVE 
 
43
    if not PLUGIN.get_property("visible"):
 
44
        PLUGIN.show_window()
 
45
        APP.window.hide()
 
46
        MM_ACTIVE = True
 
47
    else:
 
48
        PLUGIN.hide()
 
49
        MM_ACTIVE = False
 
50
        APP.window.show()
 
51
    print "Minimode toggled"
 
52
 
 
53
def configure():
 
54
    """
 
55
        Configuration for mini mode
 
56
    """
 
57
    exaile = APP
 
58
    settings = exaile.settings
 
59
 
 
60
    dialog = plugins.PluginConfigDialog(exaile.window, PLUGIN_NAME)
 
61
    box = dialog.main
 
62
 
 
63
    on_top = settings.get_boolean('on_top', plugin=plugins.name(__file__), default=False)
 
64
    no_taskbar = settings.get_boolean('no_taskbar',
 
65
        plugin=plugins.name(__file__), default=False)
 
66
    decoration = settings.get_boolean('decoration',
 
67
        plugin=plugins.name(__file__), default=False)
 
68
 
 
69
    on_top_box = gtk.CheckButton('Always on top')
 
70
    no_taskbar_box = gtk.CheckButton('Skip taskbar')
 
71
    decoration_box = gtk.CheckButton('Window decoration')
 
72
 
 
73
    on_top_box.set_active(on_top)
 
74
    no_taskbar_box.set_active(no_taskbar)
 
75
    decoration_box.set_active(decoration)
 
76
 
 
77
    box.pack_start(on_top_box)
 
78
    box.pack_start(no_taskbar_box)
 
79
    box.pack_start(decoration_box)
 
80
    dialog.show_all()
 
81
 
 
82
    result = dialog.run()
 
83
    dialog.hide()
 
84
 
 
85
    settings.set_boolean('on_top', on_top_box.get_active(), plugin=plugins.name(__file__))
 
86
    settings.set_boolean('no_taskbar', no_taskbar_box.get_active(), plugin=plugins.name(__file__))
 
87
    settings.set_boolean('decoration', decoration_box.get_active(), plugin=plugins.name(__file__))
 
88
 
 
89
class MiniWindow(gtk.Window):
 
90
    """
 
91
        The main minimode window
 
92
    """
 
93
    def __init__(self):
 
94
        """
 
95
            Initializes the minimode window
 
96
        """
 
97
        gtk.Window.__init__(self)
 
98
 
 
99
        self.set_title("Exaile")
 
100
        self.set_icon(APP.window.get_icon())
 
101
        self.tips = gtk.Tooltips()
 
102
        self.seek_id = None
 
103
        self.seeking = False
 
104
 
 
105
        main = gtk.VBox()
 
106
        main.set_border_width(3)
 
107
        self.tlabel = gtk.Label("")
 
108
        self.tlabel.set_size_request(120, 10)
 
109
        self.tlabel.set_alignment(0.0, 0.5)
 
110
 
 
111
        bbox = gtk.HBox()
 
112
        bbox.set_spacing(3)
 
113
 
 
114
        prev = self.create_button('gtk-media-previous', self.on_prev,
 
115
            'Previous')
 
116
        bbox.pack_start(prev, False)
 
117
 
 
118
        self.play = self.create_button('gtk-media-play', self.on_play,
 
119
            'Play/Pause')
 
120
        bbox.pack_start(self.play, False)
 
121
 
 
122
        self.next = self.create_button('gtk-media-next', self.on_next, 'Next')
 
123
        bbox.pack_start(self.next)
 
124
 
 
125
        self.model = gtk.ListStore(str, object)
 
126
        self.title_box = gtk.ComboBox(self.model)
 
127
        cell = gtk.CellRendererText()
 
128
        cell.set_property('font-desc', pango.FontDescription('Normal 8'))
 
129
        cell.set_property('ellipsize', pango.ELLIPSIZE_END)
 
130
    
 
131
        self.title_box.pack_start(cell, True)
 
132
        self.title_box.set_size_request(170, 26)
 
133
        self.title_box.add_attribute(cell, 'text', 0)
 
134
        self.title_id = \
 
135
            self.title_box.connect('changed', self.change_track)
 
136
        bbox.pack_start(self.title_box, False)
 
137
 
 
138
        self.seeker = gtk.HScale(gtk.Adjustment(0, 0, 100, 1, 5, 0))
 
139
        self.seeker.set_draw_value(False)
 
140
        self.seeker.set_size_request(150, -1)
 
141
        self.seeker_id = self.seeker.connect('change-value', self.seek)
 
142
        bbox.pack_start(self.seeker, False)
 
143
 
 
144
        self.pos_label = gtk.Label("0:00")
 
145
        self.pos_label.set_size_request(40, -1)
 
146
        self.pos_label.set_alignment(0.0, .5)
 
147
        bbox.pack_start(self.pos_label)
 
148
 
 
149
        mm = self.create_button('gtk-fullscreen', toggle_minimode, 'Restore'
 
150
            ' Regular View')
 
151
        bbox.pack_start(mm, False)
 
152
 
 
153
        main.pack_start(bbox)
 
154
 
 
155
        self.add(main)
 
156
 
 
157
        self.connect('configure-event', self.on_move)
 
158
        self.first = False
 
159
 
 
160
    def seek(self, range, scroll, value): 
 
161
        """
 
162
            Seeks in the current track
 
163
        """
 
164
 
 
165
        if self.seek_id:
 
166
            gobject.source_remove(self.seek_id)
 
167
            self.seeking = False
 
168
            self.seek_id = None
 
169
 
 
170
        self.seek_id = gobject.timeout_add(250, self._seek_cb, range)
 
171
        self.seeking = True
 
172
 
 
173
    def _seek_cb(self, range):
 
174
 
 
175
        duration = APP.player.current.duration
 
176
        real = long(range.get_value() * duration / 100)
 
177
        APP.player.seek(real)
 
178
        APP.player.current.submitted = True
 
179
        APP.emit('seek', real)
 
180
        self.seeking = False
 
181
 
 
182
    def change_track(self, combo):
 
183
        """
 
184
            Called when the user uses the title combo to pick a new song
 
185
        """
 
186
        iter = self.title_box.get_active_iter()
 
187
        if iter:
 
188
            song = self.model.get_value(iter, 1)
 
189
            APP.stop()
 
190
            APP.player.play_track(song)
 
191
 
 
192
    def setup_title_box(self):
 
193
        """
 
194
            Populates the title box and selects the currently playing track
 
195
 
 
196
            The combobox will be populated with all the tracks in the current
 
197
            playlist, UNLESS there are more than 50 songs in the playlist.  In
 
198
            that case, only the current song and the next 50 upcoming tracks
 
199
            are displayed.
 
200
        """
 
201
        blank = gtk.ListStore(str, object)
 
202
        self.title_box.set_model(blank)
 
203
        self.model.clear()
 
204
        count = 0; select = -1
 
205
        current = APP.player.current
 
206
        if current:
 
207
            select = 0
 
208
        elif APP.songs:
 
209
            select = -1
 
210
            current = APP.songs[0] 
 
211
 
 
212
        # if there are more than 50 songs in the current playlist, then only
 
213
        # display the next 50 tracks
 
214
        if len(APP.songs) > 50:
 
215
            if current:  
 
216
                count += 1
 
217
                self.model.append([current.title, current])
 
218
 
 
219
            next = current
 
220
 
 
221
            while True:
 
222
                next = APP.tracks.get_next_track(next)
 
223
                if not next: break
 
224
                self.model.append([next.title, next])
 
225
                count += 1
 
226
                if count >= 50: break
 
227
 
 
228
        # otherwise, display all songs in the current playlist
 
229
        else:
 
230
            for song in APP.songs:
 
231
                if song == current and APP.player.current:
 
232
                    select = count
 
233
                self.model.append([song.title, song])
 
234
                count += 1
 
235
 
 
236
        self.title_box.set_model(self.model)
 
237
        self.title_box.disconnect(self.title_id)
 
238
        if select > -1: self.title_box.set_active(select)
 
239
        self.title_id = self.title_box.connect('changed',
 
240
            self.change_track)
 
241
        self.title_box.set_sensitive(len(self.model) > 0)
 
242
 
 
243
    def on_move(self, *e):
 
244
        """
 
245
            Saves the position of the minimode window if it is moved
 
246
        """
 
247
        (x, y) = self.get_position()
 
248
        settings = APP.settings
 
249
        settings.set_int('x', x, plugin=plugins.name(__file__))
 
250
        settings.set_int('y', y, plugin=plugins.name(__file__))
 
251
 
 
252
    def show_window(self):
 
253
        """
 
254
            Gets the last position from the settings, and then
 
255
            displays the mimimode window
 
256
        """
 
257
 
 
258
        if not self.first:
 
259
            self.first = True
 
260
            self.show_all()
 
261
        else:
 
262
            self.show()
 
263
 
 
264
        settings = APP.settings
 
265
        x = settings.get_int("x", plugin=plugins.name(__file__),   
 
266
            default=10)
 
267
        y = settings.get_int("y", plugin=plugins.name(__file__),
 
268
            default=10)
 
269
        self.move(x, y)
 
270
        self.setup_title_box()
 
271
        self.stick()
 
272
 
 
273
        if APP.settings.get_boolean('on_top', plugin=plugins.name(__file__),
 
274
            default=False):
 
275
            self.set_keep_above(True)
 
276
        else:
 
277
            self.set_keep_above(False)
 
278
 
 
279
        if APP.settings.get_boolean('no_taskbar',
 
280
            plugin=plugins.name(__file__), default=False):
 
281
            self.set_property('skip-taskbar-hint', True)
 
282
        else:
 
283
            self.set_property('skip-taskbar-hint', False)
 
284
 
 
285
        if APP.settings.get_boolean('decoration',
 
286
            plugin=plugins.name(__file__), default=False):
 
287
            self.set_decorated(True)
 
288
        else:
 
289
            self.set_decorated(False)
 
290
 
 
291
    def on_prev(self, button):
 
292
        """
 
293
            Called when the user presses the previous button
 
294
        """
 
295
 
 
296
        APP.player.previous()
 
297
        self.timeout_cb()
 
298
 
 
299
    def on_play(self, button):
 
300
        """
 
301
            Called when the user clicks the play button
 
302
        """
 
303
 
 
304
        APP.player.toggle_pause()
 
305
        self.timeout_cb()
 
306
 
 
307
    def on_stop(self, button=None):
 
308
        """
 
309
            Called when the user clicks the stop button
 
310
        """
 
311
 
 
312
        if button: APP.player.stop(True)
 
313
        self.timeout_cb()
 
314
        self.play.set_image(APP.get_play_image(gtk.ICON_SIZE_MENU))
 
315
        self.setup_title_box()
 
316
        self.set_title(APP.window.get_title())
 
317
 
 
318
    def on_next(self, button):
 
319
        """ 
 
320
            Called when the user clicks the next button
 
321
        """
 
322
        
 
323
        APP.player.next()
 
324
        self.timeout_cb()
 
325
 
 
326
    def create_button(self, stock_id, func, tip):
 
327
        """
 
328
            Creates a little button
 
329
        """
 
330
        button = gtk.Button()
 
331
        button.connect('clicked', func)
 
332
        image = gtk.Image()
 
333
        image.set_from_stock(stock_id, gtk.ICON_SIZE_MENU)
 
334
        button.set_image(image)
 
335
        button.set_size_request(26, 26)
 
336
        self.tips.set_tip(button, tip)
 
337
 
 
338
        return button
 
339
 
 
340
    def pause_toggled(self):
 
341
        """
 
342
            Called when pause is toggled
 
343
        """
 
344
 
 
345
        track = APP.player.current
 
346
        if not track:
 
347
            self.play.set_image(APP.get_play_image(gtk.ICON_SIZE_MENU))
 
348
        else:
 
349
            if APP.player.is_paused():
 
350
                self.play.set_image(APP.get_play_image(gtk.ICON_SIZE_MENU))
 
351
            else:
 
352
                self.play.set_image(APP.get_pause_image(gtk.ICON_SIZE_MENU))
 
353
        self.set_title(APP.window.get_title())
 
354
 
 
355
    def timeout_cb(self):
 
356
        text = APP.new_progressbar.get_text()
 
357
        b = text.find(' /')
 
358
        if b > -1:
 
359
            text = text[:b]
 
360
        self.pos_label.set_label(text)
 
361
        self.seeker.set_value(APP.new_progressbar.get_fraction() * 100)
 
362
            
 
363
        return True
 
364
 
 
365
def pause_toggled(exaile, track):
 
366
    PLUGIN.pause_toggled()
 
367
 
 
368
def play_track(exaile, track):
 
369
    PLUGIN.pause_toggled()
 
370
    PLUGIN.setup_title_box()
 
371
 
 
372
def stop_track(exaile, track):
 
373
    PLUGIN.on_stop()
 
374
 
 
375
def toggle_hide(*args):
 
376
    if not MM_ACTIVE: return False
 
377
 
 
378
    if PLUGIN.get_property("visible"):
 
379
        PLUGIN.hide()
 
380
    else: PLUGIN.show_window()
 
381
 
 
382
    return True
 
383
 
 
384
def tray_toggled(app, enabled):
 
385
    if enabled:
 
386
        CONS.connect(app.tray_icon, 'toggle-hide', toggle_hide)
 
387
    else:
 
388
        CONS.disconnect_object(app.tray_icon)
 
389
 
 
390
def pass_func(*args):
 
391
    global MM_ACTIVE 
 
392
    if PLUGIN.get_property("visible"):
 
393
        PLUGIN.hide()
 
394
        MM_ACTIVE = False
 
395
        APP.window.show()
 
396
        return True
 
397
 
 
398
def initialize():
 
399
    global TIMER_ID, PLUGIN, ACCEL_GROUP, MENU_ITEM
 
400
 
 
401
    PLUGIN = MiniWindow()
 
402
    TIMER_ID = gobject.timeout_add(1000, PLUGIN.timeout_cb)
 
403
    ACCEL_GROUP = gtk.AccelGroup()
 
404
    key, mod = gtk.accelerator_parse("<Control><Alt>M")
 
405
    ACCEL_GROUP.connect_group(key, mod, gtk.ACCEL_VISIBLE, pass_func)
 
406
 
 
407
    APP.window.add_accel_group(ACCEL_GROUP)
 
408
    MENU_ITEM = gtk.MenuItem("Mini Mode")
 
409
    MENU_ITEM.connect('activate', toggle_minimode)
 
410
    MENU_ITEM.add_accelerator('activate', ACCEL_GROUP, key, mod,
 
411
        gtk.ACCEL_VISIBLE)
 
412
    APP.view_menu.get_submenu().append(MENU_ITEM)
 
413
    MENU_ITEM.show()
 
414
    PLUGIN.add_accel_group(ACCEL_GROUP)
 
415
    CONS.connect(APP.player, 'play-track', play_track)
 
416
    CONS.connect(APP.player, 'stop-track', stop_track)
 
417
    CONS.connect(APP.player, 'pause-toggled', pause_toggled)
 
418
 
 
419
    if APP.tray_icon:
 
420
        CONS.connect(APP.tray_icon, 'toggle-hide', toggle_hide)
 
421
    CONS.connect(APP, 'tray-icon-toggled', tray_toggled)
 
422
    return True
 
423
 
 
424
def destroy():
 
425
    global PLUGIN, MENU_ITEM, ACCEL_GROUP, MENU_ITEM, TIMER_ID
 
426
 
 
427
    CONS.disconnect_all()
 
428
 
 
429
    if TIMER_ID:
 
430
        gobject.source_remove(TIMER_ID)
 
431
        TIMER_ID = None
 
432
 
 
433
    if PLUGIN:
 
434
        PLUGIN.destroy()
 
435
        PLUGIN = None
 
436
 
 
437
    if MENU_ITEM:
 
438
        APP.view_menu.get_submenu().remove(MENU_ITEM)
 
439
        MENU_ITEM = None
 
440
        
 
441
    if ACCEL_GROUP: 
 
442
        APP.window.remove_accel_group(ACCEL_GROUP)
 
443
        ACCEL_GROUP = None