Home | History | Annotate | Download | only in ui
      1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 'use strict';
      6 
      7 base.requireStylesheet('ui.quad_stack');
      8 
      9 base.require('base.properties');
     10 base.require('base.bbox2');
     11 base.require('base.quad');
     12 base.require('base.utils');
     13 base.require('base.raf');
     14 base.require('ui.quad_view');
     15 base.require('cc.region');
     16 base.require('ui.camera');
     17 base.require('ui.rect_view');
     18 
     19 base.exportTo('ui', function() {
     20   var QuadView = ui.QuadView;
     21 
     22   function validateQuads(quads) {
     23     for (var i = 0; i < quads.length; i++) {
     24       if (quads[i].stackingGroupId === undefined)
     25         throw new Error('All quads must have stackingGroupIds');
     26     }
     27   }
     28 
     29   /**
     30    * @constructor
     31    */
     32   var QuadStack = ui.define('quad-stack');
     33 
     34   QuadStack.prototype = {
     35     __proto__: HTMLUnknownElement.prototype,
     36 
     37     decorate: function() {
     38       this.contentContainer_ = document.createElement('view-container');
     39       this.appendChild(this.contentContainer_);
     40       this.viewport_ = undefined;
     41       this.worldViewportRectView_ = new ui.RectView();
     42       this.quads_ = undefined;
     43     },
     44 
     45     initialize: function(unpaddedWorldRect, opt_worldViewportRect) {
     46       this.viewport_ = new ui.QuadViewViewport(unpaddedWorldRect);
     47 
     48       this.viewport_.addEventListener('change', function() {
     49         this.worldViewportRectView_.viewport = this.viewport_;
     50       }.bind(this));
     51 
     52       this.worldViewportRect_ = base.Rect.FromXYWH(
     53           opt_worldViewportRect.x || 0,
     54           opt_worldViewportRect.y || 0,
     55           opt_worldViewportRect.width,
     56           opt_worldViewportRect.height
     57           );
     58 
     59       this.worldViewportRectView_.viewport = this.viewport_;
     60       this.worldViewportRectView_.rect = this.worldViewportRect_;
     61     },
     62 
     63     get layers() {
     64       return this.layers_;
     65     },
     66 
     67     set layers(newValue) {
     68       base.setPropertyAndDispatchChange(this, 'layers', newValue);
     69     },
     70 
     71     get quads() {
     72       return this.quads_;
     73     },
     74 
     75     set quads(quads) {
     76       validateQuads(quads);
     77       this.quads_ = quads;
     78       this.updateContents_();
     79     },
     80 
     81     get viewport() {
     82       return this.viewport_;
     83     },
     84 
     85     get worldViewportRect() {
     86       return this.worldViewportRect_;
     87     },
     88 
     89     get worldViewportRectView() {
     90       return this.worldViewportRectView_;
     91     },
     92 
     93     get contentContainer() {
     94       return this.contentContainer_;
     95     },
     96 
     97     updateContents_: function() {
     98       // Build the stacks.
     99       var stackingGroupsById = {};
    100       var quads = this.quads;
    101       for (var i = 0; i < quads.length; i++) {
    102         var quad = quads[i];
    103         if (stackingGroupsById[quad.stackingGroupId] === undefined)
    104           stackingGroupsById[quad.stackingGroupId] = [];
    105         stackingGroupsById[quad.stackingGroupId].push(quad);
    106       }
    107 
    108       // Remove worldViewportRectView to re-insert after Quads.
    109       if (this.worldViewportRectView_.parentNode === this.contentContainer_)
    110         this.contentContainer_.removeChild(this.worldViewportRectView_);
    111 
    112       // Get rid of old quad views if needed.
    113       var numStackingGroups = base.dictionaryValues(stackingGroupsById).length;
    114       while (this.contentContainer_.children.length > numStackingGroups) {
    115         var n = this.contentContainer_.children.length - 1;
    116         this.contentContainer_.removeChild(
    117             this.contentContainer_.children[n]);
    118       }
    119 
    120       // Helper function to create a new quad view and track the current one.
    121       var that = this;
    122       var curQuadViewIndex = -1;
    123       var curQuadView = undefined;
    124       function appendNewQuadView() {
    125         curQuadViewIndex++;
    126         if (curQuadViewIndex < that.contentContainer_.children.length) {
    127           curQuadView = that.contentContainer_.children[curQuadViewIndex];
    128         } else {
    129           curQuadView = new QuadView();
    130           that.contentContainer_.appendChild(curQuadView);
    131         }
    132         curQuadView.quads = undefined;
    133         curQuadView.viewport = that.viewport_;
    134         curQuadView.pendingQuads = [];
    135         curQuadView.region = new cc.Region();
    136         return curQuadView;
    137       }
    138 
    139       appendNewQuadView();
    140       for (var stackingGroupId in stackingGroupsById) {
    141         var stackingGroup = stackingGroupsById[stackingGroupId];
    142         var bbox = new base.BBox2();
    143         stackingGroup.forEach(function(q) { bbox.addQuad(q); });
    144         var bboxRect = bbox.asRect();
    145 
    146         if (curQuadView.region.rectIntersects(bboxRect))
    147           appendNewQuadView();
    148         curQuadView.region.rects.push(bboxRect);
    149         stackingGroup.forEach(function(q) {
    150           curQuadView.pendingQuads.push(q);
    151         });
    152       }
    153 
    154       // Add worldViewportRectView after the Quads.
    155       this.contentContainer_.appendChild(this.worldViewportRectView_);
    156 
    157       for (var i = 0; i < this.contentContainer_.children.length; i++) {
    158         var child = this.contentContainer_.children[i];
    159         if (child instanceof ui.QuadView) {
    160           child.quads = child.pendingQuads;
    161           delete child.pendingQuads;
    162         }
    163       }
    164 
    165       this.viewport.updateBoxSize(this.contentContainer_);
    166       this.layers = this.contentContainer_.children;
    167     },
    168 
    169 
    170   };
    171 
    172   return {
    173     QuadStack: QuadStack
    174   };
    175 });
    176