Accumulate/coalesce GDK_SCROLL_SMOOTH events until we equal or exceed +/-1.0 This avoids having one zoom adjustment for every single event which makes touchpad zooming unusable due to frequent small deltas This makes trackpad zooming usable while having no effect on mice that emit GDK_SMOOTH_SCROLL with values of +/-1.0 instead of GDK_SCROLL_UP and GDK_SCROLL_DOWN If any mice exist that have scroll wheel detents but emit smaller values per detent, this may have the negative effect of requiring multiple detents per zoom level. It remains to be seen whether any mice behave like this. The discrete step implementation of zoomSteps requires us to coalesce events instead of smoothly zooming in and out.
244 lines
8.7 KiB
C++
244 lines
8.7 KiB
C++
/*
|
|
* This file is part of RawTherapee.
|
|
*
|
|
* Copyright (c) 2004-2010 Gabor Horvath <hgabor@rawtherapee.com>
|
|
*
|
|
* RawTherapee is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* RawTherapee is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with RawTherapee. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
#ifndef _CROPWINDOW_
|
|
#define _CROPWINDOW_
|
|
|
|
#include "../rtengine/rtengine.h"
|
|
#include <gtkmm.h>
|
|
#include "lwbutton.h"
|
|
#include "lwbuttonset.h"
|
|
#include "editenums.h"
|
|
#include "crophandler.h"
|
|
#include <list>
|
|
#include "cropguilistener.h"
|
|
#include "pointermotionlistener.h"
|
|
#include "cursormanager.h"
|
|
#include "editbuffer.h"
|
|
#include "editcoordsys.h"
|
|
#include "../rtengine/noncopyable.h"
|
|
|
|
class CropWindow;
|
|
|
|
class CropWindowListener
|
|
{
|
|
public:
|
|
virtual ~CropWindowListener() = default;
|
|
virtual void cropPositionChanged(CropWindow*) = 0;
|
|
virtual void cropWindowSizeChanged(CropWindow*) = 0;
|
|
virtual void cropZoomChanged(CropWindow*) = 0;
|
|
virtual void initialImageArrived() = 0;
|
|
};
|
|
|
|
class ImageArea;
|
|
class CropWindow : public LWButtonListener, public CropDisplayHandler, public EditCoordSystem, public ObjectMOBuffer, public rtengine::NonCopyable
|
|
{
|
|
static bool initialized;
|
|
|
|
static Glib::ustring zoomOuttt;
|
|
static Glib::ustring zoomIntt;
|
|
static Glib::ustring zoom100tt;
|
|
static Glib::ustring closett;
|
|
|
|
// state management
|
|
ImgEditState state; // current state of user (see enum State)
|
|
int press_x, press_y; // position of the cursor in the GUI space on button press
|
|
int action_x, action_y; // parameter that will evolve during a pan or drag action
|
|
int pickedObject;
|
|
int pickModifierKey;
|
|
double rot_deg;
|
|
bool onResizeArea;
|
|
bool deleted;
|
|
bool fitZoomEnabled;
|
|
bool fitZoom;
|
|
//bool isLowUpdatePriority;
|
|
CursorShape cursor_type;
|
|
|
|
// color pickers
|
|
std::vector<LockableColorPicker*> colorPickers;
|
|
LockableColorPicker* hoveredPicker;
|
|
|
|
// decoration
|
|
LWButton *bZoomIn, *bZoomOut, *bZoom100, /**bZoomFit,*/ *bClose;
|
|
LWButtonSet buttonSet;
|
|
Glib::ustring cropLabel;
|
|
int backColor;
|
|
bool decorated;
|
|
bool isFlawnOver;
|
|
|
|
// crop frame description
|
|
int titleHeight, sideBorderWidth, lowerBorderWidth, upperBorderWidth, sepWidth, minWidth;
|
|
// size & position of the crop relative to the top left corner
|
|
// of the main preview area
|
|
int xpos, ypos, width, height;
|
|
// size & pos of the drawable area relative to the top left corner of the crop
|
|
int imgAreaX, imgAreaY, imgAreaW, imgAreaH;
|
|
// size & pos of the piece of preview image relative to the top left corner of the crop
|
|
int imgX, imgY, imgW, imgH;
|
|
|
|
// image handling
|
|
|
|
ImageArea* iarea;
|
|
int cropZoom; // *1000
|
|
unsigned int zoomVersion, exposeVersion;
|
|
|
|
// crop gui listener
|
|
CropGUIListener* cropgl;
|
|
PointerMotionListener* pmlistener;
|
|
PointerMotionListener* pmhlistener;
|
|
std::list<CropWindowListener*> listeners;
|
|
double scrollAccum;
|
|
|
|
CropWindow* observedCropWin; // Pointer to the currently active detail CropWindow
|
|
|
|
float crop_custom_ratio;
|
|
|
|
bool onArea (CursorArea a, int x, int y);
|
|
void updateCursor (int x, int y);
|
|
void drawDecoration (Cairo::RefPtr<Cairo::Context> cr);
|
|
void drawStraightenGuide (Cairo::RefPtr<Cairo::Context> cr);
|
|
void drawScaledSpotRectangle (Cairo::RefPtr<Cairo::Context> cr, int rectSize);
|
|
void drawUnscaledSpotRectangle (Cairo::RefPtr<Cairo::Context> cr, int rectSize);
|
|
void drawObservedFrame (Cairo::RefPtr<Cairo::Context> cr, int rw = 0, int rh = 0);
|
|
void changeZoom (int zoom, bool notify = true, int centerx = -1, int centery = -1, bool needsRedraw = true);
|
|
void updateHoveredPicker (rtengine::Coord *imgPos = nullptr);
|
|
void cycleRGB ();
|
|
void cycleHSV ();
|
|
|
|
LockableColorPicker::Validity checkValidity (LockableColorPicker* picker, const rtengine::Coord &pos);
|
|
|
|
// Used by the mainCropWindow only
|
|
void getObservedFrameArea (int& x, int& y, int& w, int& h, int rw = 0, int rh = 0);
|
|
|
|
struct ZoomStep {
|
|
Glib::ustring label;
|
|
double zoom;
|
|
int czoom;
|
|
bool is_major;
|
|
|
|
explicit ZoomStep(const Glib::ustring &l="", double z=0.0,
|
|
int cz=0, bool m=false):
|
|
label(l), zoom(z), czoom(cz), is_major(m) {}
|
|
};
|
|
std::vector<ZoomStep> zoomSteps;
|
|
size_t zoom11index;
|
|
|
|
void initZoomSteps();
|
|
|
|
public:
|
|
CropHandler cropHandler;
|
|
CropWindow (ImageArea* parent, bool isLowUpdatePriority_, bool isDetailWindow);
|
|
~CropWindow () override;
|
|
|
|
void setDecorated (bool decorated)
|
|
{
|
|
this->decorated = decorated;
|
|
}
|
|
void setFitZoomEnabled (bool fze)
|
|
{
|
|
fitZoomEnabled = fze;
|
|
}
|
|
void setObservedCropWin (CropWindow* cw)
|
|
{
|
|
observedCropWin = cw;
|
|
}
|
|
void deleteColorPickers ();
|
|
|
|
void screenCoordToCropBuffer (int phyx, int phyy, int& cropx, int& cropy) override;
|
|
void screenCoordToImage (int phyx, int phyy, int& imgx, int& imgy) override;
|
|
void screenCoordToCropCanvas (int phyx, int phyy, int& prevx, int& prevy);
|
|
void imageCoordToCropCanvas (int imgx, int imgy, int& phyx, int& phyy) override;
|
|
void imageCoordToScreen (int imgx, int imgy, int& phyx, int& phyy) override;
|
|
void imageCoordToCropBuffer (int imgx, int imgy, int& phyx, int& phyy) override;
|
|
void imageCoordToCropImage (int imgx, int imgy, int& phyx, int& phyy) override;
|
|
int scaleValueToImage (int value) override;
|
|
float scaleValueToImage (float value) override;
|
|
double scaleValueToImage (double value) override;
|
|
int scaleValueToCanvas (int value) override;
|
|
float scaleValueToCanvas (float value) override;
|
|
double scaleValueToCanvas (double value) override;
|
|
double getZoomFitVal ();
|
|
void setPosition (int x, int y);
|
|
void getPosition (int& x, int& y);
|
|
void setSize (int w, int h, bool norefresh = false);
|
|
void getSize (int& w, int& h);
|
|
void enable ();
|
|
|
|
void leaveNotify (GdkEventCrossing* event);
|
|
void flawnOver (bool isFlawnOver);
|
|
|
|
// zoomlistener interface
|
|
void zoomIn (bool toCursor = false, int cursorX = -1, int cursorY = -1);
|
|
void zoomOut (bool toCursor = false, int cursorX = -1, int cursorY = -1);
|
|
void zoom11 (bool notify = true);
|
|
void zoomFit ();
|
|
void zoomFitCrop ();
|
|
double getZoom ();
|
|
bool isMinZoom ();
|
|
bool isMaxZoom ();
|
|
void setZoom (double zoom);
|
|
|
|
bool isInside (int x, int y);
|
|
|
|
|
|
void scroll (int state, GdkScrollDirection direction, int x, int y, double deltaX=0.0, double deltaY=0.0);
|
|
void buttonPress (int button, int num, int state, int x, int y);
|
|
void buttonRelease (int button, int num, int state, int x, int y);
|
|
void pointerMoved (int bstate, int x, int y);
|
|
|
|
void expose (Cairo::RefPtr<Cairo::Context> cr);
|
|
|
|
void setEditSubscriber (EditSubscriber* newSubscriber);
|
|
|
|
// interface lwbuttonlistener
|
|
void buttonPressed (LWButton* button, int actionCode, void* actionData) override;
|
|
void redrawNeeded (LWButton* button) override;
|
|
|
|
// crop handling
|
|
void getCropRectangle (int& x, int& y, int& w, int& h);
|
|
void getCropPosition (int& x, int& y);
|
|
void setCropPosition (int x, int y, bool update = true);
|
|
void centerCrop (bool update = true);
|
|
void getCropSize (int& w, int& h);
|
|
void getCropAnchorPosition (int& w, int& h);
|
|
void setCropAnchorPosition (int& w, int& h);
|
|
|
|
// listeners
|
|
void setCropGUIListener (CropGUIListener* cgl);
|
|
void setPointerMotionListener (PointerMotionListener* pml);
|
|
PointerMotionListener* getPointerMotionListener ();
|
|
void setPointerMotionHListener (PointerMotionListener* pml);
|
|
|
|
// crop window listeners
|
|
void addCropWindowListener (CropWindowListener* l);
|
|
void delCropWindowListener (CropWindowListener* l);
|
|
|
|
// crophandlerlistener interface
|
|
void cropImageUpdated () override;
|
|
void cropWindowChanged () override;
|
|
void initialImageArrived () override;
|
|
void setDisplayPosition (int x, int y) override;
|
|
|
|
void remoteMove (int deltaX, int deltaY);
|
|
void remoteMoveReady ();
|
|
|
|
ImageArea* getImageArea();
|
|
};
|
|
|
|
#endif
|