[gnome-shell/wip/message-tray-menu: 12/20] slider: Separate PopupSliderMenuItem into its own widget



commit a987be2c314a2e6a36331dd8ef517082875d6beb
Author: Jasper St. Pierre <jstpierre mecheye net>
Date:   Tue Jul 12 16:12:28 2011 -0400

    slider: Separate PopupSliderMenuItem into its own widget

 js/Makefile.am     |    1 +
 js/ui/popupMenu.js |  199 +++-----------------------------------------------
 js/ui/slider.js    |  208 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 219 insertions(+), 189 deletions(-)
---
diff --git a/js/Makefile.am b/js/Makefile.am
index 62c8323..a14b3f4 100644
--- a/js/Makefile.am
+++ b/js/Makefile.am
@@ -68,6 +68,7 @@ nobase_dist_js_DATA =         \
        ui/sessionMode.js       \
        ui/shellEntry.js        \
        ui/shellMountOperation.js \
+       ui/slider.js            \
        ui/notificationDaemon.js \
        ui/osdWindow.js         \
        ui/overview.js          \
diff --git a/js/ui/popupMenu.js b/js/ui/popupMenu.js
index b37fd6c..4099ff5 100644
--- a/js/ui/popupMenu.js
+++ b/js/ui/popupMenu.js
@@ -15,10 +15,9 @@ const GrabHelper = imports.ui.grabHelper;
 const Main = imports.ui.main;
 const Params = imports.misc.params;
 const Separator = imports.ui.separator;
+const Slider = imports.ui.slider;
 const Tweener = imports.ui.tweener;
 
-const SLIDER_SCROLL_STEP = 0.05; /* Slider scrolling step in % */
-
 const Ornament = {
     NONE: 0,
     DOT: 1,
@@ -508,200 +507,22 @@ const PopupSliderMenuItem = new Lang.Class({
     _init: function(value) {
         this.parent({ activate: false });
 
-        this.actor.connect('key-press-event', Lang.bind(this, this._onKeyPressEvent));
-
-        if (isNaN(value))
-            // Avoid spreading NaNs around
-            throw TypeError('The slider value must be a number');
-        this._value = Math.max(Math.min(value, 1), 0);
-
-        this._slider = new St.DrawingArea({ style_class: 'popup-slider-menu-item', reactive: true });
-        this.addActor(this._slider, { span: -1, expand: true });
-        this._slider.connect('repaint', Lang.bind(this, this._sliderRepaint));
-        this.actor.connect('button-press-event', Lang.bind(this, this._startDragging));
-        this.actor.connect('scroll-event', Lang.bind(this, this._onScrollEvent));
-        this.actor.connect('notify::mapped', Lang.bind(this, function() {
-            if (!this.actor.mapped)
-                this._endDragging();
+        this._slider = new Slider.Slider(value);
+        this._slider.connect('value-changed', Lang.bind(this, function(actor, value) {
+            this.emit('value-changed', value);
         }));
-
-        this._releaseId = this._motionId = 0;
-        this._dragging = false;
-    },
-
-    setValue: function(value) {
-        if (isNaN(value))
-            throw TypeError('The slider value must be a number');
-
-        this._value = Math.max(Math.min(value, 1), 0);
-        this._slider.queue_repaint();
-    },
-
-    _sliderRepaint: function(area) {
-        let cr = area.get_context();
-        let themeNode = area.get_theme_node();
-        let [width, height] = area.get_surface_size();
-
-        let handleRadius = themeNode.get_length('-slider-handle-radius');
-
-        let sliderWidth = width - 2 * handleRadius;
-        let sliderHeight = themeNode.get_length('-slider-height');
-
-        let sliderBorderWidth = themeNode.get_length('-slider-border-width');
-
-        let sliderBorderColor = themeNode.get_color('-slider-border-color');
-        let sliderColor = themeNode.get_color('-slider-background-color');
-
-        let sliderActiveBorderColor = themeNode.get_color('-slider-active-border-color');
-        let sliderActiveColor = themeNode.get_color('-slider-active-background-color');
-
-        cr.setSourceRGBA (
-            sliderActiveColor.red / 255,
-            sliderActiveColor.green / 255,
-            sliderActiveColor.blue / 255,
-            sliderActiveColor.alpha / 255);
-        cr.rectangle(handleRadius, (height - sliderHeight) / 2, sliderWidth * this._value, sliderHeight);
-        cr.fillPreserve();
-        cr.setSourceRGBA (
-            sliderActiveBorderColor.red / 255,
-            sliderActiveBorderColor.green / 255,
-            sliderActiveBorderColor.blue / 255,
-            sliderActiveBorderColor.alpha / 255);
-        cr.setLineWidth(sliderBorderWidth);
-        cr.stroke();
-
-        cr.setSourceRGBA (
-            sliderColor.red / 255,
-            sliderColor.green / 255,
-            sliderColor.blue / 255,
-            sliderColor.alpha / 255);
-        cr.rectangle(handleRadius + sliderWidth * this._value, (height - sliderHeight) / 2, sliderWidth * (1 
- this._value), sliderHeight);
-        cr.fillPreserve();
-        cr.setSourceRGBA (
-            sliderBorderColor.red / 255,
-            sliderBorderColor.green / 255,
-            sliderBorderColor.blue / 255,
-            sliderBorderColor.alpha / 255);
-        cr.setLineWidth(sliderBorderWidth);
-        cr.stroke();
-
-        let handleY = height / 2;
-        let handleX = handleRadius + (width - 2 * handleRadius) * this._value;
-
-        let color = themeNode.get_foreground_color();
-        cr.setSourceRGBA (
-            color.red / 255,
-            color.green / 255,
-            color.blue / 255,
-            color.alpha / 255);
-        cr.arc(handleX, handleY, handleRadius, 0, 2 * Math.PI);
-        cr.fill();
-        cr.$dispose();
-    },
-
-    _startDragging: function(actor, event) {
-        if (this._dragging) // don't allow two drags at the same time
-            return false;
-
-        this._dragging = true;
-
-        // FIXME: we should only grab the specific device that originated
-        // the event, but for some weird reason events are still delivered
-        // outside the slider if using clutter_grab_pointer_for_device
-        Clutter.grab_pointer(this._slider);
-        this._releaseId = this._slider.connect('button-release-event', Lang.bind(this, this._endDragging));
-        this._motionId = this._slider.connect('motion-event', Lang.bind(this, this._motionEvent));
-        let absX, absY;
-        [absX, absY] = event.get_coords();
-        this._moveHandle(absX, absY);
-
-        return true;
-    },
-
-    _endDragging: function() {
-        if (this._dragging) {
-            this._slider.disconnect(this._releaseId);
-            this._slider.disconnect(this._motionId);
-
-            Clutter.ungrab_pointer();
-            this._dragging = false;
-
+        this._slider.connect('drag-end', Lang.bind(this, function(actor) {
             this.emit('drag-end');
-        }
-        return true;
-    },
-
-    scroll: function(event) {
-        let direction = event.get_scroll_direction();
-        let delta;
-
-        if (event.is_pointer_emulated())
-            return;
-
-        if (direction == Clutter.ScrollDirection.DOWN) {
-            delta = -SLIDER_SCROLL_STEP;
-        } else if (direction == Clutter.ScrollDirection.UP) {
-            delta = +SLIDER_SCROLL_STEP;
-        } else if (direction == Clutter.ScrollDirection.SMOOTH) {
-            let [dx, dy] = event.get_scroll_delta();
-            // Even though the slider is horizontal, use dy to match
-            // the UP/DOWN above.
-            delta = -dy / 10;
-        }
-
-        this._value = Math.min(Math.max(0, this._value + delta), 1);
-
-        this._slider.queue_repaint();
-        this.emit('value-changed', this._value);
-    },
-
-    _onScrollEvent: function(actor, event) {
-        this.scroll(event);
-    },
-
-    _motionEvent: function(actor, event) {
-        let absX, absY;
-        [absX, absY] = event.get_coords();
-        this._moveHandle(absX, absY);
-        return true;
+        }));
+        this.addActor(this._slider.actor, { span: -1, expand: true });
     },
 
-    _moveHandle: function(absX, absY) {
-        let relX, relY, sliderX, sliderY;
-        [sliderX, sliderY] = this._slider.get_transformed_position();
-        relX = absX - sliderX;
-        relY = absY - sliderY;
-
-        let width = this._slider.width;
-        let handleRadius = this._slider.get_theme_node().get_length('-slider-handle-radius');
-
-        let newvalue;
-        if (relX < handleRadius)
-            newvalue = 0;
-        else if (relX > width - handleRadius)
-            newvalue = 1;
-        else
-            newvalue = (relX - handleRadius) / (width - 2 * handleRadius);
-        this._value = newvalue;
-        this._slider.queue_repaint();
-        this.emit('value-changed', this._value);
+    setValue: function(value) {
+        this._slider.setValue(value);
     },
 
     get value() {
-        return this._value;
-    },
-
-    _onKeyPressEvent: function (actor, event) {
-        let key = event.get_key_symbol();
-        if (key == Clutter.KEY_Right || key == Clutter.KEY_Left) {
-            let delta = key == Clutter.KEY_Right ? 0.1 : -0.1;
-            this._value = Math.max(0, Math.min(this._value + delta, 1));
-            this._slider.queue_repaint();
-            this.emit('value-changed', this._value);
-            this.emit('drag-end');
-            return true;
-        }
-        return false;
+        return this._slider.value;
     }
 });
 
diff --git a/js/ui/slider.js b/js/ui/slider.js
new file mode 100644
index 0000000..cad4827
--- /dev/null
+++ b/js/ui/slider.js
@@ -0,0 +1,208 @@
+/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
+
+const Cairo = imports.cairo;
+const Clutter = imports.gi.Clutter;
+const Lang = imports.lang;
+const St = imports.gi.St;
+const Signals = imports.signals;
+
+const SLIDER_SCROLL_STEP = 0.05; /* Slider scrolling step in % */
+
+const Slider = new Lang.Class({
+    Name: "Slider",
+
+    _init: function(value) {
+        if (isNaN(value))
+            // Avoid spreading NaNs around
+            throw TypeError('The slider value must be a number');
+        this._value = Math.max(Math.min(value, 1), 0);
+
+        this.actor = new St.DrawingArea({ style_class: 'popup-slider-menu-item',
+                                          can_focus: true,
+                                          reactive: true });
+        this.actor.connect('repaint', Lang.bind(this, this._sliderRepaint));
+        this.actor.connect('button-press-event', Lang.bind(this, this._startDragging));
+        this.actor.connect('scroll-event', Lang.bind(this, this._onScrollEvent));
+        this.actor.connect('key-press-event', Lang.bind(this, this._onKeyPressEvent));
+
+        this._releaseId = this._motionId = 0;
+        this._dragging = false;
+    },
+
+    setValue: function(value) {
+        if (isNaN(value))
+            throw TypeError('The slider value must be a number');
+
+        this._value = Math.max(Math.min(value, 1), 0);
+        this.actor.queue_repaint();
+    },
+
+    _sliderRepaint: function(area) {
+        let cr = area.get_context();
+        let themeNode = area.get_theme_node();
+        let [width, height] = area.get_surface_size();
+
+        let handleRadius = themeNode.get_length('-slider-handle-radius');
+
+        let sliderWidth = width - 2 * handleRadius;
+        let sliderHeight = themeNode.get_length('-slider-height');
+
+        let sliderBorderWidth = themeNode.get_length('-slider-border-width');
+
+        let sliderBorderColor = themeNode.get_color('-slider-border-color');
+        let sliderColor = themeNode.get_color('-slider-background-color');
+
+        let sliderActiveBorderColor = themeNode.get_color('-slider-active-border-color');
+        let sliderActiveColor = themeNode.get_color('-slider-active-background-color');
+
+        cr.setSourceRGBA (
+            sliderActiveColor.red / 255,
+            sliderActiveColor.green / 255,
+            sliderActiveColor.blue / 255,
+            sliderActiveColor.alpha / 255);
+        cr.rectangle(handleRadius, (height - sliderHeight) / 2, sliderWidth * this._value, sliderHeight);
+        cr.fillPreserve();
+        cr.setSourceRGBA (
+            sliderActiveBorderColor.red / 255,
+            sliderActiveBorderColor.green / 255,
+            sliderActiveBorderColor.blue / 255,
+            sliderActiveBorderColor.alpha / 255);
+        cr.setLineWidth(sliderBorderWidth);
+        cr.stroke();
+
+        cr.setSourceRGBA (
+            sliderColor.red / 255,
+            sliderColor.green / 255,
+            sliderColor.blue / 255,
+            sliderColor.alpha / 255);
+        cr.rectangle(handleRadius + sliderWidth * this._value, (height - sliderHeight) / 2, sliderWidth * (1 
- this._value), sliderHeight);
+        cr.fillPreserve();
+        cr.setSourceRGBA (
+            sliderBorderColor.red / 255,
+            sliderBorderColor.green / 255,
+            sliderBorderColor.blue / 255,
+            sliderBorderColor.alpha / 255);
+        cr.setLineWidth(sliderBorderWidth);
+        cr.stroke();
+
+        let handleY = height / 2;
+        let handleX = handleRadius + (width - 2 * handleRadius) * this._value;
+
+        let color = themeNode.get_foreground_color();
+        cr.setSourceRGBA (
+            color.red / 255,
+            color.green / 255,
+            color.blue / 255,
+            color.alpha / 255);
+        cr.arc(handleX, handleY, handleRadius, 0, 2 * Math.PI);
+        cr.fill();
+        cr.$dispose();
+    },
+
+    _startDragging: function(actor, event) {
+        if (this._dragging) // don't allow two drags at the same time
+            return false;
+
+        this._dragging = true;
+
+        // FIXME: we should only grab the specific device that originated
+        // the event, but for some weird reason events are still delivered
+        // outside the slider if using clutter_grab_pointer_for_device
+        Clutter.grab_pointer(this.actor);
+        this._releaseId = this.actor.connect('button-release-event', Lang.bind(this, this._endDragging));
+        this._motionId = this.actor.connect('motion-event', Lang.bind(this, this._motionEvent));
+        let absX, absY;
+        [absX, absY] = event.get_coords();
+        this._moveHandle(absX, absY);
+
+        return true;
+    },
+
+    _endDragging: function() {
+        if (this._dragging) {
+            this.actor.disconnect(this._releaseId);
+            this.actor.disconnect(this._motionId);
+
+            Clutter.ungrab_pointer();
+            this._dragging = false;
+
+            this.emit('drag-end');
+        }
+        return true;
+    },
+
+    scroll: function(event) {
+        let direction = event.get_scroll_direction();
+        let delta;
+
+        if (event.is_pointer_emulated())
+            return;
+
+        if (direction == Clutter.ScrollDirection.DOWN) {
+            delta = -SLIDER_SCROLL_STEP;
+        } else if (direction == Clutter.ScrollDirection.UP) {
+            delta = +SLIDER_SCROLL_STEP;
+        } else if (direction == Clutter.ScrollDirection.SMOOTH) {
+            let [dx, dy] = event.get_scroll_delta();
+            // Even though the slider is horizontal, use dy to match
+            // the UP/DOWN above.
+            delta = -dy / 10;
+        }
+
+        this._value = Math.min(Math.max(0, this._value + delta), 1);
+
+        this.actor.queue_repaint();
+        this.emit('value-changed', this._value);
+    },
+
+    _onScrollEvent: function(actor, event) {
+        this.scroll(event);
+    },
+
+    _motionEvent: function(actor, event) {
+        let absX, absY;
+        [absX, absY] = event.get_coords();
+        this._moveHandle(absX, absY);
+        return true;
+    },
+
+    _onKeyPressEvent: function (actor, event) {
+        let key = event.get_key_symbol();
+        if (key == Clutter.KEY_Right || key == Clutter.KEY_Left) {
+            let delta = key == Clutter.KEY_Right ? 0.1 : -0.1;
+            this._value = Math.max(0, Math.min(this._value + delta, 1));
+            this._slider.queue_repaint();
+            this.emit('value-changed', this._value);
+            this.emit('drag-end');
+            return true;
+        }
+        return false;
+    },
+
+    _moveHandle: function(absX, absY) {
+        let relX, relY, sliderX, sliderY;
+        [sliderX, sliderY] = this.actor.get_transformed_position();
+        relX = absX - sliderX;
+        relY = absY - sliderY;
+
+        let width = this.actor.width;
+        let handleRadius = this.actor.get_theme_node().get_length('-slider-handle-radius');
+
+        let newvalue;
+        if (relX < handleRadius)
+            newvalue = 0;
+        else if (relX > width - handleRadius)
+            newvalue = 1;
+        else
+            newvalue = (relX - handleRadius) / (width - 2 * handleRadius);
+        this._value = newvalue;
+        this.actor.queue_repaint();
+        this.emit('value-changed', this._value);
+    },
+
+    get value() {
+        return this._value;
+    }
+});
+
+Signals.addSignalMethods(Slider.prototype);


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]