Revision: 4304
          http://vexi.svn.sourceforge.net/vexi/?rev=4304&view=rev
Author:   mkpg2
Date:     2011-12-12 01:05:02 +0000 (Mon, 12 Dec 2011)
Log Message:
-----------
New widget. Duration field.

Added Paths:
-----------
    trunk/org.vexi-vexi.widgets/src_main/org/vexi/lib/util/abstractlexer.t
    trunk/org.vexi-vexi.widgets/src_main/org/vexi/lib/widget/durationfield.t
    trunk/org.vexi-vexi.widgets/src_main/org/vexi/theme/classic/durationfield.t
    trunk/org.vexi-vexi.widgets/src_main/vexi/widget/durationfield.t
    trunk/org.vexi-vexi.widgets/src_poke/poke/widgets/durationfield.t
    trunk/org.vexi-vexi.widgets/src_test/test/widget/durationfield.t

Added: trunk/org.vexi-vexi.widgets/src_main/org/vexi/lib/util/abstractlexer.t
===================================================================
--- trunk/org.vexi-vexi.widgets/src_main/org/vexi/lib/util/abstractlexer.t      
                        (rev 0)
+++ trunk/org.vexi-vexi.widgets/src_main/org/vexi/lib/util/abstractlexer.t      
2011-12-12 01:05:02 UTC (rev 4304)
@@ -0,0 +1,162 @@
+<!-- Copyright 2011 Web Enable IT -- all rights reserved -->
+
+<vexi xmlns:ui="vexi://js" xmlns:meta="vexi://meta">
+    <meta:doc>
+        <author>Mike Goodwin</author>
+        <name></name>
+        <desc></desc>
+        <usage></usage>
+    </meta:doc>
+        
+    // constants
+    const C0 = "0".charCodeAt(0);
+    const C9 = "9".charCodeAt(0);
+    const CA = "A".charCodeAt(0);
+    const CZ = "Z".charCodeAt(0);
+    const Ca = "a".charCodeAt(0);
+    const Cz = "z".charCodeAt(0);
+    const C_ = "_".charCodeAt(0);
+    
+    // || c == '\u0020' || c == '\u0009' || c == '\u000C' || c == '\u000B'
+    static.isWhitespace = function(c) { return c ==" " || c == "\n" || c == 
"\r" || c=="\t"; };  
+    static.isDigit = function(code) { return code >= C0 and C9 >= code; }
+    static.isDigitOrDot = function(c) { 
+        return c!=null and (isDigit(c.charCodeAt(0)) || c=="."); 
+    }
+    static.isIdStart = function(code) {
+        return (code >= CA and CZ >= code) || (code >= Ca and Cz >= code) || 
code==C_;
+    };
+    static.isId = function(c) {
+        if(c == null) return null;
+        const code = c.charCodeAt(0);
+        
+        //vexi.log.info(c + " " +code + " " + isIdStart(code) + " " + 
isDigit(code));
+        return isIdStart(code) || isDigit(code);
+    };
+    
+    
+    <ui:Object>
+
+        thisobj.lexToken;            // implement ...
+      
+        const cstack = [];  // reader char stack
+        const tstack = [];  // token stack
+        const ostack = [];  // object stack (strings/numbers)
+
+        var utf8reader;
+        thisobj.reader = {};       // Pushback Reader
+        
+        reader.c ++= function() {
+             if (cstack.length==0) return utf8reader["char"];
+             else return cstack.pop();       
+        };
+        
+        reader.c ++= function(v) {
+            cstack.push(v);
+            return;
+        };
+        
+        reader.peek ++= function(v) {
+            var ret = reader.c;
+            reader.c = ret;
+            return ret;
+        };
+    
+        
+        var tok;     // last token parsed
+        thisobj.obj; // obj (string/number)
+        
+        thisobj.init = function(s) {
+            cstack.clear();
+            tstack.clear();
+            ostack.clear();
+            
+            tok = null;
+            obj = null;
+            
+            // INIT
+            if (typeof(s)=="string") {
+                //vexi.log.info("Lexing: " + arguments[0]);
+                utf8reader = vexi.stream.utf8reader(vexi.stream.fromString(s));
+            } else {
+                throw "expected expression string as argument, got " + 
typeof(s); 
+            } 
+        }
+        
+
+        const isId = static.isId;
+        const isDigitOrDot = static.isDigitOrDot;
+        
+        thisobj.lexIdentifier = function(c) {
+            var arr = [c];
+            while (isId(c = reader.c)) arr.push(c);
+            reader.c = c; //pushback
+            obj = arr.join("");
+            var kw = keywords?[obj];
+            if (kw) return kw;
+            tok = "NAME";
+            return tok;
+        }
+        
+        thisobj.lexNumber = function(c) {
+            var arr = [c];
+            while (isDigitOrDot(c = reader.c)) arr.push(c);
+            reader.c = c; //pushback
+            var str = arr.join("");
+            if (str.indexOf(".") == -1)
+                obj = vexi.string.parseInt(str);
+            else obj = vexi.string.parseFloat(str);
+            tok = "NUMBER";
+            return tok;
+        };
+        
+        thisobj.lexString = function(c) {
+            var arr = [];
+            var quote = c;
+            
+            while ((c = reader.c) != quote) {
+                if (c == "\n" || c == null) throw "unterminated string 
literal";
+                arr.push(c);
+            }
+            obj = arr.join("");
+            tok = "STRING";
+            return tok;
+        }
+        
+        thisobj.match = function(exp) {
+            var c = reader.c;
+            if (c == exp) return true;
+            reader.c = c;
+        };
+        
+        thisobj.le = function(msg) {
+            throw msg;
+        };
+        
+        thisobj.pushBack = function() {
+            ostack.push(obj);
+            tstack.push(tok);
+        };
+        
+        thisobj.peekToken = function() {
+               var r = nextToken();
+               ostack.push(obj);
+               tstack.push(r);
+            return r;
+        };
+        
+        thisobj.nextToken = function() {
+            obj = null;
+            if (tstack.length>0) {
+                tok = tstack.pop();
+                obj = ostack.pop();
+            } else {
+                tok = lexToken();
+            }
+            return tok;
+        };
+        
+
+        
+    </ui:Object>
+</vexi>

Added: trunk/org.vexi-vexi.widgets/src_main/org/vexi/lib/widget/durationfield.t
===================================================================
--- trunk/org.vexi-vexi.widgets/src_main/org/vexi/lib/widget/durationfield.t    
                        (rev 0)
+++ trunk/org.vexi-vexi.widgets/src_main/org/vexi/lib/widget/durationfield.t    
2011-12-12 01:05:02 UTC (rev 4304)
@@ -0,0 +1,197 @@
+<!-- Copyright 2011 - see COPYING for details [LGPL] -->
+
+<vexi xmlns:ui="vexi://ui" xmlns:meta="vexi://meta" xmlns="org.vexi.lib" 
xmlns:sync="vexi.util.sync">
+    <meta:doc>
+        <author>Mike Goodwin</author>
+    </meta:doc>
+    
+    <role.focusable />
+    <role.tooltipable />
+    <text.field />
+    <ui:box>
+        
+        thisbox.v_edit;             // abstract
+        thisbox.enabled = true;        
+      
+        thisbox.value;              // value and the v_edit.text are 
synchronized
+        thisbox.defaultUnit = "h";
+        thisbox.largestUnit = "h";
+
+        thisbox.duration2text = function(d){
+            return static.formatDuration(d, largestUnit);
+        };
+
+        thisbox.text2duration = function(s) {
+            return static.parseDuration(s, defaultUnit);
+        }
+        
+        KeyPressed ++= static.keypressEvent;
+        focused    ++= static.focusWrite;
+        v_edit     ++= static.editWrite;
+        
+        
+    </ui:box>
+    
+    const units = {
+           list: [
+               {"name": "y", "mult": 3600*24*365},
+            {"name": "d", "mult": 3600*24},
+            {"name": "h", "mult": 3600},
+               {"name": "m", "mult": 60  },
+               {"name": "s", "mult": 1}
+           ],
+           get: function(unit){
+               var i = this.getIndex(unit);
+               return this.list[i];
+           },
+           getIndex: function(unit){
+               for(var i,u in this.list){
+                   if(u==unit || u.name==unit) return i; 
+               }
+               return null;
+           },
+           getNextSmallest: function(unit){
+               var i = this.getIndex(unit);
+               if(i!=null and this.list.length>i+1) return this.list[i+1];
+               return null; 
+           },
+           isLarger: function(uA, uB){
+               var iA = this.getIndex(uA);
+            var iB = this.getIndex(uB);
+            if(iA!=null and iB!=null){
+                return iA>iB;
+            }
+            return false;
+           }
+    };
+    
+    
+    static.formatDuration= function(d, largestUnit) {
+        if(d==null) return null;
+        var r = "";
+        var i = units.getIndex(largestUnit);
+        for(; units.list.length>i; i++){
+            var u = units.list[i];
+            var remainder = d%u.mult;
+            var qty = (d-remainder)/u.mult;
+            if(qty>0)
+                r += ""+qty+u.name;
+            d = remainder;
+        }
+        return r;
+    }
+
+    const isWhitespace = .util.abstractlexer..isWhitespace;
+    const isAlpha = .util.abstractlexer..isIdStart;
+    const isDigit = .util.abstractlexer..isDigit;
+    const lexer = new .util.abstractlexer();
+    const lexUnit = function(c){
+        var arr = [c];
+        while (isAlpha(c = lexer.reader.c)) arr.push(c);
+        lexer.reader.c = c; //pushback
+        lexer.obj = arr.join("");
+        return "UNIT";
+    };
+    
+    lexer.lexToken = function(){
+        var c;
+        do{
+            c = lexer.reader.c;
+            if (c==null) return null;
+        } while( isWhitespace(c) ); // || c == '\u0020' || c == '\u0009' || c 
== '\u000C' || c == '\u000B'
+        var code = c.charCodeAt(0);
+        if (isDigit(code)) return lexer.lexNumber(c);
+        if (isAlpha(code)) return lexUnit(c);
+        return null;
+    };
+    
+    
+    
+    const isInt = function(n){ return n==vexi.math.round(n); }
+    const parseSegment = function(top, defaultUnit){
+        defaultUnit = units.get(defaultUnit);
+        var tok = lexer.nextToken();
+        if(tok==null) return 0; 
+        if(tok!="NUMBER") return null;
+        var qty = lexer.obj;
+        
+        var tok2 = lexer.nextToken(); 
+        if(tok2=="UNIT"){
+            var unitSpecified = units.get(lexer.obj);
+            if(unitSpecified==null){
+                return null;
+            }else{
+                // cannot have larger units after smaller ones
+                if(!top and units.isLarger(unitSpecified,defaultUnit)){
+                    return null;
+                }
+                var r = unitSpecified.mult*qty;
+                   if(isInt(qty)){
+                       var nextU = units.getNextSmallest(unitSpecified);
+                       if(nextU!=null){
+                           var nextR = callee(false, nextU);
+                           if(nextR==null) return null;
+                           return r + nextR;
+                       }
+                   }
+                   var tok3 = lexer.nextToken();
+                   if(tok3!=null) return null;
+                   return r;
+            }
+            
+        }else if(tok2==null){
+            return defaultUnit.mult*qty;;
+        }
+    }
+    
+    static.parseDuration = function(s, defaultUnit){
+        lexer.init(s);
+        return parseSegment(true, defaultUnit);
+    }
+    
+    /** set up sync between edit.text and numfield.value */
+    static.editWrite = function(v) {
+        cascade = v;
+        sync..syncTransform(trapee, v, "value", "text", trapee.duration2text, 
trapee.text2duration);
+        trapee[trapname] --= callee;
+    }
+    
+    /** when focus changes, self put text in case text content is updated */
+    static.focusWrite = function(v) {
+        if (!v) {
+            // trigger value setting
+            trapee.value = trapee.text2duration(trapee.v_edit.text);
+        }
+        cascade = v;
+    }
+    
+    /** fire action or filter key in case of password fields */
+    static.keypressEvent = function(v) {
+        var t = trapee;
+        var e = t.v_edit;
+        var txt0 = e.text;
+        
+        switch (v) {
+                   case "ENTER":
+                   case "enter": {
+                       var cpos = e.getCursorCharIndex();
+                       t.value = t.text2duration(e.text);
+                       cpos = vexi.math.max(e.text.length, cpos);
+                       e.setCursorCharIndex(cpos);
+                       return;
+                   }
+                   default: {
+                       var cpos = e.getCursorCharIndex();
+                       cascade = v;
+                       // If invalid revert ...        
+                       var value2 = t.text2duration(e.text);
+                       if(value2==null){
+                           e.text = txt0;
+                           e.setCursorCharIndex(cpos);
+                       }
+                       return;
+                   }
+        }
+    }
+
+</vexi>

Added: 
trunk/org.vexi-vexi.widgets/src_main/org/vexi/theme/classic/durationfield.t
===================================================================
--- trunk/org.vexi-vexi.widgets/src_main/org/vexi/theme/classic/durationfield.t 
                        (rev 0)
+++ trunk/org.vexi-vexi.widgets/src_main/org/vexi/theme/classic/durationfield.t 
2011-12-12 01:05:02 UTC (rev 4304)
@@ -0,0 +1,33 @@
+<!-- Copyright 2011 - see COPYING for details [LGPL] -->
+
+<vexi xmlns:ui="vexi://ui" xmlns:meta="vexi://meta" xmlns="vexi.theme"
+    xmlns:lib="org.vexi.lib">
+    <meta:doc>
+        <author>Charles Goodwin</author>
+    </meta:doc>
+    
+    <lib:widget.durationfield />
+    <lib:widget.shadowtext />
+    <bevel redirect=":$content" form="down" margin="3" padding="3" 
vshrink="true">
+        <ui:box id="inset" layout="place" minheight="19">
+            <ui:box id="content" />
+            <lib:layout.pad id="shadowpad" padding="3" vshrink="true">
+                 <ui:box id="shadow" align="right" textcolor="#999999" />
+            </lib:layout.pad>
+        </ui:box>
+        
+        thisbox.th_bevel = thisbox;
+        thisbox.th_shadowtext = $shadow;
+        thisbox.th_shadowwrap = $shadowpad;
+        thisbox.th_minus = $minus;
+        thisbox.th_view = $inset;
+        thisbox.th_viewport = $content;
+        thisbox.v_init = static.init;
+        thisbox.v_prevfill = .settings..fill;
+        
+    </bevel>
+    <lib.finalize />
+    
+    static.init = { textalign:"right" }
+    
+</vexi>

Added: trunk/org.vexi-vexi.widgets/src_main/vexi/widget/durationfield.t
===================================================================
--- trunk/org.vexi-vexi.widgets/src_main/vexi/widget/durationfield.t            
                (rev 0)
+++ trunk/org.vexi-vexi.widgets/src_main/vexi/widget/durationfield.t    
2011-12-12 01:05:02 UTC (rev 4304)
@@ -0,0 +1,27 @@
+<!-- Copyright 2009 - see COPYING for details [LGPL] -->
+
+<vexi xmlns:ui="vexi://ui" xmlns:meta="vexi://meta" xmlns:theme="vexi.theme"
+    xmlns="org.vexi.lib.layout">
+    <meta:doc>
+        <author>Charles Goodwin</author>
+        <name>Textfield</name>
+        <desc>An editable single-line textfield</desc>
+        <usage>
+            Has the following specific properties:
+            - enabled   (boolean)
+                If set to false, users can not edit the content
+            - maxlength (int)
+                Prevents the textfield content growing longer than
+                maxlength
+            - password  (boolean)
+                A passworded textfield obscures the input text as *s
+                Read 'value' to get the password from the textfield
+        </usage>
+    </meta:doc>
+    
+    <margin />
+    <theme:durationfield />
+    <pad />
+    <editbox />
+    <container />
+</vexi>

Added: trunk/org.vexi-vexi.widgets/src_poke/poke/widgets/durationfield.t
===================================================================
--- trunk/org.vexi-vexi.widgets/src_poke/poke/widgets/durationfield.t           
                (rev 0)
+++ trunk/org.vexi-vexi.widgets/src_poke/poke/widgets/durationfield.t   
2011-12-12 01:05:02 UTC (rev 4304)
@@ -0,0 +1,15 @@
+
+<vexi xmlns:ui="vexi://ui" 
+      xmlns:w="vexi.widget" 
+      xmlns:sync="vexi.util.sync">
+    <w:surface />
+    <ui:box orient="vertical">
+
+        <w:numfield id="number" />
+        <w:durationfield id="duration" />
+        sync..sync($number,$duration,"value","value");
+
+        vexi.ui.frame = thisbox;
+        
+    </ui:box>
+</vexi>

Added: trunk/org.vexi-vexi.widgets/src_test/test/widget/durationfield.t
===================================================================
--- trunk/org.vexi-vexi.widgets/src_test/test/widget/durationfield.t            
                (rev 0)
+++ trunk/org.vexi-vexi.widgets/src_test/test/widget/durationfield.t    
2011-12-12 01:05:02 UTC (rev 4304)
@@ -0,0 +1,38 @@
+<vexi xmlns:meta="vexi://meta" xmlns:ui="vexi://ui" xmlns="vexi.widget">
+    <meta:doc>
+        <author>Charles Goodwin</author>
+    </meta:doc>
+
+    /// Quick Suite
+    var suite = {};
+
+    var vunit = vexi..vexi.test.vunit;
+    var assertEq = vunit..assertEq;
+    var assertExceptionThrown = vunit..assertExceptionThrown;
+
+    suite.testBasic = function() {
+        /**
+        *  basic numfield value write tests
+        */
+        var b = new .durationfield();
+        b.value = 123;
+        assertEq("2m3s",b.text);
+        b.text = "2m4s";
+        assertEq(124,b.value);
+        b.text = "2m5";
+        assertEq(125,b.value);
+        b.text = "1";
+        assertEq(3600,b.value);
+    };
+    
+    suite.testEmpty = function() {
+        var b = new .durationfield();
+        b.focused = true;
+        b.KeyPressed = "enter";
+    };
+    
+    static.test = suite;
+   
+    <surface/>
+        
+</vexi>
\ No newline at end of file

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


------------------------------------------------------------------------------
Learn Windows Azure Live!  Tuesday, Dec 13, 2011
Microsoft is holding a special Learn Windows Azure training event for 
developers. It will provide a great way to learn Windows Azure and what it 
provides. You can attend the event by watching it streamed LIVE online.  
Learn more at http://p.sf.net/sfu/ms-windowsazure
_______________________________________________
Vexi-svn mailing list
Vexi-svn@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/vexi-svn

Reply via email to