Add export format options: CSV, JSON, PPM
[gencolormap.git] / gui.cpp
1 /*
2  * Copyright (C) 2015, 2016 Computer Graphics Group, University of Siegen
3  * Written by Martin Lambers <martin.lambers@uni-siegen.de>
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a copy
6  * of this software and associated documentation files (the "Software"), to deal
7  * in the Software without restriction, including without limitation the rights
8  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9  * copies of the Software, and to permit persons to whom the Software is
10  * furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in
13  * all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
18  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21  * SOFTWARE.
22  */
23
24 #include "gui.hpp"
25
26 #include <QApplication>
27 #include <QGuiApplication>
28 #include <QGridLayout>
29 #include <QTabWidget>
30 #include <QLabel>
31 #include <QMenu>
32 #include <QMenuBar>
33 #include <QFileDialog>
34 #include <QClipboard>
35 #include <QTextStream>
36 #include <QMessageBox>
37
38 #include "colormapwidgets.hpp"
39 #include "testwidget.hpp"
40
41
42 GUI::GUI()
43 {
44     setWindowTitle("Generate Color Map");
45     setWindowIcon(QIcon(":cg-logo.png"));
46
47     _brewerseq_widget = new ColorMapBrewerSequentialWidget;
48     _brewerdiv_widget = new ColorMapBrewerDivergingWidget;
49     _brewerqual_widget = new ColorMapBrewerQualitativeWidget;
50     _plseq_lightness_widget = new ColorMapPLSequentialLightnessWidget;
51     _plseq_saturation_widget = new ColorMapPLSequentialSaturationWidget;
52     _plseq_rainbow_widget = new ColorMapPLSequentialRainbowWidget;
53     _plseq_blackbody_widget = new ColorMapPLSequentialBlackBodyWidget;
54     _pldiv_lightness_widget = new ColorMapPLDivergingLightnessWidget;
55     _pldiv_saturation_widget = new ColorMapPLDivergingSaturationWidget;
56     _plqual_hue_widget = new ColorMapPLQualitativeHueWidget;
57     _cubehelix_widget = new ColorMapCubeHelixWidget;
58     _moreland_widget = new ColorMapMorelandWidget;
59     _mcnames_widget = new ColorMapMcNamesWidget;
60     connect(_brewerseq_widget, SIGNAL(colorMapChanged()), this, SLOT(update()));
61     connect(_brewerdiv_widget, SIGNAL(colorMapChanged()), this, SLOT(update()));
62     connect(_brewerqual_widget, SIGNAL(colorMapChanged()), this, SLOT(update()));
63     connect(_plseq_lightness_widget, SIGNAL(colorMapChanged()), this, SLOT(update()));
64     connect(_plseq_saturation_widget, SIGNAL(colorMapChanged()), this, SLOT(update()));
65     connect(_plseq_rainbow_widget, SIGNAL(colorMapChanged()), this, SLOT(update()));
66     connect(_plseq_blackbody_widget, SIGNAL(colorMapChanged()), this, SLOT(update()));
67     connect(_pldiv_lightness_widget, SIGNAL(colorMapChanged()), this, SLOT(update()));
68     connect(_pldiv_saturation_widget, SIGNAL(colorMapChanged()), this, SLOT(update()));
69     connect(_plqual_hue_widget, SIGNAL(colorMapChanged()), this, SLOT(update()));
70     connect(_cubehelix_widget, SIGNAL(colorMapChanged()), this, SLOT(update()));
71     connect(_moreland_widget, SIGNAL(colorMapChanged()), this, SLOT(update()));
72     connect(_mcnames_widget, SIGNAL(colorMapChanged()), this, SLOT(update()));
73
74     QWidget *widget = new QWidget;
75     QGridLayout *layout = new QGridLayout;
76
77     _category_widget = new QTabWidget();
78     _category_seq_widget = new QTabWidget();
79     _category_seq_widget->addTab(_brewerseq_widget, "Brewer-like");
80     _category_seq_widget->addTab(_plseq_lightness_widget, "PL Lightness");
81     _category_seq_widget->addTab(_plseq_saturation_widget, "PL Saturation");
82     _category_seq_widget->addTab(_plseq_rainbow_widget, "PL Rainbow");
83     _category_seq_widget->addTab(_plseq_blackbody_widget, "PL Black Body");
84     _category_seq_widget->addTab(_cubehelix_widget, "CubeHelix");
85     //_category_seq_widget->addTab(_mcnames_widget, "McNames");
86     connect(_category_seq_widget, SIGNAL(currentChanged(int)), this, SLOT(update()));
87     _category_widget->addTab(_category_seq_widget, "Sequential");
88     _category_div_widget = new QTabWidget();
89     _category_div_widget->addTab(_brewerdiv_widget, "Brewer-like");
90     _category_div_widget->addTab(_pldiv_lightness_widget, "PL Lightness");
91     _category_div_widget->addTab(_pldiv_saturation_widget, "PL Saturation");
92     _category_div_widget->addTab(_moreland_widget, "Moreland");
93     connect(_category_div_widget, SIGNAL(currentChanged(int)), this, SLOT(update()));
94     _category_widget->addTab(_category_div_widget, "Diverging");
95     _category_qual_widget = new QTabWidget();
96     _category_qual_widget->addTab(_brewerqual_widget, "Brewer-like");
97     _category_qual_widget->addTab(_plqual_hue_widget, "PL Hue");
98     connect(_category_qual_widget, SIGNAL(currentChanged(int)), this, SLOT(update()));
99     _category_widget->addTab(_category_qual_widget, "Qualitative");
100     connect(_category_widget, SIGNAL(currentChanged(int)), this, SLOT(update()));
101     layout->addWidget(_category_widget, 0, 0);
102     _reference_label = new QLabel(_brewerseq_widget->reference());
103     _reference_label->setWordWrap(true);
104     _reference_label->setOpenExternalLinks(true);
105     layout->addWidget(_reference_label, 1, 0);
106     layout->addItem(new QSpacerItem(0, 0), 2, 0);
107     _clipped_label = new QLabel("");
108     layout->addWidget(_clipped_label, 3, 0);
109
110     _colormap_label = new QLabel();
111     _colormap_label->setScaledContents(true);
112     layout->addWidget(_colormap_label, 0, 1, 4, 1);
113
114     QLabel* test_label = new QLabel("Test pattern "
115             "<a href=\"http://peterkovesi.com/projects/colourmaps/colourmaptestimage.html\">"
116             "designed by P. Kovesi</a>:");
117     test_label->setWordWrap(true);
118     test_label->setOpenExternalLinks(true);
119     layout->addWidget(test_label, 4, 0, 1, 2);
120     _test_widget = new ColorMapTestWidget();
121     layout->addWidget(_test_widget, 5, 0, 1, 2);
122
123     layout->setColumnStretch(0, 1);
124     layout->setRowStretch(2, 1);
125     widget->setLayout(layout);
126     setCentralWidget(widget);
127
128     QMenu* file_menu = menuBar()->addMenu("&File");
129     QAction* file_export_png_act = new QAction("Export as &PNG...", this);
130     connect(file_export_png_act, SIGNAL(triggered()), this, SLOT(file_export_png()));
131     file_menu->addAction(file_export_png_act);
132     QAction* file_export_csv_act = new QAction("Export as &CSV...", this);
133     connect(file_export_csv_act, SIGNAL(triggered()), this, SLOT(file_export_csv()));
134     file_menu->addAction(file_export_csv_act);
135     file_menu->addSeparator();
136     QAction* quit_act = new QAction("&Quit...", this);
137     quit_act->setShortcut(QKeySequence::Quit);
138     connect(quit_act, SIGNAL(triggered()), this, SLOT(close()));
139     file_menu->addAction(quit_act);
140     QMenu* edit_menu = menuBar()->addMenu("&Edit");
141     QAction* edit_reset_act = new QAction("&Reset", this);
142     connect(edit_reset_act, SIGNAL(triggered()), this, SLOT(edit_reset()));
143     edit_menu->addAction(edit_reset_act);
144     QAction* edit_copy_as_img_act = new QAction("Copy as &image", this);
145     connect(edit_copy_as_img_act, SIGNAL(triggered()), this, SLOT(edit_copy_as_img()));
146     edit_menu->addAction(edit_copy_as_img_act);
147     QAction* edit_copy_as_txt_act = new QAction("Copy as &text", this);
148     connect(edit_copy_as_txt_act, SIGNAL(triggered()), this, SLOT(edit_copy_as_txt()));
149     edit_copy_as_txt_act->setShortcut(QKeySequence::Copy);
150     edit_menu->addAction(edit_copy_as_txt_act);
151     QMenu* help_menu = menuBar()->addMenu("&Help");
152     QAction* help_about_act = new QAction("&About", this);
153     connect(help_about_act, SIGNAL(triggered()), this, SLOT(help_about()));
154     help_menu->addAction(help_about_act);
155
156     show();
157     update();
158 }
159
160 GUI::~GUI()
161 {
162 }
163
164 ColorMapWidget* GUI::currentWidget()
165 {
166     QTabWidget* tw = reinterpret_cast<QTabWidget*>(_category_widget->currentWidget());
167     return reinterpret_cast<ColorMapWidget*>(tw->currentWidget());
168 }
169
170 void GUI::update()
171 {
172     _reference_label->setText(currentWidget()->reference());
173     int clipped;
174     QVector<QColor> colormap = currentWidget()->colorMap(&clipped);
175     _clipped_label->setText(QString("Colors clipped: %1").arg(clipped));
176     _colormap_label->setPixmap(QPixmap::fromImage(currentWidget()->colorMapImage(colormap, 32, _colormap_label->height())));
177     _test_widget->update(colormap);
178 }
179
180 void GUI::file_export_png()
181 {
182     QString name = QFileDialog::getSaveFileName();
183     if (!name.isEmpty()) {
184         QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
185         currentWidget()->colorMapImage(currentWidget()->colorMap(), 0, 1).save(name, "png");
186         QApplication::restoreOverrideCursor();
187     }
188 }
189
190 void GUI::file_export_csv()
191 {
192     QString name = QFileDialog::getSaveFileName();
193     if (!name.isEmpty()) {
194         QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
195         QFile file(name);
196         if (file.open(QIODevice::WriteOnly)) {
197             QVector<QColor> colormap = currentWidget()->colorMap();
198             QTextStream stream(&file);
199             for (int i = 0; i < colormap.size(); i++) {
200                 stream << colormap[i].red()   << ", "
201                        << colormap[i].green() << ", "
202                        << colormap[i].blue()  << endl;
203             }
204         }
205         QApplication::restoreOverrideCursor();
206     }
207 }
208
209 void GUI::edit_reset()
210 {
211     currentWidget()->reset();
212 }
213
214 void GUI::edit_copy_as_img()
215 {
216     QApplication::clipboard()->setImage(currentWidget()->colorMapImage(currentWidget()->colorMap(), 0, 1));
217 }
218
219 void GUI::edit_copy_as_txt()
220 {
221     QVector<QColor> colormap = currentWidget()->colorMap();
222     QString string;
223     QTextStream stream(&string);
224     for (int i = 0; i < colormap.size(); i++) {
225         stream << colormap[i].red()   << ", "
226                << colormap[i].green() << ", "
227                << colormap[i].blue()  << endl;
228     }
229     QApplication::clipboard()->setText(string);
230 }
231
232 void GUI::help_about()
233 {
234     QMessageBox::about(this, "About",
235                 "<p>gencolormap version 0.3</p>"
236                 "<p>Copyright (C) 2016<br>"
237                 "   <a href=\"http://www.cg.informatik.uni-siegen.de/\">"
238                 "   Computer Graphics Group, University of Siegen</a>.<br>"
239                 "   Written by <a href=\"http://www.cg.informatik.uni-siegen.de/lambers-martin\">Martin Lambers</a>.<br>"
240                 "   This is free software under the terms of the "
241                     "<a href=\"https://www.debian.org/legal/licenses/mit\">MIT/Expat License</a>. "
242                 "   There is NO WARRANTY, to the extent permitted by law."
243                 "</p>");
244 }
245
246 int main(int argc, char* argv[])
247 {
248     QApplication app(argc, argv);
249     GUI gui;
250     gui.show();
251     return app.exec();
252 }