/*
* funCKit - functional Circuit Kit
* Copyright (C) 2013 Lukas Elsner <open@mindrunner.de>
* Copyright (C) 2013 Peter Dahlberg <catdog2@tuxzone.org>
* Copyright (C) 2013 Julian Stier <mail@julian-stier.de>
* Copyright (C) 2013 Sebastian Vetter <mail@b4sti.eu>
* Copyright (C) 2013 Thomas Poxrucker <poxrucker_t@web.de>
* Copyright (C) 2013 Alexander Treml <alex.treml@directbox.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.sep2011.funckit.drawer;
import de.sep2011.funckit.drawer.action.DrawAction;
import de.sep2011.funckit.model.graphmodel.Brick;
import de.sep2011.funckit.model.graphmodel.Component;
import de.sep2011.funckit.model.graphmodel.Element;
import de.sep2011.funckit.model.graphmodel.Input;
import de.sep2011.funckit.model.graphmodel.Output;
import de.sep2011.funckit.model.graphmodel.Switch;
import de.sep2011.funckit.model.graphmodel.Wire;
import de.sep2011.funckit.model.graphmodel.implementations.And;
import de.sep2011.funckit.model.graphmodel.implementations.IdPoint;
import de.sep2011.funckit.model.graphmodel.implementations.Light;
import de.sep2011.funckit.model.graphmodel.implementations.Not;
import de.sep2011.funckit.model.graphmodel.implementations.Or;
import de.sep2011.funckit.model.sessionmodel.Settings;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Path2D;
/**
* Full featured drawer, that draws elements with all its labels, access points,
* surrounding wires and connection points ({@link IdPoint}s).
*/
public class FancyDrawer implements Drawer {
/**
* LayoutResolver object for access points to enable more flexible layouts
* for them.
*/
private LayoutResolver accessPointLayoutResolver = new LayoutResolver();
/**
* State resolver for using decision table in connection with access points
*/
private ElementStateResolver accessPointStateResolver;
/**
* Injected graphics object on which this drawer paints all the stuff on.
*/
private Graphics2D graphics;
/**
* Injected action, that is performed to apply all information to the
* prepared layout object for drawing.
*/
private DrawAction action;
/**
* Injected layout object with basic information; e.g. about simulation
* queue or other information, that can not be resolved via {@link
* DrawAction} (and thus {@link DecisionTable}).
*/
private Layout layout;
/**
* Injected application settings object to apply latest configurations for
* colors, fonts, sizes, margins etc. pp.
*/
private Settings settings;
/**
* Constructor with settings injection.
*
* @param settings Application's settings object.
*/
public FancyDrawer(Settings settings) {
assert settings != null;
this.layout = new Layout();
this.settings = settings;
}
/**
* Other constructor to inject a modified {@link LayoutResolver}, that is
* used for resolving {@link Layout} objects for {@link AccessPoint}s in
* further drawing phases. Thus it would be possible to access simulation
* information for access points, so they could be drawn in a simulated
* state for example.
*
* @param settings Regular applications settings object.
* @param accessPointLayoutResolver Modified non-null layout resolver.
*/
public FancyDrawer(
Settings settings,
LayoutResolver accessPointLayoutResolver,
ElementStateResolver accessPointStateResolver) {
assert settings != null;
assert accessPointLayoutResolver != null;
this.layout = new Layout();
this.settings = settings;
this.accessPointLayoutResolver = accessPointLayoutResolver;
this.accessPointStateResolver = accessPointStateResolver;
}
/**
* {@inheritDoc}
*/
@Override
public void setGraphics(Graphics graphics) {
assert graphics != null;
this.graphics = (Graphics2D) graphics;
}
/**
* {@inheritDoc}
*/
@Override
public void setAction(DrawAction action) {
assert action != null;
this.action = action;
}
/**
* {@inheritDoc}
*/
@Override
public void setLayout(Layout layout) {
assert layout != null;
this.layout = layout;
}
/**
* {@inheritDoc}
*/
@Override
public void visit(Element element) {
throw new UnsupportedOperationException(
"Raw element object can not be drawn.");
}
/**
* {@inheritDoc}
*/
@Override
public void visit(Wire wire) {
assert graphics != null;
assert action != null;
assert layout != null;
action.setUp(layout, settings, graphics);
action.prepare(layout);
action.prepare(wire, layout);
drawShapes(layout);
}
/**
* {@inheritDoc}
*/
@Override
public void visit(Component component) {
assert graphics != null;
assert action != null;
assert layout != null;
action.setUp(layout, settings, graphics);
action.prepare(layout);
action.prepare(component, layout);
drawShapes(layout);
drawAccessPoints(component);
drawTexts(component, layout, graphics);
}
/**
* {@inheritDoc}
*/
@Override
public void visit(Switch s) {
assert graphics != null;
assert action != null;
assert layout != null;
action.setUp(layout, settings, graphics);
action.prepare(layout);
action.prepare(s, layout);
drawShapes(layout);
drawAccessPoints(s);
drawTexts(s, layout, graphics);
}
/**
* {@inheritDoc}
*/
@Override
public void visit(Light light) {
assert graphics != null;
assert action != null;
assert layout != null;
action.setUp(layout, settings, graphics);
action.prepare(layout);
action.prepare(light, layout);
drawShapes(layout);
drawAccessPoints(light);
}
/**
* {@inheritDoc}
*/
@Override
public void visit(And and) {
assert graphics != null;
assert action != null;
assert layout != null;
action.setUp(layout, settings, graphics);
action.prepare(layout);
action.prepare(and, layout);
drawShapes(layout);
drawAccessPoints(and);
drawTexts(and, layout, graphics);
}
/**
* {@inheritDoc}
*/
@Override
public void visit(Or or) {
assert graphics != null;
assert action != null;
assert layout != null;
action.setUp(layout, settings, graphics);
action.prepare(layout);
action.prepare(or, layout);
drawShapes(layout);
drawAccessPoints(or);
drawTexts(or, layout, graphics);
}
/**
* {@inheritDoc}
*/
@Override
public void visit(Not not) {
assert graphics != null;
assert action != null;
assert layout != null;
action.setUp(layout, settings, graphics);
action.prepare(layout);
action.prepare(not, layout);
drawShapes(layout);
drawAccessPoints(not);
drawTexts(not, layout, graphics);
}
/**
* {@inheritDoc}
*/
@Override
public void visit(IdPoint idPoint) {
assert graphics != null;
assert action != null;
assert layout != null;
action.setUp(layout, settings, graphics);
action.prepare(layout);
action.prepare(idPoint, layout);
drawShapes(layout);
}
/**
* {@inheritDoc}
*/
private void drawShapes(Layout layout) {
for (String shapeName : layout.getShapeMap().keySet()) {
LayoutShape layoutShape = layout.getShape(shapeName);
drawShape(
layoutShape.getShapePath(),
layoutShape.getBorderColor(),
layoutShape.getFillColor()
);
}
}
/**
* Draws a given shape with a specific border and fill color on the current
* graphics object.
*
* @param shape Shape descriptive object, that should be drawn on current
* graphics object.
* @param border Color to use for shapes border.
* @param fill Color used for filling shape.
*/
private void drawShape(Path2D shape, Color border, Color fill) {
graphics.setColor(fill);
graphics.fill(shape);
graphics.setColor(border);
graphics.draw(shape);
}
/**
* Draws all access points of the given brick.
*
* @param brick Brick which access points should be drawn.
*/
private void drawAccessPoints(Brick brick) {
for (Input input : brick.getInputs()) {
/*
* Resolve layout for input object. If layout resolver has already injected a
* simulation object, resolver can set layout to simulated state.
*/
Layout inputLayout = new Layout();
accessPointLayoutResolver.setLayout(inputLayout);
accessPointLayoutResolver.resolve(input);
DrawAction inputAction = action;
/*
* If there is a own {@link ElementStateResolver} for access points
* injected, then use that resolver to change the action for setting
* up the layout of current input, so we can draw different selection
* or active states for single access points.
*/
if (accessPointStateResolver != null) {
ElementState state = accessPointStateResolver.resolve(input);
inputAction = DecisionTable.resolve(state);
}
inputAction.setUp(inputLayout, settings, graphics);
inputAction.prepare(inputLayout);
inputAction.prepare(input, inputLayout);
drawAccessPoint(brick, inputLayout);
}
for (Output output : brick.getOutputs()) {
/*
* Resolve layout for output object. If layout resolver has already injected a
* simulation object, resolver can set layout to simulated state.
*/
Layout outputLayout = new Layout();
accessPointLayoutResolver.setLayout(outputLayout);
accessPointLayoutResolver.resolve(output);
DrawAction outputAction = action;
/*
* If there is a own {@link ElementStateResolver} for access points
* injected, then use that resolver to change the action for setting
* up the layout of current input, so we can draw different selection
* or active states for single access points.
*/
if (accessPointStateResolver != null) {
ElementState state = accessPointStateResolver.resolve(output);
outputAction = DecisionTable.resolve(state);
}
outputAction.setUp(outputLayout, settings, graphics);
outputAction.prepare(outputLayout);
outputAction.prepare(output, outputLayout);
drawAccessPoint(brick, outputLayout);
}
}
/**
* Draws a certain access point from a given layout with information from
* its associated brick.
*
* @param brick Brick of the current drawn access point.
* @param layout Layout object with descriptive information about access
* point design.
*/
private void drawAccessPoint(Brick brick, Layout layout) {
/*drawShape(layout.getAccessPointShapePath(), layout.getBorderColor(),
layout.getFillColor());*/
drawShapes(layout);
drawTexts(brick, layout, graphics);
}
private static void drawTexts(Brick s, Layout layout, Graphics2D graphics) {
for (LayoutText text : layout.getTextList()) {
graphics.setColor(text.getColor());
graphics.setFont(text.getFont());
graphics.drawString(text.getText(),
s.getBoundingRect().x + text.getRelativePosition().x,
s.getBoundingRect().y + text.getRelativePosition().y);
}
}
}