File indexing completed on 2024-04-28 05:50:38

0001 /*
0002     SPDX-FileCopyrightText: 2007-2008 Robert Knight <robertknight@gmail.com>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 // Own
0008 #include "ColorSchemeEditor.h"
0009 
0010 #include "../config-konsole.h"
0011 
0012 // Qt
0013 #include <QColorDialog>
0014 #include <QCompleter>
0015 #include <QDialogButtonBox>
0016 #include <QFileDialog>
0017 #include <QFileInfo>
0018 #include <QFileSystemModel>
0019 #include <QFontMetrics>
0020 #include <QIcon>
0021 #include <QImageReader>
0022 #include <QMetaEnum>
0023 #include <QPushButton>
0024 #include <QVBoxLayout>
0025 
0026 // KDE
0027 #include <KLocalizedString>
0028 
0029 // Konsole
0030 #include "../characters/CharacterColor.h"
0031 #include "ColorScheme.h"
0032 #include "ui_ColorSchemeEditor.h"
0033 
0034 using namespace Konsole;
0035 
0036 // colorTable is one third the length of _table in ColorScheme class,
0037 // because intense and faint colors are in separate columns
0038 const int COLOR_TABLE_ROW_LENGTH = TABLE_COLORS / 3;
0039 
0040 const int NAME_COLUMN = 0; // column 0 : color names
0041 const int COLOR_COLUMN = 1; // column 1 : actual colors
0042 const int INTENSE_COLOR_COLUMN = 2; // column 2 : intense colors
0043 const int FAINT_COLOR_COLUMN = 3; // column 2 : faint colors
0044 
0045 ColorSchemeEditor::ColorSchemeEditor(bool supportsTransparentWindows, QWidget *parent)
0046     : QDialog(parent)
0047     , _isNewScheme(false)
0048     , _ui(nullptr)
0049 {
0050     auto buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel | QDialogButtonBox::Apply);
0051     auto mainWidget = new QWidget(this);
0052     auto mainLayout = new QVBoxLayout;
0053     setLayout(mainLayout);
0054     mainLayout->addWidget(mainWidget);
0055     QPushButton *okButton = buttonBox->button(QDialogButtonBox::Ok);
0056     okButton->setDefault(true);
0057     connect(buttonBox, &QDialogButtonBox::accepted, this, &ColorSchemeEditor::accept);
0058     connect(buttonBox, &QDialogButtonBox::rejected, this, &ColorSchemeEditor::reject);
0059     mainLayout->addWidget(buttonBox);
0060     connect(buttonBox->button(QDialogButtonBox::Apply), &QPushButton::clicked, this, &Konsole::ColorSchemeEditor::saveColorScheme);
0061     connect(okButton, &QPushButton::clicked, this, &Konsole::ColorSchemeEditor::saveColorScheme);
0062 
0063     // ui
0064     _ui = new Ui::ColorSchemeEditor();
0065     _ui->setupUi(mainWidget);
0066 
0067     // description edit
0068     _ui->descriptionEdit->setClearButtonEnabled(true);
0069     connect(_ui->descriptionEdit, &QLineEdit::textChanged, this, &Konsole::ColorSchemeEditor::setDescription);
0070 
0071     // transparency slider
0072     QFontMetrics metrics(font());
0073     _ui->transparencyPercentLabel->setMinimumWidth(metrics.boundingRect(QStringLiteral("100%")).width());
0074 
0075     connect(_ui->transparencySlider, &QSlider::valueChanged, this, &Konsole::ColorSchemeEditor::setTransparencyPercentLabel);
0076 
0077     // blur behind window
0078     connect(_ui->blurCheckBox, &QCheckBox::toggled, this, &Konsole::ColorSchemeEditor::setBlur);
0079 
0080     // randomized background
0081     connect(_ui->randomizedBackgroundCheck, &QCheckBox::toggled, this, &Konsole::ColorSchemeEditor::setRandomizedBackgroundColor);
0082 
0083     // wallpaper stuff
0084     auto dirModel = new QFileSystemModel(this);
0085     dirModel->setFilter(QDir::AllEntries);
0086     dirModel->setRootPath(QStringLiteral("/"));
0087     auto completer = new QCompleter(this);
0088     completer->setModel(dirModel);
0089     _ui->wallpaperPath->setCompleter(completer);
0090 
0091     _ui->wallpaperPath->setClearButtonEnabled(true);
0092     _ui->wallpaperSelectButton->setIcon(QIcon::fromTheme(QStringLiteral("image-x-generic")));
0093 
0094     connect(_ui->wallpaperTransparencySlider, &QSlider::valueChanged, this, &Konsole::ColorSchemeEditor::setWallpaperOpacity);
0095 
0096     connect(_ui->wallpaperSelectButton, &QToolButton::clicked, this, &Konsole::ColorSchemeEditor::selectWallpaper);
0097     connect(_ui->wallpaperPath, &QLineEdit::textChanged, this, &Konsole::ColorSchemeEditor::wallpaperPathChanged);
0098 
0099     connect(_ui->wallpaperScalingType, &QComboBox::currentIndexChanged, this, &Konsole::ColorSchemeEditor::scalingTypeChanged);
0100     connect(_ui->wallpaperHorizontalAnchorSlider, &QSlider::valueChanged, this, &Konsole::ColorSchemeEditor::horizontalAnchorChanged);
0101     connect(_ui->wallpaperVerticalAnchorSlider, &QSlider::valueChanged, this, &Konsole::ColorSchemeEditor::verticalAnchorChanged);
0102 
0103     connect(_ui->wallpaperFlipType, &QComboBox::currentIndexChanged, this, &Konsole::ColorSchemeEditor::flipTypeChanged);
0104 
0105     // color table
0106     _ui->colorTable->setColumnCount(4);
0107     _ui->colorTable->setRowCount(COLOR_TABLE_ROW_LENGTH);
0108 
0109     QStringList labels;
0110     labels << i18nc("@label:listbox Column header text for color names", "Name") << i18nc("@label:listbox Column header text for the actual colors", "Color")
0111            << i18nc("@label:listbox Column header text for the actual intense colors", "Intense color")
0112            << i18nc("@label:listbox Column header text for the actual faint colors", "Faint color");
0113     _ui->colorTable->setHorizontalHeaderLabels(labels);
0114 
0115     // Set resize mode for colorTable columns
0116     _ui->colorTable->horizontalHeader()->setSectionResizeMode(NAME_COLUMN, QHeaderView::ResizeToContents);
0117     _ui->colorTable->horizontalHeader()->setSectionResizeMode(COLOR_COLUMN, QHeaderView::Stretch);
0118     _ui->colorTable->horizontalHeader()->setSectionResizeMode(INTENSE_COLOR_COLUMN, QHeaderView::Stretch);
0119     _ui->colorTable->horizontalHeader()->setSectionResizeMode(FAINT_COLOR_COLUMN, QHeaderView::Stretch);
0120 
0121     QTableWidgetItem *item = new QTableWidgetItem(QStringLiteral("Test"));
0122     _ui->colorTable->setItem(0, 0, item);
0123 
0124     _ui->colorTable->verticalHeader()->hide();
0125 
0126     connect(_ui->colorTable, &QTableWidget::itemClicked, this, &Konsole::ColorSchemeEditor::editColorItem);
0127 
0128     // warning label when transparency is not available
0129     _ui->transparencyWarningWidget->setWordWrap(true);
0130     _ui->transparencyWarningWidget->setCloseButtonVisible(false);
0131     _ui->transparencyWarningWidget->setMessageType(KMessageWidget::Warning);
0132 
0133     if (supportsTransparentWindows) {
0134         _ui->transparencyWarningWidget->setVisible(false);
0135     } else {
0136         _ui->transparencyWarningWidget->setText(i18nc("@info:status",
0137                                                       "The background transparency setting will not"
0138                                                       " be used because your desktop does not appear to support"
0139                                                       " transparent windows."));
0140     }
0141 }
0142 
0143 ColorSchemeEditor::~ColorSchemeEditor()
0144 {
0145     delete _ui;
0146 }
0147 
0148 void ColorSchemeEditor::editColorItem(QTableWidgetItem *item)
0149 {
0150     // ignore if this is not a color column
0151     if (item->column() != COLOR_COLUMN && item->column() != INTENSE_COLOR_COLUMN && item->column() != FAINT_COLOR_COLUMN) {
0152         return;
0153     }
0154 
0155     QColor color = item->background().color();
0156     color = QColorDialog::getColor(color);
0157     if (color.isValid()) {
0158         item->setBackground(color);
0159 
0160         int colorSchemeRow = item->row();
0161         // Intense colors row are in the middle third of the color table
0162         if (item->column() == INTENSE_COLOR_COLUMN) {
0163             colorSchemeRow += COLOR_TABLE_ROW_LENGTH;
0164         }
0165 
0166         // and the faint color rows are in the final third of the color table
0167         if (item->column() == FAINT_COLOR_COLUMN) {
0168             colorSchemeRow += 2 * COLOR_TABLE_ROW_LENGTH;
0169         }
0170 
0171         _colors->setColorTableEntry(colorSchemeRow, color);
0172 
0173         Q_EMIT colorsChanged(_colors);
0174     }
0175 }
0176 
0177 void ColorSchemeEditor::selectWallpaper()
0178 {
0179     // Get supported image formats and convert to QString for getOpenFileName()
0180     const QList<QByteArray> mimeTypes = QImageReader::supportedImageFormats();
0181     QString fileFormats = QStringLiteral("(");
0182     for (const QByteArray &mime : mimeTypes) {
0183         fileFormats += QStringLiteral("*.%1 ").arg(QLatin1String(mime));
0184     }
0185     fileFormats += QLatin1String(")");
0186 
0187     const QString fileName = QFileDialog::getOpenFileName(this,
0188                                                           i18nc("@title:window", "Select wallpaper image file"),
0189                                                           _ui->wallpaperPath->text(),
0190                                                           i18nc("@label:textbox Filter in file open dialog", "Supported Images") + fileFormats);
0191 
0192     if (!fileName.isEmpty()) {
0193         _ui->wallpaperPath->setText(fileName);
0194     }
0195 }
0196 
0197 void ColorSchemeEditor::setWallpaperOpacity(int percent)
0198 {
0199     _ui->wallpaperTransparencyPercentLabel->setText(QStringLiteral("%1%").arg(percent));
0200 
0201     const qreal opacity = (100.0 - percent) / 100.0;
0202     _colors->setWallpaper(_colors->wallpaper()->path(),
0203                           _colors->wallpaper()->style(),
0204                           _colors->wallpaper()->anchor(),
0205                           opacity,
0206                           _colors->wallpaper()->flipType());
0207 }
0208 
0209 void ColorSchemeEditor::wallpaperPathChanged(const QString &path)
0210 {
0211     if (path.isEmpty()) {
0212         _colors->setWallpaper(path,
0213                               _colors->wallpaper()->style(),
0214                               _colors->wallpaper()->anchor(),
0215                               _colors->wallpaper()->opacity(),
0216                               _colors->wallpaper()->flipType());
0217         enableWallpaperSettings(false);
0218     } else {
0219         QFileInfo i(path);
0220 
0221         if (i.exists() && i.isFile() && i.isReadable()) {
0222             _colors->setWallpaper(path,
0223                                   _colors->wallpaper()->style(),
0224                                   _colors->wallpaper()->anchor(),
0225                                   _colors->wallpaper()->opacity(),
0226                                   _colors->wallpaper()->flipType());
0227             enableWallpaperSettings(true);
0228         }
0229     }
0230 }
0231 
0232 void ColorSchemeEditor::scalingTypeChanged(int styleIndex)
0233 {
0234     const char *flipType = QMetaEnum::fromType<ColorSchemeWallpaper::FlipType>().valueToKey(_colors->wallpaper()->flipType());
0235     const char *style = QMetaEnum::fromType<ColorSchemeWallpaper::FillStyle>().valueToKey(styleIndex);
0236     _colors->setWallpaper(_colors->wallpaper()->path(),
0237                           QString::fromLatin1(style),
0238                           _colors->wallpaper()->anchor(),
0239                           _colors->wallpaper()->opacity(),
0240                           QString::fromLatin1(flipType));
0241 }
0242 
0243 void ColorSchemeEditor::flipTypeChanged(int flipTypeIndex)
0244 {
0245     const char *fillStyle = QMetaEnum::fromType<ColorSchemeWallpaper::FillStyle>().valueToKey(_colors->wallpaper()->style());
0246     const char *flipType = QMetaEnum::fromType<ColorSchemeWallpaper::FlipType>().valueToKey(flipTypeIndex);
0247     _colors->setWallpaper(_colors->wallpaper()->path(),
0248                           QString::fromLatin1(fillStyle),
0249                           _colors->wallpaper()->anchor(),
0250                           _colors->wallpaper()->opacity(),
0251                           QString::fromLatin1(flipType));
0252 }
0253 
0254 void ColorSchemeEditor::horizontalAnchorChanged(int pos)
0255 {
0256     QPointF anch = _colors->wallpaper()->anchor();
0257     _colors->setWallpaper(_colors->wallpaper()->path(),
0258                           _colors->wallpaper()->style(),
0259                           QPointF(pos / 2.0, anch.y()),
0260                           _colors->wallpaper()->opacity(),
0261                           _colors->wallpaper()->flipType());
0262     switch (pos) {
0263     case 2:
0264         _ui->wallpaperHorizontalAnchorPosition->setText(QString::fromLatin1("Right"));
0265         break;
0266     case 1:
0267         _ui->wallpaperHorizontalAnchorPosition->setText(QString::fromLatin1("Center"));
0268         break;
0269     case 0:
0270     default:
0271         _ui->wallpaperHorizontalAnchorPosition->setText(QString::fromLatin1("Left"));
0272         break;
0273     }
0274 }
0275 
0276 void ColorSchemeEditor::verticalAnchorChanged(int pos)
0277 {
0278     QPointF anch = _colors->wallpaper()->anchor();
0279     _colors->setWallpaper(_colors->wallpaper()->path(),
0280                           _colors->wallpaper()->style(),
0281                           QPointF(anch.x(), pos / 2.0),
0282                           _colors->wallpaper()->opacity(),
0283                           _colors->wallpaper()->flipType());
0284     switch (pos) {
0285     case 2:
0286         _ui->wallpaperVerticalAnchorPosition->setText(QString::fromLatin1("Bottom"));
0287         break;
0288     case 1:
0289         _ui->wallpaperVerticalAnchorPosition->setText(QString::fromLatin1("Middle"));
0290         break;
0291     case 0:
0292     default:
0293         _ui->wallpaperVerticalAnchorPosition->setText(QString::fromLatin1("Top"));
0294         break;
0295     }
0296 }
0297 
0298 void ColorSchemeEditor::setDescription(const QString &description)
0299 {
0300     if (_colors != nullptr) {
0301         _colors->setDescription(description);
0302     }
0303 
0304     if (_ui->descriptionEdit->text() != description) {
0305         _ui->descriptionEdit->setText(description);
0306     }
0307 }
0308 
0309 void ColorSchemeEditor::setTransparencyPercentLabel(int percent)
0310 {
0311     _ui->transparencyPercentLabel->setText(QStringLiteral("%1%").arg(percent));
0312 
0313     const qreal opacity = (100.0 - percent) / 100.0;
0314     _colors->setOpacity(opacity);
0315 }
0316 
0317 void ColorSchemeEditor::setBlur(bool blur)
0318 {
0319     _colors->setBlur(blur);
0320 }
0321 
0322 void ColorSchemeEditor::setRandomizedBackgroundColor(bool randomized)
0323 {
0324     _colors->setColorRandomization(randomized);
0325 }
0326 
0327 void ColorSchemeEditor::setup(const std::shared_ptr<const ColorScheme> &scheme, bool isNewScheme)
0328 {
0329     _isNewScheme = isNewScheme;
0330 
0331     _colors = std::make_shared<ColorScheme>(*scheme);
0332 
0333     if (_isNewScheme) {
0334         setWindowTitle(i18nc("@title:window", "New Color Scheme"));
0335         setDescription(QStringLiteral("New Color Scheme"));
0336     } else {
0337         setWindowTitle(i18nc("@title:window", "Edit Color Scheme"));
0338     }
0339 
0340     // setup description edit
0341     _ui->descriptionEdit->setText(_colors->description());
0342 
0343     // setup color table
0344     setupColorTable(_colors);
0345 
0346     // setup transparency slider
0347     const int colorTransparencyPercent = qRound((1 - _colors->opacity()) * 100);
0348     const int wallpaperTransparencyPercent = qRound((1 - _colors->wallpaper()->opacity()) * 100);
0349     _ui->transparencySlider->setValue(colorTransparencyPercent);
0350     _ui->wallpaperTransparencySlider->setValue(wallpaperTransparencyPercent);
0351     setTransparencyPercentLabel(colorTransparencyPercent);
0352     setWallpaperOpacity(wallpaperTransparencyPercent);
0353 
0354     // blur behind window checkbox
0355     _ui->blurCheckBox->setChecked(scheme->blur());
0356 
0357     // randomized background color checkbox
0358     _ui->randomizedBackgroundCheck->setChecked(scheme->isColorRandomizationEnabled());
0359 
0360     // wallpaper stuff
0361     int ax = qRound(scheme->wallpaper()->anchor().x() * 2.0);
0362     int ay = qRound(scheme->wallpaper()->anchor().y() * 2.0);
0363     _ui->wallpaperPath->setText(scheme->wallpaper()->path());
0364     _ui->wallpaperScalingType->setCurrentIndex(scheme->wallpaper()->style());
0365     _ui->wallpaperFlipType->setCurrentIndex(scheme->wallpaper()->flipType());
0366     _ui->wallpaperHorizontalAnchorSlider->setValue(ax);
0367     _ui->wallpaperVerticalAnchorSlider->setValue(ay);
0368     enableWallpaperSettings(!scheme->wallpaper()->isNull());
0369 }
0370 
0371 void ColorSchemeEditor::setupColorTable(const std::shared_ptr<ColorScheme> &colors)
0372 {
0373     QColor table[TABLE_COLORS];
0374     colors->getColorTable(table);
0375 
0376     for (int row = 0; row < COLOR_TABLE_ROW_LENGTH; row++) {
0377         QTableWidgetItem *nameItem = new QTableWidgetItem(ColorScheme::translatedColorNameForIndex(row));
0378         nameItem->setFlags(nameItem->flags() & ~Qt::ItemIsEditable);
0379 
0380         auto colorItem = new QTableWidgetItem();
0381         colorItem->setBackground(table[row]);
0382         colorItem->setFlags(colorItem->flags() & ~Qt::ItemIsEditable & ~Qt::ItemIsSelectable);
0383         colorItem->setToolTip(i18nc("@info:tooltip", "Click to choose color"));
0384 
0385         auto colorItemIntense = new QTableWidgetItem();
0386         colorItemIntense->setBackground(table[COLOR_TABLE_ROW_LENGTH + row]);
0387         colorItemIntense->setFlags(colorItem->flags() & ~Qt::ItemIsEditable & ~Qt::ItemIsSelectable);
0388         colorItemIntense->setToolTip(i18nc("@info:tooltip", "Click to choose intense color"));
0389 
0390         auto colorItemFaint = new QTableWidgetItem();
0391         colorItemFaint->setBackground(table[2 * COLOR_TABLE_ROW_LENGTH + row]);
0392         colorItemFaint->setFlags(colorItem->flags() & ~Qt::ItemIsEditable & ~Qt::ItemIsSelectable);
0393         colorItemFaint->setToolTip(i18nc("@info:tooltip", "Click to choose Faint color"));
0394 
0395         _ui->colorTable->setItem(row, NAME_COLUMN, nameItem);
0396         _ui->colorTable->setItem(row, COLOR_COLUMN, colorItem);
0397         _ui->colorTable->setItem(row, INTENSE_COLOR_COLUMN, colorItemIntense);
0398         _ui->colorTable->setItem(row, FAINT_COLOR_COLUMN, colorItemFaint);
0399     }
0400     // ensure that color names are as fully visible as possible
0401     _ui->colorTable->resizeColumnToContents(0);
0402 }
0403 
0404 ColorScheme &ColorSchemeEditor::colorScheme() const
0405 {
0406     return *_colors;
0407 }
0408 
0409 bool ColorSchemeEditor::isNewScheme() const
0410 {
0411     return _isNewScheme;
0412 }
0413 
0414 void ColorSchemeEditor::saveColorScheme()
0415 {
0416     Q_EMIT colorSchemeSaveRequested(colorScheme(), _isNewScheme);
0417 }
0418 
0419 void ColorSchemeEditor::enableWallpaperSettings(bool enable)
0420 {
0421     _ui->wallpaperHorizontalAnchorSlider->setEnabled(enable);
0422     _ui->wallpaperVerticalAnchorSlider->setEnabled(enable);
0423     _ui->wallpaperTransparencySlider->setEnabled(enable);
0424     _ui->wallpaperScalingType->setEnabled(enable);
0425     _ui->wallpaperFlipType->setEnabled(enable);
0426 }
0427 
0428 #include "moc_ColorSchemeEditor.cpp"