/** Creates and returns the Help menu. */
  private MenuManager createHelpMenu() {
    MenuManager menu = new MenuManager(Messages.HelpMenuName, IWorkbenchActionConstants.M_HELP);
    menu.add(new GroupMarker("group.intro.ext")); // $NON-NLS-1$
    menu.add(new GroupMarker("group.main")); // $NON-NLS-1$
    menu.add(helpContentsAction);
    menu.add(helpSearchAction);
    menu.add(dynamicHelpAction);
    menu.add(new GroupMarker("group.assist")); // $NON-NLS-1$
    // HELP_START should really be the first item, but it was after
    // quickStartAction and tipsAndTricksAction in 2.1.
    menu.add(new GroupMarker(IWorkbenchActionConstants.HELP_START));
    menu.add(new GroupMarker("group.main.ext")); // $NON-NLS-1$
    menu.add(new GroupMarker("group.tutorials")); // $NON-NLS-1$
    menu.add(new GroupMarker("group.tools")); // $NON-NLS-1$
    menu.add(new GroupMarker("group.updates")); // $NON-NLS-1$
    menu.add(new GroupMarker(IWorkbenchActionConstants.HELP_END));
    menu.add(new GroupMarker(IWorkbenchActionConstants.MB_ADDITIONS));
    // about should always be at the bottom
    menu.add(new Separator("group.about")); // $NON-NLS-1$

    ActionContributionItem aboutItem = new ActionContributionItem(aboutAction);
    aboutItem.setVisible(!Util.isMac());
    menu.add(aboutItem);
    menu.add(new GroupMarker("group.about.ext")); // $NON-NLS-1$
    return menu;
  }
  /** Creates and returns the File menu. */
  private MenuManager createFileMenu() {
    MenuManager menu = new MenuManager(Messages.FileMenuName, IWorkbenchActionConstants.M_FILE);
    menu.add(new GroupMarker(IWorkbenchActionConstants.FILE_START));

    ActionContributionItem newExecutableItem = new ActionContributionItem(newExecutableAction);
    menu.add(newExecutableItem);

    ActionContributionItem attachExecutableItem =
        new ActionContributionItem(attachExecutableAction);
    menu.add(attachExecutableItem);

    ActionContributionItem corefileItem = new ActionContributionItem(corefileAction);
    menu.add(corefileItem);

    menu.add(new Separator());

    // If we're on OS X we shouldn't show this command in the File menu. It
    // should be invisible to the user. However, we should not remove it -
    // the carbon UI code will do a search through our menu structure
    // looking for it when Cmd-Q is invoked (or Quit is chosen from the
    // application menu.
    ActionContributionItem quitItem = new ActionContributionItem(quitAction);
    quitItem.setVisible(!Util.isMac());
    menu.add(quitItem);
    menu.add(new GroupMarker(IWorkbenchActionConstants.FILE_END));
    return menu;
  }
  /** Creates and returns the Window menu. */
  private MenuManager createWindowMenu() {
    MenuManager menu = new MenuManager(Messages.WindowMenuName, IWorkbenchActionConstants.M_WINDOW);

    addPerspectiveActions(menu);
    Separator sep = new Separator(IWorkbenchActionConstants.MB_ADDITIONS);
    sep.setVisible(!Util.isMac());
    menu.add(sep);

    // See the comment for quit in createFileMenu
    ActionContributionItem openPreferencesItem = new ActionContributionItem(openPreferencesAction);
    openPreferencesItem.setVisible(!Util.isMac());
    menu.add(openPreferencesItem);

    menu.add(ContributionItemFactory.OPEN_WINDOWS.create(getWindow()));
    return menu;
  }
  protected void fillMenuBar(IMenuManager menuBar) {
    MenuManager fileMenu = new MenuManager("&File", IWorkbenchActionConstants.M_FILE);
    MenuManager helpMenu = new MenuManager("&Help", IWorkbenchActionConstants.M_HELP);

    menuBar.add(fileMenu);
    // Add a group marker indicating where action set menus will appear.
    menuBar.add(new GroupMarker(IWorkbenchActionConstants.MB_ADDITIONS));
    menuBar.add(helpMenu);
    helpMenu.add(helpContentsAction);

    // File Menu
    /* fileMenu.add(prefAction);
    fileMenu.add(new Separator());
    fileMenu.add(exitAction); */

    // Ajout sous la forme de ActionContributionItem pour pouvoir rendre les actions ensuite
    // invisibles, car elle sont dŽjˆ prŽsentes dans le menu Pomme du mac.
    ActionContributionItem preferencesActionItem = new ActionContributionItem(prefAction);
    fileMenu.add(preferencesActionItem);
    ActionContributionItem exitActionItem = new ActionContributionItem(exitAction);
    fileMenu.add(exitActionItem);

    if (Util.isMac()) {
      preferencesActionItem.setVisible(false);
      exitActionItem.setVisible(false);
    }
  }
  static {
    final IKeyLookup lookup = KeyLookupFactory.getDefault();
    ALT = new ModifierKey(lookup.getAlt());
    COMMAND = new ModifierKey(lookup.getCommand());
    CTRL = new ModifierKey(lookup.getCtrl());
    SHIFT = new ModifierKey(lookup.getShift());

    modifierKeysByName.put(ModifierKey.ALT.toString(), ModifierKey.ALT);
    modifierKeysByName.put(ModifierKey.COMMAND.toString(), ModifierKey.COMMAND);
    modifierKeysByName.put(ModifierKey.CTRL.toString(), ModifierKey.CTRL);
    modifierKeysByName.put(ModifierKey.SHIFT.toString(), ModifierKey.SHIFT);
    modifierKeysByName.put(M1_NAME, Util.isMac() ? ModifierKey.COMMAND : ModifierKey.CTRL);
    modifierKeysByName.put(M2_NAME, ModifierKey.SHIFT);
    modifierKeysByName.put(M3_NAME, ModifierKey.ALT);
    modifierKeysByName.put(M4_NAME, Util.isMac() ? ModifierKey.CTRL : ModifierKey.COMMAND);
  }
  /*
   * (non-Javadoc)
   *
   * @see org.eclipse.jface.bindings.keys.AbstractKeyFormatter#getKeyDelimiter()
   */
  protected String getKeyDelimiter() {
    // We must do the look up every time, as our locale might change.
    if (Util.isMac()) {
      return Util.translateString(
          RESOURCE_BUNDLE, CARBON_KEY_DELIMITER_KEY, Util.ZERO_LENGTH_STRING);
    }

    return Util.translateString(RESOURCE_BUNDLE, KEY_DELIMITER_KEY, KeyStroke.KEY_DELIMITER);
  }
Example #7
0
  protected Control createControl(Composite parent, int style) {
    if (Util.isMac()) {
      return new Scale(parent, style);
    }

    int canvasStyle = SWT.NO_REDRAW_RESIZE | SWT.V_SCROLL | SWT.H_SCROLL | SWT.DOUBLE_BUFFERED;
    FigureCanvas fc = new SliderFigureCanvas(canvasStyle, parent);
    return fc;
  }
  /**
   * Formats an individual key into a human readable format. This uses an internationalization
   * resource bundle to look up the key. This does the platform-specific formatting for Carbon.
   *
   * @param key The key to format.
   * @return The key formatted as a string; should not be <code>null</code>.
   */
  public final String format(final int key) {
    final IKeyLookup lookup = KeyLookupFactory.getDefault();
    final String name = lookup.formalNameLookup(key);

    // TODO consider platform-specific resource bundles
    if (Util.isMac()) {
      String formattedName = (String) CARBON_KEY_LOOK_UP.get(name);
      if (formattedName != null) {
        return formattedName;
      }
    }

    return super.format(key);
  }
  /*
   * (non-Javadoc)
   *
   * @see org.eclipse.jface.bindings.keys.AbstractKeyFormatter#sortModifierKeys(int)
   */
  protected int[] sortModifierKeys(final int modifierKeys) {
    final IKeyLookup lookup = KeyLookupFactory.getDefault();
    final int[] sortedKeys = new int[4];
    int index = 0;

    if (Util.isWindows()) {
      if ((modifierKeys & lookup.getCtrl()) != 0) {
        sortedKeys[index++] = lookup.getCtrl();
      }
      if ((modifierKeys & lookup.getAlt()) != 0) {
        sortedKeys[index++] = lookup.getAlt();
      }
      if ((modifierKeys & lookup.getShift()) != 0) {
        sortedKeys[index++] = lookup.getShift();
      }

    } else if (Util.isGtk() || Util.isMotif()) {
      if ((modifierKeys & lookup.getShift()) != 0) {
        sortedKeys[index++] = lookup.getShift();
      }
      if ((modifierKeys & lookup.getCtrl()) != 0) {
        sortedKeys[index++] = lookup.getCtrl();
      }
      if ((modifierKeys & lookup.getAlt()) != 0) {
        sortedKeys[index++] = lookup.getAlt();
      }

    } else if (Util.isMac()) {
      if ((modifierKeys & lookup.getShift()) != 0) {
        sortedKeys[index++] = lookup.getShift();
      }
      if ((modifierKeys & lookup.getCtrl()) != 0) {
        sortedKeys[index++] = lookup.getCtrl();
      }
      if ((modifierKeys & lookup.getAlt()) != 0) {
        sortedKeys[index++] = lookup.getAlt();
      }
      if ((modifierKeys & lookup.getCommand()) != 0) {
        sortedKeys[index++] = lookup.getCommand();
      }
    }

    return sortedKeys;
  }
  /*
   * (non-Javadoc)
   *
   * @see org.eclipse.ui.internal.progress.AnimationItem#createAnimationItem(org.eclipse.swt.widgets.Composite)
   */
  @Override
  protected Control createAnimationItem(Composite parent) {

    if (okImage == null) {
      Display display = parent.getDisplay();
      noneImage =
          WorkbenchImages.getWorkbenchImageDescriptor("progress/progress_none.png")
              .createImage(display); // $NON-NLS-1$
      okImage =
          WorkbenchImages.getWorkbenchImageDescriptor("progress/progress_ok.png")
              .createImage(display); // $NON-NLS-1$
      errorImage =
          WorkbenchImages.getWorkbenchImageDescriptor("progress/progress_error.png")
              .createImage(display); // $NON-NLS-1$
    }

    top = new Composite(parent, SWT.NULL);
    top.addDisposeListener(
        new DisposeListener() {
          @Override
          public void widgetDisposed(DisposeEvent e) {
            FinishedJobs.getInstance().removeListener(ProgressAnimationItem.this);
            noneImage.dispose();
            okImage.dispose();
            errorImage.dispose();
          }
        });

    boolean isCarbon = Util.isMac();

    GridLayout gl = new GridLayout();
    if (isHorizontal()) gl.numColumns = isCarbon ? 3 : 2;
    gl.marginHeight = 0;
    gl.marginWidth = 0;
    if (isHorizontal()) {
      gl.horizontalSpacing = 2;
    } else {
      gl.verticalSpacing = 2;
    }
    top.setLayout(gl);

    bar = new ProgressBar(top, flags | SWT.INDETERMINATE);
    bar.setVisible(false);
    bar.addMouseListener(mouseListener);

    GridData gd;
    int hh = 12;
    if (isHorizontal()) {
      gd = new GridData(SWT.BEGINNING, SWT.CENTER, true, false);
      gd.heightHint = hh;
    } else {
      gd = new GridData(SWT.CENTER, SWT.BEGINNING, false, true);
      gd.widthHint = hh;
    }

    bar.setLayoutData(gd);

    toolbar = new ToolBar(top, SWT.FLAT);
    toolbar.setVisible(false);

    toolButton = new ToolItem(toolbar, SWT.NONE);
    toolButton.addSelectionListener(
        new SelectionAdapter() {
          @Override
          public void widgetSelected(SelectionEvent e) {
            doAction();
          }
        });

    if (isCarbon) {
      new Label(top, SWT.NONE).setLayoutData(new GridData(4, 4));
    }

    refresh();

    return top;
  }
Example #11
0
 private boolean isCopyMove() {
   if (Util.isMac()) return getStatus().isStatus(GEF.ST_ALT_PRESSED);
   return getStatus().isStatus(GEF.ST_CONTROL_PRESSED);
 }
Example #12
0
public class MButton extends Viewer {

  /** Style bit: Create control with default behaviours, i.e. showing text, showing image. */
  public static final int NORMAL = 0;

  /** Style bit: Don't show text. */
  public static final int NO_TEXT = 1;

  /** Style bit: Don't show image. */
  public static final int NO_IMAGE = 1 << 1;

  /** Style bit: Don't show spinner arrows. */
  public static final int NO_ARROWS = 1 << 2;

  private static final boolean DRAWS_FOCUS = Util.isMac();

  protected static final int MARGIN = DRAWS_FOCUS ? 4 : 1;
  protected static final int CORNER_SIZE = 5;
  protected static final int BORDER = (CORNER_SIZE + 1) / 2;
  protected static final int FOCUS_CORNER_SIZE = CORNER_SIZE - 2;
  protected static final int FOCUS_BORDER = (FOCUS_CORNER_SIZE + 1) / 2;
  protected static final int IMAGE_TEXT_SPACING = 3;
  protected static final int CONTENT_ARROW_SPACING = 4;
  protected static final int ARROW_WIDTH = 7;
  protected static final int ARROW_HEIGHT = 4;
  protected static final int ARROWS_SPACING = 2;
  protected static final String ELLIPSIS = "..."; // $NON-NLS-1$

  private Composite control;

  private int style;

  private String text = null;

  private Image image = null;

  private Color textForeground = null;

  private Color textBackground = null;

  private boolean hovered = false;

  private boolean pressed = false;

  private boolean forceFocus = false;

  private Point textSize = null;

  private Point imageSize = null;

  private List<IOpenListener> openListeners = null;

  /*
   * Caches:
   */
  private Point cachedTextSize = null;
  private Point cachedImageSize = null;
  private String appliedText = null;
  private Rectangle bounds = null;
  private Rectangle contentArea = null;
  private Point arrowLoc = null;
  private Rectangle imgArea = null;
  private Rectangle textArea = null;

  /**
   * Constructs a new instance of this class given its parent and a style value describing its
   * behavior and appearance.
   *
   * @param parent a composite control which will be the parent of the new instance (cannot be null)
   * @param style the style of control to construct
   * @see #NORMAL
   * @see #NO_TEXT
   * @see #NO_IMAGE
   * @see #NO_ARROWS
   */
  public MButton(Composite parent, int style) {
    this.style =
        checkStyle(style, NORMAL, NORMAL, NO_TEXT, NO_IMAGE)
            | checkStyle(style, SWT.NONE, NO_ARROWS);
    this.control =
        new Canvas(parent, SWT.DOUBLE_BUFFERED) {
          public Point computeSize(int wHint, int hHint, boolean changed) {
            checkWidget();
            if (changed) clearCaches();
            Point imageSize = getImageSize();
            Point textSize = getTextSize();
            boolean hasArrows = hasArrows();

            int width;
            if (wHint != SWT.DEFAULT) {
              width = Math.max(wHint, MARGIN * 2);
            } else {
              width = MARGIN * 2 + imageSize.x + textSize.x + BORDER * 2;
              if (hasArrows) {
                width += ARROW_WIDTH + CONTENT_ARROW_SPACING;
              }
              if (imageSize.x != 0 && textSize.x != 0) {
                width += IMAGE_TEXT_SPACING;
              }
              //                    if (hasArrows && (imageSize.x != 0 || textSize.x != 0)) {
              //                        width += CONTENT_ARROW_SPACING;
              //                    }
            }

            int minHeight = MARGIN * 2 + Math.max(imageSize.y, textSize.y) + BORDER * 2;
            if (hasArrows) {
              minHeight = Math.max(minHeight, ARROW_HEIGHT * 2 + ARROWS_SPACING);
            }
            int height = minHeight;
            Rectangle trim = computeTrim(0, 0, width, height);
            return new Point(trim.width, trim.height);
          }
        };
    hookControl(control);
  }

  protected void hookControl(Control control) {
    Listener listener =
        new Listener() {
          public void handleEvent(Event event) {
            switch (event.type) {
              case SWT.Paint:
                paint(event.gc, event.display);
                break;
              case SWT.Resize:
                clearCaches();
                break;
              case SWT.MouseDown:
                if (event.button == 1) handleMousePress();
                break;
              case SWT.MouseUp:
                if (event.button == 1) handleMouseRelease();
                break;
              case SWT.MouseEnter:
                handleMouseEnter();
                break;
              case SWT.MouseExit:
                handleMouseExit();
                break;
              case SWT.KeyDown:
                handleKeyPress(event);
                break;
              case SWT.FocusIn:
                handleFocusIn();
                break;
              case SWT.FocusOut:
                handleFocusOut();
            }
          }
        };
    control.addListener(SWT.Paint, listener);
    control.addListener(SWT.Resize, listener);
    control.addListener(SWT.MouseDown, listener);
    control.addListener(SWT.MouseUp, listener);
    control.addListener(SWT.MouseEnter, listener);
    control.addListener(SWT.MouseExit, listener);
    control.addListener(SWT.KeyDown, listener);
    control.addListener(SWT.FocusIn, listener);
    control.addListener(SWT.FocusOut, listener);
  }

  protected void handleMousePress() {
    if (!getControl().isEnabled()) return;
    setHovered(true);
    setPressed(true);
    getControl().setFocus();
    fireOpen();
  }

  protected void handleMouseRelease() {
    if (!getControl().isEnabled()) return;
    setPressed(false);
  }

  protected void handleMouseEnter() {
    if (!getControl().isEnabled()) return;
    setHovered(true);
  }

  protected void handleMouseExit() {
    if (!getControl().isEnabled()) return;
    setHovered(false);
  }

  protected void handleFocusIn() {
    if (!getControl().isEnabled()) return;
    refreshControl();
  }

  protected void handleFocusOut() {
    if (!getControl().isEnabled()) return;
    setPressed(false);
    refreshControl();
  }

  protected void handleKeyPress(Event e) {
    if (!getControl().isEnabled()) return;

    int keyCode = e.keyCode;
    int stateMask = e.stateMask;
    if (SWTUtils.matchKeyCode(keyCode, SWT.TAB)) {
      if (SWTUtils.matchState(stateMask, SWT.SHIFT)) {
        getControl().traverse(SWT.TRAVERSE_TAB_PREVIOUS);
      } else if (SWTUtils.matchState(stateMask, 0)) {
        getControl().traverse(SWT.TRAVERSE_TAB_NEXT);
      }
    } else if (SWTUtils.matchKey(stateMask, keyCode, 0, SWT.CR)) {
      fireOpen();
    }
  }

  public void addOpenListener(IOpenListener listener) {
    if (openListeners == null) openListeners = new ArrayList<IOpenListener>();
    openListeners.add(listener);
  }

  public void removeOpenListener(IOpenListener listener) {
    if (openListeners == null) return;
    openListeners.remove(listener);
  }

  protected void fireOpen(final OpenEvent event) {
    if (openListeners == null) return;
    for (final Object l : openListeners.toArray()) {
      SafeRunner.run(
          new SafeRunnable() {
            public void run() throws Exception {
              ((IOpenListener) l).open(event);
            }
          });
    }
  }

  protected void fireOpen() {
    fireOpen(new OpenEvent(this, getSelection()));
  }

  public Control getControl() {
    return control;
  }

  protected int getStyle() {
    return style;
  }

  public String getText() {
    return text;
  }

  public Image getImage() {
    return image;
  }

  public boolean hasText() {
    return text != null && (style & NO_TEXT) == 0;
  }

  public boolean hasImage() {
    return image != null && (style & NO_IMAGE) == 0;
  }

  protected boolean hasArrows() {
    return (style & NO_ARROWS) == 0;
  }

  public Color getTextForeground() {
    return textForeground;
  }

  public Color getTextBackground() {
    return textBackground;
  }

  public void setTextForeground(Color c) {
    if (c == this.textForeground || (c != null && c.equals(this.textForeground))) return;
    this.textForeground = c;
    refreshControl();
  }

  public void setTextBackground(Color c) {
    if (c == this.textBackground || (c != null && c.equals(this.textBackground))) return;
    this.textBackground = c;
    refreshControl();
  }

  public boolean isHovered() {
    return hovered;
  }

  public boolean isPressed() {
    return pressed;
  }

  public boolean isForceFocus() {
    return forceFocus;
  }

  public void setHovered(boolean hovered) {
    if (hovered == this.hovered) return;
    this.hovered = hovered;
    refreshControl();
  }

  public void setPressed(boolean pressed) {
    if (pressed == this.pressed) return;
    this.pressed = pressed;
    refreshControl();
  }

  public void setForceFocus(boolean focused) {
    if (focused == this.forceFocus) return;
    this.forceFocus = focused;
    refreshControl();
  }

  public void setText(String text) {
    if (text == this.text || (text != null && text.equals(this.text))) return;
    this.text = text;
    cachedTextSize = null;
    clearCaches();
    refreshControl();
  }

  public void setImage(Image image) {
    if (image == this.image) return;
    this.image = image;
    cachedImageSize = null;
    clearCaches();
    refreshControl();
  }

  public Point getTextSize() {
    if (textSize != null) return textSize;
    if (cachedTextSize == null) {
      cachedTextSize = calcTextSize();
    }
    return cachedTextSize;
  }

  public Point getImageSize() {
    if (imageSize != null) return imageSize;
    if (cachedImageSize == null) {
      cachedImageSize = calcImageSize();
    }
    return cachedImageSize;
  }

  public void setTextSize(Point size) {
    if (size == this.textSize || (size != null && size.equals(this.textSize))) return;
    this.textSize = size;
    cachedTextSize = null;
    refreshControl();
  }

  public void setImageSize(Point size) {
    if (size == this.imageSize || (size != null && size.equals(this.imageSize))) return;
    this.imageSize = size;
    cachedImageSize = null;
    refreshControl();
  }

  protected Point calcTextSize() {
    String string = getText();
    if (!hasText()) {
      if ((style & NO_TEXT) != 0) return new Point(0, 0);
      string = "X"; // $NON-NLS-1$
    }
    Point size;
    GC gc = new GC(getControl().getDisplay());
    try {
      gc.setFont(getControl().getFont());
      size = gc.stringExtent(string);
    } finally {
      gc.dispose();
    }
    if (size.x == 0 && hasText()) size.x = 5;
    return size;
  }

  protected Point calcImageSize() {
    Point size = new Point(0, 0);
    if (hasImage()) {
      Rectangle bounds = image.getBounds();
      size.x = Math.max(size.x, bounds.width);
      size.y = Math.max(size.y, bounds.height);
    }
    return size;
  }

  public void setEnabled(boolean enabled) {
    getControl().setEnabled(enabled);
    refreshControl();
  }

  public boolean isEnabled() {
    return getControl().isEnabled();
  }

  public String getAppliedText() {
    if (appliedText == null) {
      buildCaches();
    }
    return appliedText;
  }

  protected void clearCaches() {
    appliedText = null;
    bounds = null;
    contentArea = null;
    arrowLoc = null;
    imgArea = null;
    textArea = null;
  }

  protected void buildCaches() {
    bounds = control.getClientArea();
    bounds.x += MARGIN;
    bounds.y += MARGIN;
    bounds.width -= MARGIN * 2;
    bounds.height -= MARGIN * 2;
    int x1 = bounds.x + BORDER;
    int y1 = bounds.y + BORDER;
    int w1 = bounds.width - BORDER * 2;
    int h1 = bounds.height - BORDER * 2;
    boolean hasArrows = hasArrows();

    if (hasArrows) {
      arrowLoc =
          new Point(
              x1 + w1 + BORDER / 2 - ARROW_WIDTH,
              y1 + (h1 - ARROW_HEIGHT * 2 - ARROWS_SPACING) / 2 - 1);
    }
    contentArea =
        new Rectangle(x1, y1, w1 - (hasArrows ? ARROW_WIDTH + CONTENT_ARROW_SPACING : 0), h1);

    boolean hasImage = hasImage();
    boolean hasText = hasText();
    if (hasImage) {
      if (hasText) {
        Point imgSize = getImageSize();
        imgArea = new Rectangle(x1, y1, imgSize.x, h1);
      } else {
        imgArea = contentArea;
      }
    }

    if (hasText) {
      if (hasImage) {
        int w = imgArea.width + IMAGE_TEXT_SPACING;
        textArea = new Rectangle(imgArea.x + w, y1, contentArea.width - w, h1);
      } else {
        textArea = contentArea;
      }
      int maxTextWidth = textArea.width;
      Point textSize = getTextSize();
      if (textSize.x > maxTextWidth) {
        GC gc = new GC(getControl().getDisplay());
        try {
          gc.setFont(getControl().getFont());
          appliedText =
              getSubString(gc, text, maxTextWidth - gc.stringExtent(ELLIPSIS).x) + ELLIPSIS;
        } finally {
          gc.dispose();
        }
      } else {
        appliedText = text;
      }
    }
  }

  protected void paint(GC gc, Display display) {
    if (bounds == null) buildCaches();

    gc.setAntialias(SWT.ON);
    gc.setTextAntialias(SWT.ON);

    int x, y, w, h;
    boolean focused = getControl().isFocusControl() || isForceFocus();
    boolean hasBackgroundAndBorder = pressed || hovered || focused;
    if (hasBackgroundAndBorder) {
      // draw control background
      gc.setBackground(getBorderBackground(display));
      gc.fillRoundRectangle(
          bounds.x, bounds.y, bounds.width, bounds.height, CORNER_SIZE, CORNER_SIZE);
    }

    if (focused) {
      // draw focused content background
      x = contentArea.x - FOCUS_BORDER;
      y = contentArea.y - FOCUS_BORDER;
      w = contentArea.width + FOCUS_BORDER * 2;
      h = contentArea.height + FOCUS_BORDER * 2;
      gc.setBackground(getRealTextBackground(display));
      gc.fillRoundRectangle(x, y, w, h, FOCUS_CORNER_SIZE, FOCUS_CORNER_SIZE);
    }

    boolean hasImage = hasImage();
    boolean hasText = hasText();
    if (hasImage) {
      Rectangle clipping = gc.getClipping();
      if (clipping == null || clipping.intersects(imgArea)) {
        // draw image
        Point imgSize = getImageSize();
        x = imgArea.x + (imgArea.width - imgSize.x) / 2;
        y = imgArea.y + (imgArea.height - imgSize.y) / 2;
        gc.setClipping(imgArea);
        gc.drawImage(image, x, y);
        gc.setClipping(clipping);
      }
    }
    if (hasText) {
      Rectangle clipping = gc.getClipping();
      if (clipping == null || clipping.intersects(textArea)) {
        // draw text
        String text = getAppliedText();
        gc.setFont(getControl().getFont());
        Point ext = gc.stringExtent(text);
        //                    if (hasImage) {
        x = textArea.x;
        //                    } else {
        //                        x = textArea.x + (textArea.width - ext.x) / 2;
        //                    }
        y = textArea.y + (textArea.height - ext.y) / 2;
        gc.setClipping(textArea);
        gc.setForeground(getRealTextForeground(display));
        gc.drawString(text, x, y, true);
        gc.setClipping(clipping);
      }
    }

    // draw arrows
    if (hasArrows() && arrowLoc != null) {
      gc.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_WIDGET_NORMAL_SHADOW));
      x = arrowLoc.x + ARROW_WIDTH / 2;
      y = arrowLoc.y;
      int x1 = arrowLoc.x - 1;
      int y1 = arrowLoc.y + ARROW_HEIGHT + 1;
      int x2 = arrowLoc.x + ARROW_WIDTH;
      gc.fillPolygon(new int[] {x, y, x1, y1, x2, y1});

      y += ARROW_HEIGHT * 2 + ARROWS_SPACING + 1;
      x1 = arrowLoc.x;
      y1 += ARROWS_SPACING;
      gc.fillPolygon(new int[] {x, y, x2, y1, x1 - 1, y1});
    }

    // draw border
    if (focused) {
      x = bounds.x;
      y = bounds.y;
      w = bounds.width;
      h = bounds.height;
      if (DRAWS_FOCUS) {
        gc.drawFocus(x - MARGIN + 1, y - MARGIN + 1, w + MARGIN * 2 - 2, h + MARGIN * 2 - 2);
      } else {
        gc.setForeground(getBorderForeground(display, focused));
        gc.drawRoundRectangle(x, y, w, h, CORNER_SIZE, CORNER_SIZE);
      }
    }
  }

  private Color getRealTextForeground(Display display) {
    if (!getControl().isEnabled()) return display.getSystemColor(SWT.COLOR_GRAY);
    if (textForeground != null) return textForeground;
    return display.getSystemColor(SWT.COLOR_LIST_FOREGROUND);
  }

  private Color getRealTextBackground(Display display) {
    if (textBackground != null) return textBackground;
    return display.getSystemColor(SWT.COLOR_LIST_BACKGROUND);
  }

  private Color getBorderBackground(Display display) {
    if (pressed) return display.getSystemColor(SWT.COLOR_WIDGET_BACKGROUND);
    return display.getSystemColor(SWT.COLOR_WIDGET_LIGHT_SHADOW);
  }

  private Color getBorderForeground(Display display, boolean focused) {
    if (focused) return display.getSystemColor(SWT.COLOR_WIDGET_BORDER);
    return display.getSystemColor(SWT.COLOR_WIDGET_NORMAL_SHADOW);
  }

  protected static int checkStyle(int style, int defaultValue, int... bits) {
    for (int bit : bits) {
      int s = style & bit;
      if (s != 0) return s;
    }
    return defaultValue;
  }

  protected static String getSubString(GC gc, String string, int maxWidth) {
    Point ext = gc.stringExtent(string);
    if (ext.x <= maxWidth || string.length() == 0) return string;
    return getSubString(gc, string.substring(0, string.length() - 1), maxWidth);
  }

  public Object getInput() {
    return null;
  }

  public ISelection getSelection() {
    return new StructuredSelection(this);
  }

  public void refresh() {}

  public void refreshControl() {
    getControl().redraw();
  }

  public void setInput(Object input) {}

  public void setSelection(ISelection selection, boolean reveal) {}
}
 static {
   UNIT = Util.isMac() ? "px" : "pt"; // $NON-NLS-1$//$NON-NLS-2$
 }