<commit_before>package com.readytalk.swt.widgets.buttons.texticon;

import com.readytalk.swt.color.ColorEffect;
import com.readytalk.swt.util.FontFactory;
import com.readytalk.swt.widgets.buttons.texticon.style.ButtonColorEffect;
import com.readytalk.swt.widgets.buttons.texticon.style.ButtonEffect;
import com.readytalk.swt.widgets.buttons.texticon.style.ButtonStyle;
import lombok.extern.java.Log;
import org.eclipse.swt.SWT;
import org.eclipse.swt.SWTException;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;

import java.util.Set;
import java.util.logging.Level;

/**
 * An implementation of ButtonRenderer responsible for drawing the contents of a TextIconButton in various states
 */
@Log
public class TextIconButtonRenderer implements ButtonRenderer {
  private static final int SHADOW_OFFSET = 1;

  protected TextIconButton button;
  protected ButtonStyle style;
  protected GC gc;

  private Point size;
  private Point textSize;
  private Point textIconSize;

  @Override
  public void drawNormal(GC gc, TextIconButton button) {
    style = button.getButtonStyles().getNormal();
    this.gc = gc;
    this.button = button;
    draw();
  }

  @Override
  public void drawHovered(GC gc, TextIconButton button) {
    style = button.getButtonStyles().getHover();
    this.gc = gc;
    this.button = button;
    draw();
  }

  @Override
  public void drawDisabled(GC gc, TextIconButton button) {
    style = button.getButtonStyles().getDisabled();
    this.gc = gc;
    this.button = button;
    draw();
  }

  @Override
  public void drawSelected(GC gc, TextIconButton button) {
    style = button.getButtonStyles().getSelected();
    this.gc = gc;
    this.button = button;
    draw();
  }

  @Override
  public void drawSelectedHovered(GC gc, TextIconButton button) {
    style = button.getButtonStyles().getSelectedHovered();
    this.gc = gc;
    this.button = button;
    draw();
  }

  @Override
  public void drawClicked(GC gc, TextIconButton button) {
    style = button.getButtonStyles().getClicked();
    this.gc = gc;
    this.button = button;
    draw();
  }

  protected void draw() {
    try {
      gc.setAdvanced(true);
      gc.setAntialias(SWT.ON);
      gc.setTextAntialias(SWT.ON);
      gc.setInterpolation(SWT.HIGH);
    } catch (SWTException e) {
      // TODO: log this once
      log.log(Level.WARNING, "Unable to set advanced drawing", e);
    }

    updateSizes();

    drawBackground();
    drawBorder();
    drawIconText();
    drawText();
  }

  private void updateSizes() {
    final Rectangle clientArea = button.getClientArea();

    textSize = computeTextSize();
    textIconSize = computeTextIconSize();

    // If we don't have a usable client area from the parent then use the computed minimum size
    size = (clientArea.width > 0 && clientArea.height > 0) ?
        new Point(clientArea.width, clientArea.height) :
        new Point(computeMinimumWidth(textSize.x, textIconSize.x), computeMinimumHeight(textSize.y, textIconSize.y));
  }

  protected void drawBackground() {
    gc.setBackground(button.getBackground());
    gc.fillRectangle(0, 0, size.x, size.y);
    gc.setBackground(getBackgroundColor(style.getBackgroundColor(), style.getButtonColorEffect()));
    gc.fillRoundRectangle(0, 0, size.x, size.y, style.getRadius(), style.getRadius());
  }

  protected void drawBorder() {
    if (isBorderStyle()) {
      gc.setForeground(getForegroundColor(style.getBorderColor(), style.getButtonColorEffect()));
      gc.setLineWidth(style.getBorderWidth());

      // The border coordinates are the center of the border width so we divide in half to get the center
      gc.drawRoundRectangle(style.getBorderWidth() / 2, style.getBorderWidth() / 2,
          size.x - Math.max(style.getBorderWidth() / 2, style.getBorderWidth()),
          size.y - Math.max(style.getBorderWidth() / 2, style.getBorderWidth()), style.getRadius(), style.getRadius());
    }
  }

  /**
   * Draw text icons at a location based on the style of the button
   */
  protected void drawIconText() {
    final int spacing = textSize.y > 0 ? style.getSpacing() : 0;

    Font font;
    Rectangle bounds;

    // First we draw the drop shadows for each TextIcon layer, if necessary
    if (isIconDropShadowStyle(style.getButtonEffects())) {
      for (TextIcon icon : button.getTextIcons()) {
        font = FontFactory.getIconFont(icon.getFontSize());
        bounds = getIconTextBounds(icon, size.x, size.y, textSize, spacing);

        drawTextAtLocation(gc, icon.getText(), font, getForegroundColor(icon.getColorLabel(), ButtonColorEffect.DARKEN),
            bounds.x + SHADOW_OFFSET, bounds.y + SHADOW_OFFSET);
      }
    }

    // TextIcons can be layered so we loop over them and draw them in place
    for (TextIcon icon : button.getTextIcons()) {
      font = FontFactory.getIconFont(icon.getFontSize());
      bounds = getIconTextBounds(icon, size.x, size.y, textSize, spacing);

      drawTextAtLocation(gc, icon.getText(), font,
          getForegroundColor(icon.getColorLabel(), style.getButtonColorEffect()), bounds.x, bounds.y);
    }
  }

  private Rectangle getIconTextBounds(TextIcon icon, int width, int height, Point textSize, int spacing) {
    // TODO: cache these locations if not changing<commit_msg>Turned off advanced mode for text icons on Windows 7<commit_after>package com.readytalk.swt.widgets.buttons.texticon;

import com.readytalk.swt.color.ColorEffect;
import com.readytalk.swt.util.FontFactory;
import com.readytalk.swt.widgets.buttons.texticon.style.ButtonColorEffect;
import com.readytalk.swt.widgets.buttons.texticon.style.ButtonEffect;
import com.readytalk.swt.widgets.buttons.texticon.style.ButtonStyle;
import lombok.extern.java.Log;
import org.eclipse.swt.SWT;
import org.eclipse.swt.SWTException;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;

import java.util.Set;
import java.util.logging.Level;

/**
 * An implementation of ButtonRenderer responsible for drawing the contents of a TextIconButton in various states
 */
@Log
public class TextIconButtonRenderer implements ButtonRenderer {
  private static final int SHADOW_OFFSET = 1;

  protected TextIconButton button;
  protected ButtonStyle style;
  protected GC gc;

  private Point size;
  private Point textSize;
  private Point textIconSize;

  @Override
  public void drawNormal(GC gc, TextIconButton button) {
    style = button.getButtonStyles().getNormal();
    this.gc = gc;
    this.button = button;
    draw();
  }

  @Override
  public void drawHovered(GC gc, TextIconButton button) {
    style = button.getButtonStyles().getHover();
    this.gc = gc;
    this.button = button;
    draw();
  }

  @Override
  public void drawDisabled(GC gc, TextIconButton button) {
    style = button.getButtonStyles().getDisabled();
    this.gc = gc;
    this.button = button;
    draw();
  }

  @Override
  public void drawSelected(GC gc, TextIconButton button) {
    style = button.getButtonStyles().getSelected();
    this.gc = gc;
    this.button = button;
    draw();
  }

  @Override
  public void drawSelectedHovered(GC gc, TextIconButton button) {
    style = button.getButtonStyles().getSelectedHovered();
    this.gc = gc;
    this.button = button;
    draw();
  }

  @Override
  public void drawClicked(GC gc, TextIconButton button) {
    style = button.getButtonStyles().getClicked();
    this.gc = gc;
    this.button = button;
    draw();
  }

  protected void draw() {
    try {
      gc.setAdvanced(true);
      gc.setAntialias(SWT.ON);
      gc.setTextAntialias(SWT.ON);
      gc.setInterpolation(SWT.HIGH);
    } catch (SWTException e) {
      // TODO: log this once
      log.log(Level.WARNING, "Unable to set advanced drawing", e);
    }

    updateSizes();

    drawBackground();
    drawBorder();
    drawIconText();
    drawText();
  }

  private void updateSizes() {
    final Rectangle clientArea = button.getClientArea();

    textSize = computeTextSize();
    textIconSize = computeTextIconSize();

    // If we don't have a usable client area from the parent then use the computed minimum size
    size = (clientArea.width > 0 && clientArea.height > 0) ?
        new Point(clientArea.width, clientArea.height) :
        new Point(computeMinimumWidth(textSize.x, textIconSize.x), computeMinimumHeight(textSize.y, textIconSize.y));
  }

  protected void drawBackground() {
    gc.setBackground(button.getBackground());
    gc.fillRectangle(0, 0, size.x, size.y);
    gc.setBackground(getBackgroundColor(style.getBackgroundColor(), style.getButtonColorEffect()));
    gc.fillRoundRectangle(0, 0, size.x, size.y, style.getRadius(), style.getRadius());
  }

  protected void drawBorder() {
    if (isBorderStyle()) {
      gc.setForeground(getForegroundColor(style.getBorderColor(), style.getButtonColorEffect()));
      gc.setLineWidth(style.getBorderWidth());

      // The border coordinates are the center of the border width so we divide in half to get the center
      gc.drawRoundRectangle(style.getBorderWidth() / 2, style.getBorderWidth() / 2,
          size.x - Math.max(style.getBorderWidth() / 2, style.getBorderWidth()),
          size.y - Math.max(style.getBorderWidth() / 2, style.getBorderWidth()), style.getRadius(), style.getRadius());
    }
  }

  private boolean isWindows7() {
    boolean windows7 = false;
    String swtPlatform = SWT.getPlatform();
    if(swtPlatform.equals("win32")) {
      double version;
      try {
        version = Float.parseFloat(System.getProperty("os.version"));
        windows7 = version <= 7.0;
      } catch (NumberFormatException ex) {
        windows7 = true;
      }
    }
    return windows7;
  }

  /**
   * Draw text icons at a location based on the style of the button
   */
  protected void drawIconText() {
    final int spacing = textSize.y > 0 ? style.getSpacing() : 0;

    Font font;
    Rectangle bounds;

    //Windows 7/under will not render FontAwesome in advanced mode, so disable advanced.
    if(isWindows7()) {
      gc.setAdvanced(false);
    }

    // First we draw the drop shadows for each TextIcon layer, if necessary
    if (isIconDropShadowStyle(style.getButtonEffects())) {
      for (TextIcon icon : button.getTextIcons()) {
        font = FontFactory.getIconFont(icon.getFontSize());
        bounds = getIconTextBounds(icon, size.x, size.y, textSize, spacing);

        drawTextAtLocation(gc, icon.getText(), font, getForegroundColor(icon.getColorLabel(), ButtonColorEffect.DARKEN),
            bounds.x + SHADOW_OFFSET, bounds.y + SHADOW_OFFSET);
      }
    }

    // TextIcons can be layered so we loop over them and draw them in place
    for (TextIcon icon : button.getTextIcons()) {
      font = FontFactory.getIconFont(icon.getFontSize());
      bounds = getIconTextBounds(icon, size.x, size.y, textSize, spacing);

      drawTextAtLocation(gc, icon.getText(), font,
          getForegroundColor(icon.getColorLabel(), style.getButtonColorEffect()), bounds.x, bounds.y);
    }
    if(isWindows7()) {
      gc.setAdvanced(true);
    }
  }

  private Rectangle getIconTextBounds(TextIcon icon, int width, int height, Point textSize, int spacing) {
    // TODO: cache these locations if not changing
{'fraction_non_alphanumeric': 0.11456327673726588, 'fraction_numerical': 0.0034132679852966917, 'mean_word_length': 3.5148162781509287, 'pattern_counts': {'":': 0, '<': 4, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5221167', 'n_tokens_mistral': 3562, 'n_tokens_neox': 3446, 'n_words': 849}