1 //===========================================
2 // Lumina-DE source code
3 // Copyright (c) 2014-2015, Ken Moore
4 // Available under the 3-clause BSD license
5 // See the LICENSE file for full details
6 //===========================================
7 #include "MainUI.h"
8 #include "ui_MainUI.h"
9
10 #include <LuminaX11.h>
11 #include <QMessageBox>
12 #include <QClipboard>
13
MainUI()14 MainUI::MainUI()
15 : QMainWindow(), ui(new Ui::MainUI),
16 mousegrabbed(false),
17 picSaved(false),
18 closeOnSave(false)
19 {
20 ui->setupUi(this); //load the designer file
21 XCB = new LXCB();
22 IMG = new ImageEditor(this);
23 ui->scrollArea->setWidget(IMG);
24 areaOverlay = 0;
25 ui->label_zoom_percent->setMinimumWidth( ui->label_zoom_percent->fontMetrics().horizontalAdvance("200%") );
26 setupIcons();
27 ui->spin_monitor->setMaximum(QGuiApplication::screens().count());
28 if(ui->spin_monitor->maximum()<2){
29 ui->spin_monitor->setEnabled(false);
30 ui->radio_monitor->setEnabled(false);
31 }
32 scaleTimer = new QTimer(this);
33 scaleTimer->setSingleShot(true);
34 scaleTimer->setInterval(200); //~1/5 second
35 tabbar = new QTabBar(this);
36 tabbar->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Preferred);
37 ui->tabLayout->insertWidget(0,tabbar, Qt::AlignLeft | Qt::AlignBottom);
38 tabbar->addTab(LXDG::findIcon("view-preview",""), tr("View"));
39 tabbar->addTab(LXDG::findIcon("preferences-other",""), tr("Settings"));
40 ui->stackedWidget->setCurrentWidget(ui->page_current);
41 //Add a spacer in the Toolbar
42 QWidget *spacer = new QWidget(this);
43 spacer->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Preferred);
44 ui->toolBar->insertWidget(ui->actionClose, spacer);
45 //Setup the connections
46 //connect(ui->tool_save, SIGNAL(clicked()), this, SLOT(saveScreenshot()) );
47 connect(ui->actionSave_As, SIGNAL(triggered()), this, SLOT(saveScreenshot()) );
48 connect(ui->tool_quicksave, SIGNAL(clicked()), this, SLOT(quicksave()) );
49 connect(ui->actionQuick_Save, SIGNAL(triggered()), this, SLOT(quicksave()) );
50 connect(ui->actionClose, SIGNAL(triggered()), this, SLOT(closeApplication()) );
51 //connect(ui->push_snap, SIGNAL(clicked()), this, SLOT(startScreenshot()) );
52 connect(ui->actionTake_Screenshot, SIGNAL(triggered()), this, SLOT(startScreenshot()) );
53 connect(ui->tool_crop, SIGNAL(clicked()), IMG, SLOT(cropImage()) );
54 connect(ui->tool_copy_to_clipboard, SIGNAL(clicked()), this, SLOT(copyToClipboard()) );
55 connect(IMG, SIGNAL(selectionChanged(bool)), this, SLOT(imgselchanged(bool)) );
56 connect(IMG, SIGNAL(scaleFactorChanged(int)), this, SLOT(imgScalingChanged(int)) );
57 connect(ui->slider_zoom, SIGNAL(valueChanged(int)), this, SLOT(sliderChanged()) );
58 connect(scaleTimer, SIGNAL(timeout()), this, SLOT(imgScalingChanged()) );
59 connect(tabbar, SIGNAL(currentChanged(int)), this, SLOT(tabChanged(int)) );
60 connect(ui->check_show_popups, SIGNAL(toggled(bool)), this, SLOT(showPopupsChanged(bool)) );
61 settings = LUtils::openSettings("lumina-desktop", "lumina-screenshot",this);
62 ppath = settings->value("previous-path", QDir::homePath()).toString();
63 QString opt = settings->value("screenshot-target", "window").toString();
64 if( opt == "window") {ui->radio_window->setChecked(true); }
65 else if(opt=="area"){ ui->radio_area->setChecked(true); }
66 else{ ui->radio_all->setChecked(true); }
67 ui->spin_delay->setValue(settings->value("screenshot-delay", 0).toInt());
68 ui->check_show_popups->setChecked( settings->value("showPopupWarnings",true).toBool() );
69
70 ui->tool_resize->setVisible(false); //not implemented yet
71 this->show();
72 IMG->setDefaultSize(ui->scrollArea->maximumViewportSize());
73 IMG->LoadImage( QApplication::screens().at(0)->grabWindow(QApplication::desktop()->winId()).toImage() ); //initial screenshot
74 lastScreenShot = QDateTime::currentDateTime();
75
76 // Shortcuts
77 quitShortcut = new QShortcut(Qt::CTRL + Qt::Key_Q, this);
78 connect(quitShortcut, SIGNAL(activated()), this, SLOT(quitShortcut_activated()) );
79 openShortcut = new QShortcut(Qt::CTRL + Qt::Key_O, this);
80 connect(openShortcut, SIGNAL(activated()), this, SLOT(quicksave()) );
81
82 //ui->label_screenshot->setPixmap( cpic.scaled(ui->label_screenshot->size(), Qt::KeepAspectRatio, Qt::SmoothTransformation) );
83 }
84
~MainUI()85 MainUI::~MainUI(){
86 if(areaOverlay!=0){ areaOverlay->deleteLater(); }
87 }
88
setupIcons()89 void MainUI::setupIcons(){
90 //Setup the icons
91 ui->tool_quicksave->setIcon( LXDG::findIcon("document-edit","") );
92 ui->actionSave_As->setIcon( LXDG::findIcon("document-save-as","") );
93 ui->actionQuick_Save->setIcon( LXDG::findIcon("document-save","") );
94 ui->actionClose->setIcon( LXDG::findIcon("application-exit","") );
95 ui->tool_copy_to_clipboard->setIcon( LXDG::findIcon("insert-image","") );
96 ui->actionTake_Screenshot->setIcon( LXDG::findIcon("camera-web","") );
97 ui->tool_crop->setIcon( LXDG::findIcon("transform-crop","") );
98 ui->tool_resize->setIcon( LXDG::findIcon("transform-scale","") );
99 this->setWindowIcon( LXDG::findIcon("camera-web","") );
100 }
101
showSaveError(QString path)102 void MainUI::showSaveError(QString path){
103 QMessageBox::warning(this, tr("Could not save screenshot"), tr("The screenshot could not be saved. Please check directory permissions or pick a different directory")+"\n\n"+path);
104 }
105
pointsToRect(QPoint pt1,QPoint pt2)106 QRect MainUI::pointsToRect(QPoint pt1, QPoint pt2){
107 QRect rec;
108 if(pt1.x() < pt2.x()){ rec.setLeft(pt1.x()); rec.setRight(pt2.x()); }
109 else{ rec.setLeft(pt2.x()); rec.setRight(pt1.x()); }
110 if(pt1.y() < pt2.y()){ rec.setTop(pt1.y()); rec.setBottom(pt2.y()); }
111 else{ rec.setTop(pt2.y()); rec.setBottom(pt1.y()); }
112 return rec;
113 }
114
showSBMessage(QString msg,int secs)115 void MainUI::showSBMessage(QString msg, int secs){
116 //Show statusbar message (for designated time)
117 ui->statusBar->showMessage("----> "+msg, secs*1000);
118 }
119
120 //==============
121 // PRIVATE SLOTS
122 //==============
saveScreenshot()123 void MainUI::saveScreenshot(){
124 if(mousegrabbed){ return; }
125 QString filepath = QFileDialog::getSaveFileName(this, tr("Save Screenshot"), ppath+"/"+QString( "Screenshot-%1.png" ).arg( lastScreenShot.toString("yyyy-MM-dd-hh-mm-ss")), tr("PNG Files (*.png);;AllFiles (*)") );
126 if(filepath.isEmpty()){
127 closeOnSave = false;
128 return;
129 }
130 if(!filepath.endsWith(".png")){ filepath.append(".png"); }
131 if( !IMG->image().save(filepath, "png") ){
132 closeOnSave = false;
133 showSaveError(filepath);
134 }else{
135 picSaved = true;
136 ppath = filepath.section("/",0,-2); //just the directory
137 settings->setValue("previous-path", ppath);
138 if (closeOnSave) {
139 // We came here from close, now we need to close *after* handling
140 // the current screen event.
141 QTimer::singleShot(0, this, SLOT(close()));
142 }
143 }
144 }
145
quicksave()146 void MainUI::quicksave(){
147 if(mousegrabbed){ return; }
148 QString savedir = QDir::homePath()+"/";
149 if(QFile::exists(savedir + "Pictures/")){ savedir.append("Pictures/"); }
150 else if(QFile::exists(savedir + "Images/")){ savedir.append("Images/"); }
151
152 QString path = savedir + QString( "Screenshot-%1.png" ).arg( lastScreenShot.toString("yyyy-MM-dd-hh-mm-ss") );
153 if(IMG->image().save(path, "png") ){
154 picSaved = true;
155 QProcess::startDetached("lumina-open -select \""+path+"\"");
156 }else{
157 showSaveError(path);
158 }
159
160 }
copyToClipboard()161 void MainUI::copyToClipboard(){
162 //qDebug() << "Copy Image to clipboard";
163 QClipboard *clipboard = QApplication::clipboard();
164 clipboard->setImage(IMG->image());
165 showSBMessage(tr("Image copied to clipboard"), 10);
166 //qDebug() << " - Success:" << !clipboard->image().isNull();
167 }
168
startScreenshot()169 void MainUI::startScreenshot(){
170 if(mousegrabbed){ return; }
171 lastgeom = this->geometry();
172 if( !getWindow() ){ return; }
173 this->hide();
174 QTimer::singleShot(50+ui->spin_delay->value()*1000, this, SLOT(getPixmap()));
175 }
176
imgselchanged(bool hassel)177 void MainUI::imgselchanged(bool hassel){
178 ui->tool_crop->setEnabled(hassel);
179 ui->tool_resize->setEnabled(hassel);
180 }
181
imgScalingChanged(int percent)182 void MainUI::imgScalingChanged(int percent){
183 //qDebug() << "Scale Changed:" << percent;
184 if(percent<0){
185 //Changed by user interaction
186 IMG->setScaling(ui->slider_zoom->value());
187 }else{
188 ui->slider_zoom->setValue(percent);
189 }
190 ui->label_zoom_percent->setText( QString::number(ui->slider_zoom->value())+"%");
191 }
192
sliderChanged()193 void MainUI::sliderChanged(){
194 ui->label_zoom_percent->setText( QString::number(ui->slider_zoom->value())+"%");
195 scaleTimer->start();
196 }
197
tabChanged(int tab)198 void MainUI::tabChanged(int tab){
199 if(tab==0){ ui->stackedWidget->setCurrentWidget(ui->page_current); }
200 else{ ui->stackedWidget->setCurrentWidget(ui->page_settings); }
201 ui->frame_modify->setVisible(tab==0);
202 }
203
showPopupsChanged(bool show)204 void MainUI::showPopupsChanged(bool show){
205 settings->setValue("showPopupWarnings", show);
206 }
207
getWindow()208 bool MainUI::getWindow(){
209 //Use this function to set cwin
210 cwin = 0;
211 snapArea = QRect(); //clear this too
212 //Save all the current settings for later
213 settings->setValue("screenshot-delay", ui->spin_delay->value());
214 if(ui->radio_window->isChecked()){
215 settings->setValue("screenshot-target", "window");
216 this->grabMouse( QCursor(Qt::CrossCursor) );
217 mousegrabbed = true;
218 this->centralWidget()->setEnabled(false);
219 this->setWindowOpacity(0);
220 return false; //wait for the next click to continue
221 }else if(ui->radio_area->isChecked()){
222 settings->setValue("screenshot-target", "area");
223 this->grabMouse( QCursor(Qt::CrossCursor) );
224 mousegrabbed = true;
225 this->centralWidget()->setEnabled(false);
226 this->setWindowOpacity(0);
227 return false; //wait for the next click to continue
228 }else if(ui->radio_monitor->isChecked()){
229 //will auto-grab the proper monitor later
230 }else{
231 settings->setValue("screenshot-target", "desktop");
232 }
233 return true;
234 }
235
getPixmap()236 void MainUI::getPixmap(){
237 QScreen *scrn = QApplication::screens().at(0);
238 QPixmap cpic;
239 //qDebug() << "Grab Pixmap:" << cwin;
240 if( (cwin==0 && ui->radio_window->isChecked() ) || ui->radio_all->isChecked() ){
241 //Grab the whole screen
242 cpic = scrn->grabWindow(QApplication::desktop()->winId());
243 }else if(cwin==0 && ui->radio_monitor->isChecked()){
244 QRect geom = QGuiApplication::screens().at(ui->spin_monitor->value()-1)->availableGeometry();
245 cpic = scrn->grabWindow(QApplication::desktop()->winId(), geom.x(), geom.y(), geom.width(), geom.height() );
246 }else if(cwin==0 && ui->radio_area->isChecked()){
247 //Grab the section of the screen which was selected
248 //qDebug() << "Screen Area:" << snapArea;
249 cpic = scrn->grabWindow(QApplication::desktop()->winId(), snapArea.x(), snapArea.y(), snapArea.width(), snapArea.height() );
250 }else{
251 //Grab just the designated window
252 if(ui->check_frame->isChecked()){
253 QRect geom = XCB->WindowGeometry(cwin, true); //include the frame
254 cpic = scrn->grabWindow(QApplication::desktop()->winId(), geom.x(), geom.y(), geom.width(), geom.height() );
255 }else{
256 cpic = scrn->grabWindow(cwin);
257 }
258 }
259 this->showNormal();
260 this->setGeometry(lastgeom);
261 lastScreenShot = QDateTime::currentDateTime();
262 //Now display the pixmap on the label as well
263 picSaved = false;
264 IMG->LoadImage( cpic.toImage() );
265 tabbar->setCurrentIndex(0);
266 }
mousePressEvent(QMouseEvent * ev)267 void MainUI::mousePressEvent(QMouseEvent *ev){
268 if(mousegrabbed && ui->radio_area->isChecked()){
269 pt_click = ev->globalPos();
270 if(areaOverlay == 0){
271 areaOverlay = new QWidget(0, Qt::Window | Qt::BypassWindowManagerHint | Qt::WindowStaysOnTopHint);
272 areaOverlay->setWindowOpacity(0.5);
273 areaOverlay->setStyleSheet("background-color: rgba(150,150,150,120)");
274 }
275 }
276 QMainWindow::mouseMoveEvent(ev);
277 }
278
mouseMoveEvent(QMouseEvent * ev)279 void MainUI::mouseMoveEvent(QMouseEvent *ev){
280 if(mousegrabbed && ui->radio_area->isChecked()){
281 //Not used yet - do something to paint the area so the user can see which area is selected
282 QRect area = pointsToRect(pt_click, ev->globalPos());
283 areaOverlay->setGeometry(area);
284 areaOverlay->show();
285 }else{
286 QMainWindow::mouseMoveEvent(ev);
287 }
288 }
289
mouseReleaseEvent(QMouseEvent * ev)290 void MainUI::mouseReleaseEvent(QMouseEvent *ev){
291 if(mousegrabbed){
292 mousegrabbed = false;
293 this->centralWidget()->setEnabled(true);
294 this->releaseMouse();
295 this->setWindowOpacity(1);
296 if(ui->radio_area->isChecked()){
297 //Need to determind the rectange which covers the area selected
298 areaOverlay->hide();
299 snapArea = pointsToRect(pt_click, ev->globalPos());
300 }else{
301 //In the middle of selecting a window to take a screenshot
302 // Get the window underneath the mouse click and take the screenshot
303 QList<WId> wins = XCB->WindowList();
304 QList<WId> stack = XCB->WM_Get_Client_List(true);
305 cwin = 0;
306 //qDebug() << "Try to select window:" << ev->globalPos() << ev->pos() << QCursor::pos();
307 for(int i=stack.length()-1; i>=0 && cwin==0; i--){ //work top->bottom in the stacking order
308 if(!wins.contains(stack[i])){ continue; }
309 if( XCB->WindowGeometry(stack[i], true).contains(ev->globalPos()) && XCB->WindowState(stack[i])!=LXCB::INVISIBLE ){
310 //qDebug() << "Found Window:" << i << XCB->WindowClass(stack[i]) << XCB->WindowGeometry(stack[i], true);
311 cwin = stack[i];
312 }
313 }
314 //qDebug() << " - Got window:" << cwin;
315 if(cwin==this->winId()){ return; } //cancelled
316 }
317 this->hide();
318 QTimer::singleShot(300+ui->spin_delay->value()*1000, this, SLOT(getPixmap()));
319 }else{
320 QMainWindow::mouseReleaseEvent(ev); //normal processing
321 }
322 }
323
resizeEvent(QResizeEvent *)324 void MainUI::resizeEvent(QResizeEvent*){
325 IMG->setDefaultSize( ui->scrollArea->maximumViewportSize() );
326 }
327
closeEvent(QCloseEvent * ev)328 void MainUI::closeEvent(QCloseEvent *ev){
329 //qDebug() << "Close Event:" << ui->check_show_popups->isChecked() << picSaved;
330 if(ui->check_show_popups->isChecked() && !picSaved){
331 //Ask what to do about the unsaved changed
332 QMessageBox dialog( QMessageBox::Warning, tr("Unsaved Screenshot"),
333 tr("The current screenshot has not been saved yet. Do you want to save or discard your changes?"),
334 QMessageBox::Discard | QMessageBox::Save | QMessageBox::Cancel, this);
335 dialog.setDefaultButton(QMessageBox::Cancel);
336 dialog.setButtonText(QMessageBox::Save, tr("Save"));
337 dialog.setButtonText(QMessageBox::Discard, tr("Discard"));
338 dialog.setButtonText(QMessageBox::Cancel, tr("Cancel"));
339 switch (dialog.exec()) {
340 case QMessageBox::Discard:
341 // Just close, we don't care about the file.
342 break;
343 case QMessageBox::Save:
344 closeOnSave = true;
345 saveScreenshot();
346 // fall through
347 case QMessageBox::Cancel:
348 ev->ignore();
349 return;
350 }
351 }
352 QMainWindow::closeEvent(ev);
353 }
354
quitShortcut_activated()355 void MainUI::quitShortcut_activated(){
356 QApplication::quit();
357 }
358