1# Copyright (C) 2012-13 Nick Boultbee, Thomas Vogt
2# Copyright (C) 2008 Andreas Bombe
3# Copyright (C) 2005  Michael Urman
4# Based on osd.py (C) 2005 Ton van den Heuvel, Joe Wreshnig
5#                 (C) 2004 Gustavo J. A. M. Carneiro
6#
7# This program is free software; you can redistribute it and/or modify
8# it under the terms of the GNU General Public License as published by
9# the Free Software Foundation; either version 2 of the License, or
10# (at your option) any later version.
11
12from gi.repository import Gtk, Gdk
13
14from quodlibet import _
15from quodlibet import app
16from quodlibet import qltk
17from quodlibet.util import connect_obj
18from quodlibet.formats import DUMMY_SONG
19from quodlibet.qltk.textedit import PatternEdit
20from quodlibet.qltk import Icons
21
22
23class ConfigLabel(Gtk.Label):
24    """Customised Label for configuration, tied to a widget"""
25
26    def __init__(self, text, widget):
27        super(Gtk.Label, self).__init__(label=text, use_underline=True)
28        self.set_mnemonic_widget(widget)
29        self.set_alignment(0.0, 0.5)
30
31
32class AnimOsdPrefs(Gtk.VBox):
33
34    def __init__(self, plugin):
35        super(AnimOsdPrefs, self).__init__(spacing=6)
36
37        self.Conf = plugin.Conf
38        self.plugin = plugin
39
40        def __coltofloat(x):
41            return x / 65535.0
42
43        def __floattocol(x):
44            return int(x * 65535)
45
46        def show_preview():
47            preview_song = (app.player.song if app.player.song else DUMMY_SONG)
48            self.plugin.plugin_on_song_started(preview_song)
49
50        def on_button_pressed(x=None, y=None):
51            show_preview()
52
53        def set_text(button):
54            color = button.get_color()
55            color = map(__coltofloat,
56                        (color.red, color.green, color.blue, 0.0))
57            self.Conf.text = tuple(color)
58            show_preview()
59
60        def set_fill(button):
61            color = button.get_color()
62            color = map(__coltofloat, (color.red, color.green, color.blue,
63                button.get_alpha()))
64            self.Conf.fill = tuple(color)
65            show_preview()
66
67        def set_font(button):
68            font = button.get_font_name()
69            self.Conf.font = font
70            show_preview()
71
72        def change_delay(button):
73            value = int(button.get_value() * 1000)
74            self.Conf.delay = value
75
76        def change_monitor(button):
77            """Monitor number config change handler"""
78            value = int(button.get_value())
79            self.Conf.monitor = value
80            show_preview()
81
82        def change_position(button, x, y):
83            self.Conf.pos_x = x / 2.0
84            self.Conf.pos_y = y / 2.0
85            show_preview()
86
87        def change_align(button):
88            value = button.get_active()
89            self.Conf.align = value
90            show_preview()
91
92        def change_shadow(button):
93            if button.get_active():
94                self.Conf.shadow = (0.0, 0.0, 0.0, self.Conf.fill[3])
95            else:
96                self.Conf.shadow = (-1.0, 0.0, 0.0, 0.0)
97            show_preview()
98
99        def change_outline(button):
100            if button.get_active():
101                # Vary with fill alpha to create a smoother outline edge
102                alpha = (min(1.0, self.Conf.fill[3] * 1.25))
103                self.Conf.outline = (0.1, 0.1, 0.1, alpha)
104            else:
105                self.Conf.outline = (-1.0, 0.0, 0.0)
106            show_preview()
107
108        def change_rounded(button):
109            if button.get_active():
110                self.Conf.corners = 1
111            else:
112                self.Conf.corners = 0
113            show_preview()
114
115        def change_coversize(button):
116            value = int(button.get_value())
117            self.Conf.coversize = value
118            show_preview()
119
120        def edit_pattern(button):
121            w = PatternEdit(button, self.Conf.string)
122            w.set_default_size(520, 260)
123            w.text = self.Conf.string
124            connect_obj(w.apply, 'clicked', set_string, w)
125            w.show()
126
127        def set_string(window):
128            value = window.text
129            self.Conf.string = value
130            show_preview()
131
132        def build_display_widget():
133            vb2 = Gtk.VBox(spacing=3)
134            hb = Gtk.HBox(spacing=6)
135            # Set monitor to display OSD on if there's more than one
136            monitor_cnt = Gdk.Screen.get_default().get_n_monitors()
137            if monitor_cnt > 1:
138                adj = Gtk.Adjustment(value=self.Conf.monitor, lower=0,
139                                     upper=monitor_cnt - 1, step_increment=1)
140                monitor = Gtk.SpinButton(adjustment=adj)
141                monitor.set_numeric(True)
142                monitor.connect('value-changed', change_monitor)
143                l2 = ConfigLabel("_Monitor:", monitor)
144                hb.pack_start(l2, False, True, 0)
145                hb.pack_start(monitor, False, True, 0)
146                vb2.pack_start(hb, True, True, 0)
147            else:
148                # should be this by default anyway
149                self.Conf.monitor = 0
150
151            hb = Gtk.HBox(spacing=6)
152            grid = Gtk.Grid(column_homogeneous=True,
153                            row_homogeneous=True,
154                            row_spacing=4,
155                            column_spacing=4)
156            arrows = [['↖', '↑', '↗'],
157                      ['←', '○', '→'],
158                      ['↙', '↓', '↘ ']]
159
160            group = None
161            for x in range(3):
162                for y in range(3):
163                    rb = Gtk.RadioButton(group=group, label=arrows[y][x])
164                    if (int(self.Conf.pos_x * 2.0) == x and
165                            int(self.Conf.pos_y * 2.0) == y):
166                        rb.set_active(True)
167                    grid.attach(rb, x, y, 1, 1)
168                    group = rb
169
170            # Connect to signal after the correct radio button has been
171            # selected
172            for x in range(3):
173                for y in range(3):
174                    rb = grid.get_child_at(x, y)
175                    rb.connect('toggled', change_position, x, y)
176
177            lbl = ConfigLabel(_("_Position:"), grid)
178            hb.pack_start(lbl, False, True, 0)
179            hb.pack_start(grid, False, True, 0)
180            vb2.pack_start(hb, False, True, 6)
181
182            hb = Gtk.HBox(spacing=6)
183            coversize = Gtk.SpinButton(
184                adjustment=Gtk.Adjustment.new(
185                    self.Conf.coversize, 1, 600, 1, 10, 0),
186                climb_rate=1, digits=0)
187            coversize.set_numeric(True)
188            coversize.connect('value-changed', change_coversize)
189            l1 = ConfigLabel(_("_Cover size:"), coversize)
190            hb.pack_start(l1, False, True, 0)
191            hb.pack_start(coversize, False, True, 0)
192            vb2.pack_start(hb, False, True, 0)
193            return vb2
194
195        frame = qltk.Frame(label=_("Display"), child=build_display_widget())
196        frame.set_border_width(6)
197        self.pack_start(frame, False, True, 0)
198
199        def build_text_widget():
200            t = Gtk.Table(n_rows=2, n_columns=2)
201            t.props.expand = False
202            t.set_col_spacings(6)
203            t.set_row_spacings(3)
204
205            font = Gtk.FontButton(show_style=True)
206            font.set_font_name(self.Conf.font)
207            font.connect('font-set', set_font)
208            lbl = ConfigLabel(_("_Font:"), font)
209            t.attach(lbl, 0, 1, 0, 1, xoptions=Gtk.AttachOptions.FILL)
210            t.attach(font, 1, 2, 0, 1)
211
212            align = Gtk.ComboBoxText()
213            align.append_text(_("Left"))
214            align.append_text(_("Center"))
215            align.append_text(_("Right"))
216            align.set_active(self.Conf.align)
217            align.connect('changed', change_align)
218            lbl = ConfigLabel(_("_Align text:"), align)
219
220            t.attach(lbl, 0, 1, 1, 2, xoptions=Gtk.AttachOptions.FILL)
221            t.attach(align, 1, 2, 1, 2)
222            return t
223
224        frame = qltk.Frame(label=_("Text"), child=build_text_widget())
225        frame.set_border_width(6)
226        self.pack_start(frame, False, True, 0)
227
228        def build_colors_widget():
229            t = Gtk.Table(n_rows=2, n_columns=2)
230            t.props.expand = False
231            t.set_col_spacings(6)
232            t.set_row_spacings(3)
233            b = Gtk.ColorButton(
234                rgba=Gdk.RGBA(*map(__floattocol, self.Conf.text)))
235            l = ConfigLabel(_("_Text:"), b)
236
237            t.attach(l, 0, 1, 0, 1, xoptions=Gtk.AttachOptions.FILL)
238            t.attach(b, 1, 2, 0, 1)
239            b.connect('color-set', set_text)
240            b = Gtk.ColorButton(color=Gdk.Color(*map(__floattocol,
241                                self.Conf.fill[0:3])))
242            b.set_use_alpha(True)
243            b.set_alpha(__floattocol(self.Conf.fill[3]))
244            b.connect('color-set', set_fill)
245            l = ConfigLabel(_("_Fill:"), b)
246            t.attach(l, 0, 1, 1, 2, xoptions=Gtk.AttachOptions.FILL)
247            t.attach(b, 1, 2, 1, 2)
248            return t
249
250        f = qltk.Frame(label=_("Colors"), child=build_colors_widget())
251        f.set_border_width(6)
252        self.pack_start(f, False, False, 0)
253
254        def build_effects_widget():
255            vb2 = Gtk.VBox(spacing=3)
256            hb = Gtk.HBox(spacing=6)
257            toggles = [
258                (_("_Shadows"), self.Conf.shadow[0], change_shadow),
259                (_("_Outline"), self.Conf.outline[0], change_outline),
260                (_("Rou_nded Corners"), self.Conf.corners - 1, change_rounded)]
261
262            for (label, current, callback) in toggles:
263                checkb = Gtk.CheckButton(label=label, use_underline=True)
264                checkb.set_active(current != -1)
265                checkb.connect("toggled", callback)
266                hb.pack_start(checkb, True, True, 0)
267            vb2.pack_start(hb, True, True, 0)
268
269            hb = Gtk.HBox(spacing=6)
270            timeout = Gtk.SpinButton(
271                adjustment=Gtk.Adjustment.new(
272                    self.Conf.delay / 1000.0, 0, 60, 0.1, 1.0, 0),
273                climb_rate=0.1, digits=1)
274            timeout.set_numeric(True)
275            timeout.connect('value-changed', change_delay)
276            l1 = ConfigLabel(_("_Delay:"), timeout)
277            hb.pack_start(l1, False, True, 0)
278            hb.pack_start(timeout, False, True, 0)
279            vb2.pack_start(hb, False, True, 0)
280            return vb2
281
282        frame = qltk.Frame(label=_("Effects"), child=build_effects_widget())
283        frame.set_border_width(6)
284        self.pack_start(frame, False, True, 0)
285
286        def build_buttons_widget():
287            hb = Gtk.HBox(spacing=6)
288            edit_button = qltk.Button(_(u"Ed_it Display Pattern…"),
289                                      Icons.EDIT)
290            edit_button.connect('clicked', edit_pattern)
291            hb.pack_start(edit_button, False, True, 0)
292            preview_button = Gtk.Button(label=_("Preview"))
293            preview_button.connect("button-press-event", on_button_pressed)
294            hb.pack_start(preview_button, False, True, 0)
295            return hb
296
297        self.pack_start(build_buttons_widget(), False, True, 0)
298