Zebra UI components itself are responsible for painting. In most cases they do rendering by implementing number of methods: “paint(g)” or “update(g)” or “paintOnTop(g)”. In the same time Zebra UI components need to share decorative elements like borders, background, etc. Zebra provides two simple classes that are supposed to be inherited whenever a developer needs to paint a visual element that can be shared between various UI components:

  • zebra.ui.View Paints a visual element on the provided surface. Developing a new decorative element requires the view class inherits “zebra.ui.View” class and implements “paint(g,x,y,w,h,c)” method. The method is responsible for painting the visual element on a rectangular surface “(x,y,w,h)” with the given “2d” context “g”. For instance let’s draw series of cells:
    // inherit "zebra.ui.View" class
    var CellsView=new zebra.Class(zebra.ui.View,[
        // implement "paint" method
        function paint(g,x,y,w,h,c) {
          var step = 10;
          g.setColor("red");
          for(var i=0; i<w/step; i++) {
             g.drawLine(x+i*step, y,
                        x+i*step, y + h);
          }
    
          g.setColor("orange");
          for(var i=0; i < h/step; i++) {
             g.drawLine(x, y + i*step,
                        x+w, y+i*step);
          }
      }
    ]);
    // create canvas
    var canvas = new zebra.ui.zCanvas(100,250);
    // instantiate and set the implemented
    // view as, for instance, the canvas root
    // UI component background
    canvas.root.setBackground(new CellsView());
    


    Live app:

  • zebra.ui.Render Render class is “zebra.ui.View” successor that is designed to render the given type of an object. Render always gets a target object that has to be visualized. For instance “zebra.ui.Picture” gets an image as the target and renders it the same way as “zebra.ui.View” classes do it – by implementing “paint(g,x,y,w,h,c)” method. As an example let’s implement a rectangular shape render:
      // target object is a structure that provides rectangle "(x, y)"
      // coordinates, size and color
      var target = { x:10, y:10,
                     width:100, height:100,
                     color: "blue" };
      // inherit render and implement "paint" method to draw a rectangle
      var RectRender = zebra.Class(zebra.ui.Render, [
          function paint(g, x, y, w, h, c) {
              g.setColor(this.target.color);
              g.drawRect(x + this.target.x, y + this.target.y,
                         this.target.width, this.target.height);
          }
      ]);
    
      var canvas = new zebra.ui.zCanvas(100,250);
      // use our implemented render as background of the
      // canvas root UI component
      canvas.root.setBackground(new RectRender(target));
    

Border view

Border is one possible decorative element of UI components. Border can be set by calling the “setBorder(border)” method. Border is a “zebra.ui.View” class implementation. Developers are free to design and render any imaginable border and apply it to any Zebra UI component. Border can influence two important UI component metrics:

  • Component gaps Border can add “top”, “left”, “right”, and “bottom” gaps. That means a UI component painting area will be clipped, taking in account the gaps and border adds. To specify border gaps a developer has to implement “getTop()” or “getLeft()” or “getRight()” or “getBottom” methods in his custom view class implementation. These methods have to return an integer value that reflects sides gaps in pixels:
        var SideBorder = zebra.Class(zebra.ui.View,[
           function getLeft() {
              return 8; // left gap in pixels
           },
    
           function getRight(){
              return 8; // right gap in pixels
           },
    
           function paint(g, x, y, w, h, c) {
               g.setColor("lightGray");
               g.drawLine(x, y, x, y + h - 1);
               g.drawLine(x + w - 1, y, x + w - 1,
                          y + h - 1);
               g.setColor("gray");
               g.drawLine(x+7, y, x+7,
                          y + h - 1);
               g.drawLine(x + w - 8, y,
                          x + w - 8, y + h - 1);
           }
       ]);
    
       var canvas = new zebra.ui.zCanvas(200,200);
       canvas.root.setBorder(new SideBorder());
    


    Live app:

  • Component shape A developer can control a component shape by specifying a border view. In this case border view has to implement the special “outline(g,x,y,w,h,c)” method. This method has to build a 2D context path and return true if the path has to be applied as the component shape. For instance, let’s create
    a round component with a round border view:
        var RoundBorder = zebra.Class(zebra.ui.View,[
           function paint(g, x, y, w, h, c) {
               g.setColor("black");
               this.outline(g, x, y, w, h, c);
               g.stroke();
           },
    
           function outline(g, x, y, w, h, c) {
              g.beginPath();
              g.arc(x + w/2, y + h/2, w/2, 0,
                    2*Math.PI, false);
              return true; // say we want to shape
           }
       ]);
    
       var canvas = new zebra.ui.zCanvas(200,200);
       canvas.root.setBorder(new RoundBorder());
    


    Live app:

Background view

Zebra UI component background is another UI component decorative element. Background can be customized by calling “setBackground(v)” method. In most cases developers pass a color (string) as the method argument. But it is also possible to paint a custom background. It can be done by implementing an own view or render or developers can use number of predefined ready-to use views and renders (picture, gradient, etc). Like it has been mentioned before the most often case is passing a color the component background has to be filled:

    ...
    var p = new zebra.ui.Panel();
    // use hex color encoding
    p.setBackground("#CCCCCC");

    // use color name
    p.setBackground("red");

    // use rgba color encoding
    p.setBackground("rgba(100,100,100,0.7)");
    ...

Another case is using existent, ready-to-use Zebra views and renders:

    ...
    var p = new Panel();
    // set gradient background
    p.setBackground(new zebra.ui.Gradient("black", "gray"));

    // set image as background
    p.setBackground(new zebra.ui.Picture(image));

    // set pattern background
    p.setBackground(new zebra.ui.Pattern(patternImage));

And implementing a custom view:

    var MyBg = zebra.Class(zebra.ui.View,[
      function paint(g,x,y,w,h,c) {
         g.setColor("green");
         for(var i=10; i < w; i+=10) {
            g.beginPath();
            g.arc(x+w/2,y+h/2,i,0,2*Math.PI,true);
            g.stroke();
         }
         g.setColor("red");
         g.drawLine(x+5,y+h/2,x+w-5,y+h/2,2);
         g.drawLine(x+w/2-1,y+5,x+w/2-1,y+h-5,2);
      }
    ]);

    var c = new zebra.ui.zCanvas(150,150);
    c.root.setBackground(new MyBg());

Live app:
 

Zebra views and renders

Zebra provides rich set of various views and renders that can be used out of box:

“zebra.ui.Gradient”
Vertical and horizontal gradient view. For instance use it as a background for an UI component:

    // shortcut to gradient class
    var Gradient = zebra.ui.Gradient;

    // create panel and set vertical gradient view as
    // it background
    var p = new zebra.ui.Panel();
    p.setBackground(new Gradient("orange", "yellow"));
    ...
    // create panel and set horizontal gradient view
    // as it background
    var p = new zebra.ui.Panel();
    p.setBackground(new Gradient("orange", "yellow",
                             zebra.layout.HORIZONTAL));

“zebra.ui.Radial”
Radial gradient view. For instance use it as a background for an UI component:

    // shortcut to Radial class
    var Radial = zebra.ui.Radial;
    // create panel and set radial gradient view as
    // it background
    var p = new zebra.ui.Panel();
    p.setBackground(new Radial("yellow", "red"));

“zebra.ui.Picture”
Picture render. The class instance gets an image to be rendered on the given surface. Also a developer can specify a rectangular part of an image to be painted. Use it, for instance, as an UI component background:

    // create UI component
    var panel = new zebra.ui.Panel();

    // set picture view as the component background
    panel.setBackground(new zebra.ui.Picture(img));

“zebra.ui.Pattern”
Pattern render.

    // create UI component
    var panel = new zebra.ui.Panel();
    panel.setBackground(new zebra.ui.Pattern(img));

“zebra.ui.Border”
Border view. Can be used to render UI components borders with the given color, width and corners radius:

    var p = new zebra.ui.Panel();
    // create and set 2 pixels orange border
    p.setBorder(new zebra.ui.Border("orange", 2));
    ...
    var p = new zebra.ui.Panel();
    // create and set 4 pixels red border with round
    // corners
    p.setBorder(new zebra.ui.Border("red", 4, 8));

“zebra.ui.Sunken”
“zebra.ui.Raised”
“zebra.ui.Etched”
“zebra.ui.Dotted”
“zebra.ui.RoundBorder”
Various predefined border views.

“zebra.ui.TextRender”
Text render. Text render paints text string or Zebra text models.

    ...
    var p = new zebra.ui.ViewPan();
    // create multilines text model
    var text = new zebra.data.Text("Line1\nLine2...");
    // render multilines text model using text render
    // set the render as "face" view of special
    // "zebra.ui.ViewPan" UI component
    p.setView(new zebra.ui.TextRender(text));

“zebra.ui.CompositeView”
Composite view allows developers to combine number of views to be rendered one by one as a stack of views. For instance let’s add some funny things to an exiting picture by composing the picture and custom view. The custom view paints moustache:

var Moustache = new zebra.Class(zebra.ui.View,[
    function paint(g,x,y,w,h,c) {
       g.setColor("rgba(0,0,0,0.3)");
       g.drawLine(w/2-15,h-h/4,w/2+25,h-h/4+5,2);
       g.drawLine(w/2-10,h-h/4+10,w/2+23,h-h/4+5,3);
       g.drawLine(w/2,h-h/4+20,w/2+25,h-h/4+5,2);

       g.drawLine(w/2+33,h-h/4+5,w/2+65,h-h/4-5,2);
       g.drawLine(w/2+33,h-h/4+5,w/2+70,h-h/4+5,2);
       g.drawLine(w/2+33,h-h/4+5,w/2+59,h-h/4+15,3);
    }
]);

var p = new zebra.ui.Panel();
var CompositeView = zebra.ui.CompositeView;
p.setBackground(new CompositeView(new Picture(img),
                                  new Moustache()));

Shorthand to decorate UI components

Developing a specific view that has to be applied only for the given particular case can be simplified by avoiding an own view class declaration. Just pass “paint(g,x,y,w,h,c)” view method implementation directly as argument to “setBorder(v)” or “setBackground(b)” methods:

   var p = new zebra.ui.Panel();
   // pass "paint" zebra.ui.View method implementation
   // directly to "setBackground" method view. View class
   // instance will be created automatically with the passed
   // paint method
   p.setBackground(function (g,x,y,w,h,c) {
      g.setColor("red");
      g.drawRect(x,y,w-1,h-1);
      ...
   });

Another way to make specific custom view declaration shorter is instantiating “zebra.view.View” (or any other view class) class as an anonymous classes:

  var p = new zebra.ui.Panel();
  // instantiate "zebra.ui.View" anonymous class,
  // implement "paint" method and pass the instance to
  // be set as background view
  p.setBackground(new zebra.ui.View([
      function (g,x,y,w,h,c) {
          g.setColor("red");
          g.drawRect(x,y,w-1,h-1);
          ...
      }
   ]));

View and preferred size

Sometimes your specific UI component implementation can widely use different views and renders. For instance “zebra.ui.Checkbox” component allows developers to customize “tick” element by specifying number of views. In this situation view elements can have influence to UI component preferred size calculation. Developers has to implement “getPreferredSize()” method that returns the size the view wants to have. The expected returned value is { width:intValue, height:intValue } structure:

    var MyView = zebra.Class(zebra.ui.View, [
         function paint(g,x,y,w,h,c) {
            // paint something
            ...
         },

        // tell the size the view wants to have
        function getPreferredSize() {
           return { width: 100, height: 20 }
        }
    ]);
    ...