radialdemo.RadialMenuWidget.java Source code

Java tutorial

Introduction

Here is the source code for radialdemo.RadialMenuWidget.java

Source

/** Copyright (C) 2012 
 * Jason Valestin (valestin@gmail.com ) and Arindam Nath (strider2023@gmail.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 radialdemo;

import java.util.ArrayList;
import java.util.List;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.support.v4.app.Fragment;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.widget.PopupWindow;

/**
 * This is the core class that handles the widget display and user interaction.
 * 
 * @author Jason Valestin (valestin@gmail.com )
 * @author Arindam Nath (strider2023@gmail.com)
 */
public class RadialMenuWidget extends View {

    private RadialMenuHelper helper;

    private List<RadialMenuItem> menuEntries = new ArrayList<RadialMenuItem>();
    private RadialMenuItem centerCircle = null;

    private float screen_density = getContext().getResources().getDisplayMetrics().density;

    private int defaultColor = Color.rgb(34, 96, 120); // default color of wedge
    // pieces
    private int defaultAlpha = 180; // transparency of the colors, 255=Opague,
    // 0=Transparent
    private int wedge2Color = Color.rgb(50, 50, 50); // default color of wedge
    // pieces
    private int wedge2Alpha = 210;
    private int outlineColor = Color.rgb(150, 150, 150); // color of outline
    private int outlineAlpha = 255; // transparency of outline
    private int selectedColor = Color.rgb(70, 130, 180); // color to fill when
    // something is
    // selected
    private int selectedAlpha = 210; // transparency of fill when something is
    // selected

    private int disabledColor = Color.rgb(34, 96, 120); // color to fill when
    // something is selected
    private int disabledAlpha = 100; // transparency of fill when something is
    // selected

    private int pictureAlpha = 255; // transparency of images

    private int textColor = Color.rgb(255, 255, 255); // color to fill when
    // something is selected
    private int textAlpha = 255; // transparency of fill when something is
    // selected

    private int headerTextColor = Color.rgb(255, 255, 255); // color of header
    // text
    private int headerTextAlpha = 255; // transparency of header text
    private int headerBackgroundColor = Color.rgb(0, 0, 0); // color of header
    // background
    private int headerBackgroundAlpha = 180; // transparency of header
    // background

    private int wedgeQty = 1; // Number of wedges
    private RadialMenuWedge[] Wedges = new RadialMenuWedge[wedgeQty];
    private RadialMenuWedge selected = null; // Keeps track of which wedge is
    // selected
    private RadialMenuWedge enabled = null; // Keeps track of which wedge is
    // enabled for outer ring
    private Rect[] iconRect = new Rect[wedgeQty];

    private int wedgeQty2 = 1; // Number of wedges
    private RadialMenuWedge[] Wedges2 = new RadialMenuWedge[wedgeQty2];
    private RadialMenuWedge selected2 = null; // Keeps track of which wedge is
    // selected
    private Rect[] iconRect2 = new Rect[wedgeQty2];
    private RadialMenuInterface wedge2Data = null; // Keeps track off which menuItem
    // data is being used for the
    // outer ring

    private int MinSize = scalePX(35); // Radius of inner ring size
    private int MaxSize = scalePX(90); // Radius of outer ring size
    private int r2MinSize = MaxSize + scalePX(5); // Radius of inner second ring
    // size
    private int r2MaxSize = r2MinSize + scalePX(45); // Radius of outer second
    // ring size
    private int MinIconSize = scalePX(15); // Min Size of Image in Wedge
    private int MaxIconSize = scalePX(35); // Max Size of Image in Wedge
    // private int BitmapSize = scalePX(40); //Size of Image in Wedge
    private int cRadius = MinSize - scalePX(7); // Inner Circle Radius
    private int textSize = scalePX(15); // TextSize
    private int animateTextSize = textSize;

    private int xPosition = scalePX(120); // Center X location of Radial Menu
    private int yPosition = scalePX(120); // Center Y location of Radial Menu

    private int xSource = 0; // Source X of clicked location
    private int ySource = 0; // Center Y of clicked location
    private boolean showSource = false; // Display icon where at source location

    private boolean inWedge = false; // Identifies touch event was in first
    // wedge
    private boolean inWedge2 = false; // Identifies touch event was in second
    // wedge
    private boolean inCircle = false; // Identifies touch event was in middle
    // circle

    private boolean Wedge2Shown = false; // Identifies 2nd wedge is drawn
    private boolean HeaderBoxBounded = false; // Identifies if header box is
    // drawn

    private String headerString = null;
    private int headerTextSize = textSize; // TextSize
    private int headerBuffer = scalePX(8);
    private Rect textRect = new Rect();
    private RectF textBoxRect = new RectF();
    private int headerTextLeft;
    private int headerTextBottom;

    private static final int ANIMATE_IN = 1;
    private static final int ANIMATE_OUT = 2;

    private int animateSections = 4;
    private int r2VariableSize;
    private boolean animateOuterIn = false;
    private boolean animateOuterOut = false;

    private PopupWindow mWindow;

    /**
     * Radial menu widget constructor.
     * @param context - Application Context.
     * <strong> Usage </strong>
     * 
     * RadialMenuWidget pieMenu = new RadialMenuWidget(this);
     * pieMenu.addMenuEntry(menuItem);
     * pieMenu.show(view);
     */
    public RadialMenuWidget(Context context) {
        super(context);
        helper = new RadialMenuHelper();
        mWindow = helper.initPopup(context);
        // Gets screen specs and defaults to center of screen
        this.xPosition = (getResources().getDisplayMetrics().widthPixels) / 2;
        this.yPosition = (getResources().getDisplayMetrics().heightPixels) / 2;

        determineWedges();
        helper.onOpenAnimation(this, xPosition, yPosition, xSource, ySource);
    }

    public RadialMenuWidget(Context context, AttributeSet attrs) {
        super(context, attrs);
        helper = new RadialMenuHelper();
        mWindow = helper.initPopup(context);
        // Gets screen specs and defaults to center of screen
        this.xPosition = (getResources().getDisplayMetrics().widthPixels) / 2;
        this.yPosition = (getResources().getDisplayMetrics().heightPixels) / 2;

        determineWedges();
        helper.onOpenAnimation(this, xPosition, yPosition, xSource, ySource);
    }

    @Override
    public boolean onTouchEvent(MotionEvent e) {
        int state = e.getAction();
        int eventX = (int) e.getX();
        int eventY = (int) e.getY();
        if (state == MotionEvent.ACTION_DOWN) {
            // selected = null;
            // selected2 = null;
            inWedge = false;
            inWedge2 = false;
            inCircle = false;

            // Checks if a pie slice is selected in first Wedge
            for (int i = 0; i < Wedges.length; i++) {
                RadialMenuWedge f = Wedges[i];
                double slice = (2 * Math.PI) / wedgeQty;
                double start = (2 * Math.PI) * (0.75) - (slice / 2); // this is
                // done
                // so
                // top
                // slice
                // is
                // the
                // centered
                // on
                // top
                // of
                // the
                // circle

                inWedge = helper.pntInWedge(eventX, eventY, xPosition, yPosition, MinSize, MaxSize,
                        (i * slice) + start, slice);

                if (inWedge == true) {
                    selected = f;
                    break;
                }
            }

            // Checks if a pie slice is selected in second Wedge
            if (Wedge2Shown == true) {
                for (int i = 0; i < Wedges2.length; i++) {
                    RadialMenuWedge f = Wedges2[i];
                    double slice = (2 * Math.PI) / wedgeQty2;
                    double start = (2 * Math.PI) * (0.75) - (slice / 2); // this
                    // is
                    // done
                    // so
                    // top
                    // slice
                    // is
                    // the
                    // centered
                    // on
                    // top
                    // of
                    // the
                    // circle

                    inWedge2 = helper.pntInWedge(eventX, eventY, xPosition, yPosition, r2MinSize, r2MaxSize,
                            (i * slice) + start, slice);

                    if (inWedge2 == true) {
                        selected2 = f;
                        break;
                    }
                }

            }

            // Checks if center is there and is selected
            if (centerCircle != null) {
                inCircle = helper.pntInCircle(eventX, eventY, xPosition, yPosition, cRadius);
            }

        } else if (state == MotionEvent.ACTION_UP) {
            // execute commands...
            // put in stuff here to "return" the button that was pressed.
            if (inCircle == true) {
                if (Wedge2Shown == true) {
                    enabled = null;
                    animateOuterIn = true; // sets Wedge2Shown = false;
                }
                selected = null;
                centerCircle.menuActiviated();

            } else if (selected != null) {
                for (int i = 0; i < Wedges.length; i++) {
                    RadialMenuWedge f = Wedges[i];
                    if (f == selected) {

                        // Checks if a inner ring is enabled if so closes the
                        // outer ring an
                        if (enabled != null) {
                            enabled = null;
                            animateOuterIn = true; // sets Wedge2Shown = false;
                            // If outer ring is not enabled, then executes event
                        } else {
                            menuEntries.get(i).menuActiviated();

                            // Figures out how many outer rings
                            if (menuEntries.get(i).getChildren() != null) {
                                determineOuterWedges(menuEntries.get(i));
                                enabled = f;
                                animateOuterOut = true; // sets Wedge2Shown =
                                // true;
                            } else {
                                Wedge2Shown = false;
                            }
                        }
                        selected = null;
                    }
                }
            } else if (selected2 != null) {
                for (int i = 0; i < Wedges2.length; i++) {
                    RadialMenuWedge f = Wedges2[i];
                    if (f == selected2) {
                        animateOuterIn = true; // sets Wedge2Shown = false;
                        enabled = null;
                        selected = null;
                        wedge2Data.getChildren().get(i).menuActiviated();
                    }
                }
            } else {
                // This is when something outside the circle or any of the rings
                // is selected
                //dismiss();
                // selected = null;
                // enabled = null;
            }
            // selected = null;
            selected2 = null;
            inCircle = false;
        }
        invalidate();
        return true;
    }

    @Override
    protected void onDraw(Canvas c) {

        Paint paint = new Paint();
        paint.setAntiAlias(true);
        paint.setStrokeWidth(3);

        // draws a dot at the source of the press
        if (showSource == true) {
            paint.setColor(outlineColor);
            paint.setAlpha(outlineAlpha);
            paint.setStyle(Paint.Style.STROKE);
            c.drawCircle(xSource, ySource, cRadius / 10, paint);

            paint.setColor(selectedColor);
            paint.setAlpha(selectedAlpha);
            paint.setStyle(Paint.Style.FILL);
            c.drawCircle(xSource, ySource, cRadius / 10, paint);
        }
        //inner
        for (int i = 0; i < Wedges.length; i++) {
            RadialMenuWedge f = Wedges[i];
            paint.setColor(outlineColor);
            paint.setAlpha(outlineAlpha);
            paint.setStyle(Paint.Style.STROKE);
            c.drawPath(f, paint);
            if (f == enabled && Wedge2Shown == true) {
                paint.setColor(wedge2Color);
                paint.setAlpha(wedge2Alpha);
                paint.setStyle(Paint.Style.FILL);
                c.drawPath(f, paint);
            } else if (f != enabled && Wedge2Shown == true) {
                paint.setColor(disabledColor);
                paint.setAlpha(disabledAlpha);
                paint.setStyle(Paint.Style.FILL);
                c.drawPath(f, paint);
            } else if (f == enabled && Wedge2Shown == false) {
                paint.setColor(wedge2Color);
                paint.setAlpha(wedge2Alpha);
                paint.setStyle(Paint.Style.FILL);
                c.drawPath(f, paint);
            } else if (f == selected) {
                paint.setColor(wedge2Color);
                paint.setAlpha(wedge2Alpha);
                paint.setStyle(Paint.Style.FILL);
                c.drawPath(f, paint);
            } else {
                paint.setColor(defaultColor);
                paint.setAlpha(defaultAlpha);
                paint.setStyle(Paint.Style.FILL);
                c.drawPath(f, paint);
            }
            //button content
            Rect rf = iconRect[i];

            if ((menuEntries.get(i).getIcon() != 0) && (menuEntries.get(i).getLabel() != null)) {

                // This will look for a "new line" and split into multiple lines
                String menuItemName = menuEntries.get(i).getLabel();
                String[] stringArray = menuItemName.split("\n");

                paint.setColor(textColor);
                if (f != enabled && Wedge2Shown == true) {
                    paint.setAlpha(disabledAlpha);
                } else {
                    paint.setAlpha(textAlpha);
                }
                paint.setStyle(Paint.Style.FILL);
                paint.setTextSize(textSize);

                Rect rect = new Rect();
                float textHeight = 0;
                for (int j = 0; j < stringArray.length; j++) {
                    paint.getTextBounds(stringArray[j], 0, stringArray[j].length(), rect);
                    textHeight = textHeight + (rect.height() + 3);
                }

                Rect rf2 = new Rect();
                rf2.set(rf.left, rf.top - ((int) textHeight / 2), rf.right, rf.bottom - ((int) textHeight / 2));

                float textBottom = rf2.bottom;
                for (int j = 0; j < stringArray.length; j++) {
                    paint.getTextBounds(stringArray[j], 0, stringArray[j].length(), rect);
                    float textLeft = rf.centerX() - rect.width() / 2;
                    textBottom = textBottom + (rect.height() + 3);
                    c.drawText(stringArray[j], textLeft - rect.left, textBottom - rect.bottom, paint);
                }

                // Puts in the Icon
                Drawable drawable = getResources().getDrawable(menuEntries.get(i).getIcon());
                drawable.setBounds(rf2);
                if (f != enabled && Wedge2Shown == true) {
                    drawable.setAlpha(disabledAlpha);
                } else {
                    drawable.setAlpha(pictureAlpha);
                }
                drawable.draw(c);

                // Icon Only
            } else if (menuEntries.get(i).getIcon() != 0) {
                // Puts in the Icon
                Drawable drawable = getResources().getDrawable(menuEntries.get(i).getIcon());
                drawable.setBounds(rf);
                if (f != enabled && Wedge2Shown == true) {
                    drawable.setAlpha(disabledAlpha);
                } else {
                    drawable.setAlpha(pictureAlpha);
                }
                drawable.draw(c);

                // Text Only
            } else {
                // Puts in the Text if no Icon
                paint.setColor(textColor);
                if (f != enabled && Wedge2Shown == true) {
                    paint.setAlpha(disabledAlpha);
                } else {
                    paint.setAlpha(textAlpha);
                }
                paint.setStyle(Paint.Style.FILL);
                paint.setTextSize(textSize + 10);

                // This will look for a "new line" and split into multiple lines
                String menuItemName = menuEntries.get(i).getLabel();
                String[] stringArray = menuItemName.split("\n");

                // gets total height
                Rect rect = new Rect();
                float textHeight = 0;
                for (int j = 0; j < stringArray.length; j++) {
                    paint.getTextBounds(stringArray[j], 0, stringArray[j].length(), rect);
                    textHeight = textHeight + (rect.height() + 3);
                }

                float textBottom = rf.centerY() - (textHeight / 2);
                for (int j = 0; j < stringArray.length; j++) {
                    paint.getTextBounds(stringArray[j], 0, stringArray[j].length(), rect);
                    float textLeft = rf.centerX() - rect.width() / 2;
                    textBottom = textBottom + (rect.height() + 3);
                    c.drawText(stringArray[j], textLeft - rect.left, textBottom - rect.bottom, paint);
                }
            }

        }

        // Animate the outer ring in/out
        if (animateOuterIn == true) {
            animateOuterWedges(ANIMATE_IN);
        } else if (animateOuterOut == true) {
            animateOuterWedges(ANIMATE_OUT);
        }
        //outer
        if (Wedge2Shown == true) {

            for (int i = 0; i < Wedges2.length; i++) {
                RadialMenuWedge f = Wedges2[i];
                paint.setColor(outlineColor);
                paint.setAlpha(20);
                paint.setStyle(Paint.Style.STROKE);
                c.drawPath(f, paint);
                if (f == selected2) {
                    paint.setColor(selectedColor);
                    paint.setAlpha(selectedAlpha);
                    paint.setStyle(Paint.Style.FILL);
                    c.drawPath(f, paint);
                } else {
                    paint.setColor(wedge2Color);
                    paint.setAlpha(wedge2Alpha);
                    paint.setStyle(Paint.Style.FILL);
                    c.drawPath(f, paint);
                }

                Rect rf = iconRect2[i];
                if ((wedge2Data.getChildren().get(i).getIcon() != 0)
                        && (wedge2Data.getChildren().get(i).getLabel() != null)) {

                    // This will look for a "new line" and split into multiple
                    // lines
                    String menuItemName = wedge2Data.getChildren().get(i).getLabel();
                    String[] stringArray = menuItemName.split("\n");

                    paint.setColor(textColor);
                    paint.setAlpha(textAlpha);
                    paint.setStyle(Paint.Style.FILL);
                    paint.setTextSize(animateTextSize);

                    Rect rect = new Rect();
                    float textHeight = 0;
                    for (int j = 0; j < stringArray.length; j++) {
                        paint.getTextBounds(stringArray[j], 0, stringArray[j].length(), rect);
                        textHeight = textHeight + (rect.height() + 3);
                    }

                    Rect rf2 = new Rect();
                    rf2.set(rf.left, rf.top - ((int) textHeight / 2), rf.right, rf.bottom - ((int) textHeight / 2));

                    float textBottom = rf2.bottom;
                    for (int j = 0; j < stringArray.length; j++) {
                        paint.getTextBounds(stringArray[j], 0, stringArray[j].length(), rect);
                        float textLeft = rf.centerX() - rect.width() / 2;
                        textBottom = textBottom + (rect.height() + 3);
                        c.drawText(stringArray[j], textLeft - rect.left, textBottom - rect.bottom, paint);
                    }

                    // Puts in the Icon
                    Drawable drawable = getResources().getDrawable(wedge2Data.getChildren().get(i).getIcon());
                    drawable.setBounds(rf2);
                    drawable.setAlpha(pictureAlpha);
                    drawable.draw(c);

                    // Icon Only
                } else if (wedge2Data.getChildren().get(i).getIcon() != 0) {
                    // Puts in the Icon
                    Drawable drawable = getResources().getDrawable(wedge2Data.getChildren().get(i).getIcon());
                    drawable.setBounds(rf);
                    drawable.setAlpha(pictureAlpha);
                    drawable.draw(c);

                    // Text Only
                } else {
                    // Puts in the Text if no Icon
                    paint.setColor(textColor);
                    paint.setAlpha(textAlpha);
                    paint.setStyle(Paint.Style.FILL);
                    paint.setTextSize(animateTextSize);

                    // This will look for a "new line" and split into multiple
                    // lines
                    String menuItemName = wedge2Data.getChildren().get(i).getLabel();
                    String[] stringArray = menuItemName.split("\n");

                    // gets total height
                    Rect rect = new Rect();
                    float textHeight = 0;
                    for (int j = 0; j < stringArray.length; j++) {
                        paint.getTextBounds(stringArray[j], 0, stringArray[j].length(), rect);
                        textHeight = textHeight + (rect.height() + 3);
                    }

                    float textBottom = rf.centerY() - (textHeight / 2);
                    for (int j = 0; j < stringArray.length; j++) {
                        paint.getTextBounds(stringArray[j], 0, stringArray[j].length(), rect);
                        float textLeft = rf.centerX() - rect.width() / 2;
                        textBottom = textBottom + (rect.height() + 3);
                        c.drawText(stringArray[j], textLeft - rect.left, textBottom - rect.bottom, paint);
                    }
                }
            }
        }

        //Check if the user has given input for centre circle
        if (centerCircle != null) {
            // Draws the Middle Circle
            paint.setColor(outlineColor);
            paint.setAlpha(outlineAlpha);
            paint.setStyle(Paint.Style.STROKE);
            c.drawCircle(xPosition, yPosition, cRadius, paint);
            if (inCircle == true) {
                paint.setColor(selectedColor);
                paint.setAlpha(selectedAlpha);
                paint.setStyle(Paint.Style.FILL);
                c.drawCircle(xPosition, yPosition, cRadius, paint);
                helper.onCloseAnimation(this, xPosition, yPosition, xSource, ySource);
            } else {
                paint.setColor(defaultColor);
                paint.setAlpha(defaultAlpha);
                paint.setStyle(Paint.Style.FILL);
                c.drawCircle(xPosition, yPosition, cRadius, paint);
            }

            // Draw the circle picture
            if ((centerCircle.getIcon() != 0) && (centerCircle.getLabel() != null)) {

                // This will look for a "new line" and split into multiple lines
                String menuItemName = centerCircle.getLabel();
                String[] stringArray = menuItemName.split("\n");

                paint.setColor(textColor);
                paint.setAlpha(textAlpha);
                paint.setStyle(Paint.Style.FILL);
                paint.setTextSize(textSize);

                Rect rectText = new Rect();
                Rect rectIcon = new Rect();
                Drawable drawable = getResources().getDrawable(centerCircle.getIcon());

                int h = getIconSize(drawable.getIntrinsicHeight(), MinIconSize, MaxIconSize);
                int w = getIconSize(drawable.getIntrinsicWidth(), MinIconSize, MaxIconSize);
                rectIcon.set(xPosition - w / 2, yPosition - h / 2, xPosition + w / 2, yPosition + h / 2);

                float textHeight = 0;
                for (int j = 0; j < stringArray.length; j++) {
                    paint.getTextBounds(stringArray[j], 0, stringArray[j].length(), rectText);
                    textHeight = textHeight + (rectText.height() + 3);
                }

                rectIcon.set(rectIcon.left, rectIcon.top - ((int) textHeight / 2), rectIcon.right,
                        rectIcon.bottom - ((int) textHeight / 2));

                float textBottom = rectIcon.bottom;
                for (int j = 0; j < stringArray.length; j++) {
                    paint.getTextBounds(stringArray[j], 0, stringArray[j].length(), rectText);
                    float textLeft = xPosition - rectText.width() / 2;
                    textBottom = textBottom + (rectText.height() + 3);
                    c.drawText(stringArray[j], textLeft - rectText.left, textBottom - rectText.bottom, paint);
                }

                // Puts in the Icon
                drawable.setBounds(rectIcon);
                drawable.setAlpha(pictureAlpha);
                drawable.draw(c);

                // Icon Only
            } else if (centerCircle.getIcon() != 0) {

                Rect rect = new Rect();

                Drawable drawable = getResources().getDrawable(centerCircle.getIcon());

                int h = getIconSize(drawable.getIntrinsicHeight(), MinIconSize, MaxIconSize);
                int w = getIconSize(drawable.getIntrinsicWidth(), MinIconSize, MaxIconSize);
                rect.set(xPosition - w / 2, yPosition - h / 2, xPosition + w / 2, yPosition + h / 2);

                drawable.setBounds(rect);
                drawable.setAlpha(pictureAlpha);
                drawable.draw(c);

                // Text Only
            } else {
                // Puts in the Text if no Icon
                paint.setColor(textColor);
                paint.setAlpha(textAlpha);
                paint.setStyle(Paint.Style.FILL);
                paint.setTextSize(textSize);

                // This will look for a "new line" and split into multiple lines
                String menuItemName = centerCircle.getLabel();
                String[] stringArray = menuItemName.split("\n");

                // gets total height
                Rect rect = new Rect();
                float textHeight = 0;
                for (int j = 0; j < stringArray.length; j++) {
                    paint.getTextBounds(stringArray[j], 0, stringArray[j].length(), rect);
                    textHeight = textHeight + (rect.height() + 3);
                }

                float textBottom = yPosition - (textHeight / 2);
                for (int j = 0; j < stringArray.length; j++) {
                    paint.getTextBounds(stringArray[j], 0, stringArray[j].length(), rect);
                    float textLeft = xPosition - rect.width() / 2;
                    textBottom = textBottom + (rect.height() + 3);
                    c.drawText(stringArray[j], textLeft - rect.left, textBottom - rect.bottom, paint);
                }

            }
        }

        // Draws Text in TextBox
        if (headerString != null) {

            paint.setTextSize(headerTextSize);
            paint.getTextBounds(headerString, 0, headerString.length(), this.textRect);
            if (HeaderBoxBounded == false) {
                determineHeaderBox();
                HeaderBoxBounded = true;
            }

            paint.setColor(outlineColor);
            paint.setAlpha(outlineAlpha);
            paint.setStyle(Paint.Style.STROKE);
            c.drawRoundRect(this.textBoxRect, scalePX(5), scalePX(5), paint);
            paint.setColor(headerBackgroundColor);
            paint.setAlpha(headerBackgroundAlpha);
            paint.setStyle(Paint.Style.FILL);
            c.drawRoundRect(this.textBoxRect, scalePX(5), scalePX(5), paint);

            paint.setColor(headerTextColor);
            paint.setAlpha(headerTextAlpha);
            paint.setStyle(Paint.Style.FILL);
            paint.setTextSize(headerTextSize);
            c.drawText(headerString, headerTextLeft, headerTextBottom, paint);
        }

    }

    private int scalePX(int dp_size) {
        int px_size = (int) (dp_size * screen_density + 0.5f);
        return px_size;
    }

    private int getIconSize(int iconSize, int minSize, int maxSize) {

        if (iconSize > minSize) {
            if (iconSize > maxSize) {
                return maxSize;
            } else { // iconSize < maxSize
                return iconSize;
            }
        } else { // iconSize < minSize
            return minSize;
        }

    }

    private void animateOuterWedges(int animation_direction) {
        boolean animationComplete = false;
        // Wedge 2
        float slice2 = 360 / wedgeQty2;
        float start_slice2 = 270 - (slice2 / 2);
        // calculates where to put the images
        double rSlice2 = (2 * Math.PI) / wedgeQty2;
        double rStart2 = (2 * Math.PI) * (0.75) - (rSlice2 / 2);

        this.Wedges2 = new RadialMenuWedge[wedgeQty2];
        this.iconRect2 = new Rect[wedgeQty2];

        Wedge2Shown = true;

        int wedgeSizeChange = (r2MaxSize - r2MinSize) / animateSections;

        if (animation_direction == ANIMATE_OUT) {
            if (r2MinSize + r2VariableSize + wedgeSizeChange < r2MaxSize) {
                r2VariableSize += wedgeSizeChange;
            } else {
                animateOuterOut = false;
                r2VariableSize = r2MaxSize - r2MinSize;
                animationComplete = true;
            }

            // animates text size change
            this.animateTextSize = (textSize / animateSections) * (r2VariableSize / wedgeSizeChange);

            // calculates new wedge sizes
            for (int i = 0; i < Wedges2.length; i++) {
                this.Wedges2[i] = new RadialMenuWedge(xPosition, yPosition, r2MinSize, r2MinSize + r2VariableSize,
                        (i * slice2) + start_slice2, slice2);
                float xCenter = (float) (Math.cos(((rSlice2 * i) + (rSlice2 * 0.5)) + rStart2)
                        * (r2MinSize + r2VariableSize + r2MinSize) / 2) + xPosition;
                float yCenter = (float) (Math.sin(((rSlice2 * i) + (rSlice2 * 0.5)) + rStart2)
                        * (r2MinSize + r2VariableSize + r2MinSize) / 2) + yPosition;

                int h = MaxIconSize;
                int w = MaxIconSize;
                if (wedge2Data.getChildren().get(i).getIcon() != 0) {
                    Drawable drawable = getResources().getDrawable(wedge2Data.getChildren().get(i).getIcon());
                    h = getIconSize(drawable.getIntrinsicHeight(), MinIconSize, MaxIconSize);
                    w = getIconSize(drawable.getIntrinsicWidth(), MinIconSize, MaxIconSize);
                }

                if (r2VariableSize < h) {
                    h = r2VariableSize;
                }
                if (r2VariableSize < w) {
                    w = r2VariableSize;
                }

                this.iconRect2[i] = new Rect((int) xCenter - w / 2, (int) yCenter - h / 2, (int) xCenter + w / 2,
                        (int) yCenter + h / 2);

                int widthOffset = MaxSize;
                if (widthOffset < this.textRect.width() / 2) {
                    widthOffset = this.textRect.width() / 2 + scalePX(3);
                }
                this.textBoxRect.set((xPosition - (widthOffset)),
                        (int) (yPosition - (r2MinSize + r2VariableSize) - headerBuffer - this.textRect.height()
                                - scalePX(3)),
                        (xPosition + (widthOffset)),
                        (yPosition - (r2MinSize + r2VariableSize) - headerBuffer + scalePX(3)));
                this.headerTextBottom = yPosition - (r2MinSize + r2VariableSize) - headerBuffer
                        - this.textRect.bottom;

            }

        } else if (animation_direction == ANIMATE_IN) {
            if (r2MinSize < r2MaxSize - r2VariableSize - wedgeSizeChange) {
                r2VariableSize += wedgeSizeChange;
            } else {
                animateOuterIn = false;
                r2VariableSize = r2MaxSize;
                animationComplete = true;
            }

            // animates text size change
            this.animateTextSize = textSize - ((textSize / animateSections) * (r2VariableSize / wedgeSizeChange));

            for (int i = 0; i < Wedges2.length; i++) {
                this.Wedges2[i] = new RadialMenuWedge(xPosition, yPosition, r2MinSize, r2MaxSize - r2VariableSize,
                        (i * slice2) + start_slice2, slice2);

                float xCenter = (float) (Math.cos(((rSlice2 * i) + (rSlice2 * 0.5)) + rStart2)
                        * (r2MaxSize - r2VariableSize + r2MinSize) / 2) + xPosition;
                float yCenter = (float) (Math.sin(((rSlice2 * i) + (rSlice2 * 0.5)) + rStart2)
                        * (r2MaxSize - r2VariableSize + r2MinSize) / 2) + yPosition;

                int h = MaxIconSize;
                int w = MaxIconSize;
                if (wedge2Data.getChildren().get(i).getIcon() != 0) {
                    Drawable drawable = getResources().getDrawable(wedge2Data.getChildren().get(i).getIcon());
                    h = getIconSize(drawable.getIntrinsicHeight(), MinIconSize, MaxIconSize);
                    w = getIconSize(drawable.getIntrinsicWidth(), MinIconSize, MaxIconSize);
                }

                if (r2MaxSize - r2MinSize - r2VariableSize < h) {
                    h = r2MaxSize - r2MinSize - r2VariableSize;
                }
                if (r2MaxSize - r2MinSize - r2VariableSize < w) {
                    w = r2MaxSize - r2MinSize - r2VariableSize;
                }

                this.iconRect2[i] = new Rect((int) xCenter - w / 2, (int) yCenter - h / 2, (int) xCenter + w / 2,
                        (int) yCenter + h / 2);

                // computes header text box
                int heightOffset = r2MaxSize - r2VariableSize;
                int widthOffset = MaxSize;
                if (MaxSize > r2MaxSize - r2VariableSize) {
                    heightOffset = MaxSize;
                }
                if (widthOffset < this.textRect.width() / 2) {
                    widthOffset = this.textRect.width() / 2 + scalePX(3);
                }
                this.textBoxRect.set((xPosition - (widthOffset)),
                        (int) (yPosition - (heightOffset) - headerBuffer - this.textRect.height() - scalePX(3)),
                        (xPosition + (widthOffset)), (yPosition - (heightOffset) - headerBuffer + scalePX(3)));
                this.headerTextBottom = yPosition - (heightOffset) - headerBuffer - this.textRect.bottom;

            }
        }

        if (animationComplete == true) {
            r2VariableSize = 0;
            this.animateTextSize = textSize;
            if (animation_direction == ANIMATE_IN) {
                Wedge2Shown = false;
            }
        }

        invalidate(); // re-draws the picture
    }

    private void determineWedges() {

        int entriesQty = menuEntries.size();
        if (entriesQty > 0) {
            wedgeQty = entriesQty;

            float degSlice = 360 / wedgeQty;
            float start_degSlice = 270 - (degSlice / 2);
            // calculates where to put the images
            double rSlice = (2 * Math.PI) / wedgeQty;
            double rStart = (2 * Math.PI) * (0.75) - (rSlice / 2);

            this.Wedges = new RadialMenuWedge[wedgeQty];
            this.iconRect = new Rect[wedgeQty];

            for (int i = 0; i < Wedges.length; i++) {
                this.Wedges[i] = new RadialMenuWedge(xPosition, yPosition, MinSize, MaxSize,
                        (i * degSlice) + start_degSlice, degSlice);
                float xCenter = (float) (Math.cos(((rSlice * i) + (rSlice * 0.5)) + rStart) * (MaxSize + MinSize)
                        / 2) + xPosition;
                float yCenter = (float) (Math.sin(((rSlice * i) + (rSlice * 0.5)) + rStart) * (MaxSize + MinSize)
                        / 2) + yPosition;

                int h = MaxIconSize;
                int w = MaxIconSize;
                if (menuEntries.get(i).getIcon() != 0) {
                    Drawable drawable = getResources().getDrawable(menuEntries.get(i).getIcon());
                    h = getIconSize(drawable.getIntrinsicHeight(), MinIconSize, MaxIconSize);
                    w = getIconSize(drawable.getIntrinsicWidth(), MinIconSize, MaxIconSize);
                }

                this.iconRect[i] = new Rect((int) xCenter - w / 2, (int) yCenter - h / 2, (int) xCenter + w / 2,
                        (int) yCenter + h / 2);
            }

            invalidate(); // re-draws the picture
        }
    }

    private void determineOuterWedges(RadialMenuItem entry) {

        int entriesQty = entry.getChildren().size();
        wedgeQty2 = entriesQty;

        // Wedge 2
        float degSlice2 = 360 / wedgeQty2;
        float start_degSlice2 = 270 - (degSlice2 / 2);
        // calculates where to put the images
        double rSlice2 = (2 * Math.PI) / wedgeQty2;
        double rStart2 = (2 * Math.PI) * (0.75) - (rSlice2 / 2);

        this.Wedges2 = new RadialMenuWedge[wedgeQty2];
        this.iconRect2 = new Rect[wedgeQty2];

        for (int i = 0; i < Wedges2.length; i++) {
            this.Wedges2[i] = new RadialMenuWedge(xPosition, yPosition, r2MinSize, r2MaxSize,
                    (i * degSlice2) + start_degSlice2, degSlice2);
            float xCenter = (float) (Math.cos(((rSlice2 * i) + (rSlice2 * 0.5)) + rStart2) * (r2MaxSize + r2MinSize)
                    / 2) + xPosition;
            float yCenter = (float) (Math.sin(((rSlice2 * i) + (rSlice2 * 0.5)) + rStart2) * (r2MaxSize + r2MinSize)
                    / 2) + yPosition;

            int h = MaxIconSize;
            int w = MaxIconSize;
            if (entry.getChildren().get(i).getIcon() != 0) {
                Drawable drawable = getResources().getDrawable(entry.getChildren().get(i).getIcon());
                h = getIconSize(drawable.getIntrinsicHeight(), MinIconSize, MaxIconSize);
                w = getIconSize(drawable.getIntrinsicWidth(), MinIconSize, MaxIconSize);
            }
            this.iconRect2[i] = new Rect((int) xCenter - w / 2, (int) yCenter - h / 2, (int) xCenter + w / 2,
                    (int) yCenter + h / 2);
        }
        this.wedge2Data = entry;
        invalidate(); // re-draws the picture
    }

    private void determineHeaderBox() {
        this.headerTextLeft = xPosition - this.textRect.width() / 2;
        this.headerTextBottom = yPosition - (MaxSize) - headerBuffer - this.textRect.bottom;
        int offset = MaxSize;
        if (offset < this.textRect.width() / 2) {
            offset = this.textRect.width() / 2 + scalePX(3);
        }
        this.textBoxRect.set((xPosition - (offset)),
                (int) (yPosition - (MaxSize) - headerBuffer - this.textRect.height() - scalePX(3)),
                (xPosition + (offset)), (yPosition - (MaxSize) - headerBuffer + scalePX(3)));

    }

    /******************************************************************************************************************************
     * ADD ITEM METHODS
     ******************************************************************************************************************************/

    /**
     * This method allows the user to add an array of menu items.
     * @param menuItems - List object of RadialMenuItem.
     * @return
     */
    public void addMenuEntry(List<RadialMenuItem> menuItems) {
        menuEntries.addAll(menuItems);
        determineWedges();
    }

    /**
     *  This method allows the user to add a menu item.
     * @param menuItem - Object of RadialMenuItem.
     * @return
     */
    public void addMenuEntry(RadialMenuItem menuItem) {
        menuEntries.add(menuItem);
        determineWedges();
    }

    /******************************************************************************************************************************
     * SET METHODS
     ******************************************************************************************************************************/

    /**
     * <strong> Optional </strong>
     * This method allows the user to add the central menu item.
     * @param menuItem - Object of RadialMenuItem.
     * @return
     */
    public void setCenterCircle(RadialMenuItem menuItem) {
        centerCircle = menuItem;
    }

    /**
     * <strong> Optional </strong>
     * Set the middle ring radius of the radial menu widget.
     * @param InnerRadius - Inner border radius.
     * @param OuterRadius - Outer border radius.
     */
    public void setInnerRingRadius(int InnerRadius, int OuterRadius) {
        this.MinSize = scalePX(InnerRadius);
        this.MaxSize = scalePX(OuterRadius);
        determineWedges();
    }

    /**
     * <strong> Optional </strong>
     * Set the outer ring radius of the radial menu widget.
     * @param InnerRadius - Inner border radius.
     * @param OuterRadius - Outer border radius.
     */
    public void setOuterRingRadius(int InnerRadius, int OuterRadius) {
        this.r2MinSize = scalePX(InnerRadius);
        this.r2MaxSize = scalePX(OuterRadius);
        determineWedges();
    }

    /**
     * <strong> Optional </strong>
     * This method set the radius of the centre circle.
     * @param centerRadius - Radius of the circle.
     */
    public void setCenterCircleRadius(int centerRadius) {
        this.cRadius = scalePX(centerRadius);
        determineWedges();
    }

    /**
     * Set the menu items text size.
     * @param TextSize - Text size of the menu items.
     */
    public void setTextSize(int TextSize) {
        this.textSize = scalePX(TextSize);
        this.animateTextSize = this.textSize;
    }

    /**
     * Set the menu item icon size.
     * @param minIconSize - Minimum scaled size.
     * @param maxIconSize - Maximum scaled size.
     */
    public void setIconSize(int minIconSize, int maxIconSize) {
        this.MinIconSize = scalePX(minIconSize);
        this.MaxIconSize = scalePX(maxIconSize);
        determineWedges();
    }

    /**
     * 
     * @param x
     * @param y
     */
    public void setCenterLocation(int x, int y) {
        this.xPosition = x;
        this.yPosition = y;
        determineWedges();
        helper.onOpenAnimation(this, xPosition, yPosition, xSource, ySource);
    }

    /**
     * 
     * @param x
     * @param y
     */
    public void setSourceLocation(int x, int y) {
        this.xSource = x;
        this.ySource = y;
        helper.onOpenAnimation(this, xPosition, yPosition, xSource, ySource);
    }

    /**
     * @deprecated
     * @param showSourceLocation
     */
    public void setShowSourceLocation(boolean showSourceLocation) {
        this.showSource = showSourceLocation;
        helper.onOpenAnimation(this, xPosition, yPosition, xSource, ySource);
    }

    /**
     * Set the widget animation speed.
     * @param millis - Time in milliseconds.
     */
    public void setAnimationSpeed(long millis) {
        helper.onOpenAnimation(this, xPosition, yPosition, xSource, ySource, millis);
    }

    /**
     * Set the radial menu inner ring color.
     * @param color - Color value .
     * @param alpha - Alpha blend value.
     */
    public void setInnerRingColor(int color, int alpha) {
        this.defaultColor = color;
        this.defaultAlpha = alpha;
    }

    /**
     * Set the radial menu outer ring color.
     * @param color - Color value .
     * @param alpha - Alpha blend value.
     */
    public void setOuterRingColor(int color, int alpha) {
        this.wedge2Color = color;
        this.wedge2Alpha = alpha;
    }

    /**
     * Set the radial widget outline color.
     * @param color - Color value .
     * @param alpha - Alpha blend value.
     */
    public void setOutlineColor(int color, int alpha) {
        this.outlineColor = color;
        this.outlineAlpha = alpha;
    }

    /**
     * Set the widget on select color.
     * @param color - Color value .
     * @param alpha - Alpha blend value.
     */
    public void setSelectedColor(int color, int alpha) {
        this.selectedColor = color;
        this.selectedAlpha = alpha;
    }

    /**
     * Set the widget on disabled color.
     * @param color - Color value .
     * @param alpha - Alpha blend value.
     */
    public void setDisabledColor(int color, int alpha) {
        this.disabledColor = color;
        this.disabledAlpha = alpha;
    }

    /**
     * Set the widget text color.
     * @param color - Text color
     * @param alpha - Text alpha belnd value
     */
    public void setTextColor(int color, int alpha) {
        this.textColor = color;
        this.textAlpha = alpha;
    }

    /**
     * <strong> Optional </strong>
     * Display a header with text along with the displayed radial menu.
     * @param header - Header text to be displayed.
     * @param TextSize -  Text size.
     */
    public void setHeader(String header, int TextSize) {
        this.headerString = header;
        this.headerTextSize = scalePX(TextSize);
        HeaderBoxBounded = false;
    }

    /**
     * <strong> Optional </strong>
     * Display a header with text along with the displayed radial menu. This method helps in configuring the display background.
     * @param TextColor
     * @param TextAlpha
     * @param BgColor
     * @param BgAlpha
     */
    public void setHeaderColors(int TextColor, int TextAlpha, int BgColor, int BgAlpha) {
        this.headerTextColor = TextColor;
        this.headerTextAlpha = TextAlpha;
        this.headerBackgroundColor = BgColor;
        this.headerBackgroundAlpha = BgAlpha;
    }

    /**
     * Shows the radial menu widget.
     * @param anchor - View to be anchored to.
     * @param posX - Position X. Pass 0 if not needed.
     * @param posY - Position Y. Pass 0 if not needed.
     */
    public void show(View anchor, int posX, int posY) {
        mWindow.setContentView(this);
        mWindow.showAtLocation(anchor, Gravity.NO_GRAVITY, posX, posY);
    }

    /**
     * Shows the radial menu widget.
     * @param anchor - View to be anchored to.
     */
    public void show(View anchor) {
        mWindow.setContentView(this);
        mWindow.showAtLocation(anchor, Gravity.NO_GRAVITY, this.xSource, this.ySource);
    }

    /**
     * Shows the radial menu widget.
     */
    public void show() {
        mWindow.showAtLocation(getRootView(), 0, 200, 200);
        ;
    }

    /**
     * Dismisses the radial menu widget.
     */
    public void dismiss() {
        if (mWindow != null)
            mWindow.dismiss();
    }
}