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