/******************************************************************************* * Copyright (c) Emil Crumhorn - Hexapixel.com - emil.crumhorn@gmail.com * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * emil.crumhorn@gmail.com - initial API and implementation *******************************************************************************/ package com.hexapixel.widgets.ribbon; import java.util.ArrayList; import java.util.List; import org.eclipse.swt.SWT; import org.eclipse.swt.events.ControlEvent; import org.eclipse.swt.events.ControlListener; import org.eclipse.swt.events.KeyEvent; import org.eclipse.swt.events.KeyListener; import org.eclipse.swt.events.MouseEvent; import org.eclipse.swt.events.MouseListener; import org.eclipse.swt.events.MouseMoveListener; import org.eclipse.swt.events.MouseTrackListener; import org.eclipse.swt.events.MouseWheelListener; import org.eclipse.swt.events.PaintEvent; import org.eclipse.swt.events.PaintListener; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.GC; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Layout; import com.hexapixel.widgets.generic.ColorCache; public class RibbonTabFolder extends Composite implements MouseListener, MouseMoveListener { private List<RibbonTab> mTabs; public static int FIRST_TAB_SPACING = 46; public static int TAB_SPACING = 1; public static int TEXT_SPACING_SIDE = 9; public static int TEXT_SPACING_TOP = 6; public static int TAB_HEIGHT = 23; public static int TAB_AREA_HEIGHT = 25; public static int NON_MAXIMIZED_HEIGHT = 29; public static int MAXIMIZED_HEIGHT = 25; private static int MAX_HEIGHT = 118; private Color mTopLine = ColorCache.getInstance().getColor(176, 207, 247); private Color mTopLineInner = ColorCache.getInstance().getColor(219, 232, 249); private Color mFillTop = ColorCache.getInstance().getColor(191, 219, 255); private Color mFillBottom = ColorCache.getInstance().getColor(165, 195, 239); private static AbstractTabPainter mTabPainter = new DefaultTabPainter(); private static AbstractShellPainter mShellPainter = new DefaultShellPainter(); private static AbstractButtonPaintManager mButtonPainter = new DefaultButtonPaintManager(); private RibbonTab mHoverTab; private RibbonTab mSelectedTab; private boolean mCollapsedTabFolder; private boolean drawEmptyTabs = true; // when we act as shell we need loads of params private boolean drawAsShell = false; private RibbonShell mRibbonShell; public static final int STATE_NONE = 0; public static final int STATE_HOVER = 1; public static final int STATE_HOVER_SELECTED = 2; public static final int STATE_INACTIVE = 3; private Rectangle minButtonRect; private Rectangle maxButtonRect; private Rectangle closeButtonRect; private Rectangle allButtonsRect; private Rectangle bigButtonRect; private Rectangle menuBarRect; private Rectangle fullMenuBarRect; private int minButtonState; private int maxButtonState; private int closeButtonState; private int bigButtonState; private boolean mMouseIsDown; private boolean mMouseWasDownOnMenubar; private Image mHelpImage; private RibbonButton mHelpButton; private Rectangle mQuickAccessBounds; // end shell params public RibbonTabFolder(Composite parent, int style) { this(parent, style, null); } public RibbonTabFolder(Composite parent, int style, RibbonShell shell) { super(parent, style | SWT.DOUBLE_BUFFERED); drawAsShell = (shell != null); mRibbonShell = shell; mTabs = new ArrayList<RibbonTab>(); setLayout(new TabFolderLayout()); if (isShell()) updateMenuBarButtonCalculations(); addKeyListener(new KeyListener() { public void keyPressed(KeyEvent e) { RibbonTooltipDialog.kill(); } public void keyReleased(KeyEvent e) { } }); addControlListener(new ControlListener() { public void controlMoved(ControlEvent e) { RibbonTooltipDialog.kill(); } public void controlResized(ControlEvent e) { RibbonTooltipDialog.kill(); if (isShell()) updateMenuBarButtonCalculations(); } }); addPaintListener(new PaintListener() { public void paintControl(PaintEvent event) { GC gc = event.gc; drawTabFolder(gc, 0); } }); addMouseTrackListener(new MouseTrackListener() { public void mouseEnter(MouseEvent e) { } public void mouseExit(MouseEvent e) { if (mHoverTab != null) { Rectangle oldBounds = mHoverTab.getBounds(); redraw(oldBounds.x-10, 0, oldBounds.width+20, TAB_HEIGHT+4, false); mHoverTab.setHover(false); } if (drawAsShell) { minButtonState = STATE_NONE; maxButtonState = STATE_NONE; closeButtonState = STATE_NONE; redrawMenuBarButton(); } if (mHelpButton != null) { if (mHelpButton.isHoverButton()) { mHelpButton.setHoverButton(false); redraw(mHelpButton.getBounds()); } } } public void mouseHover(MouseEvent me) { if (mHelpButton != null) { if (isInside(me.x, me.y, mHelpButton.getBounds())) { if (mHelpButton.getToolTip() != null) { int y = mHelpButton.getBounds().y + mHelpButton.getBounds().height + 10; RibbonTooltipDialog.makeDialog(mHelpButton.getToolTip(), toDisplay((new Point(mHelpButton.getBounds().x, y)))); } } } if (isShell()) { if (isInside(me.x, me.y, bigButtonRect)) { if (mRibbonShell.getBigButtonTooltip() != null) { RibbonTooltipDialog.makeDialog(mRibbonShell.getBigButtonTooltip(), toDisplay((new Point(bigButtonRect.x, bigButtonRect.y+bigButtonRect.height)))); } } if (isInside(me.x, me.y, mRibbonShell.getArrowButtonBounds())) { Rectangle arrBounds = mRibbonShell.getArrowButtonBounds(); if (mRibbonShell.getToolbar() != null && mRibbonShell.getToolbar().getArrowTooltip() != null) { RibbonTooltipDialog.makeDialog(mRibbonShell.getToolbar().getArrowTooltip(), toDisplay((new Point(arrBounds.x, arrBounds.y+arrBounds.height)))); } } } } }); addMouseMoveListener(this); addMouseListener(this); addMouseWheelListener(new MouseWheelListener() { public void mouseScrolled(MouseEvent me) { RibbonTooltipDialog.kill(); // if we're not inside the bounds, ignore if (getBounds() == null || !isInside(me.x, me.y, getBounds())) return; if (me.count > 0) selectPrevTab(); else selectNextTab(); } }); } public void mouseDoubleClick(MouseEvent me) { for (int i = 0; i < mTabs.size(); i++) { RibbonTab ft = mTabs.get(i); if (ft.getBounds() == null) continue; if (isInside(me.x, me.y, ft.getBounds())) { if (mCollapsedTabFolder) expandTabFolder(); else collapseTabFolder(); } } mMouseIsDown = false; // TODO: Windows only? if (isShell() && me.button == 1) { if (!isInside(me.x, me.y, bigButtonRect) && !isInside(me.x, me.y, mQuickAccessBounds) && isInside(me.x, me.y, menuBarRect)) mRibbonShell.setMaximized(!mRibbonShell.getMaximized()); } // check buttons in toolbar if any if (drawAsShell) updateButtonStates(me.x, me.y); } void setQuickAccessBounds(Rectangle bounds) { mQuickAccessBounds = bounds; } public void mouseDown(MouseEvent me) { RibbonTooltipDialog.kill(); mMouseIsDown = true; mMouseWasDownOnMenubar = false; if (drawAsShell && isInside(me.x, me.y, fullMenuBarRect) && !isInside(me.x, me.y, allButtonsRect)) { // if we allow this boolean to be true for the full area of the menu bar you could move the entire window even // when a window-border resize cursor is showing, which would be plain weird if (isInside(me.x, me.y, menuBarRect) && !isInside(me.x, me.y, bigButtonRect)) mMouseWasDownOnMenubar = true; } // regardless, tell our top shell that the mouse was clicked or we can't resize the shell in areas that are occupied by us if (drawAsShell) mRibbonShell.mouseDown(me); if (me.button != 1) return; for (int i = 0; i < mTabs.size(); i++) { RibbonTab ft = mTabs.get(i); if (ft.getBounds() == null) continue; if (isInside(me.x, me.y, ft.getBounds())) { // don't re-click already selected tab if (mSelectedTab == ft) continue; selectTab(ft); } } if (drawAsShell) { if (isInside(me.x, me.y, allButtonsRect) || isInside(me.x, me.y, bigButtonRect)) updateButtonStates(me.x, me.y); } if (mHelpButton != null) { if (isInside(me.x, me.y, mHelpButton.getBounds())) { if (mHelpButton.isSelected()) { mHelpButton.setSelected(false); redraw(mHelpButton.getBounds()); } else { mHelpButton.setSelected(true); redraw(mHelpButton.getBounds()); } } } if (drawAsShell) { if (isInside(me.x, me.y, bigButtonRect)) { bigButtonClicked(me); } } } private void bigButtonClicked(MouseEvent me) { mRibbonShell.bigButtonClicked(me); } public void mouseUp(MouseEvent me) { RibbonTooltipDialog.kill(); mMouseIsDown = false; if (drawAsShell) mRibbonShell.mouseUp(me); // do this regardless, mouse up could've been anywhere updateButtonStates(me.x, me.y); redrawMenuBarButton(); if (drawAsShell) { if (me.button == 1) { if (isInside(me.x, me.y, minButtonRect)) minButtonClicked(); else if (isInside(me.x, me.y, maxButtonRect)) maxButtonClicked(); else if (isInside(me.x, me.y, closeButtonRect)) closeButtonClicked(); } } if (mHelpButton != null) { if (mHelpButton.isSelected()) { if (isInside(me.x, me.y, mHelpButton.getBounds())) { helpButtonClicked(); mHelpButton.setSelected(false); mHelpButton.setHoverButton(true); redraw(mHelpButton.getBounds()); } else { // deselect, dehover, as user is elsewhere with the mouse if (mHelpButton.isSelected() || mHelpButton.isHoverButton()) { mHelpButton.setSelected(false); mHelpButton.setHoverButton(false); redraw(mHelpButton.getBounds()); } } } } } private void helpButtonClicked() { } public void mouseMove(MouseEvent me) { RibbonTooltipDialog.kill(); if (drawAsShell) { if (mMouseIsDown && mMouseWasDownOnMenubar) { //TODO: make this part of mMouseWasDownOnMenubar //if (!isInside(me.x, me.y, bigButtonRect) && !isInside(me.x, me.y, mQuickAccessBounds) && isInside(me.x, me.y, menuBarRect)) mRibbonShell.moveShell(me); } // for resize-shell events etc mRibbonShell.mouseMove(me); } int y = TAB_HEIGHT + 4; if (drawAsShell) y += NON_MAXIMIZED_HEIGHT; for (int i = 0; i < mTabs.size(); i++) { RibbonTab ft = mTabs.get(i); if (ft.getBounds() == null) continue; Rectangle tabBounds = ft.getBounds(); if (isInside(me.x, me.y, ft.getBounds())) { if (!ft.isHover()) { if (mHoverTab != null) { Rectangle oldBounds = mHoverTab.getBounds(); redraw(oldBounds.x-10, 0, oldBounds.width+20, y, false); mHoverTab.setHover(false); } ft.setHover(true); redraw(tabBounds.x-10, 0, tabBounds.width+20, y, false); mHoverTab = ft; } } else { if (ft.isHover()) { redraw(tabBounds.x-10, 0, tabBounds.width+20, y, false); ft.setHover(false); } } } // check buttons in toolbar if any if (drawAsShell) updateButtonStates(me.x, me.y); if (mHelpButton != null) { if (isInside(me.x, me.y, mHelpButton.getBounds())) { if (!mHelpButton.isHoverButton()) { mHelpButton.setHoverButton(true); redraw(mHelpButton.getBounds()); } } else { if (mHelpButton.isHoverButton()) { mHelpButton.setHoverButton(false); redraw(mHelpButton.getBounds()); } } } } // why doesn't swt let you pass in a rectangle to redraw?? private void redraw(Rectangle rect) { redraw(rect.x, rect.y, rect.width, rect.height, false); } public boolean isShell() { return (mRibbonShell != null && drawAsShell); } public void minButtonClicked() { if (!isShell()) return; if (!mRibbonShell.getShell().getMinimized()) mRibbonShell.getShell().setMinimized(true); } public void restoreButtonClicked() { if (!isShell()) return; mRibbonShell.setMaximized(false); } public void maxButtonClicked() { if (!isShell()) return; if (!mRibbonShell.getMaximized()) mRibbonShell.setMaximized(true); else restoreButtonClicked(); } public void closeButtonClicked() { if (!isShell()) return; mRibbonShell.getShell().close(); mRibbonShell.getShell().dispose(); } public List<RibbonTab> getTabs() { return mTabs; } public void disposeAllChildren() { for (RibbonTab tab : mTabs) tab.dispose(); mHoverTab = null; mSelectedTab = null; mTabs.clear(); redraw(); } public void redraw() { if (isShell()) updateMenuBarButtonCalculations(); super.redraw(); } public boolean isDrawEmptyTabs() { return drawEmptyTabs; } public void collapseTabFolder() { //System.err.println("collapsing"); mCollapsedTabFolder = true; if (isShell()) { mRibbonShell.getShell().layout(true, true); mRibbonShell.redrawContents(); Rectangle bounds = getBounds(); redraw(bounds.x, bounds.y, bounds.width, TAB_HEIGHT+4, true); getParent().layout(true, true); } else { redraw(); layout(true); Rectangle bounds = getBounds(); redraw(bounds.x, bounds.y, bounds.width, TAB_HEIGHT+4, true); getParent().layout(true, true); } } public void expandTabFolder() { mCollapsedTabFolder = false; if (isShell()) { mRibbonShell.getShell().layout(true); mRibbonShell.redrawContents(); } else { layout(true); redraw(); } } public boolean isCollapsed() { return mCollapsedTabFolder; } public boolean isExpanded() { return !mCollapsedTabFolder; } private void deselectTab(RibbonTab ft) { if (ft.isSelected()) { Rectangle tabBounds = ft.getBounds(); redraw(tabBounds.x-10, 0, tabBounds.width+20, TAB_HEIGHT+4, false); ft.setSelected(false); if (ft.getFancyToolbar() != null) ft.getFancyToolbar().setVisible(false); } else { if (ft.getFancyToolbar() != null) ft.getFancyToolbar().setVisible(false); } } public void selectTab(RibbonTab ft) { checkWidget(); if (mSelectedTab == ft) return; if (mSelectedTab != null) { deselectTab(mSelectedTab); } Rectangle tabBounds = ft.getBounds(); if (tabBounds == null) return; ft.setSelected(true); // do a full redraw as the right edge (which moves when control resizes) might need a redraw depending on the // width of contents inside the tab redraw(); mSelectedTab = ft; update(); layout(true); //TODO: This isn't fully functional, old hovers can still remain, the rest seems to work, may be overkill //mSelectedTab.scrollWheelUpdate(); } public void selectNextTab() { checkWidget(); int cur = 0; List<RibbonTab> visibles = getVisibleTabs(); if (mSelectedTab != null) cur = visibles.indexOf(mSelectedTab); cur++; if (cur > visibles.size()-1) cur = visibles.size()-1; selectTab(visibles.get(cur)); } private List<RibbonTab> getVisibleTabs() { if (drawEmptyTabs) return mTabs; List<RibbonTab> visibles = new ArrayList<RibbonTab>(); for (int i = 0; i < mTabs.size(); i++) { if (!mTabs.get(i).isEmpty()) visibles.add(mTabs.get(i)); } return visibles; } public void selectPrevTab() { checkWidget(); int cur = 0; List<RibbonTab> visibles = getVisibleTabs(); if (mSelectedTab != null) cur = visibles.indexOf(mSelectedTab); cur--; if (cur < 0) cur = 0; selectTab(visibles.get(cur)); } void redrawArea(Rectangle rect) { redraw(rect.x, rect.y, rect.width, rect.height, false); } void redrawMenuBarButton() { if (!isShell()) return; redrawArea(allButtonsRect); } void redrawBigButton() { if (!isShell()) return; redrawArea(bigButtonRect); } private boolean isInside(int x, int y, Rectangle rect) { if (rect == null) { return false; } return x >= rect.x && y >= rect.y && x <= (rect.x + rect.width - 1) && y <= (rect.y + rect.height - 1); } protected void tabControlSet(RibbonTab ft) { if (ft.getFancyToolbar() == null) return; if (ft == mSelectedTab) ft.getFancyToolbar().setVisible(true); else ft.getFancyToolbar().setVisible(false); layout(true); } protected void tabAdded(RibbonTab ft) { if (!mTabs.contains(ft)) { // TODO: Make option, just selects the first tab automatically if (mTabs.size() == 0) { ft.setSelected(true); mSelectedTab = ft; } mTabs.add(ft); recalculateTabBounds(); redraw(); } } // sets tab bounds so that we can actually draw them private void recalculateTabBounds() { int x = FIRST_TAB_SPACING; GC temp = new GC(this); int y = drawAsShell ? NON_MAXIMIZED_HEIGHT : 0; for (int i = 0; i < mTabs.size(); i++) { RibbonTab ft = (RibbonTab) mTabs.get(i); ft.setIndex(i); Point p = temp.stringExtent(ft.getName()); int width = p.x + (TEXT_SPACING_SIDE * 2) + (5 * 2); Rectangle bounds = new Rectangle(x, y, width, TAB_HEIGHT); ft.setBounds(bounds); x += TAB_SPACING + width; } temp.dispose(); } private void drawTabFolder(GC gc, int yStart) { Rectangle bounds = getBounds(); int neg = 0; int x = 0; if (drawAsShell) { mShellPainter.paintShell(mRibbonShell, gc); yStart += (mRibbonShell.getMaximized() ? MAXIMIZED_HEIGHT : NON_MAXIMIZED_HEIGHT); } gc.setForeground(mTopLine); gc.drawLine(x, yStart+0, bounds.width-neg, yStart); gc.setForeground(mTopLineInner); gc.drawLine(x, yStart+1, bounds.width-neg, yStart+1); gc.setForeground(mFillTop); gc.setBackground(mFillBottom); int maxHeight = mCollapsedTabFolder ? TAB_HEIGHT : MAX_HEIGHT; gc.fillGradientRectangle(x, yStart+2, bounds.width-neg, maxHeight, true); if (drawAsShell) { mShellPainter.drawBigButton(gc); mShellPainter.drawMenubarToolbar(gc); } // draw tabs for (int i = 0; i < mTabs.size(); i++) { RibbonTab ft = mTabs.get(i); if (ft.isEmpty() && !drawEmptyTabs) continue; mTabPainter.drawTab(gc, ft, yStart+3); } updateBottomLine(gc, yStart); if (mHelpImage != null) { //createHelpButton(); drawHelpArea(gc); } // shell border, half of it, rest is drawn in the RibbonShell class if (drawAsShell && !mRibbonShell.getMaximized()) { Color borderColor = null; if (Display.getDefault().getActiveShell() == mRibbonShell.getShell()) borderColor = AbstractShellPainter.outerBorderNonMaximized; else borderColor = AbstractShellPainter.outerBorderNonMaximized_Inactive; Color faded = GraphicsHelper.lighter(borderColor, 50); gc.setForeground(borderColor); // top left gc.drawLine(1, 1, 2, 1); gc.drawLine(0, 2, 1, 2); gc.drawLine(0, 3, 0, 3); // top right gc.drawLine(bounds.width-3, 1, bounds.width-2, 1); gc.drawLine(bounds.width-2, 2, bounds.width-1, 2); gc.drawLine(bounds.width-1, 3, bounds.width-1, 3); // fade the last ones gc.setForeground(faded); gc.drawLine(0, 4, 0, 4); gc.drawLine(bounds.width-4, 1, bounds.width-4, 1); gc.drawLine(bounds.width-1, 4, bounds.width-1, 4); } } private void drawHelpArea(GC gc) { if (mHelpButton == null) return; Rectangle bounds = getBounds(); int fromRight = 22; int fromTop = 31; if (isShell()) { if (mRibbonShell.getMaximized()) { //fromRight += 0; // just a reminder fromTop -= 4; } else fromRight += 4; } else fromRight += 4; // TODO: Replace 22's with globals mHelpButton.setBounds(new Rectangle(bounds.x+bounds.width-fromRight, bounds.y+fromTop, 22, 22)); mButtonPainter.drawMenuToolbarButton(gc, mHelpButton); } private void createHelpButton() { if (mHelpButton == null) mHelpButton = new RibbonButton(this, mHelpImage, null, RibbonButton.STYLE_NO_DEPRESS); if (mHelpImage == null && mHelpButton != null) mHelpButton = null; } private void updateMenuBarButtonCalculations() { boolean maximized = mRibbonShell.getMaximized(); int fromRight = maximized ? -2 : 4; int spacing = 0; int xStart = fromRight + (25 * 3) + (spacing * 2); xStart = getBounds().width - xStart; int yStart = maximized ? 0 : 4; int bigSpacerXY = maximized ? 4 : 7; minButtonRect = new Rectangle(xStart, yStart, 25, 25); maxButtonRect = new Rectangle(xStart+25, yStart, 25, 25); closeButtonRect = new Rectangle(xStart+25+25, yStart, 25, 25); allButtonsRect = new Rectangle(xStart, yStart, 75, 25); bigButtonRect = new Rectangle(bigSpacerXY, bigSpacerXY, 38, 38); menuBarRect = new Rectangle(RibbonShell.CORNER_FLEX, RibbonShell.SIDE_FLEX, getBounds().width - (RibbonShell.CORNER_FLEX * 2), (maximized ? MAXIMIZED_HEIGHT : NON_MAXIMIZED_HEIGHT) - RibbonShell.SIDE_FLEX); fullMenuBarRect = new Rectangle(0, 0, getBounds().width, (maximized ? MAXIMIZED_HEIGHT : NON_MAXIMIZED_HEIGHT) - RibbonShell.SIDE_FLEX); } public Rectangle getMinButtonBounds() { return minButtonRect; } public Rectangle getMaxButtonBounds() { return maxButtonRect; } public Rectangle getCloseButtonBounds() { return closeButtonRect; } public Rectangle getBigButtonBounds() { return bigButtonRect; } public Point getMenubarToolbarLocation() { return new Point(bigButtonRect.x+30, bigButtonRect.y-2); } private boolean shellIsFocused() { if (Display.getDefault().getFocusControl() == null) return false; if (Display.getDefault().getFocusControl().getShell() == mRibbonShell.getShell()) return true; return false; } public int getMinButtonState() { if (!shellIsFocused()) return STATE_INACTIVE; return minButtonState; } public int getMaxButtonState() { if (!shellIsFocused()) return STATE_INACTIVE; return maxButtonState; } public int getCloseButtonState() { if (!shellIsFocused()) return STATE_INACTIVE; return closeButtonState; } public int getBigButtonState() { if (!shellIsFocused()) return STATE_INACTIVE; return bigButtonState; } private void updateButtonStates(int x, int y) { Point onUs = new Point(x, y); if (isInside(onUs.x, onUs.y, allButtonsRect)) { boolean minChanged = false; boolean maxChanged = false; boolean closeChanged = false; if (isInside(onUs.x, onUs.y, minButtonRect)) { if (mMouseIsDown) { if (minButtonState != STATE_HOVER_SELECTED) minChanged = true; minButtonState = STATE_HOVER_SELECTED; } else { if (minButtonState != STATE_HOVER) minChanged = true; minButtonState = STATE_HOVER; } } else { if (minButtonState != STATE_NONE) minChanged = true; minButtonState = STATE_NONE; } if (isInside(onUs.x, onUs.y, maxButtonRect)) { if (mMouseIsDown) { if (maxButtonState != STATE_HOVER_SELECTED) maxChanged = true; maxButtonState = STATE_HOVER_SELECTED; } else { if (maxButtonState != STATE_HOVER) maxChanged = true; maxButtonState = STATE_HOVER; } } else { if (maxButtonState != STATE_NONE) maxChanged = true; maxButtonState = STATE_NONE; } if (isInside(onUs.x, onUs.y, closeButtonRect)) { if (mMouseIsDown) { if (closeButtonState != STATE_HOVER_SELECTED) closeChanged = true; closeButtonState = STATE_HOVER_SELECTED; } else { if (closeButtonState != STATE_HOVER) closeChanged = true; closeButtonState = STATE_HOVER; } } else { if (closeButtonState != STATE_NONE) closeChanged = true; closeButtonState = STATE_NONE; } if (minChanged || maxChanged || closeChanged) redrawMenuBarButton(); } else { // remove any effect if mouse isn't even here and some button is in a different state if (minButtonState != STATE_NONE || maxButtonState != STATE_NONE || closeButtonState != STATE_NONE) { minButtonState = STATE_NONE; maxButtonState = STATE_NONE; closeButtonState = STATE_NONE; redrawMenuBarButton(); } } if (isInside(onUs.x, onUs.y, bigButtonRect)) { boolean bigChanged = false; if (mMouseIsDown) { if (bigButtonState != STATE_HOVER_SELECTED) bigChanged = true; bigButtonState = STATE_HOVER_SELECTED; } else { if (bigButtonState != STATE_HOVER) bigChanged = true; bigButtonState = STATE_HOVER; } if (bigChanged) redrawBigButton(); } else { bigButtonState = STATE_NONE; redrawBigButton(); } } private void updateBottomLine(GC gc, int yStart) { // draw open tab, basically the 1px line below all tabs, draws even if mSelectedTab is null mTabPainter.drawTabBorder(gc, getBounds(), mSelectedTab, mCollapsedTabFolder, yStart); } public RibbonTab getSelectedTab() { return mSelectedTab; } @Override public Rectangle getBounds() { checkWidget(); Rectangle bounds = super.getBounds(); Rectangle ret = null; int heightBonus = drawAsShell ? (mRibbonShell.getMaximized() ? MAXIMIZED_HEIGHT : NON_MAXIMIZED_HEIGHT) : 0; if (mCollapsedTabFolder) ret = new Rectangle(bounds.x, bounds.y, bounds.width, TAB_HEIGHT+4+heightBonus); else ret = new Rectangle(bounds.x, bounds.y, bounds.width, MAX_HEIGHT+heightBonus); // compensate for shell if (drawAsShell) ret.height -= 2; return ret; } public Point getSize() { Rectangle bounds = getBounds(); return new Point(bounds.width, bounds.height); } public void setDrawEmptyTabs(boolean drawEmpty) { drawEmptyTabs = drawEmpty; } public void setHelpImage(Image helpImage) { mHelpImage = helpImage; createHelpButton(); if (helpImage != null && mHelpButton != null) mHelpButton.setImage(helpImage); } public Image getHelpImage() { return mHelpImage; } public RibbonButton getHelpButton() { return mHelpButton; } class TabFolderLayout extends Layout { @Override protected Point computeSize(Composite composite, int hint, int hint2, boolean flushCache) { return getSize(); } @Override protected void layout(Composite composite, boolean flushCache) { Control [] children = composite.getChildren(); if (children == null) return; int yBonus = drawAsShell ? (mRibbonShell.getMaximized() ? MAXIMIZED_HEIGHT : NON_MAXIMIZED_HEIGHT) : 0; for (int i = 0; i < children.length; i++) { Control child = children[i]; if (child instanceof RibbonTabComposite) { RibbonTabComposite ft = (RibbonTabComposite) child; if (mCollapsedTabFolder) { ft.setVisible(false); continue; } if (mSelectedTab != null) { if (mSelectedTab.getFancyToolbar() == ft) { ft.layout(true); ft.setLocation(new Point(4, TAB_AREA_HEIGHT+2+yBonus)); // TODO: Why do I need to do this stupid call to make it work? ft.setSize(ft.getSize()); ft.setVisible(true); } } } } } } }