package org.geogebra.common.gui.dialog.options.model;
import java.util.Arrays;
import java.util.List;
import org.geogebra.common.kernel.Kernel;
import org.geogebra.common.kernel.algos.AlgoBarChart;
import org.geogebra.common.kernel.algos.AlgoTransformation;
import org.geogebra.common.kernel.geos.GProperty;
import org.geogebra.common.kernel.geos.GeoElement;
import org.geogebra.common.kernel.geos.GeoElement.FillType;
import org.geogebra.common.kernel.geos.GeoImage;
import org.geogebra.common.kernel.geos.GeoInputBox;
import org.geogebra.common.main.App;
import org.geogebra.common.main.Localization;
import org.geogebra.common.util.debug.Log;
public class FillingModel extends MultipleOptionsModel {
public interface IFillingListener extends IComboListener {
void setSymbolsVisible(boolean isVisible);
void setFillingImage(String imageFileName);
void setFillInverseVisible(boolean isVisible);
void setFillTypeVisible(boolean isVisible);
void setFillInverseSelected(boolean value);
void setFillValue(int value);
void setAngleValue(int value);
void setDistanceValue(int value);
void setBarChart(AlgoBarChart algo);
void setImageFillType();
void setDottedFillType();
void setSymbolFillType();
void setBrickFillType();
void setCrossHatchedFillType();
void setHatchFillType();
void setStandardFillType();
int getSelectedBarIndex();
void selectSymbol(String barSymbol);
String getSelectedSymbolText();
double getFillingValue();
FillType getSelectedFillType();
int getDistanceValue();
int getAngleValue();
}
private FillType fillType;
private Kernel kernel;
private boolean hasGeoButton;
private boolean hasGeoTurtle;
public FillingModel(App app) {
super(app);
kernel = app.getKernel();
}
public IFillingListener getFillingListener() {
return (IFillingListener) getListener();
}
@Override
public List<String> getChoiches(Localization loc) {
if (app.isExam()) {
return Arrays.asList(loc.getMenu("Filling.Standard"), // index 0
loc.getMenu("Filling.Hatch"), // index 1
loc.getMenu("Filling.Crosshatch"), // index 2
loc.getMenu("Filling.Chessboard"), // index 3
loc.getMenu("Filling.Dotted"), // index 4
loc.getMenu("Filling.Honeycomb"), // index 5
loc.getMenu("Filling.Brick"), // index 6
loc.getMenu("Filling.Weaving"), // index 6
loc.getMenu("Filling.Symbol")// index 7
);
}
return Arrays.asList(loc.getMenu("Filling.Standard"), // index 0
loc.getMenu("Filling.Hatch"), // index 1
loc.getMenu("Filling.Crosshatch"), // index 2
loc.getMenu("Filling.Chessboard"), // index 3
loc.getMenu("Filling.Dotted"), // index 4
loc.getMenu("Filling.Honeycomb"), // index 5
loc.getMenu("Filling.Brick"), // index 6
loc.getMenu("Filling.Weaving"), // index 6
loc.getMenu("Filling.Symbol"), // index 7
loc.getMenu("Filling.Image") // index 8
);
}
public void updateFillType(FillType newFillType) {
switch (newFillType) {
case STANDARD:
getFillingListener().setStandardFillType();
break;
case HATCH:
getFillingListener().setHatchFillType();
break;
case CROSSHATCHED:
case CHESSBOARD:
case WEAVING:
getFillingListener().setCrossHatchedFillType();
break;
case BRICK:
getFillingListener().setBrickFillType();
break;
case SYMBOLS:
getFillingListener().setSymbolFillType();
break;
case HONEYCOMB:
case DOTTED:
getFillingListener().setDottedFillType();
break;
case IMAGE:
getFillingListener().setImageFillType();
break;
}
}
@Override
public void updateProperties() {
GeoElement geo0 = getGeoAt(0);
IFillingListener fillListener = getFillingListener();
// set selected fill type to first geo's fill type
if (isBarChart()) {
setBarFillType(geo0);
} else {
fillListener.setSelectedIndex(geo0.getFillType().ordinal());
}
// set selected fill type to first geo's fill type
fillListener.setFillInverseSelected(geo0.isInverseFill());
AlgoBarChart algo = null;
if (isBarChart()) {
algo = (AlgoBarChart) geo0.getParentAlgorithm();
updateBarFillTypePanel(algo);
} else {
updateFillType(geo0.getFillType());
}
fillListener.setBarChart(algo);
// set value to first geo's alpha value
double alpha = geo0.getAlphaValue();
if (isBarChart()) {
setAlpha(algo, alpha);
} else {
fillListener.setFillValue((int) Math.round(alpha * 100));
}
double angle = geo0.getHatchingAngle();
if (isBarChart()) {
setBarAngle(algo, angle);
} else {
fillListener.setAngleValue((int) angle);
}
int distance = geo0.getHatchingDistance();
if (isBarChart()) {
setBarDistance(algo, distance);
} else {
fillListener.setDistanceValue(distance);
}
if (isBarChart()) {
fillListener.selectSymbol(
algo.getBarSymbol(fillListener.getSelectedBarIndex()));
// setSymbol((AlgoBarChart) geo0.getParentAlgorithm());
} else {
if (geo0.getFillSymbol() != null
&& !geo0.getFillSymbol().trim().equals("")) {
fillListener.selectSymbol(geo0.getFillSymbol());
}
}
// set selected image to first geo image
fillListener.setFillingImage(geo0.getImageFileName());
}
// Methods that set value for single bar if single bar is selected
// and bar has tag for value
private void setAlpha(AlgoBarChart algo, double alpha0) {
double alpha = alpha0;
int idx = getFillingListener().getSelectedBarIndex();
if (idx != 0) {
double barAlpha = algo.getBarAlpha(idx);
if (barAlpha != -1) {
alpha = barAlpha;
}
}
getFillingListener().setFillValue((int) Math.round(alpha * 100));
}
private void updateBarFillTypePanel(AlgoBarChart algo) {
int idx = getFillingListener().getSelectedBarIndex();
FillType type = FillType.STANDARD;
if (algo.getBarFillType(idx) != FillType.STANDARD) {
type = FillType.values()[algo.getBarFillType(idx).ordinal()];
}
fillType = type;
updateFillType(type);
}
private void setBarDistance(AlgoBarChart algo, int distance0) {
int distance = distance0;
int idx = getFillingListener().getSelectedBarIndex();
if (idx != 0) {
if (algo.getBarHatchDistance(idx) != -1) {
distance = algo.getBarHatchDistance(idx);
}
}
getFillingListener().setDistanceValue(distance);
}
private void setBarAngle(AlgoBarChart algo, double angle0) {
double angle = angle0;
int idx = getFillingListener().getSelectedBarIndex();
if (idx != 0) {
if (algo.getBarHatchAngle(idx) != -1) {
angle = algo.getBarHatchAngle(idx);
}
}
getFillingListener().setAngleValue((int) angle);
}
private void setBarFillType(GeoElement geo) {
int idx = getFillingListener().getSelectedBarIndex();
if (idx == 0) {
getFillingListener().setSelectedIndex(geo.getFillType().ordinal());
} else {
AlgoBarChart algo = (AlgoBarChart) geo.getParentAlgorithm();
if (algo != null && algo.getBarFillType(idx) != null) {
getFillingListener()
.setSelectedIndex(algo.getBarFillType(idx).ordinal());
}
}
}
public void applyImage(String fileName) {
if (fileName == null) {
return;
}
for (int i = 0; i < getGeosLength(); i++) {
GeoElement geo = getGeoAt(i);
if (isBarChart()) {
if (!updateBarsFillType(geo, 2, fileName)) {
geo.setImageFileName(fileName);
}
} else {
geo.setImageFileName(fileName);
Log.debug("geo.setImageFileName(" + fileName + ")");
}
geo.setAlphaValue(fileName.isEmpty() ? 0.0f : 1.0f);
geo.updateRepaint();
}
}
public void applyUnicode(String symbolText) {
for (int i = 0; i < getGeosLength(); i++) {
GeoElement geo = getGeoAt(i);
if (!"".equals(symbolText)) {
if (isBarChart()) {
if (!updateBarsFillType(geo, 3, null)) {
geo.setFillType(fillType);
geo.setFillSymbol(symbolText);
}
} else {
geo.setFillType(fillType);
geo.setFillSymbol(symbolText);
}
geo.updateRepaint();
}
}
}
public void applyOpacity(int value) {
for (int i = 0; i < getGeosLength(); i++) {
GeoElement geo = getGeoAt(i);
if (isBarChart()) {
updateBarsFillType(geo, 4, null);
} else {
geo.setAlphaValue(value / 100.0f);
}
geo.updateVisualStyle(GProperty.COLOR);
}
kernel.notifyRepaint();
}
public void applyAngleAndDistance(int angle, int distance) {
for (int i = 0; i < getGeosLength(); i++) {
GeoElement geo = getGeoAt(i);
if (isBarChart()) {
if (!updateBarsFillType(geo, 1, null)) {
geo.setHatchingAngle(angle);
geo.setHatchingDistance(distance);
}
} else {
geo.setHatchingAngle(angle);
geo.setHatchingDistance(distance);
}
geo.updateVisualStyle(GProperty.HATCHING);
}
kernel.notifyRepaint();
}
@Override
protected void apply(int index, int value) {
// TODO Auto-generated method stub
}
@Override
protected int getValueAt(int index) {
// TODO Auto-generated method stub
return 0;
}
@Override
protected boolean isValidAt(int index) {
// TODO Auto-generated method stub
return false;
}
public void applyFillType(int index) {
fillType = getFillTypeAt(index);
GeoElement geo0 = getGeoAt(0);
if (fillType == FillType.IMAGE && geo0.getFillImage() != null) {
getFillingListener().setFillingImage(geo0.getImageFileName());
} else {
getFillingListener().setFillingImage(null);
}
if (fillType == FillType.SYMBOLS) {
getFillingListener().setSymbolsVisible(true);
} else {
getFillingListener().setSymbolsVisible(false);
for (int i = 0; i < getGeosLength(); i++) {
GeoElement geo = getGeoAt(i);
if (isBarChart()) {
if (!updateBarsFillType(geo, 1, null)) {
geo.setFillType(fillType);
}
} else {
geo.setFillType(fillType);
}
geo.updateRepaint();
}
}
storeUndoInfo();
updateFillType(fillType);
}
public void applyFillingInverse(boolean value) {
for (int i = 0; i < getGeosLength(); i++) {
GeoElement geo = getGeoAt(i);
geo.setInverseFill(value);
geo.updateRepaint();
}
storeUndoInfo();
}
public boolean updateBarsFillType(GeoElement geo, int type,
String fileName) {
int selectedBarIndex = getFillingListener().getSelectedBarIndex();
AlgoBarChart algo = (AlgoBarChart) geo.getParentAlgorithm();
if (selectedBarIndex == 0) {
int numBar = algo.getIntervals();
for (int i = 1; i < numBar + 1; i++) {
algo.setBarFillType(null, i);
algo.setBarHatchDistance(-1, i);
algo.setBarHatchAngle(-1, i);
algo.setBarSymbol(null, i);
algo.setBarImage(null, i);
}
return false;
}
switch (type) {
default:
case 1:
algo.setBarFillType(getFillType(), selectedBarIndex);
algo.setBarHatchDistance(getDistanceValue(), selectedBarIndex);
algo.setBarHatchAngle(getAngleValue(), selectedBarIndex);
algo.setBarImage(null, selectedBarIndex);
if (getSelectedFillType() == FillType.SYMBOLS) {
if (getSelectedSymbolText() != null
&& !"".equals(getSelectedSymbolText())) {
algo.setBarHatchAngle(-1, selectedBarIndex);
algo.setBarSymbol(getSelectedSymbolText(),
selectedBarIndex);
} else {
algo.setBarFillType(FillType.STANDARD, selectedBarIndex);
algo.setBarSymbol(null, selectedBarIndex);
}
} else {
algo.setBarSymbol(null, selectedBarIndex);
}
break;
case 4:
algo.setBarAlpha(getFillingValue() / 100f, selectedBarIndex);
break;
case 2:
algo.setBarFillType(null, selectedBarIndex);
algo.setBarHatchDistance(-1, selectedBarIndex);
algo.setBarHatchAngle(-1, selectedBarIndex);
algo.setBarSymbol(null, selectedBarIndex);
algo.setBarImage(fileName, selectedBarIndex);
algo.setBarFillType(FillType.IMAGE, selectedBarIndex);
break;
case 3:
if (getSelectedSymbolText() != null
&& !"".equals(getSelectedSymbolText())) {
algo.setBarFillType(FillType.SYMBOLS, selectedBarIndex);
algo.setBarHatchAngle(-1, selectedBarIndex);
algo.setBarImage(null, selectedBarIndex);
algo.setBarSymbol(getSelectedSymbolText(), selectedBarIndex);
} else {
algo.setBarSymbol(null, selectedBarIndex);
}
break;
}
storeUndoInfo();
return true;
}
private String getSelectedSymbolText() {
return getFillingListener().getSelectedSymbolText();
}
private double getFillingValue() {
return getFillingListener().getFillingValue();
}
private FillType getSelectedFillType() {
return getFillingListener().getSelectedFillType();
}
private int getAngleValue() {
return getFillingListener().getAngleValue();
}
private int getDistanceValue() {
return getFillingListener().getDistanceValue();
}
@Override
public boolean checkGeos() {
boolean geosOK = true;
hasGeoButton = false;
hasGeoTurtle = false;
if (getFillingListener() != null) {
getFillingListener().setFillInverseVisible(true);
getFillingListener().setFillTypeVisible(true);
}
for (int i = 0; i < getGeosLength(); i++) {
GeoElement geo = getGeoAt(i);
hasGeoButton = geo.isGeoButton();
hasGeoTurtle = geo.isGeoTurtle();
if (!geo.isInverseFillable()
// transformed objects copy inverse filling from parents, so
// users can't change this
|| geo.getParentAlgorithm() instanceof AlgoTransformation) {
if (getFillingListener() != null) {
getFillingListener().setFillInverseVisible(false);
}
}
if (!geo.isFillable() || geo instanceof GeoImage
|| geo instanceof GeoInputBox || geo.isGeoQuadric()) {
geosOK = false;
break;
}
// TODO add fill type for 3D elements
if (getFillingListener() != null) {
if (!geo.hasFillType()) {
getFillingListener().setFillTypeVisible(false);
}
}
}
return geosOK;
}
public boolean isBarChart() {
return getGeoAt(0).getParentAlgorithm() instanceof AlgoBarChart;
}
public boolean hasGeoButton() {
// its function must be clarified.
return hasGeoButton;
}
public boolean hasGeoTurtle() {
// its function must be clarified.
return hasGeoTurtle;
}
public FillType getFillType() {
return fillType;
}
public void setFillType(FillType fillType) {
this.fillType = fillType;
}
public FillType getFillTypeAt(int index) {
return FillType.values()[index];
}
}