blob: 98c3a0c2ac91b01c09486ea6ca0de4df68ed0827 [file] [log] [blame]
package com.android.deskclock;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.FrameLayout;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.TextView;
/**
* TODO: Insert description here. (generated by sblitz)
*/
public class CircleButtonsLinearLayout extends LinearLayout {
private Context mContext;
private int mCircleTimerViewId;
private int mLeftButtonId;
private int mRightButtonId;
private int mStopButtonId;
private int mLabelId;
private int mLabelTextId;
private float mLeftButtonPadding;
private float mRightButtonPadding;
private float mStrokeSize;
private float mDiamOffset;
private CircleTimerView mCtv;
private ImageButton mLeft, mRight;
private TextView mStop;
private FrameLayout mLabel;
private TextView mLabelText;
public CircleButtonsLinearLayout(Context context) {
this(context, null);
mContext = context;
}
public CircleButtonsLinearLayout(Context context, AttributeSet attrs) {
super(context, attrs);
mContext = context;
}
public void setCircleTimerViewIds(int circleTimerViewId, int leftButtonId, int rightButtonId,
int stopButtonId, int leftButtonPaddingDimenId, int rightButtonPaddingDimenId,
int labelId, int labelTextId) {
mCircleTimerViewId = circleTimerViewId;
mLeftButtonId = leftButtonId;
mRightButtonId = rightButtonId;
mStopButtonId = stopButtonId;
mLabelId = labelId;
mLabelTextId = labelTextId;
mLeftButtonPadding = mContext.getResources().getDimension(leftButtonPaddingDimenId);
mRightButtonPadding = mContext.getResources().getDimension(rightButtonPaddingDimenId);
float diamondStrokeSize =
mContext.getResources().getDimension(R.dimen.circletimer_diamond_size);
float markerStrokeSize =
mContext.getResources().getDimension(R.dimen.circletimer_marker_size);
mStrokeSize = mContext.getResources().getDimension(R.dimen.circletimer_circle_size);
mDiamOffset =
Utils.calculateRadiusOffset(mStrokeSize, diamondStrokeSize, markerStrokeSize) * 2;
}
@Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// We must call onMeasure both before and after re-measuring our views because the circle
// may not always be drawn here yet. The first onMeasure will force the circle to be drawn,
// and the second will force our re-measurements to take effect.
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
remeasureViews();
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
protected void remeasureViews() {
if (mCtv == null) {
mCtv = (CircleTimerView) findViewById(mCircleTimerViewId);
if (mCtv == null) {
return;
}
mLeft = (ImageButton) findViewById(mLeftButtonId);
mRight = (ImageButton) findViewById(mRightButtonId);
mStop = (TextView) findViewById(mStopButtonId);
mLabel = (FrameLayout) findViewById(mLabelId);
mLabelText = (TextView) findViewById(mLabelTextId);
}
int frameWidth = mCtv.getMeasuredWidth();
int frameHeight = mCtv.getMeasuredHeight();
int minBound = Math.min(frameWidth, frameHeight);
int circleDiam = (int) (minBound - mDiamOffset);
MarginLayoutParams stopParams = (MarginLayoutParams) mStop.getLayoutParams();
stopParams.bottomMargin = circleDiam/6;
if (minBound == frameWidth) {
stopParams.bottomMargin += (frameHeight-frameWidth)/2;
}
if (mLabel != null) {
// label will be null if this is a stopwatch, which does not have a label.
MarginLayoutParams labelParams = (MarginLayoutParams) mLabel.getLayoutParams();
labelParams.topMargin = circleDiam/6;
if (minBound == frameWidth) {
labelParams.topMargin += (frameHeight-frameWidth)/2;
}
/* The following formula has been simplified based on the following:
* Our goal is to calculate the maximum width for the label frame.
* We may do this with the following diagram to represent the top half of the circle:
* ___
* . | .
* ._________| .
* . ^ | .
* / x | \
* |_______________|_______________|
*
* where x represents the value we would like to calculate, and the final width of the
* label will be w = 2 * x.
*
* We may find x by drawing a right triangle from the center of the circle:
* ___
* . | .
* ._________| .
* . . | .
* / . | }y \
* |_____________.t|_______________|
*
* where t represents the angle of that triangle, and y is the height of that triangle.
*
* If r = radius of the circle, we know the following trigonometric identities:
* cos(t) = y / r
* and sin(t) = x / r
* => r * sin(t) = x
* and sin^2(t) = 1 - cos^2(t)
* => sin(t) = +/- sqrt(1 - cos^2(t))
* (note: because we need the positive value, we may drop the +/-).
*
* To calculate the final width, we may combine our formulas:
* w = 2 * x
* => w = 2 * r * sin(t)
* => w = 2 * r * sqrt(1 - cos^2(t))
* => w = 2 * r * sqrt(1 - (y / r)^2)
*
* Simplifying even further, to mitigate the complexity of the final formula:
* sqrt(1 - (y / r)^2)
* => sqrt(1 - (y^2 / r^2))
* => sqrt((r^2 / r^2) - (y^2 / r^2))
* => sqrt((r^2 - y^2) / (r^2))
* => sqrt(r^2 - y^2) / sqrt(r^2)
* => sqrt(r^2 - y^2) / r
* => sqrt((r + y)*(r - y)) / r
*
* Placing this back in our formula, we end up with, as our final, reduced equation:
* w = 2 * r * sqrt(1 - (y / r)^2)
* => w = 2 * r * sqrt((r + y)*(r - y)) / r
* => w = 2 * sqrt((r + y)*(r - y))
*/
// Radius of the circle.
int r = circleDiam / 2;
// Y value of the top of the label, calculated from the center of the circle.
int y = frameHeight / 2 - labelParams.topMargin;
// New maximum width of the label.
double w = 2 * Math.sqrt((r + y) * (r - y));
mLabelText.setMaxWidth((int) w);
}
int sideMarginOffset = (int) ((frameWidth - circleDiam - mStrokeSize) / 2)
- (int) mContext.getResources().getDimension(R.dimen.timer_button_extra_offset);
int leftMarginOffset = Math.max(0, sideMarginOffset - (int) mLeftButtonPadding);
int rightMarginOffset = Math.max(0, sideMarginOffset - (int) mRightButtonPadding);
int bottomMarginOffset = (frameHeight - minBound) / 2;
MarginLayoutParams leftParams = (MarginLayoutParams) mLeft.getLayoutParams();
leftParams.leftMargin = leftMarginOffset;
leftParams.bottomMargin = bottomMarginOffset;
MarginLayoutParams rightParams = (MarginLayoutParams) mRight.getLayoutParams();
rightParams.rightMargin = rightMarginOffset;
rightParams.bottomMargin = bottomMarginOffset;
}
}