// Return ColourScalePoint corresponding to label under mouse (if any) ColourScalePoint* TColourScaleEditor::labelUnderMouse(QPoint pos) { // Get the size of the textrect we need QRect masterTextRect = style()->itemTextRect(fontMetrics(), QRect(), Qt::AlignRight | Qt::AlignVCenter, true, QString::number(-0.123456, 'e', 6)); int margin = masterTextRect.height()*0.5; masterTextRect.setLeft(margin); masterTextRect.setRight(width() - gradientBarWidth_ - 3*margin - handleRadius_*2); // Draw text and line elements if (colourScale_.nPoints() > 0) { double zero = colourScale_.firstPoint()->value(); double span = colourScale_.lastPoint()->value() - zero; for (ColourScalePoint* csp = colourScale_.firstPoint(); csp != NULL; csp = csp->next) { int y = (1.0 - (csp->value() - zero) / span) * (height() - 2*margin) + margin; QString numberText = QString::number(csp->value(), 'e', 6); masterTextRect.moveBottom(y + 0.5*masterTextRect.height()); QRect textRect = style()->itemTextRect(fontMetrics(), masterTextRect, Qt::AlignRight | Qt::AlignVCenter, true, numberText); if (textRect.contains(pos)) return csp; } } return NULL; }
// Get colour associated with value supplied (as Vec4<GLfloat>) void ColourScale::colour(double value, Vec4<GLfloat>& target) const { // Step through points associated to scale and find the two that we are inbetween. // Check for no points being defined if (points_.nItems() == 0) { target.x = 0.0; target.y = 0.0; target.z = 0.0; target.w = 1.0; return; } ColourScalePoint* csp = points_.first(); // Is supplied value less than the value at the first point? if (value < csp->value()) { csp->colour(target); return; } // Find the correct delta to use for (ColourScaleDelta* delta = deltas_.first(); delta != NULL; delta = delta->next) { if (delta->containsValue(value)) { delta->colour(interpolated_ ? value : delta->start(), useHSV_, target); return; } } // If we get to here then the supplied value is outside the range of all values, so take colour from the endpoint //printf("OUTSIDE RANGE\n"); points_.last()->colour(target); }
// Add point to scale ColourScalePoint* ColourScale::addPoint(double value, QColor colour) { ColourScalePoint* csp = NULL; // If supplied value is less than that at the start of the list, add it at the beginning. // If larget than the one at the end, then append it to the end of the list. // If neither of these, find the first existing value which is larger, and add it before that one if (points_.nItems() == 0) csp = points_.add(); else if (value > points_.last()->value()) csp = points_.add(); else for (ColourScalePoint* oldPoint = points_.first(); oldPoint != NULL; oldPoint = oldPoint->next) if (oldPoint->value() > value) { csp = points_.insertBefore(oldPoint); break; } if (csp == NULL) return NULL; // Now, set data in new point csp->setColour(colour); csp->setValue(value); // Recalculate colour deltas calculateDeltas(); return csp; }
// Return colour associated with value provided void ColourScale::colour(double v, GLfloat* target) { // Step through points associated to scale and find the two that we are inbetween. // Check for no points being defined if (points_.nItems() == 0) { target[0] = (GLfloat) 0.0; target[1] = (GLfloat) 0.0; target[2] = (GLfloat) 0.0; target[3] = (GLfloat) 0.0; return; } ColourScalePoint* csp = points_.first(); // Is supplied value less than the value at the first point? if (v < csp->value()) { csp->copyColour(target); return; } // Find the correct delta to use for (ColourScaleDelta* delta = deltas_.first(); delta != NULL; delta = delta->next) { if (delta->containsValue(v)) { delta->colour( interpolated_ ? v : delta->start(), target); return; } } // If we get to here then the supplied value is outside the range of all values, so take colour from the endpoint points_.last()->copyColour(target); }
// Paint event callback void TColourScaleEditor::paintEvent(QPaintEvent *event) { QPainter painter(this); // Get the size of the textrect we need QRect masterTextRect = style()->itemTextRect(fontMetrics(), QRect(), Qt::AlignRight | Qt::AlignVCenter, true, QString::number(-0.123456, 'e', 6)); int margin = masterTextRect.height()*0.5; masterTextRect.setLeft(margin); masterTextRect.setRight(width() - gradientBarWidth_ - 3*margin - handleRadius_*2); // Set up the basic handle style option QStyleOption handleOption; handleOption.rect.setRight(width()-margin); handleOption.rect.setLeft(width()-margin-handleRadius_*2); handleOption.rect.setHeight(masterTextRect.height()); // Draw gradient bar QBrush brush(gradient_); QPen pen(Qt::black); QRect gradientRect; gradientRect.setHeight(height()-2*margin); gradientRect.setWidth(gradientBarWidth_); gradientRect.moveTop(margin); gradientRect.moveRight(width() - 2*margin - handleRadius_*2); painter.setBrush(brush); painter.setPen(pen); painter.drawRect(gradientRect); // Define regions gradientBarRegion_ = QRegion(gradientRect); // -- Handle and label region spans top to bottom of the widget (i.e. excluding margins) handleRegion_ = QRegion(QRect(width() - margin - 2*handleRadius_, 0, 2*handleRadius_, height())); labelRegion_ = QRegion(QRect(0, 0, width() - gradientRect.right() - margin, height())); // Draw text and line elements if (colourScale_.nPoints() > 0) { double zero = colourScale_.firstPoint()->value(); double span = colourScale_.lastPoint()->value() - zero; for (ColourScalePoint* csp = colourScale_.firstPoint(); csp != NULL; csp = csp->next) { int y = (1.0 - (csp->value() - zero) / span) * (height() - 2*margin) + margin; QString numberText = QString::number(csp->value(), 'e', 6); masterTextRect.moveBottom(y + 0.5*masterTextRect.height()); painter.setPen(palette().text().color()); style()->drawItemText(&painter, masterTextRect, Qt::AlignRight | Qt::AlignVCenter, palette(), true, numberText); painter.drawLine(gradientRect.left()-margin, y, gradientRect.right()+margin, y); // Draw handle for this point handleOption.rect.moveBottom(y + 0.5*masterTextRect.height()); if (csp == currentColourScalePoint_) handleOption.state = QStyle::State_Enabled; else if (csp == hoverColourScalePoint_) handleOption.state = QStyle::State_MouseOver; else handleOption.state = 0; drawHandle(handleOption, painter); } } painter.end(); }
void TColourScaleEditor::contextMenuRequested(const QPoint& point) { // Get handle at clicked point ColourScalePoint* clickedPoint = handleUnderMouse(point); if (!clickedPoint) return; // Build the context menu to display QMenu contextMenu; QAction* valueAction = contextMenu.addAction("&Set value..."); QAction* deleteAction = contextMenu.addAction("&Delete"); QAction* spaceAction = contextMenu.addAction("&Set to midpoint"); if ((!clickedPoint->prev) || (!clickedPoint->next)) spaceAction->setEnabled(false); // Show it QPoint menuPosition = mapToGlobal(point); QAction* menuResult = contextMenu.exec(menuPosition); // What was clicked? if (menuResult == valueAction) { bool ok; double newValue = QInputDialog::getDouble(this, "Set point value", "New value: ", clickedPoint->value(), -1.0e7, 1.0e7, 6, &ok); if (ok) { colourScale_.setValue(clickedPoint, newValue); updateGradient(); repaint(); emit(colourScaleChanged()); } } else if (menuResult == deleteAction) { colourScale_.removePoint(clickedPoint); updateGradient(); repaint(); emit(colourScaleChanged()); } else if (menuResult == spaceAction) { // Get average values of next and previous points double averageValue = (clickedPoint->next->value() + clickedPoint->prev->value()) * 0.5; colourScale_.setValue(clickedPoint, averageValue); updateGradient(); repaint(); emit(colourScaleChanged()); } }
// Set all alpha values to that specified void ColourScale::setAllAlpha(double alpha) { QColor color; for (ColourScalePoint* csp = points_.first(); csp != NULL; csp = csp->next) { color = csp->colour(); int alphai = alpha*255; if (alphai < 0) alphai = 0; else if (alphai > 255) alphai = 255; color.setAlpha(alphai); csp->setColour(color); } calculateDeltas(); }
// Assignment operator void ColourScale::operator=(const ColourScale& source) { clear(); useHSV_ = source.useHSV_; for (ColourScalePoint* csp = source.points_.first(); csp != NULL; csp = csp->next) addPoint( csp->value(), csp->colour() ); interpolated_ = source.interpolated_; }
// Return colour associated with value provided QColor ColourScale::colour(double value) const { // Step through points associated to scale and find the two that we are inbetween. // Check for no points being defined if (points_.nItems() == 0) return QColor(0,0,0); ColourScalePoint* csp = points_.first(); // Is supplied value less than the value at the first point? if (value < csp->value()) return csp->colour(); // Find the correct delta to use for (ColourScaleDelta* delta = deltas_.first(); delta != NULL; delta = delta->next) { if (delta->containsValue(value)) return delta->colour(interpolated_ ? value : delta->start(), useHSV_); } // If we get to here then the supplied value is outside the range of all values, so take colour from the endpoint return points_.last()->colour(); }
// Set colour and value data for point void ColourScale::setPoint(int position, double value, QColor colour, bool setval, bool setcol) { // Check position supplied if ((position < 0) || (position >= points_.nItems())) { printf("Scale point position to set (%i) is invalid - nItems = %i.\n", position, points_.nItems()); return; } if (setcol) points_[position]->setColour(colour); if (setval) { points_[position]->setValue(value); // Position in list may have changed - check... bool minBad = true, maxBad = true; ColourScalePoint* csp = points_[position]; int dummy = 0; do { // printf("BEFORE SHIFT Prev = %f, current= %f, next = %f\n", csp->prev ? csp->prev->value() : -999, csp->value(), csp->next ? csp->next->value() : -999); // Shift item if necessary if (csp->prev && (csp->prev->value() > csp->value())) { points_.shiftUp(csp); minBad = (csp->prev ? (csp->prev->value() > csp->value()) : false); } else minBad = false; if (csp->next && (csp->next->value() < csp->value())) { points_.shiftDown(csp); maxBad = (csp->next ? (csp->next->value() < csp->value()) : false); } else maxBad = false; // printf("AFTER SHIFT %i Prev = %f, current= %f, next = %f B=%i %i\n", dummy, csp->prev ? csp->prev->value() : -999, csp->value(), csp->next ? csp->next->value() : -999, minBad, maxBad); if (++dummy == 10) break; } while (minBad || maxBad); } // Recalculate colour deltas calculateDeltas(); }
// Return ColourScalePoint corresponding to handle under mouse (if any) ColourScalePoint* TColourScaleEditor::handleUnderMouse(QPoint pos) { // Did we hit a handle? if (colourScale_.nPoints() > 0) { // Check x delta first if (abs(lastPos_.x() - handleRegion_.boundingRect().center().x()) > handleRadius_) return NULL; // Check distance from centre of handles... double zero = colourScale_.firstPoint()->value(); double span = colourScale_.lastPoint()->value() - zero; for (ColourScalePoint* csp = colourScale_.firstPoint(); csp != NULL; csp = csp->next) { // Work out fractional position of colourscale value and get centre coordinates of handle double fracy = (1.0 - (csp->value() - zero) / span); int y = fracy * gradientBarRegion_.boundingRect().height() + gradientBarRegion_.boundingRect().top(); if (abs(y - pos.y()) <= handleRadius_) return csp; } } return NULL; }
// Update QGradient for display void TColourScaleEditor::updateGradient() { // Setup QGradient - in ObjectBoundingMode, 0.0 = top of rectangle, and 1.0 is bottom gradient_ = QLinearGradient(0.0, 1.0, 0.0, 0.0); gradient_.setCoordinateMode(QGradient::ObjectBoundingMode); // Add points if (colourScale_.nPoints() == 0) { gradient_.setColorAt(0.0, QColor(0,0,0)); gradient_.setColorAt(1.0, QColor(0,0,0)); } else if (colourScale_.nPoints() == 1) { gradient_.setColorAt(0.0, colourScale_.firstPoint()->colourAsQColor()); gradient_.setColorAt(1.0, colourScale_.firstPoint()->colourAsQColor()); } else { double zero = colourScale_.firstPoint()->value(); double span = colourScale_.lastPoint()->value() - zero; for (ColourScalePoint* csp = colourScale_.firstPoint(); csp != NULL; csp = csp->next) gradient_.setColorAt((csp->value() - zero) / span, csp->colourAsQColor()); } }
// Add point to scale ColourScalePoint* ColourScale::addPoint(double value, double r, double g, double b, double a) { Messenger::enter("ColourScale::addPoint"); // Find position to insert new point at ColourScalePoint* newPoint = NULL; if (points_.nItems() == 0) newPoint = points_.add(); else if (value < points_.first()->value()) newPoint = points_.prepend(); else if (value > points_.last()->value()) newPoint = points_.add(); else { for (ColourScalePoint* point = points_.first()->next; point != NULL; point = point->next) { if (value < point->value()) { newPoint = points_.insertBefore(point); break; } } } // Double-check we have a new point if (!newPoint) { printf("Internal Error: ColourScale::addPoint() failed to add a point.\n"); return NULL; } // Now, set data in new point newPoint->setParent(this); newPoint->setColour(r, g, b, a); newPoint->setValue(value); // Recalculate colour deltas calculateDeltas(); // Refresh linked objects refreshObjects(); Messenger::exit("ColourScale::addPoint"); return newPoint; }
// Write CollectionBlock keywords bool UChromaSession::writeCollectionBlock(LineParser& parser, Collection* collection, Collection::CollectionType type, int indentLevel) { // Construct indent string char* indent = new char[indentLevel*2+1]; for (int n=0; n<indentLevel*2; ++n) indent[n] = ' '; indent[indentLevel*2] = '\0'; if (type == Collection::MasterCollection) parser.writeLineF("%s%s '%s'\n", indent, UChromaSession::inputBlock(UChromaSession::CollectionBlock), qPrintable(collection->name())); else if (type == Collection::FitCollection) parser.writeLineF("%s%s '%s'\n", indent, UChromaSession::collectionKeyword(UChromaSession::FitBlockKeyword), qPrintable(collection->name())); else if (type == Collection::ExtractedCollection) parser.writeLineF("%s%s '%s'\n", indent, UChromaSession::collectionKeyword(UChromaSession::SliceBlockKeyword), qPrintable(collection->name())); parser.writeLineF("%s %s \"%s\"\n", indent, UChromaSession::collectionKeyword(UChromaSession::DataDirectoryKeyword), qPrintable(collection->dataFileDirectory().absolutePath())); // -- Transforms parser.writeLineF("%s %s %s %s\n", indent, UChromaSession::collectionKeyword(UChromaSession::TransformXKeyword), stringBool(collection->transformEnabled(0)), qPrintable(collection->transformEquation(0))); parser.writeLineF("%s %s %s %s\n", indent, UChromaSession::collectionKeyword(UChromaSession::TransformYKeyword), stringBool(collection->transformEnabled(1)), qPrintable(collection->transformEquation(1))); parser.writeLineF("%s %s %s %s\n", indent, UChromaSession::collectionKeyword(UChromaSession::TransformZKeyword), stringBool(collection->transformEnabled(2)), qPrintable(collection->transformEquation(2))); // -- Interpolation parser.writeLineF("%s %s %s %s\n", indent, UChromaSession::collectionKeyword(UChromaSession::InterpolateKeyword), stringBool(collection->interpolate(0)), stringBool(collection->interpolate(2))); parser.writeLineF("%s %s %s %s\n", indent, UChromaSession::collectionKeyword(UChromaSession::InterpolateConstrainKeyword), stringBool(collection->interpolateConstrained(0)), stringBool(collection->interpolateConstrained(2))); parser.writeLineF("%s %s %f %f\n", indent, UChromaSession::collectionKeyword(UChromaSession::InterpolateStepKeyword), collection->interpolationStep(0), collection->interpolationStep(2)); // Colour Setup parser.writeLineF("%s %s '%s'\n", indent, UChromaSession::collectionKeyword(UChromaSession::ColourSourceKeyword), Collection::colourSource(collection->colourSource())); ColourScalePoint* csp; QColor colour; double value; // -- Single Colour colour = collection->colourScalePointColour(Collection::SingleColourSource); parser.writeLineF("%s %s %i %i %i %i\n", indent, UChromaSession::collectionKeyword(UChromaSession::ColourSingleKeyword), colour.red(), colour.green(), colour.blue(), colour.alpha()); // -- RGB Gradient colour = collection->colourScalePointColour(Collection::RGBGradientSource, 0); value = collection->colourScalePointValue(Collection::RGBGradientSource, 0); parser.writeLineF("%s %s %f %i %i %i %i\n", indent, UChromaSession::collectionKeyword(UChromaSession::ColourRGBGradientAKeyword), value, colour.red(), colour.green(), colour.blue(), colour.alpha()); colour = collection->colourScalePointColour(Collection::RGBGradientSource, 1); value = collection->colourScalePointValue(Collection::RGBGradientSource, 1); parser.writeLineF("%s %s %f %i %i %i %i\n", indent, UChromaSession::collectionKeyword(UChromaSession::ColourRGBGradientBKeyword), value, colour.red(), colour.green(), colour.blue(), colour.alpha()); // -- HSV Gradient colour = collection->colourScalePointColour(Collection::HSVGradientSource, 0); value = collection->colourScalePointValue(Collection::HSVGradientSource, 0); parser.writeLineF("%s %s %f %i %i %i %i\n", indent, UChromaSession::collectionKeyword(UChromaSession::ColourHSVGradientAKeyword), value, colour.hue(), colour.saturation(), colour.value(), colour.alpha()); colour = collection->colourScalePointColour(Collection::HSVGradientSource, 1); value = collection->colourScalePointValue(Collection::HSVGradientSource, 1); parser.writeLineF("%s %s %f %i %i %i %i\n", indent, UChromaSession::collectionKeyword(UChromaSession::ColourHSVGradientBKeyword), value, colour.hue(), colour.saturation(), colour.value(), colour.alpha()); // -- Custom Gradient for (csp = collection->customColourScalePoints(); csp != NULL; csp = csp->next) { parser.writeLineF("%s %s %f %i %i %i %i\n", indent, UChromaSession::collectionKeyword(UChromaSession::ColourCustomGradientKeyword), csp->value(), csp->colour().red(), csp->colour().green(), csp->colour().blue(), csp->colour().alpha()); } // -- Alpha control parser.writeLineF("%s %s '%s'\n", indent, UChromaSession::collectionKeyword(UChromaSession::ColourAlphaControlKeyword), Collection::alphaControl(collection->alphaControl())); parser.writeLineF("%s %s %f\n", indent, UChromaSession::collectionKeyword(UChromaSession::ColourAlphaFixedKeyword), collection->fixedAlpha()); // Display parser.writeLineF("%s %s %f '%s'\n", indent, UChromaSession::collectionKeyword(UChromaSession::LineStyleKeyword), collection->displayLineStyle().width(), LineStipple::stipple[collection->displayLineStyle().stipple()].name); parser.writeLineF("%s %s %f\n", indent, UChromaSession::collectionKeyword(UChromaSession::ShininessKeyword), collection->displaySurfaceShininess()); parser.writeLineF("%s %s %s\n", indent, UChromaSession::collectionKeyword(UChromaSession::StyleKeyword), Collection::displayStyle(collection->displayStyle())); parser.writeLineF("%s %s %s\n", indent, UChromaSession::collectionKeyword(UChromaSession::VisibleCollectionKeyword), stringBool(collection->visible())); // Loop over datasets for (DataSet* dataSet = collection->dataSets(); dataSet != NULL; dataSet = dataSet->next) writeDataSetBlock(parser, dataSet, indentLevel); // Write FitKernel data if present if (collection->fitKernel()) writeFitParametersBlock(parser, collection->fitKernel(), indentLevel); // Additional data // -- Fits for (Collection* fit = collection->fits(); fit != NULL; fit = fit->next) writeCollectionBlock(parser, fit, Collection::FitCollection, indentLevel+1); // -- Extracted Data for (Collection* extract = collection->slices(); extract != NULL; extract = extract->next) writeCollectionBlock(parser, extract, Collection::ExtractedCollection, indentLevel+1); parser.writeLineF("%s%s\n", indent, UChromaSession::collectionKeyword(UChromaSession::EndCollectionKeyword)); return true; }