From 2bd2f4cce24f8e3e0f7b100217ea6d745e19901a Mon Sep 17 00:00:00 2001 From: Hombre Date: Sun, 26 Jan 2014 13:46:37 +0100 Subject: [PATCH] Various bugfix: - pipette buttons are now mutually exclusive - pipette from L curve (Lab tool) now works properly - pipette from B curve (RGB tool) now works properly - curve that doesn't handle the pipette mechanism hides the pipette button - RGB components of the Tone Curves' pipette now displayed in red, green & blue - the vertical line where the point will be inserted is displayed in grey and has a line's width of 2 pixels --- rtengine/improcfun.cc | 8 +- rtgui/curveeditorgroup.cc | 8 +- rtgui/diagonalcurveeditorsubgroup.cc | 6 ++ rtgui/edit.cc | 126 +++++++++++++++++++++++++++ rtgui/edit.h | 31 ++++++- rtgui/editid.h | 2 +- rtgui/flatcurveeditorsubgroup.cc | 6 +- rtgui/imagearea.cc | 9 ++ rtgui/imagearea.h | 1 + rtgui/mydiagonalcurve.cc | 22 +++-- rtgui/myflatcurve.cc | 16 +++- rtgui/rgbcurves.cc | 2 +- 12 files changed, 220 insertions(+), 17 deletions(-) diff --git a/rtengine/improcfun.cc b/rtengine/improcfun.cc index 7a7c2b2c6..f1379b453 100644 --- a/rtengine/improcfun.cc +++ b/rtengine/improcfun.cc @@ -3226,7 +3226,12 @@ void ImProcFunctions::chromiLuminanceCurve (EditBuffer *editBuffer, int pW, LabI float Lin=lold->L[i][j]; float Lprov2=Lin/327.68f; + + if (editID == EUID_Lab_LCurve) + editWhatever->v(i,j) = LIM01(Lin/32768.0f); + lnew->L[i][j] = curve[Lin]; + float Lprov1=(lnew->L[i][j])/327.68f; float chromaChfactor=1.0f; float atmp = acurve[lold->a[i][j]+32768.0f]-32768.0f;// curves Lab a @@ -3292,9 +3297,6 @@ void ImProcFunctions::chromiLuminanceCurve (EditBuffer *editBuffer, int pW, LabI btmp=327.68f*Chprov2*sincosval.x; } - if (editID == EUID_Lab_LCurve) - editWhatever->v(i,j) = LIM01(Lprov1/100.f); - // calculate C=f(H) if (chutili) { double hr = Color::huelab_to_huehsv2(HH); diff --git a/rtgui/curveeditorgroup.cc b/rtgui/curveeditorgroup.cc index 3e56f8b58..6e006141a 100644 --- a/rtgui/curveeditorgroup.cc +++ b/rtgui/curveeditorgroup.cc @@ -200,6 +200,12 @@ void CurveEditorGroup::typeSelectionChanged (CurveEditor* ce, int n) { void CurveEditorGroup::curveTypeToggled(CurveEditor* ce) { bool curveRestored = false; + if (displayedCurve) { + EditDataProvider* editProvider = displayedCurve->getEditProvider(); + if (editProvider && editProvider->getCurrSubscriber() == displayedCurve) + displayedCurve->switchOffEditMode(); + } + // Looking for the button state if (ce->curveType->get_active()) { // The button is now pressed, so we have to first hide all other CurveEditor @@ -328,7 +334,7 @@ CurveEditorSubGroup::~CurveEditorSubGroup() { } void CurveEditorSubGroup::updateEditButton(CurveEditor* curve, Gtk::ToggleButton *button, sigc::connection &connection) { - if (curve->getEditID() == EUID_None) { + if (!curve->getEditProvider() || curve->getEditID() == EUID_None) { button->hide(); } else { diff --git a/rtgui/diagonalcurveeditorsubgroup.cc b/rtgui/diagonalcurveeditorsubgroup.cc index a2c1bc99f..697882970 100644 --- a/rtgui/diagonalcurveeditorsubgroup.cc +++ b/rtgui/diagonalcurveeditorsubgroup.cc @@ -255,12 +255,18 @@ void DiagonalCurveEditorSubGroup::editModeSwitchedOff () { bool prevState; prevState = editCustomConn.block(true); editCustom->set_active(false); + customCurve->pipetteMouseOver(NULL, 0); + customCurve->setDirty(true); if (!prevState) editCustomConn.block(false); prevState = editNURBSConn.block(true); editNURBS->set_active(false); + NURBSCurve->pipetteMouseOver(NULL, 0); + NURBSCurve->setDirty(true); if (!prevState) editNURBSConn.block(false); prevState = editParamConn.block(true); editParam->set_active(false); + paramCurve->pipetteMouseOver(NULL, 0); + paramCurve->setDirty(true); if (!prevState) editParamConn.block(false); } diff --git a/rtgui/edit.cc b/rtgui/edit.cc index 2cfe321d4..e4b6b32f0 100644 --- a/rtgui/edit.cc +++ b/rtgui/edit.cc @@ -354,6 +354,129 @@ void Polyline::drawToMOChannel (Cairo::RefPtr &cr, Cairo::RefPtr } } +void Rectangle::setXYWH(int left, int top, int width, int height) { + topLeft.set(left, top); + bottomRight.set(left+width, top+height); +} + +void Rectangle::setXYXY(int left, int top, int right, int bottom) { + topLeft.set(left, top); + bottomRight.set(right, bottom); +} + +void Rectangle::setXYWH(Coord topLeft, Coord widthHeight) { + this->topLeft = topLeft; + this->bottomRight = topLeft + widthHeight; +} + +void Rectangle::setXYXY(Coord topLeft, Coord bottomRight) { + this->topLeft = topLeft; + this->bottomRight = bottomRight; +} + +void Rectangle::drawOuterGeometry (Cairo::RefPtr &cr, rtengine::EditBuffer *editBuffer, EditCoordSystem &coordSystem) { + if ((flags & ACTIVE)) { + cr->set_source_rgb (outerLineColor.getR(), outerLineColor.getG(), outerLineColor.getB()); + + Coord tl, br; + cr->set_line_width( getOuterLineWidth() ); + + if (datum == IMAGE) coordSystem.imageCoordToScreen(topLeft.x, topLeft.y, tl.x, tl.y); + else if (datum == CLICKED_POINT) tl = topLeft + editBuffer->getDataProvider()->posScreen; + else if (datum == CURSOR) tl = topLeft +editBuffer->getDataProvider()->posScreen + editBuffer->getDataProvider()->deltaPrevScreen; + + if (datum == IMAGE) coordSystem.imageCoordToScreen(bottomRight.x, bottomRight.y, br.x, br.y); + else if (datum == CLICKED_POINT) br = bottomRight + editBuffer->getDataProvider()->posScreen; + else if (datum == CURSOR) br = bottomRight +editBuffer->getDataProvider()->posScreen + editBuffer->getDataProvider()->deltaPrevScreen; + + cr->rectangle(tl.x, tl.y, br.x-tl.x, br.y-tl.y); + + if (filled) { + cr->fill_preserve(); + cr->stroke(); + } + else + cr->fill(); + } +} + +void Rectangle::drawInnerGeometry (Cairo::RefPtr &cr, rtengine::EditBuffer *editBuffer, EditCoordSystem &coordSystem) { + if (flags & ACTIVE) { + Coord tl, br; + if (datum == IMAGE) coordSystem.imageCoordToScreen(topLeft.x, topLeft.y, tl.x, tl.y); + else if (datum == CLICKED_POINT) tl = topLeft + editBuffer->getDataProvider()->posScreen; + else if (datum == CURSOR) tl = topLeft +editBuffer->getDataProvider()->posScreen + editBuffer->getDataProvider()->deltaPrevScreen; + + if (datum == IMAGE) coordSystem.imageCoordToScreen(bottomRight.x, bottomRight.y, br.x, br.y); + else if (datum == CLICKED_POINT) br = bottomRight + editBuffer->getDataProvider()->posScreen; + else if (datum == CURSOR) br = bottomRight +editBuffer->getDataProvider()->posScreen + editBuffer->getDataProvider()->deltaPrevScreen; + + cr->set_source_rgb (innerLineColor.getR(), innerLineColor.getG(), innerLineColor.getB()); + + if (filled) { + cr->set_line_width( innerLineWidth ); + cr->rectangle(tl.x, tl.y, br.x-tl.x, br.y-tl.y); + if (innerLineWidth > 0.) { + cr->fill_preserve(); + cr->stroke(); + } + else + cr->fill(); + } + else if (innerLineWidth > 0.) { + cr->rectangle(tl.x, tl.y, br.x-tl.x, br.y-tl.y); + cr->stroke(); + } + } +} + +void Rectangle::drawToMOChannel (Cairo::RefPtr &cr, Cairo::RefPtr &cr2, unsigned short id, rtengine::EditBuffer *editBuffer, EditCoordSystem &coordSystem) { + if (flags & ACTIVE) { + cr->set_line_width( getMouseOverLineWidth() ); + + Coord tl, br; + if (datum == IMAGE) coordSystem.imageCoordToScreen(topLeft.x, topLeft.y, tl.x, tl.y); + else if (datum == CLICKED_POINT) tl = topLeft + editBuffer->getDataProvider()->posScreen; + else if (datum == CURSOR) tl = topLeft +editBuffer->getDataProvider()->posScreen + editBuffer->getDataProvider()->deltaPrevScreen; + + if (datum == IMAGE) coordSystem.imageCoordToScreen(bottomRight.x, bottomRight.y, br.x, br.y); + else if (datum == CLICKED_POINT) br = bottomRight + editBuffer->getDataProvider()->posScreen; + else if (datum == CURSOR) br = bottomRight +editBuffer->getDataProvider()->posScreen + editBuffer->getDataProvider()->deltaPrevScreen; + + // drawing the lower byte's value + unsigned short a = (id+1) & 0xFF; + cr->set_source_rgba (0.,0., 0., double(a)/255.); + cr->rectangle(tl.x, tl.y, br.x-tl.x, br.y-tl.y); + if (filled) { + if (innerLineWidth > 0.) { + cr->fill_preserve(); + cr->stroke(); + } + else + cr->fill(); + } + else + cr->stroke(); + + // drawing the higher byte's value + if (editBuffer->getObjectMode() == OM_65535) { + a = (id+1)>>8; + cr2->set_source_rgba (0.,0., 0., double(a)/255.); + cr->rectangle(tl.x, tl.y, br.x-tl.x, br.y-tl.y); + if (filled) { + if (innerLineWidth > 0.) { + cr2->fill_preserve(); + cr2->stroke(); + } + else + cr2->fill(); + } + else + cr2->stroke(); + } + } +} + EditSubscriber::EditSubscriber () : ID(EUID_None), editingType(ET_PIPETTE), bufferType(BT_SINGLEPLANE_FLOAT), provider(NULL) {} void EditSubscriber::setEditProvider(EditDataProvider *provider) { @@ -411,6 +534,9 @@ EditDataProvider::EditDataProvider() : currSubscriber(NULL), object(0), posScree } void EditDataProvider::subscribe(EditSubscriber *subscriber) { + if (currSubscriber) + currSubscriber->switchOffEditMode(); + currSubscriber = subscriber; } diff --git a/rtgui/edit.h b/rtgui/edit.h index 5a2acf643..40038ef39 100644 --- a/rtgui/edit.h +++ b/rtgui/edit.h @@ -73,6 +73,11 @@ public: this->y = y; } + void setFromPolar(float radius, float angle) { + x = radius * cos(angle/(2*M_PI)); + y = radius * sin(angle/(2*M_PI)); + } + void operator+=(const Coord & rhs) { x += rhs.x; y += rhs.y; @@ -197,7 +202,7 @@ public: virtual void drawOuterGeometry (Cairo::RefPtr &cr, rtengine::EditBuffer *parent, EditCoordSystem &coordSystem) =0; virtual void drawInnerGeometry (Cairo::RefPtr &cr, rtengine::EditBuffer *parent, EditCoordSystem &coordSystem) =0; - virtual void drawToMOChannel (Cairo::RefPtr &cr, Cairo::RefPtr &cr2, unsigned short id, rtengine::EditBuffer *parent, EditCoordSystem &coordSystem) =0; + virtual void drawToMOChannel (Cairo::RefPtr &cr, Cairo::RefPtr &cr2, unsigned short id, rtengine::EditBuffer *editBuffer, EditCoordSystem &coordSystem) =0; }; class Circle : public Geometry { @@ -213,7 +218,7 @@ public: void drawOuterGeometry (Cairo::RefPtr &cr, rtengine::EditBuffer *editBuffer, EditCoordSystem &coordSystem); void drawInnerGeometry (Cairo::RefPtr &cr, rtengine::EditBuffer *editBuffer, EditCoordSystem &coordSystem); - void drawToMOChannel (Cairo::RefPtr &cr, Cairo::RefPtr &cr2, unsigned short id, rtengine::EditBuffer *parent, EditCoordSystem &coordSystem) =0; + void drawToMOChannel (Cairo::RefPtr &cr, Cairo::RefPtr &cr2, unsigned short id, rtengine::EditBuffer *editBuffer, EditCoordSystem &coordSystem); }; class Line : public Geometry { @@ -227,7 +232,7 @@ public: void drawOuterGeometry (Cairo::RefPtr &cr, rtengine::EditBuffer *editBuffer, EditCoordSystem &coordSystem); void drawInnerGeometry (Cairo::RefPtr &cr, rtengine::EditBuffer *editBuffer, EditCoordSystem &coordSystem); - void drawToMOChannel (Cairo::RefPtr &cr, Cairo::RefPtr &cr2, unsigned short id, rtengine::EditBuffer *parent, EditCoordSystem &coordSystem) =0; + void drawToMOChannel (Cairo::RefPtr &cr, Cairo::RefPtr &cr2, unsigned short id, rtengine::EditBuffer *editBuffer, EditCoordSystem &coordSystem); }; class Polyline : public Geometry { @@ -239,7 +244,24 @@ public: void drawOuterGeometry (Cairo::RefPtr &cr, rtengine::EditBuffer *editBuffer, EditCoordSystem &coordSystem); void drawInnerGeometry (Cairo::RefPtr &cr, rtengine::EditBuffer *editBuffer, EditCoordSystem &coordSystem); - void drawToMOChannel (Cairo::RefPtr &cr, Cairo::RefPtr &cr2, unsigned short id, rtengine::EditBuffer *parent, EditCoordSystem &coordSystem) =0; + void drawToMOChannel (Cairo::RefPtr &cr, Cairo::RefPtr &cr2, unsigned short id, rtengine::EditBuffer *editBuffer, EditCoordSystem &coordSystem); +}; + +class Rectangle : public Geometry { +public: + Coord topLeft; + Coord bottomRight; + bool filled; + + Rectangle() : topLeft(0,0), bottomRight(10,10), filled(false) {} + + void setXYWH(int left, int top, int width, int height); + void setXYXY(int left, int top, int right, int bottom); + void setXYWH(Coord topLeft, Coord widthHeight); + void setXYXY(Coord topLeft, Coord bottomRight); + void drawOuterGeometry (Cairo::RefPtr &cr, rtengine::EditBuffer *editBuffer, EditCoordSystem &coordSystem); + void drawInnerGeometry (Cairo::RefPtr &cr, rtengine::EditBuffer *editBuffer, EditCoordSystem &coordSystem); + void drawToMOChannel (Cairo::RefPtr &cr, Cairo::RefPtr &cr2, unsigned short id, rtengine::EditBuffer *editBuffer, EditCoordSystem &coordSystem); }; /// @brief Method for client tools needing Edit information @@ -331,6 +353,7 @@ public: virtual CursorShape getCursor(int objectID); int getPipetteRectSize() { return 8; } // TODO: make a GUI EditSubscriber* getCurrSubscriber(); + virtual void getImageSize (int &w, int&h) =0; }; #endif diff --git a/rtgui/editid.h b/rtgui/editid.h index 59f032340..fee08ac9a 100644 --- a/rtgui/editid.h +++ b/rtgui/editid.h @@ -20,7 +20,7 @@ #define _EDITID_H_ -/// @brief List of editing operation +/// @brief List of pipette editing operation enum EditUniqueID { EUID_None, /// special value (default) diff --git a/rtgui/flatcurveeditorsubgroup.cc b/rtgui/flatcurveeditorsubgroup.cc index 93810ae06..cf77ed9d0 100644 --- a/rtgui/flatcurveeditorsubgroup.cc +++ b/rtgui/flatcurveeditorsubgroup.cc @@ -119,7 +119,11 @@ void FlatCurveEditorSubGroup::refresh(CurveEditor *curveToRefresh) { */ void FlatCurveEditorSubGroup::editModeSwitchedOff () { // toggling off all edit buttons, even if only one is toggle on - editCPointsConn.block(true); editCPoints->set_active(false); editCPointsConn.block(false); + bool prevState = editCPointsConn.block(true); + editCPoints->set_active(false); + CPointsCurve->pipetteMouseOver(NULL, 0); + CPointsCurve->setDirty(true); + if (!prevState) editCPointsConn.block(false); } void FlatCurveEditorSubGroup::pipetteMouseOver(EditDataProvider *provider, int modifierKey) { diff --git a/rtgui/imagearea.cc b/rtgui/imagearea.cc index 763b0a23f..63b24525b 100644 --- a/rtgui/imagearea.cc +++ b/rtgui/imagearea.cc @@ -294,6 +294,15 @@ void ImageArea::unsubscribe() { listener->getToolBar()->stopEditMode (); } +void ImageArea::getImageSize (int &w, int&h) { + if (ipc) { + w = ipc->getFullWidth(); + h = ipc->getFullHeight(); + } + else + w = h = 0; +} + void ImageArea::grabFocus (CropWindow* cw) { focusGrabber = cw; diff --git a/rtgui/imagearea.h b/rtgui/imagearea.h index 43171b123..0aed665cc 100644 --- a/rtgui/imagearea.h +++ b/rtgui/imagearea.h @@ -122,6 +122,7 @@ class ImageArea : public Gtk::DrawingArea, public CropWindowListener, public Edi // EditDataProvider interface void subscribe(EditSubscriber *subscriber); void unsubscribe(); + void getImageSize (int &w, int&h); // CropWindowListener interface void cropPositionChanged (CropWindow* cw); diff --git a/rtgui/mydiagonalcurve.cc b/rtgui/mydiagonalcurve.cc index 2b25462ad..aabb96932 100644 --- a/rtgui/mydiagonalcurve.cc +++ b/rtgui/mydiagonalcurve.cc @@ -226,12 +226,8 @@ void MyDiagonalCurve::draw (int handle) { cr->fill (); } - c = style->get_fg (state); - // draw the pipette values if (pipetteR > -1.f || pipetteG > -1.f || pipetteB > -1.f) { - cr->set_line_width (0.75); - cr->set_source_rgb (c.get_red_p(), c.get_green_p(), c.get_blue_p()); int n=0; if (pipetteR > -1.f) ++n; if (pipetteG > -1.f) ++n; @@ -239,29 +235,37 @@ void MyDiagonalCurve::draw (int handle) { if (n > 1) { if (pipetteR > -1.f) { + cr->set_source_rgba (1., 0., 0., 0.5); // WARNING: assuming that red values are stored in pipetteR, which might not be the case! cr->move_to (double(graphX)+1.5 + double(graphW-3)*pipetteR, double(graphY)-1.5); cr->rel_line_to (0, double(-graphH+3)); cr->stroke (); } if (pipetteG > -1.f) { + cr->set_source_rgba (0., 1., 0., 0.5); // WARNING: assuming that green values are stored in pipetteG, which might not be the case! cr->move_to (double(graphX)+1.5 + double(graphW-3)*pipetteG, double(graphY)-1.5); cr->rel_line_to (0, double(-graphH+3)); cr->stroke (); } if (pipetteB > -1.f) { + cr->set_source_rgba (0., 0., 1., 0.5); // WARNING: assuming that blue values are stored in pipetteB, which might not be the case! cr->move_to (double(graphX)+1.5 + double(graphW-3)*pipetteB, double(graphY)-1.5); cr->rel_line_to (0, double(-graphH+3)); cr->stroke (); } } if (pipetteVal > -1.f) { - cr->set_source_rgb (1., 0., 0.); + cr->set_line_width (2.); + c = style->get_fg (state); + cr->set_source_rgb (c.get_red_p(), c.get_green_p(), c.get_blue_p()); cr->move_to (double(graphX)+1.5 + double(graphW-3)*pipetteVal, double(graphY)-1.5); cr->rel_line_to (0, double(-graphH+3)); cr->stroke (); + cr->set_line_width (1.); } } + c = style->get_fg (state); + // draw the cage of the NURBS curve if (curve.type==DCT_NURBS) { unsigned int nbPoints; @@ -519,6 +523,7 @@ bool MyDiagonalCurve::handleEvents (GdkEvent* event) { if (grab_point == -1) { new_type = CSArrow; lit_point = -1; + pipetteR = pipetteG = pipetteB = -1.f; setDirty(true); draw (lit_point); } @@ -665,6 +670,13 @@ CursorShape MyDiagonalCurve::motionNotify(CursorShape type, double minDistanceX, } void MyDiagonalCurve::pipetteMouseOver (EditDataProvider *provider, int modifierKey) { + if (!provider) { + // occurs when leaving the preview area -> cleanup the curve editor + pipetteR = pipetteG = pipetteB = -1.f; + lit_point = -1; + return; + } + pipetteR = provider->pipetteVal[0]; pipetteG = provider->pipetteVal[1]; pipetteB = provider->pipetteVal[2]; diff --git a/rtgui/myflatcurve.cc b/rtgui/myflatcurve.cc index 5c2f5b3d4..33511750b 100644 --- a/rtgui/myflatcurve.cc +++ b/rtgui/myflatcurve.cc @@ -177,26 +177,32 @@ void MyFlatCurve::draw () { if (n > 1) { if (pipetteR > -1.f) { + cr->set_source_rgba (1., 0., 0., 0.5); // WARNING: assuming that red values are stored in pipetteR, which might not be the case! cr->move_to (double(graphX)+1.5 + double(graphW-3)*pipetteR, double(graphY)-1.5); cr->rel_line_to (0, double(-graphH+3)); cr->stroke (); } if (pipetteG > -1.f) { + cr->set_source_rgba (0., 1., 0., 0.5); // WARNING: assuming that green values are stored in pipetteG, which might not be the case! cr->move_to (double(graphX)+1.5 + double(graphW-3)*pipetteG, double(graphY)-1.5); cr->rel_line_to (0, double(-graphH+3)); cr->stroke (); } if (pipetteB > -1.f) { + cr->set_source_rgba (0., 0., 1., 0.5); // WARNING: assuming that blue values are stored in pipetteB, which might not be the case! cr->move_to (double(graphX)+1.5 + double(graphW-3)*pipetteB, double(graphY)-1.5); cr->rel_line_to (0, double(-graphH+3)); cr->stroke (); } } if (pipetteVal > -1.f) { - cr->set_source_rgb (1., 0., 0.); + cr->set_line_width (2.); + c = style->get_fg (state); + cr->set_source_rgb (c.get_red_p(), c.get_green_p(), c.get_blue_p()); cr->move_to (double(graphX)+1.5 + double(graphW-3)*pipetteVal, double(graphY)-1.5); cr->rel_line_to (0, double(-graphH+3)); cr->stroke (); + cr->set_line_width (1.); } } // draw the color feedback of the control points @@ -884,6 +890,7 @@ bool MyFlatCurve::handleEvents (GdkEvent* event) { new_type = CSArrow; lit_point = -1; tanHandlesDisplayed = false; + pipetteR = pipetteG = pipetteB = -1.f; setDirty(true); draw (); } @@ -901,6 +908,13 @@ bool MyFlatCurve::handleEvents (GdkEvent* event) { } void MyFlatCurve::pipetteMouseOver (EditDataProvider *provider, int modifierKey) { + if (!provider) { + // occurs when leaving the preview area -> cleanup the curve editor + pipetteR = pipetteG = pipetteB = -1.f; + lit_point = -1; + return; + } + pipetteR = provider->pipetteVal[0]; pipetteG = provider->pipetteVal[1]; pipetteB = provider->pipetteVal[2]; diff --git a/rtgui/rgbcurves.cc b/rtgui/rgbcurves.cc index b73ec3b3d..a33e12683 100644 --- a/rtgui/rgbcurves.cc +++ b/rtgui/rgbcurves.cc @@ -58,7 +58,7 @@ RGBCurves::RGBCurves () : Gtk::VBox(), FoldableToolPanel(this) { milestones[1].g = 0.0; milestones[1].b = 1.0; Bshape = static_cast(curveEditorG->addCurve(CT_Diagonal, M("TP_RGBCURVES_BLUE"))); - Bshape->setEditID(EUID_RGB_G, BT_SINGLEPLANE_FLOAT); + Bshape->setEditID(EUID_RGB_B, BT_SINGLEPLANE_FLOAT); Bshape->setBottomBarBgGradient(milestones); Bshape->setLeftBarBgGradient(milestones);