Hello again! I’m Ajay Chauhan, and this update continues my Google Summer of Code 2025 journey with Kdenlive. Over the past few months, I’ve been working on transforming Kdenlive’s marker system from simple point markers to a range-based markers. Let me take you through the progress we’ve made since my last update.
From Backend to Frontend:
Building the User Interface
The real magic happened when we started building the user interface. I began with the Marker Dialog - the window where users create and edit markers. This was a significant challenge because we needed to maintain the simplicity of point markers while adding the complexity of range functionality.
I added three new UI elements:
- A checkbox to toggle between point and range markers
- An “End Time” field for setting the marker’s end position
- A “Duration” field that automatically calculates and displays the time span
The trickiest part was keeping these fields synchronized. When a user changes the start time, the duration updates automatically. When they modify the duration, the end time adjusts accordingly. It’s like having three interconnected gears that always move together.
🔗 Commit: feat(range-marker): implement range marker functionality in MarkerDialog
Visual Magic in the Monitor
Next came the Monitor Ruler - the horizontal timeline you see above the video preview. This is where range markers work visually with the video preview.
I implemented a visual system:
- Range Span: A semi-transparent colored rectangle that shows the marker’s duration
- Start and End Lines: Vertical lines marking the beginning and end of each range
- Color Consistency: Each marker type gets its own color, with range markers using that color for the entire span
The core of this visualization is the rangeSpan
rectangle:
Rectangle {
id: rangeSpan
visible: guideRoot.isRangeMarker
x: (model.frame * root.timeScale) - ruler.rulerZoomOffset
width: Math.max(1, guideRoot.markerDuration * root.timeScale)
height: parent.height
color: Qt.rgba(model.color.r, model.color.g, model.color.b, 0.5)
}
What this does:
visible: guideRoot.isRangeMarker
- Only shows for range markers (not point markers)width: Math.max(1, guideRoot.markerDuration * root.timeScale)
- Width represents duration, with a minimum of 1 pixelcolor: Qt.rgba(...)
- Uses the marker’s category color with 50% transparency
But the real challenge was making these markers interactive. Users can now drag the left or right edges of a range marker to resize it in real-time. The visual feedback is immediate - you see the marker grow or shrink as you drag, making it incredibly intuitive.
🔗 Commit: feat(monitor-ruler): Display the range marker color span in the Clip Monitor
Timeline Integration
The Timeline Ruler was the next frontier. This is the main timeline where users spend most of their editing time, so the range markers needed to be even more sophisticated here.
I added several visual features similar to the monitor ruler.
The timeline implementation also includes the same drag-to-resize functionality, but with additional constraints to prevent markers from extending beyond clip boundaries.
🔗 Commit: feat(markers): drag-to-resize range markers in monitor and timeline
The drag-to-resize
The drag-to-resize functionality was perhaps the most technically challenging feature. I had to implement:
- Left and Right Handle Resizing: Dragging the left and right edges changes both the start position and duration
- Live Preview: Visual feedback during resize operations
- Constraint Handling: Preventing invalid durations (minimum 1 frame)
- Binding Management: Restoring Qt’s automatic updates after resize completion
The resize handles only appear when range markers are wide enough, and they provide visual feedback through color changes and opacity adjustments. Here’s how the left and right resize handle works:
Rectangle {
id: leftResizeHandle
visible: guideRoot.isRangeMarker && rangeSpan.width > 10
width: 4
height: parent.height
x: rangeSpan.x
color: Qt.darker(model.color, 1.3)
opacity: leftResizeArea.containsMouse || leftResizeArea.isResizing ? 0.8 : 0.5
MouseArea {
id: leftResizeArea
anchors.fill: parent
anchors.margins: -2 // Extends clickable area
cursorShape: Qt.SizeHorCursor
preventStealing: true
onPositionChanged: {
if (isResizing) {
var globalCurrentX = mapToGlobal(Qt.point(mouseX, 0)).x
var realDeltaX = globalCurrentX - globalStartX
var deltaFrames = Math.round(realDeltaX / root.timeScale)
var newStartPosition = Math.max(0, startPosition + deltaFrames)
// Live preview updates
rangeSpan.x = (newStartPosition * root.timeScale) - ruler.rulerZoomOffset
rangeSpan.width = Math.max(1, newDuration * root.timeScale)
}
}
}
}
Key implementation details:
anchors.margins: -2
- Extends the clickable area beyond the visible handlepreventStealing: true
- Prevents other mouse areas from interfering- Global coordinate tracking ensures accurate resize calculations across zoom levels
- Live preview updates provide immediate visual feedback
🔗 Commit: feat(monitor-ruler): enable right-click capture for resizing markers
Zone-to-Marker
One of the other features I implemented was the Zone-to-Marker Conversion system. This feature allows users to define a time zone in the monitor and instantly create a range marker from it, bridging the gap between Kdenlive’s existing zone functionality and the new range marker system.
Before this feature, users would have to manually create range markers.
This was time-consuming and error-prone, especially when working with precise time ranges that were already defined as zones.
How It Works
The zone-to-marker system works in two ways:
Method 1: Context Menu Integration Users can right-click on the monitor ruler and select “Create Range Marker from Zone” from the context menu. This instantly creates a range marker spanning the currently defined zone.
Method 2: Quick Action A dedicated action that can be triggered from the main window, allowing users to quickly convert zones to markers without navigating through menus.
1. Monitor Proxy Enhancement
I added a new method to the MonitorProxy
class that handles the zone-to-marker conversion:
bool MonitorProxy::createRangeMarkerFromZone(const QString &comment, int type)
{
// Validate zone boundaries
if (m_zoneIn <= 0 || m_zoneOut <= 0 || m_zoneIn >= m_zoneOut) {
return false;
}
std::shared_ptr<MarkerListModel> markerModel;
// Determine which marker model to use based on monitor type
if (q->m_id == int(Kdenlive::ClipMonitor)) {
auto activeClip = pCore->monitorManager()->clipMonitor()->activeClipId();
if (!activeClip.isEmpty()) {
auto clip = pCore->bin()->getBinClip(activeClip);
if (clip) {
markerModel = clip->getMarkerModel();
}
}
} else {
// For project monitor, use the timeline guide model
if (pCore->currentDoc()) {
markerModel = pCore->currentDoc()->getGuideModel(pCore->currentTimelineId());
}
}
if (!markerModel) {
return false;
}
// Convert zone to range marker
GenTime startPos(m_zoneIn, pCore->getCurrentFps());
GenTime duration(m_zoneOut - m_zoneIn, pCore->getCurrentFps());
QString markerComment = comment.isEmpty() ? i18n("Zone marker") : comment;
// Use default marker type if none specified
if (type == -1) {
type = KdenliveSettings::default_marker_type();
}
bool success = markerModel->addRangeMarker(startPos, duration, markerComment, type);
return success;
}
User Experience Features
1. Smart Validation The system validates zone boundaries before creating markers:
- Ensures zone start is before zone end
- Prevents creation of zero-duration zones
- Handles edge cases gracefully
2. Automatic Naming If no comment is provided, the system automatically generates a descriptive name like “Zone marker” or uses the existing zone name if available.
3. Feedback System Users receive immediate feedback through status messages:
- Success confirmation when markers are created
- Error messages for invalid operations
- Warning messages for missing zones
Features
Timeline Controller Integration: Added methods like resizeGuide
and suggestSnapPoint
to make range markers work seamlessly with Kdenlive’s existing timeline operations.
The backend integration happens through the resizeMarker
method in the monitor proxy:
void MonitorProxy::resizeMarker(int position, int duration, bool isStart, int newPosition)
{
std::shared_ptr<MarkerListModel> markerModel;
// Determine appropriate marker model based on monitor type
if (q->m_id == int(Kdenlive::ClipMonitor)) {
auto activeClip = pCore->monitorManager()->clipMonitor()->activeClipId();
if (!activeClip.isEmpty()) {
auto clip = pCore->bin()->getBinClip(activeClip);
if (clip) {
markerModel = clip->getMarkerModel();
}
}
}
if (markerModel) {
GenTime pos(position, pCore->getCurrentFps());
bool exists;
CommentedTime marker = markerModel->getMarker(pos, &exists);
if (exists && marker.hasRange()) {
GenTime newDuration(duration, pCore->getCurrentFps());
// Apply constraints and update the marker
if (newDuration < GenTime(1, pCore->getCurrentFps())) {
newDuration = GenTime(1, pCore->getCurrentFps());
}
markerModel->editMarker(pos, newStartTime, marker.comment(),
marker.markerType(), newDuration);
}
}
}
🔗 Commit: feat: add functionality to create range markers from defined zones
What This Means for Kdenlive Users
Before Range Markers
Users could only place markers at specific points in time. To mark a section, they’d need multiple point markers and remember which ones belonged together.
After Range Markers
Users can now:
- Mark Complete Sections: Create a single marker that spans an entire intro, chapter, or highlight
- Visual Organization: See at a glance which parts of their project are marked and how long each section is
- Efficient Editing: Resize markers to adjust section boundaries without recreating them
- Better Collaboration: Share projects with clear, visual section markers
Final Thoughts
This GSoC project has been an incredible journey. From the initial concept of extending Kdenlive’s marker system to the final implementations of a fully featured range marker interface, every step has been a learning experience. I still have some things to improve in the Merge Request, but I’m happy with the progress I’ve made.
I’m grateful to my mentor Jean-Baptiste Mardelle for his guidance throughout this project, and to the entire Kdenlive community for their support and feedback in the Merge Request.
As I move forward in my studies and career, I’ll always remember this summer spent improving Kdenlive’s marker system. The skills I’ve developed, the challenges I’ve overcome, and the community I’ve been part of will continue to influence my work for years to come.