Revision: 4491
          http://vexi.svn.sourceforge.net/vexi/?rev=4491&view=rev
Author:   clrg
Date:     2013-03-14 02:47:29 +0000 (Thu, 14 Mar 2013)
Log Message:
-----------
Mouse3 drag support

Added Paths:
-----------
    
branches/org.vexi-vexi.widgets_editrefactor/src_main/org/vexi/lib/widget/scrollbar.t

Added: 
branches/org.vexi-vexi.widgets_editrefactor/src_main/org/vexi/lib/widget/scrollbar.t
===================================================================
--- 
branches/org.vexi-vexi.widgets_editrefactor/src_main/org/vexi/lib/widget/scrollbar.t
                                (rev 0)
+++ 
branches/org.vexi-vexi.widgets_editrefactor/src_main/org/vexi/lib/widget/scrollbar.t
        2013-03-14 02:47:29 UTC (rev 4491)
@@ -0,0 +1,366 @@
+<!-- Copyright 2009 - see COPYING for details [LGPL] -->
+
+<vexi xmlns:ui="vexi://ui" xmlns:meta="vexi://meta" xmlns="org.vexi.lib.role">
+    <meta:doc>
+        <author>Charles Goodwin</author>
+        <usage>
+            * th_thumb should be a role.draggable
+            * viewport should have the structure:
+                <box layout="place"><box /></box>
+        </usage>
+    </meta:doc>
+    
+    <polarizable />
+    <ui:box>
+        
+        // public variables
+        thisbox.lineheight = vexi.ui.font.height(font, fontsize, "dp");
+        thisbox.mwheelshift = 4;
+        thisbox.pageshift;
+        thisbox.autohide;
+        thisbox.enabled = true;
+        thisbox.hide;
+        thisbox.minthumbsize;
+        thisbox.shift;
+        thisbox.uiport;
+        thisbox.viewport;
+        
+        // theme box variables
+        thisbox.th_back;
+        thisbox.th_next;
+        thisbox.th_thumb;
+        thisbox.th_track;
+        
+        // private variables
+        var listeners = {};
+        var percent;
+        var percentset;
+        var trackpos;
+        
+        // for efficient lookups
+        var max = vexi.math.max;
+        var min = vexi.math.min;
+        var thumb, track;
+        var vport, varea;
+        
+        ////////
+        // sync functions
+        
+        /** sync viewport with thumb position */
+        const syncViewport = function() {
+            if (vport and varea)
+                varea[pos] = percent * (vport[dim] - varea[dim]);
+        }
+        
+        /** sync specific listener with viewport position */
+        const syncListener = function(v) {
+            if (v and v[0]) v[0][pos] = percent * (v[dim] - v[0][dim]);
+        }
+        
+        /** syncs all listeners with viewport position */
+        const syncAllListeners = function(v) {
+            if (motion) {
+                for (var key in listeners) {
+                    if (v == key) continue;
+                    syncListener(key);
+                }
+            }
+        }
+        
+        /** sync thumb with viewport size and position */
+        const syncThumb = function() {
+            // don't do much if we're hidden
+            if (hide) display = false;
+            // conditions where thumb placement is not [yet] desirable
+            else if (!surface || vport == null || varea == null || vport[dim] 
>= varea[dim]) {
+                if (enabled) enabled = false;
+                if (autohide) display = false;
+                else {
+                    thumb[dim] = track[dim];
+                    thumb[pos] = 0;
+                }
+            // display, size, and place thumb
+            } else {
+                if (!enabled) enabled = true;
+                if (!display) display = true;
+                thumb[dim] =
+                    max(minthumbsize,
+                        min(track[dim],
+                            (vport[dim] / varea[dim]) * track[dim]));
+                thumb[pos] = max(0, (track[dim] - thumb[dim]) * percent);
+            }
+        }
+        
+        ////////
+        // trap functions to invoke sync
+        
+        /** invokes sync funcs on all but listener trapee */
+        const listenerMove = function(v) {
+            if (trapee[trapname] == v) return;
+            cascade = v;
+            if (percentset or !trapee.constrain) return;
+            percentset = true;
+            percent = trapee[0][pos] / (trapee[0][dim] - trapee[dim]);
+            syncAllListeners(trapee);
+            syncViewport();
+            percentset = false;
+        }
+        
+        /** listener resized - sync with viewport */
+        const listenerResize = function(v) { cascade = v; 
syncListener(trapee); }
+        
+        const syncThumbTrap = function(v) { cascade = v; syncThumb(); }
+        
+        const viewportMove = function(v) {
+            cascade = min(0, max(v, vport[dim] - varea[dim]));
+            if (percentset) return;
+            percentset = true;
+            percent = varea[pos] / (vport[dim] - varea[dim]);
+            syncThumb();
+            syncAllListeners();
+            percentset = false;
+        }
+        
+        /** viewport or varea resized */
+        const viewportResize = function(v) {
+            cascade = v;
+            if (percentset) return;
+            // avoid resetting percent
+            percentset = true;
+            // viewport bigger than view subject
+            if (vport[dim] >= varea[dim]) varea[pos] = 0;
+            // constrain viewport position
+            else varea[pos] = -percent * (varea[dim] - vport[dim]);
+            // sync thumbsize to viewport
+            syncThumb();
+            percentset = false;
+        }
+        
+        /** vertical mousewheel movement */
+        const mwheelWrite = function(v) {
+            shift = lineheight * v * mwheelshift;
+            return;
+        }
+        
+        ////////
+        // public functions
+        
+        /** add listener (weak viewport) to the scrollbar */
+        thisbox.addListener = function(v) {
+            listeners[v] = true;
+            v[dim] ++= listenerResize;
+            v[0][dim] ++= listenerResize;
+            v[0][pos] ++= listenerMove;
+            syncListener(v);
+        }
+        
+        /** remove listener (weak viewport) to the scrollbar */
+        thisbox.removeListener = function(v) {
+            if (listeners[v] != null) {
+                listeners[v][dim] --= listenerResize;
+                listeners[v][0][dim] --= listenerResize;
+                listeners[v][0][pos] --= listenerMove;
+                (keysof(listeners)).remove(v);
+            }
+        }
+        
+        ////////
+        // public property traps
+        
+        autohide     ++= syncThumbTrap;
+        minthumbsize ++= static.minthumbsizeWrite;
+        pageshift    ++= static.pageshiftRead;
+        v_container  ++= static.containerWrite;
+        
+        /** adjust scrollbar orient - "horizontal" or "vertical" */
+        orient ++= function(v) {
+            if (v == orient) return;
+            cascade = v;
+            // reassign track traps
+            if (track) {
+                track[flip(dim)] --= syncThumbTrap;
+                track[dim] ++= syncThumbTrap;
+                track[flip(mindim)] = 0;
+                track[mindim] = minthumbsize;
+            }
+            // reassign viewport traps
+            if (vport) {
+                if (!varea) throw "viewport must have a child";
+                // react to viewport resize
+                vport[flip(dim)] --= viewportResize;
+                vport[dim] ++= viewportResize;
+                // react to viewarea resize
+                varea[flip(dim)] --= viewportResize;
+                varea[dim] ++= viewportResize;
+                // react to viewarea movement
+                varea[flip(pos)] --= viewportMove;
+                varea[pos] ++= viewportMove;
+            }
+            // reassign uiport traps
+            if (uiport) {
+                uiport[flip(mousewheel)] --= mwheelWrite;
+                uiport[mousewheel] ++= mwheelWrite;
+            }
+            // reassign listener traps
+            const olddim = flip(dim);
+            const oldpos = flip(pos);
+            const newdim = dim;
+            const newpos = pos;
+            for (var key in listeners) {
+                dim = olddim;
+                pos = oldpos;
+                removeListener(key);
+                dim = newdim;
+                pos = newpos;
+                addListener(key);
+            }
+        }
+        
+        /** attempt to shift viewport by given amount */
+        shift ++= function(v) {
+            varea[pos] =
+                min(0,
+                    max(vport[dim] - varea[dim],
+                        varea[pos] - v));
+            return;
+        }
+        
+        /** set up viewport */
+        viewport ++= function(v) {
+            // clean up old viewport
+            if (vport) {
+                if (!varea) throw "viewport must have a child";
+                vport[dim] --= viewportResize;
+                varea[dim] --= viewportResize;
+                varea[pos] --= viewportMove;
+            }
+            // set up new viewport
+            if (v) {
+                if (!v[0]) throw "viewport must have a child";
+                v[dim] ++= viewportResize;
+                v[0][dim] ++= viewportResize;
+                v[0][pos] ++= viewportMove;
+            }
+            cascade = v;
+            vport = v;
+            varea = v ? v[0] : null;
+            syncThumb();
+        }
+        
+        ////////
+        // theme trap assignments
+        
+        /** move up a line */
+        const backAction = function(a) { shift = -lineshift; cascade = a; }
+        
+        /** set up back button */
+        th_back ++= function(v) {
+            v.action ++= backAction;
+            v.focusable = false;
+            cascade = v;
+        }
+        
+        /** move down a line */
+        const nextAction = function(a) { shift = lineshift; cascade = a; }
+        
+        /** set up next button */
+        th_next ++= function(v) {
+            v.action ++= nextAction;
+            v.focusable = false;
+            cascade = v;
+        }
+        
+        /** invokes a pageshift in appropriate direction */
+        const trackAction = function(a) {
+            const trackpos = track.mouse[pos];
+            if (thumb[pos] > trackpos) shift = -pageshift;
+            else if (trackpos > thumb[pos] + thumb[dim]) shift = pageshift; 
+            cascade = a;
+        }
+        
+        /** set up track */
+        th_track ++= function(v) {
+            v[dim] ++= syncThumbTrap;
+            v.action ++= trackAction;
+            v[mindim] = minthumbsize;
+            cascade = v;
+            track = v;
+        }
+        
+        /** thumb is moved by user */
+        var lastpos;
+        var limitpos;
+        var startpos;
+        const thumbStart = function(v) {
+            motion = true;
+            startpos = v==1 ? thumb[pos] : varea[pos];
+            limitpos = v==1 ? track[dim] - thumb[dim] : vport[dim] - 
varea[dim];
+            return;
+        }
+        const thumbStop = function(v) { motion = false; lastpos = null; 
return; }
+        const thumbMove = function(d) { trace(d);
+            // avoid duplicates (when flip(pos) changes)
+            if (d[pos] == lastpos) return;
+            lastpos = d[pos];
+            // RMB drags relative to the content
+            if (d.button == 2) {
+                varea[pos] = min(0, max(limitpos, startpos - d[pos]));
+                return;
+            }
+            // LMB drags relative to the scrollbar
+            thumb[pos] = max(0, min(limitpos, startpos + d[pos]));
+            if (percentset) return;
+            // set percent according to thumb
+            percentset = true;
+            percent = thumb[pos] / (track[dim] - thumb[dim]);
+            syncViewport();
+            syncAllListeners();
+            percentset = false;
+            return;
+        }
+        
+        /** set up scrollbar thumb */
+        th_thumb ++= function(v) {
+            v.dragUpdate ++= thumbMove;
+            v.dragStart ++= thumbStart;
+            v.dragStop ++= thumbStop;
+            v.dragButton = 2;
+            cascade = v;
+            thumb = v;
+        }
+        
+        /** set up ui port (see scrollpane uiport) in case viewport is virtual 
*/
+        uiport ++= function(v) {
+            v[mousewheel] ++= mwheelWrite;
+            // uiport should implement role.draggable
+            v.dragUpdate ++= thumbMove;
+            v.dragStart ++= thumbStart;
+            v.dragStop ++= thumbStop;
+            v.dragButton = 3;
+            cascade = v;
+        }
+        
+    </ui:box>
+    
+    /** scrollbars can not have content */
+    static.containerWrite = function(v) { cascade = v; trapee.v_content = 
null; }
+    
+    /** updates the lineheight as used by mousewheel scrolling */
+    static.fontWrite = function(v) {
+        cascade = v;
+        trapee.lineheight = vexi.ui.font.height(trapee.font, trapee.fontsize, 
"dp");
+    }
+    
+    /** constrain track to minimum size of thumb */
+    static.minthumbsizeWrite = function(v) {
+        cascade = v;
+        if (trapee.th_track) trapee.th_track[trapee.mindim] = v;
+    }
+    
+    /** return amount by which to shift a full page */
+    static.pageshiftRead = function() {
+        if (trapee.viewport) return 0.9 * (trapee.viewport[trapee.dim]);
+        else return 0;
+    }
+    
+</vexi>

This was sent by the SourceForge.net collaborative development platform, the 
world's largest Open Source development site.


------------------------------------------------------------------------------
Everyone hates slow websites. So do we.
Make your web apps faster with AppDynamics
Download AppDynamics Lite for free today:
http://p.sf.net/sfu/appdyn_d2d_mar
_______________________________________________
Vexi-svn mailing list
Vexi-svn@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/vexi-svn

Reply via email to