/* * Catroid: An on-device visual programming system for Android devices * Copyright (C) 2010-2016 The Catrobat Team * (<http://developer.catrobat.org/credits>) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * An additional term exception under section 7 of the GNU Affero * General Public License, version 3, is available at * http://developer.catrobat.org/license_additional_term * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.catrobat.catroid.stage; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Path; import android.graphics.Rect; import android.graphics.RectF; import com.badlogic.gdx.graphics.Pixmap; import com.badlogic.gdx.graphics.Texture; import com.badlogic.gdx.graphics.g2d.Batch; import com.badlogic.gdx.scenes.scene2d.Actor; import com.badlogic.gdx.scenes.scene2d.ui.Image; import org.catrobat.catroid.ProjectManager; import org.catrobat.catroid.common.Constants; import org.catrobat.catroid.content.Sprite; import org.catrobat.catroid.utils.Utils; import java.io.ByteArrayOutputStream; import java.util.ArrayList; public class ShowBubbleActor extends Actor { ArrayList<String> bubbleValue; private Sprite sprite; private int type; private Image imageLeft; private Image imageRight; private Image image; private boolean drawRight = true; public ShowBubbleActor(String text, Sprite sprite, int type) { this.bubbleValue = Utils.formatStringForBubbleBricks(text); this.sprite = sprite; this.type = type; init(); } @Override public void draw(Batch batch, float parentAlpha) { switchLogic(); getImageForDraw().draw(batch, parentAlpha); } private void init() { imageRight = new Image(new Texture(drawBubbleOnCanvas(bubbleValue, true))); imageLeft = new Image(new Texture(drawBubbleOnCanvas(bubbleValue, false))); image = imageRight; } private Image getImageForDraw() { if (drawRight) { image.setX(sprite.look.getXInUserInterfaceDimensionUnit() + (sprite.look .getWidthInUserInterfaceDimensionUnit() / 2)); } else { image.setX(sprite.look.getXInUserInterfaceDimensionUnit() - sprite.look .getWidthInUserInterfaceDimensionUnit() / 2 - image.getWidth()); } image.setY(sprite.look.getYInUserInterfaceDimensionUnit() + (sprite.look .getHeightInUserInterfaceDimensionUnit() / 2)); return image; } private void switchLogic() { if (drawRight && !drawRight()) { drawRight = false; image = imageLeft; } if (!drawRight && !drawLeft()) { drawRight = true; image = imageRight; } } private boolean drawRight() { return sprite.look.getX() + sprite.look.getWidthInUserInterfaceDimensionUnit() + image.getWidth() < (ProjectManager.getInstance().getCurrentProject().getXmlHeader().virtualScreenWidth / 2); } private boolean drawLeft() { return sprite.look.getX() - image.getWidth() > -(ProjectManager.getInstance().getCurrentProject().getXmlHeader().virtualScreenWidth / 2); } private Pixmap drawBubbleOnCanvas(ArrayList<String> lines, boolean right) { Paint paint = new Paint(); paint.setTextSize(Constants.TEXT_SIZE_BUBBLE); paint.setAntiAlias(true); paint.setStyle(Paint.Style.FILL); paint.setColor(android.graphics.Color.BLACK); int width = 0; int height = 30; int border = Constants.BORDER_THICKNESS_BUBBLES; float y = Constants.PADDING_TOP; ArrayList<Float> xPositions = new ArrayList<>(); Rect temp = new Rect(); //Calculate height and width of textbox plus lineheight for (String line : lines) { height += Constants.LINE_SPACING_BUBBLES; paint.getTextBounds(line, 0, line.length(), temp); height += temp.height(); xPositions.add(paint.measureText(line)); if (width < temp.width()) { width = temp.width(); } } width += 55; if (width < 148) { width = 148; } float lineHeight = (height - 30) / lines.size(); //Setup Bitmap and textbox Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(bitmap); RectF rect = new RectF(0f, 0f, width, height); //Draw rounded textbox canvas.drawRoundRect(rect, 20, 20, paint); rect = new RectF(rect.left + border, rect.top + border, rect.right - border, rect.bottom - border); paint.setColor(android.graphics.Color.WHITE); canvas.drawRoundRect(rect, 15, 15, paint); paint.setColor(Color.BLACK); //Calculate x position for every line for (int i = 0; i < xPositions.size(); i++) { float x = ((float) width - xPositions.get(i)) / 2f; xPositions.set(i, x); } //Draw text in textbox int i = 0; for (String line : lines) { canvas.drawText(line, xPositions.get(i), y, paint); y += lineHeight; i++; } //Draw think bubbles or say triangle and convert to pixmap return getFinalBubble(width, height, bitmap, right); } private Pixmap getFinalBubble(int width, int height, Bitmap bitmap, boolean right) { Paint paint = new Paint(); paint.setColor(android.graphics.Color.BLACK); paint.setStyle(Paint.Style.FILL_AND_STROKE); paint.setStrokeWidth(2); Bitmap tempBitmap = Bitmap.createBitmap(width, height + Constants.OFFSET_FOR_THINK_BUBBLES_AND_ARROW, Bitmap.Config.ARGB_8888); Canvas tempCanvas = new Canvas(tempBitmap); tempCanvas.drawBitmap(bitmap, 0, 0, null); if (type == Constants.SAY_BRICK) { tempCanvas.drawPath(getSayTrianglePath(tempBitmap.getHeight(), tempBitmap.getWidth(), right), paint); paint.setColor(android.graphics.Color.WHITE); tempCanvas.drawPath(getSayTrianglePathSmaller(tempBitmap.getHeight(), tempBitmap.getWidth(), right), paint); } else { Bitmap thinkBubbles = getThinkBubbles(right); int startPos = right ? 0 : tempBitmap.getWidth() - 2 * Constants.OFFSET_FOR_THINK_BUBBLES_AND_ARROW; tempCanvas.drawBitmap(thinkBubbles, startPos, bitmap.getHeight(), null); } ByteArrayOutputStream stream = new ByteArrayOutputStream(); tempBitmap.compress(Bitmap.CompressFormat.PNG, 100, stream); byte[] bytes = stream.toByteArray(); return new Pixmap(bytes, 0, bytes.length); } private Path getSayTrianglePath(int bitmapHeight, int bitmapWidth, boolean right) { int offset = right ? 0 : bitmapWidth; Path path = new Path(); path.setFillType(Path.FillType.EVEN_ODD); path.moveTo(offset, bitmapHeight); path.lineTo(Math.abs(offset - 28), bitmapHeight - Constants.OFFSET_FOR_THINK_BUBBLES_AND_ARROW); path.lineTo(Math.abs(offset - 118), bitmapHeight - Constants.OFFSET_FOR_THINK_BUBBLES_AND_ARROW); path.lineTo(offset, bitmapHeight); path.close(); return path; } private Path getSayTrianglePathSmaller(int bitmapHeight, int bitmapWidth, boolean right) { int offset = right ? 0 : bitmapWidth; Path path = new Path(); path.moveTo(Math.abs(offset - 12), bitmapHeight - 9); path.lineTo(Math.abs(offset - 37), bitmapHeight - Constants.OFFSET_FOR_THINK_BUBBLES_AND_ARROW - 5); path.lineTo(Math.abs(offset - 116), bitmapHeight - Constants.OFFSET_FOR_THINK_BUBBLES_AND_ARROW - 5); path.lineTo(Math.abs(offset - 12), bitmapHeight - 9); path.close(); return path; } private Bitmap getThinkBubbles(boolean right) { Bitmap bitmap = Bitmap.createBitmap(Constants.OFFSET_FOR_THINK_BUBBLES_AND_ARROW + 30, Constants.OFFSET_FOR_THINK_BUBBLES_AND_ARROW, Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(bitmap); Paint paint = new Paint(); paint.setStyle(Paint.Style.FILL); int length = right ? bitmap.getWidth() : 0; for (int i = 0; i <= 3; i++) { paint.setColor(android.graphics.Color.BLACK); canvas.drawCircle(Math.abs(length - i * 15 - 10), i * 10, 10 - i, paint); paint.setColor(android.graphics.Color.WHITE); canvas.drawCircle(Math.abs(length - i * 15 - 10), i * 10, 7 - i, paint); } return bitmap; } }