/* * Copyright 2012 AndroidPlot.com * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.androidplot.ui; import android.graphics.*; import android.view.MotionEvent; import android.view.View; import com.androidplot.exception.PlotRenderException; import com.androidplot.ui.widget.Widget; import com.androidplot.util.DisplayDimensions; import com.androidplot.util.ZLinkedList; public class LayoutManager extends ZLinkedList<Widget> implements View.OnTouchListener, Resizable { private boolean drawAnchorsEnabled = false; private Paint anchorPaint; private boolean drawOutlinesEnabled = false; private Paint outlinePaint; private boolean drawOutlineShadowsEnabled = false; private Paint outlineShadowPaint; private boolean drawMarginsEnabled = false; private Paint marginPaint; private boolean drawPaddingEnabled = false; private Paint paddingPaint; private DisplayDimensions displayDims = new DisplayDimensions(); // cache of widget rects //private HashMap<Widget, DisplayDimensions> widgetRects; { //widgetRects = new HashMap<Widget, DisplayDimensions>(); anchorPaint = new Paint(); anchorPaint.setStyle(Paint.Style.FILL); anchorPaint.setColor(Color.GREEN); outlinePaint = new Paint(); outlinePaint.setColor(Color.GREEN); outlinePaint.setStyle(Paint.Style.STROKE); marginPaint = new Paint(); marginPaint.setColor(Color.YELLOW); marginPaint.setStyle(Paint.Style.FILL); marginPaint.setAlpha(200); paddingPaint= new Paint(); paddingPaint.setColor(Color.BLUE); paddingPaint.setStyle(Paint.Style.FILL); paddingPaint.setAlpha(200); } /** * Invoked immediately following XML configuration. */ public synchronized void onPostInit() { for(Widget w : elements()) { w.onPostInit(); } } public LayoutManager() { } public void setMarkupEnabled(boolean enabled) { setDrawOutlinesEnabled(enabled); setDrawAnchorsEnabled(enabled); setDrawMarginsEnabled(enabled); setDrawPaddingEnabled(enabled); setDrawOutlineShadowsEnabled(enabled); } public void draw(Canvas canvas) throws PlotRenderException { if(isDrawMarginsEnabled()) { drawSpacing(canvas, displayDims.canvasRect, displayDims.marginatedRect, marginPaint); } if (isDrawPaddingEnabled()) { drawSpacing(canvas, displayDims.marginatedRect, displayDims.paddedRect, paddingPaint); } for (Widget widget : elements()) { //int canvasState = canvas.save(Canvas.ALL_SAVE_FLAG); // preserve clipping etc try { canvas.save(Canvas.ALL_SAVE_FLAG); PositionMetrics metrics = widget.getPositionMetrics(); float elementWidth = widget.getWidthPix(displayDims.paddedRect.width()); float elementHeight = widget.getHeightPix(displayDims.paddedRect.height()); PointF coords = widget.getElementCoordinates(elementHeight, elementWidth, displayDims.paddedRect, metrics); //RectF widgetRect = new RectF(coords.x, coords.y, coords.x + elementWidth, coords.y + elementHeight); //DisplayDimensions dims = widgetRects.get(widget); DisplayDimensions dims = widget.getWidgetDimensions(); //RectF widgetRect = widgetRects.get(widget); if (drawOutlineShadowsEnabled) { canvas.drawRect(dims.canvasRect, outlineShadowPaint); } // not positive why this is, but the rect clipped by clipRect is 1 less than the one drawn by drawRect. // so this is necessary to avoid clipping borders. I suspect that its a floating point // jitter issue. if (widget.isClippingEnabled()) { //RectF clipRect = new RectF(l-1, t-1, r + 1, b + 1); //canvas.clipRect(clipRect, Region.Op.REPLACE); canvas.clipRect(dims.canvasRect, Region.Op.INTERSECT); } widget.draw(canvas, dims.canvasRect); //RectF marginatedWidgetRect = widget.getMarginatedRect(dims.canvasRect); //RectF paddedWidgetRect = widget.getPaddedRect(marginatedWidgetRect); if (drawMarginsEnabled) { drawSpacing(canvas, dims.canvasRect, dims.marginatedRect, getMarginPaint()); } if (drawPaddingEnabled) { drawSpacing(canvas, dims.marginatedRect, dims.paddedRect, getPaddingPaint()); } if (drawAnchorsEnabled) { PointF anchorCoords = Widget.getAnchorCoordinates(coords.x, coords.y, elementWidth, elementHeight, metrics.getAnchor()); drawAnchor(canvas, anchorCoords); } if (drawOutlinesEnabled) { outlinePaint.setAntiAlias(true); canvas.drawRect(dims.canvasRect, outlinePaint); } } finally { //canvas.restoreToCount(canvasState); // restore clipping etc. canvas.restore(); } } } private void drawSpacing(Canvas canvas, RectF outer, RectF inner, Paint paint) { //int saved = canvas.save(Canvas.ALL_SAVE_FLAG); try { canvas.save(Canvas.ALL_SAVE_FLAG); canvas.clipRect(inner, Region.Op.DIFFERENCE); canvas.drawRect(outer, paint); //canvas.restoreToCount(saved); } finally { canvas.restore(); } } protected void drawAnchor(Canvas canvas, PointF coords) { float anchorSize = 4; canvas.drawRect(coords.x-anchorSize, coords.y-anchorSize, coords.x+anchorSize, coords.y+anchorSize, anchorPaint); } public boolean isDrawOutlinesEnabled() { return drawOutlinesEnabled; } public void setDrawOutlinesEnabled(boolean drawOutlinesEnabled) { this.drawOutlinesEnabled = drawOutlinesEnabled; } public Paint getOutlinePaint() { return outlinePaint; } public void setOutlinePaint(Paint outlinePaint) { this.outlinePaint = outlinePaint; } public boolean isDrawAnchorsEnabled() { return drawAnchorsEnabled; } public void setDrawAnchorsEnabled(boolean drawAnchorsEnabled) { this.drawAnchorsEnabled = drawAnchorsEnabled; } public boolean isDrawMarginsEnabled() { return drawMarginsEnabled; } public void setDrawMarginsEnabled(boolean drawMarginsEnabled) { this.drawMarginsEnabled = drawMarginsEnabled; } public Paint getMarginPaint() { return marginPaint; } public void setMarginPaint(Paint marginPaint) { this.marginPaint = marginPaint; } public boolean isDrawPaddingEnabled() { return drawPaddingEnabled; } public void setDrawPaddingEnabled(boolean drawPaddingEnabled) { this.drawPaddingEnabled = drawPaddingEnabled; } public Paint getPaddingPaint() { return paddingPaint; } public void setPaddingPaint(Paint paddingPaint) { this.paddingPaint = paddingPaint; } public boolean isDrawOutlineShadowsEnabled() { return drawOutlineShadowsEnabled; } public void setDrawOutlineShadowsEnabled(boolean drawOutlineShadowsEnabled) { this.drawOutlineShadowsEnabled = drawOutlineShadowsEnabled; if(drawOutlineShadowsEnabled && outlineShadowPaint == null) { // use a default shadow effect in the case where none has been set: outlineShadowPaint = new Paint(); outlineShadowPaint.setColor(Color.DKGRAY); outlineShadowPaint.setStyle(Paint.Style.FILL); outlineShadowPaint.setShadowLayer(3, 5, 5, Color.BLACK); } } public Paint getOutlineShadowPaint() { return outlineShadowPaint; } public void setOutlineShadowPaint(Paint outlineShadowPaint) { this.outlineShadowPaint = outlineShadowPaint; } @Override public boolean onTouch(View v, MotionEvent event) { return false; } /** * Recalculates layouts for all widgets using last set * DisplayDimensions. Care should be excersized when choosing when * to call this method as it is a relatively slow operation. */ public void refreshLayout() { //widgetRects.clear(); for (Widget widget : elements()) { widget.layout(displayDims); } } @Override public void layout(final DisplayDimensions dims) { this.displayDims = dims; refreshLayout(); } }