1 # This file is part of jack_mixer
3 # Copyright (C) 2006 Nedko Arnaudov <nedko@arnaudov.name>
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; version 2 of the License
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.
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
21 from gi
.repository
import Gtk
22 from gi
.repository
import Gdk
23 from gi
.repository
import GObject
26 log
= logging
.getLogger(__name__
)
29 class AdjustmentdBFS(Gtk
.Adjustment
):
30 def __init__(self
, scale
, default_db
, step_inc
):
31 self
.default_value
= scale
.db_to_scale(default_db
)
34 self
.step_increment
= step_inc
35 Gtk
.Adjustment
.__init
__(self
, self
.default_value
, 0.0, 1.0, 0.02)
36 self
.connect("value-changed", self
.on_value_changed
)
37 self
.disable_value_notify
= False
40 self
.set_value(self
.get_value() + self
.step_increment
)
43 self
.set_value(self
.get_value() - self
.step_increment
)
46 self
.set_value(self
.default_value
)
48 def get_value_db(self
):
51 def set_value_db(self
, db
, from_midi
= False):
53 self
.disable_value_notify
= True
54 self
.set_value(self
.scale
.db_to_scale(db
))
55 self
.disable_value_notify
= False
57 self
.emit("volume-changed")
59 self
.emit("volume-changed-from-midi")
61 def on_value_changed(self
, adjustment
):
62 if not self
.disable_value_notify
:
63 self
.db
= self
.scale
.scale_to_db(self
.get_value())
64 self
.emit("volume-changed")
66 def set_scale(self
, scale
):
68 self
.disable_value_notify
= True
69 self
.set_value(self
.scale
.db_to_scale(self
.db
))
70 self
.disable_value_notify
= False
72 GObject
.signal_new("volume-changed", AdjustmentdBFS
,
73 GObject
.SignalFlags
.RUN_FIRST | GObject
.SignalFlags
.ACTION
, None, [])
75 GObject
.signal_new("volume-changed-from-midi", AdjustmentdBFS
,
76 GObject
.SignalFlags
.RUN_FIRST | GObject
.SignalFlags
.ACTION
, None, [])
78 class BalanceAdjustment(Gtk
.Adjustment
):
80 Gtk
.Adjustment
.__init
__(self
, 0.0, -1.0, 1.0, 0.02)
81 self
.connect("value-changed", self
.on_value_changed
)
82 self
.disable_value_notify
= False
84 def set_balance(self
, value
, from_midi
= False):
85 self
.disable_value_notify
= True
87 self
.disable_value_notify
= False
89 self
.emit("balance-changed")
91 def on_value_changed(self
, adjustment
):
92 if not self
.disable_value_notify
:
93 self
.emit("balance-changed")
95 GObject
.signal_new("balance-changed", BalanceAdjustment
,
96 GObject
.SignalFlags
.RUN_FIRST | GObject
.SignalFlags
.ACTION
, None, [])
98 class GtkSlider(Gtk
.VScale
):
99 def __init__(self
, adjustment
):
100 Gtk
.VScale
.__init
__(self
)#, adjustment)
101 self
.adjustment
= adjustment
102 self
.set_adjustment(adjustment
)
103 self
.set_draw_value(False)
104 self
.set_inverted(True)
105 self
.button_down
= False
106 self
.button_down_y
= 0
107 self
.button_down_value
= 0
109 self
.connect('button-press-event', self
.button_press_event
)
110 self
.connect('button-release-event', self
.button_release_event
)
111 self
.connect("motion-notify-event", self
.motion_notify_event
)
112 self
.connect("scroll-event", self
.scroll_event
)
114 def button_press_event(self
, widget
, event
):
115 if not event
.state
& Gdk
.ModifierType
.CONTROL_MASK
and event
.button
== 1 and event
.type == Gdk
.EventType
.BUTTON_PRESS
:
116 self
.button_down
= True
117 self
.button_down_y
= event
.y
118 self
.button_down_value
= self
.adjustment
.get_value()
120 if not event
.state
& Gdk
.ModifierType
.CONTROL_MASK
and event
.button
== 1 and event
.type == Gdk
.EventType
._2BUTTON
_PRESS
:
121 self
.adjustment
.set_value(0)
123 if event
.state
& Gdk
.ModifierType
.CONTROL_MASK
and event
.button
== 1 and event
.type == Gdk
.EventType
.BUTTON_PRESS
:
124 self
.adjustment
.set_value(self
.adjustment
.scale
.db_to_scale(1))
128 def button_release_event(self
, widget
, event
):
129 self
.button_down
= False
132 def motion_notify_event(self
, widget
, event
):
133 slider_length
= widget
.get_allocation().height
- widget
.get_style_context().get_property('min-height', Gtk
.StateFlags
.NORMAL
)
135 delta_y
= (self
.button_down_y
- event
.y
) / slider_length
136 y
= self
.button_down_value
+ delta_y
141 self
.adjustment
.set_value(y
)
144 def scroll_event(self
, widget
, event
):
145 delta
= self
.adjustment
.step_increment
146 value
= self
.adjustment
.get_value()
147 if event
.direction
== Gdk
.ScrollDirection
.UP
:
149 elif event
.direction
== Gdk
.ScrollDirection
.DOWN
:
151 elif event
.direction
== Gdk
.ScrollDirection
.SMOOTH
:
152 y
= value
- event
.delta_y
* delta
158 self
.adjustment
.set_value(y
)
161 class CustomSliderWidget(Gtk
.DrawingArea
):
162 def __init__(self
, adjustment
):
163 Gtk
.DrawingArea
.__init
__(self
)
165 self
.adjustment
= adjustment
167 self
.connect("draw", self
.on_expose
)
168 self
.connect("size_allocate", self
.on_size_allocate
)
169 adjustment
.connect("value-changed", self
.on_value_changed
)
170 self
.connect("button-press-event", self
.on_mouse
)
171 self
.connect("motion-notify-event", self
.on_mouse
)
172 self
.connect("scroll-event", self
.on_scroll
)
173 self
.set_events(Gdk
.EventMask
.BUTTON1_MOTION_MASK |
174 Gdk
.EventMask
.SCROLL_MASK | Gdk
.EventMask
.BUTTON_PRESS_MASK
)
176 def on_scroll(self
, widget
, event
):
177 delta
= self
.adjustment
.step_increment
178 value
= self
.adjustment
.get_value()
179 if event
.direction
== Gdk
.ScrollDirection
.UP
:
181 elif event
.direction
== Gdk
.ScrollDirection
.DOWN
:
187 self
.adjustment
.set_value(y
)
190 def on_mouse(self
, widget
, event
):
191 if event
.type == Gdk
.EventType
.BUTTON_PRESS
:
192 log
.debug("Mouse button %u pressed %ux%u", event
.button
, event
.x
, event
.y
)
193 if event
.button
== 1:
194 if event
.y
>= self
.slider_rail_up
and event
.y
< self
.slider_rail_up
+ self
.slider_rail_height
:
195 self
.adjustment
.set_value(1 - float(event
.y
- self
.slider_rail_up
)/float(self
.slider_rail_height
))
196 elif event
.type == Gdk
.EventType
.MOTION_NOTIFY
:
197 log
.debug("Mouse motion %ux%u", event
.x
, event
.y
)
198 if event
.y
< self
.slider_rail_up
:
199 y
= self
.slider_rail_up
200 elif event
.y
> self
.slider_rail_up
+ self
.slider_rail_height
:
201 y
= self
.slider_rail_up
+ self
.slider_rail_height
204 self
.adjustment
.set_value(1 - float(y
- self
.slider_rail_up
)/float(self
.slider_rail_height
))
208 def on_value_changed(self
, adjustment
):
209 self
.invalidate_all()
211 def on_expose(self
, widget
, cairo_ctx
):
217 def get_preferred_width(self
, widget
):
218 minimal_width
= natural_width
= self
.width
219 return (minimal_width
, natural_width
)
221 def get_preferred_height(self
, widget
):
222 requisition
= Gtk
.Requisition()
223 on_size_request(self
, widget
, requisition
)
224 minimal_height
= natural_heigt
= requisition
.height
225 return (minimal_height
, natural_height
)
228 def on_size_allocate(self
, widget
, allocation
):
229 self
.width
= float(allocation
.width
)
230 self
.height
= float(allocation
.height
)
233 def on_size_request(self
, widget
, requisition
):
234 requisition
.width
= 20
237 def invalidate_all(self
):
238 if hasattr(self
, 'width') and hasattr(self
, 'height'):
239 self
.queue_draw_area(0, 0, int(self
.width
), int(self
.height
))
241 def draw(self
, cairo_ctx
):
243 state
= Gtk
.StateType
.PRELIGHT
245 state
= Gtk
.StateType
.NORMAL
247 #cairo_ctx.rectangle(0, 0, self.width, self.height)
248 #cairo_ctx.set_source_color(self.style.bg[state])
249 #cairo_ctx.fill_preserve()
250 #Gdk.cairo_set_source_color(cairo_ctx,
251 # self.get_style_context().get_color(state).to_color())
254 slider_knob_width
= 37.5 if self
.width
* 3 / 4 > 37.5 else self
.width
* 3 / 4
255 slider_knob_height
= slider_knob_width
* 2
256 slider_knob_height
-= slider_knob_height
% 2
257 slider_knob_height
+= 1
259 slider_x
= self
.width
/2
261 cairo_ctx
.set_line_width(1)
264 Gdk
.cairo_set_source_color(cairo_ctx
,
265 self
.get_style_context().get_color(state
).to_color())
266 self
.slider_rail_up
= slider_knob_height
/2 + (self
.width
- slider_knob_width
)/2
267 self
.slider_rail_height
= self
.height
- 2 * self
.slider_rail_up
268 cairo_ctx
.move_to(slider_x
, self
.slider_rail_up
)
269 cairo_ctx
.line_to(slider_x
, self
.slider_rail_height
+ self
.slider_rail_up
)
273 slider_y
= round(self
.slider_rail_up
+ self
.slider_rail_height
* (1 - self
.adjustment
.get_value()))
274 lg
= cairo
.LinearGradient(slider_x
-
275 float(slider_knob_width
)/2, slider_y
- slider_knob_height
/2,
276 slider_x
- float(slider_knob_width
)/2, slider_y
+
277 slider_knob_height
/2)
279 lg
.add_color_stop_rgba(0, 0.55, 0.55, 0.55, slider_alpha
)
280 lg
.add_color_stop_rgba(0.1, 0.65, 0.65, 0.65, slider_alpha
)
281 lg
.add_color_stop_rgba(0.1, 0.75, 0.75, 0.75, slider_alpha
)
282 lg
.add_color_stop_rgba(0.125, 0.75, 0.75, 0.75, slider_alpha
)
283 lg
.add_color_stop_rgba(0.125, 0.15, 0.15, 0.15, slider_alpha
)
284 lg
.add_color_stop_rgba(0.475, 0.35, 0.35, 0.35, slider_alpha
)
285 lg
.add_color_stop_rgba(0.475, 0, 0, 0, slider_alpha
)
286 lg
.add_color_stop_rgba(0.525, 0, 0, 0, slider_alpha
)
287 lg
.add_color_stop_rgba(0.525, 0.35, 0.35, 0.35, slider_alpha
)
288 lg
.add_color_stop_rgba(0.875, 0.65, 0.65, 0.65, slider_alpha
)
289 lg
.add_color_stop_rgba(0.875, 0.75, 0.75, 0.75, slider_alpha
)
290 lg
.add_color_stop_rgba(0.900, 0.75, 0.75, 0.75, slider_alpha
)
291 lg
.add_color_stop_rgba(0.900, 0.15, 0.15, 0.15, slider_alpha
)
292 lg
.add_color_stop_rgba(1.000, 0.10, 0.10, 0.10, slider_alpha
)
293 cairo_ctx
.rectangle(slider_x
- float(slider_knob_width
)/2,
294 slider_y
- slider_knob_height
/2,
295 float(slider_knob_width
),
297 Gdk
.cairo_set_source_color(cairo_ctx
,
298 self
.get_style_context().get_background_color(state
).to_color())
299 cairo_ctx
.fill_preserve()
300 cairo_ctx
.set_source(lg
)