/* | |
* 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(); | |
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.clipOutRect(inner); | |
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(); | |
} | |
} |