1 /* -*- C++ -*-
2 *
3 * This file is part of RawTherapee.
4 *
5 * Copyright (c) 2004-2010 Gabor Horvath <hgabor@rawtherapee.com>
6 *
7 * RawTherapee is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * RawTherapee is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with RawTherapee. If not, see <http://www.gnu.org/licenses/>.
19 */
20 #pragma once
21 #include <gtkmm.h>
22 //#include "../rtengine/imagefloat.h"
23 #include "editid.h"
24 #include "cursormanager.h"
25 #include "../rtengine/rt_math.h"
26 #include "../rtengine/coord.h"
27 #include "guiutils.h"
28 #include "options.h"
29
30 #ifdef GUIVERSION
31 #include "rtsurface.h"
32 #endif
33
34 class EditDataProvider;
35 class EditSubscriber;
36
37 /** @file
38 *
39 * The Edit mechanism is designed to let tools (subscribers) communicate with the preview area (provider).
40 * Subscribers will be tools that need to create some graphics in the preview area, to let the user interact
41 * with it in a more user friendly way.
42 *
43 * Do not confuse with _local_ editing, which is another topic implemented in another class. The Edit feature
44 * is also not supported in batch editing from the File Browser.
45 *
46 * Edit tool can be of 2 types: pipette editing and object editing.
47 *
48 * ## Pipette edition
49 *
50 * By using this class, a pipette mechanism can be handled on the preview.
51 *
52 * Each pipette Edit tool must have a unique ID, that will identify them, and which let the ImProcCoordinator
53 * or other mechanism act as appropriated. They are all defined in rtgui/editid.h. A buffer type has to be given
54 * too, to know which kind of buffer to allocate (see EditSubscriber::BufferType).
55 *
56 * Only the first mouse button can be used to manipulate the pipette on the Preview, that's why the developer has
57 * to implement at least the following 4 methods:
58 * - mouseOver
59 * - button1Pressed
60 * - drag1
61 * - button1Released
62 *
63 * Actually, only curves does use this class, and everything is handled for curve implementor (as much as possible).
64 * See the curve's class documentation to see how to implement the curve's pipette feature.
65 *
66 * ### Event handling
67 *
68 * The mouseOver method is called on each mouse movement, excepted when dragging a point. This method can then access
69 * the pipetteVal array values, which contain the mean of the pixel read in the buffer, or -1 if the cursor is outside
70 * of the image. In this case, EditDataProvider::object is also set to 0 (and 1 if over the image).
71 *
72 * When the user will click on the left mouse button while pressing the CTRL key, button1Pressed will be called.
73 * Setting "dragging" to true (or false) is not required for the pipette type editing.
74 *
75 * The drag1 method will be called on all subsequent mouse move. The pipetteVal[3] array will already be filled with
76 * the mean of the read values under the cursor (actually a fixed square of 8px). If the BufferType is BT_SINGLEPLANE_FLOAT,
77 * only the first array value will be filled.
78 *
79 * Then the button1Released will be called to stop the dragging.
80 *
81 * ## Object edition
82 *
83 * By using this class, objects can be drawn and manipulated on the preview.
84 *
85 * The developer has to handle the buttonPress, buttonRelease, drag and mouseOver methods that he needs. There
86 * are buttonPress, buttonRelease and drag methods dedicated to each mouse button, for better flexibility
87 * (e.g.button2Press, button2Release, drag2 will handle event when mouse button 2 is used first). RT actually
88 * does not handle multiple mouse button event (e.g. button1 + button2), only one at a time. The first button pressed
89 * set the mechanism, all other combined button press are ignored.
90 *
91 * The developer also have to fill 2 display list with object of the Geometry subclass. Each geometric shape
92 * _can_ be used in one or the other, or both list at a time.
93 *
94 * The first list (visibleGeometry) is used to be displayed on the preview. The developer will have to set their state
95 * manually (see Geometry::State), but the display shape, line width and color can be handled automatically, or with
96 * specific values. To be displayed, the F_VISIBLE flag has to be set through the setActive or setVisible methods.
97 *
98 * The second list (mouseOverGeometry) is used in a backbuffer, the color used to draw the shape being the id of the
99 * mouseOverGeometry. As an example, you could create a line to be shown in the preview, but create 2 filled Circle object
100 * to be used as mouseOver detection, one on each end of the line. The association between both shape (visible and mouseOver)
101 * is handled by the developer. To be displayed on this backbuffer, the F_HOVERABLE flag has to be set through the
102 * setActive or setHoverable methods. For overlapping mouse over geometry, the priority is set by the order in the list :
103 * the last item is detected first (think of it like a stack piled up).
104 *
105 *
106 * ### Event handling
107 *
108 * RT will draw in the back buffer all mouseOverGeometry set by the developer once the Edit button is pressed, and handle
109 * the events automatically.
110 *
111 * RT will call the mouseOver method on each mouse movement where no mouse button is pressed.
112 *
113 * On mouse button press over a mouseOverGeometry (that has F_HOVERABLE set), it will call the button press method corresponding
114 * to the button (e.g. button1Pressed for mouse button 1), with the modifier key as parameter. Any other mouse button pressed at
115 * the same time will be ignored. It's up to the developer to decide whether this action is starting a 'drag' or 'pick' action,
116 * by setting the 'action' parameter to the appropriated value.
117 *
118 * If the user sets action to ES_ACTION_DRAGGING, RT will then send drag1 events (to stay with our button 1 pressed example) on each
119 * mouse movement. It's up to the developer of the tool to handle the dragging. The EditProvider class will help you in this by
120 * handling the actual position in various coordinate system and ways.
121 *
122 * When the user will release the mouse button, RT will call the button1Release event (in our example). The developer have
123 * then to set action to ES_ACTION_NONE.
124 *
125 * If the user sets action to ES_ACTION_PICKING, RT will keep in memory the mouseOver object that was selected when pressing the mouse
126 * (e.g. button 1), as well as the modifier keys.
127 *
128 * The element is said to be picked when the mouse button is released over the same mouse over object and with the same active
129 * modifier keys. In this case, the corresponding picked event (e.g. picked1 in our example) and the 'picked' flag will be true.
130 * If any of those condition is false, picked1 will still be be called to terminate the initiated picking action, but 'picked'
131 * will be false. This is necessary because the user may want to update the geometry if the picking is aborted. The developer have
132 * then to set action to ES_ACTION_NONE.
133 *
134 * Picking an on-screen element correspond to single-clicking on it. No double click is supported so far.
135 *
136 * Each of these methods have to returns a boolean value saying that the preview has to be refreshed or not (i.e. the displayed
137 * geometry).
138 *
139 * ## Other general internal implementation notes
140 *
141 * When a tool is being constructed, unique IDs are affected to the EditSubscribers of the Pipette type.
142 * Then the EditorPanel class will ask all ToolPanel to register the 'after' preview ImageArea object as data provider.
143 * The Subscribers have now to provide a toggle button to click on to start the Edit listening. When toggling on, the Subscriber
144 * register itself to the DataProvider, then an event is thrown through the standard ToolPanelListener::panelChanged
145 * method to update the preview with new graphics to be displayed. If a previous Edit button was active, it will be deactivated
146 * (the Edit buttons are mutually exclusive). For the Pipette type, a buffer will be created and has to be populated
147 * by the developer in rtengine's pipeline. The unique pipette ID will be used to know where to fill the buffer, as each pipette
148 * will need different data, corresponding to the state of the image right before the tool that needs pipette values. E.g for
149 * the HSV tool, the Hue and Saturation and Value curves are applied on the current state of the image. That's why the pipette
150 * of the H, S and V curve will share the same data of this "current state", otherwise the read value would be wrong.
151 *
152 * When the Edit process stops, the Subscriber is removed from the DataProvider, so buffers can be freed up.
153 * A new ToolPanelListener::panelChanged event is also thrown to update the preview again, without the tool's
154 * graphical objects. The Edit button is also toggled off (by the user or programmatically).
155 *
156 * It means that each Edit buttons toggled on will start an update of the preview which might or might not create
157 * a new History entry, depending on the ProcEvent used.
158 *
159 */
160
161
162
163 class ObjectMOBuffer
164 {
165 private:
166
167 // Used to draw the objects where the color correspond to the object's ID, in order to find the correct object when hovering
168 Cairo::RefPtr<Cairo::ImageSurface> objectMap;
169 ObjectMode objectMode;
170
171 protected:
172
173 // To avoid duplicated information, we points to a EditDataProvider that contains the current EditSubscriber
174 // instead of pointing to the EditSubscriber directly
175 EditDataProvider* dataProvider;
176
177 void createBuffer(int width, int height);
178 void resize(int newWidth, int newHeight);
179 void flush();
180 EditSubscriber *getEditSubscriber ();
181
182 public:
183 explicit ObjectMOBuffer (EditDataProvider *dataProvider);
184 ~ObjectMOBuffer();
185
186 EditDataProvider* getDataProvider ();
187 void setObjectMode (ObjectMode newType);
188 ObjectMode getObjectMode ();
189
190 Cairo::RefPtr<Cairo::ImageSurface>& getObjectMap ();
191
192 // return true if the buffer has been allocated
193 bool bufferCreated();
194
195 int getObjectID(const rtengine::Coord& location);
196 };
197
198
199 /** @brief Coordinate system where the widgets will be drawn
200 *
201 * The EditCoordSystem is used to define a screen and an image coordinate system.
202 */
203 class EditCoordSystem
204 {
205 public:
~EditCoordSystem()206 virtual ~EditCoordSystem() {}
207
208 /// Convert the widget's DrawingArea (i.e. preview area) coords to the edit buffer coords / int values
209 virtual void screenCoordToCropBuffer (int phyx, int phyy, int& cropx, int& cropy) = 0;
210 /// Convert the widget's DrawingArea (i.e. preview area) coords to the edit buffer coords / double values
211 virtual void screenCoordToCropBuffer (double phyx, double phyy, double& cropx, double& cropy) = 0;
212
213 /// Convert the widget's DrawingArea (i.e. preview area) coords to the full image coords / int values
214 virtual void screenCoordToImage (int phyx, int phyy, int& imgx, int& imgy) = 0;
215 /// Convert the widget's DrawingArea (i.e. preview area) coords to the full image coords / double values
216 virtual void screenCoordToImage (double phyx, double phyy, double& imgx, double& imgy) = 0;
217
218 /// Convert the image coords to the widget's DrawingArea (i.e. preview area) coords / int values
219 virtual void imageCoordToScreen (int imgx, int imgy, int& phyx, int& phyy) = 0;
220 /// Convert the image coords to the widget's DrawingArea (i.e. preview area) coords / double values
221 virtual void imageCoordToScreen (double imgx, double imgy, double& phyx, double& phyy) = 0;
222
223 /// Convert the image coords to the crop's canvas coords (full image + padding) / int values
224 virtual void imageCoordToCropCanvas (int imgx, int imgy, int& phyx, int& phyy) = 0;
225 /// Convert the image coords to the crop's canvas coords (full image + padding) / double values
226 virtual void imageCoordToCropCanvas (double imgx, double imgy, double& phyx, double& phyy) = 0;
227
228 /// Convert the image coords to the edit buffer coords (includes borders) / int values
229 virtual void imageCoordToCropBuffer (int imgx, int imgy, int& phyx, int& phyy) = 0;
230 /// Convert the image coords to the edit buffer coords (includes borders) / double values
231 virtual void imageCoordToCropBuffer (double imgx, double imgy, double& phyx, double& phyy) = 0;
232
233 /// Convert the image coords to the displayed image coords (no borders here) / int values
234 virtual void imageCoordToCropImage (int imgx, int imgy, int& phyx, int& phyy) = 0;
235 /// Convert the image coords to the displayed image coords (no borders here) / double values
236 virtual void imageCoordToCropImage (double imgx, double imgy, double& phyx, double& phyy) = 0;
237
238 /// Convert a size value from the preview's scale to the image's scale
239 virtual int scaleValueToImage (int value) = 0;
240
241 /// Convert a size value from the preview's scale to the image's scale
242 virtual float scaleValueToImage (float value) = 0;
243
244 /// Convert a size value from the preview's scale to the image's scale
245 virtual double scaleValueToImage (double value) = 0;
246
247 /// Convert a size value from the image's scale to the preview's scale
248 virtual int scaleValueToCanvas (int value) = 0;
249
250 /// Convert a size value from the image's scale to the preview's scale
251 virtual float scaleValueToCanvas (float value) = 0;
252
253 /// Convert a size value from the image's scale to the preview's scale
254 virtual double scaleValueToCanvas (double value) = 0;
255 };
256
257 class RGBColor
258 {
259 double r;
260 double g;
261 double b;
262
263 public:
264 RGBColor ();
265 explicit RGBColor (double r, double g, double b);
266 explicit RGBColor (char r, char g, char b);
267
268 void setColor (double r, double g, double b);
269 void setColor (char r, char g, char b);
270
271 double getR ();
272 double getG ();
273 double getB ();
274 };
275
276 class RGBAColor : public RGBColor
277 {
278 double a;
279
280 public:
281 RGBAColor ();
282 explicit RGBAColor (double r, double g, double b, double a);
283 explicit RGBAColor (char r, char g, char b, char a);
284
285 void setColor (double r, double g, double b, double a);
286 void setColor (char r, char g, char b, char a);
287
288 double getA ();
289 };
290
291 /// @brief Displayable and MouseOver geometry base class
292 class Geometry
293 {
294 public:
295 /// @brief Graphical state of the element
296 enum State {
297 NORMAL, /// Default state
298 ACTIVE, /// Focused state
299 PRELIGHT, /// Hovered state
300 DRAGGED, /// When being dragged
301 INSENSITIVE /// Displayed but insensitive
302 };
303
304 /// @brief Coordinate space and origin of the point
305 enum Datum {
306 IMAGE, /// Image coordinate system with image's top left corner as origin
307 CLICKED_POINT, /// Screen coordinate system with clicked point as origin
308 CURSOR /// Screen coordinate system with actual cursor position as origin
309 };
310 enum Flags {
311 F_VISIBLE = 1 << 0, /// true if the geometry have to be drawn on the visible layer
312 F_HOVERABLE = 1 << 1, /// true if the geometry have to be drawn on the "mouse over" layer
313 F_AUTO_COLOR = 1 << 2, /// true if the color depend on the state value, not the color field above
314 F_DASHED = 1 << 3, /// true if the geometry have to be drawn as a dash line
315 F_FRAME = 1 << 4, /// true if the geometry represent a base shape used to compute a usable shape (e.g. : control cage)
316 };
317
318 /// @brief Key point of the image's rectangle that is used to locate the icon copy to the target point:
319 enum DrivenPoint {
320 DP_CENTERCENTER,
321 DP_TOPLEFT,
322 DP_TOPCENTER,
323 DP_TOPRIGHT,
324 DP_CENTERRIGHT,
325 DP_BOTTOMRIGHT,
326 DP_BOTTOMCENTER,
327 DP_BOTTOMLEFT,
328 DP_CENTERLEFT
329 };
330
331 protected:
332 static const std::vector<double> dash;
333 RGBColor innerLineColor;
334 RGBColor outerLineColor;
335 short flags;
336
337 public:
338 float innerLineWidth; // ...outerLineWidth = innerLineWidth+2
339 Datum datum;
340 State state; // set by the Subscriber
341
342 Geometry ();
~Geometry()343 virtual ~Geometry() {}
344
345 void setInnerLineColor (double r, double g, double b);
346 void setInnerLineColor (char r, char g, char b);
347 RGBColor getInnerLineColor ();
348 void setOuterLineColor (double r, double g, double b);
349 void setOuterLineColor (char r, char g, char b);
350 RGBColor getOuterLineColor ();
351 double getOuterLineWidth ();
352 double getMouseOverLineWidth ();
353 void setAutoColor (bool aColor);
354 bool isVisible ();
355 void setVisible (bool visible);
356 bool isFrame ();
357 void setFrame (bool frame);
358 bool isHoverable ();
359 void setHoverable (bool visible);
360 bool isDashed ();
361 void setDashed (bool dashed);
362
363
364 // setActive will enable/disable the visible and hoverable flags in one shot!
365 void setActive (bool active);
366
367 virtual void drawOuterGeometry (Cairo::RefPtr<Cairo::Context> &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) = 0;
368 virtual void drawInnerGeometry (Cairo::RefPtr<Cairo::Context> &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) = 0;
369 virtual void drawToMOChannel (Cairo::RefPtr<Cairo::Context> &cr, unsigned short id, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) = 0;
370 };
371
372 #ifdef GUIVERSION
373
374 class Circle : public Geometry
375 {
376 public:
377 rtengine::Coord center;
378 int radius;
379 bool filled;
380 bool radiusInImageSpace; /// If true, the radius depend on the image scale; if false, it is a fixed 'screen' size
381
382 Circle ();
383 Circle (rtengine::Coord& center, int radius, bool filled = false, bool radiusInImageSpace = false);
384 Circle (int centerX, int centerY, int radius, bool filled = false, bool radiusInImageSpace = false);
385
386 void drawOuterGeometry (Cairo::RefPtr<Cairo::Context> &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) override;
387 void drawInnerGeometry (Cairo::RefPtr<Cairo::Context> &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) override;
388 void drawToMOChannel (Cairo::RefPtr<Cairo::Context> &cr, unsigned short id, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) override;
389 };
390
391 class Line : public Geometry
392 {
393 public:
394 rtengine::Coord begin;
395 rtengine::Coord end;
396
397 Line ();
398 Line (rtengine::Coord& begin, rtengine::Coord& end);
399 Line (int beginX, int beginY, int endX, int endY);
400
401 void drawOuterGeometry (Cairo::RefPtr<Cairo::Context> &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) override;
402 void drawInnerGeometry (Cairo::RefPtr<Cairo::Context> &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) override;
403 void drawToMOChannel (Cairo::RefPtr<Cairo::Context> &cr, unsigned short id, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) override;
404 };
405
406 class PolyLine : public Geometry
407 {
408 public:
409 std::vector<rtengine::CoordD> points;
410 bool filled;
411 bool closed;
412
413 PolyLine ();
414
415 void drawOuterGeometry (Cairo::RefPtr<Cairo::Context> &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) override;
416 void drawInnerGeometry (Cairo::RefPtr<Cairo::Context> &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) override;
417 void drawToMOChannel (Cairo::RefPtr<Cairo::Context> &cr, unsigned short id, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) override;
418 };
419
420 class Rectangle : public Geometry
421 {
422 public:
423 rtengine::Coord topLeft;
424 rtengine::Coord bottomRight;
425 bool filled;
426
427 Rectangle ();
428
429 void setXYWH(int left, int top, int width, int height);
430 void setXYXY(int left, int top, int right, int bottom);
431 void setXYWH(rtengine::Coord topLeft, rtengine::Coord widthHeight);
432 void setXYXY(rtengine::Coord topLeft, rtengine::Coord bottomRight);
433 void drawOuterGeometry (Cairo::RefPtr<Cairo::Context> &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) override;
434 void drawInnerGeometry (Cairo::RefPtr<Cairo::Context> &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) override;
435 void drawToMOChannel (Cairo::RefPtr<Cairo::Context> &cr, unsigned short id, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) override;
436 };
437
438 class OPIcon : public Geometry // OP stands for "On Preview"
439 {
440
441 private:
442 Cairo::RefPtr<RTSurface> normalImg;
443 Cairo::RefPtr<RTSurface> prelightImg;
444 Cairo::RefPtr<RTSurface> activeImg;
445 Cairo::RefPtr<RTSurface> draggedImg;
446 Cairo::RefPtr<RTSurface> insensitiveImg;
447
448 static void updateImages();
449 void changeImage(Glib::ustring &newImage);
450 void drawImage (Cairo::RefPtr<RTSurface> &img, Cairo::RefPtr<Cairo::Context> &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem);
451 void drawMOImage (Cairo::RefPtr<RTSurface> &img, Cairo::RefPtr<Cairo::Context> &cr, unsigned short id, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem);
452 void drivenPointToRectangle(const rtengine::Coord &pos, rtengine::Coord &topLeft, rtengine::Coord &bottomRight, int W, int H);
453
454 public:
455 DrivenPoint drivenPoint;
456 rtengine::Coord position;
457
458 OPIcon (const Cairo::RefPtr<RTSurface> &normal,
459 const Cairo::RefPtr<RTSurface> &active,
460 const Cairo::RefPtr<RTSurface> &prelight = {},
461 const Cairo::RefPtr<RTSurface> &dragged = {},
462 const Cairo::RefPtr<RTSurface> &insensitive = {},
463 DrivenPoint drivenPoint = DP_CENTERCENTER);
464 OPIcon (Glib::ustring normalImage, Glib::ustring activeImage, Glib::ustring prelightImage = "", Glib::ustring draggedImage = "", Glib::ustring insensitiveImage = "", DrivenPoint drivenPoint = DP_CENTERCENTER);
465 const Cairo::RefPtr<RTSurface> getNormalImg();
466 const Cairo::RefPtr<RTSurface> getPrelightImg();
467 const Cairo::RefPtr<RTSurface> getActiveImg();
468 const Cairo::RefPtr<RTSurface> getDraggedImg();
469 const Cairo::RefPtr<RTSurface> getInsensitiveImg();
470 void drawOuterGeometry (Cairo::RefPtr<Cairo::Context> &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) override;
471 void drawInnerGeometry (Cairo::RefPtr<Cairo::Context> &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) override;
472 void drawToMOChannel (Cairo::RefPtr<Cairo::Context> &cr, unsigned short id, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) override;
473 };
474
475 class OPAdjuster : public Geometry // OP stands for "On Preview"
476 {
477
478 };
479
480 #endif
481
482 /// @brief Method for client tools needing Edit information
483 class EditSubscriber
484 {
485
486 public:
487
488 private:
489 EditUniqueID ID; /// this will be used in improcfun to locate the data that has to be stored in the buffer; it must be unique in RT
490 EditType editingType;
491 BufferType bufferType;
492 EditDataProvider *provider;
493
494 protected:
495 std::vector<Geometry*> visibleGeometry; /// displayed geometry
496 std::vector<Geometry*> mouseOverGeometry; /// mouseOver geometry, drawn in a hidden buffer
497 enum {
498 ES_ACTION_NONE, ///
499 ES_ACTION_DRAGGING, /// set action to this value in the buttonPressed event to start dragging and ask for drag event
500 ES_ACTION_PICKING /// set action to this value in the buttonPressed event whenever the user is picking something through a single click. In this case, the pickX events will be called INSTEAD of buttonXReleased !
501 } action; /// object mode only, ignored in Pipette mode
502
503 public:
504 explicit EditSubscriber (EditType editType);
~EditSubscriber()505 virtual ~EditSubscriber () {}
506
507 void setEditProvider(EditDataProvider *provider);
508 EditDataProvider* getEditProvider () const;
509 void setEditID(EditUniqueID ID, BufferType buffType);
510 bool isCurrentSubscriber();
511 virtual void subscribe();
512 virtual void unsubscribe();
513 virtual void switchOffEditMode (); /// Occurs when the user want to stop the editing mode
514 EditUniqueID getEditID();
515 EditType getEditingType();
516 BufferType getPipetteBufferType();
517 bool isDragging(); /// Returns true if something is being dragged and drag events has to be sent (object mode only)
518 bool isPicking(); /// Returns true if something is being picked
519
520 /** @brief Get the cursor to be displayed when above handles
521 @param objectID object currently "hovered" */
522 virtual CursorShape getCursor (int objectID);
523
524 /** @brief Get the cursor to be displayed when above handles
525 @param objectID object currently "hovered"
526 @param xPos X cursor position in image space
527 @param yPos Y cursor position in image space */
528 virtual CursorShape getCursor (int objectID, int xPos, int yPos);
529
530 /** @brief Triggered when the mouse is moving over an object
531 This method is also triggered when the cursor is moving over the image in ET_PIPETTE mode
532 @param modifierKey Gtk's event modifier key (GDK_CONTROL_MASK | GDK_SHIFT_MASK | ...)
533 @return true if the preview has to be redrawn, false otherwise */
534 virtual bool mouseOver(int modifierKey);
535
536 /** @brief Triggered when mouse button 1 is pressed, together with the CTRL modifier key if the subscriber is of type ET_PIPETTE
537 Once the key is pressed, RT will enter in drag1 mode on subsequent mouse movements
538 @param modifierKey Gtk's event modifier key (GDK_CONTROL_MASK | GDK_SHIFT_MASK | ...)
539 @return true if the preview has to be redrawn, false otherwise */
540 virtual bool button1Pressed(int modifierKey);
button1Pressed(int modifierKey,double pressure)541 virtual bool button1Pressed(int modifierKey, double pressure) { return button1Pressed(modifierKey); }
542
543 /** @brief Triggered when mouse button 1 is released
544 @return true if the preview has to be redrawn, false otherwise */
545 virtual bool button1Released ();
546
547 /** @brief Triggered when mouse button 2 is pressed (middle button)
548 Once the key is pressed, RT will enter in drag2 mode on subsequent mouse movements
549 @param modifierKey Gtk's event modifier key (GDK_CONTROL_MASK | GDK_SHIFT_MASK | ...)
550 @return true if the preview has to be redrawn, false otherwise */
551 virtual bool button2Pressed (int modifierKey);
button2Pressed(int modifierKey,double pressure)552 virtual bool button2Pressed(int modifierKey, double pressure) { return button2Pressed(modifierKey); }
553
554 /** @brief Triggered when mouse button 2 is released (middle button)
555 @return true if the preview has to be redrawn, false otherwise */
556 virtual bool button2Released ();
557
558 /** @brief Triggered when mouse button 3 is pressed (right button)
559 Once the key is pressed, RT will enter in drag3 mode on subsequent mouse movements
560 @param modifierKey Gtk's event modifier key (GDK_CONTROL_MASK | GDK_SHIFT_MASK | ...)
561 @return true if the preview has to be redrawn, false otherwise */
562 virtual bool button3Pressed (int modifierKey);
button3Pressed(int modifierKey,double pressure)563 virtual bool button3Pressed(int modifierKey, double pressure) { return button3Pressed(modifierKey); }
564
565 /** @brief Triggered when mouse button 3 is released (right button)
566 @return true if the preview has to be redrawn, false otherwise */
567 virtual bool button3Released ();
568
569 /** @brief Triggered when the user is moving while holding down mouse button 1
570 @param modifierKey Gtk's event modifier key (GDK_CONTROL_MASK | GDK_SHIFT_MASK | ...)
571 @return true if the preview has to be redrawn, false otherwise */
572 virtual bool drag1(int modifierKey);
drag1(int modifierKey,double pressure)573 virtual bool drag1(int modifierKey, double pressure) { return drag1(modifierKey); }
574
575 /** @brief Triggered when the user is moving while holding down mouse button 2
576 @param modifierKey Gtk's event modifier key (GDK_CONTROL_MASK | GDK_SHIFT_MASK | ...)
577 @return true if the preview has to be redrawn, false otherwise */
578 virtual bool drag2(int modifierKey);
drag2(int modifierKey,double pressure)579 virtual bool drag2(int modifierKey, double pressure) { return drag2(modifierKey); }
580
581 /** @brief Triggered when the user is moving while holding down mouse button 3
582 @param modifierKey Gtk's event modifier key (GDK_CONTROL_MASK | GDK_SHIFT_MASK | ...)
583 @return true if the preview has to be redrawn, false otherwise */
584 virtual bool drag3(int modifierKey);
drag3(int modifierKey,double pressure)585 virtual bool drag3(int modifierKey, double pressure) { return drag3(modifierKey); }
586
587 /** @brief Triggered when the user is releasing mouse button 1 while in action==ES_ACTION_PICKING mode
588 No modifier key is provided, since having a different modifier key than on button press will set picked to false.
589 @param picked True if the cursor is still above the the same object than on button pressed and with the same modifier keys.
590 If false, the user moved the cursor away or the modifier key is different, so the element is considered as NOT selected.
591 @return true if the preview has to be redrawn, false otherwise */
592 virtual bool pick1 (bool picked);
593
594 /** @brief Triggered when the user is releasing mouse button 2 while in action==ES_ACTION_PICKING mode
595 @param picked True if the cursor is still above the the same object than on button pressed and with the same modifier keys.
596 If false, the user moved the cursor away or the modifier key is different, so the element is considered as NOT selected.
597 @return true if the preview has to be redrawn, false otherwise */
598 virtual bool pick2 (bool picked);
599
600 /** @brief Triggered when the user is releasing mouse button 3 while in action==ES_ACTION_PICKING mode
601 @param picked True if the cursor is still above the the same object than on button pressed and with the same modifier keys.
602 If false, the user moved the cursor away or the modifier key is different, so the element is considered as NOT selected.
603 @return true if the preview has to be redrawn, false otherwise */
604 virtual bool pick3 (bool picked);
605
606 /**
607 * triggered for scroll wheel events. Only for ET_OBJECTS types
608 *
609 * @param modifierKey Gtk's event modifier key (GDK_CONTROL_MASK | GDK_SHIFT_MASK | ...)
610 * @param direction Direction of the scroll (see Gtk documentation for more information)
611 * @param deltaX values sent by Gtk on scroll events
612 * @param deltaY values sent by Gtk on scroll events
613 * @param propagateEvent value to state whether the event has been catched (false) or should be propagated (true)
614 * @return false if the scroll event has to be propagated to the crop
615 * window, true if the event has been processed
616 */
617 virtual bool scroll(int modifierKey, GdkScrollDirection direction, double deltaX, double deltaY, bool &propagateEvent);
618
619 /** @brief Get the geometry to be shown to the user */
620 const std::vector<Geometry*>& getVisibleGeometry ();
621
622 /** @brief Get the geometry to be drawn in the "mouse over" channel, hidden from the user */
623 const std::vector<Geometry*>& getMouseOverGeometry ();
624 };
625
626 /** @brief Class to handle the furniture of data to the subscribers.
627 *
628 * It is admitted that only one Subscriber can ask data at a time. If the Subscriber is of type ET_PIPETTE, it will have to
629 * trigger the usual event so that the image will be reprocessed to compute the buffer of the current subscriber.
630 */
631 class EditDataProvider
632 {
633
634 private:
635 EditSubscriber *currSubscriber;
636
637 public:
638 int object; /// ET_OBJECTS mode: Object detected under the cursor, 0 otherwise; ET_PIPETTE mode: 1 if above the image, 0 otherwise
639 float pipetteVal[3]; /// Current pipette values; if bufferType==BT_SINGLEPLANE_FLOAT, #2 & #3 will be set to 0
640
641 rtengine::Coord posScreen; /// Location of the mouse button press, in preview image space
642 rtengine::Coord posImage; /// Location of the mouse button press, in the full image space
643 rtengine::Coord deltaScreen; /// Delta relative to posScreen
644 rtengine::Coord deltaImage; /// Delta relative to posImage
645 rtengine::Coord deltaPrevScreen; /// Delta relative to the previous mouse location, in preview image space
646 rtengine::Coord deltaPrevImage; /// Delta relative to the previous mouse location, in the full image space
647
648 EditDataProvider();
649 virtual ~EditDataProvider();
650
651 virtual void subscribe(EditSubscriber *subscriber);
652 virtual void unsubscribe(); /// Occurs when the subscriber has been switched off first
653 virtual void switchOffEditMode (); /// Occurs when the user want to stop the editing mode
654 int getObject() const;
655 void setObject(int newObject);
656
657 virtual CursorShape getCursor(int objectID, int xPos, int yPos);
658 // virtual CursorShape getCursor(int objectID);
659 int getPipetteRectSize ();
660 EditSubscriber* getCurrSubscriber();
661 virtual void getImageSize (int &w, int&h) = 0;
662 };
663
getDataProvider()664 inline EditDataProvider* ObjectMOBuffer::getDataProvider () {
665 return dataProvider;
666 }
667
getObjectMode()668 inline ObjectMode ObjectMOBuffer::getObjectMode () {
669 return objectMode;
670 }
671
getObjectMap()672 inline Cairo::RefPtr<Cairo::ImageSurface>& ObjectMOBuffer::getObjectMap () {
673 return objectMap;
674 }
675
setColor(double r,double g,double b)676 inline void RGBColor::setColor (double r, double g, double b) {
677 this->r = r;
678 this->g = g;
679 this->b = b;
680 }
681
setColor(char r,char g,char b)682 inline void RGBColor::setColor (char r, char g, char b) {
683 this->r = double (r) / 255.;
684 this->g = double (g) / 255.;
685 this->b = double (b) / 255.;
686 }
687
getR()688 inline double RGBColor::getR () {
689 return r;
690 }
691
getG()692 inline double RGBColor::getG () {
693 return g;
694 }
695
getB()696 inline double RGBColor::getB () {
697 return b;
698 }
699
setColor(double r,double g,double b,double a)700 inline void RGBAColor::setColor (double r, double g, double b, double a) {
701 RGBColor::setColor (r, g, b);
702 this->a = a;
703 }
704
setColor(char r,char g,char b,char a)705 inline void RGBAColor::setColor (char r, char g, char b, char a) {
706 RGBColor::setColor (r, g, b);
707 this->a = double (a) / 255.;
708 }
709
getA()710 inline double RGBAColor::getA () {
711 return a;
712 }
713
setInnerLineColor(double r,double g,double b)714 inline void Geometry::setInnerLineColor (double r, double g, double b) {
715 innerLineColor.setColor (r, g, b);
716 flags &= ~F_AUTO_COLOR;
717 }
718
setInnerLineColor(char r,char g,char b)719 inline void Geometry::setInnerLineColor (char r, char g, char b) {
720 innerLineColor.setColor (r, g, b);
721 flags &= ~F_AUTO_COLOR;
722 }
723
setOuterLineColor(double r,double g,double b)724 inline void Geometry::setOuterLineColor (double r, double g, double b) {
725 outerLineColor.setColor (r, g, b);
726 flags &= ~F_AUTO_COLOR;
727 }
728
getOuterLineWidth()729 inline double Geometry::getOuterLineWidth () {
730 return double (innerLineWidth) + 2.;
731 }
732
setOuterLineColor(char r,char g,char b)733 inline void Geometry::setOuterLineColor (char r, char g, char b) {
734 outerLineColor.setColor (r, g, b);
735 flags &= ~F_AUTO_COLOR;
736 }
737
getMouseOverLineWidth()738 inline double Geometry::getMouseOverLineWidth () {
739 return getOuterLineWidth () + 2.;
740 }
741
setAutoColor(bool aColor)742 inline void Geometry::setAutoColor (bool aColor) {
743 if (aColor) {
744 flags |= F_AUTO_COLOR;
745 } else {
746 flags &= ~F_AUTO_COLOR;
747 }
748 }
749
isVisible()750 inline bool Geometry::isVisible () {
751 return flags & F_VISIBLE;
752 }
753
setVisible(bool visible)754 inline void Geometry::setVisible (bool visible) {
755 if (visible) {
756 flags |= F_VISIBLE;
757 } else {
758 flags &= ~F_VISIBLE;
759 }
760 }
761
isFrame()762 inline bool Geometry::isFrame () {
763 return flags & F_FRAME;
764 }
765
setFrame(bool frame)766 inline void Geometry::setFrame (bool frame) {
767 if (frame) {
768 flags |= F_FRAME;
769 } else {
770 flags &= ~F_FRAME;
771 }
772 }
773
isHoverable()774 inline bool Geometry::isHoverable () {
775 return flags & F_HOVERABLE;
776 }
777
setHoverable(bool hoverable)778 inline void Geometry::setHoverable (bool hoverable) {
779 if (hoverable) {
780 flags |= F_HOVERABLE;
781 } else {
782 flags &= ~F_HOVERABLE;
783 }
784 }
785
setActive(bool active)786 inline void Geometry::setActive (bool active) {
787 if (active) {
788 flags |= (F_VISIBLE | F_HOVERABLE);
789 } else {
790 flags &= ~(F_VISIBLE | F_HOVERABLE);
791 }
792 }
793
isDashed()794 inline bool Geometry::isDashed () {
795 return flags & F_DASHED;
796 }
797
setDashed(bool dashed)798 inline void Geometry::setDashed (bool dashed) {
799 if (dashed) {
800 flags |= F_DASHED;
801 } else {
802 flags &= ~F_DASHED;
803 }
804 }
805
getEditProvider()806 inline EditDataProvider* EditSubscriber::getEditProvider () const {
807 return provider;
808 }
809
getCursor(int objectID)810 inline CursorShape EditSubscriber::getCursor (int objectID) {
811 return CSHandOpen;
812 }
813
mouseOver(int modifierKey)814 inline bool EditSubscriber::mouseOver (int modifierKey) {
815 return false;
816 }
817
button1Pressed(int modifierKey)818 inline bool EditSubscriber::button1Pressed (int modifierKey) {
819 return false;
820 }
821
button1Released()822 inline bool EditSubscriber::button1Released () {
823 return false;
824 }
825
button2Pressed(int modifierKey)826 inline bool EditSubscriber::button2Pressed (int modifierKey) {
827 return false;
828 }
829
button2Released()830 inline bool EditSubscriber::button2Released () {
831 return false;
832 }
833
button3Pressed(int modifierKey)834 inline bool EditSubscriber::button3Pressed (int modifierKey) {
835 return false;
836 }
837
button3Released()838 inline bool EditSubscriber::button3Released () {
839 return false;
840 }
841
drag1(int modifierKey)842 inline bool EditSubscriber::drag1 (int modifierKey) {
843 return false;
844 }
845
drag2(int modifierKey)846 inline bool EditSubscriber::drag2 (int modifierKey) {
847 return false;
848 }
849
drag3(int modifierKey)850 inline bool EditSubscriber::drag3 (int modifierKey) {
851 return false;
852 }
853
pick1(bool picked)854 inline bool EditSubscriber::pick1 (bool picked) {
855 return false;
856 }
857
pick2(bool picked)858 inline bool EditSubscriber::pick2 (bool picked) {
859 return false;
860 }
861
pick3(bool picked)862 inline bool EditSubscriber::pick3 (bool picked) {
863 return false;
864 }
865
scroll(int bstate,GdkScrollDirection direction,double deltaX,double deltaY,bool & propagateEvent)866 inline bool EditSubscriber::scroll(int bstate, GdkScrollDirection direction, double deltaX, double deltaY, bool &propagateEvent)
867 {
868 propagateEvent = true;
869 return false;
870 }
871
getVisibleGeometry()872 inline const std::vector<Geometry*>& EditSubscriber::getVisibleGeometry () {
873 return visibleGeometry;
874 }
875
getMouseOverGeometry()876 inline const std::vector<Geometry*>& EditSubscriber::getMouseOverGeometry () {
877 return mouseOverGeometry;
878 }
879
getPipetteRectSize()880 inline int EditDataProvider::getPipetteRectSize () {
881 return 8; // TODO: make a GUI
882 }
883
Geometry()884 inline Geometry::Geometry () :
885 innerLineColor (char (255), char (255), char (255)), outerLineColor (
886 char (0), char (0), char (0)), flags (
887 F_VISIBLE | F_HOVERABLE | F_AUTO_COLOR), innerLineWidth (1.5f), datum (
888 IMAGE), state (NORMAL) {
889 }
890
RGBAColor()891 inline RGBAColor::RGBAColor () :
892 RGBColor (0., 0., 0.), a (0.) {
893 }
894
RGBColor()895 inline RGBColor::RGBColor () :
896 r (0.), g (0.), b (0.) {
897 }
898
RGBColor(double r,double g,double b)899 inline RGBColor::RGBColor (double r, double g, double b) :
900 r (r), g (g), b (b) {
901 }
902
RGBColor(char r,char g,char b)903 inline RGBColor::RGBColor (char r, char g, char b) :
904 r (double (r) / 255.), g (double (g) / 255.), b (double (b) / 255.) {
905 }
906
RGBAColor(double r,double g,double b,double a)907 inline RGBAColor::RGBAColor (double r, double g, double b, double a) :
908 RGBColor (r, g, b), a (a) {
909 }
910
RGBAColor(char r,char g,char b,char a)911 inline RGBAColor::RGBAColor (char r, char g, char b, char a) :
912 RGBColor (r, g, b), a (double (a) / 255.) {
913 }
914
915 #ifdef GUIVERSION
916
Circle()917 inline Circle::Circle () :
918 center (100, 100), radius (10), filled (false), radiusInImageSpace (
919 false) {
920 }
921
Rectangle()922 inline Rectangle::Rectangle () :
923 topLeft (0, 0), bottomRight (10, 10), filled (false) {
924 }
925
PolyLine()926 inline PolyLine::PolyLine () :
927 filled (false),
928 closed (true) {
929 }
930
Line()931 inline Line::Line () :
932 begin (10, 10), end (100, 100) {
933 }
934
Circle(rtengine::Coord & center,int radius,bool filled,bool radiusInImageSpace)935 inline Circle::Circle (rtengine::Coord& center, int radius, bool filled,
936 bool radiusInImageSpace) :
937 center (center), radius (radius), filled (filled), radiusInImageSpace (
938 radiusInImageSpace) {
939 }
940
Circle(int centerX,int centerY,int radius,bool filled,bool radiusInImageSpace)941 inline Circle::Circle (int centerX, int centerY, int radius, bool filled,
942 bool radiusInImageSpace) :
943 center (centerX, centerY), radius (radius), filled (filled), radiusInImageSpace (
944 radiusInImageSpace) {
945 }
946
Line(rtengine::Coord & begin,rtengine::Coord & end)947 inline Line::Line (rtengine::Coord& begin, rtengine::Coord& end) :
948 begin (begin), end (end) {
949 }
950
Line(int beginX,int beginY,int endX,int endY)951 inline Line::Line (int beginX, int beginY, int endX, int endY) :
952 begin (beginX, beginY), end (endX, endY) {
953 }
954
955 #endif
956