package org.geogebra.web.web.gui.toolbar; import java.util.ArrayList; import java.util.Vector; import org.geogebra.common.euclidian.EuclidianConstants; import org.geogebra.common.gui.layout.DockPanel; import org.geogebra.common.gui.toolbar.ToolBar; import org.geogebra.common.gui.toolbar.ToolbarItem; import org.geogebra.common.kernel.ModeSetter; import org.geogebra.common.main.App; import org.geogebra.common.main.Feature; import org.geogebra.common.util.debug.Log; import org.geogebra.web.html5.gui.ToolBarInterface; import org.geogebra.web.html5.gui.util.UnorderedList; import org.geogebra.web.html5.main.AppW; import org.geogebra.web.web.gui.app.GGWToolBar; import org.geogebra.web.web.gui.laf.GLookAndFeel; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.event.dom.client.MouseOutEvent; import com.google.gwt.event.dom.client.MouseOutHandler; import com.google.gwt.user.client.ui.FlowPanel; import com.google.gwt.user.client.ui.ScrollPanel; /** * @author gabor * * Toolbar for GeoGebraWeb * */ public class ToolBarW extends FlowPanel implements ClickHandler, ToolBarInterface, MouseOutHandler { private AppW app; private int mode; // panels for mobile submenu view private FlowPanel submenuPanel; private ArrayList<ModeToggleMenuW> modeToggleMenus; protected UnorderedList menuList; private GGWToolBar tb; private boolean isMobileToolbar; private boolean isMouseDown = false; private int mousePosition; private int toolbarPosition; /** * Creates general toolbar. There is no app parameter here, because of * UiBinder. After instantiate the ToolBar, call init(Application app) as * well. */ public ToolBarW(GGWToolBar tb) { this.tb = tb; this.addStyleName("GGWToolbar"); this.addDomHandler(this, ClickEvent.getType()); } /** * Constructor for responsive toolbar * * @param tb * @param submenuPanel */ public ToolBarW(GGWToolBar tb, FlowPanel submenuPanel) { this.tb = tb; this.submenuPanel = submenuPanel; this.addStyleName("GGWToolbar"); this.addDomHandler(this, ClickEvent.getType()); this.addDomHandler(this, MouseOutEvent.getType()); submenuPanel.addDomHandler(this, MouseOutEvent.getType()); } /** * Creates toolbar for a specific dock panel. Call buildGui() to actually * create the GUI of this toolbar. * * @param app * application * @param dockPanel * dock panel */ /* * public ToolBarW(AppW app, DockPanel dockPanel) { this(); this.app = app; * this.dockPanel = dockPanel; * * //setFloatable(false); //setBackground(getBackground()); } */ /** * Initialization of the ToolBar object * * @param app1 * application */ public void init(AppW app1) { this.app = app1; } /** * @return The dock panel associated with this toolbar or null if this is * the general toolbar. */ public DockPanel getDockPanel() { return null; } /** * Creates a toolbar using the current strToolBarDefinition. */ public void buildGui() { mode = -1; menuList = new UnorderedList(); menuList.getElement().addClassName("toolbar_mainItem"); modeToggleMenus = new ArrayList<ModeToggleMenuW>(); addCustomModesToToolbar(menuList); this.clear(); this.add(menuList); setMode(app.getMode(), ModeSetter.TOOLBAR); if (app.has(Feature.TOOLBAR_ON_SMALL_SCREENS)) { this.setVisible(true); tb.onResize(); } // update(); } // TODO: this function is just a temporary hack! Don't regenate the toolbar. public void update() { this.clear(); int count = menuList.getWidgetCount(); menuList.clear(); for (int i = 0; i < count; i++) { menuList.add(modeToggleMenus.get(i)); } this.add(menuList); } protected ArrayList<ModeToggleMenuW> getModeToggleMenus() { return modeToggleMenus; } /** * Sets toolbar mode. This will change the selected toolbar icon. * * @param newMode * see EuclidianConstants for mode numbers * * * @return actual mode number selected (might be different if it's not * available) */ @Override public int setMode(int newMode, ModeSetter m) { boolean success = false; int tmpMode = newMode; // there is no special icon/button for the selection listener mode, use // the // move mode button instead if (tmpMode == EuclidianConstants.MODE_SELECTION_LISTENER) { tmpMode = EuclidianConstants.MODE_MOVE; } if (modeToggleMenus != null) { for (int i = 0; i < modeToggleMenus.size(); i++) { ModeToggleMenuW mtm = modeToggleMenus.get(i); if (mtm.selectMode(tmpMode, m)) { success = true; break; } } if (!success && tmpMode !=getFirstMode()) { tmpMode = setMode(getFirstMode(), m); } this.mode = tmpMode; app.getKernel().notifyModeChanged(mode, ModeSetter.DOCK_PANEL); } return tmpMode; } /** * @return currently selected mode */ public int getSelectedMode() { return mode; } /** * @return first mode in this toolbar */ public int getFirstMode() { if (modeToggleMenus == null || modeToggleMenus.size() == 0) { return -1; } ModeToggleMenuW mtm = modeToggleMenus.get(0); return mtm.getFirstMode(); } public UnorderedList getMenuList() { return menuList; } private Integer activeView = App.VIEW_EUCLIDIAN; private int maxButtons = 200; /** * Adds the given modes to a two-dimensional toolbar. The toolbar definition * string looks like "0 , 1 2 | 3 4 5 || 7 8 9" where the int values are * mode numbers, "," adds a separator within a menu, "|" starts a new menu * and "||" adds a separator before starting a new menu. * */ private void addCustomModesToToolbar(UnorderedList mainUl) { if(app.has(Feature.TOOLBAR_ON_SMALL_SCREENS)){ Vector<ToolbarItem> toolbarVec = getToolbarVec(); // set toolbar for (int i = 0; i < toolbarVec.size(); i++) { ToolbarItem ob = toolbarVec.get(i); Vector<Integer> menu = ob.getMenu(); if (app.isModeValid(menu.get(0).intValue())) { ModeToggleMenuW mtm = createModeToggleMenu(app, menu, i); mtm.setButtonTabIndex(-1); modeToggleMenus.add(mtm); mainUl.add(mtm); } } if (modeToggleMenus.size() > 0) { modeToggleMenus.get(0).setButtonTabIndex(0); // end of Feature.TOOLBAR_ON_SMALL_SCREENS } } else { Vector<ToolbarItem> toolbarVec = getToolbarVec(); // set toolbar for (int i = 0; i < toolbarVec.size() && i < this.maxButtons; i++) { ToolbarItem ob = toolbarVec.get(i); Vector<Integer> menu = ob.getMenu(); if (app.isModeValid(menu.get(0).intValue())) { ModeToggleMenuW mtm = createModeToggleMenu(app, menu, i); mtm.setButtonTabIndex(-1); modeToggleMenus.add(mtm); mainUl.add(mtm); } } for (int i = this.maxButtons; i < toolbarVec.size(); i++) { ToolbarItem ob = toolbarVec.get(i); Vector<Integer> menu = ob.getMenu(); modeToggleMenus.get(modeToggleMenus.size() - 1).addModes(menu); } if (modeToggleMenus.size() > 0) { modeToggleMenus.get(0).setButtonTabIndex(0); } } } protected ModeToggleMenuW createModeToggleMenu(AppW app, Vector<Integer> menu, int order) { if (app.has(Feature.TOOLBAR_ON_SMALL_SCREENS)) { // toolbarVecSize is i.e. 12 for AV, 14 for 3D if (maxButtons < getToolbarVecSize() || (maxButtons < 11 && getToolbarVecSize() < 11)) { isMobileToolbar = true; return new ModeToggleMenuP(app, menu, this, order, submenuPanel); } isMobileToolbar = false; return new ModeToggleMenuW(app, menu, this, order); } return new ModeToggleMenuW(app, menu, this, order); } protected Vector<ToolbarItem> getToolbarVec() { Vector<ToolbarItem> toolbarVec; try { toolbarVec = ToolBar.parseToolbarString( app.getGuiManager().getToolbarDefinition()); } catch (Exception e) { Log.debug("invalid toolbar string: " + app.getGuiManager().getToolbarDefinition()); toolbarVec = ToolBar.parseToolbarString(getDefaultToolbarString()); } return toolbarVec; } public int getToolbarVecSize() { return this.getToolbarVec().size(); } /** * @return The default definition of this toolbar with macros. */ public String getDefaultToolbarString() { return ToolBar.getAllTools(app); } public void setActiveView(Integer viewID) { activeView = viewID; } public int getActiveView() { return activeView; } public boolean hasPopupOpen() { for (int i = 0; i < this.modeToggleMenus.size(); i++) { if (this.modeToggleMenus.get(i).isMenuShown()) { return true; } } return false; } @Override public void closeAllSubmenu() { for (int i = 0; i < modeToggleMenus.size(); i++) { modeToggleMenus.get(i).hideMenu(); } if (app.has(Feature.TOOLBAR_ON_SMALL_SCREENS)) { if (submenuPanel != null) { submenuPanel.clear(); } } } /** * * @return true if any of the submenus are opened */ public boolean isAnyOtherSubmenuOpen(ModeToggleMenuW exceptMenu) { for (int i = 0; i < modeToggleMenus.size(); i++) { ModeToggleMenuW menu = modeToggleMenus.get(i); if (exceptMenu != menu && menu.isMenuShown()) { return true; } } return false; } @Override public void onClick(ClickEvent event) { // TODO: maybe use CancelEvents.instance? event.stopPropagation(); } public void selectMenuButton(int index) { tb.selectMenuButton(index); } public void selectMenu(int index) { tb.deselectButtons(); int positiveIndex = index; if (index < 0) { positiveIndex = index + getModeToggleMenus().size(); } ModeToggleMenuW mtm2 = getModeToggleMenus().get(positiveIndex); mtm2.getToolbarButtonPanel().getElement().focus(); } public int getGroupCount() { if(this.modeToggleMenus == null){ return -1; } return this.modeToggleMenus.size(); } public void setMaxButtons(int max) { for(ModeToggleMenuW m: this.modeToggleMenus){ m.setMaxHeight(app.getHeight() - GLookAndFeel.TOOLBAR_OFFSET); } if (app.has(Feature.TOOLBAR_ON_SMALL_SCREENS)) { if (getToolbarVecSize() < 11) { if ((isMobileToolbar && max >= 11) || !isMobileToolbar && max < 11) { this.maxButtons = max; closeAllSubmenu(); buildGui(); } } // make sure gui is only rebuilt when necessary (when state changes // between web view and mobile view) else if ((isMobileToolbar && max >= getToolbarVecSize()) || (!isMobileToolbar && max < getToolbarVecSize())) { this.maxButtons = max; closeAllSubmenu(); buildGui(); } else { if (Math.min(max, this.getToolbarVec().size()) == this.getGroupCount()) { return; } } } else { if (Math.min(max, this.getToolbarVec().size()) == this.getGroupCount()) { return; } this.maxButtons = max; buildGui(); } } @Override public String getImageURL(int mode) { return GGWToolBar.getImageURL(mode, app); } @Override public boolean isMobileToolbar() { return isMobileToolbar; } public int getMaxButtons() { return maxButtons; } public GGWToolBar getGGWToolBar() { return tb; } public void setPosition(int positionX) { if (isMouseDown) { if (this.isVisible()) { ((ScrollPanel) this.getParent()) .setHorizontalScrollPosition(toolbarPosition + (mousePosition - positionX)); } else { ((ScrollPanel) submenuPanel.getParent()) .setHorizontalScrollPosition(toolbarPosition + (mousePosition - positionX)); } } } @Override public void onMouseOut(MouseOutEvent event) { setMouseDown(false); } public void setMouseDown(boolean down) { isMouseDown = down; } public void setStartPositions(int mouse, int tb) { mousePosition = mouse; toolbarPosition = tb; } }