[Laszlo-checkins] r12743 - in openlaszlo/trunk: WEB-INF/lps/config WEB-INF/lps/lfc/kernel/dhtml WEB-INF/lps/lfc/kernel/swf WEB-INF/lps/lfc/kernel/swf9 WEB-INF/lps/lfc/views lps/components/base lps/components/debugger lps/components/incubator lps/components/incubator/test

ptw@openlaszlo.org ptw at openlaszlo.org
Tue Feb 3 20:06:20 PST 2009


Author: ptw
Date: 2009-02-03 20:06:10 -0800 (Tue, 03 Feb 2009)
New Revision: 12743

Modified:
   openlaszlo/trunk/WEB-INF/lps/config/lps.properties
   openlaszlo/trunk/WEB-INF/lps/lfc/kernel/dhtml/LzInputTextSprite.js
   openlaszlo/trunk/WEB-INF/lps/lfc/kernel/dhtml/LzSprite.js
   openlaszlo/trunk/WEB-INF/lps/lfc/kernel/dhtml/LzTextSprite.js
   openlaszlo/trunk/WEB-INF/lps/lfc/kernel/swf/LzSprite.as
   openlaszlo/trunk/WEB-INF/lps/lfc/kernel/swf/LzTextSprite.as
   openlaszlo/trunk/WEB-INF/lps/lfc/kernel/swf9/LzInputTextSprite.as
   openlaszlo/trunk/WEB-INF/lps/lfc/kernel/swf9/LzSprite.as
   openlaszlo/trunk/WEB-INF/lps/lfc/kernel/swf9/LzTextSprite.as
   openlaszlo/trunk/WEB-INF/lps/lfc/views/LaszloCanvas.lzs
   openlaszlo/trunk/WEB-INF/lps/lfc/views/LaszloView.lzs
   openlaszlo/trunk/WEB-INF/lps/lfc/views/LzInputText.lzs
   openlaszlo/trunk/WEB-INF/lps/lfc/views/LzText.lzs
   openlaszlo/trunk/lps/components/base/basescrollbar.lzx
   openlaszlo/trunk/lps/components/debugger/newcontent.lzx
   openlaszlo/trunk/lps/components/incubator/scrolledittext.lzx
   openlaszlo/trunk/lps/components/incubator/test/newvscrollbar-test.lzx
   openlaszlo/trunk/lps/components/incubator/test/scrolledittext-test.lzx
Log:
Change 20090130-ptw-t by ptw at dueling-banjos.home on 2009-01-30 18:08:40 EST
    in /Users/ptw/OpenLaszlo/trunk-4
    for http://svn.openlaszlo.org/openlaszlo/trunk

Summary: Implement LFC end of kernel scrolling API

Bugs Fixed: LPP-6580  scrolledittext doesn't work in 4.1 (partial)

Technical Reviewer: max (pending)
QA Reviewer: hminsky (Message-ID: <8c61fad60902031852s6489a342la9d5aa0aab396fd4 at mail.gmail.com>)

Details:
    LzSprite.*, LaszloView, LaszloCanvas: Add linescrolling
    capability, unify capabilities as a sprite instance var.

    swf/LzTextSprite.as: Turn on warnUndefinedReferences so we can
    debug this.  Stop making all sorts of undefined references.
    Actually compute `lineheight`.  Use that to implement the
    pixel/line kernel API.  Convert __updatefieldsize to use the new
    scrollevent kernel API.

    swf9/LzTextSprite: Add primitive version of setX/YScroll

    LzInputText: Set tsprite in __makeSprite

    LzText: Implement new kernel scrolling API.  Cache tsprite for
    efficiency.

    newcontent, basescrollbar: Silence warnings.

    scrolledittext: Use new API's

    test/*: Max's improved tests

Tests:
    Compiles in swf9, smokecheck in 3 runtimes, component debugger in
    swf8/9, component sampler in 3 runtimes.



Modified: openlaszlo/trunk/WEB-INF/lps/config/lps.properties
===================================================================
--- openlaszlo/trunk/WEB-INF/lps/config/lps.properties	2009-02-04 02:40:23 UTC (rev 12742)
+++ openlaszlo/trunk/WEB-INF/lps/config/lps.properties	2009-02-04 04:06:10 UTC (rev 12743)
@@ -165,7 +165,7 @@
 compiler.swf9.warnings=false
 compiler.swf9.execflex=false
 # Tell swf9 compiler to catch errors in debug mode
-#compiler.swf9.catcherrors=true
+compiler.swf9.catcherrors=true
 
 
 #===============================================================================

Modified: openlaszlo/trunk/WEB-INF/lps/lfc/kernel/dhtml/LzInputTextSprite.js
===================================================================
--- openlaszlo/trunk/WEB-INF/lps/lfc/kernel/dhtml/LzInputTextSprite.js	2009-02-04 02:40:23 UTC (rev 12742)
+++ openlaszlo/trunk/WEB-INF/lps/lfc/kernel/dhtml/LzInputTextSprite.js	2009-02-04 04:06:10 UTC (rev 12743)
@@ -899,6 +899,14 @@
     }    
 }
 
+LzInputTextSprite.prototype.setYScroll = function (n){
+  this.__LzInputDiv.scrollTop = (- n);
+}
+
+LzInputTextSprite.prototype.setXScroll = function (n){
+  this.__LzInputDiv.scrollLeft = (- n);
+}
+
 LzInputTextSprite.prototype.setWidth = function (w) {
     if (w == null || w < 0 || isNaN(w) || this.width == w) return;
     // call LzSprite.setWidth();

Modified: openlaszlo/trunk/WEB-INF/lps/lfc/kernel/dhtml/LzSprite.js
===================================================================
--- openlaszlo/trunk/WEB-INF/lps/lfc/kernel/dhtml/LzSprite.js	2009-02-04 02:40:23 UTC (rev 12742)
+++ openlaszlo/trunk/WEB-INF/lps/lfc/kernel/dhtml/LzSprite.js	2009-02-04 04:06:10 UTC (rev 12743)
@@ -383,6 +383,7 @@
     ,runtimemenus: false
     ,setclipboard: false
     ,proxypolicy: false
+    ,linescrolling: false
 }
 
 LzSprite.prototype.__updateQuirks = function () {

Modified: openlaszlo/trunk/WEB-INF/lps/lfc/kernel/dhtml/LzTextSprite.js
===================================================================
--- openlaszlo/trunk/WEB-INF/lps/lfc/kernel/dhtml/LzTextSprite.js	2009-02-04 02:40:23 UTC (rev 12742)
+++ openlaszlo/trunk/WEB-INF/lps/lfc/kernel/dhtml/LzTextSprite.js	2009-02-04 04:06:10 UTC (rev 12743)
@@ -438,6 +438,14 @@
     }
 }
 
+LzTextSprite.prototype.setYScroll = function (n){
+  this.__LZtextdiv.scrollTop = (- n);
+}
+
+LzTextSprite.prototype.setXScroll = function (n){
+  this.__LZtextdiv.scrollLeft = (- n);
+}
+
 LzTextSprite.prototype.__setWidth = LzSprite.prototype.setWidth;
 LzTextSprite.prototype.setWidth = function (w, force){
     if (w == null || w < 0 || isNaN(w) || (this.width == w && !force)) return;

Modified: openlaszlo/trunk/WEB-INF/lps/lfc/kernel/swf/LzSprite.as
===================================================================
--- openlaszlo/trunk/WEB-INF/lps/lfc/kernel/swf/LzSprite.as	2009-02-04 02:40:23 UTC (rev 12742)
+++ openlaszlo/trunk/WEB-INF/lps/lfc/kernel/swf/LzSprite.as	2009-02-04 04:06:10 UTC (rev 12743)
@@ -70,6 +70,7 @@
     ,runtimemenus: true
     ,setclipboard: true
     ,proxypolicy: true
+    ,linescrolling: true
 }
 
 /** Turns accessibility on by showing/hiding the global yellow flash focusrect

Modified: openlaszlo/trunk/WEB-INF/lps/lfc/kernel/swf/LzTextSprite.as
===================================================================
--- openlaszlo/trunk/WEB-INF/lps/lfc/kernel/swf/LzTextSprite.as	2009-02-04 02:40:23 UTC (rev 12742)
+++ openlaszlo/trunk/WEB-INF/lps/lfc/kernel/swf/LzTextSprite.as	2009-02-04 04:06:10 UTC (rev 12743)
@@ -7,7 +7,8 @@
   * @topic Kernel
   * @subtopic AS2
   */
-
+{
+#pragma "warnUndefinedReferences=true"
 var LzTextSprite = function(newowner, args) {
     if (newowner == null) return this;
     this.__LZdepth = newowner.immediateparent.sprite.__LZsvdepth++;
@@ -17,9 +18,9 @@
     this._accProps = {};
 
     //inherited attributes, documented in view
-    this.fontname = args.font;
-    this.fontsize = args.fontsize;
-    this.fontstyle = args.fontstyle;
+    if (args['font']) this.fontname = args.font;
+    if (args['fontsize']) this.fontsize = args.fontsize;
+    if (args['fontstyle']) this.fontstyle = args.fontstyle;
     this.sizeToHeight = false;
 
     this.yscroll = 0;
@@ -28,7 +29,7 @@
     //@field Boolean resize:  text width automatically resizes when text is set.
     // default: false
     // 
-    this.resize = (args.resize == true);
+    this.resize = (args['resize'] == true);
 
     ////////////////////////////////////////////////////////////////
 
@@ -56,7 +57,7 @@
     ///   textclip._highquality = 2;
 
     // default to bitmap caching being on 
-    if (args.cachebitmap == null) args.cachebitmap = true;
+    if (args['cachebitmap'] == null) args.cachebitmap = true;
 }
 
 LzTextSprite.prototype = new LzSprite(null);
@@ -69,7 +70,7 @@
 LzTextSprite.prototype.textcolor = 0x0; // black
 
 LzTextSprite.prototype.__initTextProperties = function (args) {
-    this.password = args.password  ? true : false;
+    this.password = args['password']  ? true : false;
     var textclip = this.__LZtextclip;
     textclip.password = this.password;
 
@@ -79,7 +80,7 @@
     textclip.selectable = args.selectable;
     textclip.autoSize = false;
 
-    this.setMultiline( args.multiline );
+    this.setMultiline( (!! args['multiline']) );
 
     //inherited attributes, documented in view
     this.fontname = args.font;
@@ -130,7 +131,7 @@
     this.scrollheight = this.height;
 
     textclip.onScroller = this.__updatefieldsize;
-
+    textclip.onScroller();
 }
 
 
@@ -140,7 +141,7 @@
   * @access private
   */
 LzTextSprite.prototype.getMCRef = function () {
-    return this.__LZtextclip;
+    return this['__LZtextclip'];
 }
 
 
@@ -174,6 +175,10 @@
   * @access private
   */
 LzTextSprite.prototype.maxhscroll = 0;
+/**
+ * @access private
+ */
+LzTextSprite.prototype.lineheight = 1;
 
 // [todo: 2004-3-29 hqm] lines seem to get the ends clipped off if you use the TextField.textWidth
 // from Flash, so I am adding a constant. Am I missing something here? 
@@ -213,7 +218,10 @@
   * @access private
   */
 LzTextSprite.prototype.setWidth = function ( val ){
-    this.__LZtextclip._width = val;
+    if (this['__LZtextclip']) {
+      this.__LZtextclip._width = val;
+      this.__LZforceScrollAttrs();
+    }
     this._viewsetWidth( val );
     // recalculate height
     if (this.sizeToHeight) {
@@ -228,7 +236,10 @@
   * @access private
   */
 LzTextSprite.prototype.setHeight = function ( val ){
-    this.__LZtextclip._height = val;
+    if (this['__LZtextclip']) {
+      this.__LZtextclip._height = val;
+      this.__LZforceScrollAttrs();
+    }
     this._viewsetHeight( val );
 }
 LzTextSprite.prototype._viewsetHeight = LzSprite.prototype.setHeight;
@@ -402,6 +413,14 @@
     if (this.onxscroll.ready) this.onxscroll.sendEvent(this.__LZtextclip._x);
 }
 
+LzTextSprite.prototype.lineNoToPixel = function (n:Number):Number {
+  return (n - 1) * this.lineheight;
+}
+
+LzTextSprite.prototype.pixelToLineNo = function (n:Number):Number {
+  return Math.ceil(n / this.lineheight) + 1;
+}
+
 /**
   * Set the y scroll position of the textfield.
   * @param Number n: set the top line of the textfield to offset n pixels
@@ -433,15 +452,15 @@
         // and call the Flash line scroll function to scroll the rest of the way.
         // compute how many lines to scroll the flash text field
         var lh = this.lineheight;
-        var dy = (rh - lh) - this.height;
+        var dy = rh  - this.height;
         var excess = (- this.yscroll) - dy;
         var nlines = Math.floor(excess/lh);
 
         // pixels remainder of line height
         var frac = Math.round(excess - (nlines * lh));
         //Debug.write("fraction="+fraction);
-        /// +++ CHECK THIS HOW YOU SCROLL TEXT6
-        this.__LZtextclip.scroll = nlines;
+        // lines are 1-based
+        this.__LZtextclip.scroll = nlines + 1;
         // need to figure out where to put the fraction (add or subtract??)
         this.__LZtextclip._y = - Math.floor((dy + frac));
     }
@@ -554,7 +573,7 @@
 
     // If accessibility is enabled, hunt for <img alt="...."> tags and assign and
     // put the alt tag somewhere a screen reader can find it.
-    if (canvas.accessible) {
+    if (canvas['accessible']) {
         t = this.annotateAAimg(t);
     }
 
@@ -582,9 +601,11 @@
 
     // Fix for lpp-5449 (reset the selection if the new text is not
     // within it)
-    var l = t.length;
-    if (this._selectionstart > l || this._selectionend > l) {
+    if (this['_selectionstart']) {
+      var l = t.length;
+      if (this._selectionstart > l || this._selectionend > l) {
         this.setSelection(l);
+      }
     }
 }
 
@@ -668,15 +689,16 @@
     // We want to adjust the current contents, _and_ any new contents.
     this.__LZtextclip.setNewTextFormat(tf);
     this.__LZtextclip.setTextFormat(tf);
+    var lh = tf.getTextExtent('__ypgSAMPLE__').height;
+    if (lh !== this.lineheight) {
+      this.lineheight = lh;
+      // Tell the owner the linescale has changed
+      this.owner.scrollevent('lineHeight', lh);
+    }
 }
 
 LzTextSprite.prototype.setFontInfo = function () {
     this.font = LzFontManager.getFont( this.fontname , this.fontstyle );
-
-    if (this.font != null) {
-        this.lineheight = this.font.leading + ( this.font.height *
-                                                this.fontsize/ this.DEFAULT_SIZE );
-    }
 }
 
 /**
@@ -851,22 +873,28 @@
   * __LZtextclip from __LZforceScrollAttrs
   */
 LzTextSprite.prototype.__updatefieldsize = function ( ){
-    if ( this.__lzview.scroll != this.scroll) {
-        this.__lzview.scroll = this.scroll;
-        if (this.__lzview.onscroll.ready) this.__lzview.onscroll.sendEvent(this.scroll)
-    }
-    if (this.__lzview.maxscroll != this.maxscroll) {
-        this.__lzview.maxscroll = this.maxscroll;
-        if (this.__lzview.onmaxscroll.ready) this.__lzview.onmaxscroll.sendEvent(this.maxscroll)
-    }
-    if (this.__lzview.hscroll != this.hscroll) {
-        this.__lzview.hscroll = this.hscroll;
-        if (this.__lzview.onhscroll.ready) this.__lzview.onhscroll.sendEvent(this.hscroll)
-    }
-    if (this.__lzview.maxhscroll != this.maxhscroll) {
-        this.__lzview.maxhscroll = this.maxhscroll;
-        if (this.__lzview.onmaxhscroll.ready) this.__lzview.onmaxhscroll.sendEvent(this.maxhscroll)
-    }
+  var lzv = this.__lzview;
+  var tsprite = lzv.tsprite;
+  var scroll = this.scroll;
+  if ( tsprite.scroll !== scroll) {
+    tsprite.scroll = scroll;
+    lzv.scrollevent('scrollTop', tsprite.lineNoToPixel(scroll));
+  }
+  var maxscroll = this.maxscroll;
+  if (tsprite.maxscroll !== maxscroll) {
+    tsprite.maxscroll = maxscroll;
+    lzv.scrollevent('scrollHeight', tsprite.lineNoToPixel(maxscroll) + tsprite.height);
+  }
+  var hscroll = this.hscroll;
+  if (tsprite.hscroll !== hscroll) {
+    tsprite.hscroll = hscroll;
+    lzv.scrollevent('scrollLeft', hscroll);
+  }
+  var maxhscroll = this.maxhscroll;
+  if (tsprite.maxhscroll !== maxhscroll) {
+    tsprite.maxhscroll = maxhscroll;
+    lzv.scrollevent('scrollWidth', maxhscroll + tsprite.width);
+  }
 }
 
 /**
@@ -1021,3 +1049,4 @@
     this.__setFormat();
     // note: don't need to recompute dimensions here
 }
+}

Modified: openlaszlo/trunk/WEB-INF/lps/lfc/kernel/swf9/LzInputTextSprite.as
===================================================================
--- openlaszlo/trunk/WEB-INF/lps/lfc/kernel/swf9/LzInputTextSprite.as	2009-02-04 02:40:23 UTC (rev 12742)
+++ openlaszlo/trunk/WEB-INF/lps/lfc/kernel/swf9/LzInputTextSprite.as	2009-02-04 04:06:10 UTC (rev 12743)
@@ -32,7 +32,6 @@
     var enabled = true;
     var focusable = true;
     var hasFocus = false;
-    var scroll = 0;
 
     override public function __initTextProperties (args:Object) {
         super.__initTextProperties(args);

Modified: openlaszlo/trunk/WEB-INF/lps/lfc/kernel/swf9/LzSprite.as
===================================================================
--- openlaszlo/trunk/WEB-INF/lps/lfc/kernel/swf9/LzSprite.as	2009-02-04 02:40:23 UTC (rev 12742)
+++ openlaszlo/trunk/WEB-INF/lps/lfc/kernel/swf9/LzSprite.as	2009-02-04 04:06:10 UTC (rev 12743)
@@ -105,7 +105,10 @@
       // flag to track sprite the mouse went over while down to send mouseup event later -  see LPP-7300 and LPP-7335
       private var __mouseoverInFront:LzSprite = null;
 
-      public static var capabilities:* = {
+      // NOTE: [2009-02-01 ptw] This may look like it should be a static
+      // var, but LFC code expects capabilities to be a
+      // property of the sprite, so we copy it to an instance var
+      static var capabilities:* = {
       rotation: true
       // Avoid scaling canvas to percentage values - SWF already scales the viewport size, so take window size literally to avoid scaling twice
       ,scalecanvastopercentage: false
@@ -125,7 +128,9 @@
       ,runtimemenus: true
       ,setclipboard: true
       ,proxypolicy: true
-      }
+      ,linescrolling: true
+      };
+      var capabilities = LzSprite.capabilities;
 
       public function LzSprite (newowner = null, isroot = null) {
           // owner:*, isroot:Boolean

Modified: openlaszlo/trunk/WEB-INF/lps/lfc/kernel/swf9/LzTextSprite.as
===================================================================
--- openlaszlo/trunk/WEB-INF/lps/lfc/kernel/swf9/LzTextSprite.as	2009-02-04 02:40:23 UTC (rev 12742)
+++ openlaszlo/trunk/WEB-INF/lps/lfc/kernel/swf9/LzTextSprite.as	2009-02-04 04:06:10 UTC (rev 12743)
@@ -30,8 +30,28 @@
         public static var DEFAULT_SIZE = 11;
 
         var font = null;
-        public var lineheight = 11;
 
+        /**
+        * @access private
+        */
+        public var scroll:Number = 0;
+        /**
+        * @access private
+        */
+        public var maxscroll:Number = 0;
+        /**
+        * @access private
+        */
+        public var hscroll:Number = 0;
+        /**
+        * @access private
+        */
+        public var maxhscroll:Number = 0;
+        /**
+        * @access private
+        */
+        public var lineheight:Number = 1;
+
         public var textcolor = 0;
         public var text:String = "";
 
@@ -74,24 +94,28 @@
             this.textfield.addEventListener(flash.events.Event.SCROLL, __handleScrollEvent);
         }
 
-        function __handleScrollEvent(e:Event) {
-            if ( this.owner.scroll != textfield.scrollV) {
-                this.owner.scroll = textfield.scrollV;
-                if (this.owner.onscroll.ready) this.owner.onscroll.sendEvent(textfield.scrollV);
-            }
-            if (this.owner.maxscroll != textfield.maxScrollV) {
-                this.owner.maxscroll = textfield.maxScrollV;
-                if (this.owner.onmaxscroll.ready) this.owner.onmaxscroll.sendEvent(textfield.maxScrollV);
-            }
-            if (this.owner.hscroll != textfield.scrollH) {
-                this.owner.hscroll = textfield.scrollH;
-                if (this.owner.onhscroll.ready) this.owner.onhscroll.sendEvent(textfield.scrollH);
-            }
-            if (this.owner.maxhscroll != textfield.maxScrollH) {
-                this.owner.maxhscroll = textfield.maxScrollH;
-                if (this.owner.onmaxhscroll.ready) this.owner.onmaxhscroll.sendEvent(textfield.maxScrollH);
-            }
-        }
+    function __handleScrollEvent(e:Event = null) {
+      if (scroll !== textfield.scrollV) {
+        scroll = textfield.scrollV;
+        //Debug.info('__handleScrollEvent', 'scrollTop', lineNoToPixel(textfield.scrollV));
+        owner.scrollevent('scrollTop', lineNoToPixel(textfield.scrollV));
+      }
+      if (maxscroll !== textfield.maxScrollV) {
+        maxscroll = textfield.maxScrollV;
+        //Debug.info('__handleScrollEvent', 'scrollHeight', lineNoToPixel(textfield.maxScrollV));
+        owner.scrollevent('scrollHeight', lineNoToPixel(textfield.maxScrollV) + height);
+      }
+      if (hscroll !== textfield.scrollH) {
+        hscroll = textfield.scrollH;
+        //Debug.info('__handleScrollEvent', 'scrollLeft', textfield.scrollH);
+        owner.scrollevent('scrollLeft', textfield.scrollH);
+      }
+      if (maxhscroll !== textfield.maxScrollH) {
+        maxhscroll = textfield.maxScrollH;
+        //Debug.info('__handleScrollEvent', 'scrollWidth', textfield.maxScrollH);
+        owner.scrollevent('scrollWidth', textfield.maxScrollH + width);
+      }
+    }
 
 
       // turn on/off canceling of mouse event bubbling
@@ -147,6 +171,7 @@
             super.setWidth(w);
             if (w) {
                 this.textfield.width = w;
+                this.__handleScrollEvent();
             }
         }
 
@@ -154,6 +179,7 @@
             super.setHeight(h);
             if (h) {
                 this.textfield.height = h;
+                this.__handleScrollEvent();
             }
         }
 
@@ -227,9 +253,7 @@
             this.setText((args['text'] != null) ? String(args.text) : '');
             
             if (this.sizeToHeight) {
-                //text and format is set, measure it
-                var lm:TextLineMetrics = textclip.getLineMetrics(0);
-                var h = lm.ascent + lm.descent + lm.leading;
+                var h = this.lineheight;
                 //TODO [anba 20080602] is this ok for multiline? 
                 if (this.multiline) h *= textclip.numLines;
                 h += 4;//2*2px gutter, see flash docs for flash.text.TextLineMetrics 
@@ -237,7 +261,7 @@
             }
 
             addScrollEventListener();
-
+            __handleScrollEvent();
         }
 
 
@@ -283,12 +307,6 @@
         function setFontInfo () {
             this.font = LzFontManager.getFont( this.fontname , this.fontstyle );
             //Debug.write('setFontInfo this.font = ', this.font, 'this.fontname = ', this.fontname, this.fontstyle);
-
-            if (this.font != null) {
-                //Debug.write('font.leading', this.font.leading, 'font.height = ',this.font.height, 'fontsize =',this.fontsize);
-                this.lineheight = Number(this.font.leading) + ( Number(this.font.height) *
-                                                        Number(this.fontsize) / DEFAULT_SIZE );
-            }
         }
 
         /**
@@ -414,6 +432,14 @@
             tf.letterSpacing = this.letterspacing;
 
             this.textfield.defaultTextFormat = tf;
+
+            var lm:TextLineMetrics = this.textfield.getLineMetrics(0);
+            var lh = lm.ascent + lm.descent + lm.leading;
+            if (lh !== this.lineheight) {
+              this.lineheight = lh;
+              // Tell the owner the linescale has changed
+              this.owner.scrollevent('lineHeight', lh);
+            }
         }
  
       
@@ -535,16 +561,24 @@
     return this.textfield.bottomScrollV;
 }
 
-function setXScroll ( n ){
-    Debug.write("LzTextSprite.setXScroll not yet implemented");
+function lineNoToPixel (n:Number):Number {
+  return (n - 1) * lineheight;
 }
 
+function pixelToLineNo (n:Number):Number {
+  return Math.ceil(n / lineheight) + 1;
+}
+
 function setYScroll ( n ){
-    Debug.write("LzTextSprite.setYScroll not yet implemented");
+  this.textfield.scrollV = this.pixelToLineNo((- n));
 }
 
+function setXScroll ( n ){
+  this.textfield.scrollH = (- n);
+}
+
 function setWordWrap ( wrap ){
-    Debug.write("LzTextSprite.setWordWrap not yet implemented");
+    Debug.warn("LzTextSprite.setWordWrap not yet implemented");
 }
 
 function getSelectionPosition() {

Modified: openlaszlo/trunk/WEB-INF/lps/lfc/views/LaszloCanvas.lzs
===================================================================
--- openlaszlo/trunk/WEB-INF/lps/lfc/views/LaszloCanvas.lzs	2009-02-04 02:40:23 UTC (rev 12742)
+++ openlaszlo/trunk/WEB-INF/lps/lfc/views/LaszloCanvas.lzs	2009-02-04 04:06:10 UTC (rev 12743)
@@ -1,6 +1,6 @@
 /**
   *
-  * @copyright Copyright 2001-2008 Laszlo Systems, Inc.  All Rights Reserved.
+  * @copyright Copyright 2001-2009 Laszlo Systems, Inc.  All Rights Reserved.
   *            Use is subject to license terms.
   *
   * @affects lzcanvas
@@ -186,14 +186,8 @@
       */
     override function construct (parent , args) {
         this.__makeSprite(null);
+        var capabilities = this.sprite.capabilities;
 
-        // TODO [hqm 2008-04] how can we make this consistent across runtimes ? 
-        if ($as3) {
-            var capabilities = LzSprite.capabilities;
-        } else {
-            var capabilities = LzSprite.prototype.capabilities;
-        }
-
         // TODO: [2006-05-19 ptw] The original did not do this, should we?
         // super(null, args);
         // No, we can't.  But you have to be aware that if you futz with

Modified: openlaszlo/trunk/WEB-INF/lps/lfc/views/LaszloView.lzs
===================================================================
--- openlaszlo/trunk/WEB-INF/lps/lfc/views/LaszloView.lzs	2009-02-04 02:40:23 UTC (rev 12742)
+++ openlaszlo/trunk/WEB-INF/lps/lfc/views/LaszloView.lzs	2009-02-04 04:06:10 UTC (rev 12743)
@@ -397,14 +397,7 @@
 /** @access private */
 var DOUBLE_CLICK_TIME = 500;
 
-// TODO [hqm 2008-03] Will asking for LzSprite.prototype.xxx  work in SWF9?
-if ($as3) {
-    /** @access private */
-    var capabilities = LzSprite.capabilities;
-} else {
-    /** @access private */
-    var capabilities = LzSprite.prototype.capabilities;
-}
+var capabilities;
 
 /**
   * Base level constructor for views. See LzNode.<method
@@ -429,6 +422,8 @@
     this.mask = ip.mask;
 
     this.__makeSprite(args);
+    // Cache capabilities
+    this.capabilities = this.sprite.capabilities;
 
     if (args['width'] != null || this.__LZhasConstraint('width')) {
         this.hassetwidth = true;

Modified: openlaszlo/trunk/WEB-INF/lps/lfc/views/LzInputText.lzs
===================================================================
--- openlaszlo/trunk/WEB-INF/lps/lfc/views/LzInputText.lzs	2009-02-04 02:40:23 UTC (rev 12742)
+++ openlaszlo/trunk/WEB-INF/lps/lfc/views/LzInputText.lzs	2009-02-04 04:06:10 UTC (rev 12743)
@@ -136,13 +136,15 @@
     super.destroy();
 }
 
+/** @access private */
+var isprite:LzInputTextSprite;
 /**
   * Called to create the sprite object.  May be overridden to use a specific 
   * version, e.g. LzTextSprite();
   * @access private
   */
 override function __makeSprite(args) {
-    this.sprite = new LzInputTextSprite(this, args);
+    this.sprite = this.tsprite = this.isprite = new LzInputTextSprite(this, args);
 }
 
 /** @access private */

Modified: openlaszlo/trunk/WEB-INF/lps/lfc/views/LzText.lzs
===================================================================
--- openlaszlo/trunk/WEB-INF/lps/lfc/views/LzText.lzs	2009-02-04 02:40:23 UTC (rev 12742)
+++ openlaszlo/trunk/WEB-INF/lps/lfc/views/LzText.lzs	2009-02-04 04:06:10 UTC (rev 12743)
@@ -142,8 +142,7 @@
   /** @access private */
   function $lzc$set_selectable(isSel) {
     this.selectable = isSel;
-    var tsprite:LzTextSprite = (this.sprite cast LzTextSprite);
-    tsprite.setSelectable(isSel);
+    this.tsprite.setSelectable(isSel);
   }
 
   /*
@@ -161,8 +160,7 @@
     if (this.capabilities.advancedfonts) {
       if ((aliasType == "normal") || (aliasType == "advanced")) {
         this.antiAliasType = aliasType;
-        var tsprite:LzTextSprite = (this.sprite cast LzTextSprite);
-        tsprite.setAntiAliasType(aliasType);
+        this.tsprite.setAntiAliasType(aliasType);
       } else if ($debug) {
         Debug.warn("antiAliasType invalid, must be 'normal' or 'advanced', but you said '" + aliasType + "'");
       }
@@ -182,8 +180,7 @@
     if (this.capabilities.advancedfonts) {
       if ((gridFit == "none") || (gridFit == "pixel") || (gridFit == "subpixel")) {
         this.gridFit = gridFit;
-        var tsprite:LzTextSprite = (this.sprite cast LzTextSprite);
-        tsprite.setGridFit(gridFit);
+        this.tsprite.setGridFit(gridFit);
       } else if ($debug) {
         Debug.warn("gridFit invalid, must be 'none', 'pixel', or 'subpixel' but you said '" + gridFit + "'");
       }
@@ -203,8 +200,7 @@
     if (this.capabilities.advancedfonts) {
       if  ((sharpness >= -400) && (sharpness <= 400)) {
         this.sharpness = sharpness;
-        var tsprite:LzTextSprite = (this.sprite cast LzTextSprite);
-        tsprite.setSharpness(sharpness);
+        this.tsprite.setSharpness(sharpness);
       } else if ($debug) {
         Debug.warn("sharpness out of range, must be -400 to 400");
       }
@@ -224,8 +220,7 @@
     if (this.capabilities.advancedfonts) {
       if  ((thickness >= -200) && (thickness <= 200)) {
         this.thickness = thickness;
-        var tsprite:LzTextSprite = (this.sprite cast LzTextSprite);
-        tsprite.setThickness(thickness);
+        this.tsprite.setThickness(thickness);
       } else if ($debug) {
         Debug.warn("thickness out of range, must be -200 to 200");
       }
@@ -244,14 +239,16 @@
 
   /** @access private */
   override function $lzc$set_width(val) {
-    var tsprite:LzTextSprite = (this.sprite cast LzTextSprite);
+    var tsprite = this.tsprite;
     tsprite.setWidth(val);
-    super.$lzc$set_width.apply(this, arguments);
+    super.$lzc$set_width(val);
+    // maxhscroll depends on width
+    this.updateAttribute('maxhscroll', this.scrollwidth - this.width);
     // recalculate height
     if (this.sizeToHeight) {
       var h = tsprite.getTextfieldHeight();
       if (h > 0) {
-        this.$lzc$set_height (h);
+        this.$lzc$set_height(h);
       }
     }
   }
@@ -270,61 +267,291 @@
    */
 
   /**
-   * The y scroll position of the textfield in pixels.  Default 0.
+   * Helper for updating an attribute from a sprite callback
+   *
+   * @access private
+   *
+   * @devnote NOTE: [2009-01-31 ptw] this probably could be merged
+   * with resourceevent, but `resourceevent` is not the right name, it
+   * needs to be generalized.  Also, I thought we decided the policy
+   * was that events are always sent, whether the value changes or
+   * not.
+   */
+  function updateAttribute(name:String, value):void {
+    this[name] = value;
+    var event:LzDeclaredEventClass = this['on' + name];
+    if (event.ready) { event.sendEvent(value); }
+  }
+
+  /*
+   * Support for backward-compatible line-based interfaces.  This is
+   * the same as updateAttribute but incorporates the vertical scale
+   * conversion (if any).
+   *
+   * @devnote NOTW: [2009-01-31 ptw] Some sprites support accurate
+   * conversion of pixel values to line numbers, considering interior
+   * styling of the content.  If this is not supported, default to
+   * converting assuming a uniform line height.
+   *
+   * @access private
+   */
+  function updateLineAttribute(name:String, value):void {
+    var tsprite:LzTextSprite = this.tsprite;
+    var lineNo:Number;
+    if (this.capabilities.linescrolling) {
+      lineNo = tsprite.pixelToLineNo(value);
+    } else {
+      lineNo = Math.floor(value / this.lineheight) + 1;
+    }
+    this.updateAttribute(name, lineNo);
+  }
+
+  /**
+   * The height of a line of text in the current style
+   *
    * @lzxtype Number
    * @type Number
+   * @keywords read-only
    */
-  var yscroll = 0;
+  var lineheight:Number;
   /** @access private */
-  function $lzc$set_yscroll(n) {
-    var tsprite:LzTextSprite = (this.sprite cast LzTextSprite);
-    tsprite.setYScroll(n);
-    this.yscroll = n;
-    this.onyscroll.sendEvent(n);
+  function $lzc$set_lineheight(x:Number):void {
+    if ($debug) { Debug.error("lineheight is read-only"); }
   }
   /** @lzxtype event */
-  var onyscroll = LzDeclaredEvent;
+  var onlineheight:LzDeclaredEventClass = LzDeclaredEvent;
 
   /**
-   * The x scroll position of the textfield in pixels. Default 0.
+   * The y scroll offset of the content in pixels (a negative number
+   * specifying how many pixels the content should be scrolled
+   * vertically).  Default 0.
+   *
    * @lzxtype Number
    * @type Number
+   *
+   * @devnote NOTE [2009-01-31 ptw] For hysterical reasons this is
+   * equivalent to DHTML scrolltop, but negated!
    */
-  var xscroll = 0;
+  var yscroll:Number = 0;
   /** @access private */
-  function $lzc$set_xscroll(n) {
-    var tsprite:LzTextSprite = (this.sprite cast LzTextSprite);
-    tsprite.setXScroll(n);
-    this.xscroll = n;
-    this.onxscroll.sendEvent(n);
+  function $lzc$set_yscroll(n:Number):void {
+    this.tsprite.setYScroll(n);
+    this.updateAttribute('yscroll', n);
+    this.updateLineAttribute('scroll', (- n));
   }
   /** @lzxtype event */
-  var onxscroll = LzDeclaredEvent;
+  var onyscroll:LzDeclaredEventClass = LzDeclaredEvent;
 
+  /**
+   * The total height of the content in pixels.
+   *
+   * <code>this.setAttribute('height', this.scrollheight)</code> is
+   * equivalent to <code>this.setAttribute('height', null)</code> (for
+   * the current content: the former will not follow content changes
+   * as the latter does). If <code>this.scrollheight &gt;
+   * this.height</code>, <code>this.setAttribute('yscroll',
+   * this.height - this.scrollheight)</code> will scroll the content
+   * so that the bottom of the content appears in the bottom of the
+   * view.
+   *
+   * @lzxtype Number
+   * @type number
+   * @keywords read-only
+   */
+  var scrollheight:Number;
   /** @access private */
-  var scroll = 0;
+  function $lzc$set_scrollheight(x:Number):void {
+    if ($debug) { Debug.error("scrollheight is read-only"); }
+  }
   /** @lzxtype event */
-  var onscroll = LzDeclaredEvent;
+  var onscrollheight:LzDeclaredEventClass = LzDeclaredEvent;
 
+  /**
+   * The x scroll offset of the content in pixels (a negative number
+   * specifying how many pixels the content should be scrolled
+   * horizontally). Default 0.
+   *
+   * @lzxtype Number
+   * @type Number
+   *
+   * @devnote NOTE [2009-01-31 ptw] For hysterical reasons this is
+   * equivalent to DHTML scrollleft, but negated!
+   */
+  var xscroll:Number = 0;
   /** @access private */
-  var scrollheight;
+  function $lzc$set_xscroll(n:Number):void {
+    this.tsprite.setXScroll(n);
+    this.updateAttribute('xscroll', n);
+    this.updateAttribute('hscroll', (- n));
+  }
+  /** @lzxtype event */
+  var onxscroll:LzDeclaredEventClass = LzDeclaredEvent;
 
+  /**
+   * The total width of the content in pixels.
+   *
+   * <code>this.setAttribute('width', this.scrollwidth)</code> is
+   * equivalent to <code>this.setAttribute('width', null)</code> (for
+   * the current content: the former will not follow content changes
+   * as the latter does). If <code>this.scrollwidth &gt;
+   * this.width</code>, <code>this.setAttribute('yscroll', this.width
+   * - this.scrollwidth)</code> will cause the end of content to be
+   * visible at the edge of the view.  (The rightmost content will
+   * appear at the right edge of the view for left-to-right scripts.)
+   *
+   * @lzxtype Number
+   * @type number
+   * @keywords read-only
+   */
+  var scrollwidth:Number;
   /** @access private */
-  var maxscroll = 0;
+  function $lzc$set_scrollwidth(x:Number):void {
+    if ($debug) { Debug.error("scrollwidth is read-only"); }
+  }
   /** @lzxtype event */
-  var onmaxscroll = LzDeclaredEvent;
+  var onscrollwidth:LzDeclaredEventClass = LzDeclaredEvent;
 
+  /*
+   * Backward-compatible line/character-based interfaces
+   */
+
+  /**
+   * The vertical scroll position (in lines, 1-based). Default 1.
+   * @lzxtype Number
+   * @type Number
+   *
+   * @devnote NOTE: [2009-01-31 ptw] Some sprites support accurate
+   * conversion of pixel values to line numbers, considering interior
+   * styling of the content.  If this is not supported, default to
+   * converting assuming a uniform line height.
+   */
+  var scroll:Number = 1;
   /** @access private */
-  var hscroll = 0;
+  function $lzc$set_scroll(n:Number):void {
+    var tsprite = this.tsprite;
+    var pixel:Number;
+    if (this.capabilities.linescrolling) {
+      pixel = tsprite.lineNoToPixel(n);
+    } else {
+      pixel = (n - 1) * this.lineheight;
+    }
+    // Call the pixel interface which will update the attribute and
+    // send the event
+    this.$lzc$set_yscroll((- pixel));
+  }
   /** @lzxtype event */
-  var onhscroll = LzDeclaredEvent;
+  var onscroll:LzDeclaredEventClass = LzDeclaredEvent;
 
+  /**
+   * The maximum vertical scroll position (in lines, 1-based).
+   * <code>this.setAttribute('scroll', this.maxscroll)</code> will
+   * cause the last line of the content to be visible at the bottom of
+   * the view (hence this is the line number of the line that will
+   * appear at the top of the view when scrolled all the way to the
+   * bottom).
+   *
+   * @lzxtype Number
+   * @type Number
+   * @keywords read-only
+   */
+  var maxscroll:Number = 1;
   /** @access private */
-  var maxhscroll = 0;
+  function $lzc$set_maxscroll(x:Number):void {
+    if ($debug) { Debug.error("maxscroll is read-only"); }
+  }
   /** @lzxtype event */
-  var onmaxhscroll = LzDeclaredEvent;
+  var onmaxscroll:LzDeclaredEventClass = LzDeclaredEvent;
+  /**
+   * maxscroll depends on height
+   * @access private
+   */
+  override function $lzc$set_height(v) {
+    super.$lzc$set_height(v);
+    this.updateLineAttribute('maxscroll', this.scrollheight - this.height);
+  }
 
+  /**
+   * The horizontal scroll position in pixels.  Default 0.
+   * @lzxtype Number
+   * @type Number
+   */
+  var hscroll:Number = 0;
+  /** @access private */
+  function $lzc$set_hscroll(n:Number):void {
+    // Call the pixel interface which will update the attribute and
+    // send the event
+    this.$lzc$set_xscroll((- n));
+  }
+  /** @lzxtype event */
+  var onhscroll:LzDeclaredEventClass = LzDeclaredEvent;
 
+  /**
+   * The maximum horizontal scroll position in pixels.
+   * <code>this.setAttribute('hscroll', this.maxhscroll)</code> will
+   * cause the end of content to be visible at the edge of
+   * the view.  (The rightmost content will appear at the right edge
+   * of the view for left-to-right scripts, hence this is the pixel
+   * position of the leftmost pixel that will appear in the view when
+   * scrolled all the way to the right.)
+   *
+   * @lzxtype Number
+   * @type Number
+   * @keywords read-only
+   */
+  var maxhscroll:Number = 0;
+  /** @access private */
+  function $lzc$set_maxhscroll(x:Number):void {
+    if ($debug) { Debug.error("maxhscroll is read-only"); }
+  }
+  /** @lzxtype event */
+  var onmaxhscroll:LzDeclaredEventClass = LzDeclaredEvent;
+  /**
+   * maxhscroll depends on width
+   * @devnote see $lzc$set_width
+   */
+
+  /**
+   * Kernel callback for scroll events.  This does not call the
+   * setters (which would loop back to the kernel!).  It keeps the
+   * pixel and line values 'in line' [:P]
+   *
+   * @access private
+   */
+  function scrollevent(name:String, value):void {
+    switch (name) {
+      case 'scrollTop':
+        this.updateAttribute('yscroll', value);
+        this.updateLineAttribute('scroll', value);
+        break;
+      case 'scrollLeft':
+        this.updateAttribute('xscroll', value);
+        this.updateAttribute('hscroll', value);
+        break;
+      case 'scrollHeight':
+        this.updateAttribute('scrollheight', value);
+        // This can't be negative
+        this.updateLineAttribute('maxscroll', Math.max(0, value - this.height));
+        break;
+      case 'scrollWidth':
+        this.updateAttribute('scrollwidth', value);
+        // This can't be negative
+        this.updateAttribute('maxhscroll', Math.max(0, value - this.width));
+        break;
+      case 'lineHeight':
+        this.updateAttribute('lineheight', value);
+        // Update all the line-based values...
+        this.updateLineAttribute('scroll', this.yscroll);
+        // This can't be negative
+        this.updateLineAttribute('maxscroll', Math.max(0, this.scrollheight - this.height));
+        break;
+      default:
+        if ($debug) {
+          Debug.error("%w: Uknown scrollevent %s (%w)", arguments.callee, name, value);
+        }
+    }
+  }
+
+
   /*
    * Resizing interface
    */
@@ -356,9 +583,8 @@
   var multiline;
   /** @access private */
   function $lzc$set_multiline(ml) :void {
-    var tsprite:LzTextSprite = (this.sprite cast LzTextSprite);
-    tsprite.setMultiline(ml);
-    this.multiline = (ml == true);
+    this.multiline = (ml = (!! ml));
+    this.tsprite.setMultiline(ml);
   }
 
   /**
@@ -372,9 +598,8 @@
   var resize = true;
   /** @access private */
   function $lzc$set_resize(val) {
-    var tsprite:LzTextSprite = (this.sprite cast LzTextSprite);
-    tsprite.setResize(val);
     this.resize = val;
+    this.tsprite.setResize(val);
   }
 
 
@@ -400,7 +625,7 @@
       if (this.ontext.ready) this.ontext.sendEvent(t);
       return;
     }
-    var tsprite:LzTextSprite = (this.sprite cast LzTextSprite);
+    var tsprite = this.tsprite;
     if (this.visible) tsprite.setVisible(this.visible);
     if (this.maxlength != null && t.length > this.maxlength){
       t = t.substring(0, this.maxlength);
@@ -428,13 +653,13 @@
     this._textrecompute = false;
   }
   /** * @lzxtype event */
-  var ontext = LzDeclaredEvent;
+  var ontext:LzDeclaredEventClass = LzDeclaredEvent;
 
   /** Sent when a clickable HTML link in the text field is clicked.
    *  Event data is a string with the link value.
    * @lzxtype event
    */
-  var ontextlink = LzDeclaredEvent;
+  var ontextlink:LzDeclaredEventClass = LzDeclaredEvent;
 
   /** true forces $lzc$set_text to do a full update
       @access private */
@@ -449,9 +674,8 @@
   /** @access private */
   function $lzc$set_maxlength(val) {
     if (val == null || val == '') return;
-    var tsprite:LzTextSprite = (this.sprite cast LzTextSprite);
-    tsprite.setMaxLength(val);
     this.maxlength = val;
+    this.tsprite.setMaxLength(val);
     if (this.onmaxlength.ready) this.onmaxlength.sendEvent(val);
 
     var t = this.getText();
@@ -461,7 +685,7 @@
     }
   }
   /** @lzxtype event */
-  var onmaxlength = LzDeclaredEvent;
+  var onmaxlength:LzDeclaredEventClass = LzDeclaredEvent;
 
   /**
    * regexp describing set of characters allowed in this field Restrict the characters that can be entered to a pattern specified by a regular expression.
@@ -473,26 +697,23 @@
   /** @access private */
   function $lzc$set_pattern(val) {
     if (val == null || val == '') return;
-    var tsprite:LzTextSprite = (this.sprite cast LzTextSprite);
-    tsprite.setPattern(val);
     this.pattern = val;
+    this.tsprite.setPattern(val);
     if (this.onpattern.ready) this.onpattern.sendEvent(val);
   }
   /** @lzxtype event */
-  var onpattern = LzDeclaredEvent;
+  var onpattern:LzDeclaredEventClass = LzDeclaredEvent;
 
   /** @access private */
   function $lzc$set_fontstyle(fstyle) {
-    var tsprite:LzTextSprite = (this.sprite cast LzTextSprite);
-    tsprite.setFontStyle(fstyle);
     this.fontstyle = fstyle;
+    this.tsprite.setFontStyle(fstyle);
   }
 
   /** @access private */
   override function $lzc$set_font(fname) {
-    var tsprite:LzTextSprite = (this.sprite cast LzTextSprite);
-    tsprite.setFontName(fname);
     this.fontname = fname;
+    this.tsprite.setFontName(fname);
     // force recompute of height if needed
     this._textrecompute = true;
     this.$lzc$set_text(this.getText());
@@ -500,9 +721,8 @@
 
   /** @access private */
   function $lzc$set_fontsize(fsize) {
-    var tsprite:LzTextSprite = (this.sprite cast LzTextSprite);
-    tsprite.setFontSize(fsize);
     this.fontsize = fsize;
+    this.tsprite.setFontSize(fsize);
     // force recompute of height if needed
     this._textrecompute = true;
     this.$lzc$set_text(this.getText());
@@ -524,7 +744,7 @@
       align = "left";
     }
     this.textalign = align;
-    (this.sprite cast LzTextSprite).setTextAlign(align);
+    this.tsprite.setTextAlign(align);
     // force recompute of height if needed
     this._textrecompute = true;
     this.$lzc$set_text(this.getText());
@@ -538,7 +758,7 @@
   /** @access private */
   function $lzc$set_textindent (indent:Number) :void {
     this.textindent = indent;
-    (this.sprite cast LzTextSprite).setTextIndent(indent);
+    this.tsprite.setTextIndent(indent);
     // force recompute of height if needed
     this._textrecompute = true;
     this.$lzc$set_text(this.getText());
@@ -552,7 +772,7 @@
   /** @access private */
   function $lzc$set_letterspacing (spacing:Number) :void {
     this.letterspacing = spacing;
-    (this.sprite cast LzTextSprite).setLetterSpacing(spacing);
+    this.tsprite.setLetterSpacing(spacing);
     // force recompute of height if needed
     this._textrecompute = true;
     this.$lzc$set_text(this.getText());
@@ -575,7 +795,7 @@
       decoration = "none";
     }
     this.textdecoration = decoration;
-    (this.sprite cast LzTextSprite).setTextDecoration(decoration);
+    this.tsprite.setTextDecoration(decoration);
   }
 
 
@@ -607,7 +827,7 @@
       this[attr] = args[arg];
     }
 
-    var tsprite:LzTextSprite = (this.sprite cast LzTextSprite);
+    var tsprite = this.tsprite;
     // FIXME [2008-11-24 ptw] (LPP-7391) We should not be passing node
     // init args across the kernel API, there should be a more
     // explicit API that isolates the kernel from the node
@@ -673,8 +893,6 @@
     } else if (args['height'] != null) {
       this.$lzc$set_height(args.height);
     }
-    // Default the scrollheight to the visible height.
-    this.scrollheight = this.height;
 
     if (args['pattern'] != null) {
       this.$lzc$set_pattern(args.pattern);
@@ -703,8 +921,7 @@
     // [max] had to do this because text fields don't have a height until they're attached into the DOM.
     // multiline resizable fields adjust their height
     if (this.sizeToHeight) {
-      var tsprite:LzTextSprite = (this.sprite cast LzTextSprite);
-      var h = tsprite.getTextfieldHeight();
+      var h = this.tsprite.getTextfieldHeight();
       if (h > 0) {
         this.$lzc$set_height(h);
       }
@@ -716,6 +933,8 @@
    *
    */
 
+  /** @access private */
+  var tsprite:LzTextSprite;
   /**
    * Called to create the sprite object.  May be overridden to use a specific
    * version, e.g. LzTextSprite();
@@ -723,7 +942,7 @@
    */
   override function __makeSprite(args) {
     //Debug.write('__makeSprite', args);
-    this.sprite = new LzTextSprite(this, args);
+    this.sprite = this.tsprite = new LzTextSprite(this, args);
   }
 
 
@@ -732,8 +951,7 @@
    * @access private
    */
   override function getMCRef () {
-    var tsprite:LzTextSprite = (this.sprite cast LzTextSprite);
-    return tsprite.getMCRef();
+    return this.tsprite.getMCRef();
   }
 
 
@@ -800,8 +1018,7 @@
    * Calculates the current width of the text held by the text field.
    */
   function getTextWidth ( ){
-    var tsprite:LzTextSprite = (this.sprite cast LzTextSprite);
-    return tsprite.getTextWidth();
+    return this.tsprite.getTextWidth();
   }
   /** @access private */
   function $lzc$getTextWidth_dependencies ( who , self){
@@ -812,8 +1029,7 @@
    * Calculates the current height of the text held by the text field.
    */
   function getTextHeight ( ){
-    var tsprite:LzTextSprite = (this.sprite cast LzTextSprite);
-    return tsprite.getTextHeight();
+    return this.tsprite.getTextHeight();
     //return this.__LZtextclip.textHeight;
   }
   /** @access private */
@@ -830,36 +1046,32 @@
     }
   }
 
-  /** Sets the vertical scroll position
+  /** Sets the vertical scroll position in lines
    * @param Number h: scroll position
+   * @deprecated use `setAttribute('scroll', ...)` instead
    */
   function setScroll ( h ){
-    var tsprite:LzTextSprite = (this.sprite cast LzTextSprite);
-    tsprite.setScroll(h);
+    if ($debug) Debug.deprecated(this, arguments.callee, this.setAttribute);
+    this.$lzc$set_scroll(h);
   }
 
   /** @access private */
   function getScroll ( ){
-    var tsprite:LzTextSprite = (this.sprite cast LzTextSprite);
-    return tsprite.getScroll();
+    return this.tsprite.getScroll();
   }
 
-
   /** @access private */
   function getMaxScroll ( ){
-    var tsprite:LzTextSprite = (this.sprite cast LzTextSprite);
-    return tsprite.getMaxScroll();
+    return this.tsprite.getMaxScroll();
   }
   /** @access private */
   function $lzc$getMaxScroll_dependencies ( who , self){
     return [ self , "maxscroll" ];
   }
 
-
   /** @access private */
   function getBottomScroll ( ){
-    var tsprite:LzTextSprite = (this.sprite cast LzTextSprite);
-    return tsprite.getBottomScroll();
+    return this.tsprite.getBottomScroll();
   }
 
   /**
@@ -874,7 +1086,6 @@
     this.$lzc$set_xscroll(n);
   }
 
-
   /**
    * Set the y scroll position of the textfield.
    * @param Number n: set the top line of the textfield to offset n pixels
@@ -886,7 +1097,16 @@
     this.$lzc$set_yscroll(n);
   }
 
+  /** Sets the horizontal scroll position
+   * @param Number s: horizontal scroll position
+   * @deprecated Use setAttribute('hscroll', ...) instead.
+   */
+  function setHScroll (s){
+    if ($debug) Debug.deprecated(this, arguments.callee, this.setAttribute);
+    this.$lzc$set_hscroll(s);
+  }
 
+
   /** @access private */
   function annotateAAimg (txt) {
     if (typeof(txt) == "undefined") { return; }
@@ -1110,8 +1330,7 @@
 
   /** @access private */
   function setBorder ( onroff ){
-    var tsprite:LzTextSprite = (this.sprite cast LzTextSprite);
-    tsprite.setBorder(onroff);
+    this.tsprite.setBorder(onroff);
   }
 
   /**
@@ -1119,15 +1338,13 @@
    * @todo should wrapping be made orthogonal to the multiline flag?
    */
   function setWordWrap ( wrap ){
-    var tsprite:LzTextSprite = (this.sprite cast LzTextSprite);
-    tsprite.setWordWrap(wrap);
+    this.tsprite.setWordWrap(wrap);
   }
 
 
   /** @access private */
   function setEmbedFonts ( onroff ){
-    var tsprite:LzTextSprite = (this.sprite cast LzTextSprite);
-    tsprite.setEmbedFonts(onroff);
+    this.tsprite.setEmbedFonts(onroff);
   }
 
 
@@ -1225,14 +1442,6 @@
     }
   }
 
-  /** Sets the horizontal scroll position
-   * @param Number s: horizontal scroll position
-   */
-  function setHScroll (s){
-    var tsprite:LzTextSprite = (this.sprite cast LzTextSprite);
-    tsprite.setHScroll(s);
-  }
-
   /**
    * Positions the text selection within the text field. If this object does
    * not already have the focus, this has the ancillary effect of giving it the
@@ -1245,8 +1454,7 @@
    */
   function setSelection ( start , end=null ){
     if (end == null) { end = start; }
-    var tsprite:LzTextSprite = (this.sprite cast LzTextSprite);
-    tsprite.setSelection(start, end);
+    this.tsprite.setSelection(start, end);
   }
 
   /**
@@ -1256,8 +1464,7 @@
    * based. If the text cursor is not in the textfield, this method returns -1.
    */
   function getSelectionPosition ( ){
-    var tsprite:LzTextSprite = (this.sprite cast LzTextSprite);
-    return  tsprite.getSelectionPosition();
+    return  this.tsprite.getSelectionPosition();
   }
 
   /**
@@ -1267,8 +1474,7 @@
    * If the text cursor is not in the textfield, this method returns -1.
    */
   function getSelectionSize ( ){
-    var tsprite:LzTextSprite = (this.sprite cast LzTextSprite);
-    return tsprite.getSelectionSize();
+    return this.tsprite.getSelectionSize();
   }
 
   /**
@@ -1282,7 +1488,7 @@
    send an ontextlink event to the text view, with a value of VALUE.
   */
   public function makeTextLink(str, value) {
-    return (this.sprite cast LzTextSprite).makeTextLink(str,value);
+    return this.tsprite.makeTextLink(str,value);
   }
 
 

Modified: openlaszlo/trunk/lps/components/base/basescrollbar.lzx
===================================================================
--- openlaszlo/trunk/lps/components/base/basescrollbar.lzx	2009-02-04 02:40:23 UTC (rev 12742)
+++ openlaszlo/trunk/lps/components/base/basescrollbar.lzx	2009-02-04 04:06:10 UTC (rev 12743)
@@ -608,7 +608,9 @@
             }
 
             var pos = Math.round(-thumbpos / this.trackscroll * this.targetscroll);
-            this.target.setAttribute(this.classroot.scrollattr, pos);
+            if (pos != this.target[this.classroot.scrollattr]) {
+                this.target.setAttribute(this.classroot.scrollattr, pos);
+            }
 
             return thumbpos;
         ]]></method>
@@ -678,7 +680,7 @@
 
 </library>
 <!-- * X_LZ_COPYRIGHT_BEGIN ***************************************************
-* Copyright 2001-2008 Laszlo Systems, Inc.  All Rights Reserved.              *
+* Copyright 2001-2009 Laszlo Systems, Inc.  All Rights Reserved.              *
 * Use is subject to license terms.                                            *
 * X_LZ_COPYRIGHT_END ****************************************************** -->
 <!-- @LZX_VERSION@                                                         -->

Modified: openlaszlo/trunk/lps/components/debugger/newcontent.lzx
===================================================================
--- openlaszlo/trunk/lps/components/debugger/newcontent.lzx	2009-02-04 02:40:23 UTC (rev 12742)
+++ openlaszlo/trunk/lps/components/debugger/newcontent.lzx	2009-02-04 04:06:10 UTC (rev 12743)
@@ -3,7 +3,7 @@
 
  **************************************************************************-->
 <!-- * X_LZ_COPYRIGHT_BEGIN ***************************************************
-* Copyright 2001-2004, 2007, 2008 Laszlo Systems, Inc.  All Rights Reserved.              *
+* Copyright 2001-2004, 2007, 2008, 2009 Laszlo Systems, Inc.  All Rights Reserved.              *
 * Use is subject to license terms.                                            *
 * X_LZ_COPYRIGHT_END ****************************************************** -->
 
@@ -325,11 +325,11 @@
 
 
 <method name="setLine" args="n">
-       this.textpane.setScroll(n);
+       this.textpane.setAttribute('scroll', n);
      </method>
 
 <method name="setLineNoScroll" args="n">
-       this.textpane.setScroll(n);
+       this.textpane.setAttribute('scroll', n);
      </method>
 
 <method name="computeVisibleRegion" >
@@ -352,17 +352,17 @@
 
 <method name="pageUp" args="n=null">
          var tpane = this.textpane;
-         tpane.setScroll(tpane.getScroll() - (tpane.getBottomScroll()  - tpane.getScroll()));
+         tpane.setAttribute('scroll', tpane.getScroll() - (tpane.getBottomScroll()  - tpane.getScroll()));
          this.updateDisplay();
      </method>
 <method name="pageDown" args="n=null">
          var tpane = this.textpane;
-         tpane.setScroll(tpane.getScroll() + (tpane.getBottomScroll()  - tpane.getScroll()));
+         tpane.setAttribute('scroll', tpane.getScroll() + (tpane.getBottomScroll()  - tpane.getScroll()));
          this.updateDisplay();
      </method>
 
 <method name="incScroll" args="n">
-       this.textpane.setScroll(this.textpane.getScroll() + n);
+       this.textpane.setAttribute('scroll', this.textpane.getScroll() + n);
        this.updateDisplay();
      </method>
 

Modified: openlaszlo/trunk/lps/components/incubator/scrolledittext.lzx
===================================================================
--- openlaszlo/trunk/lps/components/incubator/scrolledittext.lzx	2009-02-04 02:40:23 UTC (rev 12742)
+++ openlaszlo/trunk/lps/components/incubator/scrolledittext.lzx	2009-02-04 04:06:10 UTC (rev 12743)
@@ -16,22 +16,19 @@
 
         <_newinternalinputtext name="inp" x="${parent.border}" 
             y="${parent.border}">
-            <attribute name="lineheight"
-                       value="${this.getTextHeight()/this.getMaxScroll()}"/>
-            <attribute name="maxtextheight"
-                       value="${this.getTextHeight() - (this.getTextHeight()/this.getMaxScroll())}"/>
-            <attribute name="maxheight" 
-                       value="${this.height + this.maxtextheight}"/>
-            <event name="onpos" />
-            <attribute name="pos" value="0" setter="this.setPos(pos)"/>
+            <attribute name="pos" value="0" type="number"/>
             
-            <method name="setPos" args="p">
-                if (this.isinited) {
-                    this.setScroll(Math.ceil(1 - (p / this.lineheight)));
+            <setter name="pos" args="p">
+                if (this.inited) {
+                    var scroll = Math.ceil(1 - (p / this.lineheight));
+                    if (scroll !== this.scroll) {
+                        this.setAttribute('scroll', scroll);
+                        //Debug.info('pos', p, this.scroll)
+                    }
                     this.pos = p;
                     if (this.onpos) this.onpos.sendEvent(p);
                 }
-            </method>
+            </setter>
             
             <method name="_constainWidth" args="IGNORE_THIS_ARG">
                 this.setAttribute("width", parent.width - parent.vscrollwidth - parent.border*2 );
@@ -47,7 +44,7 @@
             </handler>
             
             <handler name="onscroll" args="IGNORE_THIS_ARG">
-                this.setPos(-this.lineheight * (this.scroll - 1));
+                this.setAttribute('pos', -this.lineheight * (this.scroll - 1));
             </handler>
         </_newinternalinputtext>
 
@@ -64,13 +61,13 @@
             scrolltarget="parent.inp"
             x="${parent.width - this.width - parent.border + 1}" 
             stepsize="${parent.inp.lineheight}" 
-            scrollmax="${parent.inp.maxheight}">
+            scrollmax="${parent.inp.scrollheight}">
         </vscrollbar>
 -->
 
         <!--- Name of class to instantiate for vertical scroll bar.
               @keywords public -->
-        <attribute name="vscrollbarclassname" type="string" value="lz.vscrollbar"/>
+        <attribute name="vscrollbarclassname" type="string" value="vscrollbar"/>
         
         <!--- Our vertical scrollbar
               @keywords private -->
@@ -85,13 +82,14 @@
                 }
                 if ($debug) {
                     if (typeof(lz[classname]) == "undefined") {
-                        Debug.write("scrollbarclassname undefined", this);
+                        Debug.warn("scrollbarclassname undefined", this);
                     }
                 }
                 if(typeof(lz[classname]) != "undefined"){
                     this._vs = new lz[classname](this, 
                                                  { axis: "y",
                                                    scrollattr: "pos",
+                                                   scrollmax: "0",
                                                    scrolltarget: this.inp});
                                                    
                     var xDel = new lz.Delegate(this, 'updateX');
@@ -99,28 +97,31 @@
                     xDel.register(this, 'onwidth');
                     xDel.register(this, 'onborder');
                     
-                    new lz.Delegate(this, 'updateScrollMax', this.inp, 'onmaxheight');
+                    new lz.Delegate(this, 'updateScrollMax', this.inp, 'onscrollheight');
                     new lz.Delegate(this, 'updateStepSize', this.inp, 'onlineheight');
+                    // call once manually
+                    this.updateX();
+                    this.updateStepSize();
                 }
 
             }
         </method>
         
-        <method name="updateX" args="IGNORE_THIS_ARG">
+        <method name="updateX" args="IGNORE_THIS_ARG = null">
             if(this['_vs']){
                 this._vs.setAttribute("x", this.width - this._vs.width );
             }
         </method>
         
-        <method name="updateStepSize" args="IGNORE_THIS_ARG">
+        <method name="updateStepSize" args="IGNORE_THIS_ARG = null">
             if(this['_vs']){
                 this._vs.setAttribute("stepsize", this.inp.lineheight);
             }
         </method>
         
-        <method name="updateScrollMax" args="IGNORE_THIS_ARG">
+        <method name="updateScrollMax" args="IGNORE_THIS_ARG = null">
             if(this['_vs']){
-                this._vs.setAttribute("scrollmax", this.inp.maxheight);
+                this._vs.setAttribute("scrollmax", this.inp.scrollheight);
             }
         </method>
         

Modified: openlaszlo/trunk/lps/components/incubator/test/newvscrollbar-test.lzx
===================================================================
--- openlaszlo/trunk/lps/components/incubator/test/newvscrollbar-test.lzx	2009-02-04 02:40:23 UTC (rev 12742)
+++ openlaszlo/trunk/lps/components/incubator/test/newvscrollbar-test.lzx	2009-02-04 04:06:10 UTC (rev 12743)
@@ -4,9 +4,14 @@
 <include href="incubator/newhscrollbar.lzx" />
 
 <view height="200" width="200" bgcolor="0x7F7F7F">
-    <view height="800" width="800" />
-    <newvscrollbar />
-    <newhscrollbar />
+    <view height="800" width="800" name="foo">
+        <handler name="onclick">
+            setAttribute('width', this.width > 100 ? 100 : 800); 
+            setAttribute('height', this.height > 100 ? 100 : 800);
+        </handler>
+    </view>
+    <newvscrollbar scrolltarget="$once{parent.foo}" axis="y" scrollattr="y"/>
+    <newhscrollbar scrolltarget="$once{parent.foo}" axis="x" scrollattr="x"/>
 </view>
 </canvas>
 <!-- * X_LZ_COPYRIGHT_BEGIN ***************************************************

Modified: openlaszlo/trunk/lps/components/incubator/test/scrolledittext-test.lzx
===================================================================
--- openlaszlo/trunk/lps/components/incubator/test/scrolledittext-test.lzx	2009-02-04 02:40:23 UTC (rev 12742)
+++ openlaszlo/trunk/lps/components/incubator/test/scrolledittext-test.lzx	2009-02-04 04:06:10 UTC (rev 12743)
@@ -8,19 +8,25 @@
 
     <simplelayout axis="x" spacing="6"/>
     
-    <view>
+    <view bgcolor="papayawhip">
         <simplelayout axis="y" spacing="6"/>
-        <scrolledittext name="set1" x="20" y="20" width="300" height="200" vscrollbarclassname="newvscrollbar">this is the fun scrolledittext</scrolledittext>
+        <scrolledittext id="set1" x="20" y="20" width="300" height="100" vscrollbarclassname="newvscrollbar">this is the fun scrolledittext</scrolledittext>
         <button>Wider
-            <handler name="onclick">this.parent.set1.setAttribute("width", 350);</handler>
+            <handler name="onclick">set1.setAttribute("width", set1.width + 20);</handler>
         </button>
+        <button>Taller
+            <handler name="onclick">set1.setAttribute("height", set1.height + 20);</handler>
+        </button>
+        <button>Change style
+            <handler name="onclick">set1.inp.setAttribute("fontsize", set1.inp.fontsize != 9 ? 9 : 11);</handler>
+        </button>
     </view>
 
-        <scrolledittext x="20" y="20" width="300" height="200" vscrollbarclassname="newvscrollbar">this is the fun scrolledittext</scrolledittext>
+        <!--scrolledittext x="20" y="20" width="300" height="200" vscrollbarclassname="newvscrollbar">this is the fun scrolledittext</scrolledittext-->
 
 </canvas>
 <!-- * X_LZ_COPYRIGHT_BEGIN ***************************************************
-* Copyright 2006-2007 Laszlo Systems, Inc. All Rights Reserved.               *
+* Copyright 2006-2007, 2009 Laszlo Systems, Inc. All Rights Reserved.               *
 * Use is subject to license terms.                                            *
 * X_LZ_COPYRIGHT_END ****************************************************** -->
 <!-- @LZX_VERSION@                                                         -->



More information about the Laszlo-checkins mailing list