Lines 15-28
Link Here
|
15 |
import java.util.Map; |
15 |
import java.util.Map; |
16 |
import java.util.Set; |
16 |
import java.util.Set; |
17 |
|
17 |
|
|
|
18 |
import org.eclipse.jface.action.Action; |
19 |
import org.eclipse.jface.action.ActionContributionItem; |
20 |
import org.eclipse.jface.action.IAction; |
21 |
import org.eclipse.jface.action.Separator; |
22 |
import org.eclipse.jface.action.ToolBarManager; |
18 |
import org.eclipse.jface.layout.GridDataFactory; |
23 |
import org.eclipse.jface.layout.GridDataFactory; |
|
|
24 |
import org.eclipse.jface.resource.ImageDescriptor; |
19 |
import org.eclipse.jface.wizard.IWizardPage; |
25 |
import org.eclipse.jface.wizard.IWizardPage; |
20 |
import org.eclipse.jface.wizard.WizardPage; |
26 |
import org.eclipse.jface.wizard.WizardPage; |
21 |
import org.eclipse.mylyn.internal.tasks.core.LocalAttachment; |
|
|
22 |
import org.eclipse.mylyn.internal.tasks.ui.TaskListColorsAndFonts; |
27 |
import org.eclipse.mylyn.internal.tasks.ui.TaskListColorsAndFonts; |
23 |
import org.eclipse.mylyn.internal.tasks.ui.TasksUiImages; |
28 |
import org.eclipse.mylyn.internal.tasks.ui.TasksUiImages; |
24 |
import org.eclipse.swt.SWT; |
29 |
import org.eclipse.swt.SWT; |
25 |
import org.eclipse.swt.custom.ScrolledComposite; |
30 |
import org.eclipse.swt.custom.ScrolledComposite; |
|
|
31 |
import org.eclipse.swt.custom.ViewForm; |
26 |
import org.eclipse.swt.events.ControlAdapter; |
32 |
import org.eclipse.swt.events.ControlAdapter; |
27 |
import org.eclipse.swt.events.ControlEvent; |
33 |
import org.eclipse.swt.events.ControlEvent; |
28 |
import org.eclipse.swt.events.MouseAdapter; |
34 |
import org.eclipse.swt.events.MouseAdapter; |
Lines 30-75
Link Here
|
30 |
import org.eclipse.swt.events.MouseMoveListener; |
36 |
import org.eclipse.swt.events.MouseMoveListener; |
31 |
import org.eclipse.swt.events.PaintEvent; |
37 |
import org.eclipse.swt.events.PaintEvent; |
32 |
import org.eclipse.swt.events.PaintListener; |
38 |
import org.eclipse.swt.events.PaintListener; |
33 |
import org.eclipse.swt.events.SelectionAdapter; |
39 |
import org.eclipse.swt.graphics.Color; |
34 |
import org.eclipse.swt.events.SelectionEvent; |
|
|
35 |
import org.eclipse.swt.graphics.Cursor; |
40 |
import org.eclipse.swt.graphics.Cursor; |
36 |
import org.eclipse.swt.graphics.GC; |
41 |
import org.eclipse.swt.graphics.GC; |
37 |
import org.eclipse.swt.graphics.Image; |
42 |
import org.eclipse.swt.graphics.Image; |
38 |
import org.eclipse.swt.graphics.Point; |
43 |
import org.eclipse.swt.graphics.Point; |
|
|
44 |
import org.eclipse.swt.graphics.RGB; |
39 |
import org.eclipse.swt.graphics.Rectangle; |
45 |
import org.eclipse.swt.graphics.Rectangle; |
40 |
import org.eclipse.swt.graphics.Region; |
46 |
import org.eclipse.swt.graphics.Region; |
41 |
import org.eclipse.swt.layout.GridLayout; |
|
|
42 |
import org.eclipse.swt.widgets.Button; |
43 |
import org.eclipse.swt.widgets.Canvas; |
47 |
import org.eclipse.swt.widgets.Canvas; |
44 |
import org.eclipse.swt.widgets.Composite; |
48 |
import org.eclipse.swt.widgets.Composite; |
45 |
import org.eclipse.swt.widgets.Display; |
49 |
import org.eclipse.swt.widgets.Display; |
|
|
50 |
import org.eclipse.swt.widgets.Event; |
46 |
import org.eclipse.swt.widgets.Shell; |
51 |
import org.eclipse.swt.widgets.Shell; |
|
|
52 |
import org.eclipse.swt.widgets.ToolItem; |
47 |
|
53 |
|
48 |
/** |
54 |
/** |
49 |
* A wizard page to create a screenshot from the display. |
55 |
* A wizard page to create a screenshot from the display. |
50 |
* <p> |
|
|
51 |
* Note: this class uses {@link GC#setXORMode(boolean)} which is deprecated because of lack of Mac implementation |
52 |
* (bug#50228). The strategy to make it work on platforms XOR is implemented and still have a good looking in platforms |
53 |
* where it is not implemented, is to draw each line 2 times: first using a WHITE foreground followed by the same draw |
54 |
* using a BLACK foreground. On platforms where XOR is implemented, the second draw will have no effect, since anything |
55 |
* XOR black results in noop. On platforms where XOR is NOT implemented, the {@link GC#setXORMode(boolean)} is a noop, |
56 |
* so the end result will be a black line. |
57 |
* |
56 |
* |
58 |
* @author Balazs Brinkus (bug 160572) |
57 |
* @author Balazs Brinkus (bug 160572) |
59 |
* @author Mik Kersten |
58 |
* @author Mik Kersten |
60 |
* @author Willian Mitsuda |
59 |
* @author Willian Mitsuda |
61 |
*/ |
60 |
*/ |
62 |
public class ScreenshotAttachmentPage extends WizardPage { |
61 |
public class ScreenshotAttachmentPage extends WizardPage implements IImageCreator { |
63 |
|
62 |
|
64 |
private ScreenshotAttachmentPage page; |
63 |
private IAction captureAction; |
65 |
|
64 |
|
66 |
private LocalAttachment attachment; |
65 |
private IAction fitAction; |
67 |
|
66 |
|
68 |
private Button captureButton; |
67 |
private IAction cropAction; |
69 |
|
68 |
|
70 |
private Button fitButton; |
69 |
private IAction markAction; |
71 |
|
70 |
|
72 |
private Image screenshotImage; |
71 |
private IAction colorAction; |
|
|
72 |
|
73 |
private Image colorIcon; |
74 |
|
75 |
private Color markColor; |
76 |
|
77 |
private IAction clearAction; |
78 |
|
79 |
/** |
80 |
* Original screenshot image; used for backup purposes |
81 |
*/ |
82 |
private Image originalImage; |
83 |
|
84 |
/** |
85 |
* Copy of {@link #originalImage original} image; all drawing operations are done here; base for the result image |
86 |
*/ |
87 |
private Image workImage; |
88 |
|
89 |
/** |
90 |
* Used to draw into {@link #workImage} |
91 |
*/ |
92 |
private GC workImageGC; |
73 |
|
93 |
|
74 |
private Canvas canvas; |
94 |
private Canvas canvas; |
75 |
|
95 |
|
Lines 87-99
Link Here
|
87 |
private Rectangle originalSelection; |
107 |
private Rectangle originalSelection; |
88 |
|
108 |
|
89 |
/** |
109 |
/** |
90 |
* Temporary storage for selection start point or selection resizing initial reference point; this value is |
110 |
* Temporary storage for selection start point, selection resizing initial reference point or previous mark point |
91 |
* normalized to real image coordinates, no matter the zoom level (see {@link #scaleFactor}) |
111 |
* (it depends on current tool); this value is normalized to real image coordinates, no matter the zoom level (see |
|
|
112 |
* {@link #scaleFactor}) |
92 |
*/ |
113 |
*/ |
93 |
private Point startPoint; |
114 |
private Point startPoint; |
94 |
|
115 |
|
95 |
/** |
116 |
/** |
96 |
* What sides I'm resizing when doing an selection {@link Action#RESIZING_SELECTION resize} |
117 |
* What sides I'm resizing when doing an selection {@link EditorAction#RESIZING_SELECTION resize} |
97 |
*/ |
118 |
*/ |
98 |
private Set<SelectionSide> resizableSides = EnumSet.noneOf(SelectionSide.class); |
119 |
private Set<SelectionSide> resizableSides = EnumSet.noneOf(SelectionSide.class); |
99 |
|
120 |
|
Lines 110-157
Link Here
|
110 |
/** |
131 |
/** |
111 |
* Available actions for the screenshot editor |
132 |
* Available actions for the screenshot editor |
112 |
*/ |
133 |
*/ |
113 |
private static enum Action { |
134 |
private static enum EditorAction { |
114 |
|
135 |
|
115 |
IDLE, SELECTING, RESIZING_SELECTION, MOVING_SELECTION; |
136 |
CROPPING, SELECTING, RESIZING_SELECTION, MOVING_SELECTION, MARKING; |
116 |
|
137 |
|
117 |
}; |
138 |
}; |
118 |
|
139 |
|
119 |
/** |
140 |
/** |
120 |
* What am I doing now? |
141 |
* What am I doing now? |
121 |
*/ |
142 |
*/ |
122 |
private Action currentAction = Action.IDLE; |
143 |
private EditorAction currentAction = EditorAction.CROPPING; |
123 |
|
144 |
|
124 |
protected ScreenshotAttachmentPage(LocalAttachment attachment) { |
145 |
protected ScreenshotAttachmentPage() { |
125 |
super("ScreenShotAttachment"); |
146 |
super("ScreenShotAttachment"); |
126 |
setTitle("Capture Screenshot"); |
147 |
setTitle("Capture Screenshot"); |
127 |
setDescription("After capturing, drag the mouse to crop. This window will not be captured. " |
148 |
setDescription("After capturing, you can crop the image and make drawings on it. This window will not be captured. " |
128 |
+ "Note that you can continue to interact with the workbench in order to set up the screenshot."); |
149 |
+ "Note that you can continue to interact with the workbench in order to set up the screenshot."); |
129 |
this.attachment = attachment; |
|
|
130 |
this.page = this; |
131 |
} |
150 |
} |
132 |
|
151 |
|
133 |
public void createControl(Composite parent) { |
152 |
public void createControl(Composite parent) { |
134 |
|
153 |
ViewForm vf = new ViewForm(parent, SWT.BORDER | SWT.FLAT); |
135 |
Composite composite = new Composite(parent, SWT.NONE); |
154 |
vf.horizontalSpacing = 0; |
136 |
composite.setLayout(new GridLayout()); |
155 |
vf.verticalSpacing = 0; |
137 |
setControl(composite); |
156 |
setControl(vf); |
|
|
157 |
vf.setLayoutData(GridDataFactory.fillDefaults().create()); |
138 |
|
158 |
|
139 |
allocateCursors(); |
159 |
allocateCursors(); |
140 |
|
160 |
|
141 |
Composite buttonsComposite = new Composite(composite, SWT.NONE); |
161 |
// TODO: need disabled versions of all toolbar icons |
142 |
buttonsComposite.setLayout(new GridLayout(3, false)); |
162 |
ToolBarManager tbm = new ToolBarManager(SWT.FLAT | SWT.HORIZONTAL | SWT.RIGHT); |
143 |
captureButton = new Button(buttonsComposite, SWT.PUSH); |
163 |
captureAction = new Action("&Capture Desktop", IAction.AS_PUSH_BUTTON) { |
144 |
captureButton.setText("Capture Desktop"); |
164 |
|
145 |
captureButton.setImage(TasksUiImages.getImage(TasksUiImages.IMAGE_CAPTURE)); |
165 |
private boolean isFirstCapture = true; |
146 |
captureButton.addSelectionListener(new SelectionAdapter() { |
|
|
147 |
|
166 |
|
148 |
public void widgetSelected(SelectionEvent e) { |
167 |
@Override |
|
|
168 |
public void run() { |
149 |
captureScreenshotContent(); |
169 |
captureScreenshotContent(); |
150 |
page.setErrorMessage(null); |
170 |
setErrorMessage(null); |
151 |
fitButton.setEnabled(true); |
171 |
if (isFirstCapture) { |
|
|
172 |
isFirstCapture = false; |
173 |
fitAction.setEnabled(true); |
174 |
cropAction.setEnabled(true); |
175 |
cropAction.setChecked(true); |
176 |
markAction.setEnabled(true); |
177 |
clearAction.setEnabled(false); |
178 |
} |
152 |
} |
179 |
} |
153 |
|
180 |
|
154 |
}); |
181 |
}; |
|
|
182 |
captureAction.setToolTipText("Capture Desktop"); |
183 |
captureAction.setImageDescriptor(ImageDescriptor.createFromImage(TasksUiImages.getImage(TasksUiImages.IMAGE_CAPTURE))); |
155 |
|
184 |
|
156 |
// captureDelayedButton = new Button(buttonsComposite, SWT.PUSH); |
185 |
// captureDelayedButton = new Button(buttonsComposite, SWT.PUSH); |
157 |
// final String captureIn = "Capture in "; |
186 |
// final String captureIn = "Capture in "; |
Lines 186-239
Link Here
|
186 |
// } |
215 |
// } |
187 |
// }); |
216 |
// }); |
188 |
|
217 |
|
189 |
fitButton = new Button(buttonsComposite, SWT.TOGGLE); |
218 |
fitAction = new Action("", IAction.AS_CHECK_BOX) { |
190 |
fitButton.setText("Fit Image"); |
219 |
@Override |
191 |
fitButton.setImage(TasksUiImages.getImage(TasksUiImages.IMAGE_FIT)); |
220 |
public void run() { |
192 |
fitButton.addSelectionListener(new SelectionAdapter() { |
|
|
193 |
|
194 |
public void widgetSelected(SelectionEvent e) { |
195 |
refreshCanvasSize(); |
221 |
refreshCanvasSize(); |
196 |
} |
222 |
} |
|
|
223 |
}; |
224 |
fitAction.setToolTipText("Fit Image"); |
225 |
fitAction.setText("&Fit Image"); |
226 |
fitAction.setImageDescriptor(ImageDescriptor.createFromImage(TasksUiImages.getImage(TasksUiImages.IMAGE_FIT))); |
227 |
fitAction.setChecked(true); |
228 |
fitAction.setEnabled(false); |
197 |
|
229 |
|
198 |
}); |
230 |
cropAction = new Action("C&rop", IAction.AS_RADIO_BUTTON) { |
199 |
fitButton.setSelection(true); |
231 |
@Override |
200 |
fitButton.setEnabled(false); |
232 |
public void run() { |
|
|
233 |
currentAction = EditorAction.CROPPING; |
234 |
cropAction.setChecked(true); |
235 |
markAction.setChecked(false); |
236 |
colorAction.setEnabled(false); |
237 |
canvas.redraw(); |
238 |
} |
239 |
}; |
240 |
cropAction.setToolTipText("Crop"); |
241 |
cropAction.setImageDescriptor(ImageDescriptor.createFromFile(getClass(), "crop.png")); |
242 |
cropAction.setEnabled(false); |
243 |
|
244 |
markAction = new Action("&Annotate", IAction.AS_RADIO_BUTTON) { |
245 |
@Override |
246 |
public void run() { |
247 |
currentAction = EditorAction.MARKING; |
248 |
cropAction.setChecked(false); |
249 |
markAction.setChecked(true); |
250 |
colorAction.setEnabled(true); |
251 |
canvas.redraw(); |
252 |
} |
253 |
}; |
254 |
markAction.setToolTipText("Draw annotations on screenshot image"); |
255 |
markAction.setImageDescriptor(ImageDescriptor.createFromFile(getClass(), "mark.gif")); |
256 |
markAction.setDisabledImageDescriptor(ImageDescriptor.createFromFile(getClass(), "mark_disabled.gif")); |
257 |
markAction.setEnabled(false); |
258 |
|
259 |
colorAction = new Action("", IAction.AS_DROP_DOWN_MENU) { |
260 |
@Override |
261 |
public void runWithEvent(final Event e) { |
262 |
final ColorSelectionWindow colorWindow = new ColorSelectionWindow(getControl().getShell()) { |
263 |
|
264 |
@Override |
265 |
protected Point getInitialLocation(Point initialSize) { |
266 |
ToolItem toolItem = (ToolItem) e.widget; |
267 |
Rectangle itemBounds = toolItem.getBounds(); |
268 |
Point location = toolItem.getParent().toDisplay(itemBounds.x + itemBounds.width, |
269 |
itemBounds.y + itemBounds.height); |
270 |
location.x -= initialSize.x; |
271 |
return location; |
272 |
} |
273 |
|
274 |
}; |
275 |
colorWindow.setBlockOnOpen(true); |
276 |
colorWindow.open(); |
277 |
RGB color = colorWindow.getSelectedRGB(); |
278 |
if (color != null) { |
279 |
setMarkColor(color); |
280 |
} |
281 |
} |
282 |
}; |
283 |
colorAction.setToolTipText("Change pen color"); |
284 |
colorIcon = new Image(getShell().getDisplay(), 16, 16); |
285 |
setMarkColor(new RGB(255, 85, 85)); |
286 |
colorAction.setEnabled(false); |
201 |
|
287 |
|
202 |
scrolledComposite = new ScrolledComposite(composite, SWT.V_SCROLL | SWT.H_SCROLL | SWT.BORDER); |
288 |
clearAction = new Action("C&lear Annotations", IAction.AS_PUSH_BUTTON) { |
203 |
scrolledComposite.setLayoutData(GridDataFactory.fillDefaults() |
289 |
@Override |
204 |
.align(SWT.FILL, SWT.FILL) |
290 |
public void run() { |
205 |
.grab(true, true) |
291 |
clearAction.setEnabled(false); |
206 |
.create()); |
292 |
workImageGC.drawImage(originalImage, 0, 0); |
|
|
293 |
canvas.redraw(); |
294 |
markAttachmentDirty(); |
295 |
} |
296 |
}; |
297 |
clearAction.setToolTipText("Clear all annotations made on screenshot image"); |
298 |
clearAction.setImageDescriptor(ImageDescriptor.createFromFile(getClass(), "erase.png")); |
299 |
clearAction.setEnabled(false); |
300 |
|
301 |
tbm.add(createAndConfigureCI(captureAction)); |
302 |
tbm.add(createAndConfigureCI(fitAction)); |
303 |
tbm.add(new Separator()); |
304 |
tbm.add(createAndConfigureCI(cropAction)); |
305 |
tbm.add(createAndConfigureCI(markAction)); |
306 |
tbm.add(createAndConfigureCI(colorAction)); |
307 |
tbm.add(new Separator()); |
308 |
tbm.add(createAndConfigureCI(clearAction)); |
207 |
|
309 |
|
|
|
310 |
scrolledComposite = new ScrolledComposite(vf, SWT.V_SCROLL | SWT.H_SCROLL); |
208 |
canvas = new Canvas(scrolledComposite, SWT.DOUBLE_BUFFERED); |
311 |
canvas = new Canvas(scrolledComposite, SWT.DOUBLE_BUFFERED); |
209 |
scrolledComposite.setContent(canvas); |
312 |
scrolledComposite.setContent(canvas); |
210 |
canvas.addPaintListener(new PaintListener() { |
313 |
canvas.addPaintListener(new PaintListener() { |
211 |
|
314 |
|
212 |
public void paintControl(PaintEvent e) { |
315 |
public void paintControl(PaintEvent e) { |
213 |
if (screenshotImage != null) { |
316 |
if (workImage != null) { |
214 |
Rectangle imageBounds = screenshotImage.getBounds(); |
317 |
Rectangle imageBounds = workImage.getBounds(); |
215 |
Rectangle canvasBounds = canvas.getClientArea(); |
318 |
Rectangle canvasBounds = canvas.getClientArea(); |
216 |
|
319 |
|
217 |
if (fitButton.getSelection()) { |
320 |
if (fitAction.isChecked()) { |
218 |
e.gc.drawImage(screenshotImage, 0, 0, imageBounds.width, imageBounds.height, 0, 0, |
321 |
e.gc.drawImage(workImage, 0, 0, imageBounds.width, imageBounds.height, 0, 0, |
219 |
canvasBounds.width, canvasBounds.height); |
322 |
canvasBounds.width, canvasBounds.height); |
220 |
} else { |
323 |
} else { |
221 |
e.gc.drawImage(screenshotImage, 0, 0); |
324 |
e.gc.drawImage(workImage, 0, 0); |
222 |
} |
|
|
223 |
|
224 |
if (currentAction == Action.IDLE) { |
225 |
if (currentSelection != null) { |
226 |
drawSelection(e.gc); |
227 |
} |
228 |
} else if (currentAction == Action.SELECTING || currentAction == Action.RESIZING_SELECTION |
229 |
|| currentAction == Action.MOVING_SELECTION) { |
230 |
if (currentSelection != null) { |
231 |
drawSelectionPreview(e.gc); |
232 |
} |
233 |
} |
325 |
} |
|
|
326 |
drawSelection(e.gc); |
234 |
} else { |
327 |
} else { |
235 |
// page.setErrorMessage("Screenshot required"); |
328 |
// page.setErrorMessage("Screenshot required"); |
236 |
fitButton.setEnabled(false); |
329 |
fitAction.setEnabled(false); |
237 |
} |
330 |
} |
238 |
} |
331 |
} |
239 |
}); |
332 |
}); |
Lines 241-257
Link Here
|
241 |
scrolledComposite.addControlListener(new ControlAdapter() { |
334 |
scrolledComposite.addControlListener(new ControlAdapter() { |
242 |
@Override |
335 |
@Override |
243 |
public void controlResized(ControlEvent e) { |
336 |
public void controlResized(ControlEvent e) { |
244 |
if (fitButton.getSelection()) { |
337 |
if (fitAction.isChecked()) { |
245 |
refreshCanvasSize(); |
338 |
refreshCanvasSize(); |
246 |
} |
339 |
} |
247 |
} |
340 |
} |
248 |
}); |
341 |
}); |
249 |
|
342 |
|
|
|
343 |
vf.setTopLeft(tbm.createControl(vf)); |
344 |
vf.setContent(scrolledComposite); |
250 |
registerMouseListeners(); |
345 |
registerMouseListeners(); |
251 |
} |
346 |
} |
252 |
|
347 |
|
|
|
348 |
private ActionContributionItem createAndConfigureCI(IAction action) { |
349 |
ActionContributionItem ci = new ActionContributionItem(action); |
350 |
ci.setMode(ActionContributionItem.MODE_FORCE_TEXT); |
351 |
return ci; |
352 |
} |
353 |
|
354 |
private void setMarkColor(RGB color) { |
355 |
if (markColor != null) { |
356 |
markColor.dispose(); |
357 |
} |
358 |
markColor = new Color(getShell().getDisplay(), color); |
359 |
if (workImageGC != null) { |
360 |
workImageGC.setForeground(markColor); |
361 |
} |
362 |
|
363 |
GC colorGC = new GC(colorIcon); |
364 |
colorGC.setBackground(markColor); |
365 |
colorGC.fillRectangle(0, 0, 16, 16); |
366 |
colorGC.drawRectangle(0, 0, 15, 15); |
367 |
colorGC.dispose(); |
368 |
|
369 |
colorAction.setImageDescriptor(ImageDescriptor.createFromImage(colorIcon)); |
370 |
} |
371 |
|
253 |
@Override |
372 |
@Override |
254 |
public void dispose() { |
373 |
public void dispose() { |
|
|
374 |
disposeImageResources(); |
375 |
if (markColor != null) { |
376 |
markColor.dispose(); |
377 |
} |
378 |
if (colorIcon != null) { |
379 |
colorIcon.dispose(); |
380 |
} |
381 |
|
255 |
canvas.setCursor(null); |
382 |
canvas.setCursor(null); |
256 |
for (Cursor cursor : cursors.values()) { |
383 |
for (Cursor cursor : cursors.values()) { |
257 |
cursor.dispose(); |
384 |
cursor.dispose(); |
Lines 259-266
Link Here
|
259 |
super.dispose(); |
386 |
super.dispose(); |
260 |
} |
387 |
} |
261 |
|
388 |
|
|
|
389 |
private void disposeImageResources() { |
390 |
if (originalImage != null) { |
391 |
originalImage.dispose(); |
392 |
} |
393 |
if (workImageGC != null) { |
394 |
workImageGC.dispose(); |
395 |
} |
396 |
if (workImage != null) { |
397 |
workImage.dispose(); |
398 |
} |
399 |
} |
400 |
|
401 |
private static final int CURSOR_MARK_TOOL = -1; |
402 |
|
262 |
private void allocateCursors() { |
403 |
private void allocateCursors() { |
263 |
Display display = Display.getCurrent(); |
404 |
Display display = getShell().getDisplay(); |
264 |
cursors.put(SWT.CURSOR_ARROW, new Cursor(display, SWT.CURSOR_ARROW)); |
405 |
cursors.put(SWT.CURSOR_ARROW, new Cursor(display, SWT.CURSOR_ARROW)); |
265 |
cursors.put(SWT.CURSOR_SIZEALL, new Cursor(display, SWT.CURSOR_SIZEALL)); |
406 |
cursors.put(SWT.CURSOR_SIZEALL, new Cursor(display, SWT.CURSOR_SIZEALL)); |
266 |
cursors.put(SWT.CURSOR_SIZENWSE, new Cursor(display, SWT.CURSOR_SIZENWSE)); |
407 |
cursors.put(SWT.CURSOR_SIZENWSE, new Cursor(display, SWT.CURSOR_SIZENWSE)); |
Lines 268-273
Link Here
|
268 |
cursors.put(SWT.CURSOR_SIZENS, new Cursor(display, SWT.CURSOR_SIZENS)); |
409 |
cursors.put(SWT.CURSOR_SIZENS, new Cursor(display, SWT.CURSOR_SIZENS)); |
269 |
cursors.put(SWT.CURSOR_SIZEWE, new Cursor(display, SWT.CURSOR_SIZEWE)); |
410 |
cursors.put(SWT.CURSOR_SIZEWE, new Cursor(display, SWT.CURSOR_SIZEWE)); |
270 |
cursors.put(SWT.CURSOR_CROSS, new Cursor(display, SWT.CURSOR_CROSS)); |
411 |
cursors.put(SWT.CURSOR_CROSS, new Cursor(display, SWT.CURSOR_CROSS)); |
|
|
412 |
|
413 |
// TODO: allocate custom cursor for "mark" tool |
414 |
cursors.put(CURSOR_MARK_TOOL, new Cursor(display, SWT.CURSOR_HAND)); |
271 |
} |
415 |
} |
272 |
|
416 |
|
273 |
private Rectangle getScaledSelection() { |
417 |
private Rectangle getScaledSelection() { |
Lines 278-302
Link Here
|
278 |
int y = (int) Math.round(currentSelection.y * scaleFactor); |
422 |
int y = (int) Math.round(currentSelection.y * scaleFactor); |
279 |
int right = (int) Math.round((currentSelection.x + currentSelection.width) * scaleFactor); |
423 |
int right = (int) Math.round((currentSelection.x + currentSelection.width) * scaleFactor); |
280 |
int bottom = (int) Math.round((currentSelection.y + currentSelection.height) * scaleFactor); |
424 |
int bottom = (int) Math.round((currentSelection.y + currentSelection.height) * scaleFactor); |
281 |
int width = Math.min(right, (int) Math.round((screenshotImage.getBounds().width - 1) * scaleFactor)) - x; |
425 |
int width = Math.min(right, (int) Math.round((workImage.getBounds().width - 1) * scaleFactor)) - x; |
282 |
int height = Math.min(bottom, (int) Math.round((screenshotImage.getBounds().height - 1) * scaleFactor)) - y; |
426 |
int height = Math.min(bottom, (int) Math.round((workImage.getBounds().height - 1) * scaleFactor)) - y; |
283 |
return new Rectangle(x, y, width, height); |
427 |
return new Rectangle(x, y, width, height); |
284 |
} |
428 |
} |
285 |
|
429 |
|
286 |
@Override |
430 |
@Override |
287 |
public boolean isPageComplete() { |
431 |
public boolean isPageComplete() { |
288 |
if (screenshotImage == null) |
432 |
return workImage != null; |
289 |
return false; |
|
|
290 |
return true; |
291 |
} |
433 |
} |
292 |
|
434 |
|
293 |
@Override |
435 |
@Override |
294 |
public IWizardPage getNextPage() { |
436 |
public IWizardPage getNextPage() { |
295 |
NewAttachmentPage page = (NewAttachmentPage) getWizard().getPage("AttachmentDetails"); |
437 |
NewAttachmentPage page = (NewAttachmentPage) getWizard().getPage("AttachmentDetails"); |
296 |
attachment.setContentType("image/jpeg"); |
|
|
297 |
page.setFilePath(InputAttachmentSourcePage.SCREENSHOT_LABEL); |
438 |
page.setFilePath(InputAttachmentSourcePage.SCREENSHOT_LABEL); |
298 |
page.setContentType(); |
439 |
page.setContentType(); |
299 |
getCropScreenshot(); |
|
|
300 |
return page; |
440 |
return page; |
301 |
} |
441 |
} |
302 |
|
442 |
|
Lines 306-314
Link Here
|
306 |
} |
446 |
} |
307 |
|
447 |
|
308 |
private void captureScreenshotContent() { |
448 |
private void captureScreenshotContent() { |
309 |
|
449 |
Display display = getShell().getDisplay(); |
310 |
final Display display = Display.getDefault(); |
450 |
Shell wizardShell = getWizard().getContainer().getShell(); |
311 |
final Shell wizardShell = getWizard().getContainer().getShell(); |
|
|
312 |
wizardShell.setVisible(false); |
451 |
wizardShell.setVisible(false); |
313 |
|
452 |
|
314 |
// NOTE: need a wait since the shell can take time to disappear (e.g. fade on Vista) |
453 |
// NOTE: need a wait since the shell can take time to disappear (e.g. fade on Vista) |
Lines 318-341
Link Here
|
318 |
// ignore |
457 |
// ignore |
319 |
} |
458 |
} |
320 |
|
459 |
|
321 |
display.asyncExec(new Runnable() { |
460 |
disposeImageResources(); |
322 |
public void run() { |
461 |
Rectangle displayBounds = display.getBounds(); |
323 |
Rectangle displayBounds = display.getBounds(); |
462 |
originalImage = new Image(display, displayBounds); |
324 |
screenshotImage = new Image(display, displayBounds); |
463 |
workImage = new Image(display, displayBounds); |
|
|
464 |
|
465 |
GC gc = new GC(display); |
466 |
gc.copyArea(originalImage, 0, 0); |
467 |
gc.copyArea(workImage, 0, 0); |
468 |
gc.dispose(); |
325 |
|
469 |
|
326 |
GC gc = new GC(display); |
470 |
workImageGC = new GC(workImage); |
327 |
gc.copyArea(screenshotImage, 0, 0); |
471 |
workImageGC.setForeground(markColor); |
328 |
gc.dispose(); |
472 |
workImageGC.setLineWidth(4); |
|
|
473 |
workImageGC.setLineCap(SWT.CAP_ROUND); |
329 |
|
474 |
|
330 |
clearSelection(); |
475 |
clearSelection(); |
331 |
refreshCanvasSize(); |
476 |
refreshCanvasSize(); |
332 |
|
477 |
|
333 |
wizardShell.setVisible(true); |
478 |
wizardShell.setVisible(true); |
334 |
if (screenshotImage != null) { |
479 |
setPageComplete(true); |
335 |
setPageComplete(true); |
|
|
336 |
} |
337 |
} |
338 |
}); |
339 |
} |
480 |
} |
340 |
|
481 |
|
341 |
/** |
482 |
/** |
Lines 352-358
Link Here
|
352 |
currentSelection = new Rectangle(startX, startY, width, height); |
493 |
currentSelection = new Rectangle(startX, startY, width, height); |
353 |
|
494 |
|
354 |
// Decreases 1 pixel size from original image because Rectangle.intersect() consider them as right-bottom limit |
495 |
// Decreases 1 pixel size from original image because Rectangle.intersect() consider them as right-bottom limit |
355 |
Rectangle imageBounds = screenshotImage.getBounds(); |
496 |
Rectangle imageBounds = workImage.getBounds(); |
356 |
imageBounds.width--; |
497 |
imageBounds.width--; |
357 |
imageBounds.height--; |
498 |
imageBounds.height--; |
358 |
currentSelection.intersect(imageBounds); |
499 |
currentSelection.intersect(imageBounds); |
Lines 363-374
Link Here
|
363 |
* level is changed |
504 |
* level is changed |
364 |
*/ |
505 |
*/ |
365 |
private void setUpGrabPoints() { |
506 |
private void setUpGrabPoints() { |
|
|
507 |
grabPoints.clear(); |
366 |
if (currentSelection == null) { |
508 |
if (currentSelection == null) { |
367 |
return; |
509 |
return; |
368 |
} |
510 |
} |
369 |
|
511 |
|
370 |
canvas.setCursor(null); |
|
|
371 |
grabPoints.clear(); |
372 |
Rectangle scaledSelection = getScaledSelection(); |
512 |
Rectangle scaledSelection = getScaledSelection(); |
373 |
grabPoints.add(GrabPoint.createGrabPoint(scaledSelection.x, scaledSelection.y, SWT.CURSOR_SIZENWSE, EnumSet.of( |
513 |
grabPoints.add(GrabPoint.createGrabPoint(scaledSelection.x, scaledSelection.y, SWT.CURSOR_SIZENWSE, EnumSet.of( |
374 |
SelectionSide.LEFT, SelectionSide.TOP))); |
514 |
SelectionSide.LEFT, SelectionSide.TOP))); |
Lines 393-399
Link Here
|
393 |
originalSelection.height); |
533 |
originalSelection.height); |
394 |
int deltaX = x - startPoint.x; |
534 |
int deltaX = x - startPoint.x; |
395 |
int deltaY = y - startPoint.y; |
535 |
int deltaY = y - startPoint.y; |
396 |
Rectangle imageBounds = screenshotImage.getBounds(); |
536 |
Rectangle imageBounds = workImage.getBounds(); |
397 |
|
537 |
|
398 |
// Check current selection limits |
538 |
// Check current selection limits |
399 |
if (resizableSides.contains(SelectionSide.LEFT)) { |
539 |
if (resizableSides.contains(SelectionSide.LEFT)) { |
Lines 436-441
Link Here
|
436 |
if (resizableSides.contains(SelectionSide.BOTTOM)) { |
576 |
if (resizableSides.contains(SelectionSide.BOTTOM)) { |
437 |
currentSelection.height += deltaY; |
577 |
currentSelection.height += deltaY; |
438 |
} |
578 |
} |
|
|
579 |
|
580 |
setUpGrabPoints(); |
439 |
} |
581 |
} |
440 |
|
582 |
|
441 |
private void refreshSelectionPosition(int x, int y) { |
583 |
private void refreshSelectionPosition(int x, int y) { |
Lines 447-453
Link Here
|
447 |
if (newY < 0) { |
589 |
if (newY < 0) { |
448 |
newY = 0; |
590 |
newY = 0; |
449 |
} |
591 |
} |
450 |
Rectangle imageBounds = screenshotImage.getBounds(); |
592 |
Rectangle imageBounds = workImage.getBounds(); |
451 |
if (newX + originalSelection.width - 1 > imageBounds.width) { |
593 |
if (newX + originalSelection.width - 1 > imageBounds.width) { |
452 |
newX = imageBounds.width - originalSelection.width; |
594 |
newX = imageBounds.width - originalSelection.width; |
453 |
} |
595 |
} |
Lines 455-460
Link Here
|
455 |
newY = imageBounds.height - originalSelection.height; |
597 |
newY = imageBounds.height - originalSelection.height; |
456 |
} |
598 |
} |
457 |
currentSelection = new Rectangle(newX, newY, originalSelection.width, originalSelection.height); |
599 |
currentSelection = new Rectangle(newX, newY, originalSelection.width, originalSelection.height); |
|
|
600 |
|
601 |
setUpGrabPoints(); |
458 |
} |
602 |
} |
459 |
|
603 |
|
460 |
private void registerMouseListeners() { |
604 |
private void registerMouseListeners() { |
Lines 464-480
Link Here
|
464 |
* If a selection is in course, moving the mouse around refreshes the selection rectangle |
608 |
* If a selection is in course, moving the mouse around refreshes the selection rectangle |
465 |
*/ |
609 |
*/ |
466 |
public void mouseMove(MouseEvent e) { |
610 |
public void mouseMove(MouseEvent e) { |
467 |
if (currentAction == Action.SELECTING) { |
611 |
int scaledX = (int) Math.round(e.x / scaleFactor); |
468 |
// Selection in course |
612 |
int scaledY = (int) Math.round(e.y / scaleFactor); |
469 |
refreshCurrentSelection((int) Math.round(e.x / scaleFactor), (int) Math.round(e.y / scaleFactor)); |
613 |
|
|
|
614 |
if (currentAction == EditorAction.SELECTING) { |
615 |
refreshCurrentSelection(scaledX, scaledY); |
470 |
canvas.redraw(); |
616 |
canvas.redraw(); |
471 |
} else if (currentAction == Action.RESIZING_SELECTION) { |
617 |
} else if (currentAction == EditorAction.RESIZING_SELECTION) { |
472 |
refreshSelectionResize((int) Math.round(e.x / scaleFactor), (int) Math.round(e.y / scaleFactor)); |
618 |
refreshSelectionResize(scaledX, scaledY); |
473 |
canvas.redraw(); |
619 |
canvas.redraw(); |
474 |
} else if (currentAction == Action.MOVING_SELECTION) { |
620 |
} else if (currentAction == EditorAction.MOVING_SELECTION) { |
475 |
refreshSelectionPosition((int) Math.round(e.x / scaleFactor), (int) Math.round(e.y / scaleFactor)); |
621 |
refreshSelectionPosition(scaledX, scaledY); |
476 |
canvas.redraw(); |
622 |
canvas.redraw(); |
477 |
} else if (currentAction == Action.IDLE && currentSelection != null) { |
623 |
} else if (currentAction == EditorAction.CROPPING && currentSelection != null) { |
478 |
boolean cursorSet = false; |
624 |
boolean cursorSet = false; |
479 |
|
625 |
|
480 |
// No selection in course, but have something selected; first test if I'm hovering some grab point |
626 |
// No selection in course, but have something selected; first test if I'm hovering some grab point |
Lines 491-498
Link Here
|
491 |
canvas.setCursor(cursors.get(SWT.CURSOR_SIZEALL)); |
637 |
canvas.setCursor(cursors.get(SWT.CURSOR_SIZEALL)); |
492 |
cursorSet = true; |
638 |
cursorSet = true; |
493 |
} |
639 |
} |
494 |
if (!cursorSet && canvas.getCursor() != null) { |
640 |
|
495 |
canvas.setCursor(null); |
641 |
// If I'm out, the default cursor for cropping mode is cross |
|
|
642 |
Cursor crossCursor = cursors.get(SWT.CURSOR_CROSS); |
643 |
if (!cursorSet && canvas.getCursor() != crossCursor) { |
644 |
canvas.setCursor(crossCursor); |
645 |
} |
646 |
} else if (currentAction == EditorAction.MARKING) { |
647 |
drawMarkLine(scaledX, scaledY); |
648 |
|
649 |
Cursor markCursor = cursors.get(CURSOR_MARK_TOOL); |
650 |
if (canvas.getCursor() != markCursor) { |
651 |
canvas.setCursor(markCursor); |
496 |
} |
652 |
} |
497 |
} |
653 |
} |
498 |
} |
654 |
} |
Lines 502-522
Link Here
|
502 |
canvas.addMouseListener(new MouseAdapter() { |
658 |
canvas.addMouseListener(new MouseAdapter() { |
503 |
|
659 |
|
504 |
/** |
660 |
/** |
505 |
* Releasing the mouse button ends the selection; compute the selection rectangle and redraw the cropped |
661 |
* Releasing the mouse button ends the selection or a drawing; compute the selection rectangle and redraw |
506 |
* image |
662 |
* the cropped image |
507 |
*/ |
663 |
*/ |
508 |
public void mouseUp(MouseEvent e) { |
664 |
public void mouseUp(MouseEvent e) { |
509 |
if (currentAction == Action.SELECTING || currentAction == Action.RESIZING_SELECTION |
665 |
if (currentAction == EditorAction.SELECTING || currentAction == EditorAction.RESIZING_SELECTION |
510 |
|| currentAction == Action.MOVING_SELECTION) { |
666 |
|| currentAction == EditorAction.MOVING_SELECTION) { |
511 |
canvas.setCursor(cursors.get(SWT.CURSOR_ARROW)); |
|
|
512 |
|
513 |
int scaledX = (int) Math.round(e.x / scaleFactor); |
667 |
int scaledX = (int) Math.round(e.x / scaleFactor); |
514 |
int scaledY = (int) Math.round(e.y / scaleFactor); |
668 |
int scaledY = (int) Math.round(e.y / scaleFactor); |
515 |
if (currentAction == Action.SELECTING) { |
669 |
if (currentAction == EditorAction.SELECTING) { |
516 |
refreshCurrentSelection(scaledX, scaledY); |
670 |
refreshCurrentSelection(scaledX, scaledY); |
517 |
} else if (currentAction == Action.RESIZING_SELECTION) { |
671 |
} else if (currentAction == EditorAction.RESIZING_SELECTION) { |
518 |
refreshSelectionResize(scaledX, scaledY); |
672 |
refreshSelectionResize(scaledX, scaledY); |
519 |
} else if (currentAction == Action.MOVING_SELECTION) { |
673 |
} else if (currentAction == EditorAction.MOVING_SELECTION) { |
520 |
refreshSelectionPosition(scaledX, scaledY); |
674 |
refreshSelectionPosition(scaledX, scaledY); |
521 |
} |
675 |
} |
522 |
if (currentSelection.width == 0 && currentSelection.height == 0) { |
676 |
if (currentSelection.width == 0 && currentSelection.height == 0) { |
Lines 524-540
Link Here
|
524 |
} |
678 |
} |
525 |
setUpGrabPoints(); |
679 |
setUpGrabPoints(); |
526 |
startPoint = null; |
680 |
startPoint = null; |
527 |
currentAction = Action.IDLE; |
681 |
currentAction = EditorAction.CROPPING; |
528 |
|
682 |
|
529 |
canvas.redraw(); |
683 |
canvas.redraw(); |
|
|
684 |
markAttachmentDirty(); |
685 |
} else if (currentAction == EditorAction.MARKING) { |
686 |
startPoint = null; |
687 |
markAttachmentDirty(); |
530 |
} |
688 |
} |
531 |
} |
689 |
} |
532 |
|
690 |
|
533 |
/** |
691 |
/** |
534 |
* Pressing mouse button starts a selection; normalizes and marks the start point |
692 |
* Pressing mouse button starts a selection or a drawing; normalizes and marks the start point |
535 |
*/ |
693 |
*/ |
536 |
public void mouseDown(MouseEvent e) { |
694 |
public void mouseDown(MouseEvent e) { |
537 |
if (currentAction != Action.IDLE) { |
695 |
int scaledX = (int) (e.x / scaleFactor); |
|
|
696 |
int scaledY = (int) (e.y / scaleFactor); |
697 |
|
698 |
if (currentAction == EditorAction.MARKING) { |
699 |
startPoint = new Point(scaledX, scaledY); |
700 |
drawMarkLine(scaledX, scaledY); |
701 |
canvas.setCursor(cursors.get(CURSOR_MARK_TOOL)); |
702 |
return; |
703 |
} else if (currentAction != EditorAction.CROPPING) { |
538 |
return; |
704 |
return; |
539 |
} |
705 |
} |
540 |
|
706 |
|
Lines 543-551
Link Here
|
543 |
for (GrabPoint point : grabPoints) { |
709 |
for (GrabPoint point : grabPoints) { |
544 |
if (point.grabArea.contains(e.x, e.y)) { |
710 |
if (point.grabArea.contains(e.x, e.y)) { |
545 |
originalSelection = currentSelection; |
711 |
originalSelection = currentSelection; |
546 |
currentAction = Action.RESIZING_SELECTION; |
712 |
currentAction = EditorAction.RESIZING_SELECTION; |
547 |
resizableSides = point.resizableSides; |
713 |
resizableSides = point.resizableSides; |
548 |
startPoint = new Point((int) (e.x / scaleFactor), (int) (e.y / scaleFactor)); |
714 |
startPoint = new Point(scaledX, scaledY); |
549 |
canvas.redraw(); |
715 |
canvas.redraw(); |
550 |
return; |
716 |
return; |
551 |
} |
717 |
} |
Lines 553-572
Link Here
|
553 |
} |
719 |
} |
554 |
|
720 |
|
555 |
// Check if I could move the selection |
721 |
// Check if I could move the selection |
556 |
if (currentSelection != null |
722 |
if (currentSelection != null && currentSelection.contains(scaledX, scaledY)) { |
557 |
&& currentSelection.contains((int) (e.x / scaleFactor), (int) (e.y / scaleFactor))) { |
|
|
558 |
originalSelection = currentSelection; |
723 |
originalSelection = currentSelection; |
559 |
currentAction = Action.MOVING_SELECTION; |
724 |
currentAction = EditorAction.MOVING_SELECTION; |
560 |
startPoint = new Point((int) (e.x / scaleFactor), (int) (e.y / scaleFactor)); |
725 |
startPoint = new Point(scaledX, scaledY); |
561 |
canvas.redraw(); |
726 |
canvas.redraw(); |
562 |
return; |
727 |
return; |
563 |
} |
728 |
} |
564 |
|
729 |
|
565 |
// Do a simple selection |
730 |
// Do a simple selection |
566 |
canvas.setCursor(cursors.get(SWT.CURSOR_CROSS)); |
731 |
canvas.setCursor(cursors.get(SWT.CURSOR_CROSS)); |
567 |
currentAction = Action.SELECTING; |
732 |
currentAction = EditorAction.SELECTING; |
568 |
currentSelection = null; |
733 |
currentSelection = null; |
569 |
startPoint = new Point((int) (e.x / scaleFactor), (int) (e.y / scaleFactor)); |
734 |
startPoint = new Point(scaledX, scaledY); |
|
|
735 |
setUpGrabPoints(); |
570 |
canvas.redraw(); |
736 |
canvas.redraw(); |
571 |
} |
737 |
} |
572 |
|
738 |
|
Lines 577-589
Link Here
|
577 |
private void clearSelection() { |
743 |
private void clearSelection() { |
578 |
currentSelection = null; |
744 |
currentSelection = null; |
579 |
startPoint = null; |
745 |
startPoint = null; |
|
|
746 |
markAttachmentDirty(); |
580 |
} |
747 |
} |
581 |
|
748 |
|
582 |
/** |
749 |
/** |
583 |
* Recalculates image canvas size based on "fit on canvas" setting, set up the grab points, and redraws |
750 |
* Recalculates image canvas size based on "fit on canvas" setting, set up the grab points, and redraws |
584 |
* <p> |
751 |
* <p> |
585 |
* This method should be called whenever the {@link #screenshotImage image} <strong>visible</strong> size is |
752 |
* This method should be called whenever the {@link #workImage image} <strong>visible</strong> size is changed, |
586 |
* changed, which can happen when: |
753 |
* which can happen when: |
587 |
* <p> |
754 |
* <p> |
588 |
* <ul> |
755 |
* <ul> |
589 |
* <li>The "Fit Image" setting is changed, so the image zoom level changes |
756 |
* <li>The "Fit Image" setting is changed, so the image zoom level changes |
Lines 595-609
Link Here
|
595 |
* Calling this method under other circumstances may lead to strange behavior in the scrolled composite |
762 |
* Calling this method under other circumstances may lead to strange behavior in the scrolled composite |
596 |
*/ |
763 |
*/ |
597 |
private void refreshCanvasSize() { |
764 |
private void refreshCanvasSize() { |
598 |
if (fitButton.getSelection()) { |
765 |
if (fitAction.isChecked()) { |
599 |
// This little hack is necessary to get the client area without scrollbars; |
766 |
// This little hack is necessary to get the client area without scrollbars; |
600 |
// they'll be automatically restored if necessary after Canvas.setBounds() |
767 |
// they'll be automatically restored if necessary after Canvas.setBounds() |
601 |
scrolledComposite.getHorizontalBar().setVisible(false); |
768 |
scrolledComposite.getHorizontalBar().setVisible(false); |
602 |
scrolledComposite.getVerticalBar().setVisible(false); |
769 |
scrolledComposite.getVerticalBar().setVisible(false); |
603 |
|
770 |
|
604 |
Rectangle bounds = scrolledComposite.getClientArea(); |
771 |
Rectangle bounds = scrolledComposite.getClientArea(); |
605 |
if (screenshotImage != null) { |
772 |
if (workImage != null) { |
606 |
Rectangle imageBounds = screenshotImage.getBounds(); |
773 |
Rectangle imageBounds = workImage.getBounds(); |
607 |
if (imageBounds.width > bounds.width || imageBounds.height > bounds.height) { |
774 |
if (imageBounds.width > bounds.width || imageBounds.height > bounds.height) { |
608 |
double xRatio = (double) bounds.width / imageBounds.width; |
775 |
double xRatio = (double) bounds.width / imageBounds.width; |
609 |
double yRatio = (double) bounds.height / imageBounds.height; |
776 |
double yRatio = (double) bounds.height / imageBounds.height; |
Lines 616-623
Link Here
|
616 |
} else { |
783 |
} else { |
617 |
scaleFactor = 1.0; |
784 |
scaleFactor = 1.0; |
618 |
Rectangle bounds = scrolledComposite.getClientArea(); |
785 |
Rectangle bounds = scrolledComposite.getClientArea(); |
619 |
if (screenshotImage != null) { |
786 |
if (workImage != null) { |
620 |
Rectangle imageBounds = screenshotImage.getBounds(); |
787 |
Rectangle imageBounds = workImage.getBounds(); |
621 |
bounds.width = imageBounds.width; |
788 |
bounds.width = imageBounds.width; |
622 |
bounds.height = imageBounds.height; |
789 |
bounds.height = imageBounds.height; |
623 |
} |
790 |
} |
Lines 628-652
Link Here
|
628 |
} |
795 |
} |
629 |
|
796 |
|
630 |
/** |
797 |
/** |
631 |
* Decorates the screenshot canvas with the selection rectangle; this is done while still selecting, so it does not |
|
|
632 |
* have all adornments of a {@link #drawSelection(GC) finished} selection |
633 |
*/ |
634 |
@SuppressWarnings("deprecation") |
635 |
private void drawSelectionPreview(GC gc) { |
636 |
gc.setLineDash(new int[] { 4 }); |
637 |
gc.setXORMode(true); |
638 |
gc.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_WHITE)); |
639 |
gc.drawRectangle(getScaledSelection()); |
640 |
gc.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_BLACK)); |
641 |
gc.drawRectangle(getScaledSelection()); |
642 |
gc.setXORMode(false); |
643 |
gc.setLineStyle(SWT.LINE_SOLID); |
644 |
} |
645 |
|
646 |
/** |
647 |
* Decorates the screenshot canvas with the selection rectangle, resize grab points and other adornments |
798 |
* Decorates the screenshot canvas with the selection rectangle, resize grab points and other adornments |
648 |
*/ |
799 |
*/ |
649 |
private void drawSelection(GC gc) { |
800 |
private void drawSelection(GC gc) { |
|
|
801 |
if (currentSelection == null) { |
802 |
return; |
803 |
} |
650 |
Rectangle scaledSelection = getScaledSelection(); |
804 |
Rectangle scaledSelection = getScaledSelection(); |
651 |
|
805 |
|
652 |
// Draw shadow |
806 |
// Draw shadow |
Lines 666-683
Link Here
|
666 |
|
820 |
|
667 |
// Draw selection rectangle |
821 |
// Draw selection rectangle |
668 |
gc.setLineStyle(SWT.LINE_SOLID); |
822 |
gc.setLineStyle(SWT.LINE_SOLID); |
669 |
gc.setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_DARK_GRAY)); |
823 |
gc.setForeground(getShell().getDisplay().getSystemColor(SWT.COLOR_DARK_GRAY)); |
670 |
gc.drawRectangle(scaledSelection); |
824 |
gc.drawRectangle(scaledSelection); |
671 |
|
825 |
|
672 |
// Draw grab points |
826 |
// Draw grab points |
673 |
gc.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_WHITE)); |
827 |
gc.setBackground(getShell().getDisplay().getSystemColor(SWT.COLOR_WHITE)); |
674 |
gc.setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_BLACK)); |
828 |
gc.setForeground(getShell().getDisplay().getSystemColor(SWT.COLOR_BLACK)); |
675 |
for (GrabPoint point : grabPoints) { |
829 |
for (GrabPoint point : grabPoints) { |
676 |
gc.fillRectangle(point.grabArea); |
830 |
gc.fillRectangle(point.grabArea); |
677 |
gc.drawRectangle(point.grabArea); |
831 |
gc.drawRectangle(point.grabArea); |
678 |
} |
832 |
} |
679 |
} |
833 |
} |
680 |
|
834 |
|
|
|
835 |
/** |
836 |
* Connects the previous mark point to the new reference point, by drawing a new line |
837 |
*/ |
838 |
private void drawMarkLine(int x, int y) { |
839 |
if (startPoint != null) { |
840 |
clearAction.setEnabled(true); |
841 |
workImageGC.drawLine(startPoint.x, startPoint.y, x, y); |
842 |
startPoint.x = x; |
843 |
startPoint.y = y; |
844 |
canvas.redraw(); |
845 |
} |
846 |
} |
847 |
|
681 |
private static enum SelectionSide { |
848 |
private static enum SelectionSide { |
682 |
|
849 |
|
683 |
LEFT, RIGHT, TOP, BOTTOM; |
850 |
LEFT, RIGHT, TOP, BOTTOM; |
Lines 706-727
Link Here
|
706 |
|
873 |
|
707 |
private List<GrabPoint> grabPoints = new ArrayList<GrabPoint>(8); |
874 |
private List<GrabPoint> grabPoints = new ArrayList<GrabPoint>(8); |
708 |
|
875 |
|
709 |
private Image getCropScreenshot() { |
876 |
/** |
710 |
if (currentSelection == null) { |
877 |
* Creates the final screenshot |
711 |
return screenshotImage; |
878 |
* |
|
|
879 |
* @return The final screenshot, with all markings, and cropped according to user settings; <strong>The caller is |
880 |
* responsible for disposing the returned image</strong> |
881 |
*/ |
882 |
public Image createImage() { |
883 |
Image screenshot = new Image(getShell().getDisplay(), currentSelection != null ? currentSelection |
884 |
: workImage.getBounds()); |
885 |
|
886 |
GC gc = new GC(screenshot); |
887 |
if (currentSelection != null) { |
888 |
gc.drawImage(workImage, currentSelection.x, currentSelection.y, currentSelection.width, |
889 |
currentSelection.height, 0, 0, currentSelection.width, currentSelection.height); |
890 |
} else { |
891 |
gc.drawImage(workImage, 0, 0); |
712 |
} |
892 |
} |
713 |
|
|
|
714 |
Image image = new Image(Display.getDefault(), currentSelection); |
715 |
GC gc = new GC(image); |
716 |
gc.drawImage(screenshotImage, currentSelection.x, currentSelection.y, currentSelection.width, |
717 |
currentSelection.height, 0, 0, currentSelection.width, currentSelection.height); |
718 |
gc.dispose(); |
893 |
gc.dispose(); |
719 |
|
894 |
|
720 |
return image; |
895 |
return screenshot; |
721 |
} |
896 |
} |
722 |
|
897 |
|
723 |
public Image getScreenshotImage() { |
898 |
private void markAttachmentDirty() { |
724 |
return getCropScreenshot(); |
899 |
NewAttachmentWizard wizard = (NewAttachmentWizard) getWizard(); |
|
|
900 |
((ImageAttachment) wizard.getAttachment()).markDirty(); |
725 |
} |
901 |
} |
726 |
|
902 |
|
727 |
} |
903 |
} |