bool ofxTLKeyframes::mousePressed(ofMouseEventArgs& args, long millis){
	
	
	ofVec2f screenpoint = ofVec2f(args.x, args.y);
	
    keysAreDraggable = !ofGetModifierShiftPressed();
    keysDidDrag = false;
	selectedKeyframe =  keyframeAtScreenpoint(screenpoint);
    //if we clicked OFF of a keyframe OR...
    //if we clicked on a keyframe outside of the current selection and we aren't holding down shift, clear all
    if(!ofGetModifierSelection() && (isActive() || selectedKeyframe != NULL) ){
        bool didJustDeselect = false;
	    if( selectedKeyframe == NULL || !isKeyframeSelected(selectedKeyframe)){
            //settings this to true causes the first click off of the timeline to deselct rather than create a new keyframe
            didJustDeselect = timeline->getTotalSelectedItems() > 1;
    	    timeline->unselectAll();
        }

        //if we didn't just deselect everything and clicked in an empty space add a new keyframe there
        if(selectedKeyframe == NULL && !didJustDeselect){
			createNewOnMouseup = args.button == 0 && !ofGetModifierControlPressed();
        }
    }

   
	if(selectedKeyframe != NULL){
         //add the keyframe to the selection, whether it was just generated or not
    	if(!isKeyframeSelected(selectedKeyframe)){
			selectedKeyframes.push_back(selectedKeyframe);
        }
        //unselect it if it's selected and we clicked the key with shift pressed
        else if(ofGetModifierSelection()){
        	deselectKeyframe(selectedKeyframe);
			selectedKeyframe = NULL;
        }
	}
//	if(isActive()){
//		cout << "MOUSE PRESSED args button " << args.button << " control pressed? " << (ofGetModifierControlPressed() ? "YES":"NO") << " shift/cmd pressed? " << (ofGetModifierSelection() ? "YES":"NO") << endl;
//		}
    //if we have any keyframes selected update the grab offsets and check for showing the modal window
	if(selectedKeyframes.size() != 0){
        updateDragOffsets(screenpoint, millis);
		if(selectedKeyframe != NULL){

			if(args.button == 0 && !ofGetModifierSelection() && !ofGetModifierControlPressed()){
	            timeline->setDragTimeOffset(selectedKeyframe->grabTimeOffset);
				//move the playhead
				if(timeline->getMovePlayheadOnDrag()){
					timeline->setCurrentTimeMillis(selectedKeyframe->time);
				}
			}
			if(args.button == 2 || ofGetModifierControlPressed()){
				selectedKeySecondaryClick(args);
			}
		}
	}
	return selectedKeyframe != NULL;
}
void ofxTLKeyframes::deleteSelectedKeyframes(){
	//vector<ofxTLKeyframe*>::iterator selectedIt = selectedKeyframes.end();
	for(int i = keyframes.size() - 1; i >= 0; i--){
		if(isKeyframeSelected(keyframes[i])){
			if(keyframes[i] != selectedKeyframes[selectedKeyframes.size()-1]){
				ofLogError("ofxTLKeyframes::deleteSelectedKeyframes") << "keyframe delete inconsistency";
			}
			willDeleteKeyframe(keyframes[i]);
			if(keyframes[i] == hoverKeyframe){
				hoverKeyframe = NULL;
			}
			delete keyframes[i];
			keyframes.erase(keyframes.begin()+i);
			//if(selectedIt != selectedKeyframes.begin()){
//				selectedIt--;
				selectedKeyframes.erase(--selectedKeyframes.end());
			//}
		}
	}
	
	selectedKeyframes.clear();
	updateKeyframeSort();
    
    timeline->flagTrackModified(this);
}
void ofxTLKeyframes::getSnappingPoints(set<unsigned long long>& points){
	for(int i = 0; i < keyframes.size(); i++){
		if (isKeyframeIsInBounds(keyframes[i]) && !isKeyframeSelected(keyframes[i])) {
			points.insert(keyframes[i]->time);
		}
	}
}
//draw your keyframes into bounds
void ofxTLEmptyKeyframes::draw(){
	
	ofPushStyle();
	
	ofFill();
	//show the current color as background based on the playhead position
	ofSetColor(getCurrentColor(), 100);
	ofDrawRectangle(bounds);

	for(int i = 0; i < keyframes.size(); i++){
		//make sure it's on screen
		if(isKeyframeIsInBounds(keyframes[i])){
			//we know the type because we created it in newKeyframe()
			//so we can safely cast
			ofxTLEmptyKeyframe* emptyKeyframe = (ofxTLEmptyKeyframe*)keyframes[i];
			if(hoverKeyframe == emptyKeyframe){
				ofSetColor(timeline->getColors().highlightColor);
			}
			else if(isKeyframeSelected(emptyKeyframe)){
				ofSetColor(timeline->getColors().textColor);
			}
			else{
				ofSetColor(timeline->getColors().keyColor);
			}
			ofVec2f screenPoint = screenPositionForKeyframe(emptyKeyframe);
			ofDrawCircle(screenPoint, 7);
			ofSetColor(emptyKeyframe->color);
			ofDrawCircle(screenPoint, 5);
		}
	}
	
	ofPopStyle();
}
void ofxTLCameraTrack::draw(){
	//draw your keyframes into bounds
	ofPushStyle();

	if(lockCameraToTrack){
		ofSetColor(timeline->getColors().keyColor, 40*(sin(ofGetElapsedTimef()*5)*.5+.5)+25);
		ofFill();
		ofRect(bounds);
	}
	ofSetColor(timeline->getColors().keyColor);
	ofNoFill();


	//	for(int i = 0; i < track.getSamples().size(); i++){
	for(int i = 0; i < keyframes.size(); i++){
		if(!isKeyframeIsInBounds(keyframes[i])){
			continue;
		}
		
		ofxTLCameraFrame* sample =(ofxTLCameraFrame*)keyframes[i];
		float screenX = millisToScreenX(keyframes[i]->time);
		float screenY = bounds.y;
		ofPoint screenPoint = ofPoint(screenX,screenY);
		
		//        if(keyframes[i] == selectedKeyframe){
		if(isKeyframeSelected(sample)){
			if(sample->easeInSelected){
				ofSetColor(timeline->getColors().highlightColor);
				draweEase(sample->easeIn, screenPoint, true);
				ofSetColor(timeline->getColors().keyColor);
				draweEase(sample->easeOut, screenPoint, false);
			}
			else {
				ofSetColor(timeline->getColors().keyColor);
				draweEase(sample->easeIn, screenPoint, true);
				ofSetColor(timeline->getColors().highlightColor);
				draweEase(sample->easeOut,screenPoint, false);
			}
		}
		else{
			ofSetColor(timeline->getColors().keyColor);
			draweEase(sample->easeIn,  screenPoint, true);
			draweEase(sample->easeOut, screenPoint, false);
		}
	}

	ofFill();
	ofSetColor(timeline->getColors().highlightColor);
	for(int i = 0; i < selectedKeyframes.size(); i++){
		float screenX = millisToScreenX( selectedKeyframes[i]->time );
		float screenY = bounds.y+bounds.height/2;
		ofCircle(screenX, screenY, 4);
	}

	ofPopStyle();

}
void ofxTLSwitches::getSnappingPoints(set<unsigned long>& points){
	for(int i = 0; i < keyframes.size(); i++){
        ofxTLSwitch* switchKey = (ofxTLSwitch*)keyframes[i];
		if (isKeyframeIsInBounds(switchKey) && !isKeyframeSelected(switchKey) &&
            !switchKey->startSelected && !switchKey->endSelected) {
			points.insert(switchKey->timeRange.min);
            points.insert(switchKey->timeRange.max);
		}
	}
}
Exemple #7
0
//draw your keyframes into bounds
void ofxTLLFO::draw(){
	
	//we draw keys our own way

	//ofxTLKeyframes::draw();
	if(bounds.width == 0 || bounds.height < 2){
		return;
	}
	
	if(shouldRecomputePreviews || viewIsDirty){
		recomputePreviews();
	}
	
	ofSetColor(timeline->getColors().disabledColor, 30);
	float currentPercent = sampleAtTime(currentTrackTime());
	ofFill();
	ofRect(bounds.x, bounds.getMaxY(), bounds.width, -bounds.height*currentPercent);
	
	ofPushStyle();
	ofSetColor(timeline->getColors().keyColor);
	preview.draw();
	
	
	for(int i = 0; i < keyframes.size(); i++){
		//make sure it's on screen
		if(isKeyframeIsInBounds(keyframes[i])){
			//we know the type because we created it in newKeyframe()
			//so we can safely cast
			ofxTLLFOKey* lfoKey = (ofxTLLFOKey*)keyframes[i];

			if(isKeyframeSelected(keyframes[i])){
				ofSetLineWidth(2);
				ofSetColor(timeline->getColors().textColor);
			}
			else if(keyframes[i] == hoverKeyframe){
				ofSetLineWidth(4);
				ofSetColor(timeline->getColors().highlightColor);
			}
			else{
				ofSetLineWidth(4);
				ofSetColor(timeline->getColors().keyColor);
			}
			float screenX = millisToScreenX(keyframes[i]->time);
			ofLine(screenX, bounds.y, screenX, bounds.y+bounds.height);
		}
	}
	
	ofPopStyle();
}
Exemple #8
0
void ofxTLBangs::draw(){
        
    if(bounds.height < 2){
        return;
    }
    
    ofPushStyle();
    ofFill();
	
	//float currentPercent = powf(MIN(ofGetElapsedTimef() - lastBangTime, .5), 2);
	float currentPercent = powf(ofMap(ofGetElapsedTimef() - lastBangTime, 0, .5, 1.0, 0,true), 2);
	if(currentPercent > 0){
		ofSetColor(timeline->getColors().disabledColor, 100*(currentPercent));
		ofFill();
		ofRect(bounds.x, bounds.y, bounds.width, bounds.height);
	}
	
    for(int i = keyframes.size()-1; i >= 0; i--){
		if(!isKeyframeIsInBounds(keyframes[i])){
			continue;
		}
        //int screenX = normalizedXtoScreenX(keyframes[i]->position.x);
        int screenX = millisToScreenX(keyframes[i]->time);
        if(isKeyframeSelected(keyframes[i])){
            ofSetLineWidth(2);
            ofSetColor(timeline->getColors().textColor);
        }
        else if(keyframes[i] == hoverKeyframe){
            ofSetLineWidth(4);
            ofSetColor(timeline->getColors().highlightColor);
        }
        else{
            ofSetLineWidth(4);
            ofSetColor(timeline->getColors().keyColor);
        }
        
        ofLine(screenX, bounds.y, screenX, bounds.y+bounds.height);
    }
    ofPopStyle();

}
void ofxTLSwitches::draw(){
    
    ofPushStyle();
	ofFill();
	
	//draw a little wobble if its on
	//if(isOnAtMillis(timeline->getCurrentTimeMillis())){
	//play solo change
	if(isOn()){
		ofSetColor(timeline->getColors().disabledColor, 20+(1-powf(sin(ofGetElapsedTimef()*5)*.5+.5,2))*20);
		ofRect(bounds);
	}

    for(int i = 0; i < keyframes.size(); i++){
        ofxTLSwitch* switchKey = (ofxTLSwitch*)keyframes[i];
        float startScreenX = millisToScreenX(switchKey->timeRange.min);
        float endScreenX = millisToScreenX(switchKey->timeRange.max);
		switchKey->display = ofRectangle(startScreenX, bounds.y, endScreenX-startScreenX, bounds.height);

        //draw handles

        ofSetLineWidth(2);
        bool keyIsSelected = isKeyframeSelected(switchKey);
        if(keyIsSelected || switchKey->startSelected){
	        ofSetColor(timeline->getColors().textColor);
        }
        else{
	        ofSetColor(timeline->getColors().keyColor);    
        }        

        ofLine(switchKey->display.x, bounds.y, 
               switchKey->display.x, bounds.y+bounds.height);

        if(keyIsSelected || switchKey->endSelected){
	        ofSetColor(timeline->getColors().textColor);                
        }
        else{
	        ofSetColor(timeline->getColors().keyColor);    
        }        
        ofLine(switchKey->display.x+switchKey->display.width, bounds.y, 
               switchKey->display.x+switchKey->display.width, bounds.y+bounds.height);

        //draw region
        if(keyIsSelected){
        	ofSetColor(timeline->getColors().textColor, 100);    
        }
        else{
        	ofSetColor(timeline->getColors().keyColor, 100);
        }
        //set overlay colors, this will override the colors above
        if(hoverKeyframe == switchKey){
            if(startHover){
                ofPushStyle();
                if(switchKey->startSelected){
                    ofSetColor(timeline->getColors().highlightColor);
                }
                else{
                    ofSetColor(timeline->getColors().keyColor);
                }
                ofRect(switchKey->display.x-2, bounds.y, 4, bounds.height);
                ofPopStyle();
            }
            else if(endHover){
				ofPushStyle();
                if(switchKey->endSelected){
                    ofSetColor(timeline->getColors().highlightColor);
                }
                else{
                    ofSetColor(timeline->getColors().keyColor);
                }
                ofRect(switchKey->display.x+switchKey->display.width-2, bounds.y, 4.0, bounds.height);
                ofPopStyle();
            }
            else {
                if(keyIsSelected){
	                ofSetColor(timeline->getColors().highlightColor);                    
                }else {
	                ofSetColor(timeline->getColors().keyColor);    
                }
            }
        }
        ofRect(switchKey->display);
    }
    ofPopStyle();
}
bool ofxTLSwitches::mousePressed(ofMouseEventArgs& args, long millis){
    
	if(placingSwitch != NULL){
		if(isActive() && args.button == 0){
			placingSwitch->timeRange.max = millis;
			updateTimeRanges();
		}
		else {
			deleteKeyframe(placingSwitch);
		}
		placingSwitch = NULL;
		return false;
	}
	
	keysAreDraggable = !ofGetModifierSelection();
	
    //check to see if we are close to any edges, if so select them
    bool startSelected = false;
    bool endSelected = false;
    int selectedKeyframeIndex;
    if(isActive() && args.button == 0){
        for(int i = 0; i < keyframes.size(); i++){
            
            ofxTLSwitch* switchKey = (ofxTLSwitch*)keyframes[i];
            //unselect everything else if we just clicked this edge without shift held down
            startSelected = abs(switchKey->display.x - args.x) < 10.0;
            if (startSelected && !switchKey->startSelected && !ofGetModifierSelection()) {
                timeline->unselectAll();
            }
            //Deselect the key if we clicked it already selected with shift held down
            if(ofGetModifierSelection() && ((startSelected && switchKey->startSelected) || isKeyframeSelected(switchKey))){
                switchKey->startSelected = false;    
            }
            else {
                switchKey->startSelected |= startSelected;
            }
            float endEdge = switchKey->display.x+switchKey->display.width;
            endSelected = abs(endEdge - args.x) < 10.0;
            //don't let them both be selected in one click!
            if(!startSelected && endSelected && !switchKey->endSelected && !ofGetModifierSelection()){
                timeline->unselectAll();
            }
            //Deselect the key if we clicked it already selected with shift held down
            if(ofGetModifierSelection() && ((endSelected && switchKey->endSelected) || isKeyframeSelected(switchKey))){
                switchKey->endSelected = false;    
            }
            else{
                switchKey->endSelected |= endSelected && !startSelected;
            }
            
            if(startSelected || endSelected){
				selectedKeyframeIndex = i;
                break;
            }        
        }
    }
    
    //update dragging and snapping if we clicked an edge
    updateEdgeDragOffsets(millis);
    if(endSelected || startSelected){
        ofxTLSwitch* selectedSwitch = (ofxTLSwitch*)keyframes[selectedKeyframeIndex];
        timeline->setDragTimeOffset(selectedSwitch->edgeDragOffset);
    }
	
    if(!endSelected && !startSelected){
    	//normal selection from above

	    ofxTLKeyframes::mousePressed(args, millis);
        if(isActive()){
	        timeline->cancelSnapping(); //don't snap when dragging the whole switch
        }
    }
    
    //move through the keyframes, if both the start and the end have been selected
    //count it as completely selected and let the super class take care of it
    //otherwise if just one of the edges are selected make sure it's unselected
    for(int i = 0; i < keyframes.size(); i++){
        ofxTLSwitch* switchKey = (ofxTLSwitch*)keyframes[i];
        if (switchKey->startSelected && switchKey->endSelected) {
            switchKey->startSelected = switchKey->endSelected = false;
            selectKeyframe(switchKey);
        }
        //make sure that if just one of the edges is clicked that the keyframe is *not* selected
		//also make sure it wasn't *just* selected in the last click by checking that it's not 'the' selected key
        else if( (switchKey->startSelected || switchKey->endSelected) && isKeyframeSelected(switchKey)){
			if(selectedKeyframe == switchKey){
				switchKey->startSelected = switchKey->endSelected = false;
			}
			else{
	            deselectKeyframe(switchKey);
			}
        }
    }
	return false;
}
void ofxTLNotes::draw(){
    
    ofPushStyle();
	ofFill();
    
    // Draw Row BGs
	ofFill();
	float rowHeight = bounds.height / (valueRange.span()+1);
	
	for (int i = 0; i <= valueRange.span(); i++) {
		// alternate row colors
		if(i%2 == 1) {
			ofSetColor(255, 255, 255, 50);
		} else {
			ofSetColor(255, 255, 255, 25);
		}
		
        // set row color for active notes
        int whichRow = ofMap(i, 0, valueRange.span(), valueRange.max, valueRange.min);
        if(pitchIsOn(whichRow)){
            ofSetColor(0, 0, 0, 100);
        }
		ofRect(bounds.x, bounds.y + i * rowHeight, bounds.width, rowHeight);
	}
    
    for(int i = 0; i < keyframes.size(); i++){
        // Calculate Note Bounds
        ofxTLNote* switchKey = (ofxTLNote*)keyframes[i];
        float startScreenX = MAX(millisToScreenX(switchKey->timeRange.min), 0);
        float endScreenX = MIN(millisToScreenX(switchKey->timeRange.max), bounds.getMaxX());
		if(startScreenX == endScreenX){
			continue;
		}
        int whichRow = ofMap(switchKey->pitch, valueRange.max, valueRange.min, 0, valueRange.span());
		switchKey->display = ofRectangle(startScreenX, bounds.y + whichRow * rowHeight, endScreenX-startScreenX, rowHeight);
            
        // Drawing The Handles
        ofSetLineWidth(2);
        bool keyIsSelected = isKeyframeSelected(switchKey);
        if(keyIsSelected || switchKey->startSelected){
	        ofSetColor(timeline->getColors().textColor);
        }
        else{
	        ofSetColor(timeline->getColors().keyColor);
        }
        // Do Left Line
        ofLine(switchKey->display.x, switchKey->display.y,
               switchKey->display.x, switchKey->display.y + switchKey->display.height);
        
        if(keyIsSelected || switchKey->endSelected){
	        ofSetColor(timeline->getColors().textColor);
        }
        else{
	        ofSetColor(timeline->getColors().keyColor);
        }
        // Do Right Line
        ofLine(switchKey->display.x+switchKey->display.width,  switchKey->display.y,
               switchKey->display.x+switchKey->display.width, switchKey->display.y + switchKey->display.height);
        
        //draw region
        if(keyIsSelected){
        	ofSetColor(timeline->getColors().textColor, 100);
        }
        else{
        	ofSetColor(timeline->getColors().keyColor, 100);
        }
        //set overlay colors, this will override the colors above
        if(hoverKeyframe == switchKey){
            if(startHover){
                ofPushStyle();
                if(switchKey->startSelected){
                    ofSetColor(timeline->getColors().highlightColor);
                }
                else{
                    ofSetColor(timeline->getColors().keyColor);
                }
                ofRect(switchKey->display.x-2, bounds.y, 4, bounds.height);
                ofPopStyle();
            }
            else if(endHover){
				ofPushStyle();
                if(switchKey->endSelected){
                    ofSetColor(timeline->getColors().highlightColor);
                }
                else{
                    ofSetColor(timeline->getColors().keyColor);
                }
                ofRect(switchKey->display.x+switchKey->display.width-2, bounds.y, 4.0, bounds.height);
                ofPopStyle();
            }
            else {
                if(keyIsSelected){
	                ofSetColor(timeline->getColors().highlightColor);
                }else {
	                ofSetColor(timeline->getColors().keyColor);
                }
            }
        }
        ofRect(switchKey->display);
    }
    ofPopStyle();
}
void ofxTLKeyframes::selectKeyframe(ofxTLKeyframe* k){
	if(!isKeyframeSelected(k)){
        selectedKeyframes.push_back(k);
    }
}
bool ofxTLKeyframes::mousePressed(ofMouseEventArgs& args, long millis){
	
	ofVec2f screenpoint = ofVec2f(args.x, args.y);
	keysAreStretchable = ofGetModifierShiftPressed() && ofGetModifierControlPressed();
    keysDidDrag = false;
	if(keysAreStretchable && timeline->getTotalSelectedItems() > 1){
		unsigned long long minSelected = timeline->getEarliestSelectedTime();
		unsigned long long maxSelected = timeline->getLatestSelectedTime();
		if(minSelected == maxSelected){
			keysAreStretchable = false;
		}
		else {
			unsigned long long midSelection = (maxSelected-minSelected)/2 + minSelected;
			//the anchor is the selected key opposite to where we are stretching
			stretchAnchor = midSelection <= millis ? minSelected : maxSelected;
//			cout << "Min selected " << ofxTimecode::timecodeForMillis(minSelected) << " Mid Selected " << ofxTimecode::timecodeForMillis(midSelection) << " Max selected " << ofxTimecode::timecodeForMillis(maxSelected) << " anchor "  << ofxTimecode::timecodeForMillis(stretchAnchor) << " millis down " << ofxTimecode::timecodeForMillis(millis) << endl;
			stretchSelectPoint = millis;
			//don't do anything else, like create or deselect keyframes
			updateStretchOffsets(screenpoint, millis);
		}
		return true;
	}
	
    keysAreDraggable = !ofGetModifierShiftPressed();
	selectedKeyframe =  keyframeAtScreenpoint(screenpoint);
    //if we clicked OFF of a keyframe OR...
    //if we clicked on a keyframe outside of the current selection and we aren't holding down shift, clear all
    if(!ofGetModifierSelection() && (isActive() || selectedKeyframe != NULL) ){
        bool didJustDeselect = false;
	    if( selectedKeyframe == NULL || !isKeyframeSelected(selectedKeyframe)){
            //settings this to true causes the first click off of the timeline to deselct rather than create a new keyframe
            didJustDeselect = timeline->getTotalSelectedItems() > 1;
    	    timeline->unselectAll();
        }

        //if we didn't just deselect everything and clicked in an empty space add a new keyframe there
        if(selectedKeyframe == NULL && !didJustDeselect){
			createNewOnMouseup = args.button == 0 && !ofGetModifierControlPressed();
        }
    }

	if(selectedKeyframe != NULL){
         //add the keyframe to the selection, whether it was just generated or not
    	if(!isKeyframeSelected(selectedKeyframe)){
			selectedKeyframes.push_back(selectedKeyframe);
			updateKeyframeSort();
//			selectKeyframe(selectedKeyframe);
        }
        //unselect it if it's selected and we clicked the key with shift pressed
        else if(ofGetModifierSelection()){
        	deselectKeyframe(selectedKeyframe);
			selectedKeyframe = NULL;
        }
	}
	
    //if we have any keyframes selected update the grab offsets and check for showing the modal window
	if(selectedKeyframes.size() != 0){
        updateDragOffsets(screenpoint, millis);
		if(selectedKeyframe != NULL){

			if(args.button == 0 && !ofGetModifierSelection() && !ofGetModifierControlPressed()){

	            timeline->setDragTimeOffset(selectedKeyframe->grabTimeOffset);
				//move the playhead
				if(timeline->getMovePlayheadOnDrag()){
					timeline->setCurrentTimeMillis(selectedKeyframe->time);
				}
			}
			if(args.button == 2 || ofGetModifierControlPressed()){
				selectedKeySecondaryClick(args);
			}
		}
	}
	return selectedKeyframe != NULL;
}
Exemple #14
0
void ofxTLColorTrack::draw() {

    if(bounds.height == 0) {
        return;
    }

    if(viewIsDirty || shouldRecomputePreviews) {
        updatePreviewPalette();
    }

    if(keyframes.size() == 0) {
        ofPushStyle();
        ofSetColor(defaultColor);
        ofFill();
        ofRect(bounds);
        ofPopStyle();
    }
    else if(keyframes.size() == 1) {
        ofPushStyle();
        ofxTLColorSample* s = (ofxTLColorSample*)keyframes[0];
        ofSetColor(s->color);
        ofFill();
        ofRect(bounds);
        ofPopStyle();
    }
    else {
        previewPalette.draw(bounds);
    }

    for(int i = 0; i < keyframes.size(); i++) {

        if(!isKeyframeIsInBounds(keyframes[i])) {
            continue;
        }

        float screenX = millisToScreenX(keyframes[i]->time);

        ofPoint a = ofPoint(screenX-10,bounds.y);
        ofPoint b = ofPoint(screenX+10,bounds.y);
        ofPoint c = ofPoint(screenX,bounds.y+10);

        ofPushStyle();
        ofFill();
        ofxTLColorSample* s = (ofxTLColorSample*)keyframes[i];
        ofSetColor(s->color);
        ofTriangle(a,b,c);
        ofNoFill();
        ofSetColor(s->color.getInverted());
        ofSetLineWidth(1);
        ofTriangle(a,b,c);

        if(keyframes[i] == hoverKeyframe) {
            ofSetColor(timeline->getColors().highlightColor);
            ofSetLineWidth(3);
        }
        else if(isKeyframeSelected(keyframes[i])) {
            ofSetColor(timeline->getColors().textColor);
            ofSetLineWidth(2);
        }
        else {
            ofSetColor(s->color.getInverted());
        }
        ofLine(c, ofVec2f(screenX, bounds.getMaxY()));
        ofPopStyle();
    }
}