-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathmainwindow.cpp
More file actions
executable file
·365 lines (319 loc) · 12.3 KB
/
mainwindow.cpp
File metadata and controls
executable file
·365 lines (319 loc) · 12.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
// Instanciate a scene object that we can draw to and then set up the ui
//scene = new QGraphicsScene(this);
graphics_view = new ImageView;
filter = new Filters;
x = new QMutex;
ui->setupUi(this);
// Set window w/h to desktop size
setResolution(this);
dragging = false;
cropping = false;
// we have no threads open by
workerOpen = false;
settingsOpen = false;
ui->centralWidget->layout()->addWidget( graphics_view );
scene = graphics_view->getScene();
setMouseTracking(true);
// Set up link between mainwindow.cpp and imageview.cpp so imageview.cpp has access to the image data
connect(this, SIGNAL(sendCroppingValue(bool)), graphics_view, SLOT(setCropping(bool)));
connect(this, SIGNAL(sendImageDataForCrop(QImage)), graphics_view, SLOT(setCropImage(QImage)));
connect(graphics_view, SIGNAL(croppedImage(QImage)), this, SLOT(renderImageToCanvas(QImage)));
// Disable the edit buttons as nothing is availabe
ui->cmdRGB_HSL->setEnabled(false);
ui->cmdBlack_White->setEnabled(false);
// Create the image stack
image_stack = new QList<QImage>;
}
MainWindow::~MainWindow()
{
delete ui;
if(this->workerOpen)
{
delete worker;
delete thread;
}
}
/*
* -----------------------------------------------------------------------------------------
* EVENT: SET RESOLUTION
* -----------------------------------------------------------------------------------------
* Uses the QDesktop widget to get the current desktops width and height, the main window
* is then set to fill the parent.
* -----------------------------------------------------------------------------------------
*/
void MainWindow::setResolution(MainWindow *app)
{
QRect monitor = QApplication::desktop()->screenGeometry();
app->setGeometry(0,0, monitor.width(), monitor.height());
}
/*
* -----------------------------------------------------------------------------------------
* EVENT: OPEN
* -----------------------------------------------------------------------------------------
* Creates an Open Dialog for the user to select the file they wish to open
* Triggered when using the Open option under "File > Open"
* -----------------------------------------------------------------------------------------
*/
void MainWindow::on_cmdOpen_triggered()
{
// Get the path of the selected image and call the openImage() function, the return value
// will set the global imageSet toggle (see mainwindow.h for explanation)
QString fileName = QFileDialog::getOpenFileName(this, tr("Open File"), QDir::currentPath());
if(!fileName.isEmpty())
imageSet = openImage(fileName);
}
/*
* -----------------------------------------------------------------------------------------
* EVENT: BLACK AND WHITE FILTER
* -----------------------------------------------------------------------------------------
* Runs the serial black and white filter implementation, declarations of the methods
* can be found in the filters class.
* Upon the method completing, the modified flag is updated
* -----------------------------------------------------------------------------------------
*/
void MainWindow::on_cmdBlack_White_triggered()
{
renderImageToCanvas(
filter->serialFilterBlackWhite(image)
);
modified = true;
}
/*
* -----------------------------------------------------------------------------------------
* EVENT: IMAGE CHANNELS
* -----------------------------------------------------------------------------------------
* When the Image Channels button is selected from the Edit menu, it creates the image
* channels window, from here the user is presented with a panel where they can modify
* HSL and RGB values of the window
* -----------------------------------------------------------------------------------------
*/
void MainWindow::on_cmdRGB_HSL_triggered()
{
// We only ever want one window open
if(!settingsOpen)
{
settings = new SettingsForm();
settings->show();
settingsOpen = true;
// Set up the relevant connections
connect(settings, SIGNAL(returnValues(int, int, int, FORMAT::option)),
this, SLOT(updateImage(int, int, int, FORMAT::option)));
// Destructor method to reset settingsOpen
connect(settings, SIGNAL(window_destroyed(bool)), this, SLOT(unlock_settings(bool)));
}
}
void MainWindow::unlock_settings(bool unlock)
{
if (unlock == true)
settingsOpen = false;
}
// UPDATE IMAGE SLOT
void MainWindow::updateImage(int r, int g, int b, FORMAT::option channel)
{
if(channel == FORMAT::RGB)
{
emit requestUpdatedImage(image, r, g, b, "RGB");
} else if (channel == FORMAT::HSL) {
emit requestUpdatedImage(image, r, g, b, "HSL");
}
}
/*
* -----------------------------------------------------------------------------------------
* ACTION: OPEN IMAGE
* -----------------------------------------------------------------------------------------
* Accepts a given file name string and loads the paths contents into a QPixmap object, the
* current scene is cleared of any old objects and then paints the new image to the scene.
*
* @param fileName : The relative path to the image we wish to draw to our canvas
* @return true if a valid image was requested and drawn to the scene, else return false
* -----------------------------------------------------------------------------------------
*/
bool MainWindow::openImage(const QString &fileName)
{
QImage loadedImage;
// Has a valid image been specified, if not, return false
if (!loadedImage.load(fileName))
return false;
// Check if an image already exists on the canvas, if so
// destroy the old image, worker and thread
if(imageSet)
{
imageSet = false;
worker->deleteLater();
thread->deleteLater();
workerOpen = false;
}
// Draw the image to the screen and update the ui
renderImageToCanvas(loadedImage);
// Spawn thread and create slots
createImageWorker();
return true;
}
/*
* -----------------------------------------------------------------------------------------
* RENDER IMAGE TO CANVAS
* -----------------------------------------------------------------------------------------
* Uses the gloabl image object that is set by a variety of methods to draw the QPixmap image
* to the QGraphicsScene canvas
* -----------------------------------------------------------------------------------------
*/
void MainWindow::renderImageToCanvas(QImage img)
{
// Assign the global image object
image = img;
// Set cursor back (this is used as a slot from cropping)
QApplication::setOverrideCursor(Qt::ArrowCursor);
// Destroy the old image
scene->clear();
// Convert the new object to a pixmap and add it to the graphics view
QPixmap pixImg = QPixmap::fromImage(img);
scene->addPixmap(pixImg);
scene->setSceneRect(pixImg.rect());
graphics_view->setScene(scene);
// Add the new image to the stack - this is the only code which will write to the stack,
// as its our single control method of writing a new image via signals and slots.
push_to_stack(img);
// Enable manipulation controls
ui->cmdRGB_HSL->setEnabled(true);
ui->cmdBlack_White->setEnabled(true);
}
/*
* -----------------------------------------------------------------------------------------
* CREATE IMAGE WORKER
* -----------------------------------------------------------------------------------------
* Everytime a new image is set, this method creates a new thread and worker object for the
* image to be edited on. The new thread is started immediately for operations to take place.
*
* When a new image is loaded, this thread and worker are destroyed in the openImage() function,
* then a new thread is spawned.
* -----------------------------------------------------------------------------------------
*/
void MainWindow::createImageWorker()
{
// Build a new thread and worker object
worker = new Worker();
thread = new QThread();
// Connect slots and run the new thread
connect(this, SIGNAL(requestUpdatedImage(QImage, int, int, int, QString)),
worker, SLOT(updateImage(QImage,int, int, int, QString)));
connect(worker, SIGNAL(imageUpdated(QImage)), this, SLOT(renderImageToCanvas(QImage)));
worker->moveToThread(thread);
thread->start();
// We now have a thread running, ensure Qt knows about this so we can manually dispose
// of it if the application closes:
workerOpen = true;
}
/*
* -----------------------------------------------------------------------------------------
* EVENT: MOUSE WHEEL ZOOM
* -----------------------------------------------------------------------------------------
* Gets the direction that the user is scrolling (up or down) and then checks whether a
* CONTROL + MOUSESCROLL event is being processed. If this is happening, the zoom scene
* function is called.
* -----------------------------------------------------------------------------------------
*/
void MainWindow::wheelEvent(QWheelEvent *event)
{
// Check for CTRL + MOUSEWHEEL
if(event->modifiers() == Qt::ControlModifier)
{
// Determine whether the user scrolled forwards or backward
int direction = (event->delta() / 8) / 15;
zoomScene(direction);
}
}
/*
* -----------------------------------------------------------------------------------------
* SHORTCUT: KEYBOARD SHORTCUTS
* -----------------------------------------------------------------------------------------
* Binds common events to some keyboard shourtcuts
* -----------------------------------------------------------------------------------------
*/
void MainWindow::keyPressEvent(QKeyEvent *event)
{
// Undo
if(event->modifiers() == Qt::ControlModifier && (event->key() == Qt::Key_Z))
undo();
// Zoom in ctrl +
if(event->modifiers() == Qt::ControlModifier && (event->key() == Qt::Key_Equal))
zoomScene(1);
// Zoom out ctrl -
if((event->modifiers() == Qt::ControlModifier) && (event->key() == Qt::Key_Minus))
zoomScene(0);
if(event->key() == Qt::Key_Space)
graphics_view->setDragMode(graphics_view->ScrollHandDrag);
else
graphics_view->setDragMode(graphics_view->NoDrag);
}
// When undo is pressed get the older stack
void MainWindow::on_actionUndo_triggered()
{
undo();
}
void MainWindow::undo()
{
if(image_stack->size() > 0)
{
// Render the image on the top of the stack
renderImageToCanvas(pop_from_stack());
}
}
// Stack method
void MainWindow::push_to_stack(QImage img)
{
image_stack->push_front(img);
}
QImage MainWindow::pop_from_stack()
{
image_stack->pop_front();
QImage stack_top = image_stack->at(0);
return stack_top;
}
/*
* -----------------------------------------------------------------------------------------
* EVENT: ZOOM SCENE
* -----------------------------------------------------------------------------------------
* increase or decreases the scale of the graphics view by 25% dependent on the direction
* that the user wishes to go.
*
* uses a mutex to ensure the image does not scale too far in a particular direction when
* a user scrolls their mouse wheel - ensures transaction is completed before running another
* -----------------------------------------------------------------------------------------
*/
void MainWindow::zoomScene(int direction)
{
x->lock();
if(direction > 0)
graphics_view->scale(1.20, 1.20);
else
graphics_view->scale(0.80, 0.80);
x->unlock();
}
// Set the new cursor, look at the mouse events for the crop code
void MainWindow::on_btnCrop_clicked()
{
// Sets the new image data on the ImageView
emit(sendImageDataForCrop(image));
emit(sendCroppingValue(true));
QApplication::setOverrideCursor(Qt::CrossCursor);
}
// Set the cursor back to default mode, this will stop cropping from working
void MainWindow::on_btnPointer_clicked()
{
emit(sendCroppingValue(false));
QApplication::setOverrideCursor(Qt::ArrowCursor);
}
void MainWindow::on_btnZoomOut_clicked()
{
zoomScene(0);
}
void MainWindow::on_btnZoomIn_clicked()
{
zoomScene(1);
}