Vault
4.1
|
00001 00002 /* 00003 Copyright c1997-2014 Trygve Isaacson. All rights reserved. 00004 This file is part of the Code Vault version 4.1 00005 http://www.bombaydigital.com/ 00006 License: MIT. See LICENSE.md in the Vault top level directory. 00007 */ 00008 00009 #include "vcolor.h" 00010 00011 #include "vchar.h" 00012 #include "vhex.h" 00013 #include "vsettings.h" 00014 00015 // VColor ------------------------------------------------------------------ 00016 00017 // The standard CSS named colors. 00018 const VColor& VColor::AQUA() { static const VColor kAqua ( 0, 255, 255); return kAqua; } 00019 const VColor& VColor::BLACK() { static const VColor kBlack ( 0, 0, 0); return kBlack; } 00020 const VColor& VColor::BLUE() { static const VColor kBlue ( 0, 0, 255); return kBlue; } 00021 const VColor& VColor::FUCHSIA() { static const VColor kFuchsia(255, 0, 255); return kFuchsia; } 00022 const VColor& VColor::GREEN() { static const VColor kGreen ( 0, 128, 0); return kGreen; } 00023 const VColor& VColor::GRAY() { static const VColor kGray (128, 128, 128); return kGray; } 00024 const VColor& VColor::LIME() { static const VColor kLime ( 0, 255, 0); return kLime; } 00025 const VColor& VColor::MAROON() { static const VColor kMaroon (128, 0, 0); return kMaroon; } 00026 const VColor& VColor::NAVY() { static const VColor kNavy ( 0, 0, 128); return kNavy; } 00027 const VColor& VColor::OLIVE() { static const VColor kOlive (128, 128, 0); return kOlive; } 00028 const VColor& VColor::ORANGE() { static const VColor kOrange (255, 165, 0); return kOrange; } 00029 const VColor& VColor::PURPLE() { static const VColor kPurple (128, 0, 128); return kPurple; } 00030 const VColor& VColor::RED() { static const VColor kRed (255, 0, 0); return kRed; } 00031 const VColor& VColor::SILVER() { static const VColor kSilver (192, 192, 192); return kSilver; } 00032 const VColor& VColor::TEAL() { static const VColor kTeal ( 0, 128, 128); return kTeal; } 00033 const VColor& VColor::WHITE() { static const VColor kWhite (255, 255, 255); return kWhite; } 00034 const VColor& VColor::YELLOW() { static const VColor kYellow (255, 255, 0); return kYellow; } 00035 00036 VString VColor::getCSSColor() const { 00037 if (*this == BLACK()) 00038 return "black"; 00039 if (*this == WHITE()) 00040 return "white"; 00041 00042 if (*this == AQUA()) 00043 return "aqua"; 00044 if (*this == BLUE()) 00045 return "blue"; 00046 if (*this == FUCHSIA()) 00047 return "fuchsia"; 00048 if (*this == GREEN()) 00049 return "green"; 00050 if (*this == GRAY()) 00051 return "gray"; 00052 if (*this == LIME()) 00053 return "lime"; 00054 if (*this == MAROON()) 00055 return "maroon"; 00056 if (*this == NAVY()) 00057 return "navy"; 00058 if (*this == OLIVE()) 00059 return "olive"; 00060 if (*this == ORANGE()) 00061 return "orange"; 00062 if (*this == PURPLE()) 00063 return "purple"; 00064 if (*this == RED()) 00065 return "red"; 00066 if (*this == SILVER()) 00067 return "silver"; 00068 if (*this == TEAL()) 00069 return "teal"; 00070 if (*this == YELLOW()) 00071 return "yellow"; 00072 00073 return VSTRING_FORMAT("#%02x%02x%02x", mRed, mGreen, mBlue); 00074 } 00075 00076 VDouble VColor::getLightness() const { 00077 // Calculate the Lightness value (the L in HSL; doesn't require calculating H or S). 00078 Vu8 maxColor = V_MAX(mRed, V_MAX(mGreen, mBlue)); 00079 Vu8 minColor = V_MIN(mRed, V_MIN(mGreen, mBlue)); 00080 VDouble lightness = (((VDouble) minColor) + ((VDouble) maxColor)) / 510.0; // e.g., avg of minColor and maxColor, where 0 is 0.0 and 255 is 1.0, thus divide by (2*255) 00081 return lightness; 00082 } 00083 00084 void VColor::setCSSColor(const VString& cssColor) { 00085 VString colorText(cssColor); 00086 colorText.trim(); // allow for leading/trailing whitespace in input string 00087 00088 bool valid = false; 00089 if (colorText.startsWith('#')) { 00090 // Allowed formats: 00091 // #xyz is short for #xxyyzz 00092 // #xxyyzz is the hexadecimal r-g-b byte values 00093 if (colorText.length() == 4) { 00094 valid = colorText.at(1).isHexadecimal() && 00095 colorText.at(2).isHexadecimal() && 00096 colorText.at(3).isHexadecimal(); 00097 00098 if (valid) { 00099 mRed = VHex::hexCharsToByte(colorText.at(1), colorText.at(1)); 00100 mGreen = VHex::hexCharsToByte(colorText.at(2), colorText.at(2)); 00101 mBlue = VHex::hexCharsToByte(colorText.at(3), colorText.at(3)); 00102 mAlpha = 255; 00103 } 00104 } else if (colorText.length() == 7) { 00105 valid = colorText.at(1).isHexadecimal() && 00106 colorText.at(2).isHexadecimal() && 00107 colorText.at(3).isHexadecimal() && 00108 colorText.at(4).isHexadecimal() && 00109 colorText.at(5).isHexadecimal() && 00110 colorText.at(6).isHexadecimal(); 00111 00112 if (valid) { 00113 mRed = VHex::hexCharsToByte(colorText.at(1), colorText.at(2)); 00114 mGreen = VHex::hexCharsToByte(colorText.at(3), colorText.at(4)); 00115 mBlue = VHex::hexCharsToByte(colorText.at(5), colorText.at(6)); 00116 mAlpha = 255; 00117 } 00118 } 00119 } else if (colorText.startsWith("rgb(") && colorText.endsWith(')')) { 00120 // Allowed formats: 00121 // rgb(x,y,z) -- whitespace inside () is OK; x y and z are the r, g, b integer values 00122 colorText.substringInPlace(4, colorText.length() - 1); 00123 colorText.trim(); 00124 int redStart = 0; 00125 int redEnd = colorText.indexOf(','); 00126 int greenStart = redEnd + 1; 00127 int greenEnd = colorText.indexOf(',', greenStart); 00128 int blueStart = greenEnd + 1; 00129 int blueEnd = colorText.indexOf(',', blueStart); 00130 00131 if ((redStart < redEnd) && (redEnd < greenStart) && (greenStart < greenEnd) && (greenEnd < blueStart) && (blueEnd == -1)) { 00132 VString redValue; colorText.getSubstring(redValue, redStart, redEnd); redValue.trim(); 00133 VString greenValue; colorText.getSubstring(greenValue, greenStart, greenEnd); greenValue.trim(); 00134 VString blueValue; colorText.getSubstring(blueValue, blueStart, blueEnd); blueValue.trim(); 00135 00136 if (redValue.isNotEmpty() && greenValue.isNotEmpty() && blueValue.isNotEmpty()) { // parseInt() treats empty as meaning "0" 00137 try { 00138 int r = redValue.parseInt(); 00139 int g = greenValue.parseInt(); 00140 int b = blueValue.parseInt(); 00141 this->setValues(r, g, b); 00142 valid = true; 00143 } catch (VRangeException& /*ex*/) { 00144 // Let our validity check below throw with a more informative message than "integer value out of range". 00145 } 00146 } 00147 } 00148 } else if (colorText.equalsIgnoreCase("black")) { 00149 *this = BLACK(); 00150 valid = true; 00151 } else if (colorText.equalsIgnoreCase("white")) { 00152 *this = WHITE(); 00153 valid = true; 00154 } else if (colorText.equalsIgnoreCase("aqua") || colorText.equalsIgnoreCase("cyan")) { 00155 *this = AQUA(); 00156 valid = true; 00157 } else if (colorText.equalsIgnoreCase("blue")) { 00158 *this = BLUE(); 00159 valid = true; 00160 } else if (colorText.equalsIgnoreCase("fuchsia") || colorText.equalsIgnoreCase("magenta")) { 00161 *this = FUCHSIA(); 00162 valid = true; 00163 } else if (colorText.equalsIgnoreCase("green")) { 00164 *this = GREEN(); 00165 valid = true; 00166 } else if (colorText.equalsIgnoreCase("gray") || colorText.equalsIgnoreCase("grey")) { 00167 *this = GRAY(); 00168 valid = true; 00169 } else if (colorText.equalsIgnoreCase("lime")) { 00170 *this = LIME(); 00171 valid = true; 00172 } else if (colorText.equalsIgnoreCase("maroon")) { 00173 *this = MAROON(); 00174 valid = true; 00175 } else if (colorText.equalsIgnoreCase("navy")) { 00176 *this = NAVY(); 00177 valid = true; 00178 } else if (colorText.equalsIgnoreCase("olive")) { 00179 *this = OLIVE(); 00180 valid = true; 00181 } else if (colorText.equalsIgnoreCase("orange")) { 00182 *this = ORANGE(); 00183 valid = true; 00184 } else if (colorText.equalsIgnoreCase("purple")) { 00185 *this = PURPLE(); 00186 valid = true; 00187 } else if (colorText.equalsIgnoreCase("red")) { 00188 *this = RED(); 00189 valid = true; 00190 } else if (colorText.equalsIgnoreCase("silver")) { 00191 *this = SILVER(); 00192 valid = true; 00193 } else if (colorText.equalsIgnoreCase("teal")) { 00194 *this = TEAL(); 00195 valid = true; 00196 } else if (colorText.equalsIgnoreCase("yellow")) { 00197 *this = YELLOW(); 00198 valid = true; 00199 } 00200 00201 if (!valid) 00202 throw VRangeException(VSTRING_FORMAT("VColor::setCSSColor '%s' is invalid.", cssColor.chars())); 00203 } 00204 00205 // VColorPair ----------------------------------------------------------------- 00206 00207 VColorPair::VColorPair() 00208 : mBg(VColor::WHITE()) 00209 , mFg(VColor::BLACK()) 00210 { 00211 } 00212 00213 VColorPair::VColorPair(const VColor& bg) 00214 : mBg(bg) 00215 , mFg(VColorPair::generateContrastingForeground(bg)) 00216 { 00217 } 00218 00219 VColorPair::VColorPair(const VColor& bg, const VColor& fg) 00220 : mBg(bg) 00221 , mFg(fg) 00222 { 00223 } 00224 00225 VString VColorPair::getCSSColor() const { 00226 return VSTRING_FORMAT("%s-on-%s", mFg.getCSSColor().chars(), mBg.getCSSColor().chars()); 00227 } 00228 00229 // static 00230 VColor VColorPair::generateContrastingForeground(const VColor& bg) { 00231 return (bg.getLightness() >= 0.5) ? VColor::BLACK() : VColor::WHITE(); 00232 } 00233 00234 // static 00235 VColorPair VColorPair::safeConstructColorPair(const VString& bgCssColor, const VString& fgCssColor) { 00236 VColor bg = VColor::WHITE(); 00237 VColor fg; 00238 bool hasFg = false; 00239 00240 if (bgCssColor.isNotEmpty()) { 00241 try { 00242 bg.setCSSColor(bgCssColor); 00243 } catch (...) {throw;} 00244 } 00245 00246 if (fgCssColor.isNotEmpty()) { 00247 try { 00248 fg.setCSSColor(fgCssColor); 00249 hasFg = true; 00250 } catch (...) {throw;} 00251 } 00252 00253 if (hasFg) { 00254 return VColorPair(bg, fg); 00255 } 00256 00257 return VColorPair(bg); 00258 } 00259 00260 // VColorPalette -------------------------------------------------------------- 00261 00262 VColorPalette::VColorPalette() 00263 : mName() 00264 , mColorMappers() 00265 , mAliases() 00266 { 00267 } 00268 00269 VColorPalette::VColorPalette(const VSettingsNode& paletteNode, VStringVector* errorList) 00270 : mName() 00271 , mColorMappers() 00272 , mAliases() 00273 { 00274 mName = paletteNode.getString("name", mName); 00275 int numMappers = paletteNode.countNamedChildren("color-map"); 00276 00277 if ((numMappers == 0) && (errorList != NULL)) { 00278 errorList->push_back(VSTRING_FORMAT("Color palette '%s' has no color maps.", mName.chars())); 00279 } 00280 00281 for (int i = 0; i < numMappers; ++i) { 00282 const VSettingsNode* mapperNode = paletteNode.getNamedChild("color-map", i); 00283 this->_addMapper(*mapperNode, errorList); 00284 } 00285 } 00286 00287 VColorPalette::~VColorPalette() { 00288 // Remove all alias keys from mColorMappers, so that mapDeleteAllValues doesn't double-delete aliased objects. 00289 for (VStringVector::const_iterator i = mAliases.begin(); i != mAliases.end(); ++i) { 00290 mColorMappers[*i] = NULL; 00291 } 00292 00293 vault::mapDeleteAllValues(mColorMappers); 00294 } 00295 00296 void VColorPalette::adoptColorMapper(const VString& mapperName, VColorMapper* mapper) { 00297 VColorMapper* existingMapper = mColorMappers[mapperName]; 00298 delete existingMapper; 00299 mColorMappers[mapperName] = mapper; 00300 } 00301 00302 const VColorMapper* VColorPalette::findMapper(const VString& mapperName) const { 00303 VColorPaletteMap::const_iterator position = mColorMappers.find(mapperName); 00304 if (position == mColorMappers.end()) { 00305 return NULL; 00306 } 00307 00308 VColorMapper* result = (*position).second; 00309 return result; 00310 } 00311 00312 VColorPair VColorPalette::getColors(const VString& mapperName, const VString& stringValue) const { 00313 const VColorMapper* cm = this->findMapper(mapperName); 00314 if (cm == NULL) { 00315 return VColorPair(); 00316 } 00317 00318 return cm->getColors(stringValue); 00319 } 00320 00321 VColorPair VColorPalette::getColors(const VString& mapperName, int intValue) const { 00322 const VColorMapper* cm = this->findMapper(mapperName); 00323 if (cm == NULL) { 00324 return VColorPair(); 00325 } 00326 00327 return cm->getColors(intValue); 00328 } 00329 00330 VColorPair VColorPalette::getColors(const VString& mapperName, Vs64 int64Value) const { 00331 const VColorMapper* cm = this->findMapper(mapperName); 00332 if (cm == NULL) { 00333 return VColorPair(); 00334 } 00335 00336 return cm->getColors(int64Value); 00337 } 00338 00339 VColorPair VColorPalette::getColors(const VString& mapperName, VDouble doubleValue) const { 00340 const VColorMapper* cm = this->findMapper(mapperName); 00341 if (cm == NULL) { 00342 return VColorPair(); 00343 } 00344 00345 return cm->getColors(doubleValue); 00346 } 00347 00348 void VColorPalette::_addMapper(const VSettingsNode& mapperNode, VStringVector* errorList) { 00349 try { 00350 VString mapperName = mapperNode.getString("name"); 00351 VString mapperType = mapperNode.getString("type", "string-values"); 00352 bool usesPrefixMode = mapperNode.getBoolean("prefix-mode", false); 00353 VColorMapper* mapper = this->_readNewMapper(mapperType, mapperNode, usesPrefixMode, errorList); 00354 00355 if (mapper != NULL) { 00356 // For now, we assume the palette is initialized and never subsequently modified. 00357 // So we don't look for an existing mapper to delete/replace. 00358 mColorMappers[mapperName] = mapper; 00359 00360 this->_addMapperNameAliases(mapper, mapperNode, errorList); 00361 } 00362 } catch (const std::exception& ex) { 00363 if (errorList != NULL) { 00364 errorList->push_back(VSTRING_FORMAT("At %s/%s: %s", mapperNode.getPath().chars(), mapperNode.getString("name", "").chars(), ex.what())); 00365 } 00366 } 00367 } 00368 00369 VColorMapper* VColorPalette::_readNewMapper(const VString& mapperType, const VSettingsNode& mapperNode, bool usesPrefixMode, VStringVector* errorList) { 00370 VColorMapper* mapper = NULL; 00371 if (mapperType == "string-values") { 00372 if (usesPrefixMode) { 00373 mapper = new VStringRangeColorMapper(usesPrefixMode); 00374 } else { 00375 mapper = new VStringColorMapper(); 00376 } 00377 } else if (mapperType == "integer-values") { 00378 mapper = new VIntegerColorMapper(); 00379 } else if (mapperType == "real-values") { 00380 mapper = new VDoubleColorMapper(); 00381 } else if (mapperType == "string-ranges") { 00382 mapper = new VStringRangeColorMapper(usesPrefixMode); 00383 } else if (mapperType == "integer-ranges") { 00384 mapper = new VIntegerRangeColorMapper(); 00385 } else if (mapperType == "real-ranges") { 00386 mapper = new VDoubleRangeColorMapper(); 00387 } else if (errorList != NULL) { 00388 errorList->push_back(VSTRING_FORMAT("At %s/%s: Invalid color-map type '%s'.", mapperNode.getPath().chars(), mapperNode.getString("name", "").chars(), mapperType.chars())); 00389 } 00390 00391 if (mapper != NULL) { 00392 mapper->readColors(mapperNode, errorList); 00393 } 00394 00395 return mapper; 00396 } 00397 00398 void VColorPalette::_addMapperNameAliases(VColorMapper* mapper, const VSettingsNode& mapperNode, VStringVector* errorList) { 00399 bool mapperUsesPrefixMode = mapperNode.getBoolean("prefix-mode", false); 00400 int numAliases = mapperNode.countNamedChildren("alias"); 00401 for (int i = 0; i < numAliases; ++i) { 00402 const VSettingsNode* aliasNode = mapperNode.getNamedChild("alias", i); 00403 VString alias = aliasNode->getString("name", VString::EMPTY()); 00404 if (alias.isNotEmpty()) { 00405 // If the alias uses a different prefix-mode flag than the original mapper, need a separate instance, 00406 // since behavior is totally different. In that case it's not really an "alias" we need to track, it 00407 // is really another independent mapper. 00408 bool aliasUsesPrefixMode = aliasNode->getBoolean("prefix-mode", false); 00409 if (aliasUsesPrefixMode == mapperUsesPrefixMode) { 00410 mAliases.push_back(alias); 00411 } else { 00412 mapper = this->_readNewMapper(mapperNode.getString("type", "string-values"), mapperNode, aliasUsesPrefixMode, errorList); 00413 } 00414 00415 mColorMappers[alias] = mapper; 00416 } 00417 } 00418 } 00419 00420 // VColorMapper --------------------------------------------------------------- 00421 00422 void VColorMapper::readColors(const VSettingsNode& mapperNode, VStringVector* errorList) { 00423 VString defaultBg = mapperNode.getString("default-bg", VString::EMPTY()); 00424 VString defaultFg = mapperNode.getString("default-fg", VString::EMPTY()); 00425 if (defaultBg.isNotEmpty() || defaultFg.isNotEmpty()) { 00426 this->setDefaultColors(VColorPair::safeConstructColorPair(defaultBg, defaultFg)); 00427 } 00428 00429 int numColors = mapperNode.countNamedChildren("color"); 00430 00431 if ((numColors == 0) && (errorList != NULL)) { 00432 errorList->push_back(VSTRING_FORMAT("At %s/%s: No colors defined in color-map.", mapperNode.getPath().chars(), mapperNode.getString("name", "").chars())); 00433 } 00434 00435 for (int i = 0; i < numColors; ++i) { 00436 const VSettingsNode* colorNode = mapperNode.getNamedChild("color", i); 00437 00438 try { 00439 this->_readColorElement(*colorNode); 00440 } catch (const std::exception& ex) { 00441 if (errorList != NULL) { 00442 errorList->push_back(VSTRING_FORMAT("At %s/%s: Error reading color value [%d]: %s", mapperNode.getPath().chars(), mapperNode.getString("name", "").chars(), i, ex.what())); 00443 } 00444 } 00445 } 00446 } 00447 00448 VColorPair VColorMapper::_readColorPair(const VSettingsNode& colorNode) { 00449 VString bg = colorNode.getString("bg", VString::EMPTY()); 00450 VString fg = colorNode.getString("fg", VString::EMPTY()); 00451 return VColorPair::safeConstructColorPair(bg, fg); 00452 } 00453 00454 // VStringColorMapper --------------------------------------------------------- 00455 00456 VStringColorMapper::VStringColorMapper() 00457 : VColorMapper() 00458 , mColorMap() 00459 , mCaseSensitive(false) 00460 { 00461 } 00462 00463 VStringColorMapper::~VStringColorMapper() { 00464 } 00465 00466 void VStringColorMapper::readColors(const VSettingsNode& mapperNode, VStringVector* errorList) { 00467 mCaseSensitive = mapperNode.getBoolean("case-sensitive", mCaseSensitive); 00468 VColorMapper::readColors(mapperNode, errorList); 00469 } 00470 00471 VColorPair VStringColorMapper::getColors(const VString& stringValue) const { 00472 VString key(stringValue); 00473 if (!mCaseSensitive) { 00474 key.toLowerCase(); 00475 } 00476 00477 VStringColorMap::const_iterator position = mColorMap.find(key); 00478 if (position == mColorMap.end()) { 00479 return mDefaultColors; 00480 } 00481 00482 return (*position).second; 00483 } 00484 00485 VColorPair VStringColorMapper::getColors(int intValue) const { 00486 return this->getColors(VSTRING_INT(intValue)); 00487 } 00488 00489 VColorPair VStringColorMapper::getColors(Vs64 int64Value) const { 00490 return this->getColors(VSTRING_S64(int64Value)); 00491 } 00492 00493 VColorPair VStringColorMapper::getColors(VDouble doubleValue) const { 00494 return this->getColors(VSTRING_DOUBLE(doubleValue)); 00495 } 00496 00497 void VStringColorMapper::addColors(const VString& stringValue, const VColorPair& colors) { 00498 VString key(stringValue); 00499 if (!mCaseSensitive) { 00500 key.toLowerCase(); 00501 } 00502 00503 mColorMap[key] = colors; 00504 } 00505 00506 void VStringColorMapper::_readColorElement(const VSettingsNode& colorNode) { 00507 this->addColors(colorNode.getString("value"), this->_readColorPair(colorNode)); 00508 } 00509 00510 // VIntegerColorMapper -------------------------------------------------------- 00511 00512 VIntegerColorMapper::VIntegerColorMapper() 00513 : VColorMapper() 00514 , mColorMap() 00515 { 00516 } 00517 00518 VIntegerColorMapper::~VIntegerColorMapper() { 00519 } 00520 00521 VColorPair VIntegerColorMapper::getColors(const VString& stringValue) const { 00522 try { 00523 Vs64 int64Value = stringValue.parseS64(); 00524 return this->getColors(int64Value); 00525 } catch (...) {} // Will occur if the string is not a parseable integer. 00526 00527 return mDefaultColors; 00528 } 00529 00530 VColorPair VIntegerColorMapper::getColors(int intValue) const { 00531 Vs64 int64Value = intValue; 00532 return this->getColors(int64Value); 00533 } 00534 00535 VColorPair VIntegerColorMapper::getColors(Vs64 int64Value) const { 00536 VIntegerColorMap::const_iterator position = mColorMap.find(int64Value); 00537 if (position == mColorMap.end()) { 00538 return mDefaultColors; 00539 } 00540 00541 return (*position).second; 00542 } 00543 00544 VColorPair VIntegerColorMapper::getColors(VDouble doubleValue) const { 00545 // No perfect way to know what a generic caller expects here; they really should 00546 // be using VDoubleColorMapper or VDoubleRangeColorMapper if they don't like this behavior. 00547 // We choose to truncate double to integer, and use that. 00548 // The effect is that 3, 3.0. 3.1, 3.14, etc. will all have the same output. 00549 00550 Vs64 int64Value = static_cast<Vs64>(doubleValue); 00551 return this->getColors(int64Value); 00552 } 00553 00554 void VIntegerColorMapper::addColors(Vs64 intValue, const VColorPair& colors) { 00555 mColorMap[intValue] = colors; 00556 } 00557 00558 void VIntegerColorMapper::_readColorElement(const VSettingsNode& colorNode) { 00559 this->addColors(colorNode.getS64("value"), this->_readColorPair(colorNode)); 00560 } 00561 00562 // VDoubleColorMapper --------------------------------------------------------- 00563 00564 VDoubleColorMapper::VDoubleColorMapper() 00565 : VColorMapper() 00566 , mColorMap() 00567 { 00568 } 00569 00570 VDoubleColorMapper::~VDoubleColorMapper() { 00571 } 00572 00573 VColorPair VDoubleColorMapper::getColors(const VString& stringValue) const { 00574 try { 00575 VDouble doubleValue = stringValue.parseDouble(); 00576 return this->getColors(doubleValue); 00577 } catch (...) {} // Will occur if the string is not a parseable double. 00578 00579 return mDefaultColors; 00580 } 00581 00582 VColorPair VDoubleColorMapper::getColors(int intValue) const { 00583 VDouble doubleValue = static_cast<VDouble>(intValue); 00584 return this->getColors(doubleValue); 00585 } 00586 00587 VColorPair VDoubleColorMapper::getColors(Vs64 int64Value) const { 00588 VDouble doubleValue = static_cast<VDouble>(int64Value); 00589 return this->getColors(doubleValue); 00590 } 00591 00592 VColorPair VDoubleColorMapper::getColors(VDouble doubleValue) const { 00593 VStringColorMap::const_iterator position = mColorMap.find(VSTRING_DOUBLE(doubleValue)); 00594 if (position == mColorMap.end()) { 00595 return mDefaultColors; 00596 } 00597 00598 return (*position).second; 00599 } 00600 00601 void VDoubleColorMapper::addColors(VDouble doubleValue, const VColorPair& colors) { 00602 mColorMap[VSTRING_DOUBLE(doubleValue)] = colors; 00603 } 00604 00605 void VDoubleColorMapper::_readColorElement(const VSettingsNode& colorNode) { 00606 this->addColors(colorNode.getDouble("value"), this->_readColorPair(colorNode)); 00607 } 00608 00609 // VStringRangeColorMapper -------------------------------------------------------- 00610 00611 VStringRangeColorMapper::VStringRangeColorMapper(bool usesPrefixMode) 00612 : VColorMapper() 00613 , mColorRanges() 00614 , mCaseSensitive(false) 00615 , mUsesPrefixMode(usesPrefixMode) 00616 { 00617 } 00618 00619 VStringRangeColorMapper::~VStringRangeColorMapper() { 00620 } 00621 00622 void VStringRangeColorMapper::readColors(const VSettingsNode& mapperNode, VStringVector* errorList) { 00623 mCaseSensitive = mapperNode.getBoolean("case-sensitive", mCaseSensitive); 00624 VColorMapper::readColors(mapperNode, errorList); 00625 } 00626 00627 VColorPair VStringRangeColorMapper::getColors(const VString& stringValue) const { 00628 if (mColorRanges.empty()) 00629 return mDefaultColors; 00630 00631 VString caseAdjustedValue(stringValue); 00632 if (!mCaseSensitive) 00633 caseAdjustedValue.toLowerCase(); 00634 00635 // lower_bound() uses binary search, should be the fastest way. 00636 VStringRangeColorElement testValue(caseAdjustedValue, VColorPair()); 00637 VStringRangeVector::const_iterator position = std::lower_bound(mColorRanges.begin(), mColorRanges.end(), testValue); 00638 00639 // The way this works, we have to essentially decrement the position to find the spot that was "hit", 00640 // unless we got an exact match. To do this, we check if the found mRangeMin is greater than the value. 00641 if (position == mColorRanges.end()) 00642 return this->_getColorsWithPrefixModeCheck((*(position - 1)).mColors); 00643 00644 if (position == mColorRanges.begin() && position->mRangeMin > caseAdjustedValue) 00645 return mDefaultColors; 00646 00647 if (position->mRangeMin > caseAdjustedValue) 00648 --position; 00649 00650 return this->_getColorsWithPrefixModeCheck((*position).mColors); 00651 } 00652 00653 static const VColorPair EMPTY_MAP_COLOR_VALUE(VColor(1, 1, 1), VColor(2, 2, 2)); 00654 00655 VColorPair VStringRangeColorMapper::_getColorsWithPrefixModeCheck(const VColorPair& foundColors) const { 00656 if (mUsesPrefixMode && (foundColors == EMPTY_MAP_COLOR_VALUE)) 00657 return mDefaultColors; 00658 00659 return foundColors; 00660 } 00661 00662 VColorPair VStringRangeColorMapper::getColors(int intValue) const { 00663 return this->getColors(VSTRING_INT(intValue)); 00664 } 00665 00666 VColorPair VStringRangeColorMapper::getColors(Vs64 int64Value) const { 00667 return this->getColors(VSTRING_S64(int64Value)); 00668 } 00669 00670 VColorPair VStringRangeColorMapper::getColors(VDouble doubleValue) const { 00671 return this->getColors(VSTRING_DOUBLE(doubleValue)); 00672 } 00673 00674 void VStringRangeColorMapper::addColors(const VString& rangeMin, const VColorPair& rangeColors) { 00675 VString caseAdjustedValue(rangeMin); 00676 if (!mCaseSensitive) { 00677 caseAdjustedValue.toLowerCase(); 00678 } 00679 00680 VStringRangeColorElement rangeElement(caseAdjustedValue, rangeColors); 00681 VStringRangeVector::iterator position = std::lower_bound(mColorRanges.begin(), mColorRanges.end(), rangeElement); 00682 (void) mColorRanges.insert(position, rangeElement); 00683 00684 if (mUsesPrefixMode) { 00685 VStringRangeColorElement rangeEndingElement(caseAdjustedValue + "~", EMPTY_MAP_COLOR_VALUE); 00686 VStringRangeVector::iterator nextPosition = std::lower_bound(mColorRanges.begin(), mColorRanges.end(), rangeEndingElement); 00687 (void) mColorRanges.insert(nextPosition, rangeEndingElement); 00688 } 00689 } 00690 00691 void VStringRangeColorMapper::_readColorElement(const VSettingsNode& colorNode) { 00692 this->addColors(colorNode.getString("value"), this->_readColorPair(colorNode)); 00693 } 00694 00695 // VIntegerRangeColorMapper -------------------------------------------------------- 00696 00697 VIntegerRangeColorMapper::VIntegerRangeColorMapper() 00698 : VColorMapper() 00699 , mColorRanges() 00700 { 00701 } 00702 00703 VIntegerRangeColorMapper::~VIntegerRangeColorMapper() { 00704 } 00705 00706 VColorPair VIntegerRangeColorMapper::getColors(const VString& stringValue) const { 00707 try { 00708 Vs64 int64Value = stringValue.parseS64(); 00709 return this->getColors(int64Value); 00710 } catch (...) {} // Will occur if the string is not a parseable integer. 00711 00712 return mDefaultColors; 00713 } 00714 00715 VColorPair VIntegerRangeColorMapper::getColors(int intValue) const { 00716 Vs64 int64Value = intValue; 00717 return this->getColors(int64Value); 00718 } 00719 00720 VColorPair VIntegerRangeColorMapper::getColors(Vs64 int64Value) const { 00721 if (mColorRanges.empty()) 00722 return mDefaultColors; 00723 00724 // lower_bound() uses binary search, should be the fastest way. 00725 VIntegerRangeColorElement testValue(int64Value, VColorPair()); 00726 VIntegerRangeVector::const_iterator position = std::lower_bound(mColorRanges.begin(), mColorRanges.end(), testValue); 00727 00728 // The way this works, we have to essentially decrement the position to find the spot that was "hit", 00729 // unless we got an exact match. To do this, we check if the found mRangeMin is greater than the value. 00730 if (position == mColorRanges.end()) 00731 return (position - 1)->mColors; 00732 00733 if (position == mColorRanges.begin() && position->mRangeMin > int64Value) 00734 return mDefaultColors; 00735 00736 if (position->mRangeMin > int64Value) 00737 --position; 00738 00739 return position->mColors; 00740 } 00741 00742 VColorPair VIntegerRangeColorMapper::getColors(VDouble doubleValue) const { 00743 Vs64 int64Value = static_cast<Vs64>(doubleValue); 00744 return this->getColors(int64Value); 00745 } 00746 00747 void VIntegerRangeColorMapper::addColors(Vs64 rangeMin, const VColorPair& rangeColors) { 00748 VIntegerRangeColorElement rangeElement(rangeMin, rangeColors); 00749 VIntegerRangeVector::iterator position = std::lower_bound(mColorRanges.begin(), mColorRanges.end(), rangeElement); 00750 (void) mColorRanges.insert(position, rangeElement); 00751 } 00752 00753 void VIntegerRangeColorMapper::_readColorElement(const VSettingsNode& colorNode) { 00754 this->addColors(colorNode.getInt("value"), this->_readColorPair(colorNode)); 00755 } 00756 00757 // VDoubleRangeColorMapper -------------------------------------------------------- 00758 00759 VDoubleRangeColorMapper::VDoubleRangeColorMapper() 00760 : VColorMapper() 00761 , mColorRanges() 00762 { 00763 } 00764 00765 VDoubleRangeColorMapper::~VDoubleRangeColorMapper() { 00766 } 00767 00768 VColorPair VDoubleRangeColorMapper::getColors(const VString& stringValue) const { 00769 try { 00770 VDouble doubleValue = stringValue.parseDouble(); 00771 return this->getColors(doubleValue); 00772 } catch (...) {} // Will occur if the string is not a parseable integer. 00773 00774 return mDefaultColors; 00775 } 00776 00777 VColorPair VDoubleRangeColorMapper::getColors(int intValue) const { 00778 VDouble doubleValue = static_cast<VDouble>(intValue); 00779 return this->getColors(doubleValue); 00780 } 00781 00782 VColorPair VDoubleRangeColorMapper::getColors(Vs64 int64Value) const { 00783 VDouble doubleValue = static_cast<VDouble>(int64Value); 00784 return this->getColors(doubleValue); 00785 } 00786 00787 VColorPair VDoubleRangeColorMapper::getColors(VDouble doubleValue) const { 00788 if (mColorRanges.empty()) 00789 return mDefaultColors; 00790 00791 // lower_bound() uses binary search, should be the fastest way. 00792 VDoubleRangeColorElement testValue(doubleValue, VColorPair()); 00793 VDoubleRangeVector::const_iterator position = std::lower_bound(mColorRanges.begin(), mColorRanges.end(), testValue); 00794 00795 // The way this works, we have to essentially decrement the position to find the spot that was "hit", 00796 // unless we got an exact match. To do this, we check if the found mRangeMin is greater than the value. 00797 if (position == mColorRanges.end()) 00798 return (position - 1)->mColors; 00799 00800 if (position == mColorRanges.begin() && position->mRangeMin > doubleValue) 00801 return mDefaultColors; 00802 00803 if (position->mRangeMin > doubleValue) 00804 --position; 00805 00806 return position->mColors; 00807 } 00808 00809 void VDoubleRangeColorMapper::addColors(VDouble rangeMin, const VColorPair& rangeColors) { 00810 VDoubleRangeColorElement rangeElement(rangeMin, rangeColors); 00811 VDoubleRangeVector::iterator position = std::lower_bound(mColorRanges.begin(), mColorRanges.end(), rangeElement); 00812 (void) mColorRanges.insert(position, rangeElement); 00813 } 00814 00815 void VDoubleRangeColorMapper::_readColorElement(const VSettingsNode& colorNode) { 00816 this->addColors(colorNode.getDouble("value"), this->_readColorPair(colorNode)); 00817 }