Skip to content

[GSoC] Working on Range Markers in Kdenlive Part 2

 at 03:07 PM

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:

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:

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:

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:

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:

🔗 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:

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:

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:

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.