1/* 2 * Copyright 2012 AndroidPlot.com 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.androidplot.ui; 18 19import android.graphics.*; 20import android.view.MotionEvent; 21import android.view.View; 22import com.androidplot.exception.PlotRenderException; 23import com.androidplot.ui.widget.Widget; 24import com.androidplot.util.DisplayDimensions; 25import com.androidplot.util.ZLinkedList; 26 27public class LayoutManager extends ZLinkedList<Widget> 28 implements View.OnTouchListener, Resizable { 29 private boolean drawAnchorsEnabled = false; 30 private Paint anchorPaint; 31 private boolean drawOutlinesEnabled = false; 32 private Paint outlinePaint; 33 private boolean drawOutlineShadowsEnabled = false; 34 private Paint outlineShadowPaint; 35 private boolean drawMarginsEnabled = false; 36 private Paint marginPaint; 37 private boolean drawPaddingEnabled = false; 38 private Paint paddingPaint; 39 private DisplayDimensions displayDims = new DisplayDimensions(); 40 41 // cache of widget rects 42 //private HashMap<Widget, DisplayDimensions> widgetRects; 43 44 { 45 //widgetRects = new HashMap<Widget, DisplayDimensions>(); 46 anchorPaint = new Paint(); 47 anchorPaint.setStyle(Paint.Style.FILL); 48 anchorPaint.setColor(Color.GREEN); 49 outlinePaint = new Paint(); 50 outlinePaint.setColor(Color.GREEN); 51 outlinePaint.setStyle(Paint.Style.STROKE); 52 marginPaint = new Paint(); 53 marginPaint.setColor(Color.YELLOW); 54 marginPaint.setStyle(Paint.Style.FILL); 55 marginPaint.setAlpha(200); 56 paddingPaint= new Paint(); 57 paddingPaint.setColor(Color.BLUE); 58 paddingPaint.setStyle(Paint.Style.FILL); 59 paddingPaint.setAlpha(200); 60 } 61 62 /** 63 * Invoked immediately following XML configuration. 64 */ 65 public synchronized void onPostInit() { 66 for(Widget w : elements()) { 67 w.onPostInit(); 68 } 69 } 70 71 public LayoutManager() { 72 } 73 74 public void setMarkupEnabled(boolean enabled) { 75 setDrawOutlinesEnabled(enabled); 76 setDrawAnchorsEnabled(enabled); 77 setDrawMarginsEnabled(enabled); 78 setDrawPaddingEnabled(enabled); 79 setDrawOutlineShadowsEnabled(enabled); 80 } 81 82 public void draw(Canvas canvas) throws PlotRenderException { 83 if(isDrawMarginsEnabled()) { 84 drawSpacing(canvas, displayDims.canvasRect, displayDims.marginatedRect, marginPaint); 85 } 86 if (isDrawPaddingEnabled()) { 87 drawSpacing(canvas, displayDims.marginatedRect, displayDims.paddedRect, paddingPaint); 88 } 89 for (Widget widget : elements()) { 90 //int canvasState = canvas.save(Canvas.ALL_SAVE_FLAG); // preserve clipping etc 91 try { 92 canvas.save(); 93 PositionMetrics metrics = widget.getPositionMetrics(); 94 float elementWidth = widget.getWidthPix(displayDims.paddedRect.width()); 95 float elementHeight = widget.getHeightPix(displayDims.paddedRect.height()); 96 PointF coords = widget.getElementCoordinates(elementHeight, 97 elementWidth, displayDims.paddedRect, metrics); 98 99 //RectF widgetRect = new RectF(coords.x, coords.y, coords.x + elementWidth, coords.y + elementHeight); 100 //DisplayDimensions dims = widgetRects.get(widget); 101 DisplayDimensions dims = widget.getWidgetDimensions(); 102 //RectF widgetRect = widgetRects.get(widget); 103 104 if (drawOutlineShadowsEnabled) { 105 canvas.drawRect(dims.canvasRect, outlineShadowPaint); 106 } 107 108 // not positive why this is, but the rect clipped by clipRect is 1 less than the one drawn by drawRect. 109 // so this is necessary to avoid clipping borders. I suspect that its a floating point 110 // jitter issue. 111 if (widget.isClippingEnabled()) { 112 //RectF clipRect = new RectF(l-1, t-1, r + 1, b + 1); 113 //canvas.clipRect(clipRect, Region.Op.REPLACE); 114 canvas.clipRect(dims.canvasRect, Region.Op.INTERSECT); 115 } 116 widget.draw(canvas, dims.canvasRect); 117 118 //RectF marginatedWidgetRect = widget.getMarginatedRect(dims.canvasRect); 119 //RectF paddedWidgetRect = widget.getPaddedRect(marginatedWidgetRect); 120 121 if (drawMarginsEnabled) { 122 drawSpacing(canvas, dims.canvasRect, dims.marginatedRect, getMarginPaint()); 123 } 124 125 if (drawPaddingEnabled) { 126 drawSpacing(canvas, dims.marginatedRect, dims.paddedRect, getPaddingPaint()); 127 } 128 129 if (drawAnchorsEnabled) { 130 PointF anchorCoords = 131 Widget.getAnchorCoordinates(coords.x, coords.y, elementWidth, 132 elementHeight, metrics.getAnchor()); 133 drawAnchor(canvas, anchorCoords); 134 } 135 136 137 if (drawOutlinesEnabled) { 138 outlinePaint.setAntiAlias(true); 139 canvas.drawRect(dims.canvasRect, outlinePaint); 140 } 141 } finally { 142 //canvas.restoreToCount(canvasState); // restore clipping etc. 143 canvas.restore(); 144 } 145 } 146 } 147 148 private void drawSpacing(Canvas canvas, RectF outer, RectF inner, Paint paint) { 149 //int saved = canvas.save(Canvas.ALL_SAVE_FLAG); 150 try { 151 canvas.save(); 152 canvas.clipOutRect(inner); 153 canvas.drawRect(outer, paint); 154 //canvas.restoreToCount(saved); 155 } finally { 156 canvas.restore(); 157 } 158 } 159 160 protected void drawAnchor(Canvas canvas, PointF coords) { 161 float anchorSize = 4; 162 canvas.drawRect(coords.x-anchorSize, coords.y-anchorSize, coords.x+anchorSize, coords.y+anchorSize, anchorPaint); 163 164 } 165 166 public boolean isDrawOutlinesEnabled() { 167 return drawOutlinesEnabled; 168 } 169 170 public void setDrawOutlinesEnabled(boolean drawOutlinesEnabled) { 171 this.drawOutlinesEnabled = drawOutlinesEnabled; 172 } 173 174 public Paint getOutlinePaint() { 175 return outlinePaint; 176 } 177 178 public void setOutlinePaint(Paint outlinePaint) { 179 this.outlinePaint = outlinePaint; 180 } 181 182 public boolean isDrawAnchorsEnabled() { 183 return drawAnchorsEnabled; 184 } 185 186 public void setDrawAnchorsEnabled(boolean drawAnchorsEnabled) { 187 this.drawAnchorsEnabled = drawAnchorsEnabled; 188 } 189 190 public boolean isDrawMarginsEnabled() { 191 return drawMarginsEnabled; 192 } 193 194 public void setDrawMarginsEnabled(boolean drawMarginsEnabled) { 195 this.drawMarginsEnabled = drawMarginsEnabled; 196 } 197 198 public Paint getMarginPaint() { 199 return marginPaint; 200 } 201 202 public void setMarginPaint(Paint marginPaint) { 203 this.marginPaint = marginPaint; 204 } 205 206 public boolean isDrawPaddingEnabled() { 207 return drawPaddingEnabled; 208 } 209 210 public void setDrawPaddingEnabled(boolean drawPaddingEnabled) { 211 this.drawPaddingEnabled = drawPaddingEnabled; 212 } 213 214 public Paint getPaddingPaint() { 215 return paddingPaint; 216 } 217 218 public void setPaddingPaint(Paint paddingPaint) { 219 this.paddingPaint = paddingPaint; 220 } 221 222 public boolean isDrawOutlineShadowsEnabled() { 223 return drawOutlineShadowsEnabled; 224 } 225 226 public void setDrawOutlineShadowsEnabled(boolean drawOutlineShadowsEnabled) { 227 this.drawOutlineShadowsEnabled = drawOutlineShadowsEnabled; 228 if(drawOutlineShadowsEnabled && outlineShadowPaint == null) { 229 // use a default shadow effect in the case where none has been set: 230 outlineShadowPaint = new Paint(); 231 outlineShadowPaint.setColor(Color.DKGRAY); 232 outlineShadowPaint.setStyle(Paint.Style.FILL); 233 outlineShadowPaint.setShadowLayer(3, 5, 5, Color.BLACK); 234 } 235 } 236 237 public Paint getOutlineShadowPaint() { 238 return outlineShadowPaint; 239 } 240 241 public void setOutlineShadowPaint(Paint outlineShadowPaint) { 242 this.outlineShadowPaint = outlineShadowPaint; 243 } 244 245 @Override 246 public boolean onTouch(View v, MotionEvent event) { 247 return false; 248 } 249 250 /** 251 * Recalculates layouts for all widgets using last set 252 * DisplayDimensions. Care should be excersized when choosing when 253 * to call this method as it is a relatively slow operation. 254 */ 255 public void refreshLayout() { 256 //widgetRects.clear(); 257 for (Widget widget : elements()) { 258 widget.layout(displayDims); 259 } 260 } 261 262 @Override 263 public void layout(final DisplayDimensions dims) { 264 this.displayDims = dims; 265 266 refreshLayout(); 267 } 268} 269