How to customize position arrow

Hello,
I could change the position arrow color with a plugin but
Is it possible to change the border color of the position arrow?


?

I believe it’s hardcoded to white here: QField/src/qml/LocationMarker.qml at 3adcfd5662d843d2cd13a4a6cd439c53baad5dbe · opengisch/QField · GitHub

So, I don’t think you can change it, unless you walk down children manually (which I would not recommend), and set the value there directly.

Thanks,
perhaps i would be themable in a future version

It’ll be available in the next version of QField to be released by the end of the year. See Allow for the location marker border/stroke color to be customized by nirvn · Pull Request #6723 · opengisch/QField · GitHub

3 Likes

Someone knows how i can change the border color of the position point/arrow in 4.0 QField version?

The pull request added the strokeColor attribute to src/qml/LocationMarker.qml. Setting the attribute should result in the expected color change.

I’ve seen this but location marker is not the same than position arrow or i misunderstand something ?
Could you help me Pascal because here i dont know how change boder color of arrow icon position

Oh, you are right, that is odd…

I just assumed it has an object name since the pull request specifically added the attribute to make it adjustable. :sweat_smile:
I’ll check if I can find a solution later today.

@Mathieu_Pellerin Sorry for the ping, but maybe you can help us here. Since it’s supposed to be supported now, what would be the recommended way to access this?

    QfButton {
        id: button
        Layout.fillWidth: true
        text: "Button"
        visible: true

        onClicked: {
            var mapCanvas = iface.findItemByObjectName('mapCanvasContainer');

            if (mapCanvas) {
                var locationMarker = findLocationMarker(mapCanvas);

                if (locationMarker) {
                    locationMarker.strokeColor = Qt.rgba(1, 0, 0, 1);
                    locationMarker.color = Qt.rgba(1, 0, 0, 1);
                }
            }
        }

        function findLocationMarker(parent) {
            for (var i = 0; i < parent.children.length; i++) {
                var child = parent.children[i];
                if (child.toString().indexOf("LocationMarker") !== -1) {
                    return child;
                }
            }
            return null;
        }
    }

Does this work for you? I only had the chance to test it with the dot marker, not the arrow, and there it changes the color, but not the stroke color (QField 4.0.0 Windows)
I feel like it should work :thinking:

1 Like

Thank you Pascal
I test it and it change color and stroke color on arrow but not stroke color on dot

import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15

Item {
id: root

Component.onCompleted: {
    iface.addItemToPluginsToolbar(pluginButton)
}

Button {
    id: pluginButton
    text: "Rouge"
    
    
    contentItem: Text {
        text: pluginButton.text
        color: "white"
        horizontalAlignment: Text.AlignHCenter
        verticalAlignment: Text.AlignVCenter
        font.bold: true
    }
    
    background: Rectangle {
        implicitWidth: 60
        implicitHeight: 40
        color: pluginButton.pressed ? "#d32f2f" : "#f44336" // Rouge
        radius: 4
    }

    onClicked: {
        
        var mapCanvas = iface.findItemByObjectName('mapCanvasContainer');

        if (mapCanvas) {
            var locationMarker = findLocationMarker(mapCanvas);

            if (locationMarker) {
                locationMarker.strokeColor = Qt.rgba(1, 0, 0, 1);
                locationMarker.color = Qt.rgba(1, 0, 0, 1);
                iface.mainWindow().displayToast("Marqueur passé en rouge");
            } else {
                iface.mainWindow().displayToast("Activer le GPS d'abord !");
            }
        }
    }

    function findLocationMarker(parent) {
        for (var i = 0; i < parent.children.length; i++) {
            var child = parent.children[i];
            if (child.toString().indexOf("LocationMarker") !== -1) {
                return child;
            }
            var grandChild = findLocationMarker(child);
            if (grandChild) return grandChild;
        }
        return null;
    }
}

}

1 Like

Another plugin code that will remenber you something and with locationmarker integration

import QtQuick
import QtCore
import QtQuick.Controls
import QtQuick.Layouts
import QtQuick.Dialogs

import org.qfield
import org.qgis
import Theme

import “.”

Item {
id: plugin
property var mainWindow: iface.mainWindow()

// --- 0. SYSTÈME DE TRADUCTION ---
property string currentLang: Qt.locale().name.substring(0, 2)
property var translations: {
    "pos_point":   { "en": "Pos. (Point)",   "fr": "Pos. (Point)" },
    "center_pt":   { "en": "Center point",   "fr": "Point central" },
    "pos_bg":      { "en": "Pos. (Backgr.)", "fr": "Pos. (Fond)" },
    "white_halo":  { "en": "White halo",     "fr": "Halo blanc" },
    "acc_high":    { "en": "Acc. (High)",    "fr": "Préc. (Top)" },
    "green_circ":  { "en": "Green circle",   "fr": "Cercle vert" },
    "acc_avg":     { "en": "Acc. (Avg.)",    "fr": "Préc. (Moy.)" },
    "orange_circ": { "en": "Orange circle",  "fr": "Cercle orange" },
    "acc_low":     { "en": "Acc. (Low)",     "fr": "Préc. (Mauv.)" },
    "red_circ":    { "en": "Red circle",     "fr": "Cercle rouge" },
    "gps_colors":  { "en": "GPS Colors",     "fr": "Couleurs GPS" },
    "pos_tint":    { "en": "Position Tint",  "fr": "Teinte Position" },
    "reset":       { "en": "Reset",          "fr": "Réinitialiser" },
    "apply":       { "en": "Apply",          "fr": "Appliquer" }
}

function tr(key) {
    var t = translations[key];
    if (t) return (currentLang === "fr") ? t.fr : t.en;
    return key;
}

// --- 1. CONFIGURATION ---
property var positionColorConfig: ({
    "positionColor": { "name": tr("pos_point"), "desc": tr("center_pt") },
    "positionBackgroundColor": { "name": tr("pos_bg"), "desc": tr("white_halo") },
    "accuracyExcellent": { "name": tr("acc_high"), "desc": tr("green_circ") },
    "accuracyTolerated": { "name": tr("acc_avg"), "desc": tr("orange_circ") },
    "accuracyBad": { "name": tr("acc_low"), "desc": tr("red_circ") }
})

property var defaultColors: ({
    "positionColor": "#3388FF",           
    "positionBackgroundColor": "#FFFFFF", 
    "accuracyExcellent": "#4CAF50",       
    "accuracyTolerated": "#FF9800",       
    "accuracyBad": "#F44336"              
})

property var colorKeys: Object.keys(positionColorConfig)

// --- 2. SAUVEGARDE ---
Settings {
    id: themeSettings
    property string jsonColors: "{}" 
}

// --- 3. FONCTIONS POUR LE MARQUEUR (AJOUTÉ) ---
function findLocationMarker(parent) {
    if (!parent || !parent.children) return null;
    for (var i = 0; i < parent.children.length; i++) {
        var child = parent.children[i];
        if (child.toString().indexOf("LocationMarker") !== -1) return child;
        var res = findLocationMarker(child);
        if (res) return res;
    }
    return null;
}

function updateLiveMarker(key, hexValue) {
    if (key !== "positionColor") return; // On ne change le marqueur que pour la couleur centrale
    var mapCanvas = iface.findItemByObjectName('mapCanvasContainer');
    if (mapCanvas) {
        var marker = findLocationMarker(mapCanvas);
        if (marker) {
            marker.strokeColor = hexValue;
            marker.color = hexValue;
        }
    }
}

// --- 4. FONCTION D'APPLICATION ---
function applyColorChange(key, hexValue) {
    try {
        if (key === undefined || key === "") return;
        var currentJson = themeSettings.jsonColors || "{}";
        var colorsObj = JSON.parse(currentJson);
        
        colorsObj[key] = hexValue;
        Theme.applyColors(colorsObj);
        
        // Intégration du changement de couleur en direct
        updateLiveMarker(key, hexValue);
        
        themeSettings.jsonColors = JSON.stringify(colorsObj);
    } catch (e) {
        console.log("Erreur application couleur: " + e);
    }
}

// --- 5. BOUTON TOOLBAR ---
QfToolButton {
    id: openColorsBtn
    iconSource: 'icon.svg'
    iconColor: Theme.mainColor
    bgcolor: Theme.darkGray
    round: true
    ToolTip.visible: pressed
    ToolTip.text: plugin.tr("gps_colors")
    onClicked: positionColorDialog.open()
}

// --- 6. DIALOGUE ---
Dialog {
    id: positionColorDialog
    modal: true
    visible: false
    parent: plugin.mainWindow.contentItem
    anchors.centerIn: parent 
    width: Math.min(500, parent.width * 0.95)

    background: Rectangle {
        color: Theme.mainBackgroundColor 
        radius: 8
        border.color: Theme.mainColor
        border.width: 2
    }

    contentItem: ColumnLayout {
        id: mainLayout
        spacing: 10
        
        Label {
            text: plugin.tr("pos_tint")
            font.bold: true; font.pixelSize: 18
            color: Theme.mainTextColor 
            Layout.alignment: Qt.AlignHCenter
            Layout.topMargin: 10
            Layout.bottomMargin: 5
        }

        ScrollView {
            id: listScrollView
            Layout.fillWidth: true
            Layout.preferredHeight: Math.min(listContent.implicitHeight, plugin.mainWindow.height * 0.6)
            clip: true

            GridLayout {
                id: listContent
                width: listScrollView.availableWidth
                columns: 2
                columnSpacing: 10; rowSpacing: 10

                Repeater {
                    model: plugin.colorKeys
                    delegate: Rectangle {
                        Layout.fillWidth: true
                        Layout.preferredHeight: 64
                        color: "transparent"
                        border.color: Theme.controlBorderColor; border.width: 1; radius: 6

                        property string currentKey: modelData
                        property var itemConfig: plugin.positionColorConfig[modelData]
                        
                        property string displayColor: {
                            var c = Theme[modelData];
                            return c ? c.toString() : "#000000";
                        }

                        // Zone de clic pour ouvrir le dialogue
                        MouseArea {
                            anchors.fill: parent
                            onClicked: colorPicker.open()
                        }

                        RowLayout {
                            anchors.fill: parent
                            anchors.margins: 6; spacing: 8

                            Rectangle {
                                width: 24; height: 24; radius: 12
                                color: displayColor
                                border.color: Theme.controlBorderColor; border.width: 1
                            }

                            ColumnLayout {
                                Layout.fillWidth: true; spacing: 0
                                Label { 
                                    text: itemConfig.name; font.bold: true; font.pixelSize: 12
                                    color: Theme.mainTextColor; elide: Text.ElideRight; Layout.fillWidth: true
                                }
                                Label { 
                                    text: itemConfig.desc; font.pixelSize: 10
                                    color: Theme.secondaryTextColor; elide: Text.ElideRight; Layout.fillWidth: true
                                }
                            }
                            
                            Button {
                                display: AbstractButton.IconOnly
                                icon.source: "palette_icon.svg"
                                icon.color: Theme.mainTextColor; icon.width: 30; icon.height: 30
                                Layout.preferredWidth: 40; Layout.preferredHeight: 40
                                background: Rectangle {
                                    color: parent.down ? Theme.controlBackgroundColor : "transparent"
                                    radius: 4
                                }
                                onClicked: colorPicker.open()
                            }
                        }

                        // LE DIALOGUE DE COULEUR (Votre structure exacte)
                        ColorDialog {
                            id: colorPicker
                            title: itemConfig.name
                            selectedColor: displayColor
                            options: ColorDialog.ShowAlphaChannel
                            onAccepted: {
                                var colorString = "" + selectedColor;
                                plugin.applyColorChange(currentKey, colorString);
                            }
                        }
                    }
                }
            }
        }
        
        RowLayout {
            Layout.fillWidth: true; Layout.alignment: Qt.AlignHCenter
            Layout.topMargin: 5; Layout.bottomMargin: 10; spacing: 20

            Button {
                text: plugin.tr("reset")
                onClicked: {
                    themeSettings.jsonColors = "{}";
                    Theme.applyColors(plugin.defaultColors);
                    // On réinitialise aussi le marqueur en direct
                    plugin.updateLiveMarker("positionColor", plugin.defaultColors.positionColor);
                }
            }
            Button {
                text: plugin.tr("apply")
                highlighted: true
                onClicked: positionColorDialog.close()
            }
        }
    }
}

Component.onCompleted: {
    iface.addItemToPluginsToolbar(openColorsBtn);
    loadTimer.start();
}

Timer {
    id: loadTimer
    interval: 1000
    onTriggered: {
        try {
            var c = JSON.parse(themeSettings.jsonColors || "{}");
            if(Object.keys(c).length > 0) {
                Theme.applyColors(c);
                if (c.positionColor) plugin.updateLiveMarker("positionColor", c.positionColor);
            }
        } catch(e) {}
    }
}

}

To change dot border color, you need to play with borderColor

I can change border witdth for dot but @Mathieu_Pellerin could you let us, when you will have some free time, to change arrow border too, please
Sorry for this ping in christmas holidays…


For those who are interested, you can customize size and colors

1 Like