private Item createItem(String label, float percent, int sliceColor, int itemColor) { Item it = new Item(); it.mLabel = label; it.mItemColor = itemColor; it.cSliceColor = sliceColor; it.cPercent = percent; // Log.d(TAG, "Percent for "+it.mLabel+": "+it.cPercent); // Calculate the highlight color. Saturate at 0xff to make sure that high values // don't result in aliasing. it.mItemHighlight = Color.argb( 0xff, Math.min((int) (mHighlightStrength * (float) Color.red(itemColor)), 0xff), Math.min((int) (mHighlightStrength * (float) Color.green(itemColor)), 0xff), Math.min((int) (mHighlightStrength * (float) Color.blue(itemColor)), 0xff)); it.cSliceHighlight = Color.argb( 0xff, Math.min((int) (mHighlightStrength * (float) Color.red(sliceColor)), 0xff), Math.min((int) (mHighlightStrength * (float) Color.green(sliceColor)), 0xff), Math.min((int) (mHighlightStrength * (float) Color.blue(sliceColor)), 0xff)); float centerX = mPieBounds.width() / 2; float centerY = mPieBounds.height() / 2; float itemW = (mPieBounds.width() / 2) * it.cPercent; float itemH = (mPieBounds.height() / 2) * it.cPercent; it.cSliceBounds = new RectF(centerX - itemW, centerY - itemH, centerX + itemW, centerY + itemH); return it; }
public PointF getElementCoordinates( float height, float width, RectF viewRect, PositionMetrics metrics) { float x = metrics.getXPositionMetric().getPixelValue(viewRect.width()) + viewRect.left; float y = metrics.getYPositionMetric().getPixelValue(viewRect.height()) + viewRect.top; PointF point = new PointF(x, y); return PixelUtils.sub(point, getAnchorOffset(width, height, metrics.getAnchor())); }
public SVGTileProvider(File file, float dpi) throws IOException { mScale = Math.round(dpi + .3f); // Make it look nice on N7 (1.3 dpi) mDimension = BASE_TILE_SIZE * mScale; mPool = new TileGeneratorPool(POOL_MAX_SIZE); SVG svg = new SVGBuilder().readFromInputStream(new FileInputStream(file)).build(); mSvgPicture = svg.getPicture(); RectF limits = svg.getLimits(); // These values map the SVG file to world coordinates. // See: http://stackoverflow.com/questions/21167584/google-io-2013-app-mystery-values mBaseMatrix = new Matrix(); mBaseMatrix.setPolyToPoly( new float[] { 0, 0, // North-West limits.width(), 0, // North-East limits.width(), limits.height() // South-East }, 0, BuildConfig.MAP_FLOORPLAN_MAPPING, 0, 3); }
public boolean onTouch(View view, MotionEvent event) { float x = event.getX(); float y = event.getY(); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: path.moveTo(x, y); return true; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_MOVE: l = x; r = x; t = y; b = y; for (int i = 0; i < event.getHistorySize(); i++) { float newX = event.getHistoricalX(i); float newY = event.getHistoricalY(i); path.lineTo(newX, newY); l = newX < l ? newX : l; t = newY < t ? newY : t; r = newX > r ? newX : r; b = newY > b ? newY : b; } rect.set(l, t, r, b); Log.d("TAG", rect.toShortString()); invalidate( (int) rect.left - 5, (int) rect.top - 5, (int) rect.right + 5, (int) rect.bottom + 5); break; default: } return super.onTouchEvent(event); }
// ============================================================================== public final int[] renderGlyph( char glyph, Paint paint, android.graphics.Matrix matrix, Rect bounds) { Path p = new Path(); paint.getTextPath(String.valueOf(glyph), 0, 1, 0.0f, 0.0f, p); RectF boundsF = new RectF(); p.computeBounds(boundsF, true); matrix.mapRect(boundsF); boundsF.roundOut(bounds); bounds.left--; bounds.right++; final int w = bounds.width(); final int h = bounds.height(); Bitmap bm = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); Canvas c = new Canvas(bm); matrix.postTranslate(-bounds.left, -bounds.top); c.setMatrix(matrix); c.drawPath(p, paint); final int sizeNeeded = w * h; if (cachedRenderArray.length < sizeNeeded) cachedRenderArray = new int[sizeNeeded]; bm.getPixels(cachedRenderArray, 0, w, 0, 0, w, h); bm.recycle(); return cachedRenderArray; }
/** * Drawing src bitmap to dest bitmap with rounded corners * * @param src source bitmap * @param dest destination bitmap * @param radius radius in destination bitmap scale * @param clearColor clear color */ public static void drawRoundedCorners(Bitmap src, Bitmap dest, int radius, int clearColor) { clearBitmap(dest, clearColor); Canvas canvas = new Canvas(dest); Rect sourceRect = WorkCache.RECT1.get(); Rect destRect = WorkCache.RECT2.get(); sourceRect.set(0, 0, src.getWidth(), src.getHeight()); destRect.set(0, 0, dest.getWidth(), dest.getHeight()); RectF roundRect = WorkCache.RECTF1.get(); roundRect.set(0, 0, dest.getWidth(), dest.getHeight()); Paint paint = WorkCache.PAINT.get(); paint.reset(); paint.setStyle(Paint.Style.FILL); paint.setColor(Color.RED); paint.setAntiAlias(true); canvas.drawRoundRect(roundRect, radius, radius, paint); paint.reset(); paint.setFilterBitmap(true); paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN)); canvas.drawBitmap(src, sourceRect, destRect, paint); canvas.setBitmap(null); }
private void computePath(Rect bounds) { final float currentScale = mCurrentScale; final Path path = mPath; final RectF rect = mRect; final Matrix matrix = mMatrix; path.reset(); int totalSize = Math.min(bounds.width(), bounds.height()); float initial = mClosedStateSize; float destination = totalSize; float currentSize = initial + (destination - initial) * currentScale; float halfSize = currentSize / 2f; float inverseScale = 1f - currentScale; float cornerSize = halfSize * inverseScale; float[] corners = new float[] { halfSize, halfSize, halfSize, halfSize, halfSize, halfSize, cornerSize, cornerSize }; rect.set(bounds.left, bounds.top, bounds.left + currentSize, bounds.top + currentSize); path.addRoundRect(rect, corners, Path.Direction.CCW); matrix.reset(); matrix.postRotate(-45, bounds.left + halfSize, bounds.top + halfSize); matrix.postTranslate((bounds.width() - currentSize) / 2, 0); float hDiff = (bounds.bottom - currentSize - mExternalOffset) * inverseScale; matrix.postTranslate(0, hDiff); path.transform(matrix); }
@Override protected void onBoundsChange(Rect bounds) { super.onBoundsChange(bounds); fBounds.left = bounds.left + mBorderWidth / 2f + .5f; fBounds.right = bounds.right - mBorderWidth / 2f - .5f; fBounds.top = bounds.top + mBorderWidth / 2f + .5f; fBounds.bottom = bounds.bottom - mBorderWidth / 2f - .5f; }
/** Do all of the recalculations needed when the data array changes. */ private void onDataChanged() { int angle = 360 / mData.size(); // This is the extra degrees that cannot be equally divided by the number of sides int extra = 360 % mData.size(); // When the data changes, we have to recalculate // all of the angles. int currentAngle = 0; for (Item it : mData) { // Adds the extra degrees to the last slice to ensue no gaps if (mData.get(mData.size() - 1).mLabel.equals(it.mLabel)) { it.mEndAngle = currentAngle + angle + extra; } else { it.mEndAngle = currentAngle + angle; } it.mStartAngle = currentAngle; currentAngle = it.mEndAngle; // Recalculate the gradient shaders. There are // three values in this gradient, even though only // two are necessary, in order to work around // a bug in certain versions of the graphics engine // that expects at least three values if the // positions array is non-null. // it.mItemShader = new SweepGradient( mPieBounds.width() / 2.0f, mPieBounds.height() / 2.0f, new int[] { it.mItemHighlight, it.mItemHighlight, it.mItemColor, it.mItemColor, }, new float[] { 0, (float) (360 - it.mEndAngle) / 360.0f, (float) (360 - it.mStartAngle) / 360.0f, 1.0f }); it.cSliceShader = new SweepGradient( mPieBounds.width() / 2.0f, mPieBounds.height() / 2.0f, new int[] { it.cSliceHighlight, it.cSliceHighlight, it.cSliceColor, it.cSliceColor, }, new float[] { 0, (float) (360 - it.mEndAngle) / 360.0f, (float) (360 - it.mStartAngle) / 360.0f, 1.0f }); } calcCurrentItem(); onScrollFinished(); }
/** Resets the dirty region when the motion event occurs. */ private void resetDirtyRect(float eventX, float eventY) { // The lastTouchX and lastTouchY were set when the ACTION_DOWN // motion event occurred. dirtyRect.left = Math.min(lastTouchX, eventX); dirtyRect.right = Math.max(lastTouchX, eventX); dirtyRect.top = Math.min(lastTouchY, eventY); dirtyRect.bottom = Math.max(lastTouchY, eventY); }
private RectF getRectF() { if (backgroundRectF == null) { backgroundRectF = new RectF(); backgroundRectF.left = mPadding; backgroundRectF.top = mPadding; backgroundRectF.right = getWidth() - mPadding; backgroundRectF.bottom = getHeight() - mPadding; } return backgroundRectF; }
/** Called when replaying history to ensure the dirty region includes all points. */ private void expandDirtyRect(float historicalX, float historicalY) { if (historicalX < dirtyRect.left) { dirtyRect.left = historicalX; } else if (historicalX > dirtyRect.right) { dirtyRect.right = historicalX; } if (historicalY < dirtyRect.top) { dirtyRect.top = historicalY; } else if (historicalY > dirtyRect.bottom) { dirtyRect.bottom = historicalY; } }
private void drawBorder(Canvas canvas) { RectF rect = new RectF(getBounds()); rect.inset(borderThickness / 2, borderThickness / 2); if (shape instanceof OvalShape) { canvas.drawOval(rect, borderPaint); } else if (shape instanceof RoundRectShape) { canvas.drawRoundRect(rect, radius, radius, borderPaint); } else { canvas.drawRect(rect, borderPaint); } }
private void doLimits(float x, float y) { if (x < limits.left) { limits.left = x; } if (x > limits.right) { limits.right = x; } if (y < limits.top) { limits.top = y; } if (y > limits.bottom) { limits.bottom = y; } }
public SVGTileProvider(File file, float dpi) throws IOException { mScale = Math.round(dpi + .3f); // Make it look nice on N7 (1.3 dpi) mDimension = BASE_TILE_SIZE * mScale; mPool = new TileGeneratorPool(POOL_MAX_SIZE); SVG svg = new SVGBuilder().readFromInputStream(new FileInputStream(file)).build(); mSvgPicture = svg.getPicture(); RectF limits = svg.getLimits(); mBaseMatrix = new Matrix(); mBaseMatrix.setPolyToPoly( new float[] {0, 0, limits.width(), 0, limits.width(), limits.height()}, 0, new float[] { 40.95635986328125f, 98.94217824936158f, 40.95730018615723f, 98.94123077396628f, 40.95791244506836f, 98.94186019897214f }, 0, 3); }
@Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); float xpad = (float) (getPaddingLeft() + getPaddingRight()); float ypad = (float) (getPaddingTop() + getPaddingBottom()); float ww = (float) w - xpad - axisYSpacing; float hh = (float) h - ypad - axisXSpacing; // Figure out how big we can make the pie. mPlotBounds = new RectF(0f, 0f, ww, hh); mPlotBounds.offsetTo(getPaddingLeft() + axisYSpacing, getPaddingTop()); onDataChanged(); }
private int calcX(float x) { RectF r = mPlotBounds; return Math.round(r.left + r.width() * (x - getXMin()) / (getXMax() - getXMin())); }
@Override public void onDraw(Canvas canvas) { int margeLeft, margeRight, margeTop, margeBot, line, calcLine, part; if (canvas.getWidth() > canvas.getHeight()) { ref = (int) (canvas.getHeight() * 0.85); margin = (int) (canvas.getHeight() * 0.15); } else { ref = (int) (canvas.getWidth() * 0.85); margin = (int) (canvas.getWidth() * 0.15); } part = ref / NB_SQUARE_PAR_LINE; line = -1; int size = (int) Math.pow(NB_SQUARE_PAR_LINE, 2); for (int i = 0; i < size; i++) { ISquare square = chessboard.get(i); calcLine = (i - i % NB_SQUARE_PAR_LINE) / NB_SQUARE_PAR_LINE; margeTop = calcLine * part + margin / 2; if (calcLine != line) { line = calcLine; margeLeft = margin / 2; } else { margeLeft = margin / 2 + part * (i % NB_SQUARE_PAR_LINE); } margeBot = margeTop + part; margeRight = margeLeft + part; if ((line + i) % 2 == 1) { paintSquare.setColor(Color.parseColor("#a7823d")); } else { paintSquare.setColor(Color.parseColor("#e6e6ff")); } Rect rect = new Rect(margeLeft, margeTop, margeRight, margeBot); canvas.drawRect(rect, paintSquare); int status = square.getStatus(); if (status != ISquare.STATUS_DEFAULT) { int border_margin = (int) (part * 0.08); int inner_margin; switch (status) { case (ISquare.STATUS_SELECTED): paintStatus.setColor(Color.parseColor("#0034E1")); // "#FFA200")); paintStatus.setStyle(Paint.Style.STROKE); paintStatus.setStrokeWidth(border_margin); inner_margin = border_margin / 2; rectF.set( margeLeft + inner_margin, margeTop + inner_margin, margeRight - inner_margin, margeBot - inner_margin); canvas.drawRect(rectF, paintStatus); break; case (ISquare.STATUS_TARGETABLE): paintStatus.setColor(Color.parseColor("#D23939")); paintStatus.setStyle(Paint.Style.FILL); paintStatus.setStrokeWidth(0); inner_margin = (int) (border_margin / 1.5); rectF.set( margeLeft + inner_margin, margeTop + inner_margin, margeRight - inner_margin, margeBot - inner_margin); canvas.drawRect(rectF, paintStatus); break; case (ISquare.STATUS_MOVE): paintStatus.setColor(Color.parseColor("#3899D1")); paintStatus.setStyle(Paint.Style.FILL); paintStatus.setStrokeWidth(0); inner_margin = (int) (border_margin / 1.5); rectF.set( margeLeft + inner_margin, margeTop + inner_margin, margeRight - inner_margin, margeBot - inner_margin); canvas.drawRect(rectF, paintStatus); break; } } if (!square.isEmpty()) { IPiece piece = square.getPiece(); int marginDrawable = (int) (part * 0.2); RelativeLayout myLayout = (RelativeLayout) this.getParent(); int width = (margeRight - marginDrawable) - (margeLeft + marginDrawable); int height = (margeBot - marginDrawable) - (margeTop + marginDrawable); int left = margeLeft + marginDrawable; int top = margeTop + marginDrawable; piece.setImage(getContext(), myLayout, width, height, left, top); } } }
@Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); Log.d(TAG, "Slice Count: " + mData.size()); if (mData.size() > 0) { // // Set dimensions for text, pie chart, etc // // Account for padding float xpad = (float) (getPaddingLeft() + getPaddingRight()); float ypad = (float) (getPaddingTop() + getPaddingBottom()); // Account for the label if (mShowText) xpad += mTextWidth; float ww = (float) w - xpad; float hh = (float) h - ypad; // Figure out how big we can make the pie. float diameter = Math.min(ww, hh); mPieBounds = new RectF(0.0f, 0.0f, diameter, diameter); mPieBounds.offsetTo(getPaddingLeft(), getPaddingTop()); // Log.d(TAG, "mPieBounds>> "+mPieBounds); mPointerY = mTextY - (mTextHeight / 2.0f); float pointerOffset = mPieBounds.centerY() - mPointerY; // Make adjustments based on text position if (mTextPos == TEXTPOS_LEFT) { mTextPaint.setTextAlign(Paint.Align.RIGHT); if (mShowText) mPieBounds.offset(mTextWidth, 0.0f); mTextX = mPieBounds.left; if (pointerOffset < 0) { pointerOffset = -pointerOffset; mCurrentItemAngle = 225; } else { mCurrentItemAngle = 135; } mPointerX = mPieBounds.centerX() - pointerOffset; } else { mTextPaint.setTextAlign(Paint.Align.LEFT); mTextX = mPieBounds.right; if (pointerOffset < 0) { pointerOffset = -pointerOffset; mCurrentItemAngle = 315; } else { mCurrentItemAngle = 45; } mPointerX = mPieBounds.centerX() + pointerOffset; } mShadowBounds = new RectF( mPieBounds.left + 10, mPieBounds.bottom + 10, mPieBounds.right - 10, mPieBounds.bottom + 20); // Lay out the child view that actually draws the pie. mPieView.layout( (int) mPieBounds.left, (int) mPieBounds.top, (int) mPieBounds.right, (int) mPieBounds.bottom); mPieView.setPivot(mPieBounds.width() / 2, mPieBounds.height() / 2); mPointerView.layout(0, 0, w, h); onDataChanged(); } }
@Override public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException { // Reset paint opacity paint.setAlpha(255); // Ignore everything but rectangles in bounds mode if (boundsMode) { if (localName.equals("rect")) { Float x = getFloatAttr("x", atts); if (x == null) { x = 0f; } Float y = getFloatAttr("y", atts); if (y == null) { y = 0f; } Float width = getFloatAttr("width", atts); Float height = getFloatAttr("height", atts); bounds = new RectF(x, y, x + width, y + height); } return; } if (localName.equals("svg")) { int width = (int) Math.ceil(getFloatAttr("width", atts)); int height = (int) Math.ceil(getFloatAttr("height", atts)); canvas = picture.beginRecording(width, height); } else if (localName.equals("defs")) { // Ignore } else if (localName.equals("linearGradient")) { gradient = doGradient(true, atts); } else if (localName.equals("radialGradient")) { gradient = doGradient(false, atts); } else if (localName.equals("stop")) { if (gradient != null) { float offset = getFloatAttr("offset", atts); String styles = getStringAttr("style", atts); StyleSet styleSet = new StyleSet(styles); String colorStyle = styleSet.getStyle("stop-color"); int color = Color.BLACK; if (colorStyle != null) { if (colorStyle.startsWith("#")) { color = Integer.parseInt(colorStyle.substring(1), 16); } else { color = Integer.parseInt(colorStyle, 16); } } String opacityStyle = styleSet.getStyle("stop-opacity"); if (opacityStyle != null) { float alpha = Float.parseFloat(opacityStyle); int alphaInt = Math.round(255 * alpha); color |= (alphaInt << 24); } else { color |= 0xFF000000; } gradient.positions.add(offset); gradient.colors.add(color); } } else if (localName.equals("g")) { // Check to see if this is the "bounds" layer if ("bounds".equalsIgnoreCase(getStringAttr("id", atts))) { boundsMode = true; } if (hidden) { hiddenLevel++; // Util.debug("Hidden up: " + hiddenLevel); } // Go in to hidden mode if display is "none" if ("none".equals(getStringAttr("display", atts))) { if (!hidden) { hidden = true; hiddenLevel = 1; // Util.debug("Hidden up: " + hiddenLevel); } } pushTransform(atts); } else if (!hidden && localName.equals("rect")) { Float x = getFloatAttr("x", atts); if (x == null) { x = 0f; } Float y = getFloatAttr("y", atts); if (y == null) { y = 0f; } Float width = getFloatAttr("width", atts); Float height = getFloatAttr("height", atts); Float rx = getFloatAttr("rx", atts); Float ry = getFloatAttr("ry", atts); if (rx == null) { if (ry == null) rx = ry = 0f; else rx = ry; } else { if (ry == null) ry = rx; } if (rx > width / 2) rx = width * 0.5f; if (ry > height / 2) ry = height * 0.5f; pushTransform(atts); Properties props = new Properties(atts); if (doFill(props, gradientMap)) { doLimits(x, y, width, height); if (rx > 0 && ry > 0) canvas.drawRoundRect(new RectF(x, y, x + width, y + height), rx, ry, paint); else canvas.drawRect(x, y, x + width, y + height, paint); } if (doStroke(props, gradientMap)) { if (rx > 0 && ry > 0) canvas.drawRoundRect(new RectF(x, y, x + width, y + height), rx, ry, paint); else canvas.drawRect(x, y, x + width, y + height, paint); } popTransform(); } else if (!hidden && localName.equals("line")) { Float x1 = getFloatAttr("x1", atts); Float x2 = getFloatAttr("x2", atts); Float y1 = getFloatAttr("y1", atts); Float y2 = getFloatAttr("y2", atts); Properties props = new Properties(atts); if (doStroke(props, gradientMap)) { pushTransform(atts); doLimits(x1, y1); doLimits(x2, y2); canvas.drawLine(x1, y1, x2, y2, paint); popTransform(); } } else if (!hidden && localName.equals("circle")) { Float centerX = getFloatAttr("cx", atts); Float centerY = getFloatAttr("cy", atts); Float radius = getFloatAttr("r", atts); if (centerX != null && centerY != null && radius != null) { pushTransform(atts); Properties props = new Properties(atts); if (doFill(props, gradientMap)) { doLimits(centerX - radius, centerY - radius); doLimits(centerX + radius, centerY + radius); canvas.drawCircle(centerX, centerY, radius, paint); } if (doStroke(props, gradientMap)) { canvas.drawCircle(centerX, centerY, radius, paint); } popTransform(); } } else if (!hidden && localName.equals("ellipse")) { Float centerX = getFloatAttr("cx", atts); Float centerY = getFloatAttr("cy", atts); Float radiusX = getFloatAttr("rx", atts); Float radiusY = getFloatAttr("ry", atts); if (centerX != null && centerY != null && radiusX != null && radiusY != null) { pushTransform(atts); Properties props = new Properties(atts); rect.set(centerX - radiusX, centerY - radiusY, centerX + radiusX, centerY + radiusY); if (doFill(props, gradientMap)) { doLimits(centerX - radiusX, centerY - radiusY); doLimits(centerX + radiusX, centerY + radiusY); canvas.drawOval(rect, paint); } if (doStroke(props, gradientMap)) { canvas.drawOval(rect, paint); } popTransform(); } } else if (!hidden && (localName.equals("polygon") || localName.equals("polyline"))) { NumberParse numbers = getNumberParseAttr("points", atts); if (numbers != null) { Path p = new Path(); ArrayList<Float> points = numbers.numbers; if (points.size() > 1) { pushTransform(atts); Properties props = new Properties(atts); p.moveTo(points.get(0), points.get(1)); for (int i = 2; i < points.size(); i += 2) { float x = points.get(i); float y = points.get(i + 1); p.lineTo(x, y); } // Don't close a polyline if (localName.equals("polygon")) { p.close(); } if (doFill(props, gradientMap)) { doLimits(p); canvas.drawPath(p, paint); } if (doStroke(props, gradientMap)) { canvas.drawPath(p, paint); } popTransform(); } } } else if (!hidden && localName.equals("path")) { Path p = doPath(getStringAttr("d", atts)); pushTransform(atts); Properties props = new Properties(atts); if (doFill(props, gradientMap)) { doLimits(p); canvas.drawPath(p, paint); } if (doStroke(props, gradientMap)) { canvas.drawPath(p, paint); } popTransform(); } else if (!hidden) { // Log.d(TAG, "UNRECOGNIZED SVG COMMAND: " + localName); } }
public static PointF getAnchorCoordinates(RectF widgetRect, Anchor anchor) { return PixelUtils.add( new PointF(widgetRect.left, widgetRect.top), getAnchorOffset(widgetRect.width(), widgetRect.height(), anchor)); }
@Override protected void onDraw(Canvas canvas) { float ringWidth = textHeight + 4; int height = getMeasuredHeight(); int width = getMeasuredWidth(); int px = width / 2; int py = height / 2; Point center = new Point(px, py); int radius = Math.min(px, py) - 2; RectF boundingBox = new RectF(center.x - radius, center.y - radius, center.x + radius, center.y + radius); RectF innerBoundingBox = new RectF( center.x - radius + ringWidth, center.y - radius + ringWidth, center.x + radius - ringWidth, center.y + radius - ringWidth); float innerRadius = innerBoundingBox.height() / 2; RadialGradient borderGradient = new RadialGradient( px, py, radius, borderGradientColors, borderGradientPositions, TileMode.CLAMP); Paint pgb = new Paint(); pgb.setShader(borderGradient); Path outerRingPath = new Path(); outerRingPath.addOval(boundingBox, Direction.CW); canvas.drawPath(outerRingPath, pgb); LinearGradient skyShader = new LinearGradient( center.x, innerBoundingBox.top, center.x, innerBoundingBox.bottom, skyHorizonColorFrom, skyHorizonColorTo, TileMode.CLAMP); Paint skyPaint = new Paint(); skyPaint.setShader(skyShader); LinearGradient groundShader = new LinearGradient( center.x, innerBoundingBox.top, center.x, innerBoundingBox.bottom, groundHorizonColorFrom, groundHorizonColorTo, TileMode.CLAMP); Paint groundPaint = new Paint(); groundPaint.setShader(groundShader); float tiltDegree = pitch; while (tiltDegree > 90 || tiltDegree < -90) { if (tiltDegree > 90) tiltDegree = -90 + (tiltDegree - 90); if (tiltDegree < -90) tiltDegree = 90 - (tiltDegree + 90); } float rollDegree = roll; while (rollDegree > 180 || rollDegree < -180) { if (rollDegree > 180) rollDegree = -180 + (rollDegree - 180); if (rollDegree < -180) rollDegree = 180 - (rollDegree + 180); } Path skyPath = new Path(); skyPath.addArc(innerBoundingBox, -rollDegree, (180 + (2 * rollDegree))); canvas.rotate(-tiltDegree, px, py); canvas.drawOval(innerBoundingBox, groundPaint); canvas.drawPath(skyPath, skyPaint); canvas.drawPath(skyPath, markerPaint); int markWidth = radius / 3; int startX = center.x - markWidth; int endX = center.x + markWidth; Log.d("PAARV ", "Roll " + String.valueOf(rollDegree)); Log.d("PAARV ", "Pitch " + String.valueOf(tiltDegree)); double h = innerRadius * Math.cos(Math.toRadians(90 - tiltDegree)); double justTiltX = center.x - h; float pxPerDegree = (innerBoundingBox.height() / 2) / 45f; for (int i = 90; i >= -90; i -= 10) { double ypos = justTiltX + i * pxPerDegree; if ((ypos < (innerBoundingBox.top + textHeight)) || (ypos > innerBoundingBox.bottom - textHeight)) continue; canvas.drawLine(startX, (float) ypos, endX, (float) ypos, markerPaint); int displayPos = (int) (tiltDegree - i); String displayString = String.valueOf(displayPos); float stringSizeWidth = textPaint.measureText(displayString); canvas.drawText( displayString, (int) (center.x - stringSizeWidth / 2), (int) (ypos) + 1, textPaint); } markerPaint.setStrokeWidth(2); canvas.drawLine( center.x - radius / 2, (float) justTiltX, center.x + radius / 2, (float) justTiltX, markerPaint); markerPaint.setStrokeWidth(1); Path rollArrow = new Path(); rollArrow.moveTo(center.x - 3, (int) innerBoundingBox.top + 14); rollArrow.lineTo(center.x, (int) innerBoundingBox.top + 10); rollArrow.moveTo(center.x + 3, innerBoundingBox.top + 14); rollArrow.lineTo(center.x, innerBoundingBox.top + 10); canvas.drawPath(rollArrow, markerPaint); String rollText = String.valueOf(rollDegree); double rollTextWidth = textPaint.measureText(rollText); canvas.drawText( rollText, (float) (center.x - rollTextWidth / 2), innerBoundingBox.top + textHeight + 2, textPaint); canvas.restore(); canvas.save(); canvas.rotate(180, center.x, center.y); for (int i = -180; i < 180; i += 10) { if (i % 30 == 0) { String rollString = String.valueOf(i * -1); float rollStringWidth = textPaint.measureText(rollString); PointF rollStringCenter = new PointF(center.x - rollStringWidth / 2, innerBoundingBox.top + 1 + textHeight); canvas.drawText(rollString, rollStringCenter.x, rollStringCenter.y, textPaint); } else { canvas.drawLine( center.x, (int) innerBoundingBox.top, center.x, (int) innerBoundingBox.top + 5, markerPaint); } canvas.rotate(10, center.x, center.y); } canvas.restore(); canvas.save(); canvas.rotate(-1 * (bearing), px, py); double increment = 22.5; for (double i = 0; i < 360; i += increment) { CompassDirection cd = CompassDirection.values()[(int) (i / 22.5)]; String headString = cd.toString(); float headStringWidth = textPaint.measureText(headString); PointF headStringCenter = new PointF(center.x - headStringWidth / 2, boundingBox.top + 1 + textHeight); if (i % increment == 0) canvas.drawText(headString, headStringCenter.x, headStringCenter.y, textPaint); else canvas.drawLine( center.x, (int) boundingBox.top, center.x, (int) boundingBox.top + 3, markerPaint); canvas.rotate((int) increment, center.x, center.y); } canvas.restore(); RadialGradient glassShader = new RadialGradient( px, py, (int) innerRadius, glassGradientColors, glassGradientPositions, TileMode.CLAMP); Paint glassPaint = new Paint(); glassPaint.setShader(glassShader); canvas.drawOval(innerBoundingBox, glassPaint); canvas.drawOval(boundingBox, circlePaint); circlePaint.setStrokeWidth(2); canvas.drawOval(innerBoundingBox, circlePaint); canvas.restore(); }
// Grows the cropping rectange by (dx, dy) in image space. void growBy(float dx, float dy) { if (mMaintainAspectRatio) { if (dx != 0) { dy = dx / mInitialAspectRatio; } else if (dy != 0) { dx = dy * mInitialAspectRatio; } } // Don't let the cropping rectangle grow too fast. // Grow at most half of the difference between the image rectangle and // the cropping rectangle. RectF r = new RectF(mCropRect); if (dx > 0F && r.width() + 2 * dx > mImageRect.width()) { float adjustment = (mImageRect.width() - r.width()) / 2F; dx = adjustment; if (mMaintainAspectRatio) { dy = dx / mInitialAspectRatio; } } if (dy > 0F && r.height() + 2 * dy > mImageRect.height()) { float adjustment = (mImageRect.height() - r.height()) / 2F; dy = adjustment; if (mMaintainAspectRatio) { dx = dy * mInitialAspectRatio; } } r.inset(-dx, -dy); // Don't let the cropping rectangle shrink too fast. final float widthCap = 25F; if (r.width() < widthCap) { r.inset(-(widthCap - r.width()) / 2F, 0F); } float heightCap = mMaintainAspectRatio ? (widthCap / mInitialAspectRatio) : widthCap; if (r.height() < heightCap) { r.inset(0F, -(heightCap - r.height()) / 2F); } // Put the cropping rectangle inside the image rectangle. if (r.left < mImageRect.left) { r.offset(mImageRect.left - r.left, 0F); } else if (r.right > mImageRect.right) { r.offset(-(r.right - mImageRect.right), 0); } if (r.top < mImageRect.top) { r.offset(0F, mImageRect.top - r.top); } else if (r.bottom > mImageRect.bottom) { r.offset(0F, -(r.bottom - mImageRect.bottom)); } mCropRect.set(r); mDrawRect = computeLayout(); mContext.invalidate(); }
private int calcY(float y) { RectF r = mPlotBounds; return Math.round(r.top + r.height() * (1 - (y - getYMin()) / (getYMax() - getYMin()))); }
public void build(DialogWireframe description, int w, int h, TelegramApplication application) { layoutH = h; layoutW = w; if (description.getPeerType() == PeerType.PEER_USER) { if (description.getPeerId() == 333000) { isHighlighted = false; } else { User user = description.getDialogUser(); isHighlighted = user.getLinkType() == LinkType.FOREIGN; } isGroup = false; isEncrypted = false; } else if (description.getPeerType() == PeerType.PEER_CHAT) { isHighlighted = false; isGroup = true; isEncrypted = false; } else if (description.getPeerType() == PeerType.PEER_USER_ENCRYPTED) { isHighlighted = false; isGroup = false; isEncrypted = true; } isBodyHighlighted = description.getContentType() != ContentType.MESSAGE_TEXT; if (description.getUnreadCount() != 0 && !description.isMine()) { isUnreadIn = true; } else { isUnreadIn = false; } time = org.telegram.android.ui.TextUtil.formatDate(description.getDate(), application); isRtl = application.isRTL(); if (IS_LARGE) { layoutAvatarWidth = px(64); layoutPadding = application.getResources().getDimensionPixelSize(R.dimen.dialogs_padding); layoutBodyPadding = layoutAvatarWidth + layoutPadding + px(12); layoutAvatarTop = px(8); layoutTitleTop = px(34); layoutMainTop = px(60); layoutTimeTop = px(34); layoutMarkTop = px(44); layoutMarkBottom = layoutMarkTop + px(22); layoutMarkTextTop = layoutMarkTop + px(18); } else { layoutAvatarWidth = px(54); layoutPadding = application.getResources().getDimensionPixelSize(R.dimen.dialogs_padding); layoutBodyPadding = layoutAvatarWidth + layoutPadding + px(12); layoutAvatarTop = px(8); layoutTitleTop = px(30); layoutMainTop = px(54); layoutTimeTop = px(30); layoutMarkTop = px(38); layoutMarkBottom = layoutMarkTop + px(22); layoutMarkTextTop = layoutMarkTop + px(18); } layoutMainContentTop = (int) (layoutMainTop + bodyPaint.getFontMetrics().ascent); layoutTitleLayoutTop = (int) (layoutTitleTop + titlePaint.getFontMetrics().ascent); layoutStateTop = layoutTimeTop - px(10); layoutClockTop = layoutTimeTop - px(12); layoutEncryptedTop = layoutTimeTop - px(14); if (isRtl) { layoutAvatarLeft = w - layoutPadding - layoutAvatarWidth; } else { layoutAvatarLeft = layoutPadding; } int timeWidth = (int) unreadClockPaint.measureText(time); if (isRtl) { layoutTimeLeft = layoutPadding; layoutStateLeftDouble = layoutPadding + timeWidth + px(2); layoutStateLeft = layoutStateLeftDouble + px(6); layoutClockLeft = layoutPadding + timeWidth + px(2); } else { layoutTimeLeft = w - layoutPadding - timeWidth; layoutClockLeft = w - layoutPadding - timeWidth - px(14); layoutStateLeft = w - layoutPadding - timeWidth - px(16); layoutStateLeftDouble = w - layoutPadding - timeWidth - px(6 + 16); } layoutMarkRadius = px(2); if (description.isErrorState() || (description.getMessageState() == MessageState.FAILURE && description.isMine())) { layoutMarkWidth = px(22); if (isRtl) { layoutMarkLeft = layoutPadding; // getMeasuredWidth() - layoutMarkWidth - getPx(80); } else { layoutMarkLeft = w - layoutMarkWidth - layoutPadding; } } else { if (description.getUnreadCount() > 0) { if (description.getUnreadCount() >= 1000) { unreadCountText = I18nUtil.getInstance().correctFormatNumber(description.getUnreadCount() / 1000) + "K"; } else { unreadCountText = I18nUtil.getInstance().correctFormatNumber(description.getUnreadCount()); } int width = (int) counterTitlePaint.measureText(unreadCountText); Rect r = new Rect(); counterTitlePaint.getTextBounds(unreadCountText, 0, unreadCountText.length(), r); layoutMarkTextTop = layoutMarkTop + (layoutMarkBottom - layoutMarkTop + r.top) / 2 - r.top; if (width < px(22 - 14)) { layoutMarkWidth = px(22); } else { layoutMarkWidth = px(14) + width; } layoutMarkTextLeft = (layoutMarkWidth - width) / 2; if (isRtl) { layoutMarkLeft = layoutPadding; // getMeasuredWidth() - layoutMarkWidth - getPx(80); } else { layoutMarkLeft = w - layoutMarkWidth - layoutPadding; } } else { layoutMarkLeft = 0; layoutMarkWidth = 0; } } layoutMarkRect.set( layoutMarkLeft, layoutMarkTop, layoutMarkLeft + layoutMarkWidth, layoutMarkBottom); if (description.getPeerType() == PeerType.PEER_USER_ENCRYPTED) { if (isRtl) { if (description.isMine()) { layoutTitleLeft = timeWidth + px(16) + px(16); } else { layoutTitleLeft = timeWidth + px(12); } layoutTitleWidth = w - layoutTitleLeft - layoutBodyPadding - px(14) - px(6); layoutEncryptedLeft = w - layoutBodyPadding - px(12); } else { layoutTitleLeft = layoutBodyPadding + px(16); if (description.isMine()) { layoutTitleWidth = w - layoutTitleLeft - timeWidth - px(24); } else { layoutTitleWidth = w - layoutTitleLeft - timeWidth - px(12); } layoutEncryptedLeft = layoutBodyPadding + px(2); } } else { if (isRtl) { if (description.isMine()) { layoutTitleLeft = timeWidth + px(16) + px(16); } else { layoutTitleLeft = timeWidth + px(12); } layoutTitleWidth = w - layoutTitleLeft - layoutBodyPadding; } else { layoutTitleLeft = layoutBodyPadding; if (description.isMine()) { layoutTitleWidth = w - layoutTitleLeft - timeWidth - px(24) - px(12); } else { layoutTitleWidth = w - layoutTitleLeft - timeWidth - px(12); } } } layoutMainWidth = w - layoutBodyPadding - layoutPadding; if (isRtl) { layoutMainLeft = w - layoutMainWidth - layoutBodyPadding; if (layoutMarkWidth != 0) { layoutMainLeft += layoutMarkWidth + px(8); layoutMainWidth -= layoutMarkWidth + px(8); } } else { layoutMainLeft = layoutBodyPadding; if (layoutMarkWidth != 0) { layoutMainWidth -= layoutMarkWidth + px(8); } } avatarRect.set( layoutAvatarLeft, layoutAvatarTop, layoutAvatarLeft + layoutAvatarWidth, layoutAvatarTop + layoutAvatarWidth); // Building text layouts { String message = description.getMessage(); if (message.length() > 150) { message = message.substring(0, 150) + "..."; } message = message.replace("\n", " "); TextPaint bodyTextPaint; if (isBodyHighlighted) { bodyTextPaint = bodyHighlightPaint; } else { if (HIGHLIGHT_UNDEAD) { if (isUnreadIn) { bodyTextPaint = bodyUnreadPaint; } else { bodyTextPaint = bodyPaint; } } else { bodyTextPaint = bodyPaint; } } int nameLength = 0; if (description.getContentType() != ContentType.MESSAGE_SYSTEM) { if (description.isMine()) { String name = application.getResources().getString(R.string.st_dialog_you); nameLength = BidiFormatter.getInstance().unicodeWrap(name).length(); message = BidiFormatter.getInstance().unicodeWrap(name) + ": " + BidiFormatter.getInstance().unicodeWrap(message); } else { if (isGroup) { User user = description.getSender(); nameLength = BidiFormatter.getInstance().unicodeWrap(user.getFirstName()).length(); message = BidiFormatter.getInstance().unicodeWrap(user.getFirstName().replace("\n", " ")) + ": " + BidiFormatter.getInstance().unicodeWrap(message); } } } String preSequence = TextUtils.ellipsize(message, bodyTextPaint, layoutMainWidth, TextUtils.TruncateAt.END) .toString(); // Spannable sequence = // application.getEmojiProcessor().processEmojiCutMutable(preSequence, // EmojiProcessor.CONFIGURATION_DIALOGS); // if (nameLength != 0) { // sequence.setSpan(new ForegroundColorSpan(HIGHLIGHT_COLOR), 0, // Math.min(nameLength, sequence.length()), Spanned.SPAN_EXCLUSIVE_INCLUSIVE); // } // CharSequence resSequence = TextUtils.ellipsize(sequence, bodyTextPaint, // layoutMainWidth, TextUtils.TruncateAt.END); // bodyLayout = new StaticLayout(resSequence, bodyTextPaint, layoutMainWidth, // Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); // bodyString = null; Spannable sequence = application .getEmojiProcessor() .processEmojiCutMutable(preSequence, EmojiProcessor.CONFIGURATION_DIALOGS); if (nameLength != 0) { sequence.setSpan( new ForegroundColorSpan(HIGHLIGHT_COLOR), 0, Math.min(nameLength, sequence.length()), Spanned.SPAN_EXCLUSIVE_INCLUSIVE); } CharSequence resSequence = TextUtils.ellipsize(sequence, bodyTextPaint, layoutMainWidth, TextUtils.TruncateAt.END); bodyLayout = new StaticLayout( resSequence, bodyTextPaint, layoutMainWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); bodyString = null; // if (EmojiProcessor.containsEmoji(message)) { // Spannable sequence = // application.getEmojiProcessor().processEmojiCutMutable(preSequence, // EmojiProcessor.CONFIGURATION_DIALOGS); // if (nameLength != 0) { // sequence.setSpan(new ForegroundColorSpan(HIGHLIGHT_COLOR), 0, // Math.min(nameLength, sequence.length()), Spanned.SPAN_EXCLUSIVE_INCLUSIVE); // } // // CharSequence resSequence = TextUtils.ellipsize(sequence, // bodyTextPaint, layoutMainWidth, TextUtils.TruncateAt.END); // bodyLayout = new StaticLayout(resSequence, bodyTextPaint, // layoutMainWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); // bodyString = null; // } else { // bodyString = preSequence; // bodyLayout = null; // } } // Title { String title = description.getDialogTitle(); if (title.length() > 150) { title = title.substring(150) + "..."; } title = title.replace("\n", " "); TextPaint paint = isEncrypted ? titleEncryptedPaint : (isHighlighted ? titleHighlightPaint : titlePaint); // Spannable preSequence = // application.getEmojiProcessor().processEmojiCutMutable(title, // EmojiProcessor.CONFIGURATION_DIALOGS); // CharSequence sequence = TextUtils.ellipsize(preSequence, paint, // layoutTitleWidth, TextUtils.TruncateAt.END); // titleLayout = new StaticLayout(sequence, paint, layoutTitleWidth, // Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); // titleString = null; if (EmojiProcessor.containsEmoji(title)) { Spannable preSequence = application .getEmojiProcessor() .processEmojiCutMutable(title, EmojiProcessor.CONFIGURATION_DIALOGS); CharSequence sequence = TextUtils.ellipsize(preSequence, paint, layoutTitleWidth, TextUtils.TruncateAt.END); titleLayout = new StaticLayout( sequence, paint, layoutTitleWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); titleString = null; } else { titleString = TextUtils.ellipsize(title, paint, layoutTitleWidth, TextUtils.TruncateAt.END) .toString(); titleLayout = null; } } // Placeholder placeHolderName = description.getDialogName(); placeHolderColor = Placeholders.getBgColor(description.getPeerId()); if (placeHolderName.length() > 0) { usePlaceholder = true; placeholderLeft = layoutAvatarLeft + layoutAvatarWidth / 2; Rect rect = new Rect(); placeholderTextPaint.getTextBounds(placeHolderName, 0, placeHolderName.length(), rect); placeholderTop = layoutAvatarTop + (layoutAvatarWidth / 2 + ((rect.bottom - rect.top) / 2)); } else { usePlaceholder = false; } }