void MLMultiSlider::paint (Graphics& g) { MLLookAndFeel* myLookAndFeel = (&(getRootViewResources(this).mLookAndFeel)); if (isOpaque()) myLookAndFeel->drawBackground(g, this); float outlineThickness = myLookAndFeel->getGridUnitSize() / 64.f; MLRect r = mPos.getLocalOutline(); const Colour outlineColor (findColour(MLLookAndFeel::outlineColor).withAlpha (isEnabled() ? 1.f : 0.5f)); // draw fills // vertical only Path full, empty; Colour fullColor, emptyColor; MLRect fullRect, emptyRect; float dialY; MLRange drawRange(mRange); drawRange.convertTo(MLRange(r.height(), 0.)); for (int i=0; i<mNumSliders; ++i) { MLRect sr = (mPos.getElementBounds(i)); dialY = drawRange(getFloatProperty(ml::textUtils::addFinalNumber(ml::Symbol("value"), i))); fullRect = sr; emptyRect = sr; fullRect.setTop(dialY); fullColor = findColour(trackFullDarkColor); emptyColor = findColour(trackEmptyDarkColor); // groups of 4 if (!(i&4)) { emptyColor = emptyColor.brighter(0.10f); fullColor = fullColor.brighter(0.20f); } empty.clear(); empty.addRectangle(MLToJuceRect(emptyRect)); g.setColour(emptyColor); g.fillPath(empty); full.clear(); full.addRectangle(MLToJuceRect(fullRect)); g.setColour(fullColor); g.fillPath(full); g.setColour(outlineColor); g.strokePath(empty, PathStrokeType (outlineThickness)); } }
void MLPageView::resized() { int w = getWidth(); int h = getHeight(); Rectangle<int> myBounds(0, 0, w, h); MLLookAndFeel* myLookAndFeel = (&(getRootViewResources(this).mLookAndFeel)); int u = myLookAndFeel->getGridUnitSize(); int margin = u; int numPages = getNumPages(); for(int i=0; i<numPages; ++i) { mPages[i]->setVisible(i == mCurrPage); mPages[i]->setBounds(myBounds.translated((w + margin)*(i - mCurrPage), 0)); mPages[i]->repaint(); } }
void MLEnvelope::paint (Graphics& g) { float mDelay = getFloatProperty("delay"); float mAttack = getFloatProperty("attack"); float mSustain = getFloatProperty("sustain"); float mDecay = getFloatProperty("decay"); float mRelease = getFloatProperty("release"); float r = getFloatProperty("repeat"); float mRepeat = (r > 0.f) ? (1.f / (r + 0.0001f)) : 0.f; MLLookAndFeel* myLookAndFeel = (&(getRootViewResources(this).mLookAndFeel)); if (isOpaque()) myLookAndFeel->drawBackground(g, this); float margin = myLookAndFeel->getSmallMargin() * myLookAndFeel->getGridUnitSize(); int w = getWidth()-1; int h = getHeight()-1; float totalTime; float startX, delX, attX, decX, susX, relX, repX, endX; float attTime, decTime, relTime, susTime; float leadIn = 0.01; float leadOut = 0.01; float susHeight; float epsilon = 0.0005; float susLevel = mDARMode ? 1.0f : mSustain; attTime = mAttack + kMinAttack; decTime = mDecay * (1.f - susLevel) + kMinDecay; relTime = mRelease * susLevel + kMinDecay; // get times if (mDARMode) { susTime = (mSustain > 0.5) ? 1.f : 0.f; // is hold on? decTime = 0.; totalTime = leadIn + mDelay + attTime + susTime + relTime + leadIn + leadOut; } else { susTime = 1.f; totalTime = leadIn + attTime + decTime + susTime + relTime + leadIn + leadOut; } if (mRepeat > epsilon) { totalTime = ml::max(totalTime, (float)(leadIn + mDelay + mRepeat + leadOut)); } totalTime = ml::max(totalTime, 0.01f); // get dims MLRange vRange(UnityRange); MLRange wRange(0.f, totalTime); vRange.convertTo(MLRange(h - margin, margin)); wRange.convertTo(MLRange(margin, w - margin*2)); float t = 0.; startX = wRange(0.); delX = wRange(t += mDelay); attX = wRange(t += attTime); decX = wRange(t += decTime); susX = wRange(t += susTime); relX = wRange(t += relTime); endX = wRange(totalTime); repX = wRange(leadIn + mDelay + mRepeat); susHeight = vRange(susLevel); // draw env shape Path envPath; envPath.startNewSubPath(startX, floor(h - margin) + 0.5); envPath.lineTo(delX, floor(h - margin) + 0.5); envPath.quadraticTo(delX, floor(margin) + 0.5, attX, floor(margin) + 0.5); // up envPath.quadraticTo(attX, floor(susHeight) + 0.5, decX, floor(susHeight) + 0.5); // down envPath.quadraticTo(decX, floor(susHeight) + 0.5, susX, floor(susHeight) + 0.5); // across envPath.quadraticTo(susX, floor(h - margin) + 0.5, relX, floor(h - margin) + 0.5); // down envPath.quadraticTo(relX, floor(h - margin) + 0.5, endX, floor(h - margin) + 0.5); // across g.setColour(findColour(MLLookAndFeel::outlineColor)); g.strokePath(envPath, PathStrokeType (mOutlineThickness)); g.setColour(findColour(MLLookAndFeel::outlineColor).withAlpha(0.125f)); g.fillPath(envPath); // lines down envPath.clear(); envPath.startNewSubPath(attX, floor(margin) + 0.5); envPath.lineTo(attX, floor(h - margin) + 0.5); envPath.startNewSubPath(decX, floor(susHeight) + 0.5); envPath.lineTo(decX, floor(h - margin) + 0.5); envPath.startNewSubPath(susX, floor(susHeight) + 0.5); envPath.lineTo(susX, floor(h - margin) + 0.5); g.setColour(findColour(MLLookAndFeel::outlineColor)); g.strokePath(envPath, PathStrokeType (mOutlineThickness / 2)); // draw repeat bracket if (mRepeat > epsilon) { float thick = margin / 2; float high = margin * 1.5; envPath.clear(); envPath.startNewSubPath(floor(delX - thick/2) , floor(h - margin - high)); envPath.lineTo(floor(delX - thick/2) , floor(h - margin)); envPath.lineTo(floor( repX + thick/2) , floor(h - margin)); envPath.lineTo(floor( repX + thick/2) , floor(h - margin - high)); g.strokePath(envPath, PathStrokeType (mOutlineThickness * 4)); } //debug() << "DEL " << mDelay << " ATT " << attTime << " DEC " << decTime << " SUS " << susTime << " REL " << relTime << " REP " << mRepeat << "\n"; //debug() << "repeatX: " << repX << " delayX: " << delX << "\n"; /* // TEST Path tbounds; const Rectangle<int> & boundsRect ( getLocalBounds()); tbounds.addRectangle(boundsRect); g.setColour(Colours::red); g.strokePath(tbounds, PathStrokeType(0.5f)); */ }
void MLPageView::goToPage (int destPage, bool animate, Component* prevButton, Component* nextButton) { int duration = 500; float targetAlpha; //with this on, animations fail sometimes. with this off, they fail in a different way,always. bool proxy = true; int w = getWidth(); int h = getHeight(); Rectangle<int> localBounds(0, 0, w, h); int pages = mPages.size(); if(!pages) return; if(mCurrPage == destPage) return; MLLookAndFeel* myLookAndFeel = (&(getRootViewResources(this).mLookAndFeel)); int u = myLookAndFeel->getGridUnitSize(); // margin between pages prevents invisible components from overlapping // those onscreen int margin = u; int newPage = ml::clamp(destPage, 0, (int)mPages.size() - 1); animate = true; if ((animate) && (newPage != mCurrPage) && (mCurrPage >= 0)) { // line up all pages from new through current offscreen // and make visible all in line up int start = ml::min(mCurrPage, newPage); int end = ml::max(mCurrPage, newPage); for(int i=start; i <= end; ++i) { mPages[i]->setBounds(localBounds.translated((w + margin)*(i - mCurrPage), 0)); mPages[i]->setVisible(true); } // scroll past all to new page for(int i=start; i <= end; ++i) { if (i == newPage) { targetAlpha = 1.f; } else if (i == mCurrPage) { targetAlpha = 0.f; } else { // allow intermediate pages to show? we don't really do these // transitions anyway. targetAlpha = 1.f; } // NOTE: this can cause a problem stopping a running thread in CachedImage::stop if called at just the wrong time-- TODO investigate! mAnimator.animateComponent (mPages[i], localBounds.translated((w + margin)*(i - newPage), 0), targetAlpha, duration, proxy, 4.0, 0.25); } // animate buttons if (prevButton) { targetAlpha = (newPage > 0) ? 1.f : 0.f; mAnimator.animateComponent (prevButton, prevButton->getBounds(), targetAlpha, duration, proxy, 1.0, 1.0); // //debug() << "prev alpha: " << targetAlpha << "\n"; } // animate buttons if (nextButton) { int last = mPages.size() - 1; targetAlpha = (newPage < last) ? 1.f : 0.f; mAnimator.animateComponent (nextButton, nextButton->getBounds(), targetAlpha, duration, proxy, 1.0, 1.0); // //debug() << "next alpha: " << targetAlpha << "\n"; } } else { for(int p=0; p<pages; ++p) { if(p == newPage) { mPages[p]->setBounds(localBounds); mPages[p]->setVisible(true); } else { mPages[p]->setBounds(localBounds.translated((w + margin), 0)); mPages[p]->setVisible(false); } } } mCurrPage = newPage; }
void MLDrawing::paint(Graphics& g) { MLLookAndFeel* myLookAndFeel = (&(getRootViewResources(this).mLookAndFeel)); float fu = myLookAndFeel->getGridUnitSize(); if (isOpaque()) myLookAndFeel->drawBackground(g, this); // defaults float ft = 1.0f * fu / 64.; float arrowScale = fu / 48.; float dotRadius = fu / 24.; mLineColor = mDarkColor; g.setColour(mLineColor); // int w = getWidth(); // int h = getHeight(); /* // TEST TODO auto border / background? Path tbounds; const MLRect boundsRect ( getLocalBounds()); tbounds.addRectangle(boundsRect); g.setColour(Colours::blue.withAlpha(0.5f)); g.fillPath(tbounds); g.setColour(Colours::red); g.strokePath(tbounds, PathStrokeType(1.0f)); */ //debug() << "painting MLDrawing " << getWidgetName() << "\n"; //int c = 0; for(auto op : mOperations) { Path p; Vec2 p1, p2; //const MLDrawing::Operation& op = *it; //debug() << " painting op " << c++ << "\n"; for(int i=0; i<4; ++i) { assert(ml::within((int)op.args[i], 0, (int)mTransformedPoints.size())); } switch(op.type) { case drawLine: p1 = mTransformedPoints[(int)op.args[0]]; p2 = mTransformedPoints[(int)op.args[1]]; p.startNewSubPath(MLToJucePoint(correctPoint(p1))); p.lineTo(MLToJucePoint(correctPoint(p2))); g.strokePath(p, PathStrokeType(ft)); break; case drawLineArrowStart: case drawLineArrowEnd: p1 = mTransformedPoints[(int)op.args[0]]; p2 = mTransformedPoints[(int)op.args[1]]; p.startNewSubPath(MLToJucePoint(correctPoint(p1))); p.lineTo(MLToJucePoint(correctPoint(p2))); g.strokePath(p, PathStrokeType(ft)); drawArrowhead(g, p1, p2, arrowScale); break; case drawDot: p1 = mTransformedPoints[(int)op.args[0]]; // p.startNewSubPath(MLToJucePoint(correctPoint(p1))); { juce::Point<float> pc = MLToJucePoint(correctPoint(p1)); juce::Point<float> pr1 = pc + juce::Point<float>(dotRadius, 0); p.startNewSubPath(pr1); int s = 10; for(int i=0; i<s; ++i) { float omega = i*kMLTwoPi/(s - 1); juce::Point<float> pr = pc + juce::Point<float>(cos(omega)*dotRadius, sin(omega)*dotRadius); p.lineTo(pr); } p.lineTo(pr1); g.fillPath(p); } break; case drawLineArrowBoth: break; case setLineThickness: mLineThickness = op.args[0]; ft = mLineThickness * fu / 64.; break; case setLightColor: g.setColour(mLightColor); break; case setDarkColor: g.setColour(mDarkColor); break; } } }