Work on Tools

This commit is contained in:
Alexander Lobas
2012-02-16 22:18:54 +04:00
parent 4188ab657c
commit 4975b76282
13 changed files with 458 additions and 57 deletions
@@ -35,7 +35,6 @@ public class DecorationLayer extends JComponent {
@Override
public void paint(Graphics g) {
painSelection((Graphics2D)g);
paintChildren(g);
}
@Nullable
@@ -56,6 +56,7 @@ public abstract class DesignerEditorPanel extends JPanel implements ToolProvider
protected JLayeredPane myLayeredPane;
private GlassLayer myGlassLayer;
private DecorationLayer myDecorationLayer;
private FeedbackLayer myFeedbackLayer;
private InputTool myTool;
protected EditableArea mySurfaceArea;
@@ -128,6 +129,16 @@ public abstract class DesignerEditorPanel extends JPanel implements ToolProvider
public ComponentDecorator getRootSelectionDecorator() {
return DesignerEditorPanel.this.getRootSelectionDecorator();
}
@Override
public FeedbackLayer getFeedbackLayer() {
return myFeedbackLayer;
}
@Override
public RadComponent getRootComponent() {
return myRootComponent;
}
};
myGlassLayer = new GlassLayer(this, mySurfaceArea);
@@ -136,6 +147,9 @@ public abstract class DesignerEditorPanel extends JPanel implements ToolProvider
myDecorationLayer = new DecorationLayer(mySurfaceArea);
myLayeredPane.add(myDecorationLayer, LAYER_DECORATION);
myFeedbackLayer = new FeedbackLayer();
myLayeredPane.add(myFeedbackLayer, LAYER_FEEDBACK);
gbc.gridx = 1;
gbc.gridy = 1;
gbc.weightx = 1;
@@ -268,7 +282,7 @@ public abstract class DesignerEditorPanel extends JPanel implements ToolProvider
}
}
private class FindComponentVisitor implements RadComponentVisitor {
private class FindComponentVisitor extends RadComponentVisitor {
private RadComponent myResult;
private final int myX;
private final int myY;
@@ -91,4 +91,8 @@ public abstract class EditableArea {
public abstract InputTool findTargetTool(int x, int y);
public abstract ComponentDecorator getRootSelectionDecorator();
public abstract FeedbackLayer getFeedbackLayer();
public abstract RadComponent getRootComponent();
}
@@ -0,0 +1,24 @@
/*
* Copyright 2000-2012 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 com.intellij.designer.designSurface;
import javax.swing.*;
/**
* @author Alexander Lobas
*/
public class FeedbackLayer extends JComponent {
}
@@ -39,14 +39,15 @@ public class NonResizeSelectionDecorator implements ComponentDecorator {
@Override
public InputTool findTargetTool(DecorationLayer layer, RadComponent component, int x, int y) {
Rectangle bounds = layer.getComponentBounds(component);
int lineWidth = Math.max(myLineWidth, 2);
Rectangle top = new Rectangle(bounds.x, bounds.y, bounds.width, myLineWidth);
Rectangle bottom = new Rectangle(bounds.x, bounds.y + bounds.height - myLineWidth, bounds.width, myLineWidth);
Rectangle left = new Rectangle(bounds.x, bounds.y, myLineWidth, bounds.height);
Rectangle right = new Rectangle(bounds.x + bounds.width - myLineWidth, bounds.y, myLineWidth, bounds.height);
Rectangle top = new Rectangle(bounds.x, bounds.y, bounds.width, lineWidth);
Rectangle bottom = new Rectangle(bounds.x, bounds.y + bounds.height - lineWidth, bounds.width, lineWidth);
Rectangle left = new Rectangle(bounds.x, bounds.y, lineWidth, bounds.height);
Rectangle right = new Rectangle(bounds.x + bounds.width - lineWidth, bounds.y, lineWidth, bounds.height);
if (top.contains(x, y) || bottom.contains(x, y) || left.contains(x, y) || right.contains(x, y)) {
return new DragTracker();
return new DragTracker(component);
}
return null;
@@ -15,13 +15,16 @@
*/
package com.intellij.designer.designSurface.tools;
import com.intellij.designer.model.RadComponent;
import com.intellij.designer.utils.Cursors;
/**
* @author Alexander Lobas
*/
public class DragTracker extends TargetingTool {
public DragTracker() {
public class DragTracker extends SelectionTracker {
public DragTracker(RadComponent component) {
super(component);
setDefaultCursor(Cursors.RESIZE_ALL);
setDisabledCursor(Cursors.getNoCursor());
}
}
@@ -15,8 +15,180 @@
*/
package com.intellij.designer.designSurface.tools;
import com.intellij.designer.designSurface.FeedbackLayer;
import com.intellij.designer.model.RadComponent;
import com.intellij.designer.model.RadComponentVisitor;
import com.intellij.designer.utils.Cursors;
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;
/**
* @author Alexander Lobas
*/
public class MarqueeTracker extends InputTool {
private static final AlphaComposite myComposite1 = AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, 0.3f);
private static final AlphaComposite myComposite2 = AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, 0.6f);
private static final Color myColor = new Color(47, 67, 96);
private static final int TOGGLE_MODE = 1;
private static final int APPEND_MODE = 2;
private JComponent myFeedback;
private int mySelectionMode;
public MarqueeTracker() {
setDefaultCursor(Cursors.CROSS);
setDisabledCursor(Cursors.getNoCursor());
}
@Override
protected void handleButtonDown(int button) {
if (button == MouseEvent.BUTTON1 || button == MouseEvent.BUTTON2) {
if (myState == STATE_INIT) {
myState = STATE_DRAG;
if (myInputEvent.isControlDown()) {
mySelectionMode = TOGGLE_MODE;
}
else if (myInputEvent.isShiftDown()) {
mySelectionMode = APPEND_MODE;
}
}
}
else {
myState = STATE_INVALID;
eraseFeedback();
}
refreshCursor();
}
@Override
protected void handleButtonUp(int button) {
if (myState == STATE_DRAG_IN_PROGRESS) {
myState = STATE_NONE;
eraseFeedback();
performMarqueeSelect();
}
}
@Override
protected void handleDragInProgress() {
if (myState == STATE_DRAG) {
myState = STATE_DRAG_IN_PROGRESS;
refreshCursor();
}
if (myState == STATE_DRAG_IN_PROGRESS) {
showFeedback();
}
}
@Override
public void deactivate() {
if (myState == STATE_DRAG_IN_PROGRESS) {
eraseFeedback();
}
super.deactivate();
}
@Override
protected Cursor calculateCursor() {
if (myState == STATE_DRAG_IN_PROGRESS) {
return getDefaultCursor();
}
else if (myState == STATE_INVALID) {
return getDisabledCursor();
}
else {
return null;
}
}
private void showFeedback() {
FeedbackLayer layer = myArea.getFeedbackLayer();
if (myFeedback == null) {
myFeedback = new JComponent() {
protected void paintComponent(final Graphics g) {
Graphics2D g2d = (Graphics2D)g;
super.paintComponent(g);
final Composite oldComposite = g2d.getComposite();
final Color oldColor = g2d.getColor();
g2d.setColor(myColor);
g2d.setComposite(myComposite1);
g2d.fillRect(0, 0, getWidth(), getHeight());
g2d.setComposite(myComposite2);
g2d.drawRect(0, 0, getWidth() - 1, getHeight() - 1);
g2d.setColor(oldColor);
g2d.setComposite(oldComposite);
}
};
layer.add(myFeedback);
}
myFeedback.setBounds(getSelectionRectangle());
layer.repaint();
}
private void eraseFeedback() {
if (myFeedback != null) {
FeedbackLayer layer = myArea.getFeedbackLayer();
layer.remove(myFeedback);
layer.repaint();
myFeedback = null;
}
}
private Rectangle getSelectionRectangle() {
return new Rectangle(myStartScreenX, myStartScreenY, 0, 0).union(new Rectangle(myCurrentScreenX, myCurrentScreenY, 0, 0));
}
private void performMarqueeSelect() {
final Rectangle selectionRectangle = getSelectionRectangle();
final List<RadComponent> newSelection = new ArrayList<RadComponent>();
myArea.getRootComponent().accept(new RadComponentVisitor() {
@Override
public void endVisit(RadComponent component) {
Rectangle bounds = component.getBounds();
Point location = component.convertPoint(bounds.x, bounds.y, myArea.getNativeComponent());
if (selectionRectangle.contains(location) &&
selectionRectangle.contains(location.x + bounds.width, location.y + bounds.height)) {
newSelection.add(component);
}
}
}, true);
if (mySelectionMode == TOGGLE_MODE) {
List<RadComponent> selection = new ArrayList<RadComponent>(myArea.getSelection());
for (RadComponent component : newSelection) {
int index = selection.indexOf(component);
if (index == -1) {
selection.add(component);
}
else {
selection.remove(index);
}
}
myArea.setSelection(selection);
}
else if (mySelectionMode == APPEND_MODE) {
for (RadComponent component : newSelection) {
myArea.appendSelection(component);
}
}
else {
myArea.setSelection(newSelection);
}
}
}
@@ -18,65 +18,51 @@ package com.intellij.designer.designSurface.tools;
import com.intellij.designer.designSurface.EditableArea;
import com.intellij.designer.model.RadComponent;
import com.intellij.designer.utils.Cursors;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.util.List;
/**
* @author Alexander Lobas
*/
public class SelectionTool extends InputTool {
public SelectionTool() {
setDisabledCursor(Cursors.getNoCursor());
}
private void performSelection(RadComponent component) {
if (myInputEvent.isControlDown()) {
if (myArea.isSelected(component)) {
myArea.deselect(component);
}
else {
myArea.appendSelection(component);
}
}
else if (myInputEvent.isShiftDown()) {
myArea.appendSelection(component);
}
else {
myArea.select(component);
}
}
private InputTool myTracker;
@Override
protected void handleButtonDown(int button) {
if (myState == STATE_INIT && (button == 1 || button == 3)) {
if (myState == STATE_INIT) {
myState = STATE_DRAG;
deactivateTracker();
if (myInputEvent.isAltDown()) {
setTracker(new MarqueeTracker());
return;
}
InputTool tracker = myArea.findTargetTool(myCurrentScreenX, myCurrentScreenY);
if (tracker != null) {
setTracker(tracker);
return;
}
RadComponent component = myArea.findTarget(myCurrentScreenX, myCurrentScreenY);
if (component != null) {
performSelection(component);
}
}
if (button == 1) {
if (myState == STATE_INIT) {
myState = STATE_DRAG;
}
}
else {
if (button == 3) {
myState = STATE_NONE;
if (component == null) {
setTracker(new MarqueeTracker());
}
else {
myState = STATE_INVALID;
setTracker(component.getDragTracker());
}
setCommand(null);
}
}
@Override
protected void handleButtonUp(int button) {
myState = STATE_INIT;
refreshCursor();
setTracker(null);
}
@Override
@@ -92,15 +78,86 @@ public class SelectionTool extends InputTool {
}
}
protected Cursor calculateCursor() {
return myState == STATE_INIT || myState == STATE_DRAG
? getDefaultCursor()
: super.calculateCursor();
@Override
public void deactivate() {
deactivateTracker();
super.deactivate();
}
@Override
public void refreshCursor() {
if (myTracker == null) {
super.refreshCursor();
}
}
private void setTracker(@Nullable InputTool tracker) {
if (myTracker != tracker) {
deactivateTracker();
myTracker = tracker;
refreshCursor();
if (myTracker != null) {
myTracker.setToolProvider(myToolProvider);
myTracker.setArea(myArea);
myTracker.activate();
}
}
}
private void deactivateTracker() {
if (myTracker != null) {
myTracker.deactivate();
myTracker = null;
}
}
@Override
public void mouseDown(MouseEvent event, EditableArea area) throws Exception {
super.mouseDown(event, area);
if (myTracker != null) {
myTracker.mouseDown(event, area);
}
}
@Override
public void mouseUp(MouseEvent event, EditableArea area) throws Exception {
if (myTracker != null) {
myTracker.mouseUp(event, area);
}
super.mouseUp(event, area);
}
@Override
public void mouseMove(MouseEvent event, EditableArea area) throws Exception {
if (myTracker != null) {
myTracker.mouseMove(event, area);
}
super.mouseMove(event, area);
}
@Override
public void mouseDrag(MouseEvent event, EditableArea area) throws Exception {
if (myTracker != null) {
myTracker.mouseDrag(event, area);
}
super.mouseDrag(event, area);
}
@Override
public void mouseDoubleClick(MouseEvent event, EditableArea area) throws Exception {
super.mouseDoubleClick(event, area);
if (myTracker != null) {
myTracker.mouseDoubleClick(event, area);
}
}
@Override
public void keyPressed(KeyEvent event, EditableArea area) throws Exception {
if (event.getKeyCode() == KeyEvent.VK_ESCAPE) {
if (myTracker != null) {
myTracker.keyPressed(event, area);
}
else if (event.getKeyCode() == KeyEvent.VK_ESCAPE) {
List<RadComponent> selection = area.getSelection();
if (!selection.isEmpty()) {
RadComponent component = selection.get(0).getParent();
@@ -110,4 +167,18 @@ public class SelectionTool extends InputTool {
}
}
}
@Override
public void keyTyped(KeyEvent event, EditableArea area) throws Exception {
if (myTracker != null) {
myTracker.keyTyped(event, area);
}
}
@Override
public void keyReleased(KeyEvent event, EditableArea area) throws Exception {
if (myTracker != null) {
myTracker.keyReleased(event, area);
}
}
}
@@ -0,0 +1,105 @@
/*
* Copyright 2000-2012 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 com.intellij.designer.designSurface.tools;
import com.intellij.designer.model.RadComponent;
import java.awt.*;
import java.awt.event.MouseEvent;
/**
* @author Alexander Lobas
*/
public class SelectionTracker extends TargetingTool {
private final RadComponent myComponent;
private boolean mySelected;
public SelectionTracker(RadComponent component) {
myComponent = component;
}
@Override
protected void resetState() {
super.resetState();
mySelected = false;
}
protected Cursor calculateCursor() {
return myState == STATE_INIT || myState == STATE_DRAG
? getDefaultCursor()
: super.calculateCursor();
}
@Override
protected void handleButtonDown(int button) {
if (myState == STATE_INIT &&
(button == MouseEvent.BUTTON1 || button == MouseEvent.BUTTON3) &&
!myArea.isSelected(myComponent)) {
performSelection();
}
if (button == MouseEvent.BUTTON1) {
if (myState == STATE_INIT) {
myState = STATE_DRAG;
}
}
else {
if (button == MouseEvent.BUTTON3) {
myState = STATE_NONE;
}
else {
myState = STATE_INVALID;
}
handleInvalidInput();
}
}
@Override
protected void handleButtonUp(int button) {
if (myState == STATE_DRAG) {
performSelection();
myState = STATE_NONE;
}
}
@Override
protected void handleDragStarted() {
if (myState == STATE_DRAG) {
myState = STATE_DRAG_IN_PROGRESS;
}
}
private void performSelection() {
if (mySelected) {
return;
}
mySelected = true;
if (myInputEvent.isControlDown()) {
if (myArea.isSelected(myComponent)) {
myArea.deselect(myComponent);
}
else {
myArea.appendSelection(myComponent);
}
}
else if (myInputEvent.isShiftDown()) {
myArea.appendSelection(myComponent);
}
else {
myArea.select(myComponent);
}
}
}
@@ -19,4 +19,7 @@ package com.intellij.designer.designSurface.tools;
* @author Alexander Lobas
*/
public abstract class TargetingTool extends InputTool {
protected void handleInvalidInput() {
setCommand(null);
}
}
@@ -15,6 +15,8 @@
*/
package com.intellij.designer.model;
import com.intellij.designer.designSurface.tools.DragTracker;
import com.intellij.designer.designSurface.tools.InputTool;
import com.intellij.designer.propertyTable.Property;
import com.intellij.util.containers.hash.HashMap;
import org.jetbrains.annotations.NotNull;
@@ -54,10 +56,6 @@ public abstract class RadComponent {
return getChildren().toArray();
}
public List<RadComponent> getSurfaceChildren() {
return getChildren();
}
public Rectangle getBounds() {
return null;
}
@@ -70,6 +68,10 @@ public abstract class RadComponent {
return null;
}
public InputTool getDragTracker() {
return new DragTracker(this);
}
public RadLayout getLayout() {
return myLayout;
}
@@ -18,8 +18,10 @@ package com.intellij.designer.model;
/**
* @author Alexander Lobas
*/
public interface RadComponentVisitor {
boolean visit(RadComponent component);
public abstract class RadComponentVisitor {
public boolean visit(RadComponent component) {
return true;
}
void endVisit(RadComponent component);
public abstract void endVisit(RadComponent component);
}
@@ -24,6 +24,7 @@ import java.awt.*;
*/
public final class Cursors {
public static final Cursor RESIZE_ALL = Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR);
public static final Cursor CROSS = Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR);
public static Cursor getNoCursor() {
try {