package org.geogebra.web.web.gui.dialog.options; import java.util.ArrayList; import org.geogebra.common.euclidian.event.KeyEvent; import org.geogebra.common.euclidian.event.KeyHandler; //import org.geogebra.common.euclidian.event.KeyHandler; import org.geogebra.common.gui.dialog.options.model.FillingModel; import org.geogebra.common.gui.dialog.options.model.FillingModel.IFillingListener; import org.geogebra.common.gui.util.SelectionTable; import org.geogebra.common.kernel.Construction; import org.geogebra.common.kernel.algos.AlgoBarChart; import org.geogebra.common.kernel.geos.GeoElement.FillType; import org.geogebra.common.kernel.geos.GeoImage; import org.geogebra.common.kernel.geos.GeoPoint; import org.geogebra.common.main.Localization; import org.geogebra.common.util.MD5EncrypterGWTImpl; import org.geogebra.common.util.Util; import org.geogebra.common.util.debug.Log; import org.geogebra.common.util.lang.Unicode; import org.geogebra.web.html5.css.GuiResourcesSimple; import org.geogebra.web.html5.event.FocusListenerW; import org.geogebra.web.html5.gui.inputfield.AutoCompleteTextFieldW; import org.geogebra.web.html5.gui.util.SliderPanel; import org.geogebra.web.html5.main.AppW; import org.geogebra.web.web.gui.dialog.FileInputDialog; import org.geogebra.web.web.gui.images.AppResources; import org.geogebra.web.web.gui.properties.OptionPanel; import org.geogebra.web.web.gui.util.BarList; import org.geogebra.web.web.gui.util.GeoGebraIconW; import org.geogebra.web.web.gui.util.ImageOrText; import org.geogebra.web.web.gui.util.PopupMenuButtonW; import org.geogebra.web.web.gui.view.algebra.InputPanelW; import com.google.gwt.core.client.JavaScriptObject; import com.google.gwt.dom.client.Element; import com.google.gwt.event.dom.client.ChangeEvent; import com.google.gwt.event.dom.client.ChangeHandler; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.resources.client.ImageResource; import com.google.gwt.user.client.ui.Button; import com.google.gwt.user.client.ui.CheckBox; import com.google.gwt.user.client.ui.FlowPanel; import com.google.gwt.user.client.ui.Image; import com.google.gwt.user.client.ui.Label; import com.google.gwt.user.client.ui.ListBox; import com.google.gwt.user.client.ui.PushButton; public class FillingPanel extends OptionPanel implements IFillingListener { FillingModel model; SliderPanel opacitySlider; SliderPanel angleSlider; SliderPanel distanceSlider; private Label fillingSliderTitle; private Label angleSliderTitle; private Label distanceSliderTitle; private FlowPanel opacityPanel, hatchFillPanel, imagePanel, anglePanel; private Label lblSelectedSymbol; private Label lblMsgSelected; private Button btnOpenFile; private PopupMenuButtonW btnImage; // button for removing turtle's image private PushButton btnClearImage; private Label lblSymbols; ArrayList<ImageResource> iconList; private ArrayList<String> iconNameList; // private PopupMenuButton btInsertUnicode; ListBox lbFillType; CheckBox cbFillInverse; private FlowPanel fillTypePanel; private Label fillTypeTitle; private FlowPanel btnPanel; AutoCompleteTextFieldW tfInsertUnicode; private InputPanelW unicodePanel; private AppW app; private BarList lbBars; private class MyImageFileInputDialog extends FileInputDialog { public MyImageFileInputDialog(AppW app, GeoPoint location) { super(app, location); createGUI(); } @Override protected void createGUI() { super.createGUI(); addGgbChangeHandler(getInputWidget().getElement()); } public native void addGgbChangeHandler(Element el) /*-{ var dialog = this; el.setAttribute("accept", "image/*"); el.onchange = function(event) { var files = this.files; if (files.length) { var fileTypes = /^image.*$/; for (var i = 0, j = files.length; i < j; ++i) { if (!files[i].type.match(fileTypes)) { continue; } var fileToHandle = files[i]; dialog.@org.geogebra.web.web.gui.dialog.options.FillingPanel.MyImageFileInputDialog::openFileAsImage(Lcom/google/gwt/core/client/JavaScriptObject;Lcom/google/gwt/core/client/JavaScriptObject;)(fileToHandle, dialog.@org.geogebra.web.web.gui.dialog.FileInputDialog::getNativeHideAndFocus()()); break; } } }; }-*/; @Override public void onClick(ClickEvent event) { if (event.getSource() == btCancel) { hideAndFocus(); } } public native boolean openFileAsImage(JavaScriptObject fileToHandle, JavaScriptObject callback) /*-{ var imageRegEx = /\.(png|jpg|jpeg|gif|bmp|svg)$/i; if (!fileToHandle.name.toLowerCase().match(imageRegEx)) return false; var appl = this; var reader = new FileReader(); reader.onloadend = function(ev) { if (reader.readyState === reader.DONE) { var fileData = reader.result; var fileName = fileToHandle.name; appl.@org.geogebra.web.web.gui.dialog.options.FillingPanel.MyImageFileInputDialog::applyImage(Ljava/lang/String;Ljava/lang/String;)(fileName, fileData); if (callback != null) { callback(); } } }; reader.readAsDataURL(fileToHandle); return true; }-*/; public void applyImage(String fileName, String fileData) { MD5EncrypterGWTImpl md5e = new MD5EncrypterGWTImpl(); String zip_directory = md5e.encrypt(fileData); String fn = fileName; int index = fn.lastIndexOf('/'); if (index != -1) { fn = fn.substring(index + 1, fn.length()); // filename without } // path fn = Util.processFilename(fn); // filename will be of form // "a04c62e6a065b47476607ac815d022cc\liar.gif" fn = zip_directory + '/' + fn; Construction cons = app.getKernel().getConstruction(); app.getImageManager().addExternalImage(fn, fileData); GeoImage geoImage = new GeoImage(cons); app.getImageManager().triggerSingleImageLoading(fn, geoImage); model.applyImage(fn); Log.debug("Applying " + fn + " from dialog"); } } public FillingPanel(FillingModel model0, AppW app) { this.app = app; model = model0; model.setListener(this); setModel(model); FlowPanel mainWidget = new FlowPanel(); fillTypePanel = new FlowPanel(); fillTypePanel.setStyleName("optionsPanel"); fillTypeTitle = new Label(); lbFillType = new ListBox(); fillTypePanel.add(fillTypeTitle); fillTypePanel.add(lbFillType); cbFillInverse = new CheckBox(); fillTypePanel.add(cbFillInverse); lbFillType.addChangeHandler(new ChangeHandler() { @Override public void onChange(ChangeEvent event) { model.applyFillType(lbFillType.getSelectedIndex()); } }); cbFillInverse.addClickHandler(new ClickHandler() { @Override public void onClick(ClickEvent event) { model.applyFillingInverse(cbFillInverse.getValue()); } }); FlowPanel panel = new FlowPanel(); panel.add(fillTypePanel); unicodePanel = new InputPanelW(null, app, 1, -1, true); // buildInsertUnicodeButton(); unicodePanel.setVisible(false); tfInsertUnicode = unicodePanel.getTextComponent(); tfInsertUnicode.setAutoComplete(false); tfInsertUnicode.addStyleName("fillSymbol"); lblMsgSelected = new Label(app.getLocalization().getMenu( "Filling.CurrentSymbol") + ":"); lblMsgSelected.setVisible(false); lblSymbols = new Label( app.getLocalization().getMenu("Filling.Symbol") + ":"); lblSymbols.setVisible(false); lblSelectedSymbol = new Label(); opacitySlider = new SliderPanel(0, 100); opacitySlider.setMajorTickSpacing(25); opacitySlider.setMinorTickSpacing(5); opacitySlider.setPaintTicks(true); opacitySlider.setPaintLabels(true); angleSlider = new SliderPanel(0, 180); angleSlider.setMajorTickSpacing(45); angleSlider.setMinorTickSpacing(5); angleSlider.setPaintTicks(true); angleSlider.setPaintLabels(true); distanceSlider = new SliderPanel(5, 50); // distanceSlider.setPreferredSize(new Dimension(150,50)); distanceSlider.setMajorTickSpacing(10); distanceSlider.setMinorTickSpacing(5); distanceSlider.setPaintTicks(true); distanceSlider.setPaintLabels(true); FlowPanel symbol1Panel = new FlowPanel(); symbol1Panel.setStyleName("optionsPanelCell"); symbol1Panel.add(lblSymbols); symbol1Panel.add(tfInsertUnicode); FlowPanel symbol2Panel = new FlowPanel(); symbol2Panel.setStyleName("optionsPanelCell"); symbol2Panel.add(lblMsgSelected); symbol2Panel.add(lblSelectedSymbol); FlowPanel symbolPanel = new FlowPanel(); symbolPanel.setStyleName("optionsPanelIndent"); symbolPanel.add(symbol1Panel); symbolPanel.add(symbol2Panel); lblSelectedSymbol.setVisible(false); panel.add(symbolPanel); // panels to hold sliders opacityPanel = new FlowPanel(); opacityPanel.setStyleName("optionsPanelIndent"); fillingSliderTitle = new Label(); opacityPanel.add(fillingSliderTitle); opacityPanel.add(opacitySlider); anglePanel = new FlowPanel(); anglePanel.setStyleName("optionsPanelIndent"); angleSliderTitle = new Label(); anglePanel.add(angleSliderTitle); anglePanel.add(angleSlider); distanceSliderTitle = new Label(); FlowPanel distancePanel = new FlowPanel(); distancePanel.setStyleName("optionsPanelIndent"); distancePanel.add(distanceSliderTitle); distancePanel.add(distanceSlider); // hatchfill panel: only shown when hatch fill option is selected hatchFillPanel = new FlowPanel(); hatchFillPanel.add(anglePanel); hatchFillPanel.add(distancePanel); hatchFillPanel.setVisible(false); // image panel: only shown when image fill option is selected createImagePanel(); imagePanel.setVisible(false); // =========================================================== // put all the sub panels together mainWidget.add(panel); mainWidget.add(opacityPanel); mainWidget.add(hatchFillPanel); mainWidget.add(imagePanel); mainWidget.add(symbolPanel); lbBars = new BarList(app); lbBars.setVisible(false); fillTypePanel.add(lbBars); lbBars.addChangeHandler(new ChangeHandler() { @Override public void onChange(ChangeEvent event) { model.updateProperties(); } }); setWidget(mainWidget); opacitySlider.addChangeHandler(new ChangeHandler() { @Override public void onChange(ChangeEvent event) { model.applyOpacity(opacitySlider.getValue()); } }); ChangeHandler angleAndDistanceHandler = new ChangeHandler() { @Override public void onChange(ChangeEvent event) { model.applyAngleAndDistance(angleSlider.getValue(), distanceSlider.getValue()); } }; angleSlider.addChangeHandler(angleAndDistanceHandler); distanceSlider.addChangeHandler(angleAndDistanceHandler); tfInsertUnicode.addFocusListener(new FocusListenerW(this) { @Override protected void wrapFocusLost() { String symbolText = tfInsertUnicode.getText(); if (symbolText.isEmpty()) { return; } selectSymbol(symbolText); model.applyUnicode(symbolText); } }); tfInsertUnicode.addKeyHandler(new KeyHandler() { @Override public void keyReleased(KeyEvent e) { if (e.isEnterKey()) { String symbolText = tfInsertUnicode.getText(); selectSymbol(symbolText); model.applyUnicode(symbolText); } } }); setLabels(); } protected String getImageFileName(String fileName, String fileData) { MD5EncrypterGWTImpl md5e = new MD5EncrypterGWTImpl(); String zip_directory = md5e.encrypt(fileData); String fn = fileName; int index = fileName.lastIndexOf('/'); if (index != -1) { fn = fn.substring(index + 1, fn.length()); // filename without } fn = Util.processFilename(fn); // filename will be of form // "a04c62e6a065b47476607ac815d022cc\liar.gif" return zip_directory + '/' + fn; } public void applyImage(String fileName0, String fileData) { String fileName = getImageFileName(fileName0, fileData); Construction cons = app.getKernel().getConstruction(); app.getImageManager().addExternalImage(fileName, fileData); GeoImage geoImage = new GeoImage(cons); app.getImageManager().triggerSingleImageLoading(fileName, geoImage); model.applyImage(fileName); } private void createImagePanel() { imagePanel = new FlowPanel(); btnPanel = new FlowPanel(); iconList = new ArrayList<ImageResource>(); iconList.add(null); // for delete GuiResourcesSimple res = GuiResourcesSimple.INSTANCE; iconList.add(res.icons_fillings_arrow_big_down()); iconList.add(res.icons_fillings_arrow_big_up()); iconList.add(res.icons_fillings_arrow_big_left()); iconList.add(res.icons_fillings_arrow_big_right()); iconList.add(res.icons_fillings_fastforward()); iconList.add(res.icons_fillings_rewind()); iconList.add(res.icons_fillings_skipback()); iconList.add(res.icons_fillings_skipforward()); iconList.add(res.icons_fillings_play()); iconList.add(res.icons_fillings_pause()); iconList.add(res.icons_fillings_cancel()); iconNameList = new ArrayList<String>(); for (ImageResource ir : iconList) { iconNameList.add(ir != null ? ir.getName() : ""); } final ImageOrText[] iconArray = new ImageOrText[iconList.size()]; iconArray[0] = GeoGebraIconW.createNullSymbolIcon(); for (int i = 1; i < iconArray.length; i++) { iconArray[i] = new ImageOrText(iconList.get(i)); } // // ============================================ // // // panel for button to open external file // btnImage = new PopupMenuButtonW(app, iconArray, -1, 4, SelectionTable.MODE_ICON) { @Override public void handlePopupActionEvent() { super.handlePopupActionEvent(); ImageResource resource = null; int idx = getSelectedIndex(); resource = iconList.get(idx); if (resource != null) { applyImage(resource.getName(), resource.getSafeUri() .asString()); Log.debug("Applying " + resource.getName() + " at index " + idx); } else { model.applyImage(""); } } }; btnImage.setSelectedIndex(-1); btnImage.setKeepVisible(false); btnClearImage = new PushButton(new Image( AppResources.INSTANCE.delete_small())); btnClearImage.addClickHandler(new ClickHandler() { @Override public void onClick(ClickEvent event) { model.applyImage(""); } }); btnOpenFile = new Button(); btnOpenFile.addClickHandler(new ClickHandler() { @Override public void onClick(ClickEvent event) { new MyImageFileInputDialog(app, null); } }); btnPanel.add(btnImage); btnPanel.add(btnClearImage); btnPanel.add(btnOpenFile); btnPanel.setStyleName("optionsPanelIndent"); imagePanel.add(btnPanel); } @Override public void setStandardFillType() { fillTypePanel.setVisible(true); opacityPanel.setVisible(false); hatchFillPanel.setVisible(false); imagePanel.setVisible(false); setSymbolsVisible(false); } @Override public void setHatchFillType() { fillTypePanel.setVisible(true); distanceSlider.setMinimum(5); opacityPanel.setVisible(false); hatchFillPanel.setVisible(true); imagePanel.setVisible(false); anglePanel.setVisible(true); angleSlider.setMaximum(180); angleSlider.setMinorTickSpacing(5); setSymbolsVisible(false); } @Override public void setCrossHatchedFillType() { fillTypePanel.setVisible(true); distanceSlider.setMinimum(5); opacityPanel.setVisible(false); hatchFillPanel.setVisible(true); imagePanel.setVisible(false); anglePanel.setVisible(true); // Only at 0, 45 and 90 degrees texturepaint not have mismatches angleSlider.setMaximum(45); angleSlider.setMinorTickSpacing(45); setSymbolsVisible(false); } @Override public void setBrickFillType() { fillTypePanel.setVisible(true); distanceSlider.setMinimum(5); opacityPanel.setVisible(false); hatchFillPanel.setVisible(true); imagePanel.setVisible(false); anglePanel.setVisible(true); angleSlider.setMaximum(180); angleSlider.setMinorTickSpacing(45); setSymbolsVisible(false); } @Override public void setSymbolFillType() { fillTypePanel.setVisible(true); distanceSlider.setMinimum(10); opacityPanel.setVisible(false); hatchFillPanel.setVisible(true); imagePanel.setVisible(false); // for dotted angle is useless anglePanel.setVisible(false); setSymbolsVisible(true); } @Override public void setDottedFillType() { distanceSlider.setMinimum(5); opacityPanel.setVisible(false); hatchFillPanel.setVisible(true); imagePanel.setVisible(false); // for dotted angle is useless anglePanel.setVisible(false); setSymbolsVisible(false); } @Override public void setImageFillType() { fillTypePanel.setVisible(true); opacityPanel.setVisible(true); hatchFillPanel.setVisible(false); imagePanel.setVisible(true); this.btnImage.setVisible(true); this.btnClearImage.setVisible(true); // for GeoButtons only show the image file button if (model.hasGeoButton() || model.hasGeoTurtle()) { fillTypePanel.setVisible(false); opacityPanel.setVisible(false); if (model.hasGeoTurtle()) { this.btnImage.setVisible(false); this.btnClearImage.setVisible(true); } } setSymbolsVisible(false); } @Override public void setSelectedIndex(int index) { lbFillType.setSelectedIndex(index); } @Override public void addItem(String item) { lbFillType.addItem(item); } public void updateFillTypePanel(FillType fillType) { // TODO Auto-generated method stub } @Override public void setFillInverseVisible(boolean isVisible) { cbFillInverse.setVisible(isVisible); } @Override public void setFillTypeVisible(boolean isVisible) { lbFillType.setVisible(isVisible); } @Override public void setLabels() { Localization loc = app.getLocalization(); fillTypeTitle.setText(loc.getMenu("Filling") + ":"); cbFillInverse.setText(loc.getPlain("InverseFilling")); int idx = lbFillType.getSelectedIndex(); lbFillType.clear(); model.fillModes(loc); lbFillType.setSelectedIndex(idx); fillingSliderTitle.setText(loc.getMenu("Opacity")); angleSliderTitle.setText(loc.getMenu("Angle")); distanceSliderTitle.setText(loc.getMenu("Spacing")); btnOpenFile.setText(loc.getMenu("ChooseFromFile") + Unicode.ellipsis); } @Override public void setSelectedItem(String item) { int idx = 0; lbFillType.setSelectedIndex(idx); } @Override public void setSymbolsVisible(boolean isVisible) { if (isVisible) { unicodePanel.setVisible(true); lblSymbols.setVisible(true); lblSelectedSymbol.setVisible(true); lblMsgSelected.setVisible(true); } else { lblSymbols.setVisible(false); unicodePanel.setVisible(false); lblMsgSelected.setVisible(false); lblSelectedSymbol.setVisible(false); lblSelectedSymbol.setText(""); } } @Override public void setFillingImage(String imageFileName) { int itemIndex = -1; if (imageFileName != null) { String fileName = imageFileName.substring(imageFileName .indexOf('/') + 1); Log.debug("Filling with " + fileName); int idx = iconNameList.lastIndexOf(fileName); itemIndex = idx > 0 ? idx : 0; } btnImage.setSelectedIndex(itemIndex); } @Override public void setFillValue(int value) { opacitySlider.setValue(value); } @Override public void setAngleValue(int value) { angleSlider.setValue(value); } @Override public void setDistanceValue(int value) { distanceSlider.setValue(value); } @Override public int getSelectedBarIndex() { return lbBars.getSelectedIndex(); } @Override public void selectSymbol(String symbol) { lblSelectedSymbol.setText(symbol); } @Override public String getSelectedSymbolText() { return lblSelectedSymbol.getText(); } @Override public double getFillingValue() { return opacitySlider.getValue(); } @Override public FillType getSelectedFillType() { return model.getFillTypeAt(lbFillType.getSelectedIndex()); } @Override public int getDistanceValue() { return distanceSlider.getValue(); } @Override public int getAngleValue() { return angleSlider.getValue(); } @Override public void setFillInverseSelected(boolean value) { cbFillInverse.setValue(value); } @Override public void clearItems() { // TODO Auto-generated method stub } @Override public void setBarChart(AlgoBarChart algo) { if (algo != null) { lbBars.setBarCount(algo.getIntervals()); } lbBars.update(algo != null); } }