/* * Copyright 2003-2011 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jetbrains.mps.nodeEditor.leftHighlighter; import com.intellij.openapi.editor.colors.EditorColors; import com.intellij.openapi.editor.colors.EditorColorsManager; import jetbrains.mps.openapi.editor.EditorComponent; import jetbrains.mps.openapi.editor.cells.CellInfo; import jetbrains.mps.openapi.editor.cells.CellTraversalUtil; import jetbrains.mps.openapi.editor.cells.EditorCell; import jetbrains.mps.openapi.editor.cells.EditorCell_Collection; import org.jetbrains.annotations.NotNull; import javax.swing.JScrollBar; import java.awt.Color; import java.awt.Component; import java.awt.Cursor; import java.awt.Graphics; /** * User: Alexander Shatalin * Date: 02.03.2010 */ class FoldingButton { public static final int HALF_WIDTH = 4; private static final int HEIGHT = HALF_WIDTH * 5 / 2; private static final int CANT_HEIGHT = HALF_WIDTH * 3 / 2; private CellInfo myCellInfo; private EditorComponent myEditor; private int myY1; private int myY2; private boolean myIsHidden = false; private boolean myIsFolded = false; private boolean myMouseOver = false; private Color myBackgroundColor; FoldingButton(@NotNull EditorCell_Collection cell, @NotNull Color background) { //TODO: Can we hold cell directly instad of CellInfo here? myCellInfo = cell.getCellInfo(); assert myCellInfo != null : "CellInfo unavailable for: " + cell; myEditor = cell.getEditorComponent(); myBackgroundColor = background; } boolean relayout() { EditorCell cell = getCell(); if (cell == null) { myIsHidden = true; return true; } if (cell instanceof EditorCell_Collection) { EditorCell_Collection collectionCell = (EditorCell_Collection) cell; myIsHidden = CellTraversalUtil.getFoldedParent(collectionCell) != null; if (!myIsHidden) { myIsFolded = collectionCell.isCollapsed(); EditorCell firstLeafCell = CellTraversalUtil.getFirstLeaf(collectionCell); myY1 = firstLeafCell != null ? firstLeafCell.getBaseline() - HEIGHT : collectionCell.getBaseline() - HEIGHT; EditorCell lastLeafCell = CellTraversalUtil.getLastLeaf(collectionCell); myY2 = lastLeafCell != null ? CellTraversalUtil.getLastLeaf(collectionCell).getBaseline() : collectionCell.getBaseline(); if (!myIsFolded && myY2 - myY1 < 2 * HEIGHT) { // to avoid overlapping folding buttons myIsHidden = true; } } return true; } return false; } private Color getBorderColor() { return myMouseOver ? EditorColorsManager.getInstance().getGlobalScheme().getColor(EditorColors.SELECTED_TEARLINE_COLOR) : EditorColorsManager.getInstance().getGlobalScheme().getColor(EditorColors.TEARLINE_COLOR); } void paintFeedback(Graphics g) { if (myMouseOver && !myIsFolded) { g.setColor(getBorderColor()); g.drawLine(0, myY1 + HEIGHT, 0, myY2 - HEIGHT); } } void paint(Graphics g) { if (myIsHidden) { return; } Color borderColor = getBorderColor(); if (!myIsFolded) { int xs[] = {-HALF_WIDTH, -HALF_WIDTH, 0, HALF_WIDTH, HALF_WIDTH}; int ys[] = {myY1, myY1 + CANT_HEIGHT, myY1 + HEIGHT, myY1 + CANT_HEIGHT, myY1}; g.setColor(myBackgroundColor); g.fillPolygon(xs, ys, xs.length); g.setColor(borderColor); g.drawPolygon(xs, ys, xs.length); for (int i = 0; i < xs.length; i++) { ys[i] = myY2 - (ys[i] - myY1); } g.setColor(myBackgroundColor); g.fillPolygon(xs, ys, xs.length); g.setColor(borderColor); g.drawPolygon(xs, ys, xs.length); g.setColor(borderColor); g.drawLine(-HALF_WIDTH / 2, myY1 + HALF_WIDTH, HALF_WIDTH / 2, myY1 + HALF_WIDTH); g.drawLine(-HALF_WIDTH / 2, myY2 - HALF_WIDTH, HALF_WIDTH / 2, myY2 - HALF_WIDTH); } else { g.setColor(myBackgroundColor); g.fillRect(-HALF_WIDTH, myY1, HALF_WIDTH * 2, HALF_WIDTH * 2); g.setColor(borderColor); g.drawRect(-HALF_WIDTH, myY1, HALF_WIDTH * 2, HALF_WIDTH * 2); g.drawLine(-HALF_WIDTH / 2, myY1 + HALF_WIDTH, HALF_WIDTH / 2, myY1 + HALF_WIDTH); g.drawLine(0, myY1 + HALF_WIDTH / 2, 0, myY1 + HALF_WIDTH * 3 / 2); } } private EditorCell getCell() { return myCellInfo.findCell(myEditor); } void activate(int x, int y) { EditorCell cell = getCell(); if (cell instanceof EditorCell_Collection) { EditorCell_Collection collection = (EditorCell_Collection) cell; if (CellTraversalUtil.getFoldedParent(collection) != null) { return; } if (collection.isCollapsed()) { collection.unfold(); } else { if (isOnBottomButton(y)) { JScrollBar verticalScrollBar = ((jetbrains.mps.nodeEditor.EditorComponent) myEditor).getVerticalScrollBar(); verticalScrollBar.setValue(Math.max(verticalScrollBar.getValue() - (myY2 - myY1 - HEIGHT), 0)); } collection.fold(); } } } void mouseEntered(Component component) { component.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); myMouseOver = true; } void mouseExited(Component component) { component.setCursor(null); myMouseOver = false; } boolean isInside(int x, int y) { if (myIsHidden) { return false; } if (myIsFolded) { return Math.abs(x) <= HALF_WIDTH && isOnTopButton(y); } else { return Math.abs(x) <= HALF_WIDTH && (isOnTopButton(y) || isOnBottomButton(y)); } } private boolean isOnTopButton(int y) { return myY1 <= y && y <= myY1 + HEIGHT; } private boolean isOnBottomButton(int y) { return myY2 - HEIGHT <= y && y <= myY2; } int getY() { return myY1; } int getHeight() { return myY2 - myY1; } }