Package com.redcareditor.mate.colouring.swt

Source Code of com.redcareditor.mate.colouring.swt.SwtColourer$StyleRangeComparator

package com.redcareditor.mate.colouring.swt;

import java.util.ArrayList;
import java.util.Comparator;

import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.CaretEvent;
import org.eclipse.swt.custom.CaretListener;
import org.eclipse.swt.custom.LineStyleEvent;
import org.eclipse.swt.custom.LineBackgroundEvent;
import org.eclipse.swt.custom.LineBackgroundListener;
import org.eclipse.swt.custom.LineStyleListener;
import org.eclipse.swt.custom.StyleRange;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.VerifyEvent;
import org.eclipse.swt.events.VerifyListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.ImageData;
import org.eclipse.swt.graphics.PaletteData;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Caret;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;

import com.redcareditor.mate.DoublePattern;
import com.redcareditor.mate.MateText;
import com.redcareditor.mate.Scope;
import com.redcareditor.mate.SinglePattern;
import com.redcareditor.mate.colouring.Colourer;
import com.redcareditor.theme.Theme;
import com.redcareditor.theme.ThemeSetting;
import com.redcareditor.util.swt.ColourUtil;

public class SwtColourer implements Colourer {
  private Theme theme;
  private MateText mateText;

  private int highlightedLine = 0;
  private StyledText control;

  public SwtColourer(MateText mt) {
    mateText = mt;
   
    control = mateText.getControl();
   
    this.control.addPaintListener(new MarginPaintListener(mateText));
    this.control.addLineStyleListener(new LineStyleListener() {
      public void lineGetStyle(LineStyleEvent event) {
        colourLine(event);
      }
    });
    // this.control.addLineBackgroundListener(new LineBackgroundListener() {
    //   public void lineGetBackground(LineBackgroundEvent event) {
    //     int eventLine = control.getLineAtOffset(event.lineOffset);
    //     int caretLine = control.getLineAtOffset(control.getCaretOffset());
    //     if (eventLine == caretLine) {
    //       event.lineBackground = ColourUtil.getColour(globalLineBackground());
    //       highlightedLine = eventLine;
    //     }
    //   }
    // });
    //
    // control.addCaretListener(new CaretListener() {
    //   public void caretMoved(CaretEvent e) {
    //     int line = control.getLineAtOffset(e.caretOffset);
    //     System.out.printf("caretMoved(%d)\n", line);
    //     if (line == highlightedLine) return;
    //     redrawLine(highlightedLine);
    //     redrawLine(line);
    //   }
    // });
  }
 
  // private void redrawLine(int line) {
  //   int maxPossibleLine = control.getLineCount() - 1;
  //   System.out.printf("redrawLine(%d) (maxPossibleLine: %d)\n", line, maxPossibleLine);
  //   if (line > maxPossibleLine) return;
  //   int startOffset = control.getOffsetAtLine(line);
//
  //   int endOffset;   
  //   if (line == maxPossibleLine) {
  //     endOffset = control.getCharCount();
  //   } else {
  //     endOffset = control.getOffsetAtLine(line + 1);
  //   }
  //   int length = endOffset - startOffset;
  //   length = length < 0 ? 0 : length;
  //   control.redrawRange(startOffset, length, false);
  // }
 
  public void setTheme(Theme theme) {
    this.theme = theme;
    theme.initForUse();
    setGlobalColours();
  }

  public void setGlobalColours() {
    if (theme != null) {
      setMateTextColours();
      setCaretColour();
    }
  }

  private void setCaretColour() {
    Caret caret = control.getCaret();
    Rectangle bounds = caret.getBounds();
    int width = bounds.width;
    int height = bounds.height;
    caret = new Caret(control, SWT.NONE);
    Display display = Display.getCurrent();
    // System.out.printf("caret colour: %s %d %d\n", globalColour("caret"), width, height);
    String caretColourString = bareGlobalColour("caret");
    Color caretColour = ColourUtil.getColour(caretColourString);
    Color white = display.getSystemColor(SWT.COLOR_WHITE);
    Color black = display.getSystemColor(SWT.COLOR_BLACK);
    String backgroundColourString = globalBackground();
    int red = Integer.parseInt(backgroundColourString.substring(1, 3), 16) ^
          Integer.parseInt(caretColourString.substring(1, 3), 16);
    int green = Integer.parseInt(backgroundColourString.substring(3, 5), 16) ^
            Integer.parseInt(caretColourString.substring(3, 5), 16);
    int blue = Integer.parseInt(backgroundColourString.substring(5, 7), 16) ^
            Integer.parseInt(caretColourString.substring(5, 7), 16);
    PaletteData palette = new PaletteData (
      new RGB [] {
        new RGB (0, 0, 0),
        new RGB (red, green, blue),
        new RGB (0xFF, 0xFF, 0xFF),
      });
    ImageData maskData = new ImageData (1, height, 2, palette);
    for (int y=0; y < height; y++)
      maskData.setPixel(0, y, 1);
    Image image = new Image (display, maskData);
    caret.setImage(image);
    control.setCaret(caret);
  }

  private void setMateTextColours() {
    control.setBackground(ColourUtil.getColour(globalBackground()));
    control.setForeground(ColourUtil.getColour(globalForeground()));
    int currentLine = control.getLineAtOffset(control.getCaretOffset());
//    int startLine = JFaceTextUtil.getPartialTopIndex(control);
  //  int endLine = JFaceTextUtil.getPartialBottomIndex(control);
    for (int i = 0; i < control.getLineCount(); i ++)
      control.setLineBackground(i, 1, ColourUtil.getColour(globalBackground()));
    control.setLineBackground(currentLine, 1, ColourUtil.getColour(globalLineBackground()));
    if (mateText.getCompositeRuler() != null) {
          Composite rulerControl = (Composite) mateText.getCompositeRuler().getControl();
          for (Control c : rulerControl.getChildren()) {
              c.setBackground(ColourUtil.getColour(globalLineBackground()));
              c.setForeground(ColourUtil.getColour(globalForeground()));
          }
          rulerControl.getParent().setBackground(ColourUtil.getColour(globalLineBackground()));
    }
    mateText.setGutterBackground(ColourUtil.getColour(globalLineBackground()));
    mateText.setGutterForeground(ColourUtil.getColour(globalForeground()));
  }

  public Theme getTheme() {
    return theme;
  }

  private ThemeSetting globalThemeSetting() {
    if (mateText.parser != null && mateText.parser.grammar != null && theme != null) {
      return theme.findSetting(mateText.parser.grammar.scopeName, false, null);
    }
    else {
      return new ThemeSetting();
    }
  }

  private String globalBackground() {
    ThemeSetting globalSetting = globalThemeSetting();
    if (globalSetting.background == null) {
      return bareGlobalColour("background");
    }
    else {
      return globalSetting.background;
    }
  }

  private String globalForeground() {
    ThemeSetting globalSetting = globalThemeSetting();
    if (globalSetting.foreground == null) {
      return bareGlobalColour("foreground");
    }
    else {
      return globalSetting.foreground;
    }
  }

  private String globalLineBackground() {
    return ColourUtil.mergeColour(globalBackground(), bareGlobalColour("lineHighlight"));
  }

  private String bareGlobalColour(String name) {
    if (theme == null)
      return "#FFFFFF";
    String colour = theme.globalSettings.get(name);
    if (isColorDefined(colour)) {
      return colour;
    } else {
      return "#FFFFFF";
    }
  }

  private boolean themeHasMarginColours() {
    return (theme.globalSettings.get("marginForeground") != null &&
        theme.globalSettings.get("marginBackground") != null);
  }

  private Color globalMarginForeground() {
    return ColourUtil.getColour(theme.globalSettings.get("marginForeground"));
  }

    private Color globalMarginBackground() {
        return ColourUtil.getColour(theme.globalSettings.get("marginBackground"));
    }

  private boolean isColorDefined(String colour) {
    return colour != null && !(colour.length() == 0);
  }

  public class StyleRangeComparator implements Comparator {

    public int compare(Object o1, Object o2) {
      StyleRange s1 = (StyleRange) o1;
      StyleRange s2 = (StyleRange) o2;
      if (s1.start < s2.start) {
        return -1;
      } else {
        if (s1.start > s2.start) {
          return 1;
        }
        else {
           if (s1.length < s2.length) {
            return -1;
          }
          else {
            if (s1.length > s2.length) {
              return 1;
            }
            else {
              return 0;
            }
          }
        }
      }
    }

    public boolean equals(Object obj) {
      return false;
    }
  }

  private void colourLine(LineStyleEvent event) {
    if (theme == null)
      return;
    if (!mateText.shouldColour())
      return;
    int eventLine = mateText.getControl().getLineAtOffset(event.lineOffset);
    // System.out.printf("c%d, ", eventLine);

    // ArrayList<Scope> scopes = mateText.parser.root.scopesOnLine(eventLine);
    int startLineOffset = event.lineOffset;
    int endLineOffset;

    if (eventLine >= mateText.getControl().getLineCount() - 1)
      endLineOffset = mateText.getControl().getCharCount();
    else
      endLineOffset = mateText.getControl().getOffsetAtLine(eventLine + 1);

    ArrayList<Scope> scopes = mateText.parser.root.scopesBetween(startLineOffset, endLineOffset);
    //System.out.printf("[Color] colouring %d (%d-%d) n%d\n", eventLine, startLineOffset, endLineOffset, scopes.size());

    // System.out.printf("[Color] got to colour %d scopes\n", scopes.size());
    ArrayList<StyleRange> styleRanges = new ArrayList<StyleRange>();
    for (Scope scope : scopes) {
      // System.out.printf("[Color] scope: %s\n", scope.name);
      if (scope.parent == null) {
        continue;
      }
      if (scope.name == null && scope.pattern != null
          && (scope.pattern instanceof SinglePattern || ((DoublePattern) scope.pattern).contentName == null)) {
        continue;
      }
      addStyleRangeForScope(styleRanges, scope, false, event);
      if (scope.pattern instanceof DoublePattern && ((DoublePattern) scope.pattern).contentName != null && scope.isCapture == false)
        addStyleRangeForScope(styleRanges, scope, true, event);
      // printStyleRanges(styleRanges);
    }
    int tabWidth = mateText.getControl().getTabs();
    addMarginColumnStyleRange(styleRanges, event, tabWidth);

    event.styles = (StyleRange[]) styleRanges.toArray(new StyleRange[0]);
  }

  private void printStyleRanges(ArrayList<StyleRange> styleRanges) {
    System.out.printf("[");
    for (StyleRange r : styleRanges) {
      System.out.printf("%s, ", r);
    }
    System.out.printf("]\n");
  }

  private void addStyleRangeForScope(ArrayList<StyleRange> styleRanges, Scope scope, boolean inner, LineStyleEvent event) {
    StyleRange styleRange = new StyleRange();

    ThemeSetting setting = null;
    ThemeSetting excludeSetting = null;
    if (scope.parent != null)
      excludeSetting = scope.parent.themeSetting;
    setting = theme.settingsForScope(scope, inner, null);

    int startLineOffset = event.lineOffset;
    int endLineOffset   = startLineOffset + event.lineText.length();

    if (inner) {
      styleRange.start = Math.max(scope.getInnerStart().getOffset(), startLineOffset);
      styleRange.length = Math.min(scope.getInnerEnd().getOffset() - styleRange.start,
                     event.lineText.length() - styleRange.start + startLineOffset);
    } else {
      styleRange.start = Math.max(scope.getStart().getOffset(), startLineOffset);
      styleRange.length = Math.min(scope.getEnd().getOffset() - styleRange.start,
                     event.lineText.length() - styleRange.start + startLineOffset);
    }
    if (styleRange.length == 0)
      return;
    if (setting != null) {
      setStyleRangeProperties(scope, setting, styleRange);
      addStyleRangeWithoutOverlaps(styleRanges, styleRange);
      //System.out.printf("[Color] style range (%d, %d) %s\n", styleRange.start, styleRange.length, styleRange.toString());
    }
  }

  private void addMarginColumnStyleRange(ArrayList<StyleRange> styleRanges, LineStyleEvent event, int tabWidth) {
    int marginColumn = mateText.getMarginColumn();

    if (marginColumn == -1 || !themeHasMarginColours())
      return;

    int startLineOffset = event.lineOffset;
    int endLineOffset   = startLineOffset + event.lineText.length();
    int maxColumn       = MateText.columnOfLineOffset(event.lineText, endLineOffset - startLineOffset, tabWidth);

    if (maxColumn <= marginColumn)
      return;

    StyleRange styleRange = new StyleRange();

    int offsetOfColumn = MateText.lineOffsetOfColumn(event.lineText, marginColumn, tabWidth);
    styleRange.start = startLineOffset + offsetOfColumn;
    styleRange.length = endLineOffset - styleRange.start;

    styleRange.background = globalMarginBackground();
    styleRange.foreground = globalMarginForeground();

    addStyleRangeWithoutOverlaps(styleRanges, styleRange);
  }

  private void addStyleRangeWithoutOverlaps(ArrayList<StyleRange> styleRanges, StyleRange styleRange) {
    if (styleRanges.size() == 0) {
      styleRanges.add(styleRange);
      return;
    }

    // there is always an overlapping StyleRange because the document root scope is always in here
    int indexOfParent = indexOfOverlappingStyleRange(styleRanges, styleRange);
    if (indexOfParent == -1) {
      styleRanges.add(styleRange);
      return;
    }

    StyleRange parentStyleRange = styleRanges.get(indexOfParent);

    int parentStart = parentStyleRange.start;
    int parentEnd   = parentStyleRange.start + parentStyleRange.length;
    int childStart  = styleRange.start;
    int childEnd    = styleRange.start + styleRange.length;

    //System.out.printf("parent %d-%d, child: %d-%d\n", parentStart, parentEnd, childStart, childEnd);

    // *-----*
    // *-----*
    if (parentStart == childStart && parentEnd == childEnd) {
      styleRangeCopyValues(parentStyleRange, styleRange);
      return;
    }

    // *------*
    // *--*
    if (childStart == parentStart) {
      parentStyleRange.start = childEnd;
      parentStyleRange.length -= styleRange.length;
      styleRanges.add(indexOfParent, styleRange);
      return;
    }

    // *------*
    //    *---*
    if (childEnd == parentEnd) {
      parentStyleRange.length = childStart - parentStart;
      styleRanges.add(indexOfParent + 1, styleRange);
      return;
    }

    // *----------*
    //    *---*
    parentStyleRange.length = childStart - parentStart;
    styleRanges.add(indexOfParent + 1, styleRange);
    StyleRange newStyleRange = new StyleRange();
    newStyleRange.start = childEnd;
    newStyleRange.length = parentEnd - childEnd;
    styleRangeCopyValues(newStyleRange, parentStyleRange);
    styleRanges.add(indexOfParent + 2, newStyleRange);
  }

  private void styleRangeCopyValues(StyleRange target, StyleRange source) {
    target.fontStyle = source.fontStyle;
    target.foreground = source.foreground;
    target.background = source.background;
    target.underline = source.underline;
  }

  private int indexOfOverlappingStyleRange(ArrayList<StyleRange> styleRanges, StyleRange styleRange) {
    int i = 0;
    for (StyleRange possibleParent : styleRanges) {
      if (possibleParent.start < styleRange.start + styleRange.length &&
        possibleParent.start + possibleParent.length > styleRange.start)
        return i;
      i++;
    }
    return -1;
  }

  private void setStyleRangeProperties(Scope scope, ThemeSetting setting, StyleRange styleRange) {
    String fontStyle = setting.fontStyle;
    if (fontStyle != null) {
      // TODO: make this support "bold italic" etc.
      if (fontStyle.equals("italic")) {
        styleRange.fontStyle = SWT.ITALIC;
      }
      if (fontStyle.equals("bold")) {
        styleRange.fontStyle = SWT.BOLD;
      }
      if (fontStyle.equals("underline")) {
        styleRange.underline = true;
      }
    }

    String background = setting.background;
    // System.out.printf("[Color] scope background: %s\n", background);
    String mergedBgColour;
    String parentBg = globalBackground();
    //System.out.printf("       global background: %s\n", parentBg);
    if (background != null && background != "") {
      mergedBgColour = ColourUtil.mergeColour(parentBg, background);
      if (mergedBgColour != null) {
        scope.bgColour = mergedBgColour;
        styleRange.background = ColourUtil.getColour(mergedBgColour);
        // System.out.printf("[Color] background = %s\n", mergedBgColour);
      }
    } else {
      mergedBgColour = parentBg;
    }
    // stdout.printf("      merged_bg_colour:   %s\n", merged_bg_colour);
    String foreground = setting.foreground;
    // System.out.printf("[Color] scope foreground: %s\n", foreground);
    String parentFg = scope.nearestForegroundColour();
    if (parentFg == null) {
      parentFg = globalForeground();
      // stdout.printf("      global foreground:    %s\n",
      // parent_fg);
    }
    if (foreground != null && foreground != "") {
      String mergedFgColour;
      if (parentFg != null && !scope.isCapture)
        mergedFgColour = ColourUtil.mergeColour(parentFg, foreground);
      else
        mergedFgColour = foreground;
      if (mergedFgColour != null) {
        scope.fgColour = mergedFgColour;
        styleRange.foreground = ColourUtil.getColour(mergedFgColour);
      }
      // stdout.printf("     merged_fg_colour: %s\n", merged_fg_colour);
    }
    // stdout.printf("\n");
  }

}
TOP

Related Classes of com.redcareditor.mate.colouring.swt.SwtColourer$StyleRangeComparator

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.