pnmixer-rust/src/ui_prefs_dialog.rs

412 lines
15 KiB
Rust
Raw Normal View History

2017-07-02 16:11:56 +00:00
use app_state::*;
2017-07-07 20:10:45 +00:00
use audio::{AudioUser, AudioSignal};
2017-07-08 00:38:49 +00:00
use errors::*;
2017-07-07 10:03:53 +00:00
use gdk;
use gtk::ResponseType;
2017-07-02 16:11:56 +00:00
use gtk::prelude::*;
use gtk;
2017-07-07 10:03:53 +00:00
use prefs::*;
2017-07-04 19:15:11 +00:00
use std::rc::Rc;
use support_alsa::*;
2017-07-08 00:38:49 +00:00
use support_audio::*;
2017-07-04 19:15:11 +00:00
2017-07-02 16:11:56 +00:00
2017-07-08 00:38:49 +00:00
// TODO: reference count leak
2017-07-06 14:53:19 +00:00
2017-07-07 10:03:53 +00:00
pub struct PrefsDialog {
_cant_construct: (),
2017-07-08 00:38:49 +00:00
prefs_dialog: gtk::Dialog,
2017-07-10 19:07:59 +00:00
notebook: gtk::Notebook,
2017-07-07 10:03:53 +00:00
/* DevicePrefs */
2017-07-08 00:38:49 +00:00
card_combo: gtk::ComboBoxText,
chan_combo: gtk::ComboBoxText,
2017-07-07 10:03:53 +00:00
/* ViewPrefs */
2017-07-08 00:38:49 +00:00
vol_meter_draw_check: gtk::CheckButton,
vol_meter_pos_spin: gtk::SpinButton,
vol_meter_color_button: gtk::ColorButton,
system_theme: gtk::CheckButton,
2017-07-07 10:03:53 +00:00
/* BehaviorPrefs */
2017-07-08 00:38:49 +00:00
vol_control_entry: gtk::Entry,
scroll_step_spin: gtk::SpinButton,
2017-07-08 22:14:49 +00:00
fine_scroll_step_spin: gtk::SpinButton,
2017-07-08 00:38:49 +00:00
middle_click_combo: gtk::ComboBoxText,
custom_entry: gtk::Entry,
2017-07-07 10:03:53 +00:00
/* NotifyPrefs */
2017-07-10 19:07:59 +00:00
#[cfg(feature = "notify")]
2017-07-08 00:38:49 +00:00
noti_enable_check: gtk::CheckButton,
2017-07-10 19:07:59 +00:00
#[cfg(feature = "notify")]
2017-07-08 00:38:49 +00:00
noti_timeout_spin: gtk::SpinButton,
2017-07-07 10:03:53 +00:00
// pub noti_hotkey_check: gtk::CheckButton,
2017-07-10 19:07:59 +00:00
#[cfg(feature = "notify")]
2017-07-08 00:38:49 +00:00
noti_mouse_check: gtk::CheckButton,
2017-07-10 19:07:59 +00:00
#[cfg(feature = "notify")]
2017-07-08 00:38:49 +00:00
noti_popup_check: gtk::CheckButton,
2017-07-10 19:07:59 +00:00
#[cfg(feature = "notify")]
2017-07-08 00:38:49 +00:00
noti_ext_check: gtk::CheckButton,
2017-07-07 10:03:53 +00:00
}
impl PrefsDialog {
2017-07-08 00:38:49 +00:00
fn new() -> PrefsDialog {
let builder =
gtk::Builder::new_from_string(include_str!(concat!(env!("CARGO_MANIFEST_DIR"),
"/data/ui/prefs-dialog.glade")));
2017-07-07 10:03:53 +00:00
let prefs_dialog = PrefsDialog {
_cant_construct: (),
prefs_dialog: builder.get_object("prefs_dialog").unwrap(),
2017-07-10 19:07:59 +00:00
notebook: builder.get_object("notebook").unwrap(),
2017-07-07 10:03:53 +00:00
card_combo: builder.get_object("card_combo").unwrap(),
chan_combo: builder.get_object("chan_combo").unwrap(),
2017-07-07 20:10:45 +00:00
vol_meter_draw_check: builder.get_object("vol_meter_draw_check")
2017-07-07 10:03:53 +00:00
.unwrap(),
2017-07-07 20:10:45 +00:00
vol_meter_pos_spin: builder.get_object("vol_meter_pos_spin")
2017-07-07 10:03:53 +00:00
.unwrap(),
2017-07-07 20:10:45 +00:00
vol_meter_color_button: builder.get_object("vol_meter_color_button")
2017-07-07 10:03:53 +00:00
.unwrap(),
system_theme: builder.get_object("system_theme").unwrap(),
vol_control_entry: builder.get_object("vol_control_entry").unwrap(),
scroll_step_spin: builder.get_object("scroll_step_spin").unwrap(),
2017-07-08 22:14:49 +00:00
fine_scroll_step_spin: builder.get_object("fine_scroll_step_spin")
.unwrap(),
2017-07-07 20:10:45 +00:00
middle_click_combo: builder.get_object("middle_click_combo")
2017-07-07 10:03:53 +00:00
.unwrap(),
custom_entry: builder.get_object("custom_entry").unwrap(),
2017-07-10 19:07:59 +00:00
#[cfg(feature = "notify")]
2017-07-07 10:03:53 +00:00
noti_enable_check: builder.get_object("noti_enable_check").unwrap(),
2017-07-10 19:07:59 +00:00
#[cfg(feature = "notify")]
2017-07-07 10:03:53 +00:00
noti_timeout_spin: builder.get_object("noti_timeout_spin").unwrap(),
// noti_hotkey_check: builder.get_object("noti_hotkey_check").unwrap(),
2017-07-10 19:07:59 +00:00
#[cfg(feature = "notify")]
2017-07-07 10:03:53 +00:00
noti_mouse_check: builder.get_object("noti_mouse_check").unwrap(),
2017-07-10 19:07:59 +00:00
#[cfg(feature = "notify")]
2017-07-07 10:03:53 +00:00
noti_popup_check: builder.get_object("noti_popup_check").unwrap(),
2017-07-10 19:07:59 +00:00
#[cfg(feature = "notify")]
2017-07-07 10:03:53 +00:00
noti_ext_check: builder.get_object("noti_ext_check").unwrap(),
};
2017-07-10 19:07:59 +00:00
#[cfg(feature = "notify")]
let notify_tab: gtk::Box = builder.get_object("noti_vbox_enabled").unwrap();
#[cfg(not(feature = "notify"))]
let notify_tab: gtk::Box = builder.get_object("noti_vbox_disabled").unwrap();
2017-07-07 10:03:53 +00:00
2017-07-10 19:07:59 +00:00
prefs_dialog.notebook.append_page(&notify_tab,
Some(&gtk::Label::new(Some("Notifications"))));
2017-07-07 10:03:53 +00:00
return prefs_dialog;
}
2017-07-08 00:38:49 +00:00
fn from_prefs(&self, prefs: &Prefs) {
2017-07-07 10:03:53 +00:00
/* DevicePrefs */
2017-07-07 20:10:45 +00:00
/* filled on show signal with audio info */
2017-07-07 10:03:53 +00:00
self.card_combo.remove_all();
self.chan_combo.remove_all();
/* ViewPrefs */
2017-07-07 20:10:45 +00:00
self.vol_meter_draw_check.set_active(prefs.view_prefs.draw_vol_meter);
self.vol_meter_pos_spin.set_value(prefs.view_prefs.vol_meter_offset as
f64);
2017-07-07 10:03:53 +00:00
// TODO don't convert like that
let rgba = gdk::RGBA {
red: prefs.view_prefs.vol_meter_color.red as f64 / 255.0,
green: prefs.view_prefs.vol_meter_color.green as f64 / 255.0,
blue: prefs.view_prefs.vol_meter_color.blue as f64 / 255.0,
alpha: 1.0,
};
self.vol_meter_color_button.set_rgba(&rgba);
self.system_theme.set_active(prefs.view_prefs.system_theme);
/* BehaviorPrefs */
2017-07-07 20:10:45 +00:00
self.vol_control_entry.set_text(prefs.behavior_prefs
.vol_control_cmd
.as_ref()
.unwrap_or(&String::from(""))
.as_str());
self.scroll_step_spin.set_value(prefs.behavior_prefs.vol_scroll_step);
2017-07-08 22:14:49 +00:00
self.fine_scroll_step_spin
.set_value(prefs.behavior_prefs.vol_fine_scroll_step);
2017-07-07 10:03:53 +00:00
// TODO: make sure these values always match, must be a better way
// also check to_prefs()
self.middle_click_combo.append_text("Toggle Mute");
self.middle_click_combo.append_text("Show Preferences");
self.middle_click_combo.append_text("Volume Control");
2017-07-07 15:00:04 +00:00
self.middle_click_combo.append_text("Custom Command (set below)");
2017-07-07 20:10:45 +00:00
self.middle_click_combo.set_active(prefs.behavior_prefs
.middle_click_action
.into());
self.custom_entry.set_text(prefs.behavior_prefs
.custom_command
.as_ref()
.unwrap_or(&String::from(""))
.as_str());
2017-07-07 10:03:53 +00:00
/* NotifyPrefs */
2017-07-10 19:07:59 +00:00
#[cfg(feature = "notify")]
2017-07-07 20:10:45 +00:00
self.noti_enable_check
.set_active(prefs.notify_prefs.enable_notifications);
2017-07-10 19:07:59 +00:00
#[cfg(feature = "notify")]
2017-07-07 20:10:45 +00:00
self.noti_timeout_spin
.set_value(prefs.notify_prefs.notifcation_timeout as f64);
2017-07-10 19:07:59 +00:00
#[cfg(feature = "notify")]
2017-07-07 20:10:45 +00:00
self.noti_mouse_check
.set_active(prefs.notify_prefs.notify_mouse_scroll);
2017-07-10 19:07:59 +00:00
#[cfg(feature = "notify")]
2017-07-07 20:10:45 +00:00
self.noti_popup_check.set_active(prefs.notify_prefs.notify_popup);
2017-07-10 19:07:59 +00:00
#[cfg(feature = "notify")]
2017-07-07 20:10:45 +00:00
self.noti_ext_check.set_active(prefs.notify_prefs.notify_external);
2017-07-07 10:03:53 +00:00
}
2017-07-08 00:38:49 +00:00
fn to_prefs(&self) -> Prefs {
2017-07-07 10:03:53 +00:00
// TODO: remove duplication with default instance
2017-07-07 20:10:45 +00:00
let device_prefs =
DevicePrefs {
card: self.card_combo
.get_active_text()
.unwrap_or(String::from("(default)")),
channel: self.chan_combo
.get_active_text()
.unwrap_or(String::from("Master")),
};
2017-07-07 10:03:53 +00:00
// TODO don't convert like that
let vol_meter_color = VolColor {
red: (self.vol_meter_color_button.get_rgba().red * 255.0) as u8,
green: (self.vol_meter_color_button.get_rgba().green * 255.0) as u8,
blue: (self.vol_meter_color_button.get_rgba().blue * 255.0) as u8,
};
let view_prefs = ViewPrefs {
draw_vol_meter: self.vol_meter_draw_check.get_active(),
vol_meter_offset: self.vol_meter_pos_spin.get_value_as_int(),
system_theme: self.system_theme.get_active(),
vol_meter_color,
};
2017-07-07 20:10:45 +00:00
let vol_control_cmd =
self.vol_control_entry.get_text().and_then(|x| if x.is_empty() {
None
} else {
Some(x)
});
2017-07-07 10:03:53 +00:00
let custom_command =
self.custom_entry.get_text().and_then(|x| if x.is_empty() {
2017-07-07 20:10:45 +00:00
None
} else {
Some(x)
});
2017-07-07 10:03:53 +00:00
let behavior_prefs = BehaviorPrefs {
vol_control_cmd,
vol_scroll_step: self.scroll_step_spin.get_value(),
2017-07-08 22:14:49 +00:00
vol_fine_scroll_step: self.fine_scroll_step_spin.get_value(),
2017-07-07 10:03:53 +00:00
middle_click_action: self.middle_click_combo.get_active().into(),
custom_command,
};
2017-07-10 19:07:59 +00:00
#[cfg(feature = "notify")]
2017-07-07 10:03:53 +00:00
let notify_prefs = NotifyPrefs {
enable_notifications: self.noti_enable_check.get_active(),
notifcation_timeout: self.noti_timeout_spin.get_value_as_int() as
2017-07-07 20:10:45 +00:00
i64,
2017-07-07 10:03:53 +00:00
notify_mouse_scroll: self.noti_mouse_check.get_active(),
notify_popup: self.noti_popup_check.get_active(),
notify_external: self.noti_ext_check.get_active(),
};
return Prefs {
2017-07-07 20:10:45 +00:00
device_prefs,
view_prefs,
behavior_prefs,
2017-07-10 19:07:59 +00:00
#[cfg(feature = "notify")]
2017-07-07 20:10:45 +00:00
notify_prefs,
};
2017-07-07 10:03:53 +00:00
}
}
2017-07-07 15:00:04 +00:00
pub fn show_prefs_dialog(appstate: &Rc<AppS>) {
2017-07-07 20:10:45 +00:00
if appstate.gui
.prefs_dialog
.borrow()
.is_some() {
2017-07-06 22:28:55 +00:00
return;
2017-07-06 14:53:19 +00:00
}
2017-07-02 17:08:17 +00:00
2017-07-06 22:28:55 +00:00
*appstate.gui.prefs_dialog.borrow_mut() = Some(PrefsDialog::new());
init_prefs_dialog(&appstate);
2017-07-02 17:08:17 +00:00
{
2017-07-06 22:28:55 +00:00
let m_pd = appstate.gui.prefs_dialog.borrow();
let prefs_dialog = &m_pd.as_ref().unwrap();
2017-07-02 17:08:17 +00:00
let prefs_dialog_w = &prefs_dialog.prefs_dialog;
2017-07-06 22:28:55 +00:00
prefs_dialog.from_prefs(&appstate.prefs.borrow());
2017-07-02 17:08:17 +00:00
prefs_dialog_w.set_transient_for(&appstate.gui.popup_menu.menu_window);
2017-07-06 14:53:19 +00:00
prefs_dialog_w.present();
2017-07-02 17:08:17 +00:00
}
}
2017-07-08 00:38:49 +00:00
pub fn init_prefs_callback(appstate: Rc<AppS>) {
let apps = appstate.clone();
appstate.audio.connect_handler(Box::new(move |s, u| {
2017-07-08 22:14:49 +00:00
/* skip if prefs window is not present */
2017-07-10 19:07:59 +00:00
if apps.gui
.prefs_dialog
.borrow()
.is_none() {
2017-07-08 22:14:49 +00:00
return;
}
2017-07-08 00:38:49 +00:00
match (s, u) {
(AudioSignal::CardInitialized, _) => (),
(AudioSignal::CardCleanedUp, _) => {
fill_card_combo(&apps);
fill_chan_combo(&apps, None);
2017-07-10 19:07:59 +00:00
}
2017-07-08 00:38:49 +00:00
_ => (),
}
}));
}
2017-07-07 20:10:45 +00:00
2017-07-08 00:38:49 +00:00
fn init_prefs_dialog(appstate: &Rc<AppS>) {
2017-07-02 17:08:17 +00:00
2017-07-02 16:11:56 +00:00
/* prefs_dialog.connect_show */
{
let apps = appstate.clone();
2017-07-06 22:28:55 +00:00
let m_pd = appstate.gui.prefs_dialog.borrow();
let pd = m_pd.as_ref().unwrap();
2017-07-08 00:38:49 +00:00
pd.prefs_dialog.connect_show(move |_| {
fill_card_combo(&apps);
fill_chan_combo(&apps, None);
});
2017-07-06 22:28:55 +00:00
}
2017-07-07 20:10:45 +00:00
/* card_combo.connect_changed */
{
let apps = appstate.clone();
let m_cc = appstate.gui.prefs_dialog.borrow();
let card_combo = &m_cc.as_ref().unwrap().card_combo;
card_combo.connect_changed(move |_| {
let m_cc = apps.gui.prefs_dialog.borrow();
let card_combo = &m_cc.as_ref().unwrap().card_combo;
2017-07-08 00:38:49 +00:00
let card_name = card_combo.get_active_text().unwrap();
2017-07-07 20:10:45 +00:00
fill_chan_combo(&apps, Some(card_name));
return;
});
}
/* prefs_dialog.connect_response */
2017-07-06 22:28:55 +00:00
{
let apps = appstate.clone();
let m_pd = appstate.gui.prefs_dialog.borrow();
let pd = m_pd.as_ref().unwrap();
pd.prefs_dialog.connect_response(move |_, response_id| {
if response_id == ResponseType::Ok.into() ||
response_id == ResponseType::Apply.into() {
let mut prefs = apps.prefs.borrow_mut();
let prefs_dialog = apps.gui.prefs_dialog.borrow();
*prefs = prefs_dialog.as_ref().unwrap().to_prefs();
}
if response_id != ResponseType::Apply.into() {
let mut prefs_dialog = apps.gui.prefs_dialog.borrow_mut();
prefs_dialog.as_ref().unwrap().prefs_dialog.destroy();
*prefs_dialog = None;
}
if response_id == ResponseType::Ok.into() ||
response_id == ResponseType::Apply.into() {
// TODO: update popup, tray_icon, hotkeys, notification and audio
2017-07-10 19:07:59 +00:00
#[cfg(feature = "notify")]
try_w!(apps.notif.reload(&apps.prefs.borrow()));
2017-07-07 10:03:53 +00:00
try_w!(apps.update_tray_icon());
try_w!(apps.update_popup_window());
2017-07-07 20:10:45 +00:00
{
let prefs = apps.prefs.borrow();
2017-07-08 00:38:49 +00:00
try_w!(audio_reload(&apps.audio, &prefs, AudioUser::PrefsWindow));
2017-07-07 20:10:45 +00:00
}
2017-07-06 22:28:55 +00:00
let prefs = apps.prefs.borrow_mut();
try_w!(prefs.store_config());
}
2017-07-04 14:54:16 +00:00
});
2017-07-02 16:11:56 +00:00
}
}
2017-07-07 20:10:45 +00:00
fn fill_card_combo(appstate: &AppS) {
2017-07-06 22:28:55 +00:00
let m_cc = appstate.gui.prefs_dialog.borrow();
let card_combo = &m_cc.as_ref().unwrap().card_combo;
2017-07-07 20:10:45 +00:00
card_combo.remove_all();
2017-07-02 16:11:56 +00:00
let acard = appstate.audio.acard.borrow();
/* set card combo */
2017-07-07 20:10:45 +00:00
let cur_card_name = try_w!(acard.card_name(),
"Can't get current card name!");
2017-07-07 23:35:13 +00:00
let available_card_names = get_playable_alsa_card_names();
2017-07-02 16:11:56 +00:00
/* set_active_id doesn't work, so save the index */
let mut c_index: i32 = -1;
for i in 0..available_card_names.len() {
let name = available_card_names.get(i).unwrap();
if *name == cur_card_name {
c_index = i as i32;
}
card_combo.append_text(&name);
}
// TODO, block signal?
card_combo.set_active(c_index);
2017-07-07 20:10:45 +00:00
}
2017-07-02 16:11:56 +00:00
2017-07-07 20:10:45 +00:00
fn fill_chan_combo(appstate: &AppS, cardname: Option<String>) {
let m_cc = appstate.gui.prefs_dialog.borrow();
let chan_combo = &m_cc.as_ref().unwrap().chan_combo;
chan_combo.remove_all();
let cur_acard = appstate.audio.acard.borrow();
let card = match cardname {
2017-07-08 00:38:49 +00:00
Some(name) => try_w!(get_alsa_card_by_name(name).from_err()),
2017-07-07 20:10:45 +00:00
None => cur_acard.as_ref().card,
};
2017-07-02 16:11:56 +00:00
/* set chan combo */
2017-07-07 20:10:45 +00:00
let cur_chan_name = try_w!(cur_acard.chan_name());
let mixer = try_w!(get_mixer(&card));
2017-07-07 23:35:13 +00:00
let available_chan_names = get_playable_selem_names(&mixer);
2017-07-02 16:11:56 +00:00
/* set_active_id doesn't work, so save the index */
let mut c_index: i32 = -1;
for i in 0..available_chan_names.len() {
let name = available_chan_names.get(i).unwrap();
if *name == cur_chan_name {
c_index = i as i32;
}
chan_combo.append_text(&name);
}
/* TODO, block signal?`*/
chan_combo.set_active(c_index);
}