File indexing completed on 2024-04-21 14:43:56
0001 /* 0002 SPDX-FileCopyrightText: 2002 Jason Harris <kstars@30doradus.org> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "colorscheme.h" 0008 0009 #include "kspaths.h" 0010 #include "ksutils.h" 0011 #include "Options.h" 0012 #include "auxiliary/ksnotification.h" 0013 #include "skyobjects/starobject.h" 0014 #ifdef KSTARS_LITE 0015 #include "skymaplite.h" 0016 #else 0017 #include "skyqpainter.h" 0018 #endif 0019 0020 ColorScheme::ColorScheme() : FileName() 0021 { 0022 //Each color has two names associated with it. The KeyName is its 0023 //identification in the QMap, the *.colors file, and the config file. 0024 //The Name is what appears in the ViewOpsDialog ListBox. 0025 //In addition, we define default RGB strings for each item. 0026 //To add another color to the Palette, just add an entry for KeyName, 0027 //Name and Default here. 0028 0029 appendItem("SkyColor", i18n("Sky"), "#000000"); 0030 appendItem("DSOColor", i18n("Messier Object"), "#008f00"); 0031 appendItem("HSTColor", i18nc("Object with extra attached URLs", "Object w/ Links"), "#930000"); 0032 appendItem("SNameColor", i18n("Star Name"), "#577d7d"); 0033 appendItem("DSNameColor", i18n("Deep Sky Object Name"), "#75759c"); 0034 appendItem("PNameColor", i18n("Planet Name"), "#ac9800"); 0035 appendItem("CNameColor", i18nc("Constellation Name", "Constell. Name"), "#718488"); 0036 appendItem("CLineColor", i18nc("Constellation Line", "Constell. Line"), "#3d3d3d"); 0037 appendItem("CBoundColor", i18nc("Constellation Boundary", "Constell. Boundary"), "#222f2f"); 0038 appendItem("CBoundHighColor", i18nc("Highlighted Constellation Boundary", "Constell. Boundary Highlight"), 0039 "#445555"); 0040 appendItem("MWColor", i18nc("refers to the band of stars in the sky due to the Galactic plane", "Milky Way"), 0041 "#0d1115"); 0042 appendItem("EqColor", i18n("Equator"), "#909090"); 0043 appendItem("EclColor", i18n("Ecliptic"), "#613d12"); 0044 appendItem("HorzColor", i18n("Horizon"), "#091f14"); 0045 appendItem("LocalMeridianColor", i18n("Local Meridian"), "#0059b3"); 0046 appendItem("CompassColor", i18n("Compass Labels"), "#909055"); 0047 appendItem("EquatorialGridColor", i18n("Equatorial Coordinate Grid"), "#445566"); 0048 appendItem("HorizontalGridColor", i18n("Horizontal Coordinate Grid"), "#091f14"); 0049 appendItem("BoxTextColor", i18n("Info Box Text"), "#d2dbef"); 0050 appendItem("BoxGrabColor", i18n("Info Box Selected"), "#900000"); 0051 appendItem("BoxBGColor", i18n("Info Box Background"), "#000000"); 0052 appendItem("TargetColor", i18n("Target Indicator"), "#DD0000"); 0053 appendItem("UserLabelColor", i18n("User Labels"), "#AAAAAA"); 0054 appendItem("PlanetTrailColor", i18n("Planet Trails"), "#993311"); 0055 appendItem("AngularRuler", i18n("Angular Distance Ruler"), "#445566"); 0056 appendItem("ObsListColor", i18n("Observing List Label"), "#FF0000"); 0057 appendItem("StarHopRouteColor", i18n("Star-Hop Route"), "#00FFFF"); 0058 appendItem("VisibleSatColor", i18n("Visible Satellites"), "#00FF00"); 0059 appendItem("SatColor", i18n("Satellites"), "#FF0000"); 0060 appendItem("SatLabelColor", i18n("Satellites Labels"), "#640000"); 0061 appendItem("SupernovaColor", i18n("Supernovae"), "#FFA500"); 0062 appendItem("AsteroidColor", i18n("Asteroids"), "#F1C232"); 0063 appendItem("ArtificialHorizonColor", i18n("Artificial Horizon"), "#C82828"); 0064 appendItem("RAGuideError", i18n("RA Guide Error"), "#00FF00"); 0065 appendItem("DEGuideError", i18n("DEC Guide Error"), "#00A5FF"); 0066 appendItem("SolverFOVColor", i18n("Solver FOV"), "#FFFFFF"); 0067 appendItem("SensorFOVColor", i18n("Sensor FOV"), "#FFAA00"); 0068 appendItem("HIPSGridColor", i18n("HiPS Grid"), "#FFFFFF"); 0069 appendItem("FITSObjectLabelColor", i18n("FITS Image Object Label"), "#00FF00"); 0070 0071 //Load colors from config object 0072 loadFromConfig(); 0073 0074 //Default values for integer variables: 0075 StarColorMode = 0; 0076 StarColorIntensity = 4; 0077 DarkPalette = 0; 0078 } 0079 0080 void ColorScheme::appendItem(const QString &key, const QString &name, const QString &def) 0081 { 0082 KeyName.append(key); 0083 Name.append(name); 0084 Default.append(def); 0085 } 0086 0087 QColor ColorScheme::colorNamed(const QString &name) const 0088 { 0089 if (!hasColorNamed(name)) 0090 { 0091 qWarning() << "No color named" << name << "found in color scheme."; 0092 // Return white if no color found 0093 return QColor(Qt::white); 0094 } 0095 return QColor(Palette[name]); 0096 } 0097 0098 QColor ColorScheme::colorAt(int i) const 0099 { 0100 return QColor(Palette[KeyName.at(i)]); 0101 } 0102 0103 QString ColorScheme::nameAt(int i) const 0104 { 0105 return Name.at(i); 0106 } 0107 0108 QString ColorScheme::keyAt(int i) const 0109 { 0110 return KeyName.at(i); 0111 } 0112 0113 QString ColorScheme::nameFromKey(const QString &key) const 0114 { 0115 return nameAt(KeyName.indexOf(key)); 0116 } 0117 0118 void ColorScheme::setColor(const QString &key, const QString &color) 0119 { 0120 //We can blindly insert() the new value; if the key exists, the old value is replaced 0121 Palette.insert(key, color); 0122 0123 KConfigGroup cg = KSharedConfig::openConfig()->group("Colors"); 0124 cg.writeEntry(key, color); 0125 } 0126 0127 bool ColorScheme::load(const QString &name) 0128 { 0129 QString filename = name.toLower().trimmed(); 0130 QFile file; 0131 int inew = 0, iold = 0; 0132 bool ok = false; 0133 0134 //Parse default names which don't follow the regular file-naming scheme 0135 if (name == i18nc("use default color scheme", "Default Colors")) 0136 filename = "classic.colors"; 0137 if (name == i18nc("use 'star chart' color scheme", "Star Chart")) 0138 filename = "chart.colors"; 0139 if (name == i18nc("use 'night vision' color scheme", "Night Vision")) 0140 filename = "night.colors"; 0141 0142 //Try the filename if it ends with ".colors" 0143 if (filename.endsWith(QLatin1String(".colors"))) 0144 ok = KSUtils::openDataFile(file, filename); 0145 0146 //If that didn't work, try assuming that 'name' is the color scheme name 0147 //convert it to a filename exactly as ColorScheme::save() does 0148 if (!ok) 0149 { 0150 if (!filename.isEmpty()) 0151 { 0152 filename.replace(' ', '-').append(".colors"); 0153 ok = KSUtils::openDataFile(file, filename); 0154 } 0155 0156 if (!ok) 0157 { 0158 qDebug() << Q_FUNC_INFO << QString("Unable to load color scheme named %1. Also tried %2.").arg(name, filename); 0159 return false; 0160 } 0161 } 0162 0163 //If we reach here, the file should have been successfully opened 0164 QTextStream stream(&file); 0165 0166 //first line is the star-color mode and star color intensity and dark palette 0167 QString line = stream.readLine(); 0168 QStringList modes = line.split(':'); 0169 0170 // Star Color Mode 0171 if (modes.count() > 0) 0172 { 0173 int newmode = modes[0].toInt(&ok); 0174 if (ok) 0175 setStarColorMode(newmode); 0176 } 0177 0178 // Star Intensity 0179 if (modes.count() > 1) 0180 { 0181 int newintens = modes[1].toInt(&ok); 0182 if (ok) 0183 setStarColorIntensity(newintens); 0184 } 0185 0186 // Dark Palette 0187 #if 0 0188 if (modes.count() > 2) 0189 { 0190 int newintens = modes[2].toInt(&ok); 0191 if (ok) 0192 setDarkPalette(newintens == 1); 0193 } 0194 #endif 0195 0196 //More flexible method for reading in color values. Any order is acceptable, and 0197 //missing entries are ignored. 0198 while (!stream.atEnd()) 0199 { 0200 line = stream.readLine(); 0201 0202 if (line.count(':') == 0203 1) //the new color preset format contains a ":" in each line, followed by the name of the color 0204 { 0205 ++inew; 0206 if (iold) 0207 return false; //we read at least one line without a colon...file is corrupted. 0208 0209 //If this line has a valid Key, set the color. 0210 QString tkey = line.mid(line.indexOf(':') + 1).trimmed(); 0211 QString tname = line.left(line.indexOf(':') - 1); 0212 0213 if (KeyName.contains(tkey)) 0214 { 0215 setColor(tkey, tname); 0216 } 0217 else //attempt to translate from old color ID 0218 { 0219 QString k(line.mid(5).trimmed() + "Color"); 0220 if (KeyName.contains(k)) 0221 { 0222 setColor(k, tname); 0223 } 0224 else 0225 { 0226 qWarning() << "Could not use the key \"" << tkey << "\" from the color scheme file \"" << filename 0227 << "\". I also tried \"" << k << "\"."; 0228 } 0229 } 0230 } 0231 else // no ':' seen in the line, so we must assume the old format 0232 { 0233 ++iold; 0234 if (inew) 0235 return false; //a previous line had a colon, this line doesn't. File is corrupted. 0236 0237 //Assuming the old *.colors format. Loop through the KeyName list, 0238 //and assign each color. Note that order matters here, but only here 0239 //(so if you don't use the old format, then order doesn't ever matter) 0240 foreach (const QString &key, KeyName) 0241 setColor(key, line.left(7)); 0242 } 0243 } 0244 0245 FileName = filename; 0246 return true; 0247 } 0248 0249 bool ColorScheme::save(const QString &name) 0250 { 0251 QFile file; 0252 0253 //Construct a file name from the scheme name. Make lowercase, replace spaces with "-", 0254 //and append ".colors". 0255 QString filename = name.toLower().trimmed(); 0256 if (!filename.isEmpty()) 0257 { 0258 for (int i = 0; i < filename.length(); ++i) 0259 if (filename.at(i) == ' ') 0260 filename.replace(i, 1, "-"); 0261 0262 filename = filename.append(".colors"); 0263 //determine filename in local user KDE directory tree. 0264 file.setFileName(QDir(KSPaths::writableLocation(QStandardPaths::AppLocalDataLocation)).filePath(filename)); 0265 0266 //if (file.exists() || !file.open(QIODevice::ReadWrite | QIODevice::Append)) 0267 if (!file.open(QIODevice::ReadWrite)) 0268 { 0269 KSNotification::sorry(i18n("Local color scheme file could not be opened.\nScheme cannot be recorded.")); 0270 return false; 0271 } 0272 else 0273 { 0274 QTextStream stream(&file); 0275 stream << StarColorMode << ":" << StarColorIntensity << ":" << DarkPalette << '\n'; 0276 0277 foreach (const QString &key, KeyName) 0278 stream << Palette[key] << " :" << key << '\n'; 0279 file.close(); 0280 } 0281 0282 //determine filename in local user KDE directory tree. 0283 file.setFileName(QDir(KSPaths::writableLocation(QStandardPaths::AppLocalDataLocation)).filePath("colors.dat")); 0284 0285 if (!file.open(QIODevice::ReadWrite)) 0286 { 0287 KSNotification::sorry(i18n("Local color scheme index file could not be opened.\nScheme cannot be recorded.")); 0288 } 0289 else 0290 { 0291 bool found = false; 0292 QString schemeLine = name + ':' + filename; 0293 0294 // Check if the scheme line is in the colors.dat file 0295 // If not, then we add it 0296 QTextStream stream(&file); 0297 while (stream.atEnd() == false) 0298 { 0299 QString line = stream.readLine(); 0300 if (line == schemeLine) 0301 { 0302 found = true; 0303 break; 0304 } 0305 } 0306 0307 if (found == false) 0308 { 0309 stream << schemeLine << '\n'; 0310 file.close(); 0311 } 0312 } 0313 } 0314 else 0315 { 0316 KSNotification::sorry("Invalid filename requested.\nScheme cannot be recorded."); 0317 return false; 0318 } 0319 0320 FileName = filename; 0321 saveToConfig(); 0322 return true; 0323 } 0324 0325 void ColorScheme::loadFromConfig() 0326 { 0327 KConfigGroup cg = KSharedConfig::openConfig()->group("Colors"); 0328 0329 for (int i = 0; i < KeyName.size(); ++i) 0330 setColor(KeyName.at(i), cg.readEntry(KeyName.at(i).toUtf8().constData(), Default.at(i))); 0331 0332 setStarColorModeIntensity(cg.readEntry("StarColorMode", 0), cg.readEntry("StarColorIntensity", 5)); 0333 //setDarkPalette(cg.readEntry("DarkAppColors", false)); 0334 0335 FileName = cg.readEntry("ColorSchemeFile", "moonless-night.colors"); 0336 } 0337 0338 void ColorScheme::saveToConfig() 0339 { 0340 KConfigGroup cg = KSharedConfig::openConfig()->group("Colors"); 0341 for (int i = 0; i < KeyName.size(); ++i) 0342 { 0343 QString c = colorNamed(KeyName.at(i)).name(); 0344 cg.writeEntry(KeyName.at(i), c); 0345 } 0346 0347 cg.writeEntry("StarColorMode", starColorMode()); 0348 cg.writeEntry("StarColorIntensity", starColorIntensity()); 0349 cg.writeEntry("ColorSchemeFile", FileName); 0350 cg.writeEntry("DarkAppColors", useDarkPalette()); 0351 } 0352 0353 void ColorScheme::setStarColorMode(int mode) 0354 { 0355 StarColorMode = mode; 0356 Options::setStarColorMode(mode); 0357 #ifndef KSTARS_LITE 0358 SkyQPainter::initStarImages(); 0359 #endif 0360 } 0361 0362 #if 0 0363 void ColorScheme::setDarkPalette(bool enable) 0364 { 0365 DarkPalette = enable ? 1 : 0; 0366 Options::setDarkAppColors(enable); 0367 #ifndef KSTARS_LITE 0368 SkyQPainter::initStarImages(); 0369 #endif 0370 } 0371 #endif 0372 0373 void ColorScheme::setStarColorIntensity(int intens) 0374 { 0375 StarColorIntensity = intens; 0376 Options::setStarColorIntensity(intens); 0377 #ifndef KSTARS_LITE 0378 SkyQPainter::initStarImages(); 0379 #endif 0380 } 0381 0382 void ColorScheme::setStarColorModeIntensity(int mode, int intens) 0383 { 0384 StarColorMode = mode; 0385 StarColorIntensity = intens; 0386 Options::setStarColorMode(mode); 0387 Options::setStarColorIntensity(intens); 0388 #ifndef KSTARS_LITE 0389 SkyQPainter::initStarImages(); 0390 #endif 0391 }