1 /*******************************************************************************
2  * Copyright (c) 2010, 2018 IBM Corporation and others.
3  *
4  * This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License 2.0
6  * which accompanies this distribution, and is available at
7  * https://www.eclipse.org/legal/epl-2.0/
8  *
9  * SPDX-License-Identifier: EPL-2.0
10  *
11  * Contributors:
12  *     IBM Corporation - initial API and implementation
13  ******************************************************************************/
14 
15 package org.eclipse.e4.ui.workbench.addons.minmax;
16 
17 import org.eclipse.e4.ui.model.application.ui.menu.MToolControl;
18 import org.eclipse.swt.SWT;
19 import org.eclipse.swt.events.MouseAdapter;
20 import org.eclipse.swt.events.MouseEvent;
21 import org.eclipse.swt.events.MouseTrackListener;
22 import org.eclipse.swt.graphics.Point;
23 import org.eclipse.swt.graphics.Rectangle;
24 import org.eclipse.swt.widgets.Composite;
25 import org.eclipse.swt.widgets.Control;
26 import org.eclipse.swt.widgets.Layout;
27 
28 /**
29  *
30  */
31 public class TrimPaneLayout extends Layout {
32 	private static int BORDER_WIDTH = 4;
33 	private static final Rectangle EMPTY_RECT = new Rectangle(0, 0, 0, 0);
34 	private int fixedCorner;
35 
36 	public Rectangle hSizingRect = EMPTY_RECT;
37 	public Rectangle vSizingRect = EMPTY_RECT;
38 	public Rectangle cornerRect = EMPTY_RECT;
39 	private Rectangle clientRect = EMPTY_RECT;
40 	private boolean resizeInstalled = false;
41 
42 	private static int NOT_SIZING = 0;
43 	private static int HORIZONTAL_SIZING = 1;
44 	private static int VERTICAL_SIZING = 2;
45 	private static int CORNER_SIZING = 3;
46 
47 	int trackState = SWT.NONE;
48 	protected Point curPos;
49 	private MToolControl toolControl;
50 
TrimPaneLayout(MToolControl toolControl, int barSide)51 	public TrimPaneLayout(MToolControl toolControl, int barSide) {
52 		this.toolControl = toolControl;
53 		this.fixedCorner = barSide;
54 	}
55 
56 	@Override
computeSize(Composite composite, int wHint, int hHint, boolean flushCache)57 	protected Point computeSize(Composite composite, int wHint, int hHint, boolean flushCache) {
58 		return new Point(600, 400);
59 	}
60 
61 	@Override
layout(Composite composite, boolean flushCache)62 	protected void layout(Composite composite, boolean flushCache) {
63 		installResize(composite);
64 
65 		if (composite.getChildren().length != 1) {
66 			return;
67 		}
68 
69 		if (fixedCorner == SWT.NONE) {
70 			return;
71 		}
72 
73 		Rectangle bounds = composite.getBounds();
74 
75 		if (isFixed(SWT.TOP)) {
76 			if (isFixed(SWT.RIGHT)) {
77 				hSizingRect = new Rectangle(0, 0, BORDER_WIDTH, bounds.height - BORDER_WIDTH);
78 				vSizingRect = new Rectangle(BORDER_WIDTH, bounds.height - BORDER_WIDTH,
79 						bounds.width - BORDER_WIDTH, BORDER_WIDTH);
80 				cornerRect = new Rectangle(0, bounds.height - BORDER_WIDTH, BORDER_WIDTH,
81 						BORDER_WIDTH);
82 				clientRect = new Rectangle(BORDER_WIDTH, 0, bounds.width - BORDER_WIDTH,
83 						bounds.height - BORDER_WIDTH);
84 			} else {
85 				hSizingRect = new Rectangle(bounds.width - BORDER_WIDTH, 0, BORDER_WIDTH,
86 						bounds.height - BORDER_WIDTH);
87 				vSizingRect = new Rectangle(0, bounds.height - BORDER_WIDTH, bounds.width
88 						- BORDER_WIDTH, BORDER_WIDTH);
89 				cornerRect = new Rectangle(bounds.width - BORDER_WIDTH, bounds.height
90 						- BORDER_WIDTH, BORDER_WIDTH, BORDER_WIDTH);
91 				clientRect = new Rectangle(0, 0, bounds.width - BORDER_WIDTH, bounds.height
92 						- BORDER_WIDTH);
93 			}
94 		} else if (isFixed(SWT.BOTTOM)) {
95 			if (isFixed(SWT.RIGHT)) {
96 				hSizingRect = new Rectangle(0, BORDER_WIDTH, BORDER_WIDTH, bounds.height
97 						- BORDER_WIDTH);
98 				vSizingRect = new Rectangle(BORDER_WIDTH, 0, bounds.width - BORDER_WIDTH,
99 						BORDER_WIDTH);
100 				cornerRect = new Rectangle(0, 0, BORDER_WIDTH, BORDER_WIDTH);
101 				clientRect = new Rectangle(BORDER_WIDTH, BORDER_WIDTH, bounds.width - BORDER_WIDTH,
102 						bounds.height - BORDER_WIDTH);
103 			} else {
104 				hSizingRect = new Rectangle(bounds.width - BORDER_WIDTH, BORDER_WIDTH,
105 						BORDER_WIDTH, bounds.height - BORDER_WIDTH);
106 				vSizingRect = new Rectangle(0, 0, bounds.width - BORDER_WIDTH, BORDER_WIDTH);
107 				cornerRect = new Rectangle(bounds.width - BORDER_WIDTH, 0, BORDER_WIDTH,
108 						BORDER_WIDTH);
109 				clientRect = new Rectangle(0, BORDER_WIDTH, bounds.width - BORDER_WIDTH,
110 						bounds.height - BORDER_WIDTH);
111 			}
112 		}
113 		Control child = composite.getChildren()[0];
114 		child.setBounds(clientRect);
115 	}
116 
installResize(final Composite composite)117 	private void installResize(final Composite composite) {
118 		if (resizeInstalled) {
119 			return;
120 		}
121 
122 		composite.addMouseMoveListener(e -> {
123 			Point p = e.display.getCursorLocation();
124 			if (trackState == NOT_SIZING) {
125 				setCursor(composite, new Point(e.x, e.y));
126 			} else if (trackState == HORIZONTAL_SIZING) {
127 				dragHorizontal(composite, p);
128 			} else if (trackState == VERTICAL_SIZING) {
129 				dragVertical(composite, p);
130 			} else if (trackState == CORNER_SIZING) {
131 				dragCorner(composite, p);
132 			}
133 		});
134 
135 		composite.addMouseListener(new MouseAdapter() {
136 
137 			@Override
138 			public void mouseUp(MouseEvent e) {
139 				composite.setCapture(false);
140 
141 				// Persist the current size
142 				Point size = composite.getSize();
143 				toolControl.getPersistedState()
144 						.put(TrimStack.STATE_XSIZE, Integer.toString(size.x));
145 				toolControl.getPersistedState()
146 						.put(TrimStack.STATE_YSIZE, Integer.toString(size.y));
147 
148 				trackState = NOT_SIZING;
149 			}
150 
151 			@Override
152 			public void mouseDown(MouseEvent e) {
153 				Point p = new Point(e.x, e.y);
154 				if (hSizingRect.contains(p)) {
155 					curPos = e.display.getCursorLocation();
156 					trackState = HORIZONTAL_SIZING;
157 					composite.setCapture(true);
158 				} else if (vSizingRect.contains(p)) {
159 					curPos = e.display.getCursorLocation();
160 					trackState = VERTICAL_SIZING;
161 					composite.setCapture(true);
162 				} else if (cornerRect.contains(p)) {
163 					curPos = e.display.getCursorLocation();
164 					trackState = CORNER_SIZING;
165 					composite.setCapture(true);
166 				}
167 			}
168 		});
169 
170 		composite.addMouseTrackListener(MouseTrackListener.mouseExitAdapter(e -> {
171 			Composite comp = (Composite) e.widget;
172 			comp.setCursor(null);
173 		}));
174 
175 		resizeInstalled = true;
176 	}
177 
178 	/**
179 	 * @param p
180 	 */
setCursor(Composite composite, Point p)181 	protected void setCursor(Composite composite, Point p) {
182 		if (hSizingRect.contains(p)) {
183 			composite.setCursor(composite.getDisplay().getSystemCursor(SWT.CURSOR_SIZEWE));
184 		} else if (vSizingRect.contains(p)) {
185 			composite.setCursor(composite.getDisplay().getSystemCursor(SWT.CURSOR_SIZENS));
186 		} else if (cornerRect.contains(p)) {
187 			if (isFixed(SWT.TOP)) {
188 				if (isFixed(SWT.RIGHT)) {
189 					composite.setCursor(composite.getDisplay().getSystemCursor(SWT.CURSOR_SIZESW));
190 				} else {
191 					composite.setCursor(composite.getDisplay().getSystemCursor(SWT.CURSOR_SIZESE));
192 				}
193 			} else if (isFixed(SWT.BOTTOM)) {
194 				if (isFixed(SWT.RIGHT)) {
195 					composite.setCursor(composite.getDisplay().getSystemCursor(SWT.CURSOR_SIZESE));
196 				} else {
197 					composite.setCursor(composite.getDisplay().getSystemCursor(SWT.CURSOR_SIZESW));
198 				}
199 			}
200 		} else {
201 			composite.setCursor(null);
202 		}
203 	}
204 
dragCorner(Composite composite, Point p)205 	protected void dragCorner(Composite composite, Point p) {
206 		int dx = p.x - curPos.x;
207 		int dy = p.y - curPos.y;
208 		Rectangle bounds = composite.getBounds();
209 
210 		if (isFixed(SWT.RIGHT)) {
211 			bounds.x += dx;
212 			bounds.width -= dx;
213 		} else {
214 			bounds.width += dx;
215 		}
216 
217 		if (isFixed(SWT.BOTTOM)) {
218 			bounds.y += dy;
219 			bounds.height -= dy;
220 		} else {
221 			bounds.height += dy;
222 		}
223 
224 		composite.setBounds(bounds);
225 		composite.getDisplay().update();
226 
227 		curPos = p;
228 	}
229 
dragVertical(Composite composite, Point p)230 	protected void dragVertical(Composite composite, Point p) {
231 		int dy = p.y - curPos.y;
232 		Rectangle bounds = composite.getBounds();
233 		if (isFixed(SWT.BOTTOM)) {
234 			bounds.y += dy;
235 			bounds.height -= dy;
236 		} else {
237 			bounds.height += dy;
238 		}
239 
240 		composite.setBounds(bounds);
241 		composite.getDisplay().update();
242 
243 		curPos = p;
244 	}
245 
dragHorizontal(Composite composite, Point p)246 	protected void dragHorizontal(Composite composite, Point p) {
247 		int dx = p.x - curPos.x;
248 		Rectangle bounds = composite.getBounds();
249 		if (isFixed(SWT.RIGHT)) {
250 			bounds.x += dx;
251 			bounds.width -= dx;
252 		} else {
253 			bounds.width += dx;
254 		}
255 
256 		composite.setBounds(bounds);
257 		composite.getDisplay().update();
258 
259 		curPos = p;
260 	}
261 
isFixed(int swtSide)262 	private boolean isFixed(int swtSide) {
263 		return (fixedCorner & swtSide) != 0;
264 	}
265 }
266