Fix colormap label layout.
[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
40
41 GUI::GUI()
42 {
43     setWindowTitle("Generate Color Map");
44     setWindowIcon(QIcon(":cg-logo.png"));
45
46     _brewerseq_widget = new ColorMapBrewerSequentialWidget;
47     _brewerdiv_widget = new ColorMapBrewerDivergingWidget;
48     _brewerqual_widget = new ColorMapBrewerQualitativeWidget;
49     _plseq_lightness_widget = new ColorMapPLSequentialLightnessWidget;
50     _plseq_saturation_widget = new ColorMapPLSequentialSaturationWidget;
51     _plseq_rainbow_widget = new ColorMapPLSequentialRainbowWidget;
52     _plseq_blackbody_widget = new ColorMapPLSequentialBlackBodyWidget;
53     _pldiv_lightness_widget = new ColorMapPLDivergingLightnessWidget;
54     _pldiv_saturation_widget = new ColorMapPLDivergingSaturationWidget;
55     _plqual_hue_widget = new ColorMapPLQualitativeHueWidget;
56     _cubehelix_widget = new ColorMapCubeHelixWidget;
57     _moreland_widget = new ColorMapMorelandWidget;
58     _mcnames_widget = new ColorMapMcNamesWidget;
59     connect(_brewerseq_widget, SIGNAL(colorMapChanged()), this, SLOT(update()));
60     connect(_brewerdiv_widget, SIGNAL(colorMapChanged()), this, SLOT(update()));
61     connect(_brewerqual_widget, SIGNAL(colorMapChanged()), this, SLOT(update()));
62     connect(_plseq_lightness_widget, SIGNAL(colorMapChanged()), this, SLOT(update()));
63     connect(_plseq_saturation_widget, SIGNAL(colorMapChanged()), this, SLOT(update()));
64     connect(_plseq_rainbow_widget, SIGNAL(colorMapChanged()), this, SLOT(update()));
65     connect(_plseq_blackbody_widget, SIGNAL(colorMapChanged()), this, SLOT(update()));
66     connect(_pldiv_lightness_widget, SIGNAL(colorMapChanged()), this, SLOT(update()));
67     connect(_pldiv_saturation_widget, SIGNAL(colorMapChanged()), this, SLOT(update()));
68     connect(_plqual_hue_widget, SIGNAL(colorMapChanged()), this, SLOT(update()));
69     connect(_cubehelix_widget, SIGNAL(colorMapChanged()), this, SLOT(update()));
70     connect(_moreland_widget, SIGNAL(colorMapChanged()), this, SLOT(update()));
71     connect(_mcnames_widget, SIGNAL(colorMapChanged()), this, SLOT(update()));
72
73     QWidget *widget = new QWidget;
74     widget->setMinimumWidth(384 * qApp->devicePixelRatio());
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     _clipped_label = new QLabel("");
103     layout->addWidget(_clipped_label, 1, 0);
104     layout->addItem(new QSpacerItem(0, 0), 2, 0);
105     _reference_label = new QLabel(_brewerseq_widget->reference());
106     _reference_label->setWordWrap(true);
107     _reference_label->setOpenExternalLinks(true);
108     layout->addWidget(_reference_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     layout->setColumnStretch(0, 1);
115     layout->setRowStretch(1, 1);
116     widget->setLayout(layout);
117     setCentralWidget(widget);
118
119     QMenu* file_menu = menuBar()->addMenu("&File");
120     QAction* file_export_png_act = new QAction("Export as &PNG...", this);
121     connect(file_export_png_act, SIGNAL(triggered()), this, SLOT(file_export_png()));
122     file_menu->addAction(file_export_png_act);
123     QAction* file_export_csv_act = new QAction("Export as &CSV...", this);
124     connect(file_export_csv_act, SIGNAL(triggered()), this, SLOT(file_export_csv()));
125     file_menu->addAction(file_export_csv_act);
126     file_menu->addSeparator();
127     QAction* quit_act = new QAction("&Quit...", this);
128     quit_act->setShortcut(QKeySequence::Quit);
129     connect(quit_act, SIGNAL(triggered()), this, SLOT(close()));
130     file_menu->addAction(quit_act);
131     QMenu* edit_menu = menuBar()->addMenu("&Edit");
132     QAction* edit_reset_act = new QAction("&Reset", this);
133     connect(edit_reset_act, SIGNAL(triggered()), this, SLOT(edit_reset()));
134     edit_menu->addAction(edit_reset_act);
135     QAction* edit_copy_as_img_act = new QAction("Copy as &image", this);
136     connect(edit_copy_as_img_act, SIGNAL(triggered()), this, SLOT(edit_copy_as_img()));
137     edit_menu->addAction(edit_copy_as_img_act);
138     QAction* edit_copy_as_txt_act = new QAction("Copy as &text", this);
139     connect(edit_copy_as_txt_act, SIGNAL(triggered()), this, SLOT(edit_copy_as_txt()));
140     edit_copy_as_txt_act->setShortcut(QKeySequence::Copy);
141     edit_menu->addAction(edit_copy_as_txt_act);
142     QMenu* help_menu = menuBar()->addMenu("&Help");
143     QAction* help_about_act = new QAction("&About", this);
144     connect(help_about_act, SIGNAL(triggered()), this, SLOT(help_about()));
145     help_menu->addAction(help_about_act);
146
147     show();
148     update();
149 }
150
151 GUI::~GUI()
152 {
153 }
154
155 ColorMapWidget* GUI::currentWidget()
156 {
157     QTabWidget* tw = reinterpret_cast<QTabWidget*>(_category_widget->currentWidget());
158     return reinterpret_cast<ColorMapWidget*>(tw->currentWidget());
159 }
160
161 void GUI::update()
162 {
163     _reference_label->setText(currentWidget()->reference());
164     int clipped;
165     _colormap_label->setPixmap(QPixmap::fromImage(currentWidget()->colorMapImage(32, _colormap_label->height(), &clipped)));
166     _clipped_label->setText(QString("Colors clipped: %1").arg(clipped));
167 }
168
169 void GUI::file_export_png()
170 {
171     QString name = QFileDialog::getSaveFileName();
172     if (!name.isEmpty()) {
173         QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
174         currentWidget()->colorMapImage(0, 1).save(name, "png");
175         QApplication::restoreOverrideCursor();
176     }
177 }
178
179 void GUI::file_export_csv()
180 {
181     QString name = QFileDialog::getSaveFileName();
182     if (!name.isEmpty()) {
183         QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
184         QFile file(name);
185         if (file.open(QIODevice::WriteOnly)) {
186             QVector<QColor> colormap = currentWidget()->colorMap();
187             QTextStream stream(&file);
188             for (int i = 0; i < colormap.size(); i++) {
189                 stream << colormap[i].red()   << ", "
190                        << colormap[i].green() << ", "
191                        << colormap[i].blue()  << endl;
192             }
193         }
194         QApplication::restoreOverrideCursor();
195     }
196 }
197
198 void GUI::edit_reset()
199 {
200     currentWidget()->reset();
201 }
202
203 void GUI::edit_copy_as_img()
204 {
205     QApplication::clipboard()->setImage(currentWidget()->colorMapImage(0, 1));
206 }
207
208 void GUI::edit_copy_as_txt()
209 {
210     QVector<QColor> colormap = currentWidget()->colorMap();
211     QString string;
212     QTextStream stream(&string);
213     for (int i = 0; i < colormap.size(); i++) {
214         stream << colormap[i].red()   << ", "
215                << colormap[i].green() << ", "
216                << colormap[i].blue()  << endl;
217     }
218     QApplication::clipboard()->setText(string);
219 }
220
221 void GUI::help_about()
222 {
223     QMessageBox::about(this, "About",
224                 "<p>gencolormap version 0.3</p>"
225                 "<p>Copyright (C) 2016<br>"
226                 "   <a href=\"http://www.cg.informatik.uni-siegen.de/\">"
227                 "   Computer Graphics Group, University of Siegen</a>.<br>"
228                 "   Written by <a href=\"http://www.cg.informatik.uni-siegen.de/lambers-martin\">Martin Lambers</a>.<br>"
229                 "   This is free software under the terms of the "
230                     "<a href=\"https://www.debian.org/legal/licenses/mit\">MIT/Expat License</a>. "
231                 "   There is NO WARRANTY, to the extent permitted by law."
232                 "</p>");
233 }
234
235 int main(int argc, char* argv[])
236 {
237     QApplication app(argc, argv);
238     GUI gui;
239     gui.show();
240     return app.exec();
241 }