/* * Copyright 2015 Igor Maznitsa. * * 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 com.igormaznitsa.mindmap.swing.panel.ui; import com.igormaznitsa.mindmap.swing.panel.MindMapPanelConfig; import static com.igormaznitsa.mindmap.model.ModelUtils.breakToLines; import java.awt.Color; import java.awt.Font; import java.awt.geom.Rectangle2D; import javax.annotation.Nonnull; import javax.annotation.Nullable; import javax.swing.text.JTextComponent; import com.igormaznitsa.meta.common.utils.Assertions; import com.igormaznitsa.mindmap.swing.panel.ui.gfx.MMGraphics; public final class TextBlock implements Cloneable { private static final class Line { private final Rectangle2D bounds; private final String line; private Line(@Nonnull final String line, @Nonnull final Rectangle2D bounds) { this.bounds = bounds; this.line = line; } } private String text; private Line[] lines; private Font font; private float maxLineAscent; private final Rectangle2D bounds = new Rectangle2D.Double(); private TextAlign textAlign; private static final Rectangle2D ZERO = new Rectangle2D.Float(); public TextBlock(@Nonnull final TextBlock orig){ this.text = orig.text; this.lines = orig.lines.clone(); this.font = orig.font; this.maxLineAscent = orig.maxLineAscent; this.bounds.setRect(orig.getBounds()); this.textAlign = orig.textAlign; } public TextBlock(@Nonnull final String text, @Nonnull final TextAlign justify) { updateText(Assertions.assertNotNull(text)); this.textAlign = Assertions.assertNotNull(justify); } public void updateText(@Nullable final String text) { this.text = text == null ? "" : text; //NOI18N invalidate(); } public void fillByTextAndFont(@Nonnull final JTextComponent compo) { compo.setFont(this.font); compo.setText(this.text); } @Nonnull public Rectangle2D getBounds() { return this.bounds == null ? ZERO : this.bounds; } @Nonnull public TextAlign getTextAlign(){ return this.textAlign; } public void setTextAlign(@Nullable final TextAlign textAlign){ this.textAlign = textAlign == null ? TextAlign.CENTER : textAlign; invalidate(); } public void invalidate() { this.lines = null; } public void setCoordOffset(final double x, final double y){ this.bounds.setFrame(x, y, this.bounds.getWidth(), this.bounds.getHeight()); } public void updateSize(@Nonnull final MMGraphics gfx, @Nonnull final MindMapPanelConfig cfg) { this.font = cfg.getFont().deriveFont(cfg.safeScaleFloatValue(cfg.getFont().getSize2D(),2f)); gfx.setFont(font); this.maxLineAscent = gfx.getFontMaxAscent(); float maxWidth = 0.0f; float maxHeight = 0.0f; final String[] brokenText = breakToLines(this.text); this.lines = new Line[brokenText.length]; int index = 0; for (final String s : brokenText) { final Rectangle2D lineBounds = gfx.getStringBounds(s); if (Float.compare((float) lineBounds.getWidth(), maxWidth) > 0) { maxWidth = (float) lineBounds.getWidth(); } maxHeight += (float) lineBounds.getHeight(); this.lines[index++] = new Line(s, lineBounds); } this.bounds.setRect(0f, 0f, maxWidth, maxHeight); } public void paint(@Nonnull final MMGraphics gfx, @Nonnull final Color color) { if (this.font != null && this.lines != null) { double posy = this.bounds.getY() + this.maxLineAscent; gfx.setFont(this.font); for (final Line l : this.lines) { final double drawX; switch (this.textAlign) { case LEFT: { drawX = this.bounds.getX(); } break; case CENTER: { drawX = this.bounds.getX() + (this.bounds.getWidth() - l.bounds.getWidth()) / 2; } break; case RIGHT: { drawX = this.bounds.getX() + (this.bounds.getWidth() - l.bounds.getWidth()); } break; default: throw new Error("unexpected situation #283794"); //NOI18N } gfx.drawString(l.line, (int)Math.round(drawX), (int)Math.round(posy),color); posy += l.bounds.getHeight(); } } } }