View Javadoc
1   /**
2    * This file Copyright (c) 2015-2018 Magnolia International
3    * Ltd.  (http://www.magnolia-cms.com). All rights reserved.
4    *
5    *
6    * This file is dual-licensed under both the Magnolia
7    * Network Agreement and the GNU General Public License.
8    * You may elect to use one or the other of these licenses.
9    *
10   * This file is distributed in the hope that it will be
11   * useful, but AS-IS and WITHOUT ANY WARRANTY; without even the
12   * implied warranty of MERCHANTABILITY or FITNESS FOR A
13   * PARTICULAR PURPOSE, TITLE, or NONINFRINGEMENT.
14   * Redistribution, except as permitted by whichever of the GPL
15   * or MNA you select, is prohibited.
16   *
17   * 1. For the GPL license (GPL), you can redistribute and/or
18   * modify this file under the terms of the GNU General
19   * Public License, Version 3, as published by the Free Software
20   * Foundation.  You should have received a copy of the GNU
21   * General Public License, Version 3 along with this program;
22   * if not, write to the Free Software Foundation, Inc., 51
23   * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
24   *
25   * 2. For the Magnolia Network Agreement (MNA), this file
26   * and the accompanying materials are made available under the
27   * terms of the MNA which accompanies this distribution, and
28   * is available at http://www.magnolia-cms.com/mna.html
29   *
30   * Any modifications to this file must keep this entire header
31   * intact.
32   *
33   */
34  package info.magnolia.ui.vaadin.gwt.client.layout.lazylayout.widget;
35  
36  import com.google.gwt.dom.client.Element;
37  import com.google.gwt.dom.client.Node;
38  import com.google.gwt.dom.client.Style;
39  import com.google.gwt.user.client.DOM;
40  import com.vaadin.client.ComputedStyle;
41  
42  /**
43   * Tracks the base sizes of the thumbnails set from the server, applies those to all the thumbnails,
44   * calculates the resulting actual size. Also is capable of applying a scaling ratio to the thumbnails.
45   * 6.0 change: always scale thumbnails to fit the full width of view; width to height ratio is constant.
46   */
47  public class ThumbnailsSizeKeeper {
48  
49      private static final int MAX_WIDTH = 260; // mock-up size + 1px border
50      private static final int MAX_HEIGHT = 208; // mock-up size + 1px border
51  
52      private int calculatedWidth;
53  
54      private int calculatedHeight;
55  
56      private int baseWidth;
57  
58      private int baseHeight;
59  
60      private Element elementsParent;
61  
62      private float ratio;
63  
64      private int unscaledWidth;
65  
66      private int unscaledHeight;
67      private int verticalDecorations;
68      private int horizontalDecorations;
69  
70      ThumbnailsSizeKeeper(Element elementsParent) {
71          this.elementsParent = elementsParent;
72      }
73  
74      public void scale(float ratio) {
75          this.ratio = ratio;
76          updateCalculatedOffsetSizes();
77          doUpdateAllElementsSize(calculatedWidth, calculatedHeight);
78      }
79  
80      void scaleToWidth(int width) {
81          scale((float)(width - unscaledWidth) / (maxWidth() - baseWidth));
82      }
83  
84      int height() {
85          return this.calculatedHeight;
86      }
87  
88      int width() {
89          return this.calculatedWidth;
90      }
91  
92      /**
93       * @return maximum width of tile, close to default size given by mockup, but scaled to fit full width without remainder.
94       */
95      int maxWidth() {
96          int tiles = (int) Math.round((double) this.elementsParent.getOffsetWidth() / MAX_WIDTH);
97          return elementsParent.getOffsetWidth() / tiles;
98      }
99  
100     boolean updateAllElementsSize(int width, int height) {
101         if (this.baseHeight != height || this.baseWidth != width) {
102             this.baseHeight = height;
103             this.baseWidth = width;
104 
105             doUpdateAllElementsSize(width, height);
106             updateCalculatedOffsetSizes();
107             return true;
108         }
109 
110         return false;
111     }
112 
113     void applySizeToElement(Element element) {
114         int scaledWidth = scaleWidth(baseWidth, ratio);
115         doSetElementSize(scaledWidth, (int) Math.round((double) scaledWidth * MAX_HEIGHT / MAX_WIDTH), element);
116     }
117 
118     private int scaleWidth(int minValue, double ratio) {
119         long scaledWidth = Math.round((maxWidth() - minValue) * ratio + minValue);
120         return (int) Math.min(scaledWidth, maxWidth());
121     }
122 
123     private void doUpdateAllElementsSize(int width, int height) {
124         Node element = elementsParent.getFirstChildElement();
125         while (element != null) {
126             doSetElementSize(width, height, Element.as(element));
127             element = element.getNextSibling();
128         }
129     }
130 
131     private void doSetElementSize(int width, int height, Element element) {
132         final Style style = element.getStyle();
133         style.setFontSize(width * 0.75d, Style.Unit.PX); // can be removed with old UI
134         style.setWidth(width, Style.Unit.PX);
135         style.setHeight(height, Style.Unit.PX);
136 
137         addOrRemoveClass(height <= 155, "caption-hidden", element);
138     }
139 
140     private void addOrRemoveClass(boolean addClass, String className, Element element) {
141         if (addClass) {
142             element.addClassName(className);
143         } else {
144             element.removeClassName(className);
145         }
146     }
147 
148     private void updateCalculatedOffsetSizes() {
149         ComputedStyle cs;
150 
151         int[] padding;
152         int[] border;
153         int[] margin;
154 
155         if (elementsParent.getChildCount() > 0) {
156             final Element firstElement = Element.as(elementsParent.getFirstChild());
157             cs = new ComputedStyle(firstElement);
158 
159             padding = cs.getPadding();
160             border = cs.getBorder();
161             margin = cs.getMargin();
162         } else {
163             final Element stub = Element.as(DOM.createDiv());
164             stub.addClassName("thumbnail");
165             elementsParent.appendChild(stub);
166             cs = new ComputedStyle(stub);
167             padding = cs.getPadding();
168             border = cs.getBorder();
169             margin = cs.getMargin();
170 
171             elementsParent.removeChild(stub);
172         }
173 
174         horizontalDecorations = padding[1] + padding[3] + border[1] + border[3] + margin[1] + margin[3];
175         verticalDecorations = padding[0] + padding[2] + border[0] + border[2] + margin[0] + margin[2];
176 
177         this.unscaledWidth = baseWidth + horizontalDecorations;
178         this.unscaledHeight = baseHeight + verticalDecorations;
179 
180         this.calculatedWidth = scaleWidth(baseWidth, ratio);
181         this.calculatedHeight = (int) Math.round((double) this.calculatedWidth * MAX_HEIGHT / MAX_WIDTH);
182 
183     }
184 
185     public float getScaleRatio() {
186         return ratio;
187     }
188 
189     public int getUnscaledWidth() {
190         return unscaledWidth;
191     }
192 
193     public int getUnscaledHeight() {
194         return unscaledHeight;
195     }
196 
197     void setElementsParent(Element elementsParent) {
198         this.elementsParent = elementsParent;
199     }
200 }