Home | History | Annotate | Download | only in ui
      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 
     17 package com.androidplot.ui;
     18 
     19 import android.graphics.*;
     20 import android.view.MotionEvent;
     21 import android.view.View;
     22 import com.androidplot.exception.PlotRenderException;
     23 import com.androidplot.ui.widget.Widget;
     24 import com.androidplot.util.DisplayDimensions;
     25 import com.androidplot.util.ZLinkedList;
     26 
     27 public 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(Canvas.ALL_SAVE_FLAG);
     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(Canvas.ALL_SAVE_FLAG);
    152             canvas.clipRect(inner, Region.Op.DIFFERENCE);
    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