/*
* 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 jetbrains.mps.nodeEditor.EditorComponent;
import jetbrains.mps.openapi.editor.cells.CellInfo;
import jetbrains.mps.openapi.editor.cells.EditorCell_Collection;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.event.MouseEvent;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
/**
* User: Alexander Shatalin
* Date: 02.03.2010
*/
public class FoldingButtonsPainter extends AbstractFoldingAreaPainter {
private Map<CellInfo, FoldingButton> myFoldingButtons = new HashMap<CellInfo, FoldingButton>();
private FoldingButton myButtonUnderMouse;
private boolean myNeedsRelayout = false;
public FoldingButtonsPainter(LeftEditorHighlighter leftHighlighter) {
super(leftHighlighter);
}
@Override
public void editorRebuilt() {
myFoldingButtons.clear();
EditorComponent editorComponent = getEditorComponent();
for (EditorCell_Collection foldable : editorComponent.getCellTracker().getFoldableCells()) {
assert foldable.getEditorComponent() == editorComponent : "cell must be from my editor";
myFoldingButtons.put(foldable.getCellInfo(), new FoldingButton(foldable, getLeftHighlighter().getBackground()));
}
myNeedsRelayout = true;
}
@Override
public void relayout() {
myNeedsRelayout = true;
}
private void doRelayout() {
for (Iterator<Entry<CellInfo, FoldingButton>> it = myFoldingButtons.entrySet().iterator(); it.hasNext(); ) {
Entry<CellInfo, FoldingButton> nextEntry = it.next();
if (!nextEntry.getValue().relayout()) {
it.remove();
}
}
}
@Override
public int getLeftAreaWidth() {
return myFoldingButtons.isEmpty() ? 0 : FoldingButton.HALF_WIDTH;
}
@Override
public int getRightAreaWidth() {
// same as leftAreaWidth
return getLeftAreaWidth();
}
@Override
public void paintInLocalCoordinates(Graphics g) {
if (myNeedsRelayout) {
myNeedsRelayout = false;
doRelayout();
}
Rectangle clipBounds = g.getClipBounds();
// Painting mouse over feedback "below" all other folding buttons
for (FoldingButton button : myFoldingButtons.values()) {
if (isVisible(button, clipBounds)) {
button.paintFeedback(g);
}
}
for (FoldingButton button : myFoldingButtons.values()) {
if (isVisible(button, clipBounds)) {
button.paint(g);
}
}
}
private boolean isVisible(FoldingButton button, Rectangle clipBounds) {
return !(clipBounds.y + clipBounds.height < button.getY() ||
clipBounds.y > button.getY() + button.getHeight() ||
clipBounds.x + clipBounds.width < -FoldingButton.HALF_WIDTH ||
clipBounds.x > FoldingButton.HALF_WIDTH);
}
@Override
public void mouseMoved(MouseEvent e) {
FoldingButton newButtonUnderMouse = getFoldingButtonUnderMouse(e);
if (newButtonUnderMouse != null) {
e.consume();
}
if (newButtonUnderMouse == myButtonUnderMouse) {
return;
}
if (myButtonUnderMouse != null) {
myButtonUnderMouse.mouseExited(getLeftHighlighter());
repaint(myButtonUnderMouse);
}
if (newButtonUnderMouse != null) {
newButtonUnderMouse.mouseEntered(getLeftHighlighter());
repaint(newButtonUnderMouse);
}
myButtonUnderMouse = newButtonUnderMouse;
}
@Override
public void mouseExited(MouseEvent e) {
if (myButtonUnderMouse != null) {
myButtonUnderMouse.mouseExited(getLeftHighlighter());
repaint(myButtonUnderMouse);
myButtonUnderMouse = null;
}
}
@Override
public void mousePressed(MouseEvent e) {
if (e.getButton() != MouseEvent.BUTTON1) {
return;
}
FoldingButton buttonUnderMouse = getFoldingButtonUnderMouse(e);
if (buttonUnderMouse != null) {
if (e.getID() == MouseEvent.MOUSE_CLICKED) {
buttonUnderMouse.activate(getLocalXCoordinate(e), e.getY());
}
e.consume();
}
}
@Override
public int getWeight() {
return 2;
}
private FoldingButton getFoldingButtonUnderMouse(MouseEvent e) {
int x = getLocalXCoordinate(e);
int y = e.getY();
for (FoldingButton button : myFoldingButtons.values()) {
if (button.isInside(x, y)) {
return button;
}
}
return null;
}
private void repaint(FoldingButton buttonUnderMouse) {
repaint(buttonUnderMouse.getY(), buttonUnderMouse.getHeight());
}
}