All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.sourceforge.plantuml.mindmap.FingerImpl Maven / Gradle / Ivy

There is a newer version: 1.2024.8
Show newest version
// THIS FILE HAS BEEN GENERATED BY A PREPROCESSOR.
/* +=======================================================================
 * |
 * |      PlantUML : a free UML diagram generator
 * |
 * +=======================================================================
 *
 * (C) Copyright 2009-2024, Arnaud Roques
 *
 * Project Info:  https://plantuml.com
 *
 * If you like this project or if you find it useful, you can support us at:
 *
 * https://plantuml.com/patreon (only 1$ per month!)
 * https://plantuml.com/liberapay (only 1€ per month!)
 * https://plantuml.com/paypal
 *
 *
 * PlantUML is free software; you can redistribute it and/or modify it
 * under the terms of the Eclipse Public License.
 *
 * THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC
 * LICENSE ("AGREEMENT"). [Eclipse Public License - v 1.0]
 *
 * ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES
 * RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.
 *
 * You may obtain a copy of the License at
 *
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * 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.
 *
 * PlantUML can occasionally display sponsored or advertising messages. Those
 * messages are usually generated on welcome or error images and never on
 * functional diagrams.
 * See https://plantuml.com/professional if you want to remove them
 *
 * Images (whatever their format : PNG, SVG, EPS...) generated by running PlantUML
 * are owned by the author of their corresponding sources code (that is, their
 * textual description in PlantUML language). Those images are not covered by
 * this EPL license.
 *
 * The generated images can then be used without any reference to the EPL license.
 * It is not even necessary to stipulate that they have been generated with PlantUML,
 * although this will be appreciated by the PlantUML team.
 *
 * There is an exception : if the textual description in PlantUML language is also covered
 * by any license, then the generated images are logically covered
 * by the very same license.
 *
 * This is the IGY distribution (Install GraphViz by Yourself).
 * You have to install GraphViz and to setup the GRAPHVIZ_DOT environment variable
 * (see https://plantuml.com/graphviz-dot )
 *
 * Icons provided by OpenIconic :  https://useiconic.com/open
 * Archimate sprites provided by Archi :  http://www.archimatetool.com
 * Stdlib AWS provided by https://github.com/milo-minderbinder/AWS-PlantUML
 * Stdlib Icons provided https://github.com/tupadr3/plantuml-icon-font-sprites
 * ASCIIMathML (c) Peter Jipsen http://www.chapman.edu/~jipsen
 * ASCIIMathML (c) David Lippman http://www.pierce.ctc.edu/dlippman
 * CafeUndZopfli ported by Eugene Klyuchnikov https://github.com/eustas/CafeUndZopfli
 * Brotli (c) by the Brotli Authors https://github.com/google/brotli
 * Themes (c) by Brett Schwarz https://github.com/bschwarz/puml-themes
 * Twemoji (c) by Twitter at https://twemoji.twitter.com/
 *
 */
package net.sourceforge.plantuml.mindmap;

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

import net.sourceforge.plantuml.activitydiagram3.ftile.vertical.FtileBoxOld;
import net.sourceforge.plantuml.klimt.UPath;
import net.sourceforge.plantuml.klimt.UStroke;
import net.sourceforge.plantuml.klimt.UTranslate;
import net.sourceforge.plantuml.klimt.color.ColorType;
import net.sourceforge.plantuml.klimt.color.Colors;
import net.sourceforge.plantuml.klimt.color.HColor;
import net.sourceforge.plantuml.klimt.creole.CreoleMode;
import net.sourceforge.plantuml.klimt.drawing.UGraphic;
import net.sourceforge.plantuml.klimt.font.StringBounder;
import net.sourceforge.plantuml.klimt.geom.Rankdir;
import net.sourceforge.plantuml.klimt.geom.XDimension2D;
import net.sourceforge.plantuml.klimt.geom.XPoint2D;
import net.sourceforge.plantuml.klimt.shape.TextBlock;
import net.sourceforge.plantuml.klimt.shape.TextBlockUtils;
import net.sourceforge.plantuml.klimt.shape.UDrawable;
import net.sourceforge.plantuml.skin.SkinParamColors;
import net.sourceforge.plantuml.style.ClockwiseTopRightBottomLeft;
import net.sourceforge.plantuml.style.ISkinParam;
import net.sourceforge.plantuml.style.PName;
import net.sourceforge.plantuml.style.Style;

public class FingerImpl implements Finger, UDrawable {

	private final Idea idea;
	private final ISkinParam skinParam;
	private final int direction;
	private boolean drawPhalanx = true;

	private final List nail = new ArrayList<>();
	private Tetris tetris = null;

	public static FingerImpl build(Idea idea, ISkinParam skinParam, boolean direction) {
		final FingerImpl result = new FingerImpl(idea, skinParam, direction);
		for (Idea child : idea.getChildren())
			result.addInNail(build(child, skinParam, direction));

		return result;
	}

	private boolean isTopToBottom() {
		return skinParam.getRankdir() == Rankdir.TOP_TO_BOTTOM;
	}

	public void addInNail(FingerImpl child) {
		nail.add(child);
	}

	private FingerImpl(Idea idea, ISkinParam skinParam, boolean direction) {
		this.idea = idea;
		this.skinParam = skinParam;
		this.direction = direction ? 1 : -1;
	}

	private ClockwiseTopRightBottomLeft getMargin() {
		return getStyle().getMargin();
	}

	public void drawU(final UGraphic ug) {
		final StringBounder stringBounder = ug.getStringBounder();
		final TextBlock phalanx = getPhalanx();
		final XDimension2D dimPhalanx = phalanx.calculateDimension(stringBounder);
		if (drawPhalanx) {
			final double posX;
			final double posY;
			if (isTopToBottom()) {
				posX = -getPhalanxThickness(stringBounder) / 2;
				posY = direction == 1 ? 0 : -dimPhalanx.getHeight();
			} else {
				posX = direction == 1 ? 0 : -dimPhalanx.getWidth();
				posY = -getPhalanxThickness(stringBounder) / 2;
			}
			phalanx.drawU(ug.apply(new UTranslate(posX, posY)));
		}
		final XPoint2D p1;
		if (isTopToBottom())
			p1 = new XPoint2D(0, direction * dimPhalanx.getHeight());
		else
			p1 = new XPoint2D(direction * dimPhalanx.getWidth(), 0);

		for (int i = 0; i < nail.size(); i++) {
			final FingerImpl child = nail.get(i);
			final SymetricalTeePositioned stp = getTetris(stringBounder).getElements().get(i);
			final XPoint2D p2;
			if (isTopToBottom())
				p2 = new XPoint2D(stp.getY(), direction * (dimPhalanx.getHeight() + getX12()));
			else
				p2 = new XPoint2D(direction * (dimPhalanx.getWidth() + getX12()), stp.getY());

			child.drawU(ug.apply(UTranslate.point(p2)));
			final HColor linkColor = getLinkColor();
			if (linkColor.isTransparent() == false)
				drawLine(ug.apply(linkColor).apply(getUStroke()), p1, p2);
		}

	}

	private HColor getLinkColor() {
		final Style styleArrow = getStyleArrow();
		return styleArrow.value(PName.LineColor).asColor(skinParam.getIHtmlColorSet());
	}

	private UStroke getUStroke() {
		final Style styleArrow = getStyleArrow();
		return styleArrow.getStroke();
	}

	private void drawLine(UGraphic ug, XPoint2D p1, XPoint2D p2) {
		final UPath path = UPath.none();
		path.moveTo(p1);
		if (isTopToBottom()) {
			final double delta1 = direction * 3;
			final double delta2 = direction * 10;
			path.lineTo(p1.getX(), p1.getY() + delta1);
			path.cubicTo(p1.getX(), p1.getY() + delta2, p2.getX(), p2.getY() - delta2, p2.getX(), p2.getY() - delta1);
		} else {
			final double delta1 = direction * 10;
			final double delta2 = direction * 25;
			path.lineTo(p1.getX() + delta1, p1.getY());
			path.cubicTo(p1.getX() + delta2, p1.getY(), p2.getX() - delta2, p2.getY(), p2.getX() - delta1, p2.getY());
		}
		path.lineTo(p2);
		ug.draw(path);
	}

	private Tetris getTetris(StringBounder stringBounder) {
		if (tetris == null) {
			tetris = new Tetris(idea.getLabel().toString());
			for (FingerImpl child : nail)
				tetris.add(child.asSymetricalTee(stringBounder));

			tetris.balance();
		}
		return tetris;
	}

	private SymetricalTee asSymetricalTee(StringBounder stringBounder) {
		final double thickness1 = getPhalanxThickness(stringBounder);
		final double elongation1 = getPhalanxElongation(stringBounder);
		if (nail.size() == 0)
			return new SymetricalTee(thickness1, elongation1, 0, 0);

		final double thickness2 = getNailThickness(stringBounder);
		final double elongation2 = getNailElongation(stringBounder);
		return new SymetricalTee(thickness1, elongation1 + getX1(), thickness2, getX2() + elongation2);
	}

	private double getX1() {
		if (isTopToBottom())
			return getMargin().getTop();
		else
			return getMargin().getLeft();
	}

	private double getX2() {
		if (isTopToBottom())
			return getMargin().getBottom() + 5;
		else
			return getMargin().getRight() + 30;
	}

	public double getX12() {
		return getX1() + getX2();
	}

	public double getPhalanxThickness(StringBounder stringBounder) {
		if (isTopToBottom())
			return getPhalanx().calculateDimension(stringBounder).getWidth();
		return getPhalanx().calculateDimension(stringBounder).getHeight();
	}

	public double getPhalanxElongation(StringBounder stringBounder) {
		if (isTopToBottom())
			return getPhalanx().calculateDimension(stringBounder).getHeight();
		return getPhalanx().calculateDimension(stringBounder).getWidth();
	}

	private TextBlock getPhalanx() {
		if (drawPhalanx == false)
			return TextBlockUtils.empty(0, 0);

		final Style style = getStyle();

		if (idea.getShape() == IdeaShape.BOX) {
			final ISkinParam foo = new SkinParamColors(skinParam,
					Colors.empty().add(ColorType.BACK, idea.getBackColor()));
			final TextBlock box = FtileBoxOld.createMindMap(style, foo, idea.getLabel());
			final ClockwiseTopRightBottomLeft margin = getMargin();
			if (isTopToBottom())
				return TextBlockUtils.withMargin(box, margin.getLeft(), margin.getRight(), 0, 0);
			else
				return TextBlockUtils.withMargin(box, 0, 0, margin.getTop(), margin.getBottom());
		}

		assert idea.getShape() == IdeaShape.NONE;
		final TextBlock text = idea.getLabel().create0(style.getFontConfiguration(skinParam.getIHtmlColorSet()),
				style.getHorizontalAlignment(), skinParam, style.wrapWidth(), CreoleMode.FULL, null, null);
		if (direction == 1)
			return TextBlockUtils.withMargin(text, 3, 0, 1, 1);

		return TextBlockUtils.withMargin(text, 0, 3, 1, 1);
	}

	private Style getStyle() {
		if (nail.size() != idea.getChildren().size())
			throw new IllegalStateException();

		return idea.getStyle();
	}

	private Style getStyleArrow() {
		return idea.getStyleArrow();
	}

	public double getNailThickness(StringBounder stringBounder) {
		return getTetris(stringBounder).getHeight();
	}

	public double getNailElongation(StringBounder stringBounder) {
		return getTetris(stringBounder).getWidth();
	}

	public double getFullThickness(StringBounder stringBounder) {
		final double thickness1 = getPhalanxThickness(stringBounder);
		final double thickness2 = getNailThickness(stringBounder);
		return Math.max(thickness1, thickness2);
	}

	public double getFullElongation(StringBounder stringBounder) {
		return getPhalanxElongation(stringBounder) + getNailElongation(stringBounder);
	}

	public void doNotDrawFirstPhalanx() {
		this.drawPhalanx = false;
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy