1   /****************************************************************************
2    * This demo file is part of yFiles for Java 2.14.
3    * Copyright (c) 2000-2017 by yWorks GmbH, Vor dem Kreuzberg 28,
4    * 72070 Tuebingen, Germany. All rights reserved.
5    * 
6    * yFiles demo files exhibit yFiles for Java functionalities. Any redistribution
7    * of demo files in source code or binary form, with or without
8    * modification, is not permitted.
9    * 
10   * Owners of a valid software license for a yFiles for Java version that this
11   * demo is shipped with are allowed to use the demo source code as basis
12   * for their own yFiles for Java powered applications. Use of such programs is
13   * governed by the rights and conditions as set out in the yFiles for Java
14   * license agreement.
15   * 
16   * THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESS OR IMPLIED
17   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18   * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
19   * NO EVENT SHALL yWorks BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
21   * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22   * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
23   * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
24   * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25   * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26   *
27   ***************************************************************************/
28  package demo.view.uml;
29  
30  import y.view.AbstractMouseInputEditor;
31  import y.view.Graph2DView;
32  import y.view.Mouse2DEvent;
33  import y.view.MouseInputEditor;
34  import y.view.NodeRealizer;
35  
36  import java.awt.Graphics2D;
37  import java.awt.geom.Rectangle2D;
38  
39  /**
40   * Base class for UML class button implementations.
41   * Subclasses must implement the method {@link #getButtonArea(y.view.NodeRealizer)} to specify the size and the position
42   * of the button. The implementation of {@link #paint(y.view.NodeRealizer, java.awt.Graphics2D)} draws the button in
43   * that area.
44   * To react on mouse interactions subclasses can implement the following methods:
45   * <ul>
46   *   <li>{@link #buttonClicked(y.view.NodeRealizer, y.view.Graph2DView)}</li> is called when the mouse clicks within the button.
47   *   <li>{@link #buttonEntered(y.view.NodeRealizer, y.view.Graph2DView)}</li> is called when the mouse enters the button.
48   *   <li>{@link #buttonExited(y.view.NodeRealizer, y.view.Graph2DView)}</li> is called when the mouse leaves the button.
49   * </ul>
50   */
51  abstract class UmlClassButton {
52    /**
53     * Paints the button.
54     */
55    public abstract void paint(final NodeRealizer context, final Graphics2D graphics);
56  
57    /**
58     * Checks whether or not the button is visible.
59     */
60    protected abstract boolean isVisible(NodeRealizer context);
61  
62    /**
63     * Checks if the given point is within the button.
64     */
65    public boolean contains(final NodeRealizer context, final double x, final double y) {
66      return isVisible(context) && getButtonArea(context).contains(x, y);
67    }
68  
69    /**
70     * Returns the size and the position of the button.
71     */
72    protected abstract Rectangle2D getButtonArea(NodeRealizer context);
73  
74    /**
75     * Could be overwritten to react when the mouse clicks within the button.
76     */
77    protected void buttonClicked(NodeRealizer context, Graph2DView view) {}
78  
79    /**
80     * Could be overwritten to react when the mouse enters the button.
81     */
82    protected void buttonEntered(NodeRealizer context, Graph2DView view) {}
83  
84    /**
85     * Resets an appropriate style property of the given context to notify that the mouse is currently not over this
86     * button.
87     */
88    protected void buttonExited(NodeRealizer context, Graph2DView view) {
89      UmlRealizerFactory.setMouseOverButton(context, UmlRealizerFactory.BUTTON_NONE);
90      view.updateView(getButtonArea(context));
91    }
92  
93    /**
94     * Returns an {@link MouseInputEditor} to handle mouse events for the button.
95     */
96    public MouseInputEditor getMouseInputEditor(final NodeRealizer context, final Graph2DView view) {
97      return new ButtonMouseInputEditor(context, view);
98    }
99  
100   /**
101    * An {@link MouseInputEditor} to handle mouse events for the button. The editor gets mouse events and forwards them
102    * to the following methods:
103    * <ul>
104    *   <li>{@link #buttonClicked(y.view.NodeRealizer, y.view.Graph2DView)}</li>
105    *   <li>{@link #buttonEntered(y.view.NodeRealizer, y.view.Graph2DView)}</li>
106    *   <li>{@link #buttonExited(y.view.NodeRealizer, y.view.Graph2DView)}</li>
107    * </ul>
108    * when the mouse event is within the button.
109    */
110   private class ButtonMouseInputEditor extends AbstractMouseInputEditor {
111     private final NodeRealizer context;
112     private final Graph2DView view;
113 
114     private ButtonMouseInputEditor(final NodeRealizer context, final Graph2DView view) {
115       this.context = context;
116       this.view = view;
117     }
118 
119     public boolean startsEditing(final Mouse2DEvent event) {
120       return isDetailed() && contains(context, event.getX(), event.getY());
121     }
122 
123     /**
124      * Overridden to notify when the mouse enters the button.
125      */
126     public void startEditing() {
127       if (isDetailed()) {
128         buttonEntered(context, view);
129         super.startEditing();
130       }
131     }
132 
133     /**
134      * Overridden to notify when the mouse leaves the button.
135      */
136     public void stopEditing() {
137       if (isDetailed()) {
138         buttonExited(context, view);
139         super.stopEditing();
140       }
141     }
142 
143     /**
144      * Overridden to notify when the mouse clicks the button.
145      */
146     public void mouse2DEventHappened(final Mouse2DEvent event) {
147       if (!contains(context, event.getX(), event.getY())) {
148         stopEditing();
149         return;
150       }
151 
152       if ((event.getId() == Mouse2DEvent.MOUSE_CLICKED) && isDetailed()) {
153         buttonClicked(context, view);
154         stopEditing();
155       }
156     }
157 
158     private boolean isDetailed() {
159       return view.getZoom() > view.getPaintDetailThreshold();
160     }
161   }
162 }
163