#! /usr/bin/python
#
# Magnifier Preferences - GnomeShell Magnifier settings via GConf
#
# Copyright (C) 2010 Adaptive Technology Resource Centre
#  * Contributor: Joseph Scheuhammer <clown@utoronto.ca>
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation; either version 2.1 of the License, or (at your
# option) any later version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
# for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

import gtk
import gio
import dbus

ScreenPosition = \
    { "NONE": 0, "FULL_SCREEN": 1, "TOP_HALF": 2, "BOTTOM_HALF": 3, "LEFT_HALF": 4, "RIGHT_HALF": 5, "DOCKED": 6 };
MouseTrackingMode = { "NONE": 0, "CENTERED": 1, "PUSH": 2, "PROPORTIONAL": 3 };

A11Y_MAG_PREFS_DIR    = "/desktop/gnome/accessibility/magnifier/";

SHOW_KEY              = "show_magnifier";
SCREEN_POSITION_KEY   = "screen_position";
MAG_FACTOR_KEY        = "mag_factor";
LENS_MODE_KEY         = "lens_mode";
CLAMP_MODE_KEY        = "scroll_at_edges";
MOUSE_MODE_KEY        = "mouse_tracking";

CROSSHAIRS_SHOW_KEY         = "show_cross_hairs";
CROSSHAIRS_CLIP_KEY         = "cross_hairs_clip";
CROSSHAIRS_COLOR_KEY        = "cross_hairs_color";
CROSSHAIRS_THICKNESS_KEY    = "cross_hairs_thickness";
CROSSHAIRS_OPACITY_KEY      = "cross_hairs_opacity";
CROSSHAIRS_LENGTH_KEY       = "cross_hairs_length";

DEFAULT_CROSSHAIRS_COLOR = "#ff0000";   # red
DEFAULT_CROSSHAIRS_OPACITY = 169;       # 66%
DEFAULT_CROSSHAIRS_LENGTH = 4096;

# Actual opacity values in the range [0,255]
CROSSHAIRS_OPACITY_RANGE = 255;

##
# UI for magnifier preferences.
#

class MagPrefsUI:
    __gtype_name__ = "MagPrefsUI";

    def __init__(self):
    
        self._calcDockedViewPort();

        builder = gtk.Builder();
        builder.add_from_file('MagnifierGConfUI.glade');

        self.dBus = dbus.SessionBus();
        try:
            self.magProxy = self.dBus.get_object('org.gnome.Magnifier', '/org/gnome/Magnifier');
        except:
            print "Can't get dbus connection to Magnifier";
            self.zoomRegionProxy = None;
                        
        settings = gio.Settings("org.gnome.accessibility.magnifier");
        self.settings = settings;

        # Set the widgets according to the current stored gconf values (if any).
        # Show/hide magnifier toggle ...
        showToggle = builder.get_object("showMagnifierToggle");
        aSetting = gConf.get_bool(SHOW_KEY);
        showToggle.set_active(aSetting);
        showToggle.connect("clicked", self.doShowHide, self);
        
        # ... Mouse tracking mode combobox ...
        mouseTrackingComboBox = builder.get_object("mouseTrackingCombo");
        aSetting = settings.get_enum(MOUSE_MODE_KEY);
        if (aSetting >= MouseTrackingMode["NONE"] and aSetting <= ["MouseTrackingMode.PROPORTIONAL"]):
            mouseTrackingComboBox.set_active(aSetting);
        else:
            mouseTrackingComboBox.set_active(MouseTrackingMode["CENTERED"]);
        mouseTrackingComboBox.connect("changed", self.doMouseTracking, self);

        # ... Screen position combobox ...
        screenPosComboBox = builder.get_object("screenPositionCombo");
        aSetting = settings.get_enum(SCREEN_POSITION_KEY);
        if (ScreenPosition["FULL_SCREEN"] <= aSetting <= ScreenPosition["DOCKED"]):
            screenPosComboBox.set_active(aSetting - 1);
        else:
            screenPosComboBox.set_active(ScreenPosition["DOCKED"] - 1);
        screenPosComboBox.connect("changed", self.doScreenPosition, self);
        self.screenPosComboBox = screenPosComboBox;

        # ... Magnification factor slider ...
        magSlider = builder.get_object("magFactorSlider");
        aSetting = settings.get_double(MAG_FACTOR_KEY);
        if (aSetting == 0.0):
            magSlider.set_value(2.0);
            settings.set_double(MAG_FACTOR_KEY, 2.0);
        else:
            magSlider.set_value(aSetting);
        magSlider.connect("value-changed", self.doMagnification, self);
        
        # ... Lens mode checkbox ...
        lensMode = builder.get_object("moveableLensCheckbox");
        aSetting = settings.get_boolean(LENS_MODE_KEY);
        gConf.set_bool(LENS_MODE_KEY, aSetting);
        lensMode.set_active(aSetting);
        lensMode.connect("clicked", self.doLensMode, self);

        # ... Clamp scrolling at screen edges checkbox ...
        edgeScrollMode = builder.get_object("scrollAtEdges");
        aSetting = gConf.get_bool(CLAMP_MODE_KEY);
        gConf.set_bool(CLAMP_MODE_KEY, aSetting);
        edgeScrollMode.set_active(aSetting);
        edgeScrollMode.connect("clicked", self.doClampScrolling, self);
        
        # ... Cross hairs: show/hide ...
        showCrosshairsMode = builder.get_object("xHairsShowHide");
        aSetting = settings.get_boolean(CROSSHAIRS_SHOW_KEY);
        settings.set_boolean(CROSSHAIRS_SHOW_KEY, aSetting);
        showCrosshairsMode.set_active(aSetting);
        showCrosshairsMode.connect("clicked", self.doShowCrosshairs, self);
        
        # ... Cross hairs: color ...
        crosshairsColor = builder.get_object("xHairsPicker");
        aSetting = settings.get_string(CROSSHAIRS_COLOR_KEY);
        if aSetting == None:
            aSetting = DEFAULT_CROSSHAIRS_COLOR;
        settings.set_string(CROSSHAIRS_COLOR_KEY, aSetting);
        crosshairsColor.set_color(gtk.gdk.Color(aSetting));
        crosshairsColor.connect("color-set", self.doCrosshairsColor, self);

        # ... Cross hairs: opacity ...
        crosshairsOpacity = builder.get_object("xHairsOpacitySlider");
        aSetting = settings.get_int(CROSSHAIRS_OPACITY_KEY);
        settings.set_int(CROSSHAIRS_OPACITY_KEY, aSetting);
        aSetting = aSetting / float(CROSSHAIRS_OPACITY_RANGE);
        crosshairsOpacity.set_value(aSetting);
        crosshairsOpacity.connect("value-changed", self.doCrosshairsOpacity, self);

        # ... Cross hairs: thickness ...
        crosshairsThickness = builder.get_object("xHairsThicknessSpinner");
        aSetting = settings.get_int(CROSSHAIRS_THICKNESS_KEY);
        settings.set_int(CROSSHAIRS_THICKNESS_KEY, aSetting);
        crosshairsThickness.set_value(aSetting);
        crosshairsThickness.connect("value-changed", self.doCrosshairsThickness, self);

        # ... Cross hairs: clip ...
        clipCrosshairsMode = builder.get_object("xHairsClipCheckbox");
        aSetting = settings.get_bool(CROSSHAIRS_CLIP_KEY);
        settings.set_bool(CROSSHAIRS_CLIP_KEY, aSetting);
        clipCrosshairsMode.set_active(aSetting);
        clipCrosshairsMode.connect("clicked", self.doCrosshairsClip, self);

        # ... Cross hairs: length
        crosshairsLength = builder.get_object("xHairsLengthSlider");
        aSetting = settings.get_int(CROSSHAIRS_LENGTH_KEY);
        settings.set_int(CROSSHAIRS_LENGTH_KEY, aSetting);
        crosshairsLength.set_value(aSetting);
        crosshairsLength.connect("value-changed", self.doCrosshairsLength, self);        

        # Handle closing.
        mainWindow = builder.get_object("magPrefsDialog");
        mainWindow.connect("destroy", gtk.main_quit);
        mainWindow.connect("delete_event", lambda window, event: False);
        closeButton = builder.get_object("closeButton");
        closeButton.connect("clicked", lambda button: mainWindow.destroy());
        
        # Listen for changes that other processes might make to the mag
        # GSettings.
#        settings.connect("changed", self.handleSettingsChanges, self);

                
        mainWindow.show_all();
    
    def _getFirstZoomRegion(self):
        if self.magProxy != None:
            zoomRegionPaths = self.magProxy.getZoomRegions();
            if len(zoomRegionPaths) > 0:
                return self.dBus.get_object('org.gnome.Magnifier', zoomRegionPaths[0]);
            else:
                return None;
    
    def _calcDockedViewPort(self):
        screenWidth = gtk.gdk.screen_width();
        screenHeight = gtk.gdk.screen_height();
        top = screenHeight / 3 * 2;
        height = screenHeight / 3;
        width = screenWidth / 2;
        self._dockedViewPort = [0, top, width, height];

    # Handlers for the widgets in the preferences dialog.
    #        
    def doShowHide(self, toggleButton, event):
        self.settings.set_boolean(SHOW_KEY, toggleButton.get_active());
        
    def doMouseTracking(self, combobox, event):
        self.settings.set_enum(MOUSE_MODE_KEY, combobox.get_active());
     
    def doScreenPosition(self, combobox, event):
        position = combobox.get_active() + 1;
        if position == ScreenPosition["DOCKED"]:
            aZoomRegion = self._getFirstZoomRegion();
            if aZoomRegion != None:
                try:
                    aZoomRegion.moveResize(self._dockedViewPort);
                except:
                    pass;
        self.settings.set_enum(SCREEN_POSITION_KEY, combobox.get_active() + 1);

    def doMagnification(self, slider, event):
        self.settings.set_double(MAG_FACTOR_KEY, slider.get_value());
    
    def doLensMode(self, checkbox, event):
        lensMode = checkbox.get_active();
        position = self.screenPosComboBox.get_active() + 1;
        self.settings.set_boolean(LENS_MODE_KEY, lensMode);
        if not lensMode and position == ScreenPosition["DOCKED"]:
            if self.zoomRegionProxy != None:
                try:
                    self.zoomRegionProxy.moveResize(self._dockedViewPort);
                except:
                    pass;            

    def doClampScrolling(self, checkbox, event):
        self.settings.set_boolean(CLAMP_MODE_KEY, checkbox.get_active());
    
    def doShowCrosshairs(self, checkbox, event):
        self.settings.set_boolean(CROSSHAIRS_SHOW_KEY, checkbox.get_active());
    
    def doCrosshairsColor(self, colorButton, event):
        # colorVal is in the form "#rrrrggggbbbb".  Convert to "#rrggbb".
        colorVal = colorButton.get_color().to_string();
        cVal = "#";
        cVal += colorVal[1:3];      # red
        cVal += colorVal[5:7];      # green
        cVal += colorVal[9:11];     # blue
        self.settings.set_string(CROSSHAIRS_COLOR_KEY, cVal);

    def doCrosshairsOpacity(self, opacitySlider, event):
        opacity = int(opacitySlider.get_value() * CROSSHAIRS_OPACITY_RANGE);
        self.settings.set_int(CROSSHAIRS_OPACITY_KEY, opacity);
    
    def doCrosshairsThickness(self, thicknessSpinner, event):
        self.settings.set_int(CROSSHAIRS_THICKNESS_KEY, int(thicknessSpinner.get_value()));

    def doCrosshairsClip(self, checkbox, event):
        self.settings.set_boolean(CROSSHAIRS_CLIP_KEY, checkbox.get_active());
 
    def doCrosshairsLength(self, lengthSlider, event):
        self.settings.set_int(CROSSHAIRS_LENGTH_KEY, int(lengthSlider.get_value()));

    # Handle changes that GSettings notifies us about.
    #
#    def handleSettingsChanges(self, settings, key):
#        print settings.get(key);
    
magPrefsUI = MagPrefsUI();
gtk.main();






