forked from 1b-agent/opencadstudio-upstream
Options: snap marker size (#1770)
The object-snap glyphs were fixed at 5 px; a Drafting slider now scales them from 1 to 20 px. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
d915489a67
commit
d5de798f8a
29 files changed
+375
-315
No files matched your search
@@ -2444,6 +2444,7 @@ common =
|
|||||||
.load-linetypes = تحميل أنواع الخطوط
|
.load-linetypes = تحميل أنواع الخطوط
|
||||||
.requires-two-positive-values = يتطلب قيمتين موجبتين (x,y) أو قيمة واحدة لكليهما.
|
.requires-two-positive-values = يتطلب قيمتين موجبتين (x,y) أو قيمة واحدة لكليهما.
|
||||||
.snap-marker-color = لون علامة الالتقاط
|
.snap-marker-color = لون علامة الالتقاط
|
||||||
|
.snap-marker-size = حجم علامة الالتقاط
|
||||||
.command-line-text-color = لون نص سطر الأوامر
|
.command-line-text-color = لون نص سطر الأوامر
|
||||||
.operand = المعامل
|
.operand = المعامل
|
||||||
.linetypes-loaded = تم تحميل __ocs_fmt_0__ من أنواع الخطوط.
|
.linetypes-loaded = تم تحميل __ocs_fmt_0__ من أنواع الخطوط.
|
||||||
|
|||||||
@@ -2431,6 +2431,7 @@ common =
|
|||||||
.load-linetypes = Зареждане на типове линии
|
.load-linetypes = Зареждане на типове линии
|
||||||
.requires-two-positive-values = Изискват се две положителни стойности (x,y) или една за двете.
|
.requires-two-positive-values = Изискват се две положителни стойности (x,y) или една за двете.
|
||||||
.snap-marker-color = Цвят на маркера за прихващане
|
.snap-marker-color = Цвят на маркера за прихващане
|
||||||
|
.snap-marker-size = Размер на маркера за прихващане
|
||||||
.command-line-text-color = Цвят на текста в командния ред
|
.command-line-text-color = Цвят на текста в командния ред
|
||||||
.operand = Операнд
|
.operand = Операнд
|
||||||
.linetypes-loaded = Заредени типове линии: __ocs_fmt_0__.
|
.linetypes-loaded = Заредени типове линии: __ocs_fmt_0__.
|
||||||
|
|||||||
@@ -2431,6 +2431,7 @@ common =
|
|||||||
.load-linetypes = Načíst typy čar
|
.load-linetypes = Načíst typy čar
|
||||||
.requires-two-positive-values = Vyžaduje dvě kladné hodnoty (x,y) nebo jednu pro obě.
|
.requires-two-positive-values = Vyžaduje dvě kladné hodnoty (x,y) nebo jednu pro obě.
|
||||||
.snap-marker-color = Barva značky uchopení
|
.snap-marker-color = Barva značky uchopení
|
||||||
|
.snap-marker-size = Velikost značky uchopení
|
||||||
.command-line-text-color = Barva textu příkazového řádku
|
.command-line-text-color = Barva textu příkazového řádku
|
||||||
.operand = Operand
|
.operand = Operand
|
||||||
.linetypes-loaded = Načteno typů čar: __ocs_fmt_0__.
|
.linetypes-loaded = Načteno typů čar: __ocs_fmt_0__.
|
||||||
|
|||||||
@@ -2432,6 +2432,7 @@ common =
|
|||||||
.load-linetypes = Linientypen laden
|
.load-linetypes = Linientypen laden
|
||||||
.requires-two-positive-values = Erfordert zwei positive Werte (x,y) oder einen für beide.
|
.requires-two-positive-values = Erfordert zwei positive Werte (x,y) oder einen für beide.
|
||||||
.snap-marker-color = Farbe der Fangmarkierung
|
.snap-marker-color = Farbe der Fangmarkierung
|
||||||
|
.snap-marker-size = Größe der Fangmarkierung
|
||||||
.command-line-text-color = Textfarbe der Befehlszeile
|
.command-line-text-color = Textfarbe der Befehlszeile
|
||||||
.operand = Operand
|
.operand = Operand
|
||||||
.linetypes-loaded = __ocs_fmt_0__ Linientyp(en) geladen.
|
.linetypes-loaded = __ocs_fmt_0__ Linientyp(en) geladen.
|
||||||
|
|||||||
@@ -2431,6 +2431,7 @@ common =
|
|||||||
.load-linetypes = Φόρτωση τύπων γραμμής
|
.load-linetypes = Φόρτωση τύπων γραμμής
|
||||||
.requires-two-positive-values = Απαιτούνται δύο θετικές τιμές (x,y) ή μία και για τις δύο.
|
.requires-two-positive-values = Απαιτούνται δύο θετικές τιμές (x,y) ή μία και για τις δύο.
|
||||||
.snap-marker-color = Χρώμα δείκτη έλξης
|
.snap-marker-color = Χρώμα δείκτη έλξης
|
||||||
|
.snap-marker-size = Μέγεθος δείκτη έλξης
|
||||||
.command-line-text-color = Χρώμα κειμένου γραμμής εντολών
|
.command-line-text-color = Χρώμα κειμένου γραμμής εντολών
|
||||||
.operand = Τελεστέος
|
.operand = Τελεστέος
|
||||||
.linetypes-loaded = Φορτώθηκαν __ocs_fmt_0__ τύποι γραμμής.
|
.linetypes-loaded = Φορτώθηκαν __ocs_fmt_0__ τύποι γραμμής.
|
||||||
|
|||||||
@@ -2432,6 +2432,7 @@ common =
|
|||||||
.load-linetypes = Load Linetypes
|
.load-linetypes = Load Linetypes
|
||||||
.requires-two-positive-values = Requires two positive values (x,y) or one for both.
|
.requires-two-positive-values = Requires two positive values (x,y) or one for both.
|
||||||
.snap-marker-color = Snap marker color
|
.snap-marker-color = Snap marker color
|
||||||
|
.snap-marker-size = Snap marker size
|
||||||
.command-line-text-color = Command line text color
|
.command-line-text-color = Command line text color
|
||||||
.operand = Operand
|
.operand = Operand
|
||||||
.linetypes-loaded = __ocs_fmt_0__ linetype(s) loaded.
|
.linetypes-loaded = __ocs_fmt_0__ linetype(s) loaded.
|
||||||
|
|||||||
@@ -2432,6 +2432,7 @@ common =
|
|||||||
.load-linetypes = Cargar tipos de línea
|
.load-linetypes = Cargar tipos de línea
|
||||||
.requires-two-positive-values = Requiere dos valores positivos (x,y) o uno para ambos.
|
.requires-two-positive-values = Requiere dos valores positivos (x,y) o uno para ambos.
|
||||||
.snap-marker-color = Color del marcador de referencia
|
.snap-marker-color = Color del marcador de referencia
|
||||||
|
.snap-marker-size = Tamaño del marcador de referencia
|
||||||
.command-line-text-color = Color del texto de la línea de comandos
|
.command-line-text-color = Color del texto de la línea de comandos
|
||||||
.operand = Operando
|
.operand = Operando
|
||||||
.linetypes-loaded = __ocs_fmt_0__ tipo(s) de línea cargado(s).
|
.linetypes-loaded = __ocs_fmt_0__ tipo(s) de línea cargado(s).
|
||||||
|
|||||||
@@ -2431,6 +2431,7 @@ common =
|
|||||||
.load-linetypes = Lataa viivatyypit
|
.load-linetypes = Lataa viivatyypit
|
||||||
.requires-two-positive-values = Vaatii kaksi positiivista arvoa (x,y) tai yhden molemmille.
|
.requires-two-positive-values = Vaatii kaksi positiivista arvoa (x,y) tai yhden molemmille.
|
||||||
.snap-marker-color = Kohdistusmerkin väri
|
.snap-marker-color = Kohdistusmerkin väri
|
||||||
|
.snap-marker-size = Kohdistusmerkin koko
|
||||||
.command-line-text-color = Komentorivin tekstin väri
|
.command-line-text-color = Komentorivin tekstin väri
|
||||||
.operand = Operandi
|
.operand = Operandi
|
||||||
.linetypes-loaded = Ladattu __ocs_fmt_0__ viivatyyppiä.
|
.linetypes-loaded = Ladattu __ocs_fmt_0__ viivatyyppiä.
|
||||||
|
|||||||
@@ -2432,6 +2432,7 @@ common =
|
|||||||
.load-linetypes = Charger des types de ligne
|
.load-linetypes = Charger des types de ligne
|
||||||
.requires-two-positive-values = Nécessite deux valeurs positives (x,y) ou une seule pour les deux.
|
.requires-two-positive-values = Nécessite deux valeurs positives (x,y) ou une seule pour les deux.
|
||||||
.snap-marker-color = Couleur du marqueur d'accrochage
|
.snap-marker-color = Couleur du marqueur d'accrochage
|
||||||
|
.snap-marker-size = Taille du marqueur d'accrochage
|
||||||
.command-line-text-color = Couleur du texte de la ligne de commande
|
.command-line-text-color = Couleur du texte de la ligne de commande
|
||||||
.operand = Opérande
|
.operand = Opérande
|
||||||
.linetypes-loaded = __ocs_fmt_0__ type(s) de ligne chargé(s).
|
.linetypes-loaded = __ocs_fmt_0__ type(s) de ligne chargé(s).
|
||||||
|
|||||||
@@ -2420,6 +2420,7 @@ common =
|
|||||||
.load-linetypes = लाइनटाइप लोड करें
|
.load-linetypes = लाइनटाइप लोड करें
|
||||||
.requires-two-positive-values = दो धनात्मक मान (x,y) या दोनों के लिए एक मान आवश्यक है।
|
.requires-two-positive-values = दो धनात्मक मान (x,y) या दोनों के लिए एक मान आवश्यक है।
|
||||||
.snap-marker-color = स्नैप मार्कर का रंग
|
.snap-marker-color = स्नैप मार्कर का रंग
|
||||||
|
.snap-marker-size = स्नैप मार्कर का आकार
|
||||||
.command-line-text-color = कमांड लाइन टेक्स्ट रंग
|
.command-line-text-color = कमांड लाइन टेक्स्ट रंग
|
||||||
.operand = ऑपरेंड
|
.operand = ऑपरेंड
|
||||||
.linetypes-loaded = __ocs_fmt_0__ लाइनटाइप लोड हुए।
|
.linetypes-loaded = __ocs_fmt_0__ लाइनटाइप लोड हुए।
|
||||||
|
|||||||
@@ -2437,6 +2437,7 @@ common =
|
|||||||
.load-linetypes = Vonaltípusok betöltése
|
.load-linetypes = Vonaltípusok betöltése
|
||||||
.requires-two-positive-values = Két pozitív érték (x,y) vagy egy közös érték szükséges.
|
.requires-two-positive-values = Két pozitív érték (x,y) vagy egy közös érték szükséges.
|
||||||
.snap-marker-color = Tárgyraszterjel színe
|
.snap-marker-color = Tárgyraszterjel színe
|
||||||
|
.snap-marker-size = Tárgyraszterjel mérete
|
||||||
.command-line-text-color = Parancssor szövegszíne
|
.command-line-text-color = Parancssor szövegszíne
|
||||||
.operand = Operandus
|
.operand = Operandus
|
||||||
.linetypes-loaded = __ocs_fmt_0__ vonaltípus betöltve.
|
.linetypes-loaded = __ocs_fmt_0__ vonaltípus betöltve.
|
||||||
|
|||||||
@@ -2431,6 +2431,7 @@ common =
|
|||||||
.load-linetypes = Carica tipi di linea
|
.load-linetypes = Carica tipi di linea
|
||||||
.requires-two-positive-values = Richiede due valori positivi (x,y) o uno per entrambi.
|
.requires-two-positive-values = Richiede due valori positivi (x,y) o uno per entrambi.
|
||||||
.snap-marker-color = Colore del marcatore di snap
|
.snap-marker-color = Colore del marcatore di snap
|
||||||
|
.snap-marker-size = Dimensione del marcatore di snap
|
||||||
.command-line-text-color = Colore del testo della riga di comando
|
.command-line-text-color = Colore del testo della riga di comando
|
||||||
.operand = Operando
|
.operand = Operando
|
||||||
.linetypes-loaded = __ocs_fmt_0__ tipo/i di linea caricato/i.
|
.linetypes-loaded = __ocs_fmt_0__ tipo/i di linea caricato/i.
|
||||||
|
|||||||
@@ -2422,6 +2422,7 @@ common =
|
|||||||
.load-linetypes = 線種をロード
|
.load-linetypes = 線種をロード
|
||||||
.requires-two-positive-values = 2つの正の値 (x,y)、または両方に共通の1つの値が必要です。
|
.requires-two-positive-values = 2つの正の値 (x,y)、または両方に共通の1つの値が必要です。
|
||||||
.snap-marker-color = スナップ マーカーの色
|
.snap-marker-color = スナップ マーカーの色
|
||||||
|
.snap-marker-size = スナップ マーカーのサイズ
|
||||||
.command-line-text-color = コマンドラインの文字色
|
.command-line-text-color = コマンドラインの文字色
|
||||||
.operand = オペランド
|
.operand = オペランド
|
||||||
.linetypes-loaded = __ocs_fmt_0__ 個の線種をロードしました。
|
.linetypes-loaded = __ocs_fmt_0__ 個の線種をロードしました。
|
||||||
|
|||||||
@@ -2431,6 +2431,7 @@ common =
|
|||||||
.load-linetypes = 선종류 로드
|
.load-linetypes = 선종류 로드
|
||||||
.requires-two-positive-values = 양수 값 두 개(x,y) 또는 둘 다에 쓸 값 하나가 필요합니다.
|
.requires-two-positive-values = 양수 값 두 개(x,y) 또는 둘 다에 쓸 값 하나가 필요합니다.
|
||||||
.snap-marker-color = 스냅 마커 색상
|
.snap-marker-color = 스냅 마커 색상
|
||||||
|
.snap-marker-size = 스냅 마커 크기
|
||||||
.command-line-text-color = 명령줄 텍스트 색상
|
.command-line-text-color = 명령줄 텍스트 색상
|
||||||
.operand = 피연산자
|
.operand = 피연산자
|
||||||
.linetypes-loaded = 선종류 __ocs_fmt_0__개를 로드했습니다.
|
.linetypes-loaded = 선종류 __ocs_fmt_0__개를 로드했습니다.
|
||||||
|
|||||||
@@ -2432,6 +2432,7 @@ common =
|
|||||||
.load-linetypes = ໂຫຼດຮູບແບບເສັ້ນ
|
.load-linetypes = ໂຫຼດຮູບແບບເສັ້ນ
|
||||||
.requires-two-positive-values = ຕ້ອງການຄ່າບວກສອງຄ່າ (x,y) ຫຼື ຄ່າດຽວສຳລັບທັງສອງ.
|
.requires-two-positive-values = ຕ້ອງການຄ່າບວກສອງຄ່າ (x,y) ຫຼື ຄ່າດຽວສຳລັບທັງສອງ.
|
||||||
.snap-marker-color = ສີເຄື່ອງໝາຍຈຸດດູດ
|
.snap-marker-color = ສີເຄື່ອງໝາຍຈຸດດູດ
|
||||||
|
.snap-marker-size = ຂະໜາດເຄື່ອງໝາຍຈຸດດູດ
|
||||||
.command-line-text-color = ສີຂໍ້ຄວາມແຖວຄຳສັ່ງ
|
.command-line-text-color = ສີຂໍ້ຄວາມແຖວຄຳສັ່ງ
|
||||||
.operand = ຕົວດຳເນີນການ
|
.operand = ຕົວດຳເນີນການ
|
||||||
.linetypes-loaded = ໂຫຼດຮູບແບບເສັ້ນແລ້ວ __ocs_fmt_0__ ຮູບແບບ.
|
.linetypes-loaded = ໂຫຼດຮູບແບບເສັ້ນແລ້ວ __ocs_fmt_0__ ຮູບແບບ.
|
||||||
|
|||||||
@@ -2432,6 +2432,7 @@ common =
|
|||||||
.load-linetypes = Lijntypen laden
|
.load-linetypes = Lijntypen laden
|
||||||
.requires-two-positive-values = Vereist twee positieve waarden (x,y) of één voor beide.
|
.requires-two-positive-values = Vereist twee positieve waarden (x,y) of één voor beide.
|
||||||
.snap-marker-color = Kleur van snapmarkering
|
.snap-marker-color = Kleur van snapmarkering
|
||||||
|
.snap-marker-size = Grootte van snapmarkering
|
||||||
.command-line-text-color = Tekstkleur opdrachtregel
|
.command-line-text-color = Tekstkleur opdrachtregel
|
||||||
.operand = Operand
|
.operand = Operand
|
||||||
.linetypes-loaded = __ocs_fmt_0__ lijntype(n) geladen.
|
.linetypes-loaded = __ocs_fmt_0__ lijntype(n) geladen.
|
||||||
|
|||||||
@@ -2431,6 +2431,7 @@ common =
|
|||||||
.load-linetypes = Wczytaj rodzaje linii
|
.load-linetypes = Wczytaj rodzaje linii
|
||||||
.requires-two-positive-values = Wymaga dwóch wartości dodatnich (x,y) lub jednej dla obu.
|
.requires-two-positive-values = Wymaga dwóch wartości dodatnich (x,y) lub jednej dla obu.
|
||||||
.snap-marker-color = Kolor znacznika przyciągania
|
.snap-marker-color = Kolor znacznika przyciągania
|
||||||
|
.snap-marker-size = Rozmiar znacznika przyciągania
|
||||||
.command-line-text-color = Kolor tekstu wiersza poleceń
|
.command-line-text-color = Kolor tekstu wiersza poleceń
|
||||||
.operand = Operand
|
.operand = Operand
|
||||||
.linetypes-loaded = Wczytano rodzaje linii: __ocs_fmt_0__.
|
.linetypes-loaded = Wczytano rodzaje linii: __ocs_fmt_0__.
|
||||||
|
|||||||
@@ -2432,6 +2432,7 @@ common =
|
|||||||
.load-linetypes = Carregar tipos de linha
|
.load-linetypes = Carregar tipos de linha
|
||||||
.requires-two-positive-values = Requer dois valores positivos (x,y) ou um para ambos.
|
.requires-two-positive-values = Requer dois valores positivos (x,y) ou um para ambos.
|
||||||
.snap-marker-color = Cor do marcador de snap
|
.snap-marker-color = Cor do marcador de snap
|
||||||
|
.snap-marker-size = Tamanho do marcador de snap
|
||||||
.command-line-text-color = Cor do texto da linha de comando
|
.command-line-text-color = Cor do texto da linha de comando
|
||||||
.operand = Operando
|
.operand = Operando
|
||||||
.linetypes-loaded = __ocs_fmt_0__ tipo(s) de linha carregado(s).
|
.linetypes-loaded = __ocs_fmt_0__ tipo(s) de linha carregado(s).
|
||||||
|
|||||||
@@ -2435,6 +2435,7 @@ common =
|
|||||||
.load-linetypes = Загрузить типы линий
|
.load-linetypes = Загрузить типы линий
|
||||||
.requires-two-positive-values = Требуются два положительных значения (x,y) или одно для обоих.
|
.requires-two-positive-values = Требуются два положительных значения (x,y) или одно для обоих.
|
||||||
.snap-marker-color = Цвет маркера привязки
|
.snap-marker-color = Цвет маркера привязки
|
||||||
|
.snap-marker-size = Размер маркера привязки
|
||||||
.command-line-text-color = Цвет текста командной строки
|
.command-line-text-color = Цвет текста командной строки
|
||||||
.operand = Операнд
|
.operand = Операнд
|
||||||
.linetypes-loaded = Загружено типов линий: __ocs_fmt_0__.
|
.linetypes-loaded = Загружено типов линий: __ocs_fmt_0__.
|
||||||
|
|||||||
@@ -2416,6 +2416,7 @@ common =
|
|||||||
.load-linetypes = Çizgi tiplerini yükle
|
.load-linetypes = Çizgi tiplerini yükle
|
||||||
.requires-two-positive-values = İki pozitif değer (x,y) ya da ikisi için tek değer gerekir.
|
.requires-two-positive-values = İki pozitif değer (x,y) ya da ikisi için tek değer gerekir.
|
||||||
.snap-marker-color = Yakalama işaretçisi rengi
|
.snap-marker-color = Yakalama işaretçisi rengi
|
||||||
|
.snap-marker-size = Yakalama işaretçisi boyutu
|
||||||
.command-line-text-color = Komut satırı metin rengi
|
.command-line-text-color = Komut satırı metin rengi
|
||||||
.operand = İşlenen
|
.operand = İşlenen
|
||||||
.linetypes-loaded = __ocs_fmt_0__ çizgi tipi yüklendi.
|
.linetypes-loaded = __ocs_fmt_0__ çizgi tipi yüklendi.
|
||||||
|
|||||||
@@ -2419,6 +2419,7 @@ common =
|
|||||||
.load-linetypes = 加载线型
|
.load-linetypes = 加载线型
|
||||||
.requires-two-positive-values = 需要两个正值 (x,y),或一个同时用于两者的值。
|
.requires-two-positive-values = 需要两个正值 (x,y),或一个同时用于两者的值。
|
||||||
.snap-marker-color = 捕捉标记颜色
|
.snap-marker-color = 捕捉标记颜色
|
||||||
|
.snap-marker-size = 捕捉标记大小
|
||||||
.command-line-text-color = 命令行文字颜色
|
.command-line-text-color = 命令行文字颜色
|
||||||
.operand = 操作对象
|
.operand = 操作对象
|
||||||
.linetypes-loaded = 已加载 __ocs_fmt_0__ 个线型。
|
.linetypes-loaded = 已加载 __ocs_fmt_0__ 个线型。
|
||||||
|
|||||||
@@ -2431,6 +2431,7 @@ common =
|
|||||||
.load-linetypes = 載入線型
|
.load-linetypes = 載入線型
|
||||||
.requires-two-positive-values = 需要兩個正值 (x,y),或一個同時用於兩者的值。
|
.requires-two-positive-values = 需要兩個正值 (x,y),或一個同時用於兩者的值。
|
||||||
.snap-marker-color = 鎖點標記顏色
|
.snap-marker-color = 鎖點標記顏色
|
||||||
|
.snap-marker-size = 鎖點標記大小
|
||||||
.command-line-text-color = 命令列文字顏色
|
.command-line-text-color = 命令列文字顏色
|
||||||
.operand = 運算元
|
.operand = 運算元
|
||||||
.linetypes-loaded = 已載入 __ocs_fmt_0__ 個線型。
|
.linetypes-loaded = 已載入 __ocs_fmt_0__ 個線型。
|
||||||
|
|||||||
@@ -369,6 +369,8 @@ pub struct ModelSpaceThemeConfig {
|
|||||||
pub grip_hot: u8,
|
pub grip_hot: u8,
|
||||||
/// GRIPHOVER: hovered/warm grip ACI color (0 = Theme Primary Strong, 1..=255 = ACI).
|
/// GRIPHOVER: hovered/warm grip ACI color (0 = Theme Primary Strong, 1..=255 = ACI).
|
||||||
pub grip_hover: u8,
|
pub grip_hover: u8,
|
||||||
|
/// SNAPMARKERSIZE: object-snap marker half-size in pixels (1–20, default 5).
|
||||||
|
pub snap_marker_size: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for ModelSpaceThemeConfig {
|
impl Default for ModelSpaceThemeConfig {
|
||||||
@@ -390,6 +392,7 @@ impl Default for ModelSpaceThemeConfig {
|
|||||||
grip_color: 0,
|
grip_color: 0,
|
||||||
grip_hot: 0,
|
grip_hot: 0,
|
||||||
grip_hover: 0,
|
grip_hover: 0,
|
||||||
|
snap_marker_size: 5,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2609,6 +2609,8 @@ pub enum Message {
|
|||||||
SelectionHighlightColorChanged(u8),
|
SelectionHighlightColorChanged(u8),
|
||||||
/// Change Grip size in pixels (1–25, GRIPSIZE).
|
/// Change Grip size in pixels (1–25, GRIPSIZE).
|
||||||
GripSizeChanged(u8),
|
GripSizeChanged(u8),
|
||||||
|
/// Change the object-snap marker size in pixels (1–20, SNAPMARKERSIZE).
|
||||||
|
SnapMarkerSizeChanged(u8),
|
||||||
/// Change Unselected Grip color ACI index (0 = Theme Primary, 1..=255 = ACI, GRIPCOLOR).
|
/// Change Unselected Grip color ACI index (0 = Theme Primary, 1..=255 = ACI, GRIPCOLOR).
|
||||||
GripColorChanged(u8),
|
GripColorChanged(u8),
|
||||||
/// Change Selected/Hot Grip color ACI index (0 = Theme Danger, 1..=255 = ACI, GRIPHOT).
|
/// Change Selected/Hot Grip color ACI index (0 = Theme Danger, 1..=255 = ACI, GRIPHOT).
|
||||||
|
|||||||
@@ -9052,6 +9052,12 @@ impl OpenCADStudio {
|
|||||||
Task::none()
|
Task::none()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Message::SnapMarkerSizeChanged(size) => {
|
||||||
|
self.model_space.snap_marker_size = size.clamp(1, 20);
|
||||||
|
self.persist_settings_if_changed();
|
||||||
|
Task::none()
|
||||||
|
}
|
||||||
|
|
||||||
Message::GripColorChanged(color) => {
|
Message::GripColorChanged(color) => {
|
||||||
self.model_space.grip_color = color;
|
self.model_space.grip_color = color;
|
||||||
self.sync_model_space_theme(false);
|
self.sync_model_space_theme(false);
|
||||||
|
|||||||
@@ -958,6 +958,7 @@ bg={bg_ms:.1}ms n={view_count}"
|
|||||||
|| c.is_selection_gathering()
|
|| c.is_selection_gathering()
|
||||||
}),
|
}),
|
||||||
snap_color: self.snap_marker_color,
|
snap_color: self.snap_marker_color,
|
||||||
|
snap_size: self.model_space.snap_marker_size as f32,
|
||||||
},
|
},
|
||||||
// MATCHPROP paints properties onto destinations; it gets the
|
// MATCHPROP paints properties onto destinations; it gets the
|
||||||
// paintbrush cursor instead of the crosshair.
|
// paintbrush cursor instead of the crosshair.
|
||||||
|
|||||||
@@ -5141,6 +5141,7 @@ pub(super) fn message_attribute(source: &str) -> Option<(&'static str, &'static
|
|||||||
"Load Linetypes" => Some(("common", "load-linetypes")),
|
"Load Linetypes" => Some(("common", "load-linetypes")),
|
||||||
"Requires two positive values (x,y) or one for both." => Some(("common", "requires-two-positive-values")),
|
"Requires two positive values (x,y) or one for both." => Some(("common", "requires-two-positive-values")),
|
||||||
"Snap marker color" => Some(("common", "snap-marker-color")),
|
"Snap marker color" => Some(("common", "snap-marker-color")),
|
||||||
|
"Snap marker size" => Some(("common", "snap-marker-size")),
|
||||||
"Command line text color" => Some(("common", "command-line-text-color")),
|
"Command line text color" => Some(("common", "command-line-text-color")),
|
||||||
"Operand" => Some(("common", "operand")),
|
"Operand" => Some(("common", "operand")),
|
||||||
"{added} linetype(s) loaded." => Some(("common", "linetypes-loaded")),
|
"{added} linetype(s) loaded." => Some(("common", "linetypes-loaded")),
|
||||||
|
|||||||
+324
-315
@@ -307,6 +307,8 @@ pub struct CrosshairOptions {
|
|||||||
/// Explicit object-snap marker colour; `None` picks one that reads on
|
/// Explicit object-snap marker colour; `None` picks one that reads on
|
||||||
/// the canvas.
|
/// the canvas.
|
||||||
pub snap_color: Option<[u8; 3]>,
|
pub snap_color: Option<[u8; 3]>,
|
||||||
|
/// Object-snap marker half-size in pixels (SNAPMARKERSIZE, 1–20).
|
||||||
|
pub snap_size: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Rendering style for the viewport grid.
|
/// Rendering style for the viewport grid.
|
||||||
@@ -1679,110 +1681,231 @@ impl canvas::Program<Message> for SelectionCanvas {
|
|||||||
style: canvas::Style::Solid(marker),
|
style: canvas::Style::Solid(marker),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
match snap_type {
|
// SNAPMARKERSIZE scales the glyphs drawn for the default 5 px.
|
||||||
SnapType::ObjectPick => {
|
let scale = self.crosshair.snap_size.clamp(1.0, 20.0) / 5.0;
|
||||||
// Target box + center dot (object-acquisition glyph).
|
frame.with_save(|frame| {
|
||||||
let h = 7.0_f32;
|
frame.translate(iced::Vector::new(sp.x, sp.y));
|
||||||
let rect = canvas::Path::rectangle(
|
frame.scale(scale);
|
||||||
Point::new(sp.x - h, sp.y - h),
|
frame.translate(iced::Vector::new(-sp.x, -sp.y));
|
||||||
Size::new(h * 2.0, h * 2.0),
|
match snap_type {
|
||||||
);
|
SnapType::ObjectPick => {
|
||||||
frame.stroke(&rect, stroke.clone());
|
// Target box + center dot (object-acquisition glyph).
|
||||||
let r = 3.0_f32;
|
let h = 7.0_f32;
|
||||||
frame.fill(
|
let rect = canvas::Path::rectangle(
|
||||||
&canvas::Path::circle(sp, r),
|
Point::new(sp.x - h, sp.y - h),
|
||||||
Color {
|
Size::new(h * 2.0, h * 2.0),
|
||||||
r: 0.95,
|
);
|
||||||
g: 0.50,
|
frame.stroke(&rect, stroke.clone());
|
||||||
b: 0.08,
|
let r = 3.0_f32;
|
||||||
a: 0.85,
|
frame.fill(
|
||||||
},
|
&canvas::Path::circle(sp, r),
|
||||||
);
|
Color {
|
||||||
}
|
r: 0.95,
|
||||||
SnapType::Endpoint => {
|
g: 0.50,
|
||||||
let h = 5.0_f32;
|
b: 0.08,
|
||||||
let rect = canvas::Path::rectangle(
|
a: 0.85,
|
||||||
Point::new(sp.x - h, sp.y - h),
|
},
|
||||||
Size::new(h * 2.0, h * 2.0),
|
);
|
||||||
);
|
}
|
||||||
frame.stroke(&rect, stroke);
|
SnapType::Endpoint => {
|
||||||
}
|
let h = 5.0_f32;
|
||||||
SnapType::Midpoint => {
|
let rect = canvas::Path::rectangle(
|
||||||
let r = 6.0_f32;
|
Point::new(sp.x - h, sp.y - h),
|
||||||
let path = canvas::Path::new(|b| {
|
Size::new(h * 2.0, h * 2.0),
|
||||||
b.move_to(Point::new(sp.x, sp.y - r));
|
);
|
||||||
b.line_to(Point::new(sp.x + r * 0.866, sp.y + r * 0.5));
|
frame.stroke(&rect, stroke);
|
||||||
b.line_to(Point::new(sp.x - r * 0.866, sp.y + r * 0.5));
|
}
|
||||||
b.close();
|
SnapType::Midpoint => {
|
||||||
});
|
let r = 6.0_f32;
|
||||||
frame.stroke(&path, stroke);
|
let path = canvas::Path::new(|b| {
|
||||||
}
|
b.move_to(Point::new(sp.x, sp.y - r));
|
||||||
SnapType::Center => {
|
b.line_to(Point::new(sp.x + r * 0.866, sp.y + r * 0.5));
|
||||||
let r = 5.5_f32;
|
b.line_to(Point::new(sp.x - r * 0.866, sp.y + r * 0.5));
|
||||||
let path = canvas::Path::circle(sp, r);
|
b.close();
|
||||||
frame.stroke(&path, stroke);
|
});
|
||||||
}
|
frame.stroke(&path, stroke);
|
||||||
SnapType::GeometricCenter => {
|
}
|
||||||
// Pentagon around a centre dot: the area centroid.
|
SnapType::Center => {
|
||||||
let r = 6.5_f32;
|
let r = 5.5_f32;
|
||||||
let path = canvas::Path::new(|b| {
|
let path = canvas::Path::circle(sp, r);
|
||||||
for k in 0..5 {
|
frame.stroke(&path, stroke);
|
||||||
let a = -std::f32::consts::FRAC_PI_2
|
}
|
||||||
+ k as f32 * std::f32::consts::TAU / 5.0;
|
SnapType::GeometricCenter => {
|
||||||
let p = Point::new(sp.x + r * a.cos(), sp.y + r * a.sin());
|
// Pentagon around a centre dot: the area centroid.
|
||||||
if k == 0 {
|
let r = 6.5_f32;
|
||||||
b.move_to(p);
|
let path = canvas::Path::new(|b| {
|
||||||
} else {
|
for k in 0..5 {
|
||||||
b.line_to(p);
|
let a = -std::f32::consts::FRAC_PI_2
|
||||||
|
+ k as f32 * std::f32::consts::TAU / 5.0;
|
||||||
|
let p = Point::new(sp.x + r * a.cos(), sp.y + r * a.sin());
|
||||||
|
if k == 0 {
|
||||||
|
b.move_to(p);
|
||||||
|
} else {
|
||||||
|
b.line_to(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
b.close();
|
||||||
|
});
|
||||||
|
frame.stroke(&path, stroke.clone());
|
||||||
|
frame.fill(&canvas::Path::circle(sp, 1.6), marker);
|
||||||
|
}
|
||||||
|
SnapType::Node => {
|
||||||
|
// Circle with an inscribed X.
|
||||||
|
let r = 5.5_f32;
|
||||||
|
let cpath = canvas::Path::circle(sp, r);
|
||||||
|
frame.stroke(&cpath, stroke.clone());
|
||||||
|
let d = r * std::f32::consts::FRAC_1_SQRT_2;
|
||||||
|
let x1 = canvas::Path::new(|b| {
|
||||||
|
b.move_to(Point::new(sp.x - d, sp.y - d));
|
||||||
|
b.line_to(Point::new(sp.x + d, sp.y + d));
|
||||||
|
});
|
||||||
|
let x2 = canvas::Path::new(|b| {
|
||||||
|
b.move_to(Point::new(sp.x - d, sp.y + d));
|
||||||
|
b.line_to(Point::new(sp.x + d, sp.y - d));
|
||||||
|
});
|
||||||
|
frame.stroke(&x1, stroke.clone());
|
||||||
|
frame.stroke(&x2, stroke);
|
||||||
|
}
|
||||||
|
SnapType::Quadrant => {
|
||||||
|
let r = 6.0_f32;
|
||||||
|
let path = canvas::Path::new(|b| {
|
||||||
|
b.move_to(Point::new(sp.x, sp.y - r));
|
||||||
|
b.line_to(Point::new(sp.x + r, sp.y));
|
||||||
|
b.line_to(Point::new(sp.x, sp.y + r));
|
||||||
|
b.line_to(Point::new(sp.x - r, sp.y));
|
||||||
|
b.close();
|
||||||
|
});
|
||||||
|
frame.stroke(&path, stroke);
|
||||||
|
}
|
||||||
|
SnapType::Intersection => {
|
||||||
|
// An extended intersection sets one or two extension bases;
|
||||||
|
// draw a dashed guide from each endpoint through the crossing
|
||||||
|
// so both contributing extension paths stay visible. A real
|
||||||
|
// on-segment crossing carries no bases, so nothing draws here.
|
||||||
|
// (#247, #259)
|
||||||
|
for base in [self.snap_ext_base, self.snap_ext_base2]
|
||||||
|
.into_iter()
|
||||||
|
.flatten()
|
||||||
|
{
|
||||||
|
let dx = sp.x - base.x;
|
||||||
|
let dy = sp.y - base.y;
|
||||||
|
let len = (dx * dx + dy * dy).sqrt();
|
||||||
|
if len > 1e-3 {
|
||||||
|
let dash = canvas::Stroke {
|
||||||
|
line_dash: canvas::LineDash {
|
||||||
|
segments: &[4.0, 4.0],
|
||||||
|
offset: 0,
|
||||||
|
},
|
||||||
|
..canvas::Stroke::default().with_color(marker).with_width(1.0)
|
||||||
|
};
|
||||||
|
let tip = Point::new(sp.x + dx / len * 18.0, sp.y + dy / len * 18.0);
|
||||||
|
// `base` is a projected entity endpoint: clip before
|
||||||
|
// stroking (see `clip_seg`).
|
||||||
|
if let Some((a, b)) = clip_seg(base, tip, bounds) {
|
||||||
|
frame.stroke(&canvas::Path::line(a, b), dash);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
b.close();
|
let r = 5.0_f32;
|
||||||
});
|
let p1 = canvas::Path::new(|b| {
|
||||||
frame.stroke(&path, stroke.clone());
|
b.move_to(Point::new(sp.x - r, sp.y - r));
|
||||||
frame.fill(&canvas::Path::circle(sp, 1.6), marker);
|
b.line_to(Point::new(sp.x + r, sp.y + r));
|
||||||
}
|
});
|
||||||
SnapType::Node => {
|
let p2 = canvas::Path::new(|b| {
|
||||||
// Circle with an inscribed X.
|
b.move_to(Point::new(sp.x - r, sp.y + r));
|
||||||
let r = 5.5_f32;
|
b.line_to(Point::new(sp.x + r, sp.y - r));
|
||||||
let cpath = canvas::Path::circle(sp, r);
|
});
|
||||||
frame.stroke(&cpath, stroke.clone());
|
frame.stroke(&p1, stroke.clone());
|
||||||
let d = r * std::f32::consts::FRAC_1_SQRT_2;
|
frame.stroke(&p2, stroke);
|
||||||
let x1 = canvas::Path::new(|b| {
|
}
|
||||||
b.move_to(Point::new(sp.x - d, sp.y - d));
|
SnapType::ApparentIntersection => {
|
||||||
b.line_to(Point::new(sp.x + d, sp.y + d));
|
// X like Intersection, framed by a small square so the
|
||||||
});
|
// two are visually distinguishable.
|
||||||
let x2 = canvas::Path::new(|b| {
|
let r = 5.0_f32;
|
||||||
b.move_to(Point::new(sp.x - d, sp.y + d));
|
let rect = canvas::Path::rectangle(
|
||||||
b.line_to(Point::new(sp.x + d, sp.y - d));
|
Point::new(sp.x - r, sp.y - r),
|
||||||
});
|
Size::new(r * 2.0, r * 2.0),
|
||||||
frame.stroke(&x1, stroke.clone());
|
);
|
||||||
frame.stroke(&x2, stroke);
|
frame.stroke(&rect, stroke.clone());
|
||||||
}
|
let xr = r - 1.5;
|
||||||
SnapType::Quadrant => {
|
let p1 = canvas::Path::new(|b| {
|
||||||
let r = 6.0_f32;
|
b.move_to(Point::new(sp.x - xr, sp.y - xr));
|
||||||
let path = canvas::Path::new(|b| {
|
b.line_to(Point::new(sp.x + xr, sp.y + xr));
|
||||||
b.move_to(Point::new(sp.x, sp.y - r));
|
});
|
||||||
b.line_to(Point::new(sp.x + r, sp.y));
|
let p2 = canvas::Path::new(|b| {
|
||||||
b.line_to(Point::new(sp.x, sp.y + r));
|
b.move_to(Point::new(sp.x - xr, sp.y + xr));
|
||||||
b.line_to(Point::new(sp.x - r, sp.y));
|
b.line_to(Point::new(sp.x + xr, sp.y - xr));
|
||||||
b.close();
|
});
|
||||||
});
|
frame.stroke(&p1, stroke.clone());
|
||||||
frame.stroke(&path, stroke);
|
frame.stroke(&p2, stroke);
|
||||||
}
|
}
|
||||||
SnapType::Intersection => {
|
SnapType::Insertion => {
|
||||||
// An extended intersection sets one or two extension bases;
|
// Two overlapping rectangles (a small "tag" glyph).
|
||||||
// draw a dashed guide from each endpoint through the crossing
|
let r = 5.0_f32;
|
||||||
// so both contributing extension paths stay visible. A real
|
let inner = canvas::Path::rectangle(
|
||||||
// on-segment crossing carries no bases, so nothing draws here.
|
Point::new(sp.x - r * 0.5, sp.y - r),
|
||||||
// (#247, #259)
|
Size::new(r, r * 2.0),
|
||||||
for base in [self.snap_ext_base, self.snap_ext_base2]
|
);
|
||||||
.into_iter()
|
let outer = canvas::Path::rectangle(
|
||||||
.flatten()
|
Point::new(sp.x - r, sp.y - r * 0.5),
|
||||||
{
|
Size::new(r * 2.0, r),
|
||||||
let dx = sp.x - base.x;
|
);
|
||||||
let dy = sp.y - base.y;
|
frame.stroke(&outer, stroke.clone());
|
||||||
let len = (dx * dx + dy * dy).sqrt();
|
frame.stroke(&inner, stroke);
|
||||||
if len > 1e-3 {
|
}
|
||||||
|
SnapType::Perpendicular => {
|
||||||
|
// Right-angle hook in the lower-left quadrant.
|
||||||
|
let r = 6.0_f32;
|
||||||
|
let p = canvas::Path::new(|b| {
|
||||||
|
b.move_to(Point::new(sp.x - r, sp.y - r));
|
||||||
|
b.line_to(Point::new(sp.x - r, sp.y + r));
|
||||||
|
b.line_to(Point::new(sp.x + r, sp.y + r));
|
||||||
|
});
|
||||||
|
let foot = canvas::Path::new(|b| {
|
||||||
|
b.move_to(Point::new(sp.x - r, sp.y));
|
||||||
|
b.line_to(Point::new(sp.x, sp.y));
|
||||||
|
b.line_to(Point::new(sp.x, sp.y + r));
|
||||||
|
});
|
||||||
|
frame.stroke(&p, stroke.clone());
|
||||||
|
frame.stroke(&foot, stroke);
|
||||||
|
}
|
||||||
|
SnapType::Tangent => {
|
||||||
|
// Circle with a tangent bar across the top.
|
||||||
|
let r = 5.5_f32;
|
||||||
|
let c = canvas::Path::circle(sp, r);
|
||||||
|
frame.stroke(&c, stroke.clone());
|
||||||
|
let bar = canvas::Path::new(|b| {
|
||||||
|
b.move_to(Point::new(sp.x - r, sp.y - r));
|
||||||
|
b.line_to(Point::new(sp.x + r, sp.y - r));
|
||||||
|
});
|
||||||
|
frame.stroke(&bar, stroke);
|
||||||
|
}
|
||||||
|
SnapType::Nearest => {
|
||||||
|
// Bowtie / hourglass — two opposed triangles meeting at sp.
|
||||||
|
let r = 5.5_f32;
|
||||||
|
let path = canvas::Path::new(|b| {
|
||||||
|
b.move_to(Point::new(sp.x - r, sp.y - r));
|
||||||
|
b.line_to(Point::new(sp.x + r, sp.y - r));
|
||||||
|
b.line_to(Point::new(sp.x - r, sp.y + r));
|
||||||
|
b.line_to(Point::new(sp.x + r, sp.y + r));
|
||||||
|
b.close();
|
||||||
|
});
|
||||||
|
frame.stroke(&path, stroke);
|
||||||
|
}
|
||||||
|
SnapType::Extension => {
|
||||||
|
// Unit direction from the endpoint the snap extends from
|
||||||
|
// toward the snap point, so the guide line and the three
|
||||||
|
// dots follow the actual extension path (#238).
|
||||||
|
let dir = self.snap_ext_base.and_then(|base| {
|
||||||
|
let dx = sp.x - base.x;
|
||||||
|
let dy = sp.y - base.y;
|
||||||
|
let len = (dx * dx + dy * dy).sqrt();
|
||||||
|
(len > 1e-3).then(|| (base, Point::new(dx / len, dy / len)))
|
||||||
|
});
|
||||||
|
// Dashed guide line from that endpoint, through the snap
|
||||||
|
// point and a little beyond, so the extension path is
|
||||||
|
// visible as the cursor tracks along it.
|
||||||
|
if let Some((base, u)) = dir {
|
||||||
let dash = canvas::Stroke {
|
let dash = canvas::Stroke {
|
||||||
line_dash: canvas::LineDash {
|
line_dash: canvas::LineDash {
|
||||||
segments: &[4.0, 4.0],
|
segments: &[4.0, 4.0],
|
||||||
@@ -1790,229 +1913,115 @@ impl canvas::Program<Message> for SelectionCanvas {
|
|||||||
},
|
},
|
||||||
..canvas::Stroke::default().with_color(marker).with_width(1.0)
|
..canvas::Stroke::default().with_color(marker).with_width(1.0)
|
||||||
};
|
};
|
||||||
let tip = Point::new(sp.x + dx / len * 18.0, sp.y + dy / len * 18.0);
|
let tip = Point::new(sp.x + u.x * 18.0, sp.y + u.y * 18.0);
|
||||||
// `base` is a projected entity endpoint: clip before
|
// `base` is a projected entity endpoint: clip before
|
||||||
// stroking (see `clip_seg`).
|
// stroking (see `clip_seg`).
|
||||||
if let Some((a, b)) = clip_seg(base, tip, bounds) {
|
if let Some((a, b)) = clip_seg(base, tip, bounds) {
|
||||||
frame.stroke(&canvas::Path::line(a, b), dash);
|
frame.stroke(&canvas::Path::line(a, b), dash);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
// Three dots at the snap point, strung along the extension
|
||||||
let r = 5.0_f32;
|
// direction (horizontal fallback when the base is unknown).
|
||||||
let p1 = canvas::Path::new(|b| {
|
let u = dir.map(|(_, u)| u).unwrap_or(Point::new(1.0, 0.0));
|
||||||
b.move_to(Point::new(sp.x - r, sp.y - r));
|
let r = 1.4_f32;
|
||||||
b.line_to(Point::new(sp.x + r, sp.y + r));
|
for k in [-7.0_f32, 0.0, 7.0] {
|
||||||
});
|
let dot =
|
||||||
let p2 = canvas::Path::new(|b| {
|
canvas::Path::circle(Point::new(sp.x + u.x * k, sp.y + u.y * k), r);
|
||||||
b.move_to(Point::new(sp.x - r, sp.y + r));
|
frame.fill(&dot, marker);
|
||||||
b.line_to(Point::new(sp.x + r, sp.y - r));
|
|
||||||
});
|
|
||||||
frame.stroke(&p1, stroke.clone());
|
|
||||||
frame.stroke(&p2, stroke);
|
|
||||||
}
|
|
||||||
SnapType::ApparentIntersection => {
|
|
||||||
// X like Intersection, framed by a small square so the
|
|
||||||
// two are visually distinguishable.
|
|
||||||
let r = 5.0_f32;
|
|
||||||
let rect = canvas::Path::rectangle(
|
|
||||||
Point::new(sp.x - r, sp.y - r),
|
|
||||||
Size::new(r * 2.0, r * 2.0),
|
|
||||||
);
|
|
||||||
frame.stroke(&rect, stroke.clone());
|
|
||||||
let xr = r - 1.5;
|
|
||||||
let p1 = canvas::Path::new(|b| {
|
|
||||||
b.move_to(Point::new(sp.x - xr, sp.y - xr));
|
|
||||||
b.line_to(Point::new(sp.x + xr, sp.y + xr));
|
|
||||||
});
|
|
||||||
let p2 = canvas::Path::new(|b| {
|
|
||||||
b.move_to(Point::new(sp.x - xr, sp.y + xr));
|
|
||||||
b.line_to(Point::new(sp.x + xr, sp.y - xr));
|
|
||||||
});
|
|
||||||
frame.stroke(&p1, stroke.clone());
|
|
||||||
frame.stroke(&p2, stroke);
|
|
||||||
}
|
|
||||||
SnapType::Insertion => {
|
|
||||||
// Two overlapping rectangles (a small "tag" glyph).
|
|
||||||
let r = 5.0_f32;
|
|
||||||
let inner = canvas::Path::rectangle(
|
|
||||||
Point::new(sp.x - r * 0.5, sp.y - r),
|
|
||||||
Size::new(r, r * 2.0),
|
|
||||||
);
|
|
||||||
let outer = canvas::Path::rectangle(
|
|
||||||
Point::new(sp.x - r, sp.y - r * 0.5),
|
|
||||||
Size::new(r * 2.0, r),
|
|
||||||
);
|
|
||||||
frame.stroke(&outer, stroke.clone());
|
|
||||||
frame.stroke(&inner, stroke);
|
|
||||||
}
|
|
||||||
SnapType::Perpendicular => {
|
|
||||||
// Right-angle hook in the lower-left quadrant.
|
|
||||||
let r = 6.0_f32;
|
|
||||||
let p = canvas::Path::new(|b| {
|
|
||||||
b.move_to(Point::new(sp.x - r, sp.y - r));
|
|
||||||
b.line_to(Point::new(sp.x - r, sp.y + r));
|
|
||||||
b.line_to(Point::new(sp.x + r, sp.y + r));
|
|
||||||
});
|
|
||||||
let foot = canvas::Path::new(|b| {
|
|
||||||
b.move_to(Point::new(sp.x - r, sp.y));
|
|
||||||
b.line_to(Point::new(sp.x, sp.y));
|
|
||||||
b.line_to(Point::new(sp.x, sp.y + r));
|
|
||||||
});
|
|
||||||
frame.stroke(&p, stroke.clone());
|
|
||||||
frame.stroke(&foot, stroke);
|
|
||||||
}
|
|
||||||
SnapType::Tangent => {
|
|
||||||
// Circle with a tangent bar across the top.
|
|
||||||
let r = 5.5_f32;
|
|
||||||
let c = canvas::Path::circle(sp, r);
|
|
||||||
frame.stroke(&c, stroke.clone());
|
|
||||||
let bar = canvas::Path::new(|b| {
|
|
||||||
b.move_to(Point::new(sp.x - r, sp.y - r));
|
|
||||||
b.line_to(Point::new(sp.x + r, sp.y - r));
|
|
||||||
});
|
|
||||||
frame.stroke(&bar, stroke);
|
|
||||||
}
|
|
||||||
SnapType::Nearest => {
|
|
||||||
// Bowtie / hourglass — two opposed triangles meeting at sp.
|
|
||||||
let r = 5.5_f32;
|
|
||||||
let path = canvas::Path::new(|b| {
|
|
||||||
b.move_to(Point::new(sp.x - r, sp.y - r));
|
|
||||||
b.line_to(Point::new(sp.x + r, sp.y - r));
|
|
||||||
b.line_to(Point::new(sp.x - r, sp.y + r));
|
|
||||||
b.line_to(Point::new(sp.x + r, sp.y + r));
|
|
||||||
b.close();
|
|
||||||
});
|
|
||||||
frame.stroke(&path, stroke);
|
|
||||||
}
|
|
||||||
SnapType::Extension => {
|
|
||||||
// Unit direction from the endpoint the snap extends from
|
|
||||||
// toward the snap point, so the guide line and the three
|
|
||||||
// dots follow the actual extension path (#238).
|
|
||||||
let dir = self.snap_ext_base.and_then(|base| {
|
|
||||||
let dx = sp.x - base.x;
|
|
||||||
let dy = sp.y - base.y;
|
|
||||||
let len = (dx * dx + dy * dy).sqrt();
|
|
||||||
(len > 1e-3).then(|| (base, Point::new(dx / len, dy / len)))
|
|
||||||
});
|
|
||||||
// Dashed guide line from that endpoint, through the snap
|
|
||||||
// point and a little beyond, so the extension path is
|
|
||||||
// visible as the cursor tracks along it.
|
|
||||||
if let Some((base, u)) = dir {
|
|
||||||
let dash = canvas::Stroke {
|
|
||||||
line_dash: canvas::LineDash {
|
|
||||||
segments: &[4.0, 4.0],
|
|
||||||
offset: 0,
|
|
||||||
},
|
|
||||||
..canvas::Stroke::default().with_color(marker).with_width(1.0)
|
|
||||||
};
|
|
||||||
let tip = Point::new(sp.x + u.x * 18.0, sp.y + u.y * 18.0);
|
|
||||||
// `base` is a projected entity endpoint: clip before
|
|
||||||
// stroking (see `clip_seg`).
|
|
||||||
if let Some((a, b)) = clip_seg(base, tip, bounds) {
|
|
||||||
frame.stroke(&canvas::Path::line(a, b), dash);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Three dots at the snap point, strung along the extension
|
SnapType::Parallel => {
|
||||||
// direction (horizontal fallback when the base is unknown).
|
// Two short parallel diagonal bars.
|
||||||
let u = dir.map(|(_, u)| u).unwrap_or(Point::new(1.0, 0.0));
|
let r = 6.0_f32;
|
||||||
let r = 1.4_f32;
|
let off = 3.0_f32;
|
||||||
for k in [-7.0_f32, 0.0, 7.0] {
|
let b1 = canvas::Path::new(|b| {
|
||||||
let dot =
|
b.move_to(Point::new(sp.x - r - off, sp.y + r));
|
||||||
canvas::Path::circle(Point::new(sp.x + u.x * k, sp.y + u.y * k), r);
|
b.line_to(Point::new(sp.x + r - off, sp.y - r));
|
||||||
frame.fill(&dot, marker);
|
});
|
||||||
|
let b2 = canvas::Path::new(|b| {
|
||||||
|
b.move_to(Point::new(sp.x - r + off, sp.y + r));
|
||||||
|
b.line_to(Point::new(sp.x + r + off, sp.y - r));
|
||||||
|
});
|
||||||
|
frame.stroke(&b1, stroke.clone());
|
||||||
|
frame.stroke(&b2, stroke);
|
||||||
|
}
|
||||||
|
SnapType::Grid => {
|
||||||
|
let arm = 4.0_f32;
|
||||||
|
let h = canvas::Path::new(|b| {
|
||||||
|
b.move_to(Point::new(sp.x - arm, sp.y));
|
||||||
|
b.line_to(Point::new(sp.x + arm, sp.y));
|
||||||
|
});
|
||||||
|
let v = canvas::Path::new(|b| {
|
||||||
|
b.move_to(Point::new(sp.x, sp.y - arm));
|
||||||
|
b.line_to(Point::new(sp.x, sp.y + arm));
|
||||||
|
});
|
||||||
|
frame.stroke(&h, stroke.clone());
|
||||||
|
frame.stroke(&v, stroke);
|
||||||
|
}
|
||||||
|
SnapType::Vertex => {
|
||||||
|
// Filled square: the solid rhyme of Endpoint's hollow box.
|
||||||
|
let h = 5.0_f32;
|
||||||
|
frame.fill(
|
||||||
|
&canvas::Path::rectangle(
|
||||||
|
Point::new(sp.x - h, sp.y - h),
|
||||||
|
Size::new(h * 2.0, h * 2.0),
|
||||||
|
),
|
||||||
|
marker,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
SnapType::EdgeMidpoint => {
|
||||||
|
// Filled triangle: the solid rhyme of Midpoint's outline.
|
||||||
|
let r = 6.0_f32;
|
||||||
|
let path = canvas::Path::new(|b| {
|
||||||
|
b.move_to(Point::new(sp.x, sp.y - r));
|
||||||
|
b.line_to(Point::new(sp.x + r * 0.866, sp.y + r * 0.5));
|
||||||
|
b.line_to(Point::new(sp.x - r * 0.866, sp.y + r * 0.5));
|
||||||
|
b.close();
|
||||||
|
});
|
||||||
|
frame.fill(&path, marker);
|
||||||
|
}
|
||||||
|
SnapType::FaceCenter => {
|
||||||
|
// Filled disc: the solid rhyme of Center's outline.
|
||||||
|
frame.fill(&canvas::Path::circle(sp, 5.5_f32), marker);
|
||||||
|
}
|
||||||
|
SnapType::Knot => {
|
||||||
|
// Filled diamond: distinct from Quadrant's outline.
|
||||||
|
let r = 5.5_f32;
|
||||||
|
let path = canvas::Path::new(|b| {
|
||||||
|
b.move_to(Point::new(sp.x, sp.y - r));
|
||||||
|
b.line_to(Point::new(sp.x + r, sp.y));
|
||||||
|
b.line_to(Point::new(sp.x, sp.y + r));
|
||||||
|
b.line_to(Point::new(sp.x - r, sp.y));
|
||||||
|
b.close();
|
||||||
|
});
|
||||||
|
frame.fill(&path, marker);
|
||||||
|
}
|
||||||
|
SnapType::FacePerpendicular => {
|
||||||
|
// Right-angle hook like the 2D marker, plus a filled foot
|
||||||
|
// dot marking the face contact.
|
||||||
|
let r = 6.0_f32;
|
||||||
|
let p = canvas::Path::new(|b| {
|
||||||
|
b.move_to(Point::new(sp.x - r, sp.y - r));
|
||||||
|
b.line_to(Point::new(sp.x - r, sp.y + r));
|
||||||
|
b.line_to(Point::new(sp.x + r, sp.y + r));
|
||||||
|
});
|
||||||
|
frame.stroke(&p, stroke.clone());
|
||||||
|
frame.fill(&canvas::Path::circle(sp, 2.0_f32), marker);
|
||||||
|
}
|
||||||
|
SnapType::NearestFace => {
|
||||||
|
// Filled bowtie: the solid rhyme of Nearest's outline.
|
||||||
|
let r = 5.5_f32;
|
||||||
|
let path = canvas::Path::new(|b| {
|
||||||
|
b.move_to(Point::new(sp.x - r, sp.y - r));
|
||||||
|
b.line_to(Point::new(sp.x + r, sp.y - r));
|
||||||
|
b.line_to(Point::new(sp.x - r, sp.y + r));
|
||||||
|
b.line_to(Point::new(sp.x + r, sp.y + r));
|
||||||
|
b.close();
|
||||||
|
});
|
||||||
|
frame.fill(&path, marker);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SnapType::Parallel => {
|
});
|
||||||
// Two short parallel diagonal bars.
|
|
||||||
let r = 6.0_f32;
|
|
||||||
let off = 3.0_f32;
|
|
||||||
let b1 = canvas::Path::new(|b| {
|
|
||||||
b.move_to(Point::new(sp.x - r - off, sp.y + r));
|
|
||||||
b.line_to(Point::new(sp.x + r - off, sp.y - r));
|
|
||||||
});
|
|
||||||
let b2 = canvas::Path::new(|b| {
|
|
||||||
b.move_to(Point::new(sp.x - r + off, sp.y + r));
|
|
||||||
b.line_to(Point::new(sp.x + r + off, sp.y - r));
|
|
||||||
});
|
|
||||||
frame.stroke(&b1, stroke.clone());
|
|
||||||
frame.stroke(&b2, stroke);
|
|
||||||
}
|
|
||||||
SnapType::Grid => {
|
|
||||||
let arm = 4.0_f32;
|
|
||||||
let h = canvas::Path::new(|b| {
|
|
||||||
b.move_to(Point::new(sp.x - arm, sp.y));
|
|
||||||
b.line_to(Point::new(sp.x + arm, sp.y));
|
|
||||||
});
|
|
||||||
let v = canvas::Path::new(|b| {
|
|
||||||
b.move_to(Point::new(sp.x, sp.y - arm));
|
|
||||||
b.line_to(Point::new(sp.x, sp.y + arm));
|
|
||||||
});
|
|
||||||
frame.stroke(&h, stroke.clone());
|
|
||||||
frame.stroke(&v, stroke);
|
|
||||||
}
|
|
||||||
SnapType::Vertex => {
|
|
||||||
// Filled square: the solid rhyme of Endpoint's hollow box.
|
|
||||||
let h = 5.0_f32;
|
|
||||||
frame.fill(
|
|
||||||
&canvas::Path::rectangle(
|
|
||||||
Point::new(sp.x - h, sp.y - h),
|
|
||||||
Size::new(h * 2.0, h * 2.0),
|
|
||||||
),
|
|
||||||
marker,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
SnapType::EdgeMidpoint => {
|
|
||||||
// Filled triangle: the solid rhyme of Midpoint's outline.
|
|
||||||
let r = 6.0_f32;
|
|
||||||
let path = canvas::Path::new(|b| {
|
|
||||||
b.move_to(Point::new(sp.x, sp.y - r));
|
|
||||||
b.line_to(Point::new(sp.x + r * 0.866, sp.y + r * 0.5));
|
|
||||||
b.line_to(Point::new(sp.x - r * 0.866, sp.y + r * 0.5));
|
|
||||||
b.close();
|
|
||||||
});
|
|
||||||
frame.fill(&path, marker);
|
|
||||||
}
|
|
||||||
SnapType::FaceCenter => {
|
|
||||||
// Filled disc: the solid rhyme of Center's outline.
|
|
||||||
frame.fill(&canvas::Path::circle(sp, 5.5_f32), marker);
|
|
||||||
}
|
|
||||||
SnapType::Knot => {
|
|
||||||
// Filled diamond: distinct from Quadrant's outline.
|
|
||||||
let r = 5.5_f32;
|
|
||||||
let path = canvas::Path::new(|b| {
|
|
||||||
b.move_to(Point::new(sp.x, sp.y - r));
|
|
||||||
b.line_to(Point::new(sp.x + r, sp.y));
|
|
||||||
b.line_to(Point::new(sp.x, sp.y + r));
|
|
||||||
b.line_to(Point::new(sp.x - r, sp.y));
|
|
||||||
b.close();
|
|
||||||
});
|
|
||||||
frame.fill(&path, marker);
|
|
||||||
}
|
|
||||||
SnapType::FacePerpendicular => {
|
|
||||||
// Right-angle hook like the 2D marker, plus a filled foot
|
|
||||||
// dot marking the face contact.
|
|
||||||
let r = 6.0_f32;
|
|
||||||
let p = canvas::Path::new(|b| {
|
|
||||||
b.move_to(Point::new(sp.x - r, sp.y - r));
|
|
||||||
b.line_to(Point::new(sp.x - r, sp.y + r));
|
|
||||||
b.line_to(Point::new(sp.x + r, sp.y + r));
|
|
||||||
});
|
|
||||||
frame.stroke(&p, stroke.clone());
|
|
||||||
frame.fill(&canvas::Path::circle(sp, 2.0_f32), marker);
|
|
||||||
}
|
|
||||||
SnapType::NearestFace => {
|
|
||||||
// Filled bowtie: the solid rhyme of Nearest's outline.
|
|
||||||
let r = 5.5_f32;
|
|
||||||
let path = canvas::Path::new(|b| {
|
|
||||||
b.move_to(Point::new(sp.x - r, sp.y - r));
|
|
||||||
b.line_to(Point::new(sp.x + r, sp.y - r));
|
|
||||||
b.line_to(Point::new(sp.x - r, sp.y + r));
|
|
||||||
b.line_to(Point::new(sp.x + r, sp.y + r));
|
|
||||||
b.close();
|
|
||||||
});
|
|
||||||
frame.fill(&path, marker);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── CAD crosshair cursor ──────────────────────────────────────────────
|
// ── CAD crosshair cursor ──────────────────────────────────────────────
|
||||||
|
|||||||
@@ -1578,6 +1578,22 @@ pub fn view_window<'a>(
|
|||||||
]
|
]
|
||||||
.spacing(10)
|
.spacing(10)
|
||||||
.align_y(iced::Center),
|
.align_y(iced::Center),
|
||||||
|
Space::new().height(14),
|
||||||
|
row![
|
||||||
|
text(crate::t!("Snap marker size")).size(12).width(150),
|
||||||
|
slider(
|
||||||
|
1..=20,
|
||||||
|
model_space.snap_marker_size.clamp(1, 20),
|
||||||
|
Message::SnapMarkerSizeChanged,
|
||||||
|
)
|
||||||
|
.step(1)
|
||||||
|
.width(Fill),
|
||||||
|
text(format!("{} px", model_space.snap_marker_size.clamp(1, 20)))
|
||||||
|
.size(11)
|
||||||
|
.width(44),
|
||||||
|
]
|
||||||
|
.spacing(10)
|
||||||
|
.align_y(iced::Center),
|
||||||
Space::new().height(24),
|
Space::new().height(24),
|
||||||
text(crate::t!("Snap and Grid")).size(15),
|
text(crate::t!("Snap and Grid")).size(15),
|
||||||
Space::new().height(10),
|
Space::new().height(10),
|
||||||
|
|||||||
Reference in new issue
Block a user