feat(styles): overhaul style managers

Unify editor layouts, live previews, comparisons, read-only behavior, and localized controls across all named style managers.

Refs #629
This commit is contained in:
Hakan Seven 2026-08-03 02:01:47 +03:00
commit 25515fa33c
27 changed files with 5480 additions and 1636 deletions

View file

@ -3193,3 +3193,185 @@ catalog-mod-shortcuts-4c54bbb78e = ── __ocs_arg_MOD__-Tastenkürzel ──
catalog-custom-overrides-shortcuts-set-07be563dec = ── Benutzerdefinierte Überschreibungen (SHORTCUTS SET)
catalog-function-keys-b5a2df24e9 = ── Funktionstasten ────────────────────────────────────
catalog-other-keys-a882812cf2 = ── Weitere Tasten ─────────────────────────────────────
dimstyle-keep-text-between-extension-lines = Text immer zwischen Hilfslinien halten
dimstyle-angular-dimensions = Winkelbemaßungen
dimstyle-arc-length-symbol = Bogenlängensymbol
dimstyle-arrowheads = Pfeilspitzen
dimstyle-available-style = Verfügbarer Stil
dimstyle-baseline-spacing = Basislinienabstand
dimstyle-basic = Theoretisch genau
dimstyle-both-arrowheads = Beide Pfeilspitzen
dimstyle-center-mark = Mittelpunktmarkierung
dimstyle-center-mark-size = Größe der Mittelpunktmarkierung
dimstyle-center-marks = Mittelpunktmarkierungen
dimstyle-centerlines = Mittellinien
dimstyle-compare-with = Vergleichen mit
dimstyle-current-style = Aktueller Stil
dimstyle-deviation = Abweichung
dimstyle-different-sections = Abweichende Bereiche
dimstyle-dimension-line-color = Maßlinienfarbe
dimstyle-dimension-linetype = Maßlinientyp
dimstyle-dimension-lineweight = Maßlinienstärke
dimstyle-display-alternate-units = Alternative Einheiten anzeigen
dimstyle-draw-dimension-line-between-extension-lines = Maßlinie zwischen Hilfslinien zeichnen
dimstyle-extend-beyond-dimension-line = Über Maßlinie hinaus verlängern
dimstyle-extend-beyond-ticks = Über Schrägstriche hinaus verlängern
dimstyle-extension-line-color = Hilfslinienfarbe
dimstyle-extension-lineweight = Hilfslinienstärke
dimstyle-feet-and-inches = Fuß und Zoll
dimstyle-fine-tuning = Feinabstimmung
dimstyle-first-arrowhead = Erste Pfeilspitze
dimstyle-first-extension-linetype = Linientyp der ersten Hilfslinie
dimstyle-fit-options = Einpassungsoptionen
dimstyle-fixed-length = Feste Länge
dimstyle-fraction-format = Bruchformat
dimstyle-height-scale = Höhenskalierung
dimstyle-horizontal-placement = Horizontale Platzierung
dimstyle-keep-text-horizontal-inside = Text innen horizontal halten
dimstyle-keep-text-horizontal-outside = Text außen horizontal halten
dimstyle-leader-arrowhead = Führungslinien-Pfeilspitze
dimstyle-limits = Grenzmaße
dimstyle-linear-dimensions = Lineare Bemaßungen
dimstyle-lower-value = Unterer Wert
dimstyle-measurement-scale = Maßstab der Messwerte
dimstyle-measurement-template = Messwertvorlage
dimstyle-method = Methode
dimstyle-multiplier = Multiplikator
dimstyle-no-differences = Keine Unterschiede
dimstyle-not-applicable = Nicht zutreffend
dimstyle-offset-from-measured-point = Abstand vom gemessenen Punkt
dimstyle-place-text-manually = Text beim Erstellen der Bemaßung manuell platzieren
dimstyle-radius-jog-angle = Winkel des Radiusknicks (°)
dimstyle-read-left-to-right = Von links nach rechts lesen
dimstyle-referenced-read-only = Referenzierter Stil · Schreibgeschützt
dimstyle-round-off = Rundung
dimstyle-second-arrowhead = Zweite Pfeilspitze
dimstyle-second-extension-linetype = Linientyp der zweiten Hilfslinie
dimstyle-show-zero-feet-and-inches = Null Fuß und null Zoll anzeigen
dimstyle-show-zero-feet-suppress-zero-inches = Null Fuß anzeigen; null Zoll unterdrücken
dimstyle-suppress-arrows-when-no-fit = Pfeile unterdrücken, wenn sie nicht passen
dimstyle-suppress-first-dimension-line = Erste Maßlinie unterdrücken
dimstyle-suppress-first-extension-line = Erste Hilfslinie unterdrücken
dimstyle-suppress-second-dimension-line = Zweite Maßlinie unterdrücken
dimstyle-suppress-second-extension-line = Zweite Hilfslinie unterdrücken
dimstyle-suppress-zero-feet-and-inches = Null Fuß und null Zoll unterdrücken
dimstyle-suppress-zero-feet-show-zero-inches = Null Fuß unterdrücken; null Zoll anzeigen
dimstyle-symbols-and-arrows = Symbole und Pfeile
dimstyle-symmetrical = Symmetrisch
dimstyle-text-background = Texthintergrund
dimstyle-text-gap = Textabstand
dimstyle-fixed-text-height-note = Der gewählte Textstil legt die Höhe auf __ocs_arg_height__ fest.
dimstyle-tick-size = Schrägstrichgröße
dimstyle-tolerance-zero-suppression = Nullunterdrückung für Toleranzen
dimstyle-unit-format = Einheitenformat
dimstyle-upper-value = Oberer Wert
dimstyle-measurement-template-help = Verwenden Sie <> für den Messwert; Text davor und danach wird zum Präfix bzw. Suffix.
dimstyle-use-different-arrowheads = Unterschiedliche erste und zweite Pfeilspitzen verwenden
dimstyle-use-fixed-length-extension-lines = Hilfslinien mit fester Länge verwenden
dimstyle-used-in-drawing = In Zeichnung verwendet
dimstyle-vertical-offset = Vertikaler Abstand
dimstyle-vertical-placement = Vertikale Platzierung
dimstyle-vertical-position = Vertikale Position
dimstyle-when-space-is-limited = Bei begrenztem Platz
dimstyle-when-text-is-moved = Wenn Text verschoben wird
dimstyle-zero-suppression = Nullunterdrückung
dimstyle-add-a-leader = Führungslinie hinzufügen
dimstyle-automatic = Automatisch
dimstyle-by-block = Von Block
dimstyle-comma = Komma
dimstyle-degrees-minutes-seconds = Grad, Minuten, Sekunden
dimstyle-keep-dimension-line-with-text = Maßlinie mit Text verschieben
dimstyle-leading-and-trailing = Führende und nachfolgende Nullen
dimstyle-move-arrows-outside-first = Zuerst Pfeile nach außen verschieben
dimstyle-move-text-and-arrows-outside = Text und Pfeile nach außen verschieben
dimstyle-move-text-freely = Text frei verschieben
dimstyle-move-text-outside-first = Zuerst Text nach außen verschieben
dimstyle-period = Punkt
dimstyle-space = Leerzeichen
style-manager-alignment-spacing = Ausrichtungsabstand
style-manager-always-left-align = Immer links ausrichten
style-manager-attachment-direction = Anschlussrichtung
style-manager-background-fill-enabled = Hintergrundfüllung aktiviert
style-manager-big-font = Großschrift
style-manager-block-scale-x = Blockskalierung X
style-manager-block-scale-y = Blockskalierung Y
style-manager-block-scale-z = Blockskalierung Z
style-manager-borders = Rahmenlinien
style-manager-bottom-attachment = Unterer Anschluss
style-manager-break-gap-size = Unterbrechungsabstand
style-manager-caps-and-fill = Abschlüsse und Füllung
style-manager-content-type = Inhaltstyp
style-manager-data-row = Datenzeile
style-manager-data-type = Datentyp
style-manager-default-text = Standardtext
style-manager-different = Unterschiedlich
style-manager-display-joints = Verbindungen anzeigen
style-manager-drawing-height = Zeichnungshöhe
style-manager-drawing-scale = Zeichnungsmaßstab
style-manager-effects = Effekte
style-manager-elements = Elemente
style-manager-end-caps = Endabschlüsse
style-manager-fill-and-joints = Füllung und Verbindungen
style-manager-fill-enabled = Füllung aktiviert
style-manager-first-segment-angle = Winkel des ersten Segments
style-manager-fixed-height = Feste Höhe
style-manager-flow-direction = Flussrichtung
style-manager-font-file = Schriftdatei
style-manager-fonts = Schriftarten
style-manager-format-string = Formatzeichenfolge
style-manager-header = Kopfzeile
style-manager-header-row = Kopfzeile
style-manager-horizontal-margin = Horizontaler Rand
style-manager-inner-arcs = Innere Bögen
style-manager-inside-horizontal = Innen horizontal
style-manager-inside-vertical = Innen vertikal
style-manager-leader-draw-order = Zeichnungsreihenfolge der Führungslinie
style-manager-leader-note = Führungslinienhinweis
style-manager-left-attachment = Linker Anschluss
style-manager-line-color = Linienfarbe
style-manager-line-type = Linientyp
style-manager-line-weight = Linienstärke
style-manager-maximum-leader-points = Maximale Führungslinienpunkte
style-manager-multileader-draw-order = Zeichnungsreihenfolge der Multi-Führungslinie
style-manager-no-preview = Keine Vorschau
style-manager-oblique-angle = Schrägstellwinkel
style-manager-outer-arc = Außenbogen
style-manager-paper-height = Papierhöhe
style-manager-paper-text-height = Papiertexthöhe
style-manager-path-type = Pfadtyp
style-manager-right-attachment = Rechter Anschluss
style-manager-scale-factor = Skalierungsfaktor
style-manager-second-segment-angle = Winkel des zweiten Segments
style-manager-size-and-effects = Größe und Effekte
style-manager-start-caps = Startabschlüsse
style-manager-stroke-fonts = Strichschriftarten
style-manager-suppress-header-row = Kopfzeile unterdrücken
style-manager-suppress-title-row = Titelzeile unterdrücken
style-manager-system-font = Systemschriftart
style-manager-system-fonts = Systemschriftarten
style-manager-text-alignment = Textausrichtung
style-manager-text-angle = Textwinkel
style-manager-title-row = Titelzeile
style-manager-top-attachment = Oberer Anschluss
style-manager-unit-type = Einheitentyp
style-manager-vertical-margin = Vertikaler Rand
style-manager-font-family-placeholder = Schriftfamilie…
style-manager-bottom-to-top = Von unten nach oben
style-manager-arrowhead-first = Pfeilspitze zuerst
style-manager-content-first = Inhalt zuerst
style-manager-leader-first = Führungslinie zuerst
style-manager-straight = Gerade
style-manager-parallel-last-segment = Parallel zum letzten Segment
style-manager-top-of-top-line = Oberkante der obersten Zeile
style-manager-middle-of-top-line = Mitte der obersten Zeile
style-manager-middle-of-text = Textmitte
style-manager-middle-of-bottom-line = Mitte der untersten Zeile
style-manager-bottom-of-bottom-line = Unterkante der untersten Zeile
style-manager-bottom-line = Unterste Zeile
style-manager-underline-bottom-line = Unterste Zeile unterstreichen
style-manager-underline-top-line = Oberste Zeile unterstreichen
style-manager-underline-all-text = Gesamten Text unterstreichen
style-manager-center-of-text = Textzentrum
style-manager-center-of-text-overline = Textzentrum mit Oberstrich
style-manager-block-extents = Blockgrenzen
style-manager-base-point = Basispunkt

View file

@ -3195,3 +3195,185 @@ catalog-mod-shortcuts-4c54bbb78e = ── __ocs_arg_MOD__ Shortcuts ────
catalog-custom-overrides-shortcuts-set-07be563dec = ── Custom Overrides (SHORTCUTS SET) ──────────────────
catalog-function-keys-b5a2df24e9 = ── Function Keys ──────────────────────────────────────
catalog-other-keys-a882812cf2 = ── Other Keys ──────────────────────────────────────────
dimstyle-keep-text-between-extension-lines = Always keep text between extension lines
dimstyle-angular-dimensions = Angular dimensions
dimstyle-arc-length-symbol = Arc length symbol
dimstyle-arrowheads = Arrowheads
dimstyle-available-style = Available style
dimstyle-baseline-spacing = Baseline spacing
dimstyle-basic = Basic
dimstyle-both-arrowheads = Both arrowheads
dimstyle-center-mark = Center mark
dimstyle-center-mark-size = Center mark size
dimstyle-center-marks = Center marks
dimstyle-centerlines = Centerlines
dimstyle-compare-with = Compare with
dimstyle-current-style = Current style
dimstyle-deviation = Deviation
dimstyle-different-sections = Different sections
dimstyle-dimension-line-color = Dimension line color
dimstyle-dimension-linetype = Dimension linetype
dimstyle-dimension-lineweight = Dimension lineweight
dimstyle-display-alternate-units = Display alternate units
dimstyle-draw-dimension-line-between-extension-lines = Draw dimension line between extension lines
dimstyle-extend-beyond-dimension-line = Extend beyond dimension line
dimstyle-extend-beyond-ticks = Extend beyond ticks
dimstyle-extension-line-color = Extension line color
dimstyle-extension-lineweight = Extension lineweight
dimstyle-feet-and-inches = Feet and inches
dimstyle-fine-tuning = Fine tuning
dimstyle-first-arrowhead = First arrowhead
dimstyle-first-extension-linetype = First extension linetype
dimstyle-fit-options = Fit options
dimstyle-fixed-length = Fixed length
dimstyle-fraction-format = Fraction format
dimstyle-height-scale = Height scale
dimstyle-horizontal-placement = Horizontal placement
dimstyle-keep-text-horizontal-inside = Keep text horizontal when inside
dimstyle-keep-text-horizontal-outside = Keep text horizontal when outside
dimstyle-leader-arrowhead = Leader arrowhead
dimstyle-limits = Limits
dimstyle-linear-dimensions = Linear dimensions
dimstyle-lower-value = Lower value
dimstyle-measurement-scale = Measurement scale
dimstyle-measurement-template = Measurement template
dimstyle-method = Method
dimstyle-multiplier = Multiplier
dimstyle-no-differences = No differences
dimstyle-not-applicable = Not applicable
dimstyle-offset-from-measured-point = Offset from measured point
dimstyle-place-text-manually = Place text manually while creating dimensions
dimstyle-radius-jog-angle = Radius jog angle (°)
dimstyle-read-left-to-right = Read left to right
dimstyle-referenced-read-only = Referenced style · Read only
dimstyle-round-off = Round off
dimstyle-second-arrowhead = Second arrowhead
dimstyle-second-extension-linetype = Second extension linetype
dimstyle-show-zero-feet-and-inches = Show zero feet and zero inches
dimstyle-show-zero-feet-suppress-zero-inches = Show zero feet; suppress zero inches
dimstyle-suppress-arrows-when-no-fit = Suppress arrows when they do not fit
dimstyle-suppress-first-dimension-line = Suppress first dimension line
dimstyle-suppress-first-extension-line = Suppress first extension line
dimstyle-suppress-second-dimension-line = Suppress second dimension line
dimstyle-suppress-second-extension-line = Suppress second extension line
dimstyle-suppress-zero-feet-and-inches = Suppress zero feet and zero inches
dimstyle-suppress-zero-feet-show-zero-inches = Suppress zero feet; show zero inches
dimstyle-symbols-and-arrows = Symbols and Arrows
dimstyle-symmetrical = Symmetrical
dimstyle-text-background = Text background
dimstyle-text-gap = Text gap
dimstyle-fixed-text-height-note = The selected text style fixes the height at __ocs_arg_height__.
dimstyle-tick-size = Tick size
dimstyle-tolerance-zero-suppression = Tolerance zero suppression
dimstyle-unit-format = Unit format
dimstyle-upper-value = Upper value
dimstyle-measurement-template-help = Use <> as the measured value; text before and after it becomes the prefix and suffix.
dimstyle-use-different-arrowheads = Use different first and second arrowheads
dimstyle-use-fixed-length-extension-lines = Use fixed-length extension lines
dimstyle-used-in-drawing = Used in drawing
dimstyle-vertical-offset = Vertical offset
dimstyle-vertical-placement = Vertical placement
dimstyle-vertical-position = Vertical position
dimstyle-when-space-is-limited = When space is limited
dimstyle-when-text-is-moved = When text is moved
dimstyle-zero-suppression = Zero suppression
dimstyle-add-a-leader = Add a leader
dimstyle-automatic = Automatic
dimstyle-by-block = By block
dimstyle-comma = Comma
dimstyle-degrees-minutes-seconds = Degrees, minutes, seconds
dimstyle-keep-dimension-line-with-text = Keep dimension line with text
dimstyle-leading-and-trailing = Leading and trailing
dimstyle-move-arrows-outside-first = Move arrows outside first
dimstyle-move-text-and-arrows-outside = Move text and arrows outside
dimstyle-move-text-freely = Move text freely
dimstyle-move-text-outside-first = Move text outside first
dimstyle-period = Period
dimstyle-space = Space
style-manager-alignment-spacing = Alignment spacing
style-manager-always-left-align = Always left align
style-manager-attachment-direction = Attachment direction
style-manager-background-fill-enabled = Background fill enabled
style-manager-big-font = Big font
style-manager-block-scale-x = Block scale X
style-manager-block-scale-y = Block scale Y
style-manager-block-scale-z = Block scale Z
style-manager-borders = Borders
style-manager-bottom-attachment = Bottom attachment
style-manager-break-gap-size = Break gap size
style-manager-caps-and-fill = Caps and Fill
style-manager-content-type = Content type
style-manager-data-row = Data Row
style-manager-data-type = Data type
style-manager-default-text = Default text
style-manager-different = Different
style-manager-display-joints = Display joints
style-manager-drawing-height = Drawing height
style-manager-drawing-scale = Drawing scale
style-manager-effects = Effects
style-manager-elements = Elements
style-manager-end-caps = End caps
style-manager-fill-and-joints = Fill and joints
style-manager-fill-enabled = Fill enabled
style-manager-first-segment-angle = First segment angle
style-manager-fixed-height = Fixed height
style-manager-flow-direction = Flow direction
style-manager-font-file = Font file
style-manager-fonts = Fonts
style-manager-format-string = Format string
style-manager-header = Header
style-manager-header-row = Header Row
style-manager-horizontal-margin = Horizontal margin
style-manager-inner-arcs = Inner arcs
style-manager-inside-horizontal = Inside horizontal
style-manager-inside-vertical = Inside vertical
style-manager-leader-draw-order = Leader draw order
style-manager-leader-note = Leader note
style-manager-left-attachment = Left attachment
style-manager-line-color = Line color
style-manager-line-type = Line type
style-manager-line-weight = Line weight
style-manager-maximum-leader-points = Maximum leader points
style-manager-multileader-draw-order = Multileader draw order
style-manager-no-preview = No preview
style-manager-oblique-angle = Oblique angle
style-manager-outer-arc = Outer arc
style-manager-paper-height = Paper height
style-manager-paper-text-height = Paper text height
style-manager-path-type = Path type
style-manager-right-attachment = Right attachment
style-manager-scale-factor = Scale factor
style-manager-second-segment-angle = Second segment angle
style-manager-size-and-effects = Size and Effects
style-manager-start-caps = Start caps
style-manager-stroke-fonts = Stroke fonts
style-manager-suppress-header-row = Suppress header row
style-manager-suppress-title-row = Suppress title row
style-manager-system-font = System font
style-manager-system-fonts = System fonts
style-manager-text-alignment = Text alignment
style-manager-text-angle = Text angle
style-manager-title-row = Title Row
style-manager-top-attachment = Top attachment
style-manager-unit-type = Unit type
style-manager-vertical-margin = Vertical margin
style-manager-font-family-placeholder = font family…
style-manager-bottom-to-top = Bottom to top
style-manager-arrowhead-first = Arrowhead first
style-manager-content-first = Content first
style-manager-leader-first = Leader first
style-manager-straight = Straight
style-manager-parallel-last-segment = Parallel to last segment
style-manager-top-of-top-line = Top of top line
style-manager-middle-of-top-line = Middle of top line
style-manager-middle-of-text = Middle of text
style-manager-middle-of-bottom-line = Middle of bottom line
style-manager-bottom-of-bottom-line = Bottom of bottom line
style-manager-bottom-line = Bottom line
style-manager-underline-bottom-line = Underline bottom line
style-manager-underline-top-line = Underline top line
style-manager-underline-all-text = Underline all text
style-manager-center-of-text = Center of text
style-manager-center-of-text-overline = Center of text with overline
style-manager-block-extents = Block extents
style-manager-base-point = Base point

View file

@ -3194,3 +3194,185 @@ catalog-mod-shortcuts-4c54bbb78e = ── Raccourcis __ocs_arg_MOD__ ───
catalog-custom-overrides-shortcuts-set-07be563dec = ── Remplacements personnalisés (SHORTCUTS SET) ───────
catalog-function-keys-b5a2df24e9 = ── Touches de fonction ────────────────────────────────
catalog-other-keys-a882812cf2 = ── Autres touches ─────────────────────────────────────
dimstyle-keep-text-between-extension-lines = Toujours conserver le texte entre les lignes dattache
dimstyle-angular-dimensions = Cotes angulaires
dimstyle-arc-length-symbol = Symbole de longueur darc
dimstyle-arrowheads = Pointes de flèche
dimstyle-available-style = Style disponible
dimstyle-baseline-spacing = Espacement des lignes de base
dimstyle-basic = Théorique exacte
dimstyle-both-arrowheads = Deux pointes de flèche
dimstyle-center-mark = Marque de centre
dimstyle-center-mark-size = Taille de la marque de centre
dimstyle-center-marks = Marques de centre
dimstyle-centerlines = Axes
dimstyle-compare-with = Comparer avec
dimstyle-current-style = Style courant
dimstyle-deviation = Écarts
dimstyle-different-sections = Sections différentes
dimstyle-dimension-line-color = Couleur de ligne de cote
dimstyle-dimension-linetype = Type de ligne de cote
dimstyle-dimension-lineweight = Épaisseur de ligne de cote
dimstyle-display-alternate-units = Afficher les unités alternatives
dimstyle-draw-dimension-line-between-extension-lines = Tracer la ligne de cote entre les lignes dattache
dimstyle-extend-beyond-dimension-line = Dépassement de la ligne de cote
dimstyle-extend-beyond-ticks = Dépassement des obliques
dimstyle-extension-line-color = Couleur de ligne dattache
dimstyle-extension-lineweight = Épaisseur de ligne dattache
dimstyle-feet-and-inches = Pieds et pouces
dimstyle-fine-tuning = Ajustement fin
dimstyle-first-arrowhead = Première pointe de flèche
dimstyle-first-extension-linetype = Type de la première ligne dattache
dimstyle-fit-options = Options dajustement
dimstyle-fixed-length = Longueur fixe
dimstyle-fraction-format = Format de fraction
dimstyle-height-scale = Échelle de hauteur
dimstyle-horizontal-placement = Placement horizontal
dimstyle-keep-text-horizontal-inside = Conserver le texte horizontal à lintérieur
dimstyle-keep-text-horizontal-outside = Conserver le texte horizontal à lextérieur
dimstyle-leader-arrowhead = Pointe de flèche de repère
dimstyle-limits = Limites
dimstyle-linear-dimensions = Cotes linéaires
dimstyle-lower-value = Valeur inférieure
dimstyle-measurement-scale = Échelle de mesure
dimstyle-measurement-template = Modèle de mesure
dimstyle-method = Méthode
dimstyle-multiplier = Multiplicateur
dimstyle-no-differences = Aucune différence
dimstyle-not-applicable = Sans objet
dimstyle-offset-from-measured-point = Décalage depuis le point mesuré
dimstyle-place-text-manually = Placer le texte manuellement lors de la cotation
dimstyle-radius-jog-angle = Angle de la ligne brisée de rayon (°)
dimstyle-read-left-to-right = Lire de gauche à droite
dimstyle-referenced-read-only = Style référencé · Lecture seule
dimstyle-round-off = Arrondi
dimstyle-second-arrowhead = Deuxième pointe de flèche
dimstyle-second-extension-linetype = Type de la deuxième ligne dattache
dimstyle-show-zero-feet-and-inches = Afficher zéro pied et zéro pouce
dimstyle-show-zero-feet-suppress-zero-inches = Afficher zéro pied ; supprimer zéro pouce
dimstyle-suppress-arrows-when-no-fit = Supprimer les flèches si elles ne tiennent pas
dimstyle-suppress-first-dimension-line = Supprimer la première ligne de cote
dimstyle-suppress-first-extension-line = Supprimer la première ligne dattache
dimstyle-suppress-second-dimension-line = Supprimer la deuxième ligne de cote
dimstyle-suppress-second-extension-line = Supprimer la deuxième ligne dattache
dimstyle-suppress-zero-feet-and-inches = Supprimer zéro pied et zéro pouce
dimstyle-suppress-zero-feet-show-zero-inches = Supprimer zéro pied ; afficher zéro pouce
dimstyle-symbols-and-arrows = Symboles et flèches
dimstyle-symmetrical = Symétrique
dimstyle-text-background = Arrière-plan du texte
dimstyle-text-gap = Espacement du texte
dimstyle-fixed-text-height-note = Le style de texte sélectionné fixe la hauteur à __ocs_arg_height__.
dimstyle-tick-size = Taille des obliques
dimstyle-tolerance-zero-suppression = Suppression des zéros de tolérance
dimstyle-unit-format = Format dunité
dimstyle-upper-value = Valeur supérieure
dimstyle-measurement-template-help = Utilisez <> pour la valeur mesurée ; le texte placé avant et après devient le préfixe et le suffixe.
dimstyle-use-different-arrowheads = Utiliser des pointes différentes aux deux extrémités
dimstyle-use-fixed-length-extension-lines = Utiliser des lignes dattache de longueur fixe
dimstyle-used-in-drawing = Utilisé dans le dessin
dimstyle-vertical-offset = Décalage vertical
dimstyle-vertical-placement = Placement vertical
dimstyle-vertical-position = Position verticale
dimstyle-when-space-is-limited = Lorsque lespace est limité
dimstyle-when-text-is-moved = Lorsque le texte est déplacé
dimstyle-zero-suppression = Suppression des zéros
dimstyle-add-a-leader = Ajouter une ligne de repère
dimstyle-automatic = Automatique
dimstyle-by-block = Du bloc
dimstyle-comma = Virgule
dimstyle-degrees-minutes-seconds = Degrés, minutes, secondes
dimstyle-keep-dimension-line-with-text = Déplacer la ligne de cote avec le texte
dimstyle-leading-and-trailing = Zéros de début et de fin
dimstyle-move-arrows-outside-first = Déplacer dabord les flèches à lextérieur
dimstyle-move-text-and-arrows-outside = Déplacer le texte et les flèches à lextérieur
dimstyle-move-text-freely = Déplacer le texte librement
dimstyle-move-text-outside-first = Déplacer dabord le texte à lextérieur
dimstyle-period = Point
dimstyle-space = Espace
style-manager-alignment-spacing = Espacement dalignement
style-manager-always-left-align = Toujours aligner à gauche
style-manager-attachment-direction = Direction dattachement
style-manager-background-fill-enabled = Remplissage darrière-plan activé
style-manager-big-font = Police grande taille
style-manager-block-scale-x = Échelle X du bloc
style-manager-block-scale-y = Échelle Y du bloc
style-manager-block-scale-z = Échelle Z du bloc
style-manager-borders = Bordures
style-manager-bottom-attachment = Attachement inférieur
style-manager-break-gap-size = Taille de lespacement de coupure
style-manager-caps-and-fill = Extrémités et remplissage
style-manager-content-type = Type de contenu
style-manager-data-row = Ligne de données
style-manager-data-type = Type de données
style-manager-default-text = Texte par défaut
style-manager-different = Différent
style-manager-display-joints = Afficher les jonctions
style-manager-drawing-height = Hauteur dans le dessin
style-manager-drawing-scale = Échelle du dessin
style-manager-effects = Effets
style-manager-elements = Éléments
style-manager-end-caps = Extrémités de fin
style-manager-fill-and-joints = Remplissage et jonctions
style-manager-fill-enabled = Remplissage activé
style-manager-first-segment-angle = Angle du premier segment
style-manager-fixed-height = Hauteur fixe
style-manager-flow-direction = Sens de lecture
style-manager-font-file = Fichier de police
style-manager-fonts = Polices
style-manager-format-string = Chaîne de format
style-manager-header = En-tête
style-manager-header-row = Ligne den-tête
style-manager-horizontal-margin = Marge horizontale
style-manager-inner-arcs = Arcs intérieurs
style-manager-inside-horizontal = Intérieur horizontal
style-manager-inside-vertical = Intérieur vertical
style-manager-leader-draw-order = Ordre de tracé de la ligne de repère
style-manager-leader-note = Note de repère
style-manager-left-attachment = Attachement gauche
style-manager-line-color = Couleur de ligne
style-manager-line-type = Type de ligne
style-manager-line-weight = Épaisseur de ligne
style-manager-maximum-leader-points = Nombre maximal de points de repère
style-manager-multileader-draw-order = Ordre de tracé du repère multiple
style-manager-no-preview = Aucun aperçu
style-manager-oblique-angle = Angle dinclinaison
style-manager-outer-arc = Arc extérieur
style-manager-paper-height = Hauteur sur papier
style-manager-paper-text-height = Hauteur de texte sur papier
style-manager-path-type = Type de trajectoire
style-manager-right-attachment = Attachement droit
style-manager-scale-factor = Facteur déchelle
style-manager-second-segment-angle = Angle du deuxième segment
style-manager-size-and-effects = Taille et effets
style-manager-start-caps = Extrémités de départ
style-manager-stroke-fonts = Polices filaires
style-manager-suppress-header-row = Masquer la ligne den-tête
style-manager-suppress-title-row = Masquer la ligne de titre
style-manager-system-font = Police système
style-manager-system-fonts = Polices système
style-manager-text-alignment = Alignement du texte
style-manager-text-angle = Angle du texte
style-manager-title-row = Ligne de titre
style-manager-top-attachment = Attachement supérieur
style-manager-unit-type = Type dunité
style-manager-vertical-margin = Marge verticale
style-manager-font-family-placeholder = famille de polices…
style-manager-bottom-to-top = De bas en haut
style-manager-arrowhead-first = Pointe de flèche en premier
style-manager-content-first = Contenu en premier
style-manager-leader-first = Ligne de repère en premier
style-manager-straight = Droite
style-manager-parallel-last-segment = Parallèle au dernier segment
style-manager-top-of-top-line = Haut de la ligne supérieure
style-manager-middle-of-top-line = Milieu de la ligne supérieure
style-manager-middle-of-text = Milieu du texte
style-manager-middle-of-bottom-line = Milieu de la ligne inférieure
style-manager-bottom-of-bottom-line = Bas de la ligne inférieure
style-manager-bottom-line = Ligne inférieure
style-manager-underline-bottom-line = Souligner la ligne inférieure
style-manager-underline-top-line = Souligner la ligne supérieure
style-manager-underline-all-text = Souligner tout le texte
style-manager-center-of-text = Centre du texte
style-manager-center-of-text-overline = Centre du texte avec surlignement
style-manager-block-extents = Limites du bloc
style-manager-base-point = Point de base

View file

@ -3183,3 +3183,185 @@ catalog-mod-shortcuts-4c54bbb78e = ── __ocs_arg_MOD__ शॉर्टकट
catalog-custom-overrides-shortcuts-set-07be563dec = ── कस्टम ओवरराइड (SHORTCUTS SET) ────────────────────
catalog-function-keys-b5a2df24e9 = ── फ़ंक्शन कुंजियाँ ───────────────────────────────────
catalog-other-keys-a882812cf2 = ── अन्य कुंजियाँ ─────────────────────────────────────
dimstyle-keep-text-between-extension-lines = पाठ को हमेशा विस्तार रेखाओं के बीच रखें
dimstyle-angular-dimensions = कोणीय माप
dimstyle-arc-length-symbol = चाप लंबाई चिह्न
dimstyle-arrowheads = तीर शीर्ष
dimstyle-available-style = उपलब्ध शैली
dimstyle-baseline-spacing = आधार रेखा अंतर
dimstyle-basic = मूल
dimstyle-both-arrowheads = दोनों तीर शीर्ष
dimstyle-center-mark = केंद्र चिह्न
dimstyle-center-mark-size = केंद्र चिह्न का आकार
dimstyle-center-marks = केंद्र चिह्न
dimstyle-centerlines = केंद्र रेखाएँ
dimstyle-compare-with = इससे तुलना करें
dimstyle-current-style = वर्तमान शैली
dimstyle-deviation = विचलन
dimstyle-different-sections = भिन्न अनुभाग
dimstyle-dimension-line-color = माप रेखा का रंग
dimstyle-dimension-linetype = माप रेखा प्रकार
dimstyle-dimension-lineweight = माप रेखा मोटाई
dimstyle-display-alternate-units = वैकल्पिक इकाइयाँ दिखाएँ
dimstyle-draw-dimension-line-between-extension-lines = विस्तार रेखाओं के बीच माप रेखा बनाएँ
dimstyle-extend-beyond-dimension-line = माप रेखा से आगे बढ़ाएँ
dimstyle-extend-beyond-ticks = तिरछे चिह्नों से आगे बढ़ाएँ
dimstyle-extension-line-color = विस्तार रेखा का रंग
dimstyle-extension-lineweight = विस्तार रेखा मोटाई
dimstyle-feet-and-inches = फुट और इंच
dimstyle-fine-tuning = सूक्ष्म समायोजन
dimstyle-first-arrowhead = पहला तीर शीर्ष
dimstyle-first-extension-linetype = पहली विस्तार रेखा का प्रकार
dimstyle-fit-options = समायोजन विकल्प
dimstyle-fixed-length = निश्चित लंबाई
dimstyle-fraction-format = भिन्न प्रारूप
dimstyle-height-scale = ऊँचाई मापनी
dimstyle-horizontal-placement = क्षैतिज स्थान
dimstyle-keep-text-horizontal-inside = अंदर होने पर पाठ क्षैतिज रखें
dimstyle-keep-text-horizontal-outside = बाहर होने पर पाठ क्षैतिज रखें
dimstyle-leader-arrowhead = संकेतक तीर शीर्ष
dimstyle-limits = सीमाएँ
dimstyle-linear-dimensions = रैखिक माप
dimstyle-lower-value = निचला मान
dimstyle-measurement-scale = मापन मापनी
dimstyle-measurement-template = मापन साँचा
dimstyle-method = विधि
dimstyle-multiplier = गुणक
dimstyle-no-differences = कोई अंतर नहीं
dimstyle-not-applicable = लागू नहीं
dimstyle-offset-from-measured-point = मापे गए बिंदु से दूरी
dimstyle-place-text-manually = माप बनाते समय पाठ को स्वयं रखें
dimstyle-radius-jog-angle = त्रिज्या मोड़ कोण (°)
dimstyle-read-left-to-right = बाएँ से दाएँ पढ़ें
dimstyle-referenced-read-only = संदर्भित शैली · केवल पढ़ने योग्य
dimstyle-round-off = पूर्णांकन
dimstyle-second-arrowhead = दूसरा तीर शीर्ष
dimstyle-second-extension-linetype = दूसरी विस्तार रेखा का प्रकार
dimstyle-show-zero-feet-and-inches = शून्य फुट और शून्य इंच दिखाएँ
dimstyle-show-zero-feet-suppress-zero-inches = शून्य फुट दिखाएँ; शून्य इंच छिपाएँ
dimstyle-suppress-arrows-when-no-fit = जगह न होने पर तीर छिपाएँ
dimstyle-suppress-first-dimension-line = पहली माप रेखा छिपाएँ
dimstyle-suppress-first-extension-line = पहली विस्तार रेखा छिपाएँ
dimstyle-suppress-second-dimension-line = दूसरी माप रेखा छिपाएँ
dimstyle-suppress-second-extension-line = दूसरी विस्तार रेखा छिपाएँ
dimstyle-suppress-zero-feet-and-inches = शून्य फुट और शून्य इंच छिपाएँ
dimstyle-suppress-zero-feet-show-zero-inches = शून्य फुट छिपाएँ; शून्य इंच दिखाएँ
dimstyle-symbols-and-arrows = चिह्न और तीर
dimstyle-symmetrical = सममित
dimstyle-text-background = पाठ पृष्ठभूमि
dimstyle-text-gap = पाठ अंतर
dimstyle-fixed-text-height-note = चुनी गई पाठ शैली ऊँचाई को __ocs_arg_height__ पर स्थिर करती है।
dimstyle-tick-size = तिरछे चिह्न का आकार
dimstyle-tolerance-zero-suppression = सहनशीलता के शून्य छिपाना
dimstyle-unit-format = इकाई प्रारूप
dimstyle-upper-value = ऊपरी मान
dimstyle-measurement-template-help = मापे गए मान के लिए <> का उपयोग करें; इसके पहले और बाद का पाठ उपसर्ग और प्रत्यय बनता है।
dimstyle-use-different-arrowheads = पहले और दूसरे तीर शीर्ष अलग रखें
dimstyle-use-fixed-length-extension-lines = निश्चित लंबाई की विस्तार रेखाएँ उपयोग करें
dimstyle-used-in-drawing = आरेख में प्रयुक्त
dimstyle-vertical-offset = ऊर्ध्वाधर दूरी
dimstyle-vertical-placement = ऊर्ध्वाधर स्थान
dimstyle-vertical-position = ऊर्ध्वाधर स्थिति
dimstyle-when-space-is-limited = जब स्थान सीमित हो
dimstyle-when-text-is-moved = जब पाठ हटाया जाए
dimstyle-zero-suppression = शून्य छिपाना
dimstyle-add-a-leader = संकेतक रेखा जोड़ें
dimstyle-automatic = स्वचालित
dimstyle-by-block = ब्लॉक के अनुसार
dimstyle-comma = अल्पविराम
dimstyle-degrees-minutes-seconds = अंश, मिनट, सेकंड
dimstyle-keep-dimension-line-with-text = माप रेखा को पाठ के साथ रखें
dimstyle-leading-and-trailing = आरंभिक और अंतिम
dimstyle-move-arrows-outside-first = पहले तीर बाहर ले जाएँ
dimstyle-move-text-and-arrows-outside = पाठ और तीर बाहर ले जाएँ
dimstyle-move-text-freely = पाठ को स्वतंत्र रूप से ले जाएँ
dimstyle-move-text-outside-first = पहले पाठ बाहर ले जाएँ
dimstyle-period = दशमलव बिंदु
dimstyle-space = रिक्त स्थान
style-manager-alignment-spacing = संरेखण अंतराल
style-manager-always-left-align = हमेशा बाएँ संरेखित करें
style-manager-attachment-direction = संयोजन दिशा
style-manager-background-fill-enabled = पृष्ठभूमि भराव सक्षम
style-manager-big-font = बड़ा फ़ॉन्ट
style-manager-block-scale-x = ब्लॉक X स्केल
style-manager-block-scale-y = ब्लॉक Y स्केल
style-manager-block-scale-z = ब्लॉक Z स्केल
style-manager-borders = सीमाएँ
style-manager-bottom-attachment = निचला संयोजन
style-manager-break-gap-size = ब्रेक अंतराल आकार
style-manager-caps-and-fill = सिरे और भराव
style-manager-content-type = सामग्री प्रकार
style-manager-data-row = डेटा पंक्ति
style-manager-data-type = डेटा प्रकार
style-manager-default-text = डिफ़ॉल्ट टेक्स्ट
style-manager-different = भिन्न
style-manager-display-joints = जोड़ दिखाएँ
style-manager-drawing-height = ड्रॉइंग ऊँचाई
style-manager-drawing-scale = ड्रॉइंग स्केल
style-manager-effects = प्रभाव
style-manager-elements = अवयव
style-manager-end-caps = अंतिम सिरे
style-manager-fill-and-joints = भराव और जोड़
style-manager-fill-enabled = भराव सक्षम
style-manager-first-segment-angle = पहले खंड का कोण
style-manager-fixed-height = निश्चित ऊँचाई
style-manager-flow-direction = प्रवाह दिशा
style-manager-font-file = फ़ॉन्ट फ़ाइल
style-manager-fonts = फ़ॉन्ट
style-manager-format-string = प्रारूप स्ट्रिंग
style-manager-header = शीर्षलेख
style-manager-header-row = शीर्षलेख पंक्ति
style-manager-horizontal-margin = क्षैतिज हाशिया
style-manager-inner-arcs = आंतरिक चाप
style-manager-inside-horizontal = आंतरिक क्षैतिज
style-manager-inside-vertical = आंतरिक ऊर्ध्वाधर
style-manager-leader-draw-order = लीडर आरेखन क्रम
style-manager-leader-note = लीडर टिप्पणी
style-manager-left-attachment = बायाँ संयोजन
style-manager-line-color = रेखा रंग
style-manager-line-type = रेखा प्रकार
style-manager-line-weight = रेखा मोटाई
style-manager-maximum-leader-points = अधिकतम लीडर बिंदु
style-manager-multileader-draw-order = मल्टीलीडर आरेखन क्रम
style-manager-no-preview = कोई पूर्वावलोकन नहीं
style-manager-oblique-angle = तिरछा कोण
style-manager-outer-arc = बाहरी चाप
style-manager-paper-height = काग़ज़ ऊँचाई
style-manager-paper-text-height = काग़ज़ पर टेक्स्ट ऊँचाई
style-manager-path-type = पथ प्रकार
style-manager-right-attachment = दायाँ संयोजन
style-manager-scale-factor = स्केल गुणक
style-manager-second-segment-angle = दूसरे खंड का कोण
style-manager-size-and-effects = आकार और प्रभाव
style-manager-start-caps = आरंभिक सिरे
style-manager-stroke-fonts = रेखीय फ़ॉन्ट
style-manager-suppress-header-row = शीर्षलेख पंक्ति छिपाएँ
style-manager-suppress-title-row = शीर्षक पंक्ति छिपाएँ
style-manager-system-font = सिस्टम फ़ॉन्ट
style-manager-system-fonts = सिस्टम फ़ॉन्ट
style-manager-text-alignment = टेक्स्ट संरेखण
style-manager-text-angle = टेक्स्ट कोण
style-manager-title-row = शीर्षक पंक्ति
style-manager-top-attachment = ऊपरी संयोजन
style-manager-unit-type = इकाई प्रकार
style-manager-vertical-margin = ऊर्ध्वाधर हाशिया
style-manager-font-family-placeholder = फ़ॉन्ट परिवार…
style-manager-bottom-to-top = नीचे से ऊपर
style-manager-arrowhead-first = पहले तीर का सिरा
style-manager-content-first = पहले सामग्री
style-manager-leader-first = पहले लीडर
style-manager-straight = सीधा
style-manager-parallel-last-segment = अंतिम खंड के समांतर
style-manager-top-of-top-line = शीर्ष पंक्ति का ऊपरी भाग
style-manager-middle-of-top-line = शीर्ष पंक्ति का मध्य
style-manager-middle-of-text = टेक्स्ट का मध्य
style-manager-middle-of-bottom-line = निचली पंक्ति का मध्य
style-manager-bottom-of-bottom-line = निचली पंक्ति का निचला भाग
style-manager-bottom-line = निचली पंक्ति
style-manager-underline-bottom-line = निचली पंक्ति के नीचे रेखा
style-manager-underline-top-line = शीर्ष पंक्ति के नीचे रेखा
style-manager-underline-all-text = सभी टेक्स्ट के नीचे रेखा
style-manager-center-of-text = टेक्स्ट का केंद्र
style-manager-center-of-text-overline = ऊपरी रेखा सहित टेक्स्ट का केंद्र
style-manager-block-extents = ब्लॉक परिमिति
style-manager-base-point = आधार बिंदु

View file

@ -3195,3 +3195,185 @@ catalog-mod-shortcuts-4c54bbb78e = ── __ocs_arg_MOD__-sneltoetsen ───
catalog-custom-overrides-shortcuts-set-07be563dec = ── Aangepaste overschrijvingen (SHORTCUTS SET) ────────
catalog-function-keys-b5a2df24e9 = ── Functietoetsen ─────────────────────────────────────
catalog-other-keys-a882812cf2 = ── Overige toetsen ────────────────────────────────────
dimstyle-keep-text-between-extension-lines = Tekst altijd tussen hulplijnen houden
dimstyle-angular-dimensions = Hoekmaten
dimstyle-arc-length-symbol = Booglengtesymbool
dimstyle-arrowheads = Pijlpunten
dimstyle-available-style = Beschikbare stijl
dimstyle-baseline-spacing = Basislijnafstand
dimstyle-basic = Basis
dimstyle-both-arrowheads = Beide pijlpunten
dimstyle-center-mark = Middelpuntmarkering
dimstyle-center-mark-size = Grootte van middelpuntmarkering
dimstyle-center-marks = Middelpuntmarkeringen
dimstyle-centerlines = Hartlijnen
dimstyle-compare-with = Vergelijken met
dimstyle-current-style = Huidige stijl
dimstyle-deviation = Afwijking
dimstyle-different-sections = Afwijkende secties
dimstyle-dimension-line-color = Kleur maatlijn
dimstyle-dimension-linetype = Lijntype maatlijn
dimstyle-dimension-lineweight = Lijndikte maatlijn
dimstyle-display-alternate-units = Alternatieve eenheden weergeven
dimstyle-draw-dimension-line-between-extension-lines = Maatlijn tussen hulplijnen tekenen
dimstyle-extend-beyond-dimension-line = Voorbij maatlijn verlengen
dimstyle-extend-beyond-ticks = Voorbij schuine streepjes verlengen
dimstyle-extension-line-color = Kleur hulplijn
dimstyle-extension-lineweight = Lijndikte hulplijn
dimstyle-feet-and-inches = Voet en inch
dimstyle-fine-tuning = Fijnafstelling
dimstyle-first-arrowhead = Eerste pijlpunt
dimstyle-first-extension-linetype = Lijntype eerste hulplijn
dimstyle-fit-options = Inpasopties
dimstyle-fixed-length = Vaste lengte
dimstyle-fraction-format = Breuknotatie
dimstyle-height-scale = Hoogteschaal
dimstyle-horizontal-placement = Horizontale plaatsing
dimstyle-keep-text-horizontal-inside = Tekst binnen horizontaal houden
dimstyle-keep-text-horizontal-outside = Tekst buiten horizontaal houden
dimstyle-leader-arrowhead = Pijlpunt van verwijslijn
dimstyle-limits = Grenswaarden
dimstyle-linear-dimensions = Lineaire maten
dimstyle-lower-value = Onderwaarde
dimstyle-measurement-scale = Meetschaal
dimstyle-measurement-template = Meetwaardesjabloon
dimstyle-method = Methode
dimstyle-multiplier = Vermenigvuldigingsfactor
dimstyle-no-differences = Geen verschillen
dimstyle-not-applicable = Niet van toepassing
dimstyle-offset-from-measured-point = Afstand vanaf meetpunt
dimstyle-place-text-manually = Tekst handmatig plaatsen tijdens het bematen
dimstyle-radius-jog-angle = Hoek van radiusknik (°)
dimstyle-read-left-to-right = Van links naar rechts lezen
dimstyle-referenced-read-only = Gerefereerde stijl · Alleen-lezen
dimstyle-round-off = Afronding
dimstyle-second-arrowhead = Tweede pijlpunt
dimstyle-second-extension-linetype = Lijntype tweede hulplijn
dimstyle-show-zero-feet-and-inches = Nul voet en nul inch weergeven
dimstyle-show-zero-feet-suppress-zero-inches = Nul voet weergeven; nul inch onderdrukken
dimstyle-suppress-arrows-when-no-fit = Pijlen onderdrukken als ze niet passen
dimstyle-suppress-first-dimension-line = Eerste maatlijn onderdrukken
dimstyle-suppress-first-extension-line = Eerste hulplijn onderdrukken
dimstyle-suppress-second-dimension-line = Tweede maatlijn onderdrukken
dimstyle-suppress-second-extension-line = Tweede hulplijn onderdrukken
dimstyle-suppress-zero-feet-and-inches = Nul voet en nul inch onderdrukken
dimstyle-suppress-zero-feet-show-zero-inches = Nul voet onderdrukken; nul inch weergeven
dimstyle-symbols-and-arrows = Symbolen en pijlen
dimstyle-symmetrical = Symmetrisch
dimstyle-text-background = Tekstachtergrond
dimstyle-text-gap = Tekstafstand
dimstyle-fixed-text-height-note = De gekozen tekststijl legt de hoogte vast op __ocs_arg_height__.
dimstyle-tick-size = Grootte schuine streep
dimstyle-tolerance-zero-suppression = Nulonderdrukking tolerantie
dimstyle-unit-format = Eenheidsnotatie
dimstyle-upper-value = Bovenwaarde
dimstyle-measurement-template-help = Gebruik <> voor de meetwaarde; tekst ervoor en erna wordt het voor- en achtervoegsel.
dimstyle-use-different-arrowheads = Verschillende eerste en tweede pijlpunten gebruiken
dimstyle-use-fixed-length-extension-lines = Hulplijnen met vaste lengte gebruiken
dimstyle-used-in-drawing = Gebruikt in tekening
dimstyle-vertical-offset = Verticale afstand
dimstyle-vertical-placement = Verticale plaatsing
dimstyle-vertical-position = Verticale positie
dimstyle-when-space-is-limited = Wanneer de ruimte beperkt is
dimstyle-when-text-is-moved = Wanneer tekst wordt verplaatst
dimstyle-zero-suppression = Nulonderdrukking
dimstyle-add-a-leader = Verwijslijn toevoegen
dimstyle-automatic = Automatisch
dimstyle-by-block = Per blok
dimstyle-comma = Komma
dimstyle-degrees-minutes-seconds = Graden, minuten, seconden
dimstyle-keep-dimension-line-with-text = Maatlijn met tekst meeverplaatsen
dimstyle-leading-and-trailing = Voorloop- en eindnullen
dimstyle-move-arrows-outside-first = Eerst pijlen naar buiten verplaatsen
dimstyle-move-text-and-arrows-outside = Tekst en pijlen naar buiten verplaatsen
dimstyle-move-text-freely = Tekst vrij verplaatsen
dimstyle-move-text-outside-first = Eerst tekst naar buiten verplaatsen
dimstyle-period = Punt
dimstyle-space = Spatie
style-manager-alignment-spacing = Uitlijningsafstand
style-manager-always-left-align = Altijd links uitlijnen
style-manager-attachment-direction = Aanhechtingsrichting
style-manager-background-fill-enabled = Achtergrondvulling ingeschakeld
style-manager-big-font = Groot lettertype
style-manager-block-scale-x = Blokschaal X
style-manager-block-scale-y = Blokschaal Y
style-manager-block-scale-z = Blokschaal Z
style-manager-borders = Randen
style-manager-bottom-attachment = Onderste aanhechting
style-manager-break-gap-size = Grootte van onderbrekingsruimte
style-manager-caps-and-fill = Eindkappen en vulling
style-manager-content-type = Inhoudstype
style-manager-data-row = Gegevensrij
style-manager-data-type = Gegevenstype
style-manager-default-text = Standaardtekst
style-manager-different = Verschillend
style-manager-display-joints = Verbindingen weergeven
style-manager-drawing-height = Tekeninghoogte
style-manager-drawing-scale = Tekenschaal
style-manager-effects = Effecten
style-manager-elements = Elementen
style-manager-end-caps = Eindkappen
style-manager-fill-and-joints = Vulling en verbindingen
style-manager-fill-enabled = Vulling ingeschakeld
style-manager-first-segment-angle = Hoek van eerste segment
style-manager-fixed-height = Vaste hoogte
style-manager-flow-direction = Leesrichting
style-manager-font-file = Lettertypebestand
style-manager-fonts = Lettertypen
style-manager-format-string = Opmaakreeks
style-manager-header = Kolomkop
style-manager-header-row = Kolomkoprij
style-manager-horizontal-margin = Horizontale marge
style-manager-inner-arcs = Binnenbogen
style-manager-inside-horizontal = Horizontaal binnen
style-manager-inside-vertical = Verticaal binnen
style-manager-leader-draw-order = Tekenvolgorde van verwijslijn
style-manager-leader-note = Verwijslijnnotitie
style-manager-left-attachment = Linker aanhechting
style-manager-line-color = Lijnkleur
style-manager-line-type = Lijntype
style-manager-line-weight = Lijndikte
style-manager-maximum-leader-points = Maximumaantal verwijslijnpunten
style-manager-multileader-draw-order = Tekenvolgorde van multiverwijslijn
style-manager-no-preview = Geen voorbeeld
style-manager-oblique-angle = Schuintehoek
style-manager-outer-arc = Buitenboog
style-manager-paper-height = Papierhoogte
style-manager-paper-text-height = Teksthoogte op papier
style-manager-path-type = Padtype
style-manager-right-attachment = Rechter aanhechting
style-manager-scale-factor = Schaalfactor
style-manager-second-segment-angle = Hoek van tweede segment
style-manager-size-and-effects = Grootte en effecten
style-manager-start-caps = Startkappen
style-manager-stroke-fonts = Lijnlettertypen
style-manager-suppress-header-row = Kolomkoprij verbergen
style-manager-suppress-title-row = Titelrij verbergen
style-manager-system-font = Systeemlettertype
style-manager-system-fonts = Systeemlettertypen
style-manager-text-alignment = Tekstuitlijning
style-manager-text-angle = Teksthoek
style-manager-title-row = Titelrij
style-manager-top-attachment = Bovenste aanhechting
style-manager-unit-type = Eenheidstype
style-manager-vertical-margin = Verticale marge
style-manager-font-family-placeholder = lettertypefamilie…
style-manager-bottom-to-top = Van onder naar boven
style-manager-arrowhead-first = Pijlpunt eerst
style-manager-content-first = Inhoud eerst
style-manager-leader-first = Verwijslijn eerst
style-manager-straight = Recht
style-manager-parallel-last-segment = Evenwijdig aan laatste segment
style-manager-top-of-top-line = Bovenkant van bovenste regel
style-manager-middle-of-top-line = Midden van bovenste regel
style-manager-middle-of-text = Midden van tekst
style-manager-middle-of-bottom-line = Midden van onderste regel
style-manager-bottom-of-bottom-line = Onderkant van onderste regel
style-manager-bottom-line = Onderste regel
style-manager-underline-bottom-line = Onderste regel onderstrepen
style-manager-underline-top-line = Bovenste regel onderstrepen
style-manager-underline-all-text = Alle tekst onderstrepen
style-manager-center-of-text = Tekstmiddelpunt
style-manager-center-of-text-overline = Tekstmiddelpunt met bovenstreep
style-manager-block-extents = Blokgrenzen
style-manager-base-point = Basispunt

View file

@ -3198,3 +3198,185 @@ catalog-mod-shortcuts-4c54bbb78e = ── Сочетания __ocs_arg_MOD__ ─
catalog-custom-overrides-shortcuts-set-07be563dec = ── Пользовательские переопределения (SHORTCUTS SET) ─
catalog-function-keys-b5a2df24e9 = ── Функциональные клавиши ─────────────────────────────
catalog-other-keys-a882812cf2 = ── Прочие клавиши ─────────────────────────────────────
dimstyle-keep-text-between-extension-lines = Всегда размещать текст между выносными линиями
dimstyle-angular-dimensions = Угловые размеры
dimstyle-arc-length-symbol = Символ длины дуги
dimstyle-arrowheads = Стрелки
dimstyle-available-style = Доступный стиль
dimstyle-baseline-spacing = Шаг базовых размеров
dimstyle-basic = Теоретически точный
dimstyle-both-arrowheads = Обе стрелки
dimstyle-center-mark = Маркер центра
dimstyle-center-mark-size = Размер маркера центра
dimstyle-center-marks = Маркеры центра
dimstyle-centerlines = Осевые линии
dimstyle-compare-with = Сравнить с
dimstyle-current-style = Текущий стиль
dimstyle-deviation = Отклонения
dimstyle-different-sections = Различающиеся разделы
dimstyle-dimension-line-color = Цвет размерной линии
dimstyle-dimension-linetype = Тип размерной линии
dimstyle-dimension-lineweight = Вес размерной линии
dimstyle-display-alternate-units = Показывать альтернативные единицы
dimstyle-draw-dimension-line-between-extension-lines = Рисовать размерную линию между выносными
dimstyle-extend-beyond-dimension-line = Выступ за размерную линию
dimstyle-extend-beyond-ticks = Выступ за засечки
dimstyle-extension-line-color = Цвет выносной линии
dimstyle-extension-lineweight = Вес выносной линии
dimstyle-feet-and-inches = Футы и дюймы
dimstyle-fine-tuning = Точная настройка
dimstyle-first-arrowhead = Первая стрелка
dimstyle-first-extension-linetype = Тип первой выносной линии
dimstyle-fit-options = Параметры размещения
dimstyle-fixed-length = Фиксированная длина
dimstyle-fraction-format = Формат дробей
dimstyle-height-scale = Масштаб высоты
dimstyle-horizontal-placement = Размещение по горизонтали
dimstyle-keep-text-horizontal-inside = Сохранять текст горизонтальным внутри
dimstyle-keep-text-horizontal-outside = Сохранять текст горизонтальным снаружи
dimstyle-leader-arrowhead = Стрелка выноски
dimstyle-limits = Предельные значения
dimstyle-linear-dimensions = Линейные размеры
dimstyle-lower-value = Нижнее значение
dimstyle-measurement-scale = Масштаб измерения
dimstyle-measurement-template = Шаблон значения
dimstyle-method = Способ
dimstyle-multiplier = Множитель
dimstyle-no-differences = Различий нет
dimstyle-not-applicable = Неприменимо
dimstyle-offset-from-measured-point = Отступ от измеряемой точки
dimstyle-place-text-manually = Размещать текст вручную при создании размера
dimstyle-radius-jog-angle = Угол излома радиуса (°)
dimstyle-read-left-to-right = Читать слева направо
dimstyle-referenced-read-only = Ссылочный стиль · Только чтение
dimstyle-round-off = Округление
dimstyle-second-arrowhead = Вторая стрелка
dimstyle-second-extension-linetype = Тип второй выносной линии
dimstyle-show-zero-feet-and-inches = Показывать нулевые футы и дюймы
dimstyle-show-zero-feet-suppress-zero-inches = Показывать нулевые футы; подавлять нулевые дюймы
dimstyle-suppress-arrows-when-no-fit = Подавлять стрелки, если они не помещаются
dimstyle-suppress-first-dimension-line = Подавлять первую размерную линию
dimstyle-suppress-first-extension-line = Подавлять первую выносную линию
dimstyle-suppress-second-dimension-line = Подавлять вторую размерную линию
dimstyle-suppress-second-extension-line = Подавлять вторую выносную линию
dimstyle-suppress-zero-feet-and-inches = Подавлять нулевые футы и дюймы
dimstyle-suppress-zero-feet-show-zero-inches = Подавлять нулевые футы; показывать нулевые дюймы
dimstyle-symbols-and-arrows = Символы и стрелки
dimstyle-symmetrical = Симметрично
dimstyle-text-background = Фон текста
dimstyle-text-gap = Отступ текста
dimstyle-fixed-text-height-note = Выбранный стиль текста фиксирует высоту: __ocs_arg_height__.
dimstyle-tick-size = Размер засечек
dimstyle-tolerance-zero-suppression = Подавление нулей допуска
dimstyle-unit-format = Формат единиц
dimstyle-upper-value = Верхнее значение
dimstyle-measurement-template-help = Используйте <> для измеренного значения; текст до и после него станет префиксом и суффиксом.
dimstyle-use-different-arrowheads = Использовать разные первую и вторую стрелки
dimstyle-use-fixed-length-extension-lines = Использовать выносные линии фиксированной длины
dimstyle-used-in-drawing = Используется в чертеже
dimstyle-vertical-offset = Вертикальный отступ
dimstyle-vertical-placement = Размещение по вертикали
dimstyle-vertical-position = Положение по вертикали
dimstyle-when-space-is-limited = При недостатке места
dimstyle-when-text-is-moved = При перемещении текста
dimstyle-zero-suppression = Подавление нулей
dimstyle-add-a-leader = Добавить выноску
dimstyle-automatic = Автоматически
dimstyle-by-block = По блоку
dimstyle-comma = Запятая
dimstyle-degrees-minutes-seconds = Градусы, минуты, секунды
dimstyle-keep-dimension-line-with-text = Перемещать размерную линию вместе с текстом
dimstyle-leading-and-trailing = Ведущие и конечные
dimstyle-move-arrows-outside-first = Сначала вынести стрелки
dimstyle-move-text-and-arrows-outside = Вынести текст и стрелки
dimstyle-move-text-freely = Свободно перемещать текст
dimstyle-move-text-outside-first = Сначала вынести текст
dimstyle-period = Точка
dimstyle-space = Пробел
style-manager-alignment-spacing = Интервал выравнивания
style-manager-always-left-align = Всегда выравнивать по левому краю
style-manager-attachment-direction = Направление присоединения
style-manager-background-fill-enabled = Фоновая заливка включена
style-manager-big-font = Большой шрифт
style-manager-block-scale-x = Масштаб блока X
style-manager-block-scale-y = Масштаб блока Y
style-manager-block-scale-z = Масштаб блока Z
style-manager-borders = Границы
style-manager-bottom-attachment = Нижнее присоединение
style-manager-break-gap-size = Размер зазора разрыва
style-manager-caps-and-fill = Торцы и заливка
style-manager-content-type = Тип содержимого
style-manager-data-row = Строка данных
style-manager-data-type = Тип данных
style-manager-default-text = Текст по умолчанию
style-manager-different = Отличается
style-manager-display-joints = Показывать стыки
style-manager-drawing-height = Высота в чертеже
style-manager-drawing-scale = Масштаб чертежа
style-manager-effects = Эффекты
style-manager-elements = Элементы
style-manager-end-caps = Конечные торцы
style-manager-fill-and-joints = Заливка и стыки
style-manager-fill-enabled = Заливка включена
style-manager-first-segment-angle = Угол первого сегмента
style-manager-fixed-height = Фиксированная высота
style-manager-flow-direction = Направление заполнения
style-manager-font-file = Файл шрифта
style-manager-fonts = Шрифты
style-manager-format-string = Строка формата
style-manager-header = Заголовок столбцов
style-manager-header-row = Строка заголовков
style-manager-horizontal-margin = Горизонтальное поле
style-manager-inner-arcs = Внутренние дуги
style-manager-inside-horizontal = Внутренняя горизонтальная
style-manager-inside-vertical = Внутренняя вертикальная
style-manager-leader-draw-order = Порядок отрисовки выноски
style-manager-leader-note = Примечание выноски
style-manager-left-attachment = Левое присоединение
style-manager-line-color = Цвет линии
style-manager-line-type = Тип линии
style-manager-line-weight = Вес линии
style-manager-maximum-leader-points = Максимум точек выноски
style-manager-multileader-draw-order = Порядок отрисовки мультивыноски
style-manager-no-preview = Нет предпросмотра
style-manager-oblique-angle = Угол наклона
style-manager-outer-arc = Внешняя дуга
style-manager-paper-height = Высота на бумаге
style-manager-paper-text-height = Высота текста на бумаге
style-manager-path-type = Тип траектории
style-manager-right-attachment = Правое присоединение
style-manager-scale-factor = Масштабный коэффициент
style-manager-second-segment-angle = Угол второго сегмента
style-manager-size-and-effects = Размер и эффекты
style-manager-start-caps = Начальные торцы
style-manager-stroke-fonts = Штриховые шрифты
style-manager-suppress-header-row = Скрыть строку заголовков
style-manager-suppress-title-row = Скрыть строку названия
style-manager-system-font = Системный шрифт
style-manager-system-fonts = Системные шрифты
style-manager-text-alignment = Выравнивание текста
style-manager-text-angle = Угол текста
style-manager-title-row = Строка названия
style-manager-top-attachment = Верхнее присоединение
style-manager-unit-type = Тип единиц
style-manager-vertical-margin = Вертикальное поле
style-manager-font-family-placeholder = семейство шрифтов…
style-manager-bottom-to-top = Снизу вверх
style-manager-arrowhead-first = Сначала стрелка
style-manager-content-first = Сначала содержимое
style-manager-leader-first = Сначала выноска
style-manager-straight = Прямая
style-manager-parallel-last-segment = Параллельно последнему сегменту
style-manager-top-of-top-line = Верх верхней строки
style-manager-middle-of-top-line = Середина верхней строки
style-manager-middle-of-text = Середина текста
style-manager-middle-of-bottom-line = Середина нижней строки
style-manager-bottom-of-bottom-line = Низ нижней строки
style-manager-bottom-line = Нижняя строка
style-manager-underline-bottom-line = Подчеркнуть нижнюю строку
style-manager-underline-top-line = Подчеркнуть верхнюю строку
style-manager-underline-all-text = Подчеркнуть весь текст
style-manager-center-of-text = Центр текста
style-manager-center-of-text-overline = Центр текста с надчёркиванием
style-manager-block-extents = Габариты блока
style-manager-base-point = Базовая точка

View file

@ -3118,3 +3118,185 @@ catalog-mod-shortcuts-4c54bbb78e = ── __ocs_arg_MOD__ Kısayolları ──
catalog-custom-overrides-shortcuts-set-07be563dec = ── Özel Geçersiz Kılmalar (SHORTCUTS SET) ─────────────
catalog-function-keys-b5a2df24e9 = ── İşlev Tuşları ───────────────────────────────────────
catalog-other-keys-a882812cf2 = ── Diğer Tuşlar ────────────────────────────────────────
dimstyle-keep-text-between-extension-lines = Metni her zaman uzatma çizgileri arasında tut
dimstyle-angular-dimensions = Açısal ölçüler
dimstyle-arc-length-symbol = Yay uzunluğu simgesi
dimstyle-arrowheads = Ok uçları
dimstyle-available-style = Kullanılabilir stil
dimstyle-baseline-spacing = Taban çizgisi aralığı
dimstyle-basic = Temel
dimstyle-both-arrowheads = Her iki ok ucu
dimstyle-center-mark = Merkez işareti
dimstyle-center-mark-size = Merkez işareti boyutu
dimstyle-center-marks = Merkez işaretleri
dimstyle-centerlines = Merkez çizgileri
dimstyle-compare-with = Karşılaştır
dimstyle-current-style = Geçerli stil
dimstyle-deviation = Sapma
dimstyle-different-sections = Farklı bölümler
dimstyle-dimension-line-color = Ölçü çizgisi rengi
dimstyle-dimension-linetype = Ölçü çizgisi türü
dimstyle-dimension-lineweight = Ölçü çizgisi kalınlığı
dimstyle-display-alternate-units = Alternatif birimleri göster
dimstyle-draw-dimension-line-between-extension-lines = Uzatma çizgileri arasına ölçü çizgisi çiz
dimstyle-extend-beyond-dimension-line = Ölçü çizgisini aşma
dimstyle-extend-beyond-ticks = İşaretleri aşma
dimstyle-extension-line-color = Uzatma çizgisi rengi
dimstyle-extension-lineweight = Uzatma çizgisi kalınlığı
dimstyle-feet-and-inches = Fit ve inç
dimstyle-fine-tuning = İnce ayar
dimstyle-first-arrowhead = Birinci ok ucu
dimstyle-first-extension-linetype = Birinci uzatma çizgisi türü
dimstyle-fit-options = Sığdırma seçenekleri
dimstyle-fixed-length = Sabit uzunluk
dimstyle-fraction-format = Kesir biçimi
dimstyle-height-scale = Yükseklik ölçeği
dimstyle-horizontal-placement = Yatay yerleşim
dimstyle-keep-text-horizontal-inside = İçerideyken metni yatay tut
dimstyle-keep-text-horizontal-outside = Dışarıdayken metni yatay tut
dimstyle-leader-arrowhead = Kılavuz ok ucu
dimstyle-limits = Sınırlar
dimstyle-linear-dimensions = Doğrusal ölçüler
dimstyle-lower-value = Alt değer
dimstyle-measurement-scale = Ölçüm ölçeği
dimstyle-measurement-template = Ölçüm şablonu
dimstyle-method = Yöntem
dimstyle-multiplier = Çarpan
dimstyle-no-differences = Fark yok
dimstyle-not-applicable = Uygulanamaz
dimstyle-offset-from-measured-point = Ölçülen noktadan uzaklık
dimstyle-place-text-manually = Ölçü oluştururken metni elle yerleştir
dimstyle-radius-jog-angle = Yarıçap kırılma açısı (°)
dimstyle-read-left-to-right = Soldan sağa oku
dimstyle-referenced-read-only = Başvurulan stil · Salt okunur
dimstyle-round-off = Yuvarlama
dimstyle-second-arrowhead = İkinci ok ucu
dimstyle-second-extension-linetype = İkinci uzatma çizgisi türü
dimstyle-show-zero-feet-and-inches = Sıfır fit ve sıfır inçi göster
dimstyle-show-zero-feet-suppress-zero-inches = Sıfır fiti göster; sıfır inçi gizle
dimstyle-suppress-arrows-when-no-fit = Sığmadığında okları gizle
dimstyle-suppress-first-dimension-line = Birinci ölçü çizgisini gizle
dimstyle-suppress-first-extension-line = Birinci uzatma çizgisini gizle
dimstyle-suppress-second-dimension-line = İkinci ölçü çizgisini gizle
dimstyle-suppress-second-extension-line = İkinci uzatma çizgisini gizle
dimstyle-suppress-zero-feet-and-inches = Sıfır fit ve sıfır inçi gizle
dimstyle-suppress-zero-feet-show-zero-inches = Sıfır fiti gizle; sıfır inçi göster
dimstyle-symbols-and-arrows = Simgeler ve Oklar
dimstyle-symmetrical = Simetrik
dimstyle-text-background = Metin arka planı
dimstyle-text-gap = Metin boşluğu
dimstyle-fixed-text-height-note = Seçili metin stili yüksekliği __ocs_arg_height__ olarak sabitler.
dimstyle-tick-size = İşaret boyutu
dimstyle-tolerance-zero-suppression = Tolerans sıfırlarını gizleme
dimstyle-unit-format = Birim biçimi
dimstyle-upper-value = Üst değer
dimstyle-measurement-template-help = Ölçülen değer için <> kullanın; önündeki ve arkasındaki metin, ön ek ve son ek olur.
dimstyle-use-different-arrowheads = Birinci ve ikinci ok uçlarını farklı kullan
dimstyle-use-fixed-length-extension-lines = Sabit uzunlukta uzatma çizgileri kullan
dimstyle-used-in-drawing = Çizimde kullanılıyor
dimstyle-vertical-offset = Dikey uzaklık
dimstyle-vertical-placement = Dikey yerleşim
dimstyle-vertical-position = Dikey konum
dimstyle-when-space-is-limited = Alan yetersiz olduğunda
dimstyle-when-text-is-moved = Metin taşındığında
dimstyle-zero-suppression = Sıfırları gizleme
dimstyle-add-a-leader = Kılavuz ekle
dimstyle-automatic = Otomatik
dimstyle-by-block = Bloğa göre
dimstyle-comma = Virgül
dimstyle-degrees-minutes-seconds = Derece, dakika, saniye
dimstyle-keep-dimension-line-with-text = Ölçü çizgisini metinle birlikte taşı
dimstyle-leading-and-trailing = Baştaki ve sondaki
dimstyle-move-arrows-outside-first = Önce okları dışarı taşı
dimstyle-move-text-and-arrows-outside = Metni ve okları dışarı taşı
dimstyle-move-text-freely = Metni serbestçe taşı
dimstyle-move-text-outside-first = Önce metni dışarı taşı
dimstyle-period = Nokta
dimstyle-space = Boşluk
style-manager-alignment-spacing = Hizalama aralığı
style-manager-always-left-align = Her zaman sola hizala
style-manager-attachment-direction = Bağlantı yönü
style-manager-background-fill-enabled = Arka plan dolgusu etkin
style-manager-big-font = Büyük yazı tipi
style-manager-block-scale-x = Blok X ölçeği
style-manager-block-scale-y = Blok Y ölçeği
style-manager-block-scale-z = Blok Z ölçeği
style-manager-borders = Kenarlar
style-manager-bottom-attachment = Alt bağlantı
style-manager-break-gap-size = Kesinti boşluğu boyutu
style-manager-caps-and-fill = Kapaklar ve Dolgu
style-manager-content-type = İçerik türü
style-manager-data-row = Veri Satırı
style-manager-data-type = Veri türü
style-manager-default-text = Varsayılan metin
style-manager-different = Farklı
style-manager-display-joints = Birleşimleri göster
style-manager-drawing-height = Çizim yüksekliği
style-manager-drawing-scale = Çizim ölçeği
style-manager-effects = Etkiler
style-manager-elements = Elemanlar
style-manager-end-caps = Bitiş kapakları
style-manager-fill-and-joints = Dolgu ve birleşimler
style-manager-fill-enabled = Dolgu etkin
style-manager-first-segment-angle = Birinci segment açısı
style-manager-fixed-height = Sabit yükseklik
style-manager-flow-direction = Akış yönü
style-manager-font-file = Yazı tipi dosyası
style-manager-fonts = Yazı tipleri
style-manager-format-string = Biçim dizgesi
style-manager-header = Sütun başlığı
style-manager-header-row = Sütun Başlığı Satırı
style-manager-horizontal-margin = Yatay kenar boşluğu
style-manager-inner-arcs = İç yaylar
style-manager-inside-horizontal = Yatay iç kenar
style-manager-inside-vertical = Dikey iç kenar
style-manager-leader-draw-order = Lider çizim sırası
style-manager-leader-note = Lider notu
style-manager-left-attachment = Sol bağlantı
style-manager-line-color = Çizgi rengi
style-manager-line-type = Çizgi türü
style-manager-line-weight = Çizgi kalınlığı
style-manager-maximum-leader-points = En fazla lider noktası
style-manager-multileader-draw-order = Çoklu lider çizim sırası
style-manager-no-preview = Önizleme yok
style-manager-oblique-angle = Eğiklik açısı
style-manager-outer-arc = Dış yay
style-manager-paper-height = Kağıt yüksekliği
style-manager-paper-text-height = Kağıt metin yüksekliği
style-manager-path-type = Yol türü
style-manager-right-attachment = Sağ bağlantı
style-manager-scale-factor = Ölçek çarpanı
style-manager-second-segment-angle = İkinci segment açısı
style-manager-size-and-effects = Boyut ve Etkiler
style-manager-start-caps = Başlangıç kapakları
style-manager-stroke-fonts = Çizgi yazı tipleri
style-manager-suppress-header-row = Sütun başlığı satırını gizle
style-manager-suppress-title-row = Tablo başlığı satırını gizle
style-manager-system-font = Sistem yazı tipi
style-manager-system-fonts = Sistem yazı tipleri
style-manager-text-alignment = Metin hizalaması
style-manager-text-angle = Metin açısı
style-manager-title-row = Tablo Başlığı Satırı
style-manager-top-attachment = Üst bağlantı
style-manager-unit-type = Birim türü
style-manager-vertical-margin = Dikey kenar boşluğu
style-manager-font-family-placeholder = yazı tipi ailesi…
style-manager-bottom-to-top = Aşağıdan yukarıya
style-manager-arrowhead-first = Önce ok ucu
style-manager-content-first = Önce içerik
style-manager-leader-first = Önce lider
style-manager-straight = Düz
style-manager-parallel-last-segment = Son segmente paralel
style-manager-top-of-top-line = Üst satırın üstü
style-manager-middle-of-top-line = Üst satırın ortası
style-manager-middle-of-text = Metnin ortası
style-manager-middle-of-bottom-line = Alt satırın ortası
style-manager-bottom-of-bottom-line = Alt satırın altı
style-manager-bottom-line = Alt satır
style-manager-underline-bottom-line = Alt satırın altını çiz
style-manager-underline-top-line = Üst satırın altını çiz
style-manager-underline-all-text = Tüm metnin altını çiz
style-manager-center-of-text = Metnin merkezi
style-manager-center-of-text-overline = Üst çizgili metin merkezi
style-manager-block-extents = Blok sınırları
style-manager-base-point = Taban noktası

View file

@ -3180,3 +3180,185 @@ catalog-mod-shortcuts-4c54bbb78e = ── __ocs_arg_MOD__ 快捷键 ────
catalog-custom-overrides-shortcuts-set-07be563dec = ── 自定义覆盖 (SHORTCUTS SET) ──────────────────
catalog-function-keys-b5a2df24e9 = ── 功能键 ──────────────────────────────────────
catalog-other-keys-a882812cf2 = ── 其他按键 ──────────────────────────────────────────
dimstyle-keep-text-between-extension-lines = 始终将文字置于尺寸界线之间
dimstyle-angular-dimensions = 角度标注
dimstyle-arc-length-symbol = 弧长符号
dimstyle-arrowheads = 箭头
dimstyle-available-style = 可用样式
dimstyle-baseline-spacing = 基线间距
dimstyle-basic = 基本尺寸
dimstyle-both-arrowheads = 两端箭头
dimstyle-center-mark = 圆心标记
dimstyle-center-mark-size = 圆心标记大小
dimstyle-center-marks = 圆心标记
dimstyle-centerlines = 中心线
dimstyle-compare-with = 比较对象
dimstyle-current-style = 当前样式
dimstyle-deviation = 偏差
dimstyle-different-sections = 存在差异的分区
dimstyle-dimension-line-color = 尺寸线颜色
dimstyle-dimension-linetype = 尺寸线线型
dimstyle-dimension-lineweight = 尺寸线线宽
dimstyle-display-alternate-units = 显示换算单位
dimstyle-draw-dimension-line-between-extension-lines = 在尺寸界线之间绘制尺寸线
dimstyle-extend-beyond-dimension-line = 超出尺寸线
dimstyle-extend-beyond-ticks = 超出斜线
dimstyle-extension-line-color = 尺寸界线颜色
dimstyle-extension-lineweight = 尺寸界线线宽
dimstyle-feet-and-inches = 英尺和英寸
dimstyle-fine-tuning = 精细调整
dimstyle-first-arrowhead = 第一个箭头
dimstyle-first-extension-linetype = 第一条尺寸界线线型
dimstyle-fit-options = 调整选项
dimstyle-fixed-length = 固定长度
dimstyle-fraction-format = 分数格式
dimstyle-height-scale = 高度比例
dimstyle-horizontal-placement = 水平位置
dimstyle-keep-text-horizontal-inside = 位于内部时保持文字水平
dimstyle-keep-text-horizontal-outside = 位于外部时保持文字水平
dimstyle-leader-arrowhead = 引线箭头
dimstyle-limits = 极限尺寸
dimstyle-linear-dimensions = 线性标注
dimstyle-lower-value = 下偏差
dimstyle-measurement-scale = 测量比例
dimstyle-measurement-template = 测量值模板
dimstyle-method = 方式
dimstyle-multiplier = 换算系数
dimstyle-no-differences = 无差异
dimstyle-not-applicable = 不适用
dimstyle-offset-from-measured-point = 与测量点的偏移
dimstyle-place-text-manually = 创建标注时手动放置文字
dimstyle-radius-jog-angle = 半径折弯角度 (°)
dimstyle-read-left-to-right = 从左向右阅读
dimstyle-referenced-read-only = 参照样式 · 只读
dimstyle-round-off = 舍入值
dimstyle-second-arrowhead = 第二个箭头
dimstyle-second-extension-linetype = 第二条尺寸界线线型
dimstyle-show-zero-feet-and-inches = 显示零英尺和零英寸
dimstyle-show-zero-feet-suppress-zero-inches = 显示零英尺;抑制零英寸
dimstyle-suppress-arrows-when-no-fit = 箭头无法容纳时将其隐藏
dimstyle-suppress-first-dimension-line = 隐藏第一条尺寸线
dimstyle-suppress-first-extension-line = 隐藏第一条尺寸界线
dimstyle-suppress-second-dimension-line = 隐藏第二条尺寸线
dimstyle-suppress-second-extension-line = 隐藏第二条尺寸界线
dimstyle-suppress-zero-feet-and-inches = 抑制零英尺和零英寸
dimstyle-suppress-zero-feet-show-zero-inches = 抑制零英尺;显示零英寸
dimstyle-symbols-and-arrows = 符号和箭头
dimstyle-symmetrical = 对称
dimstyle-text-background = 文字背景
dimstyle-text-gap = 文字间距
dimstyle-fixed-text-height-note = 所选文字样式将高度固定为 __ocs_arg_height__。
dimstyle-tick-size = 斜线大小
dimstyle-tolerance-zero-suppression = 公差零值抑制
dimstyle-unit-format = 单位格式
dimstyle-upper-value = 上偏差
dimstyle-measurement-template-help = 使用 <> 表示测量值;其前后的文字将分别成为前缀和后缀。
dimstyle-use-different-arrowheads = 两端使用不同箭头
dimstyle-use-fixed-length-extension-lines = 使用固定长度的尺寸界线
dimstyle-used-in-drawing = 已在图形中使用
dimstyle-vertical-offset = 垂直偏移
dimstyle-vertical-placement = 垂直位置
dimstyle-vertical-position = 垂直定位
dimstyle-when-space-is-limited = 空间不足时
dimstyle-when-text-is-moved = 移动文字时
dimstyle-zero-suppression = 零值抑制
dimstyle-add-a-leader = 添加引线
dimstyle-automatic = 自动
dimstyle-by-block = 随块
dimstyle-comma = 逗号
dimstyle-degrees-minutes-seconds = 度、分、秒
dimstyle-keep-dimension-line-with-text = 尺寸线随文字移动
dimstyle-leading-and-trailing = 前导和后续
dimstyle-move-arrows-outside-first = 优先将箭头移到外部
dimstyle-move-text-and-arrows-outside = 将文字和箭头移到外部
dimstyle-move-text-freely = 自由移动文字
dimstyle-move-text-outside-first = 优先将文字移到外部
dimstyle-period = 句点
dimstyle-space = 空格
style-manager-alignment-spacing = 对齐间距
style-manager-always-left-align = 始终左对齐
style-manager-attachment-direction = 附着方向
style-manager-background-fill-enabled = 启用背景填充
style-manager-big-font = 大字体
style-manager-block-scale-x = 块 X 比例
style-manager-block-scale-y = 块 Y 比例
style-manager-block-scale-z = 块 Z 比例
style-manager-borders = 边框
style-manager-bottom-attachment = 底部附着
style-manager-break-gap-size = 打断间隙大小
style-manager-caps-and-fill = 端盖和填充
style-manager-content-type = 内容类型
style-manager-data-row = 数据行
style-manager-data-type = 数据类型
style-manager-default-text = 默认文字
style-manager-different = 不同
style-manager-display-joints = 显示接合处
style-manager-drawing-height = 图形高度
style-manager-drawing-scale = 图形比例
style-manager-effects = 效果
style-manager-elements = 元素
style-manager-end-caps = 终点端盖
style-manager-fill-and-joints = 填充和接合处
style-manager-fill-enabled = 启用填充
style-manager-first-segment-angle = 第一段角度
style-manager-fixed-height = 固定高度
style-manager-flow-direction = 排列方向
style-manager-font-file = 字体文件
style-manager-fonts = 字体
style-manager-format-string = 格式字符串
style-manager-header = 列标题
style-manager-header-row = 列标题行
style-manager-horizontal-margin = 水平边距
style-manager-inner-arcs = 内弧
style-manager-inside-horizontal = 内部水平
style-manager-inside-vertical = 内部垂直
style-manager-leader-draw-order = 引线绘制顺序
style-manager-leader-note = 引线注释
style-manager-left-attachment = 左侧附着
style-manager-line-color = 线颜色
style-manager-line-type = 线型
style-manager-line-weight = 线宽
style-manager-maximum-leader-points = 最大引线点数
style-manager-multileader-draw-order = 多重引线绘制顺序
style-manager-no-preview = 无预览
style-manager-oblique-angle = 倾斜角
style-manager-outer-arc = 外弧
style-manager-paper-height = 图纸高度
style-manager-paper-text-height = 图纸文字高度
style-manager-path-type = 路径类型
style-manager-right-attachment = 右侧附着
style-manager-scale-factor = 比例因子
style-manager-second-segment-angle = 第二段角度
style-manager-size-and-effects = 大小和效果
style-manager-start-caps = 起点端盖
style-manager-stroke-fonts = 线性字体
style-manager-suppress-header-row = 隐藏列标题行
style-manager-suppress-title-row = 隐藏标题行
style-manager-system-font = 系统字体
style-manager-system-fonts = 系统字体
style-manager-text-alignment = 文字对齐
style-manager-text-angle = 文字角度
style-manager-title-row = 标题行
style-manager-top-attachment = 顶部附着
style-manager-unit-type = 单位类型
style-manager-vertical-margin = 垂直边距
style-manager-font-family-placeholder = 字体族…
style-manager-bottom-to-top = 从下到上
style-manager-arrowhead-first = 先绘制箭头
style-manager-content-first = 先绘制内容
style-manager-leader-first = 先绘制引线
style-manager-straight = 直线
style-manager-parallel-last-segment = 平行于最后一段
style-manager-top-of-top-line = 顶行顶部
style-manager-middle-of-top-line = 顶行中部
style-manager-middle-of-text = 文字中部
style-manager-middle-of-bottom-line = 底行中部
style-manager-bottom-of-bottom-line = 底行底部
style-manager-bottom-line = 底行
style-manager-underline-bottom-line = 底行下划线
style-manager-underline-top-line = 顶行下划线
style-manager-underline-all-text = 所有文字下划线
style-manager-center-of-text = 文字中心
style-manager-center-of-text-overline = 带上划线的文字中心
style-manager-block-extents = 块范围
style-manager-base-point = 基点

View file

@ -670,9 +670,18 @@ pub(super) struct OpenCADStudio {
// ── MLineStyle Dialog ─────────────────────────────────────────────────
mlstyle_selected: String,
mlstyle_tab: u8,
mlstyle_compare: String,
mln_description: String,
mln_start_angle: String,
mln_end_angle: String,
mln_fill_color: String,
mln_elements: Vec<[String; 3]>,
// ── MLeaderStyle Dialog ───────────────────────────────────────────────
mleaderstyle_selected: String,
mleaderstyle_tab: u8,
mleaderstyle_compare: String,
/// Colour field whose expanded palette is open (line/text/block).
mls_color_open: Option<&'static str>,
mls_landing_distance: String,
@ -697,6 +706,8 @@ pub(super) struct OpenCADStudio {
// ── TableStyle Dialog ─────────────────────────────────────────────────
tablestyle_selected: String,
tablestyle_tab: u8,
tablestyle_compare: String,
/// Edit buffers for the table style's general margins.
ts_hmargin: String,
ts_vmargin: String,
@ -732,6 +743,8 @@ pub(super) struct OpenCADStudio {
// ── TextStyle Font Browser ────────────────────────────────────────────
textstyle_selected: String,
textstyle_tab: u8,
textstyle_compare: String,
/// Edit buffer for font file name.
textstyle_font: String,
/// Edit buffer for width factor.
@ -868,8 +881,10 @@ pub(super) struct OpenCADStudio {
dimstyle_selected: String,
/// Which colour field currently has its expanded palette open (if any).
ds_color_open: Option<DsField>,
/// Active tab: 0=Lines, 1=Arrows, 2=Text, 3=Scale/Units, 4=Tolerances.
/// Active property group in the dimension style manager.
dimstyle_tab: u8,
/// Style used by the manager's comparison summary.
dimstyle_compare: String,
// Edit buffers (strings while typing):
ds_dimdle: String,
ds_dimdli: String,
@ -2438,6 +2453,8 @@ pub enum Message {
#[allow(dead_code)]
TextStyleDialogClose,
TextStyleDialogSelect(String),
TextStyleDialogTab(u8),
TextStyleDialogCompare(String),
TextStyleDialogSetCurrent,
TextStyleDialogNew,
TextStyleDialogCopy,
@ -2465,6 +2482,8 @@ pub enum Message {
#[allow(dead_code)]
TableStyleDialogClose,
TableStyleDialogSelect(String),
TableStyleDialogTab(u8),
TableStyleDialogCompare(String),
TableStyleDialogNew,
TableStyleDialogCopy,
TableStyleDialogDelete,
@ -2523,16 +2542,32 @@ pub enum Message {
#[allow(dead_code)]
MlStyleDialogClose,
MlStyleDialogSelect(String),
MlStyleDialogTab(u8),
MlStyleDialogCompare(String),
MlStyleDialogSetCurrent,
MlStyleApply,
MlStyleDialogNew,
MlStyleDialogCopy,
MlStyleDialogDelete,
MlStyleEdit {
field: &'static str,
value: String,
},
MlStyleToggle(&'static str),
MlStyleElementEdit {
index: usize,
field: &'static str,
value: String,
},
MlStyleElementAdd,
MlStyleElementDelete(usize),
// ── MLeaderStyle Dialog ───────────────────────────────────────────────
MLeaderStyleDialogOpen,
#[allow(dead_code)]
MLeaderStyleDialogClose,
MLeaderStyleDialogSelect(String),
MLeaderStyleDialogTab(u8),
MLeaderStyleDialogCompare(String),
MLeaderStyleDialogSetCurrent,
MLeaderStyleDialogNew,
MLeaderStyleDialogCopy,
@ -2565,6 +2600,8 @@ pub enum Message {
DimStyleDialogSelect(String),
/// Switch the active tab.
DimStyleDialogTab(u8),
/// Change the style used by the comparison summary.
DimStyleDialogCompare(String),
/// Create a new empty style (prompts via command line).
DimStyleDialogNew,
DimStyleDialogCopy,
@ -2575,6 +2612,14 @@ pub enum Message {
// Field edit messages:
DsEdit(DsField, String),
DsToggle(DsField),
/// Select the mutually-exclusive tolerance presentation.
DsToleranceMode(String),
/// Change the feet/inches mode in a zero-suppression bit field.
DsZeroBase(DsField, i16),
/// Toggle leading/trailing suppression in a zero-suppression bit field.
DsZeroFlag(DsField, i16),
/// Select no center mark, a mark, or centerlines.
DsCenterMarkMode(String),
/// Toggle the expanded colour palette for a DimStyle colour field.
DsColorMore(DsField),
/// Open the `iced_aw` colour picker for a field and its current colour.
@ -2887,6 +2932,8 @@ impl OpenCADStudio {
style_rename_buf: String::new(),
style_stage: None,
textstyle_selected: "Standard".to_string(),
textstyle_tab: 0,
textstyle_compare: String::new(),
textstyle_font: String::new(),
textstyle_width: "1.0".to_string(),
textstyle_oblique: "0.0".to_string(),
@ -2895,6 +2942,8 @@ impl OpenCADStudio {
textstyle_ttf: String::new(),
// TableStyle dialog
tablestyle_selected: "Standard".to_string(),
tablestyle_tab: 0,
tablestyle_compare: String::new(),
ts_hmargin: "1.5".to_string(),
ts_vmargin: "1.5".to_string(),
ts_description: String::new(),
@ -2911,8 +2960,17 @@ impl OpenCADStudio {
ts_border_spacing: Default::default(),
// MLineStyle dialog
mlstyle_selected: "Standard".to_string(),
mlstyle_tab: 0,
mlstyle_compare: String::new(),
mln_description: String::new(),
mln_start_angle: "90".to_string(),
mln_end_angle: "90".to_string(),
mln_fill_color: "256".to_string(),
mln_elements: Vec::new(),
// MLeaderStyle dialog
mleaderstyle_selected: "Standard".to_string(),
mleaderstyle_tab: 0,
mleaderstyle_compare: String::new(),
mls_color_open: None,
mls_landing_distance: String::new(),
mls_landing_gap: String::new(),
@ -2937,6 +2995,7 @@ impl OpenCADStudio {
dimstyle_selected: "Standard".to_string(),
ds_color_open: None,
dimstyle_tab: 0,
dimstyle_compare: String::new(),
ds_dimdle: "0".to_string(),
ds_dimdli: "3.75".to_string(),
ds_dimgap: "0.625".to_string(),

View file

@ -301,7 +301,7 @@ impl OpenCADStudio {
}
}
fn style_in_use(&self, kind: StyleKind, name: &str) -> bool {
pub(super) fn style_in_use(&self, kind: StyleKind, name: &str) -> bool {
use acadrust::entities::EntityType;
let i = self.active_tab;
@ -613,6 +613,20 @@ impl OpenCADStudio {
pub(super) fn style_delete(&mut self, kind: StyleKind) {
let name = self.style_selected(kind);
if matches!(kind, StyleKind::Dim)
&& self.tabs[self.active_tab]
.scene
.document
.dim_styles
.get(&name)
.is_some_and(|style| {
style.xref_reference || style.xref_dependent || !style.xref_handle.is_null()
})
{
self.command_line
.push_error(crate::t!("Referenced styles are read only.").as_ref());
return;
}
if name.eq_ignore_ascii_case("Standard") {
self.command_line
.push_error(crate::t!("Cannot delete the Standard style.").as_ref());
@ -657,6 +671,20 @@ impl OpenCADStudio {
if new.is_empty() || new.eq_ignore_ascii_case(&old) {
return;
}
if matches!(kind, StyleKind::Dim)
&& self.tabs[self.active_tab]
.scene
.document
.dim_styles
.get(&old)
.is_some_and(|style| {
style.xref_reference || style.xref_dependent || !style.xref_handle.is_null()
})
{
self.command_line
.push_error(crate::t!("Referenced styles are read only.").as_ref());
return;
}
if old.eq_ignore_ascii_case("Standard") {
self.command_line
.push_error(crate::t!("Cannot rename the Standard style.").as_ref());

View file

@ -5408,11 +5408,25 @@ impl OpenCADStudio {
self.load_textstyle_bufs(i);
Task::none()
}
Message::TextStyleDialogTab(tab) => {
self.textstyle_tab = tab;
Task::none()
}
Message::TextStyleDialogCompare(name) => {
self.textstyle_compare = name;
Task::none()
}
Message::TextStyleDialogSetCurrent => {
// Staged: persists on Apply.
let i = self.active_tab;
let name = self.textstyle_selected.clone();
if self.tabs[i].scene.document.text_styles.get(&name).is_some() {
if self.tabs[i]
.scene
.document
.text_styles
.get(&name)
.is_some_and(|style| !style.xref_dependent)
{
self.tabs[i].scene.document.header.current_text_style_name = name.clone();
self.sync_ribbon_styles();
self.command_line
@ -5468,9 +5482,13 @@ impl OpenCADStudio {
let i = self.active_tab;
let name = self.textstyle_selected.clone();
if let Some(s) = self.tabs[i].scene.document.text_styles.get_mut(&name) {
if s.xref_dependent {
return Task::none();
}
match field {
"backward" => s.flags.backward = !s.flags.backward,
"upside_down" => s.flags.upside_down = !s.flags.upside_down,
"vertical" => s.is_vertical = !s.is_vertical,
"annotative" => s.annotative = !s.annotative,
_ => {}
}
@ -5481,8 +5499,17 @@ impl OpenCADStudio {
Message::TextStyleFontPick(font_file) => {
// Staged: update the buffer + live style; persist on Apply.
let i = self.active_tab;
self.textstyle_font = font_file.clone();
let name = self.textstyle_selected.clone();
if self.tabs[i]
.scene
.document
.text_styles
.get(&name)
.is_some_and(|style| style.xref_dependent)
{
return Task::none();
}
self.textstyle_font = font_file.clone();
if let Some(s) = self.tabs[i].scene.document.text_styles.get_mut(&name) {
s.font_file = font_file;
}
@ -5516,12 +5543,23 @@ impl OpenCADStudio {
Task::none()
}
Message::TableStyleDialogSelect(name) => {
for row in 0..3 {
let _ = self.on_table_style_cell_apply(row);
}
self.stage_tablestyle_bufs();
self.tablestyle_selected = name;
let i = self.active_tab;
self.load_tablestyle_bufs(i);
Task::none()
}
Message::TableStyleDialogTab(tab) => {
self.tablestyle_tab = tab;
Task::none()
}
Message::TableStyleDialogCompare(name) => {
self.tablestyle_compare = name;
Task::none()
}
Message::TableStyleEdit { field, value } => {
match field {
@ -5534,6 +5572,9 @@ impl OpenCADStudio {
}
Message::TableStyleApply => {
for row in 0..3 {
let _ = self.on_table_style_cell_apply(row);
}
self.stage_tablestyle_bufs();
self.style_stage_commit();
Task::none()
@ -5728,7 +5769,18 @@ impl OpenCADStudio {
Task::none()
}
Message::MlStyleDialogSelect(name) => {
self.stage_mlstyle_bufs();
self.mlstyle_selected = name;
let i = self.active_tab;
self.load_mlstyle_bufs(i);
Task::none()
}
Message::MlStyleDialogTab(tab) => {
self.mlstyle_tab = tab;
Task::none()
}
Message::MlStyleDialogCompare(name) => {
self.mlstyle_compare = name;
Task::none()
}
Message::MlStyleDialogSetCurrent => {
@ -5749,13 +5801,8 @@ impl OpenCADStudio {
}
Task::none()
}
// Placeholder so the Multiline manager has the same Set Current +
// Apply pair as every other style manager. The editor is currently
// read-only, so there is nothing to apply yet — wire this up when
// editable MLineStyle properties land.
Message::MlStyleApply => {
// Multiline styles have no editable properties yet; Apply still
// commits any staged structural / current-style changes.
self.stage_mlstyle_bufs();
self.style_stage_commit();
Task::none()
}
@ -5771,6 +5818,66 @@ impl OpenCADStudio {
self.style_delete(crate::app::StyleKind::MLine);
Task::none()
}
Message::MlStyleEdit { field, value } => {
match field {
"description" => self.mln_description = value,
"start_angle" => self.mln_start_angle = value,
"end_angle" => self.mln_end_angle = value,
"fill_color" => self.mln_fill_color = value,
_ => {}
}
self.stage_mlstyle_bufs();
Task::none()
}
Message::MlStyleToggle(field) => {
let i = self.active_tab;
if let Some(style) = self.mlstyle_mut(i) {
match field {
"fill" => style.flags.fill_on = !style.flags.fill_on,
"joints" => style.flags.display_joints = !style.flags.display_joints,
"start_square" => style.flags.start_square_cap = !style.flags.start_square_cap,
"start_inner" => style.flags.start_inner_arcs_cap = !style.flags.start_inner_arcs_cap,
"start_round" => style.flags.start_round_cap = !style.flags.start_round_cap,
"end_square" => style.flags.end_square_cap = !style.flags.end_square_cap,
"end_inner" => style.flags.end_inner_arcs_cap = !style.flags.end_inner_arcs_cap,
"end_round" => style.flags.end_round_cap = !style.flags.end_round_cap,
_ => {}
}
}
Task::none()
}
Message::MlStyleElementEdit { index, field, value } => {
if let Some(element) = self.mln_elements.get_mut(index) {
match field {
"offset" => element[0] = value,
"color" => element[1] = value,
"linetype" => element[2] = value,
_ => {}
}
}
self.stage_mlstyle_bufs();
Task::none()
}
Message::MlStyleElementAdd => {
let i = self.active_tab;
if let Some(style) = self.mlstyle_mut(i) {
style
.elements
.push(acadrust::objects::MLineStyleElement::default());
}
self.load_mlstyle_bufs(i);
Task::none()
}
Message::MlStyleElementDelete(index) => {
let i = self.active_tab;
if let Some(style) = self.mlstyle_mut(i) {
if style.elements.len() > 1 && index < style.elements.len() {
style.elements.remove(index);
}
}
self.load_mlstyle_bufs(i);
Task::none()
}
// ── MLeaderStyle Dialog ───────────────────────────────────────────
Message::MLeaderStyleDialogOpen => self.on_mleader_style_dialog_open(),
@ -5785,6 +5892,14 @@ impl OpenCADStudio {
self.load_mleaderstyle_bufs(i);
Task::none()
}
Message::MLeaderStyleDialogTab(tab) => {
self.mleaderstyle_tab = tab;
Task::none()
}
Message::MLeaderStyleDialogCompare(name) => {
self.mleaderstyle_compare = name;
Task::none()
}
Message::MLeaderStyleDialogSetCurrent => self.on_mleader_style_dialog_set_current(),
Message::MLeaderStyleDialogNew => {
self.style_new(crate::app::StyleKind::MLeader);
@ -5864,6 +5979,10 @@ impl OpenCADStudio {
self.dimstyle_tab = tab;
Task::none()
}
Message::DimStyleDialogCompare(name) => {
self.dimstyle_compare = name;
Task::none()
}
Message::DimStyleDialogNew => {
self.style_new(crate::app::StyleKind::Dim);
Task::none()
@ -5875,6 +5994,19 @@ impl OpenCADStudio {
Message::DimStyleDialogSetCurrent => {
// Staged: persists on Apply.
let i = self.active_tab;
let read_only = self.tabs[i]
.scene
.document
.dim_styles
.get(&self.dimstyle_selected)
.is_some_and(|style| {
style.xref_reference
|| style.xref_dependent
|| !style.xref_handle.is_null()
});
if read_only {
return Task::none();
}
self.tabs[i].scene.document.header.current_dimstyle_name =
self.dimstyle_selected.clone();
self.sync_ribbon_styles();
@ -5894,7 +6026,75 @@ impl OpenCADStudio {
Task::none()
}
Message::DsToggle(field) => {
let separate_arrows = field == crate::app::DsField::Dimsah;
self.apply_ds_toggle(field);
if separate_arrows && self.ds_dimsah {
let i = self.active_tab;
if let Some(style) = self.tabs[i]
.scene
.document
.dim_styles
.get_mut(&self.dimstyle_selected)
{
if style.dimblk1.is_null() {
style.dimblk1 = style.dimblk;
}
if style.dimblk2.is_null() {
style.dimblk2 = style.dimblk1;
}
}
}
Task::none()
}
Message::DsToleranceMode(mode) => {
self.ds_dimlim = mode == "limits";
self.ds_dimtol = matches!(mode.as_str(), "symmetrical" | "deviation");
if mode == "symmetrical" {
self.ds_dimtm = self.ds_dimtp.clone();
}
let gap = self.ds_dimgap.trim().parse::<f64>().unwrap_or(0.625).abs();
self.ds_dimgap = if mode == "basic" {
format!("-{}", gap.max(f64::EPSILON))
} else {
format!("{}", gap)
};
Task::none()
}
Message::DsZeroBase(field, base) => {
let current = match &field {
crate::app::DsField::Dimzin => &self.ds_dimzin,
crate::app::DsField::Dimaltz => &self.ds_dimaltz,
crate::app::DsField::Dimalttz => &self.ds_dimalttz,
crate::app::DsField::Dimtzin => &self.ds_dimtzin,
_ => return Task::none(),
}
.trim()
.parse::<i16>()
.unwrap_or(0);
self.apply_ds_edit(field, ((current & !3) | (base & 3)).to_string());
Task::none()
}
Message::DsZeroFlag(field, bit) => {
let current = match &field {
crate::app::DsField::Dimzin => &self.ds_dimzin,
crate::app::DsField::Dimaltz => &self.ds_dimaltz,
crate::app::DsField::Dimalttz => &self.ds_dimalttz,
crate::app::DsField::Dimtzin => &self.ds_dimtzin,
_ => return Task::none(),
}
.trim()
.parse::<i16>()
.unwrap_or(0);
self.apply_ds_edit(field, (current ^ bit).to_string());
Task::none()
}
Message::DsCenterMarkMode(mode) => {
let size = self.ds_dimcen.trim().parse::<f64>().unwrap_or(0.09).abs();
self.ds_dimcen = match mode.as_str() {
"mark" => size.max(f64::EPSILON).to_string(),
"lines" => format!("-{}", size.max(f64::EPSILON)),
_ => "0".to_string(),
};
Task::none()
}
Message::DsColorMore(field) => {

View file

@ -22,6 +22,91 @@ use iced::{mouse, Point, Task};
impl OpenCADStudio {
pub(in crate::app) fn mlstyle_mut(
&mut self,
tab: usize,
) -> Option<&mut acadrust::objects::MLineStyle> {
use acadrust::objects::ObjectType;
let name = self.mlstyle_selected.clone();
self.tabs[tab]
.scene
.document
.objects
.values_mut()
.find_map(|object| match object {
ObjectType::MLineStyle(style) if style.name == name => Some(style),
_ => None,
})
}
pub(in crate::app) fn load_mlstyle_bufs(&mut self, tab: usize) {
use acadrust::objects::ObjectType;
let name = self.mlstyle_selected.clone();
let Some((description, start_angle, end_angle, fill_color, elements)) = self.tabs[tab]
.scene
.document
.objects
.values()
.find_map(|object| match object {
ObjectType::MLineStyle(style) if style.name == name => Some((
style.description.clone(),
style.start_angle.to_degrees(),
style.end_angle.to_degrees(),
style.fill_color.index().unwrap_or(256),
style
.elements
.iter()
.map(|element| {
[
format!("{}", element.offset),
element.color.index().unwrap_or(256).to_string(),
element.linetype.clone(),
]
})
.collect::<Vec<_>>(),
)),
_ => None,
})
else {
return;
};
self.mln_description = description;
self.mln_start_angle = format!("{start_angle:.4}");
self.mln_end_angle = format!("{end_angle:.4}");
self.mln_fill_color = fill_color.to_string();
self.mln_elements = elements;
}
pub(in crate::app) fn stage_mlstyle_bufs(&mut self) {
let tab = self.active_tab;
let description = self.mln_description.clone();
let start_angle = self.mln_start_angle.trim().parse::<f64>().ok();
let end_angle = self.mln_end_angle.trim().parse::<f64>().ok();
let fill_color = self.mln_fill_color.trim().parse::<i16>().ok();
let elements = self.mln_elements.clone();
if let Some(style) = self.mlstyle_mut(tab) {
style.description = description;
if let Some(value) = start_angle {
style.start_angle = value.to_radians();
}
if let Some(value) = end_angle {
style.end_angle = value.to_radians();
}
if let Some(value) = fill_color {
style.fill_color = acadrust::types::Color::from_index(value);
}
for (element, values) in style.elements.iter_mut().zip(elements) {
if let Ok(value) = values[0].trim().parse::<f64>() {
element.offset = value;
}
if let Ok(value) = values[1].trim().parse::<i16>() {
element.color = acadrust::types::Color::from_index(value);
}
element.linetype = values[2].clone();
}
}
}
pub(in crate::app) fn tablestyle_mut(&mut self, tab: usize) -> Option<&mut acadrust::objects::TableStyle> {
use acadrust::objects::ObjectType;
let name = self.tablestyle_selected.clone();
@ -163,8 +248,8 @@ impl OpenCADStudio {
self.mls_text_height = format!("{:.4}", s.text_height);
self.mls_scale_factor = format!("{:.4}", s.scale_factor);
self.mls_break_gap = format!("{:.4}", s.break_gap_size);
self.mls_first_seg_angle = format!("{:.4}", s.first_segment_angle);
self.mls_second_seg_angle = format!("{:.4}", s.second_segment_angle);
self.mls_first_seg_angle = format!("{:.4}", s.first_segment_angle.to_degrees());
self.mls_second_seg_angle = format!("{:.4}", s.second_segment_angle.to_degrees());
self.mls_max_points = s.max_leader_points.to_string();
self.mls_default_text = s.default_text.clone();
self.mls_line_color = s
@ -184,7 +269,7 @@ impl OpenCADStudio {
.index()
.map(|c| c.to_string())
.unwrap_or_default();
self.mls_block_rotation = format!("{:.4}", s.block_content_rotation);
self.mls_block_rotation = format!("{:.4}", s.block_content_rotation.to_degrees());
self.mls_block_scale_x = format!("{:.4}", s.block_content_scale_x);
self.mls_block_scale_y = format!("{:.4}", s.block_content_scale_y);
self.mls_block_scale_z = format!("{:.4}", s.block_content_scale_z);
@ -273,6 +358,20 @@ impl OpenCADStudio {
pub(in crate::app) fn apply_dimstyle_bufs(&mut self, tab: usize) {
let doc = &mut self.tabs[tab].scene.document;
let read_only = doc
.dim_styles
.get(&self.dimstyle_selected)
.is_some_and(|style| {
style.xref_reference || style.xref_dependent || !style.xref_handle.is_null()
});
if read_only {
return;
}
let text_style_handle = doc
.text_styles
.get(&self.ds_dimtxsty)
.map(|style| style.handle)
.unwrap_or(acadrust::types::Handle::NULL);
let Some(ds) = doc.dim_styles.get_mut(&self.dimstyle_selected) else {
return;
};
@ -323,6 +422,7 @@ impl OpenCADStudio {
ds.dimlim = self.ds_dimlim;
ds.dimpost = self.ds_dimpost.clone();
ds.dimtxsty = self.ds_dimtxsty.clone();
ds.dimtxsty_handle = text_style_handle;
ds.annotative = self.ds_annotative;
set_i16!(dimclrd, self.ds_dimclrd);
set_i16!(dimlwd, self.ds_dimlwd);
@ -392,7 +492,15 @@ impl OpenCADStudio {
Dimlunit => self.ds_dimlunit = val,
Dimdec => self.ds_dimdec = val,
Dimpost => self.ds_dimpost = val,
Dimtp => self.ds_dimtp = val,
Dimtp => {
let symmetrical = self.ds_dimtol
&& !self.ds_dimlim
&& self.ds_dimtp.trim() == self.ds_dimtm.trim();
self.ds_dimtp = val.clone();
if symmetrical {
self.ds_dimtm = val;
}
}
Dimtm => self.ds_dimtm = val,
Dimtdec => self.ds_dimtdec = val,
Dimtfac => self.ds_dimtfac = val,
@ -518,6 +626,9 @@ pub(super) fn on_text_style_dialog_open(&mut self) -> Task<Message> {
let bigfont = self.textstyle_bigfont.clone();
let ttf = self.textstyle_ttf.clone();
if let Some(s) = self.tabs[i].scene.document.text_styles.get_mut(&name) {
if s.xref_dependent {
return;
}
s.font_file = font;
s.big_font_file = bigfont;
s.true_type_font = ttf;
@ -629,6 +740,7 @@ pub(super) fn on_text_style_dialog_open(&mut self) -> Task<Message> {
.unwrap_or_else(|| "Standard".to_string())
};
self.active_modal = Some(crate::app::ModalKind::MlStyle);
self.load_mlstyle_bufs(i);
self.style_stage_begin();
Task::none()
}
@ -818,7 +930,10 @@ pub(super) fn on_text_style_dialog_open(&mut self) -> Task<Message> {
pub(super) fn on_mleader_style_set_handle(&mut self, field: &'static str, value: String) -> Task<Message> {
let i = self.active_tab;
let doc = &self.tabs[i].scene.document;
let handle: Option<acadrust::types::Handle> = if value == "None" {
let handle: Option<acadrust::types::Handle> = if value == "None"
|| value == "ByBlock"
|| value == "Closed filled"
{
None
} else {
match field {
@ -897,10 +1012,10 @@ pub(super) fn on_text_style_dialog_open(&mut self) -> Task<Message> {
s.break_gap_size = v;
}
if let Some(v) = fsa {
s.first_segment_angle = v;
s.first_segment_angle = v.to_radians();
}
if let Some(v) = ssa {
s.second_segment_angle = v;
s.second_segment_angle = v.to_radians();
}
if let Some(v) = mp {
s.max_leader_points = v;
@ -920,7 +1035,7 @@ pub(super) fn on_text_style_dialog_open(&mut self) -> Task<Message> {
s.block_content_color = acadrust::types::Color::from_index(v);
}
if let Some(v) = brot {
s.block_content_rotation = v;
s.block_content_rotation = v.to_radians();
}
if let Some(v) = bsx {
s.block_content_scale_x = v;
@ -962,6 +1077,14 @@ pub(super) fn on_text_style_dialog_open(&mut self) -> Task<Message> {
.unwrap_or_else(|| "Standard".to_string())
};
self.dimstyle_selected = selected.clone();
self.dimstyle_compare = self.tabs[i]
.scene
.document
.dim_styles
.iter()
.map(|style| style.name.clone())
.find(|name| !name.eq_ignore_ascii_case(&selected))
.unwrap_or_default();
self.load_dimstyle_bufs(i);
self.active_modal = Some(crate::app::ModalKind::DimStyle);
self.style_stage_begin();
@ -1018,6 +1141,11 @@ pub(super) fn on_text_style_dialog_open(&mut self) -> Task<Message> {
"dimltex_handle" | "dimltex1_handle" | "dimltex2_handle"
);
let doc = &self.tabs[i].scene.document;
if doc.dim_styles.get(&name).is_some_and(|style| {
style.xref_reference || style.xref_dependent || !style.xref_handle.is_null()
}) {
return Task::none();
}
let handle = if value == "Default" || value == "ByBlock" {
acadrust::types::Handle::NULL
} else if is_lt {
@ -1037,7 +1165,10 @@ pub(super) fn on_text_style_dialog_open(&mut self) -> Task<Message> {
if let Some(ds) = self.tabs[i].scene.document.dim_styles.get_mut(&name) {
match field {
"dimblk" => ds.dimblk = handle,
"dimblk1" => ds.dimblk1 = handle,
"dimblk1" => {
ds.dimblk1 = handle;
ds.dimblk2 = handle;
}
"dimblk2" => ds.dimblk2 = handle,
"dimldrblk" => ds.dimldrblk = handle,
"dimltex_handle" => ds.dimltex_handle = handle,

View file

@ -362,6 +362,7 @@ impl OpenCADStudio {
),
super::super::ModalKind::TextStyle => {
let tab = &self.tabs[self.active_tab];
let doc = &tab.scene.document;
let styles: Vec<String> = tab
.scene
.document
@ -369,23 +370,77 @@ impl OpenCADStudio {
.iter()
.map(|s| s.name.clone())
.collect();
let (backward, upside_down, annotative) = tab
.scene
.document
let selected_style = doc
.text_styles
.get(&self.textstyle_selected)
.map(|s| (s.flags.backward, s.flags.upside_down, s.annotative))
.unwrap_or((false, false, false));
.get(&self.textstyle_selected);
let (backward, upside_down, vertical, annotative, read_only) = selected_style
.map(|style| {
(
style.flags.backward,
style.flags.upside_down,
style.is_vertical,
style.annotative,
style.xref_dependent,
)
})
.unwrap_or((false, false, false, false, false));
let in_use = self.style_in_use(
crate::app::StyleKind::Text,
&self.textstyle_selected,
);
let compare_opts: Vec<String> = styles
.iter()
.filter(|name| !name.eq_ignore_ascii_case(&self.textstyle_selected))
.cloned()
.collect();
let compare_name = compare_opts
.iter()
.find(|name| name.eq_ignore_ascii_case(&self.textstyle_compare))
.cloned()
.or_else(|| compare_opts.first().cloned())
.unwrap_or_default();
let mut comparison_sections = Vec::new();
if let (Some(a), Some(b)) = (selected_style, doc.text_styles.get(&compare_name)) {
if (
&a.font_file,
&a.big_font_file,
&a.true_type_font,
a.is_shape_file,
) != (
&b.font_file,
&b.big_font_file,
&b.true_type_font,
b.is_shape_file,
) {
comparison_sections.push(crate::i18n::translate("Fonts").into_owned());
}
if (a.height, a.width_factor, a.oblique_angle, a.last_height)
!= (b.height, b.width_factor, b.oblique_angle, b.last_height)
{
comparison_sections.push(crate::i18n::translate("Size").into_owned());
}
if (a.flags, a.is_vertical, a.annotative)
!= (b.flags, b.is_vertical, b.annotative)
{
comparison_sections.push(crate::i18n::translate("Effects").into_owned());
}
}
sized_flow(
ex,
860,
480,
960,
680,
|flow| {
crate::ui::style::textstyle::view_window(
crate::ui::style::textstyle::TextStyleView {
styles: styles.clone(),
selected: &self.textstyle_selected,
current: &tab.scene.document.header.current_text_style_name,
tab: self.textstyle_tab,
compare_name: compare_name.clone(),
compare_opts: compare_opts.clone(),
comparison_sections: comparison_sections.clone(),
read_only,
in_use,
font_buf: &self.textstyle_font,
width_buf: &self.textstyle_width,
oblique_buf: &self.textstyle_oblique,
@ -394,6 +449,7 @@ impl OpenCADStudio {
ttf_buf: &self.textstyle_ttf,
backward,
upside_down,
vertical,
annotative,
rename_active: self.style_rename.as_deref(),
rename_buf: &self.style_rename_buf,
@ -420,18 +476,60 @@ impl OpenCADStudio {
ObjectType::MLineStyle(s) if s.name == self.mlstyle_selected => Some(s),
_ => None,
});
let compare_opts: Vec<String> = styles
.iter()
.filter(|name| !name.eq_ignore_ascii_case(&self.mlstyle_selected))
.cloned()
.collect();
let compare_name = compare_opts
.iter()
.find(|name| name.eq_ignore_ascii_case(&self.mlstyle_compare))
.cloned()
.or_else(|| compare_opts.first().cloned())
.unwrap_or_default();
let compare_style = tab.scene.document.objects.values().find_map(|object| match object {
ObjectType::MLineStyle(style) if style.name == compare_name => Some(style),
_ => None,
});
let mut comparison_sections = Vec::new();
if let (Some(a), Some(b)) = (selected_style, compare_style) {
if (&a.description, a.flags, a.fill_color, a.start_angle, a.end_angle)
!= (&b.description, b.flags, b.fill_color, b.start_angle, b.end_angle)
{
comparison_sections.push(crate::i18n::translate("Caps and Fill").into_owned());
}
if a.elements != b.elements {
comparison_sections.push(crate::i18n::translate("Elements").into_owned());
}
}
let in_use = self.style_in_use(
crate::app::StyleKind::MLine,
&self.mlstyle_selected,
);
sized_flow(
ex,
620,
420,
960,
680,
|flow| {
crate::ui::style::mlstyle::view_window(
styles.clone(),
&self.mlstyle_selected,
selected_style,
tab.scene.document.header.multiline_style.clone(),
self.style_rename.as_deref(),
&self.style_rename_buf,
crate::ui::style::mlstyle::MlStyleView {
styles: styles.clone(),
selected: &self.mlstyle_selected,
style: selected_style,
current: tab.scene.document.header.multiline_style.clone(),
tab: self.mlstyle_tab,
compare_name: compare_name.clone(),
compare_opts: compare_opts.clone(),
comparison_sections: comparison_sections.clone(),
in_use,
description: &self.mln_description,
start_angle: &self.mln_start_angle,
end_angle: &self.mln_end_angle,
fill_color: &self.mln_fill_color,
elements: &self.mln_elements,
rename_active: self.style_rename.as_deref(),
rename_buf: &self.style_rename_buf,
},
flow,
)
},
@ -454,32 +552,89 @@ impl OpenCADStudio {
ObjectType::TableStyle(s) if s.name == self.tablestyle_selected => Some(s),
_ => None,
});
let compare_opts: Vec<String> = styles
.iter()
.filter(|name| !name.eq_ignore_ascii_case(&self.tablestyle_selected))
.cloned()
.collect();
let compare_name = compare_opts
.iter()
.find(|name| name.eq_ignore_ascii_case(&self.tablestyle_compare))
.cloned()
.or_else(|| compare_opts.first().cloned())
.unwrap_or_default();
let compare_style = tab.scene.document.objects.values().find_map(|object| match object {
ObjectType::TableStyle(style) if style.name == compare_name => Some(style),
_ => None,
});
let mut comparison_sections = Vec::new();
if let (Some(a), Some(b)) = (selected_style, compare_style) {
if (
&a.description,
a.flow_direction,
a.horizontal_margin,
a.vertical_margin,
a.title_suppressed,
a.header_suppressed,
a.annotative,
) != (
&b.description,
b.flow_direction,
b.horizontal_margin,
b.vertical_margin,
b.title_suppressed,
b.header_suppressed,
b.annotative,
) {
comparison_sections.push(crate::i18n::translate("General").into_owned());
}
for (label, different) in [
("Data Row", a.data_row_style != b.data_row_style),
("Header Row", a.header_row_style != b.header_row_style),
("Title Row", a.title_row_style != b.title_row_style),
] {
if different {
comparison_sections.push(crate::i18n::translate(label).into_owned());
}
}
}
let in_use = self.style_in_use(
crate::app::StyleKind::Table,
&self.tablestyle_selected,
);
sized_flow(
ex,
620,
420,
960,
680,
|flow| {
crate::ui::style::tablestyle::view_window(
styles.clone(),
&self.tablestyle_selected,
&self.ribbon.active_table_style,
selected_style,
&self.ts_hmargin,
&self.ts_vmargin,
&self.ts_description,
&self.ts_cell_textstyle,
&self.ts_cell_height,
&self.ts_cell_textcolor,
&self.ts_cell_fillcolor,
&self.ts_cell_datatype,
&self.ts_cell_unittype,
&self.ts_cell_format,
&self.ts_border_lw,
&self.ts_border_color,
&self.ts_border_spacing,
self.style_rename.as_deref(),
&self.style_rename_buf,
self.ts_color_open,
crate::ui::style::tablestyle::TableStyleView {
styles: styles.clone(),
selected: &self.tablestyle_selected,
current: &tab.scene.document.header.current_table_style_name,
style: selected_style,
tab: self.tablestyle_tab,
compare_name: compare_name.clone(),
compare_opts: compare_opts.clone(),
comparison_sections: comparison_sections.clone(),
in_use,
hmargin: &self.ts_hmargin,
vmargin: &self.ts_vmargin,
description: &self.ts_description,
cell_textstyle: &self.ts_cell_textstyle,
cell_height: &self.ts_cell_height,
cell_textcolor: &self.ts_cell_textcolor,
cell_fillcolor: &self.ts_cell_fillcolor,
cell_datatype: &self.ts_cell_datatype,
cell_unittype: &self.ts_cell_unittype,
cell_format: &self.ts_cell_format,
border_lw: &self.ts_border_lw,
border_color: &self.ts_border_color,
border_spacing: &self.ts_border_spacing,
rename_active: self.style_rename.as_deref(),
rename_buf: &self.style_rename_buf,
color_open: self.ts_color_open,
},
flow,
)
},
@ -507,7 +662,9 @@ impl OpenCADStudio {
let doc = &tab.scene.document;
let mut block_opts: Vec<String> = vec!["None".to_string()];
block_opts.extend(doc.block_records.iter().map(|b| b.name.clone()));
let mut lt_opts: Vec<String> = vec!["None".to_string()];
let mut arrow_opts: Vec<String> = vec!["Closed filled".to_string()];
arrow_opts.extend(doc.block_records.iter().map(|b| b.name.clone()));
let mut lt_opts: Vec<String> = vec!["ByBlock".to_string()];
lt_opts.extend(doc.line_types.iter().map(|lt| lt.name.clone()));
let mut textstyle_opts: Vec<String> = vec!["None".to_string()];
textstyle_opts.extend(doc.text_styles.iter().map(|t| t.name.clone()));
@ -529,8 +686,8 @@ impl OpenCADStudio {
.iter()
.find(|lt| lt.handle == h)
.map(|lt| lt.name.clone())
.unwrap_or_else(|| "None".to_string()),
None => "None".to_string(),
.unwrap_or_else(|| "ByBlock".to_string()),
None => "ByBlock".to_string(),
}
};
let opt_ts = |h: Option<acadrust::types::Handle>| -> String {
@ -548,16 +705,153 @@ impl OpenCADStudio {
match selected_style {
Some(s) => (
opt_lt(s.line_type_handle),
opt_block(s.arrowhead_handle),
s.arrowhead_handle
.and_then(|handle| {
doc.block_records
.iter()
.find(|record| record.handle == handle)
.map(|record| record.name.clone())
})
.unwrap_or_else(|| "Closed filled".to_string()),
opt_ts(s.text_style_handle),
opt_block(s.block_content_handle),
),
None => Default::default(),
};
let compare_opts: Vec<String> = styles
.iter()
.filter(|name| !name.eq_ignore_ascii_case(&self.mleaderstyle_selected))
.cloned()
.collect();
let compare_name = compare_opts
.iter()
.find(|name| name.eq_ignore_ascii_case(&self.mleaderstyle_compare))
.cloned()
.or_else(|| compare_opts.first().cloned())
.unwrap_or_default();
let compare_style = doc.objects.values().find_map(|object| match object {
ObjectType::MultiLeaderStyle(style) if style.name == compare_name => Some(style),
_ => None,
});
let mut comparison_sections = Vec::new();
if let (Some(a), Some(b)) = (selected_style, compare_style) {
if (
&a.description,
a.path_type,
a.line_color,
a.line_type_handle,
a.line_weight,
a.arrowhead_handle,
a.arrowhead_size,
a.break_gap_size,
) != (
&b.description,
b.path_type,
b.line_color,
b.line_type_handle,
b.line_weight,
b.arrowhead_handle,
b.arrowhead_size,
b.break_gap_size,
) {
comparison_sections.push(crate::i18n::translate("Leader Format").into_owned());
}
if (
a.enable_landing,
a.enable_dogleg,
a.landing_distance,
a.landing_gap,
a.scale_factor,
a.align_space,
a.max_leader_points,
a.first_segment_angle,
a.second_segment_angle,
a.leader_draw_order,
a.multileader_draw_order,
a.is_annotative,
) != (
b.enable_landing,
b.enable_dogleg,
b.landing_distance,
b.landing_gap,
b.scale_factor,
b.align_space,
b.max_leader_points,
b.first_segment_angle,
b.second_segment_angle,
b.leader_draw_order,
b.multileader_draw_order,
b.is_annotative,
) {
comparison_sections.push(crate::i18n::translate("Leader Structure").into_owned());
}
if (
a.content_type,
&a.default_text,
a.text_style_handle,
a.text_height,
a.text_color,
a.text_angle_type,
a.text_alignment,
) != (
b.content_type,
&b.default_text,
b.text_style_handle,
b.text_height,
b.text_color,
b.text_angle_type,
b.text_alignment,
) || (
a.text_left_attachment,
a.text_right_attachment,
a.text_top_attachment,
a.text_bottom_attachment,
a.text_attachment_direction,
a.text_frame,
a.text_always_left,
) != (
b.text_left_attachment,
b.text_right_attachment,
b.text_top_attachment,
b.text_bottom_attachment,
b.text_attachment_direction,
b.text_frame,
b.text_always_left,
) {
comparison_sections.push(crate::i18n::translate("Content").into_owned());
}
if (
a.block_content_handle,
a.block_content_color,
a.block_content_connection,
a.block_content_rotation,
a.block_content_scale_x,
a.block_content_scale_y,
a.block_content_scale_z,
a.enable_block_scale,
a.enable_block_rotation,
) != (
b.block_content_handle,
b.block_content_color,
b.block_content_connection,
b.block_content_rotation,
b.block_content_scale_x,
b.block_content_scale_y,
b.block_content_scale_z,
b.enable_block_scale,
b.enable_block_rotation,
) {
comparison_sections.push(crate::i18n::translate("Block Content").into_owned());
}
}
let in_use = self.style_in_use(
crate::app::StyleKind::MLeader,
&self.mleaderstyle_selected,
);
sized_flow(
ex,
560,
560,
960,
680,
|flow| {
crate::ui::style::mleaderstyle::view_window(
crate::ui::style::mleaderstyle::MLeaderStyleView {
@ -565,6 +859,11 @@ impl OpenCADStudio {
selected: &self.mleaderstyle_selected,
style: selected_style,
current: tab.active_mleader_style.clone(),
tab: self.mleaderstyle_tab,
compare_name: compare_name.clone(),
compare_opts: compare_opts.clone(),
comparison_sections: comparison_sections.clone(),
in_use,
landing_distance: &self.mls_landing_distance,
landing_gap: &self.mls_landing_gap,
arrowhead_size: &self.mls_arrowhead_size,
@ -585,6 +884,7 @@ impl OpenCADStudio {
block_scale_y: &self.mls_block_scale_y,
block_scale_z: &self.mls_block_scale_z,
block_opts: block_opts.clone(),
arrow_opts: arrow_opts.clone(),
lt_opts: lt_opts.clone(),
textstyle_opts: textstyle_opts.clone(),
line_type_name: line_type_name.clone(),
@ -630,6 +930,13 @@ impl OpenCADStudio {
);
let mut lt_opts: Vec<String> = vec!["ByBlock".to_string()];
lt_opts.extend(doc.line_types.iter().map(|lt| lt.name.clone()));
let text_style_opts: Vec<String> =
doc.text_styles.iter().map(|style| style.name.clone()).collect();
let text_style_fixed_height = doc
.text_styles
.get(&self.ds_dimtxsty)
.map(|style| style.height)
.filter(|height| *height > 0.0);
let blk_name = |h: acadrust::types::Handle| -> String {
if h.is_null() {
"Default".to_string()
@ -653,6 +960,70 @@ impl OpenCADStudio {
}
};
let ds_sel = doc.dim_styles.get(&self.dimstyle_selected);
let read_only = ds_sel.is_some_and(|style| {
style.xref_reference || style.xref_dependent || !style.xref_handle.is_null()
});
let in_use = doc.entities().any(|entity| {
matches!(entity, acadrust::EntityType::Dimension(dimension)
if dimension.base().style_name.eq_ignore_ascii_case(&self.dimstyle_selected))
});
let compare_opts: Vec<String> = styles
.iter()
.filter(|name| !name.eq_ignore_ascii_case(&self.dimstyle_selected))
.cloned()
.collect();
let compare_name = compare_opts
.iter()
.find(|name| name.eq_ignore_ascii_case(&self.dimstyle_compare))
.cloned()
.or_else(|| compare_opts.first().cloned())
.unwrap_or_default();
let mut comparison_sections = Vec::new();
if let (Some(a), Some(b)) = (ds_sel, doc.dim_styles.get(&compare_name)) {
if (a.dimdle, a.dimdli, a.dimgap, a.dimclrd, a.dimlwd, a.dimsd1, a.dimsd2)
!= (b.dimdle, b.dimdli, b.dimgap, b.dimclrd, b.dimlwd, b.dimsd1, b.dimsd2)
|| (a.dimexe, a.dimexo, a.dimclre, a.dimlwe, a.dimse1, a.dimse2, a.dimfxl, a.dimfxlon)
!= (b.dimexe, b.dimexo, b.dimclre, b.dimlwe, b.dimse1, b.dimse2, b.dimfxl, b.dimfxlon)
|| (a.dimltex_handle, a.dimltex1_handle, a.dimltex2_handle)
!= (b.dimltex_handle, b.dimltex1_handle, b.dimltex2_handle)
{
comparison_sections.push(crate::i18n::translate("Lines").into_owned());
}
if (a.dimasz, a.dimblk, a.dimblk1, a.dimblk2, a.dimldrblk, a.dimsah, a.dimcen, a.dimtsz)
!= (b.dimasz, b.dimblk, b.dimblk1, b.dimblk2, b.dimldrblk, b.dimsah, b.dimcen, b.dimtsz)
|| (a.dimarcsym, a.dimjogang) != (b.dimarcsym, b.dimjogang)
{
comparison_sections.push(crate::i18n::translate("Symbols and Arrows").into_owned());
}
if (a.dimclrt, a.dimtxt, &a.dimtxsty, a.dimjust, a.dimtad, a.dimtvp)
!= (b.dimclrt, b.dimtxt, &b.dimtxsty, b.dimjust, b.dimtad, b.dimtvp)
|| (a.dimtih, a.dimtoh, a.dimtfill, a.dimtfillclr, a.dimtxtdirection)
!= (b.dimtih, b.dimtoh, b.dimtfill, b.dimtfillclr, b.dimtxtdirection)
{
comparison_sections.push(crate::i18n::translate("Text").into_owned());
}
if (a.dimatfit, a.dimtix, a.dimsoxd, a.dimtmove, a.dimupt, a.dimtofl, a.dimscale, a.annotative)
!= (b.dimatfit, b.dimtix, b.dimsoxd, b.dimtmove, b.dimupt, b.dimtofl, b.dimscale, b.annotative)
{
comparison_sections.push(crate::i18n::translate("Fit").into_owned());
}
if (a.dimlfac, a.dimlunit, a.dimdec, &a.dimpost, a.dimdsep, a.dimrnd, a.dimzin, a.dimfrac)
!= (b.dimlfac, b.dimlunit, b.dimdec, &b.dimpost, b.dimdsep, b.dimrnd, b.dimzin, b.dimfrac)
|| (a.dimaunit, a.dimadec, a.dimazin) != (b.dimaunit, b.dimadec, b.dimazin)
{
comparison_sections.push(crate::i18n::translate("Primary Units").into_owned());
}
if (a.dimalt, a.dimaltf, a.dimaltd, a.dimaltu, a.dimalttd, a.dimaltrnd, &a.dimapost, a.dimaltz, a.dimalttz)
!= (b.dimalt, b.dimaltf, b.dimaltd, b.dimaltu, b.dimalttd, b.dimaltrnd, &b.dimapost, b.dimaltz, b.dimalttz)
{
comparison_sections.push(crate::i18n::translate("Alternate Units").into_owned());
}
if (a.dimtol, a.dimlim, a.dimtp, a.dimtm, a.dimtdec, a.dimtfac, a.dimtolj, a.dimtzin)
!= (b.dimtol, b.dimlim, b.dimtp, b.dimtm, b.dimtdec, b.dimtfac, b.dimtolj, b.dimtzin)
{
comparison_sections.push(crate::i18n::translate("Tolerances").into_owned());
}
}
let (
dimblk_name,
dimblk1_name,
@ -673,7 +1044,7 @@ impl OpenCADStudio {
),
None => Default::default(),
};
sized_flow(ex, 720, 560, |flow| {
sized_flow(ex, 960, 680, |flow| {
crate::ui::style::dimstyle::view_window(
styles.clone(),
&self.dimstyle_selected,
@ -734,14 +1105,12 @@ impl OpenCADStudio {
dimtmove: &self.ds_dimtmove,
dimupt: self.ds_dimupt,
dimtofl: self.ds_dimtofl,
dimfit: &self.ds_dimfit,
dimdsep: &self.ds_dimdsep,
dimrnd: &self.ds_dimrnd,
dimzin: &self.ds_dimzin,
dimfrac: &self.ds_dimfrac,
dimaunit: &self.ds_dimaunit,
dimadec: &self.ds_dimadec,
dimunit: &self.ds_dimunit,
dimazin: &self.ds_dimazin,
dimalt: self.ds_dimalt,
dimaltf: &self.ds_dimaltf,
@ -763,6 +1132,13 @@ impl OpenCADStudio {
dimltex2_name: dimltex2_name.clone(),
block_opts: block_opts.clone(),
lt_opts: lt_opts.clone(),
text_style_opts: text_style_opts.clone(),
text_style_fixed_height,
compare_name: compare_name.clone(),
compare_opts: compare_opts.clone(),
comparison_sections: comparison_sections.clone(),
read_only,
in_use,
color_open: self.ds_color_open.clone(),
},
self.style_rename.as_deref(),

View file

@ -13,12 +13,79 @@ use acadrust::{CadDocument, Handle};
// DXF group codes of the dimension variables surfaced on the leader panel.
pub const DIMSCALE: i16 = 40; // overall scale (real)
pub const DIMPOST: i16 = 3;
pub const DIMAPOST: i16 = 4;
pub const DIMASZ: i16 = 41; // arrow size (real)
pub const DIMTAD: i16 = 77; // text vertical pos (int16)
pub const DIMCLRD: i16 = 176; // dim line colour (int16 = ACI index)
pub const DIMGAP: i16 = 147; // text offset / gap (real)
pub const DIMLWD: i16 = 371; // dim line lineweight (int16)
pub const DIMLDRBLK: i16 = 341; // leader arrow block (handle)
pub const DIMEXO: i16 = 42;
pub const DIMDLI: i16 = 43;
pub const DIMEXE: i16 = 44;
pub const DIMRND: i16 = 45;
pub const DIMDLE: i16 = 46;
pub const DIMTP: i16 = 47;
pub const DIMTM: i16 = 48;
pub const DIMFXL: i16 = 49;
pub const DIMJOGANG: i16 = 50;
pub const DIMTOL: i16 = 71;
pub const DIMLIM: i16 = 72;
pub const DIMTIH: i16 = 73;
pub const DIMTOH: i16 = 74;
pub const DIMSE1: i16 = 75;
pub const DIMSE2: i16 = 76;
pub const DIMZIN: i16 = 78;
pub const DIMAZIN: i16 = 79;
pub const DIMARCSYM: i16 = 90;
pub const DIMTXT: i16 = 140;
pub const DIMCEN: i16 = 141;
pub const DIMTSZ: i16 = 142;
pub const DIMALTF: i16 = 143;
pub const DIMLFAC: i16 = 144;
pub const DIMTVP: i16 = 145;
pub const DIMTFAC: i16 = 146;
pub const DIMALTRND: i16 = 148;
pub const DIMALT: i16 = 170;
pub const DIMALTD: i16 = 171;
pub const DIMTOFL: i16 = 172;
pub const DIMSAH: i16 = 173;
pub const DIMTIX: i16 = 174;
pub const DIMSOXD: i16 = 175;
pub const DIMCLRE: i16 = 177;
pub const DIMCLRT: i16 = 178;
pub const DIMADEC: i16 = 179;
pub const DIMDEC: i16 = 271;
pub const DIMTDEC: i16 = 272;
pub const DIMALTU: i16 = 273;
pub const DIMALTTD: i16 = 274;
pub const DIMAUNIT: i16 = 275;
pub const DIMFRAC: i16 = 276;
pub const DIMLUNIT: i16 = 277;
pub const DIMDSEP: i16 = 278;
pub const DIMTMOVE: i16 = 279;
pub const DIMJUST: i16 = 280;
pub const DIMSD1: i16 = 281;
pub const DIMSD2: i16 = 282;
pub const DIMTOLJ: i16 = 283;
pub const DIMTZIN: i16 = 284;
pub const DIMALTZ: i16 = 285;
pub const DIMALTTZ: i16 = 286;
pub const DIMUPT: i16 = 288;
pub const DIMATFIT: i16 = 289;
pub const DIMFXLON: i16 = 290;
pub const DIMTFILL: i16 = 69;
pub const DIMTFILLCLR: i16 = 70;
pub const DIMTXTDIRECTION: i16 = 295;
pub const DIMTXSTY: i16 = 340;
pub const DIMBLK: i16 = 342;
pub const DIMBLK1: i16 = 343;
pub const DIMBLK2: i16 = 344;
pub const DIMLTYPE: i16 = 345;
pub const DIMLTEX1: i16 = 346;
pub const DIMLTEX2: i16 = 347;
pub const DIMLWE: i16 = 372;
/// Every (code, value) override present in the `ACAD`/`DSTYLE` record.
pub fn pairs(xd: &ExtendedData) -> Vec<(i16, XDataValue)> {
@ -90,6 +157,16 @@ pub fn handle(xd: &ExtendedData, code: i16) -> Option<Handle> {
})
}
pub fn string(xd: &ExtendedData, code: i16) -> Option<String> {
pairs(xd)
.into_iter()
.find(|(c, _)| *c == code)
.and_then(|(_, value)| match value {
XDataValue::String(text) => Some(text),
_ => None,
})
}
fn write_pairs(doc: &mut CadDocument, handle: Handle, pairs: Vec<(i16, XDataValue)>) {
let Some(entity) = doc.get_entity(handle) else {
return;

View file

@ -1389,27 +1389,6 @@ fn apply_dimension_breaks(
*lines = output;
}
pub(crate) fn uses_custom_arrow_blocks(document: &CadDocument, dim: &Dimension) -> bool {
let style_name = &dim.base().style_name;
let Some(style) = document.dim_styles.iter().find(|style| {
style.name.eq_ignore_ascii_case(style_name)
|| (style_name.trim().is_empty() && style.name.eq_ignore_ascii_case("Standard"))
}) else {
return false;
};
if style.dimtsz > 1e-9 {
return false;
}
let is_custom = |handle| {
crate::scene::convert::tessellate::arrow_block_is_custom(document, handle)
};
if style.dimsah {
is_custom(style.dimblk1) || is_custom(style.dimblk2)
} else {
is_custom(style.dimblk)
}
}
pub trait DimensionTess {
fn tessellate(
&self,
@ -1481,10 +1460,126 @@ fn tessellate_dimension_inner(
// recursive call goes through the LOD ladder, not the truck path.)
let style_name = &dim.base().style_name;
let style = document.dim_styles.iter().find(|s| {
let source_style = document.dim_styles.iter().find(|s| {
s.name.eq_ignore_ascii_case(style_name)
|| (style_name.trim().is_empty() && s.name.eq_ignore_ascii_case("Standard"))
});
let mut effective_style = source_style.cloned();
if let Some(style) = &mut effective_style {
use crate::entities::dim_override as ov;
let data = &dim.base().common.extended_data;
macro_rules! real {
($field:ident, $code:ident) => {
if let Some(value) = ov::real(data, ov::$code) {
style.$field = value;
}
};
}
macro_rules! int {
($field:ident, $code:ident) => {
if let Some(value) = ov::int(data, ov::$code) {
style.$field = value;
}
};
}
macro_rules! flag {
($field:ident, $code:ident) => {
if let Some(value) = ov::int(data, ov::$code) {
style.$field = value != 0;
}
};
}
macro_rules! handle {
($field:ident, $code:ident) => {
if let Some(value) = ov::handle(data, ov::$code) {
style.$field = value;
}
};
}
real!(dimscale, DIMSCALE);
real!(dimasz, DIMASZ);
real!(dimexo, DIMEXO);
real!(dimdli, DIMDLI);
real!(dimexe, DIMEXE);
real!(dimrnd, DIMRND);
real!(dimdle, DIMDLE);
real!(dimtp, DIMTP);
real!(dimtm, DIMTM);
real!(dimfxl, DIMFXL);
real!(dimjogang, DIMJOGANG);
real!(dimtxt, DIMTXT);
real!(dimcen, DIMCEN);
real!(dimtsz, DIMTSZ);
real!(dimaltf, DIMALTF);
real!(dimlfac, DIMLFAC);
real!(dimtvp, DIMTVP);
real!(dimtfac, DIMTFAC);
real!(dimgap, DIMGAP);
real!(dimaltrnd, DIMALTRND);
flag!(dimtol, DIMTOL);
flag!(dimlim, DIMLIM);
flag!(dimtih, DIMTIH);
flag!(dimtoh, DIMTOH);
flag!(dimse1, DIMSE1);
flag!(dimse2, DIMSE2);
flag!(dimalt, DIMALT);
flag!(dimtofl, DIMTOFL);
flag!(dimsah, DIMSAH);
flag!(dimtix, DIMTIX);
flag!(dimsoxd, DIMSOXD);
flag!(dimsd1, DIMSD1);
flag!(dimsd2, DIMSD2);
flag!(dimupt, DIMUPT);
flag!(dimfxlon, DIMFXLON);
flag!(dimtxtdirection, DIMTXTDIRECTION);
int!(dimzin, DIMZIN);
int!(dimazin, DIMAZIN);
int!(dimarcsym, DIMARCSYM);
int!(dimclrd, DIMCLRD);
int!(dimclre, DIMCLRE);
int!(dimclrt, DIMCLRT);
int!(dimadec, DIMADEC);
int!(dimaltd, DIMALTD);
int!(dimdec, DIMDEC);
int!(dimtdec, DIMTDEC);
int!(dimaltu, DIMALTU);
int!(dimalttd, DIMALTTD);
int!(dimaunit, DIMAUNIT);
int!(dimfrac, DIMFRAC);
int!(dimlunit, DIMLUNIT);
int!(dimdsep, DIMDSEP);
int!(dimtmove, DIMTMOVE);
int!(dimjust, DIMJUST);
int!(dimtolj, DIMTOLJ);
int!(dimtzin, DIMTZIN);
int!(dimaltz, DIMALTZ);
int!(dimalttz, DIMALTTZ);
int!(dimatfit, DIMATFIT);
int!(dimtfill, DIMTFILL);
int!(dimtfillclr, DIMTFILLCLR);
int!(dimlwd, DIMLWD);
int!(dimlwe, DIMLWE);
handle!(dimldrblk, DIMLDRBLK);
handle!(dimblk, DIMBLK);
handle!(dimblk1, DIMBLK1);
handle!(dimblk2, DIMBLK2);
handle!(dimltex_handle, DIMLTYPE);
handle!(dimltex1_handle, DIMLTEX1);
handle!(dimltex2_handle, DIMLTEX2);
if let Some(value) = ov::string(data, ov::DIMPOST) {
style.dimpost = value;
}
if let Some(value) = ov::string(data, ov::DIMAPOST) {
style.dimapost = value;
}
if let Some(value) = ov::handle(data, ov::DIMTXSTY) {
style.dimtxsty_handle = value;
if let Some(record) = document.text_styles.iter().find(|record| record.handle == value) {
style.dimtxsty = record.name.clone();
}
}
}
let style = effective_style.as_ref();
// DIMSCALE rule:
// dimstyle.dimscale > 0 → final multiplier; ignore anno_scale.
@ -1655,7 +1750,7 @@ fn tessellate_dimension_inner(
// preserved on save:
// - base.insertion_point: legacy anchor reference; render uses
// text_middle_point + dim-line geometry instead.
// - base.block_name: AutoCAD-style "*D..." anonymous block name for
// - base.block_name: generated anonymous block name for
// the dim graphics — we re-tessellate so don't need it.
// - base.version: DXF format marker (metadata only).
let _ = (
@ -2391,7 +2486,7 @@ fn append_linear_dimension(
// DIMDLE: dim line overshoots the ext line by `dimdle` at each end,
// but only when ticks are in use (DIMTSZ > 0). With arrowheads this
// is ignored, matching AutoCAD.
// is ignored.
let dle = if params.ticks { params.dimdle } else { 0.0 };
let dir_d1_to_d2 = normalized_or(d2 - d1, axis);
let d1_out = d1 - dir_d1_to_d2 * dle;
@ -2404,30 +2499,50 @@ fn append_linear_dimension(
let gap = (d2 - d1).length();
let arrows_outside = !params.ticks && params.arrow_len > 1e-6 && gap < 2.0 * params.arrow_len;
// DIMSD1/DIMSD2: when *both* set, omit the dim line entirely. AutoCAD
// splits at text otherwise — without that pivot info, leave as-is.
if !(suppress.dim1 && suppress.dim2) {
// Break the dim line where the text sits on it, so a DIMTFILL
// background reads over the line (2-D fills draw under all wires, so the
// line is gapped rather than z-masked).
let mut drew = false;
if let Some((tc, half_w, half_h)) = params.text_break {
let dir = normalized_or(d2_out - d1_out, axis);
let len = (d2_out - d1_out).length();
let along = (tc - d1_out).dot(dir);
let perp_dist = (tc - (d1_out + dir * along)).length();
if perp_dist < half_h && along - half_w > 0.0 && along + half_w < len {
add_segment(&mut g.dim_lines, d1_out, d1_out + dir * (along - half_w));
add_segment(&mut g.dim_lines, d1_out + dir * (along + half_w), d2_out);
drew = true;
// The two suppression flags address the portions at the first and second
// measured points independently. The text gap is also the natural split;
// when there is no gap, split at the projected text position or midpoint.
let line_dir = normalized_or(d2_out - d1_out, axis);
let line_len = (d2_out - d1_out).length();
let mut split = line_len * 0.5;
let mut left_end = split;
let mut right_start = split;
if let Some((text_center, half_width, half_height)) = params.text_break {
let along = (text_center - d1_out).dot(line_dir);
if along > 0.0 && along < line_len {
split = along;
left_end = split;
right_start = split;
let perpendicular = (text_center - (d1_out + line_dir * along)).length();
if perpendicular < half_height
&& along - half_width > 0.0
&& along + half_width < line_len
{
left_end = along - half_width;
right_start = along + half_width;
}
}
if !drew {
add_segment(&mut g.dim_lines, d1_out, d2_out);
}
if arrows_outside && !params.dimsoxd {
let stub = params.arrow_len * 2.0;
}
if !suppress.dim1 && left_end > 1e-6 {
add_segment(
&mut g.dim_lines,
d1_out,
d1_out + line_dir * left_end,
);
}
if !suppress.dim2 && line_len - right_start > 1e-6 {
add_segment(
&mut g.dim_lines,
d1_out + line_dir * right_start,
d2_out,
);
}
if arrows_outside && !params.dimsoxd {
let stub = params.arrow_len * 2.0;
if !suppress.dim1 {
add_segment(&mut g.dim_lines, d1 - dir_d1_to_d2 * stub, d1);
}
if !suppress.dim2 {
add_segment(&mut g.dim_lines, d2, d2 + dir_d1_to_d2 * stub);
}
}
@ -2838,8 +2953,8 @@ fn dimension_text_parts(
let base = dim.base();
let is_angular = matches!(dim, Dimension::Angular2Ln(_) | Dimension::Angular3Pt(_));
// Auto-generated body (the value AutoCAD would emit if the user did not
// override it). Built first so user_text "<>" substitution can re-use it.
// Auto-generated body used when the user did not override it. Built first
// so user_text "<>" substitution can re-use it.
let primary_raw = if is_angular {
format_angular_value(dim.measurement(), style)
} else {
@ -3168,7 +3283,7 @@ fn format_fractional(value: f64, dimfrac: i16) -> String {
}
/// Power-of-two denominator for architectural / fractional output. DIMFRAC is
/// the exponent-ish knob AutoCAD pairs with DIMLUNIT; clamp it to a readable
/// the exponent-like fraction-format knob; clamp it to a readable
/// range (16ths … 1024ths).
fn arch_denom(dimfrac: i16) -> u64 {
let exp = (dimfrac.clamp(0, 8) as u32).max(2) + 2; // 4..=10 → 16..=1024

View file

@ -2982,6 +2982,188 @@ pub(super) fn message_id(source: &str) -> Option<&'static str> {
"── Custom Overrides (SHORTCUTS SET) ──────────────────" => Some("catalog-custom-overrides-shortcuts-set-07be563dec"),
"── Function Keys ──────────────────────────────────────" => Some("catalog-function-keys-b5a2df24e9"),
"── Other Keys ──────────────────────────────────────────" => Some("catalog-other-keys-a882812cf2"),
"Always keep text between extension lines" => Some("dimstyle-keep-text-between-extension-lines"),
"Angular dimensions" => Some("dimstyle-angular-dimensions"),
"Arc length symbol" => Some("dimstyle-arc-length-symbol"),
"Arrowheads" => Some("dimstyle-arrowheads"),
"Available style" => Some("dimstyle-available-style"),
"Baseline spacing" => Some("dimstyle-baseline-spacing"),
"Basic" => Some("dimstyle-basic"),
"Both arrowheads" => Some("dimstyle-both-arrowheads"),
"Center mark" => Some("dimstyle-center-mark"),
"Center mark size" => Some("dimstyle-center-mark-size"),
"Center marks" => Some("dimstyle-center-marks"),
"Centerlines" => Some("dimstyle-centerlines"),
"Compare with" => Some("dimstyle-compare-with"),
"Current style" => Some("dimstyle-current-style"),
"Deviation" => Some("dimstyle-deviation"),
"Different sections" => Some("dimstyle-different-sections"),
"Dimension line color" => Some("dimstyle-dimension-line-color"),
"Dimension linetype" => Some("dimstyle-dimension-linetype"),
"Dimension lineweight" => Some("dimstyle-dimension-lineweight"),
"Display alternate units" => Some("dimstyle-display-alternate-units"),
"Draw dimension line between extension lines" => Some("dimstyle-draw-dimension-line-between-extension-lines"),
"Extend beyond dimension line" => Some("dimstyle-extend-beyond-dimension-line"),
"Extend beyond ticks" => Some("dimstyle-extend-beyond-ticks"),
"Extension line color" => Some("dimstyle-extension-line-color"),
"Extension lineweight" => Some("dimstyle-extension-lineweight"),
"Feet and inches" => Some("dimstyle-feet-and-inches"),
"Fine tuning" => Some("dimstyle-fine-tuning"),
"First arrowhead" => Some("dimstyle-first-arrowhead"),
"First extension linetype" => Some("dimstyle-first-extension-linetype"),
"Fit options" => Some("dimstyle-fit-options"),
"Fixed length" => Some("dimstyle-fixed-length"),
"Fraction format" => Some("dimstyle-fraction-format"),
"Height scale" => Some("dimstyle-height-scale"),
"Horizontal placement" => Some("dimstyle-horizontal-placement"),
"Keep text horizontal when inside" => Some("dimstyle-keep-text-horizontal-inside"),
"Keep text horizontal when outside" => Some("dimstyle-keep-text-horizontal-outside"),
"Leader arrowhead" => Some("dimstyle-leader-arrowhead"),
"Limits" => Some("dimstyle-limits"),
"Linear dimensions" => Some("dimstyle-linear-dimensions"),
"Lower value" => Some("dimstyle-lower-value"),
"Measurement scale" => Some("dimstyle-measurement-scale"),
"Measurement template" => Some("dimstyle-measurement-template"),
"Method" => Some("dimstyle-method"),
"Multiplier" => Some("dimstyle-multiplier"),
"No differences" => Some("dimstyle-no-differences"),
"Not applicable" => Some("dimstyle-not-applicable"),
"Offset from measured point" => Some("dimstyle-offset-from-measured-point"),
"Place text manually while creating dimensions" => Some("dimstyle-place-text-manually"),
"Radius jog angle (°)" => Some("dimstyle-radius-jog-angle"),
"Read left to right" => Some("dimstyle-read-left-to-right"),
"Referenced style · Read only" => Some("dimstyle-referenced-read-only"),
"Round off" => Some("dimstyle-round-off"),
"Second arrowhead" => Some("dimstyle-second-arrowhead"),
"Second extension linetype" => Some("dimstyle-second-extension-linetype"),
"Show zero feet and zero inches" => Some("dimstyle-show-zero-feet-and-inches"),
"Show zero feet; suppress zero inches" => Some("dimstyle-show-zero-feet-suppress-zero-inches"),
"Suppress arrows when they do not fit" => Some("dimstyle-suppress-arrows-when-no-fit"),
"Suppress first dimension line" => Some("dimstyle-suppress-first-dimension-line"),
"Suppress first extension line" => Some("dimstyle-suppress-first-extension-line"),
"Suppress second dimension line" => Some("dimstyle-suppress-second-dimension-line"),
"Suppress second extension line" => Some("dimstyle-suppress-second-extension-line"),
"Suppress zero feet and zero inches" => Some("dimstyle-suppress-zero-feet-and-inches"),
"Suppress zero feet; show zero inches" => Some("dimstyle-suppress-zero-feet-show-zero-inches"),
"Symbols and Arrows" => Some("dimstyle-symbols-and-arrows"),
"Symmetrical" => Some("dimstyle-symmetrical"),
"Text background" => Some("dimstyle-text-background"),
"Text gap" => Some("dimstyle-text-gap"),
"The selected text style fixes the height at %{height}." => Some("dimstyle-fixed-text-height-note"),
"Tick size" => Some("dimstyle-tick-size"),
"Tolerance zero suppression" => Some("dimstyle-tolerance-zero-suppression"),
"Unit format" => Some("dimstyle-unit-format"),
"Upper value" => Some("dimstyle-upper-value"),
"Use <> as the measured value; text before and after it becomes the prefix and suffix." => Some("dimstyle-measurement-template-help"),
"Use different first and second arrowheads" => Some("dimstyle-use-different-arrowheads"),
"Use fixed-length extension lines" => Some("dimstyle-use-fixed-length-extension-lines"),
"Used in drawing" => Some("dimstyle-used-in-drawing"),
"Vertical offset" => Some("dimstyle-vertical-offset"),
"Vertical placement" => Some("dimstyle-vertical-placement"),
"Vertical position" => Some("dimstyle-vertical-position"),
"When space is limited" => Some("dimstyle-when-space-is-limited"),
"When text is moved" => Some("dimstyle-when-text-is-moved"),
"Zero suppression" => Some("dimstyle-zero-suppression"),
"Add a leader" => Some("dimstyle-add-a-leader"),
"Automatic" => Some("dimstyle-automatic"),
"By block" => Some("dimstyle-by-block"),
"Comma" => Some("dimstyle-comma"),
"Degrees, minutes, seconds" => Some("dimstyle-degrees-minutes-seconds"),
"Keep dimension line with text" => Some("dimstyle-keep-dimension-line-with-text"),
"Leading and trailing" => Some("dimstyle-leading-and-trailing"),
"Move arrows outside first" => Some("dimstyle-move-arrows-outside-first"),
"Move text and arrows outside" => Some("dimstyle-move-text-and-arrows-outside"),
"Move text freely" => Some("dimstyle-move-text-freely"),
"Move text outside first" => Some("dimstyle-move-text-outside-first"),
"Period" => Some("dimstyle-period"),
"Space" => Some("dimstyle-space"),
"Alignment spacing" => Some("style-manager-alignment-spacing"),
"Always left align" => Some("style-manager-always-left-align"),
"Attachment direction" => Some("style-manager-attachment-direction"),
"Background fill enabled" => Some("style-manager-background-fill-enabled"),
"Big font" => Some("style-manager-big-font"),
"Block scale X" => Some("style-manager-block-scale-x"),
"Block scale Y" => Some("style-manager-block-scale-y"),
"Block scale Z" => Some("style-manager-block-scale-z"),
"Borders" => Some("style-manager-borders"),
"Bottom attachment" => Some("style-manager-bottom-attachment"),
"Break gap size" => Some("style-manager-break-gap-size"),
"Caps and Fill" => Some("style-manager-caps-and-fill"),
"Content type" => Some("style-manager-content-type"),
"Data Row" => Some("style-manager-data-row"),
"Data type" => Some("style-manager-data-type"),
"Default text" => Some("style-manager-default-text"),
"Different" => Some("style-manager-different"),
"Display joints" => Some("style-manager-display-joints"),
"Drawing height" => Some("style-manager-drawing-height"),
"Drawing scale" => Some("style-manager-drawing-scale"),
"Effects" => Some("style-manager-effects"),
"Elements" => Some("style-manager-elements"),
"End caps" => Some("style-manager-end-caps"),
"Fill and joints" => Some("style-manager-fill-and-joints"),
"Fill enabled" => Some("style-manager-fill-enabled"),
"First segment angle" => Some("style-manager-first-segment-angle"),
"Fixed height" => Some("style-manager-fixed-height"),
"Flow direction" => Some("style-manager-flow-direction"),
"Font file" => Some("style-manager-font-file"),
"Fonts" => Some("style-manager-fonts"),
"Format string" => Some("style-manager-format-string"),
"Header" => Some("style-manager-header"),
"Header Row" => Some("style-manager-header-row"),
"Horizontal margin" => Some("style-manager-horizontal-margin"),
"Inner arcs" => Some("style-manager-inner-arcs"),
"Inside horizontal" => Some("style-manager-inside-horizontal"),
"Inside vertical" => Some("style-manager-inside-vertical"),
"Leader draw order" => Some("style-manager-leader-draw-order"),
"Leader note" => Some("style-manager-leader-note"),
"Left attachment" => Some("style-manager-left-attachment"),
"Line color" => Some("style-manager-line-color"),
"Line type" => Some("style-manager-line-type"),
"Line weight" => Some("style-manager-line-weight"),
"Maximum leader points" => Some("style-manager-maximum-leader-points"),
"Multileader draw order" => Some("style-manager-multileader-draw-order"),
"No preview" => Some("style-manager-no-preview"),
"Oblique angle" => Some("style-manager-oblique-angle"),
"Outer arc" => Some("style-manager-outer-arc"),
"Paper height" => Some("style-manager-paper-height"),
"Paper text height" => Some("style-manager-paper-text-height"),
"Path type" => Some("style-manager-path-type"),
"Right attachment" => Some("style-manager-right-attachment"),
"Scale factor" => Some("style-manager-scale-factor"),
"Second segment angle" => Some("style-manager-second-segment-angle"),
"Size and Effects" => Some("style-manager-size-and-effects"),
"Start caps" => Some("style-manager-start-caps"),
"Stroke fonts" => Some("style-manager-stroke-fonts"),
"Suppress header row" => Some("style-manager-suppress-header-row"),
"Suppress title row" => Some("style-manager-suppress-title-row"),
"System font" => Some("style-manager-system-font"),
"System fonts" => Some("style-manager-system-fonts"),
"Text alignment" => Some("style-manager-text-alignment"),
"Text angle" => Some("style-manager-text-angle"),
"Title Row" => Some("style-manager-title-row"),
"Top attachment" => Some("style-manager-top-attachment"),
"Unit type" => Some("style-manager-unit-type"),
"Vertical margin" => Some("style-manager-vertical-margin"),
"font family…" => Some("style-manager-font-family-placeholder"),
"Bottom to top" => Some("style-manager-bottom-to-top"),
"Arrowhead first" => Some("style-manager-arrowhead-first"),
"Content first" => Some("style-manager-content-first"),
"Leader first" => Some("style-manager-leader-first"),
"Straight" => Some("style-manager-straight"),
"Parallel to last segment" => Some("style-manager-parallel-last-segment"),
"Top of top line" => Some("style-manager-top-of-top-line"),
"Middle of top line" => Some("style-manager-middle-of-top-line"),
"Middle of text" => Some("style-manager-middle-of-text"),
"Middle of bottom line" => Some("style-manager-middle-of-bottom-line"),
"Bottom of bottom line" => Some("style-manager-bottom-of-bottom-line"),
"Bottom line" => Some("style-manager-bottom-line"),
"Underline bottom line" => Some("style-manager-underline-bottom-line"),
"Underline top line" => Some("style-manager-underline-top-line"),
"Underline all text" => Some("style-manager-underline-all-text"),
"Center of text" => Some("style-manager-center-of-text"),
"Center of text with overline" => Some("style-manager-center-of-text-overline"),
"Block extents" => Some("style-manager-block-extents"),
"Base point" => Some("style-manager-base-point"),
_ => None,
}
}

View file

@ -28,7 +28,7 @@ const MAX_NESTING_DEPTH: usize = 32;
/// Skip wires whose world-AABB projects to fewer than this many pixels in
/// the active view. Picks up tiny detail at zoom-out so the tessellator
/// doesn't waste time on geometry that contributes a few sub-pixel marks
/// to the final image. 2 px is the AutoCAD-default "small element" floor
/// to the final image. Two pixels is a practical small-element floor:
/// — visibly the same image, dramatically fewer wires.
const MIN_PIXEL_SIZE: f32 = 2.0;
@ -426,66 +426,16 @@ fn build_defn(
nested_ins, doc, bg_color, depth_map,
)));
}
// A dimension nested in a block bakes its geometry (extension /
// dim lines, arrows, text) into a per-instance `*D` block, exactly
// like a top-level dimension. The top-level path expands that block
// in `tessellate_entity`; the block-expand path calls the plain
// `tessellate::tessellate`, which does NOT, so nested dimensions
// drew nothing. Expand the `*D` block's entities here as block-local
// subs so they transform with the parent insert. (Empty block_name
// — a non-baked dimension — falls through to the default arm.)
EntityType::Dimension(dim)
if !dim.base().block_name.trim().is_empty()
&& !crate::entities::dimension::uses_custom_arrow_blocks(doc, dim) =>
{
let dblk = doc
.block_records
.iter()
.find(|br| br.name.eq_ignore_ascii_case(&dim.base().block_name));
if let Some(dblk) = dblk {
// The `*D` block content is baked in the coordinate space it
// occupied when the dimension was created — for a dimension
// inside a block that is often the ORIGINAL WCS, not the
// block-local space. The dimension's insertion_point (DXF
// 12) is the offset that maps the baked content into the
// dimension's own (block-local) space; it is zero for
// dimensions baked in place, so this is a no-op there.
let ins = dim.base().insertion_point;
for &deh in &dblk.entity_handles {
let Some(dsub) = doc.get_entity(deh) else {
continue;
};
// Definition points are baked as POINTs on Defpoints —
// grip markers, never drawn (matches the top-level path).
if matches!(dsub, EntityType::Point(_)) {
continue;
}
if dsub.common().invisible || layer_hidden(doc, &dsub.common().layer) {
continue;
}
let mut placed = dsub.clone();
placed.as_entity_mut().translate(ins);
// An arrowhead is baked as a nested INSERT of an arrow
// block — route it through the nested-ref machinery so
// the arrow block expands (tessellate_sub_local doesn't
// expand inserts).
if let EntityType::Insert(arrow) = &placed {
subs.push(LocalSub::Nested(build_nested_ref(
arrow, doc, bg_color, depth_map,
)));
} else {
for lw in tessellate_sub_local(
doc,
&placed,
anno_scale,
annotation_scale_handle,
bg_color,
depth_map,
) {
subs.push(LocalSub::Wire(lw));
}
}
}
EntityType::Dimension(_) => {
for wire in tessellate_sub_local(
doc,
entity,
anno_scale,
annotation_scale_handle,
bg_color,
depth_map,
) {
subs.push(LocalSub::Wire(wire));
}
}
// A table nested in a block bakes its geometry (gridlines, cell
@ -706,21 +656,38 @@ fn tessellate_sub_local(
// Pass `local_offset` as the f64 world-offset so tessellate subtracts it
// before casting to f32 — same precision-preservation trick used for
// top-level entities, applied per-defn.
let wires_out = tessellate::tessellate(
doc,
h,
sub,
false,
sub_color,
pat_len,
pat,
lw_px,
anno_scale,
annotation_scale_handle,
None,
bg_color,
false,
);
let wires_out = if let EntityType::Dimension(dimension) = sub {
use crate::entities::dimension::DimensionTess;
dimension.tessellate(
doc,
h,
false,
sub_color,
lw_px,
anno_scale,
&HashSet::default(),
None,
bg_color,
None,
None,
)
} else {
tessellate::tessellate(
doc,
h,
sub,
false,
sub_color,
pat_len,
pat,
lw_px,
anno_scale,
annotation_scale_handle,
None,
bg_color,
false,
)
};
if wires_out.is_empty() {
return vec![];
}

View file

@ -543,8 +543,8 @@ pub(crate) fn tessellate_entity(
// An entity from an application we have no reader for (e.g. an Autodesk
// Raster Design embedded raster image) arrives as `Unknown`. Its own data is
// a private format we cannot decode — but it usually ships a proxy-graphics
// blob, the vector preview its author cached for exactly this case. AutoCAD
// draws that when the object enabler is missing; draw it too, so the entity
// blob, the vector preview its author cached for exactly this case. Draw it
// when the object enabler is missing, so the entity
// occupies its real place instead of silently disappearing.
let proxy_blob: Option<std::borrow::Cow<'_, [u8]>> = match e {
EntityType::Unknown(_) => e
@ -665,7 +665,7 @@ pub(crate) fn tessellate_entity(
//
// The DWG reader decodes the two cut-line endpoints, the signed end ticks
// and the identifier. Synthesize the end ticks + arrowheads + label glyphs
// so the mark is visible on the layout, the way AutoCAD draws it. The raw
// so the mark is visible on the layout. The raw
// record is still preserved for lossless write-back.
if let EntityType::SectionSymbol(s) = e {
return section_symbol_wires(
@ -736,118 +736,6 @@ pub(crate) fn tessellate_entity(
}];
}
// ── Dimension baked-block fast path ─────────────────────────────────────
//
// A saved dimension may carry final geometry (extension lines, dim line,
// arrows and text) in a per-instance block — usually
// `*D<n>`, but custom names like `DIMBLOCK###-4NP` also occur. When the
// block exists we render its contents through `tessellate_entity` so
// sub-Text/MText get the standard baseline/greek/full LOD ladder, and
// DIMTXT × DIMSCALE isn't re-applied on already-baked geometry.
if let EntityType::Dimension(dim) = e {
let block_name = &dim.base().block_name;
if !block_name.trim().is_empty()
&& !crate::entities::dimension::uses_custom_arrow_blocks(document, dim)
{
if let Some(br) = document
.block_records
.iter()
.find(|br| br.name.eq_ignore_ascii_case(block_name))
{
if !br.entity_handles.is_empty() {
let mut wires: Vec<WireModel> = Vec::with_capacity(br.entity_handles.len());
// The Dimension's own layer style — layer-0 inheritance
// target for baked sub-entities on layer "0" (#221).
let dim_l0_color = view::render::adapt_to_bg(
view::render::layer_render_style(document, &e.common().layer).color,
bg_color,
);
let dim_l0_aci = document
.layers
.get(&e.common().layer)
.map(|l| match &l.color {
acadrust::types::Color::Index(i) => *i,
_ => 0,
})
.unwrap_or(0);
for &eh in &br.entity_handles {
let Some(sub) = document.get_entity(eh) else {
continue;
};
// A dimension's definition points are baked into the
// block as POINTs on the Defpoints layer. They are grip
// markers rather than PDMODE display geometry, so
// geometry — so rendering them adds a stray tick at each
// measured point that makes the extension lines look like
// they run past the geometry. Skip them.
if matches!(sub, EntityType::Point(_)) {
continue;
}
// Sub-entities inside *D### / DIMBLOCK## blocks
// typically use ByBlock color/linetype/lineweight —
// they should inherit from the Dimension entity.
let has_book_color =
view::render::has_resolved_book_color(document, sub);
let sub_color_is_byblock = !has_book_color
&& sub.common().color == acadrust::types::Color::ByBlock;
let sub_is_l0_bylayer =
!has_book_color
&& view::render::is_effective_layer_zero(&sub.common().layer)
&& sub.common().color == acadrust::types::Color::ByLayer;
let sub_wires = tessellate_entity(
document,
selected,
active_viewport,
bg_color,
// Block contents are baked at the final WCS size —
// don't let downstream paths re-apply anno_scale.
1.0,
None,
sub,
block_cache,
view_aabb,
world_per_pixel,
paper_space,
);
for mut w in sub_wires {
w.name = h.value().to_string();
// Override ByBlock colour with the dim's resolved
// colour so text matches `DIMCLRT`-style behaviour
// (or layer colour) instead of the raw ByBlock
// fallback that render_style_for produces. A layer-0
// sub inherits the dim's layer colour instead.
if sub_color_is_byblock {
w.color = if sel {
WireModel::SELECTED
} else {
entity_color
};
w.aci = aci;
} else if sub_is_l0_bylayer && !sel {
w.color = dim_l0_color;
w.aci = dim_l0_aci;
}
wires.push(w);
}
}
if !wires.is_empty() {
let aabb = entity_aabb(e);
for w in &mut wires {
// Empty SDF-text cells keep their tight glyph-box
// AABB; only stroke/fill wires take the whole-block
// box as a broad-phase pick hint.
if !w.points.is_empty() || !w.fill_tris.is_empty() {
set_wire_aabb(w, aabb);
}
}
return wires;
}
}
}
}
// Fall through to the synthesis path below when no block is attached.
}
if let EntityType::Dimension(dim) = e {
let aabb = entity_aabb(e);
use crate::entities::dimension::DimensionTess;
@ -904,7 +792,7 @@ pub(crate) fn tessellate_entity(
// ── Table baked-block fast path ─────────────────────────────────────────
//
// AutoCAD bakes a Table's final rendered geometry (cell text, gridlines,
// A table may store final rendered geometry (cell text, gridlines,
// fill) into a per-instance block (usually `*T###`) referenced through
// `table.block_record_handle`. The block's text uses the *displayed*
// height; synthesising cells from `self.rows + TableStyle` instead would

View file

@ -1538,28 +1538,6 @@ pub(crate) fn arrow_from_block(
.unwrap_or_else(|| arrow_from_block_name(None, dimasz))
}
pub(crate) fn arrow_block_is_custom(
doc: &CadDocument,
handle: acadrust::types::Handle,
) -> bool {
if handle.is_null() {
return false;
}
doc.block_records
.iter()
.find(|record| record.handle == handle)
.is_some_and(|record| {
!record.entity_handles.is_empty()
&& !record.is_layout()
&& !record.is_model_space()
&& !record.is_paper_space()
&& !record.flags.is_xref
&& !record.flags.is_xref_overlay
&& !record.flags.is_external
&& builtin_arrow_from_block_name(&record.name, 1.0).is_none()
})
}
fn arrow_from_block_name(name: Option<&str>, dimasz: f32) -> ArrowKind {
name.and_then(|name| builtin_arrow_from_block_name(name, dimasz))
.unwrap_or(ArrowKind::Triangle {
@ -1742,6 +1720,10 @@ fn collect_custom_arrow_entity(
stack.pop();
return;
}
EntityType::Hatch(hatch) => {
append_custom_hatch_fill(hatch, root_base, fill);
return;
}
_ => {}
}
@ -1766,6 +1748,69 @@ fn collect_custom_arrow_entity(
}
}
fn append_custom_hatch_fill(
hatch: &acadrust::entities::Hatch,
base: acadrust::types::Vector3,
out: &mut Vec<[f32; 3]>,
) {
use lyon_tessellation::math::point;
use lyon_tessellation::path::Path;
use lyon_tessellation::{
BuffersBuilder, FillOptions, FillRule, FillTessellator, FillVertex, VertexBuffers,
};
let Some(model) = crate::scene::Scene::hatch_model_from_dxf(hatch, [1.0; 4]) else {
return;
};
let mut builder = Path::builder();
let mut ring: Vec<[f32; 2]> = Vec::new();
let mut finish_ring = |ring: &mut Vec<[f32; 2]>| {
if ring.len() >= 3 {
builder.begin(point(ring[0][0], ring[0][1]));
for p in &ring[1..] {
builder.line_to(point(p[0], p[1]));
}
builder.end(true);
}
ring.clear();
};
for &[x, y] in model.boundary.iter() {
if x.is_nan() || y.is_nan() {
finish_ring(&mut ring);
continue;
}
ring.push([
(model.world_origin[0] + x as f64 - base.x) as f32,
(model.world_origin[1] + y as f64 - base.y) as f32,
]);
}
finish_ring(&mut ring);
let mut geometry: VertexBuffers<[f32; 2], u32> = VertexBuffers::new();
let mut tessellator = FillTessellator::new();
if tessellator
.tessellate_path(
&builder.build(),
&FillOptions::default().with_fill_rule(FillRule::EvenOdd),
&mut BuffersBuilder::new(&mut geometry, |vertex: FillVertex| {
vertex.position().to_array()
}),
)
.is_err()
{
return;
}
let z = -base.z as f32;
out.extend(
geometry
.indices
.iter()
.filter_map(|&index| geometry.vertices.get(index as usize))
.map(|&[x, y]| [x, y, z]),
);
}
fn append_custom_wire_points(
points: &[[f32; 3]],
points_low: &[[f32; 3]],
@ -1928,7 +1973,7 @@ fn fallback_geometry(entity: &EntityType) -> Geometry {
/// Extract pre-computed edge-wire points from Solid3D / Region / Body entities.
///
/// AutoCAD stores explicit wire geometry (from SOLVIEW / 3DPLOT) alongside the
/// Some drawings store explicit wire geometry alongside the
/// ACIS data. We use this as a visible fallback when the SAT tessellator
/// produces no mesh (e.g. binary SAB data or unsupported geometry).
fn solid_wire_fallback(entity: &EntityType) -> Vec<[f64; 3]> {
@ -2117,7 +2162,7 @@ pub(crate) fn add_polyline(points: &mut Vec<[f32; 3]>, polyline: &[Vec3]) {
/// Returns the text position of a dimension in DXF world-space (f64, no offset applied).
/// Used when building a synthetic Text entity so tessellate() can apply world_offset itself.
/// When the saved `text_middle_point` is zero (i.e. AutoCAD never wrote one),
/// When the saved `text_middle_point` is zero (no explicit point was written),
/// computes a fallback from the dim geometry and applies DIMTAD/DIMGAP.
pub(crate) fn normalized_or(v: Vec3, fallback: Vec3) -> Vec3 {
if v.length_squared() <= 1e-12 {

View file

@ -1791,7 +1791,7 @@ impl Scene {
}
}
pub(super) fn hatch_model_from_dxf(
pub(crate) fn hatch_model_from_dxf(
dxf: &DxfHatch,
color: [f32; 4],
) -> Option<HatchModel> {
@ -1814,9 +1814,9 @@ impl Scene {
for path in &dxf.paths {
// Skip TEXTBOX boundary paths (flag bit 3). These are text
// bounding-boxes AutoCAD derives for island detection; they are
// derived bounding boxes used for island detection; they are
// never drawn or filled. Treating one as a fill boundary paints its
// rectangle solid — a phantom bar AutoCAD never shows.
// rectangle solid and creates a phantom bar.
if path.flags.bits() & 8 != 0 {
continue;
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,103 +1,383 @@
//! Multiline Style Manager window — fills the entire OS window.
//! Multiline style manager.
use crate::app::Message;
use iced::widget::{column, container, row, scrollable, text};
use iced::{Element, Theme};
use crate::t;
use iced::widget::{button, canvas, checkbox, column, container, row, text, text_input};
use iced::{mouse, Color, Element, Length, Point, Rectangle, Theme};
use std::borrow::Cow;
pub struct MlStyleView<'a> {
pub styles: Vec<String>,
pub selected: &'a str,
pub style: Option<&'a acadrust::objects::MLineStyle>,
pub current: String,
pub tab: u8,
pub compare_name: String,
pub compare_opts: Vec<String>,
pub comparison_sections: Vec<String>,
pub in_use: bool,
pub description: &'a str,
pub start_angle: &'a str,
pub end_angle: &'a str,
pub fill_color: &'a str,
pub elements: &'a [[String; 3]],
pub rename_active: Option<&'a str>,
pub rename_buf: &'a str,
}
fn muted_style(theme: &Theme) -> iced::widget::text::Style {
iced::widget::text::Style {
color: Some(theme.palette().background.base.text.scale_alpha(0.68)),
}
}
pub fn view_window<'a>(
styles: Vec<String>,
selected: &'a str,
selected_style: Option<&'a acadrust::objects::MLineStyle>,
current_style: String,
rename_active: Option<&'a str>,
rename_buf: &'a str,
sizing: crate::ui::modal::ModalSizing,
) -> Element<'a, Message> {
// ── Right: Details panel ──────────────────────────────────────────────
let info_row = |label: Cow<'static, str>, val: String| -> Element<'_, Message> {
row![
text(label).size(11).style(muted_style).width(120),
text(val).size(11),
]
.spacing(8)
.align_y(iced::Center)
.into()
};
fn primary_style(theme: &Theme) -> iced::widget::text::Style {
iced::widget::text::Style {
color: Some(theme.palette().primary.base.color),
}
}
let details: Element<'_, Message> = if let Some(s) = selected_style {
let elem_rows: Vec<Element<'_, Message>> = s
fn input_row<'a>(
label: Cow<'static, str>,
placeholder: &'static str,
value: &'a str,
field: &'static str,
) -> Element<'a, Message> {
row![
text(label).size(11).style(muted_style).width(165),
text_input(placeholder, value)
.on_input(move |value| Message::MlStyleEdit { field, value })
.size(11)
.width(190),
]
.spacing(8)
.align_y(iced::Center)
.into()
}
fn toggle<'a>(label: Cow<'static, str>, value: bool, field: &'static str) -> Element<'a, Message> {
checkbox(value)
.label(label)
.on_toggle(move |_| Message::MlStyleToggle(field))
.size(14)
.text_size(11)
.into()
}
fn aci_color(value: &str, fallback: Color) -> Color {
crate::ui::color_select::aci_string_to_color(value)
.rgb()
.map(|(r, g, b)| Color::from_rgb8(r, g, b))
.unwrap_or(fallback)
}
struct MLinePreviewCanvas {
description: String,
start_angle: String,
end_angle: String,
fill_color: String,
fill: bool,
joints: bool,
start_square: bool,
start_inner: bool,
start_round: bool,
end_square: bool,
end_inner: bool,
end_round: bool,
elements: Vec<[String; 3]>,
}
fn element_points(offset: f32, bounds: Rectangle) -> [Point; 3] {
let y = bounds.height * 0.48 - offset * 26.0;
[
Point::new(44.0, y),
Point::new(bounds.width * 0.52, y - 16.0),
Point::new(bounds.width - 44.0, y + 5.0),
]
}
fn draw_arc(frame: &mut canvas::Frame, center: Point, radius: f32, start_side: bool, color: Color) {
let path = canvas::Path::new(|builder| {
for step in 0..=18 {
let t = step as f32 / 18.0;
let angle = if start_side {
std::f32::consts::FRAC_PI_2 + t * std::f32::consts::PI
} else {
-std::f32::consts::FRAC_PI_2 + t * std::f32::consts::PI
};
let point = Point::new(center.x + radius * angle.cos(), center.y + radius * angle.sin());
if step == 0 {
builder.move_to(point);
} else {
builder.line_to(point);
}
}
});
frame.stroke(&path, canvas::Stroke::default().with_color(color).with_width(1.1));
}
impl canvas::Program<Message> for MLinePreviewCanvas {
type State = ();
fn draw(
&self,
_state: &(),
renderer: &iced::Renderer,
theme: &Theme,
bounds: Rectangle,
_cursor: mouse::Cursor,
) -> Vec<canvas::Geometry> {
let mut frame = canvas::Frame::new(renderer, bounds.size());
let ink = theme.palette().background.base.text;
let mut parsed = self
.elements
.iter()
.enumerate()
.map(|(idx, e)| {
let color_str = match &e.color {
acadrust::types::Color::ByLayer => "ByLayer".into(),
acadrust::types::Color::None => "None".into(),
acadrust::types::Color::ByBlock => "ByBlock".into(),
acadrust::types::Color::Index(i) => format!("ACI {i}"),
acadrust::types::Color::Rgb { r, g, b } => format!("#{r:02X}{g:02X}{b:02X}"),
};
let lt = if e.linetype.is_empty() {
"ByLayer"
} else {
&e.linetype
};
row![
text(format!(" {idx}:")).size(10).style(muted_style).width(24),
text(format!("{:+.3}", e.offset)).size(10).width(70),
text(color_str).size(10).width(90),
text(lt).size(10),
]
.spacing(4)
.align_y(iced::Center)
.into()
.map(|element| {
(
element[0].trim().parse::<f32>().unwrap_or(0.0),
element[1].clone(),
element[2].clone(),
)
})
.collect();
.collect::<Vec<_>>();
parsed.sort_by(|a, b| b.0.total_cmp(&a.0));
if let (Some(top), Some(bottom)) = (parsed.first(), parsed.last()) {
if self.fill {
let upper = element_points(top.0, bounds);
let lower = element_points(bottom.0, bounds);
let fill = canvas::Path::new(|builder| {
builder.move_to(upper[0]);
builder.line_to(upper[1]);
builder.line_to(upper[2]);
builder.line_to(lower[2]);
builder.line_to(lower[1]);
builder.line_to(lower[0]);
builder.close();
});
frame.fill(&fill, aci_color(&self.fill_color, theme.palette().background.weak.color));
}
}
for (offset, color, linetype) in &parsed {
let points = element_points(*offset, bounds);
let dashed = !linetype.trim().is_empty()
&& !linetype.eq_ignore_ascii_case("ByLayer")
&& !linetype.to_ascii_lowercase().contains("continuous");
let stroke = canvas::Stroke {
style: canvas::Style::Solid(aci_color(color, ink)),
width: 1.4,
line_dash: if dashed {
canvas::LineDash { segments: &[6.0, 4.0], offset: 0 }
} else {
canvas::LineDash::default()
},
..Default::default()
};
frame.stroke(
&canvas::Path::new(|builder| {
builder.move_to(points[0]);
builder.line_to(points[1]);
builder.line_to(points[2]);
}),
stroke,
);
}
if let (Some(top), Some(bottom)) = (parsed.first(), parsed.last()) {
let top_points = element_points(top.0, bounds);
let bottom_points = element_points(bottom.0, bounds);
let start_top = top_points[0];
let start_bottom = bottom_points[0];
let end_top = top_points[2];
let end_bottom = bottom_points[2];
let start_angle = self.start_angle.trim().parse::<f32>().unwrap_or(90.0).to_radians();
let end_angle = self.end_angle.trim().parse::<f32>().unwrap_or(90.0).to_radians();
let cap = |a: Point, b: Point, angle: f32| {
let middle = Point::new((a.x + b.x) * 0.5, (a.y + b.y) * 0.5);
let half = ((a.y - b.y).abs() * 0.5).max(2.0);
let direction = Point::new(angle.cos() * half, angle.sin() * half);
(Point::new(middle.x - direction.x, middle.y - direction.y), Point::new(middle.x + direction.x, middle.y + direction.y))
};
if self.start_square {
let (a, b) = cap(start_top, start_bottom, start_angle);
frame.stroke(&canvas::Path::line(a, b), canvas::Stroke::default().with_color(ink));
}
if self.end_square {
let (a, b) = cap(end_top, end_bottom, end_angle);
frame.stroke(&canvas::Path::line(a, b), canvas::Stroke::default().with_color(ink));
}
let start_center = Point::new((start_top.x + start_bottom.x) * 0.5, (start_top.y + start_bottom.y) * 0.5);
let end_center = Point::new((end_top.x + end_bottom.x) * 0.5, (end_top.y + end_bottom.y) * 0.5);
let outer_radius = ((start_top.y - start_bottom.y).abs() * 0.5).max(3.0);
if self.start_round {
draw_arc(&mut frame, start_center, outer_radius, true, ink);
}
if self.end_round {
draw_arc(&mut frame, end_center, outer_radius, false, ink);
}
if self.start_inner && parsed.len() > 2 {
draw_arc(&mut frame, start_center, outer_radius * 0.55, true, ink);
}
if self.end_inner && parsed.len() > 2 {
draw_arc(&mut frame, end_center, outer_radius * 0.55, false, ink);
}
if self.joints {
let joint_top = top_points[1];
let joint_bottom = bottom_points[1];
frame.stroke(&canvas::Path::line(joint_top, joint_bottom), canvas::Stroke::default().with_color(ink).with_width(1.0));
}
}
frame.fill_text(canvas::Text {
content: format!("{} · {} {}", self.description, t!("Elements"), self.elements.len()),
position: Point::new(10.0, bounds.height - 9.0),
color: ink.scale_alpha(0.62),
size: iced::Pixels(10.0),
align_y: iced::alignment::Vertical::Center,
..Default::default()
});
vec![frame.into_geometry()]
}
}
let mut col_items: Vec<Element<'_, Message>> = vec![
info_row(t!("Name:"), s.name.clone()),
info_row(t!("Elements:"), s.elements.len().to_string()),
text(t!(" Off Color Ltype"))
.size(10)
.style(muted_style)
.into(),
];
col_items.extend(elem_rows);
scrollable(column(col_items).spacing(6).padding([12, 12]))
.height(sizing.height)
.into()
} else {
container(text(t!("Select a style to view details.")).size(11).style(muted_style))
.padding([12, 12])
.into()
pub fn view_window<'a>(
v: MlStyleView<'a>,
sizing: crate::ui::modal::ModalSizing,
) -> Element<'a, Message> {
let style = v.style;
let content: Element<'a, Message> = match (v.tab, style) {
(_, None) => text(t!("Select a style to view details.")).size(11).into(),
(0, Some(_)) => {
let mut items = column![
row![
text(t!("Offset")).size(10).style(muted_style).width(110),
text(t!("Color")).size(10).style(muted_style).width(100),
text(t!("Line type")).size(10).style(muted_style).width(170),
button(text(t!("Add")).size(10)).on_press(Message::MlStyleElementAdd).padding([4, 12]),
]
.spacing(6)
.align_y(iced::Center),
]
.spacing(6);
for (index, element) in v.elements.iter().enumerate() {
items = items.push(
row![
text_input("0.0", &element[0])
.on_input(move |value| Message::MlStyleElementEdit { index, field: "offset", value })
.size(11).width(110),
text_input("256", &element[1])
.on_input(move |value| Message::MlStyleElementEdit { index, field: "color", value })
.size(11).width(100),
text_input("ByLayer", &element[2])
.on_input(move |value| Message::MlStyleElementEdit { index, field: "linetype", value })
.size(11).width(170),
button(text(t!("Delete")).size(10))
.on_press(Message::MlStyleElementDelete(index))
.padding([4, 10]),
]
.spacing(6)
.align_y(iced::Center),
);
}
items.into()
}
(_, Some(style)) => column![
input_row(t!("Description"), "", v.description, "description"),
text(t!("Fill and joints")).size(11).style(primary_style),
row![
toggle(t!("Fill enabled"), style.flags.fill_on, "fill"),
toggle(t!("Display joints"), style.flags.display_joints, "joints"),
].spacing(18),
input_row(t!("Fill color"), "256", v.fill_color, "fill_color"),
text(t!("Start caps")).size(11).style(primary_style),
row![
toggle(t!("Line"), style.flags.start_square_cap, "start_square"),
toggle(t!("Inner arcs"), style.flags.start_inner_arcs_cap, "start_inner"),
toggle(t!("Outer arc"), style.flags.start_round_cap, "start_round"),
].spacing(18),
input_row(t!("Start angle"), "90", v.start_angle, "start_angle"),
text(t!("End caps")).size(11).style(primary_style),
row![
toggle(t!("Line"), style.flags.end_square_cap, "end_square"),
toggle(t!("Inner arcs"), style.flags.end_inner_arcs_cap, "end_inner"),
toggle(t!("Outer arc"), style.flags.end_round_cap, "end_round"),
].spacing(18),
input_row(t!("End angle"), "90", v.end_angle, "end_angle"),
].spacing(9).into(),
};
let right_panel = container(details)
.width(sizing.width)
.height(sizing.height);
let preview: Element<'a, Message> = if let Some(style) = style {
canvas(MLinePreviewCanvas {
description: v.description.to_string(),
start_angle: v.start_angle.to_string(),
end_angle: v.end_angle.to_string(),
fill_color: v.fill_color.to_string(),
fill: style.flags.fill_on,
joints: style.flags.display_joints,
start_square: style.flags.start_square_cap,
start_inner: style.flags.start_inner_arcs_cap,
start_round: style.flags.start_round_cap,
end_square: style.flags.end_square_cap,
end_inner: style.flags.end_inner_arcs_cap,
end_round: style.flags.end_round_cap,
elements: v.elements.to_vec(),
})
.width(Length::Fill)
.height(150)
.into()
} else {
container(text(t!("No preview"))).height(150).into()
};
let status = if v.selected.eq_ignore_ascii_case(&v.current) {
t!("Current style")
} else if v.in_use {
t!("Used in drawing")
} else {
t!("Available style")
};
let summary = if v.comparison_sections.is_empty() {
t!("No differences").into_owned()
} else {
format!("{}: {}", t!("Different"), v.comparison_sections.join(", "))
};
let editor = crate::ui::style::style_manager::editor_shell(
crate::ui::style::style_manager::EditorShell {
sizing,
selected: v.selected.to_string(),
status,
preview,
comparison: Some(crate::ui::style::style_manager::EditorComparison {
selected: v.compare_name,
options: v.compare_opts,
summary,
on_select: Message::MlStyleDialogCompare,
}),
tabs: vec![
crate::ui::style::style_manager::EditorTab {
label: t!("Elements"),
active: v.tab == 0,
on_press: Message::MlStyleDialogTab(0),
},
crate::ui::style::style_manager::EditorTab {
label: t!("Caps and Fill"),
active: v.tab == 1,
on_press: Message::MlStyleDialogTab(1),
},
],
content,
},
);
crate::ui::style::style_manager::view(crate::ui::style::style_manager::Scaffold {
sizing,
kind: crate::app::StyleKind::MLine,
styles: &styles,
selected,
current: Some(current_style.as_str()),
rename_active,
rename_buf,
styles: &v.styles,
selected: v.selected,
current: Some(v.current.as_str()),
rename_active: v.rename_active,
rename_buf: v.rename_buf,
on_new: Message::MlStyleDialogNew,
on_copy: Message::MlStyleDialogCopy,
on_delete: Message::MlStyleDialogDelete,
on_select: Message::MlStyleDialogSelect,
on_set_current: Message::MlStyleDialogSetCurrent,
on_apply: Message::MlStyleApply,
editor: right_panel.into(),
read_only: false,
editor,
})
}

View file

@ -29,6 +29,7 @@ pub fn item<'a>(
on_select: Message,
rename_active: Option<&str>,
rename_buf: &'a str,
can_rename: bool,
) -> Element<'a, Message> {
if rename_active == Some(name) {
text_input("", rename_buf)
@ -56,9 +57,12 @@ pub fn item<'a>(
..Default::default()
}
});
mouse_area(cell)
.on_press(on_select)
.on_double_click(Message::StyleRenameStart(kind, name.to_string()))
.into()
let area = mouse_area(cell).on_press(on_select);
if can_rename {
area.on_double_click(Message::StyleRenameStart(kind, name.to_string()))
.into()
} else {
area.into()
}
}
}

View file

@ -10,7 +10,7 @@
use crate::app::{Message, StyleKind};
use iced::widget::button::{Status, Style};
use iced::widget::{button, column, container, row, scrollable, text, Space};
use iced::{Background, Border, Element, Theme};
use iced::{Background, Border, Element, Length, Theme};
use crate::t;
use std::borrow::Cow;
@ -45,6 +45,9 @@ pub struct Scaffold<'a, 'b> {
pub on_set_current: Message,
/// "Apply" action (right side, primary). Every manager has one.
pub on_apply: Message,
/// Referenced styles may be copied but not changed, renamed, deleted, or
/// made current.
pub read_only: bool,
pub editor: Element<'a, Message>,
}
@ -55,10 +58,10 @@ pub fn view<'a, 'b>(s: Scaffold<'a, 'b>) -> Element<'a, Message> {
let bar = row![
tb_button(t!("New"), s.on_new, false),
tb_button(t!("Copy"), s.on_copy, false),
tb_button(t!("Delete"), s.on_delete, false),
tb_button_enabled(t!("Delete"), s.on_delete, false, !s.read_only),
Space::new().width(width),
tb_button(t!("Set Current"), s.on_set_current, false),
tb_button(t!("Apply"), s.on_apply, true),
tb_button_enabled(t!("Set Current"), s.on_set_current, false, !s.read_only),
tb_button_enabled(t!("Apply"), s.on_apply, true, !s.read_only),
]
.spacing(4)
.align_y(iced::Center);
@ -87,6 +90,7 @@ pub fn view<'a, 'b>(s: Scaffold<'a, 'b>) -> Element<'a, Message> {
(s.on_select)(name.clone()),
s.rename_active,
s.rename_buf,
!(s.read_only && is_sel),
)
})
.collect();
@ -137,6 +141,102 @@ pub fn view<'a, 'b>(s: Scaffold<'a, 'b>) -> Element<'a, Message> {
.into()
}
pub struct EditorTab {
pub label: Cow<'static, str>,
pub active: bool,
pub on_press: Message,
}
pub struct EditorComparison {
pub selected: String,
pub options: Vec<String>,
pub summary: String,
pub on_select: fn(String) -> Message,
}
/// Shared right-hand editor composition used by every named style manager.
/// The preview stays visible while the active property page scrolls.
pub struct EditorShell<'a> {
pub sizing: crate::ui::modal::ModalSizing,
pub selected: String,
pub status: Cow<'static, str>,
pub preview: Element<'a, Message>,
pub comparison: Option<EditorComparison>,
pub tabs: Vec<EditorTab>,
pub content: Element<'a, Message>,
}
pub fn editor_shell<'a>(shell: EditorShell<'a>) -> Element<'a, Message> {
let tabs: Vec<Element<'a, Message>> = shell
.tabs
.into_iter()
.map(|tab| {
button(text(tab.label).size(11))
.on_press(tab.on_press)
.style(tab_button_style(tab.active))
.padding([4, 10])
.into()
})
.collect();
let comparison: Element<'a, Message> = match shell.comparison {
Some(comparison) if !comparison.options.is_empty() => row![
text(t!("Compare with")).size(10).style(muted_text_style),
iced::widget::pick_list(
Some(comparison.selected),
comparison.options,
|value| value.to_string(),
)
.on_select(comparison.on_select)
.text_size(11)
.width(150),
text(comparison.summary).size(10).style(muted_text_style),
]
.spacing(8)
.align_y(iced::Center)
.into(),
_ => Space::new().height(0).into(),
};
let preview = container(shell.preview)
.width(Length::Fill)
.style(|theme: &Theme| container::Style {
background: Some(Background::Color(theme.palette().background.weak.color)),
border: Border {
color: theme.palette().background.neutral.color,
width: 1.0,
radius: 3.0.into(),
},
..Default::default()
});
container(
column![
row![
text(shell.selected).size(13).style(primary_text_style),
Space::new().width(Length::Fill),
text(shell.status).size(10).style(muted_text_style),
]
.align_y(iced::Center),
preview,
comparison,
row(tabs).spacing(2),
hdivider(Length::Fill),
scrollable(container(shell.content).padding([12, 12]).width(Length::Fill))
.width(Length::Fill)
.height(Length::Fill),
]
.spacing(6)
.height(shell.sizing.height),
)
.height(shell.sizing.height)
.width(Length::Fill)
.padding(iced::Padding {
top: 12.0,
right: 0.0,
bottom: 12.0,
left: 0.0,
})
.into()
}
// ── Shared chrome ──────────────────────────────────────────────────────────
pub(crate) fn tb_button(
@ -152,10 +252,55 @@ pub(crate) fn tb_button(
.into()
}
pub(crate) fn tb_button_enabled(
label: impl Into<Cow<'static, str>>,
msg: Message,
accent: bool,
enabled: bool,
) -> Element<'static, Message> {
let pad = if accent { [4, 14] } else { [4, 10] };
let button = button(text(label.into()).size(11))
.style(btn_s(accent))
.padding(pad);
if enabled {
button.on_press(msg).into()
} else {
button.into()
}
}
fn tab_button_style(active: bool) -> impl Fn(&Theme, Status) -> Style {
move |theme: &Theme, status| {
let palette = theme.palette();
let pair = match (active, status) {
(true, _) => palette.primary.strong,
(false, Status::Hovered | Status::Pressed) => palette.background.strong,
_ => palette.background.weak,
};
Style {
background: Some(Background::Color(pair.color)),
text_color: pair.text,
border: Border {
color: palette.background.neutral.color,
width: 1.0,
radius: 3.0.into(),
},
..Default::default()
}
}
}
fn primary_text_style(theme: &Theme) -> iced::widget::text::Style {
iced::widget::text::Style {
color: Some(theme.palette().primary.base.color),
}
}
fn btn_s(accent: bool) -> impl Fn(&Theme, Status) -> Style {
move |theme: &Theme, st| {
let palette = theme.palette();
let pair = match (accent, st) {
(_, Status::Disabled) => palette.background.weak,
(true, Status::Hovered | Status::Pressed) => palette.primary.strong,
(false, Status::Hovered | Status::Pressed) => palette.background.strong,
(true, _) => palette.primary.base,
@ -163,7 +308,11 @@ fn btn_s(accent: bool) -> impl Fn(&Theme, Status) -> Style {
};
Style {
background: Some(Background::Color(pair.color)),
text_color: pair.text,
text_color: if st == Status::Disabled {
pair.text.scale_alpha(0.45)
} else {
pair.text
},
border: Border {
color: palette.background.neutral.color,
width: 1.0,

View file

@ -1,49 +1,60 @@
//! Table Style Manager window — fills the entire OS window.
//! Table style manager.
use crate::app::Message;
use iced::widget::{
button, checkbox, column, container, row, scrollable, text, text_input, Column,
};
use iced::{Background, Border, Element, Theme};
use crate::t;
use iced::widget::{canvas, checkbox, column, row, text, text_input, Column};
use iced::{mouse, Color, Element, Length, Point, Rectangle, Size, Theme};
use std::borrow::Cow;
use std::fmt;
#[derive(Clone, Debug, Eq, PartialEq)]
struct EnumChoice(String);
struct EnumChoice {
code: String,
label: Cow<'static, str>,
}
impl fmt::Display for EnumChoice {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str(crate::i18n::translate(&self.0).as_ref())
formatter.write_str(self.label.as_ref())
}
}
fn enum_choices(values: &[&str]) -> Vec<EnumChoice> {
values.iter().map(|value| EnumChoice((*value).to_string())).collect()
fn choices(values: &[(&str, &str)]) -> Vec<EnumChoice> {
values
.iter()
.map(|(code, label)| EnumChoice {
code: (*code).to_string(),
label: crate::i18n::translate(label),
})
.collect()
}
fn btn_s(accent: bool) -> impl Fn(&Theme, button::Status) -> button::Style {
move |theme: &Theme, st| {
let palette = theme.palette();
let pair = match (accent, st) {
(true, button::Status::Hovered | button::Status::Pressed) => palette.primary.strong,
(false, button::Status::Hovered | button::Status::Pressed) => {
palette.background.strong
}
(true, _) => palette.primary.base,
_ => palette.background.weak,
};
button::Style {
background: Some(Background::Color(pair.color)),
text_color: pair.text,
border: Border {
color: palette.background.neutral.color,
width: 1.0,
radius: 4.0.into(),
},
..Default::default()
}
}
pub struct TableStyleView<'a> {
pub styles: Vec<String>,
pub selected: &'a str,
pub current: &'a str,
pub style: Option<&'a acadrust::objects::TableStyle>,
pub tab: u8,
pub compare_name: String,
pub compare_opts: Vec<String>,
pub comparison_sections: Vec<String>,
pub in_use: bool,
pub hmargin: &'a str,
pub vmargin: &'a str,
pub description: &'a str,
pub cell_textstyle: &'a [String; 3],
pub cell_height: &'a [String; 3],
pub cell_textcolor: &'a [String; 3],
pub cell_fillcolor: &'a [String; 3],
pub cell_datatype: &'a [String; 3],
pub cell_unittype: &'a [String; 3],
pub cell_format: &'a [String; 3],
pub border_lw: &'a [[String; 6]; 3],
pub border_color: &'a [[String; 6]; 3],
pub border_spacing: &'a [[String; 6]; 3],
pub rename_active: Option<&'a str>,
pub rename_buf: &'a str,
pub color_open: Option<(u8, &'static str)>,
}
fn muted_style(theme: &Theme) -> iced::widget::text::Style {
@ -58,323 +69,492 @@ fn primary_style(theme: &Theme) -> iced::widget::text::Style {
}
}
pub fn view_window<'a>(
styles: Vec<String>,
selected: &'a str,
current: &'a str,
selected_style: Option<&'a acadrust::objects::TableStyle>,
hmargin_buf: &'a str,
vmargin_buf: &'a str,
description_buf: &'a str,
cell_textstyle: &'a [String; 3],
cell_height: &'a [String; 3],
cell_textcolor: &'a [String; 3],
cell_fillcolor: &'a [String; 3],
cell_datatype: &'a [String; 3],
cell_unittype: &'a [String; 3],
cell_format: &'a [String; 3],
border_lw: &'a [[String; 6]; 3],
border_color: &'a [[String; 6]; 3],
border_spacing: &'a [[String; 6]; 3],
rename_active: Option<&'a str>,
rename_buf: &'a str,
color_open: Option<(u8, &'static str)>,
sizing: crate::ui::modal::ModalSizing,
) -> Element<'a, Message> {
// ── Right: Details panel ──────────────────────────────────────────────
let info_row = |label: Cow<'static, str>, val: String| -> Element<'_, Message> {
row![
text(label).size(11).style(muted_style).width(160),
text(val).size(11),
]
.spacing(8)
.align_y(iced::Center)
.into()
};
#[derive(Clone)]
struct PreviewBorder {
color: String,
weight: String,
spacing: String,
double: bool,
hidden: bool,
}
let cell_editor = |row_label: Cow<'static, str>,
row: u8,
rs: &acadrust::objects::RowCellStyle|
-> Element<'a, Message> {
let r = row as usize;
let cell_in = |label: Cow<'static, str>,
placeholder: &'static str,
value: &'a str,
field: &'static str|
-> Element<'a, Message> {
row![
text(label).size(11).style(muted_style).width(150),
text_input(placeholder, value)
.on_input(move |v| Message::TableStyleCellEdit {
row,
field,
value: v
})
.size(11)
.width(100),
]
#[derive(Clone)]
struct PreviewRow {
label: String,
text_style: String,
text_height: String,
text_color: String,
fill_color: String,
fill: bool,
alignment: String,
data_type: String,
unit_type: String,
format: String,
borders: [PreviewBorder; 6],
}
struct TablePreviewCanvas {
rows: [PreviewRow; 3],
active_row: usize,
hmargin: String,
vmargin: String,
description: String,
flow_up: bool,
title_suppressed: bool,
header_suppressed: bool,
annotative: bool,
}
fn aci_color(value: &str, fallback: Color) -> Color {
crate::ui::color_select::aci_string_to_color(value)
.rgb()
.map(|(r, g, b)| Color::from_rgb8(r, g, b))
.unwrap_or(fallback)
}
fn border_width(value: &str) -> f32 {
value
.trim()
.parse::<f32>()
.map(|value| (value.abs() / 35.0).clamp(0.7, 4.5))
.unwrap_or(1.0)
}
fn draw_line(
frame: &mut canvas::Frame,
a: Point,
b: Point,
border: &PreviewBorder,
fallback: Color,
) {
if border.hidden {
return;
}
let stroke = canvas::Stroke::default()
.with_color(aci_color(&border.color, fallback))
.with_width(border_width(&border.weight));
frame.stroke(&canvas::Path::line(a, b), stroke.clone());
if border.double {
let spacing = border
.spacing
.trim()
.parse::<f32>()
.unwrap_or(1.0)
.abs()
.clamp(1.0, 5.0);
let dx = b.x - a.x;
let dy = b.y - a.y;
let length = (dx * dx + dy * dy).sqrt().max(1.0);
let offset = Point::new(-dy / length * spacing, dx / length * spacing);
frame.stroke(
&canvas::Path::line(
Point::new(a.x + offset.x, a.y + offset.y),
Point::new(b.x + offset.x, b.y + offset.y),
),
stroke,
);
}
}
impl canvas::Program<Message> for TablePreviewCanvas {
type State = ();
fn draw(
&self,
_state: &(),
renderer: &iced::Renderer,
theme: &Theme,
bounds: Rectangle,
_cursor: mouse::Cursor,
) -> Vec<canvas::Geometry> {
let mut frame = canvas::Frame::new(renderer, bounds.size());
let ink = theme.palette().background.base.text;
let mut order = vec![2usize, 1, 0];
if self.title_suppressed {
order.retain(|row| *row != 2);
}
if self.header_suppressed {
order.retain(|row| *row != 1);
}
if self.flow_up {
order.reverse();
}
let hmargin = self.hmargin.trim().parse::<f32>().unwrap_or(1.5).abs();
let vmargin = self.vmargin.trim().parse::<f32>().unwrap_or(1.5).abs();
let left = 18.0 + (hmargin * 1.2).clamp(0.0, 18.0);
let right = bounds.width - left;
let top = 9.0 + (vmargin * 0.8).clamp(0.0, 12.0);
let bottom = bounds.height - 24.0;
let row_height = ((bottom - top) / order.len().max(1) as f32).max(18.0);
let col_width = (right - left) / 3.0;
for (display_row, row_index) in order.iter().copied().enumerate() {
let row = &self.rows[row_index];
let y0 = top + display_row as f32 * row_height;
let y1 = y0 + row_height;
let fallback_fill = theme.palette().background.weak.color;
if row.fill {
frame.fill(
&canvas::Path::rectangle(
Point::new(left, y0),
Size::new(right - left, row_height),
),
aci_color(&row.fill_color, fallback_fill),
);
}
let borders = &row.borders;
draw_line(&mut frame, Point::new(left, y0), Point::new(left, y1), &borders[0], ink);
draw_line(&mut frame, Point::new(right, y0), Point::new(right, y1), &borders[1], ink);
draw_line(&mut frame, Point::new(left, y0), Point::new(right, y0), &borders[2], ink);
draw_line(&mut frame, Point::new(left, y1), Point::new(right, y1), &borders[3], ink);
for column in 1..3 {
let x = left + column as f32 * col_width;
draw_line(&mut frame, Point::new(x, y0), Point::new(x, y1), &borders[5], ink);
}
if display_row + 1 < order.len() {
draw_line(&mut frame, Point::new(left, y1), Point::new(right, y1), &borders[4], ink);
}
for column in 0..3 {
let label = if row.format.trim().is_empty() {
format!("{} {}", row.label, column + 1)
} else {
row.format.replace("{}", &(column + 1).to_string())
};
let horizontal = if row.alignment.ends_with("Left") {
iced::advanced::text::Alignment::Left
} else if row.alignment.ends_with("Right") {
iced::advanced::text::Alignment::Right
} else {
iced::advanced::text::Alignment::Center
};
let x = match horizontal {
iced::advanced::text::Alignment::Left => left + column as f32 * col_width + 5.0,
iced::advanced::text::Alignment::Right => left + (column + 1) as f32 * col_width - 5.0,
iced::advanced::text::Alignment::Center => left + (column as f32 + 0.5) * col_width,
_ => left + (column as f32 + 0.5) * col_width,
};
let y = if row.alignment.starts_with("Top") {
y0 + 7.0
} else if row.alignment.starts_with("Bottom") {
y1 - 7.0
} else {
(y0 + y1) * 0.5
};
frame.fill_text(canvas::Text {
content: label,
position: Point::new(x, y),
color: aci_color(&row.text_color, ink),
size: iced::Pixels(
row.text_height
.trim()
.parse::<f32>()
.map(|height| (height * 34.0).clamp(7.0, 16.0))
.unwrap_or(10.0),
),
align_x: horizontal,
align_y: iced::alignment::Vertical::Center,
..Default::default()
});
}
}
let active = &self.rows[self.active_row.min(2)];
frame.fill_text(canvas::Text {
content: format!(
"{} · {} · type {} / unit {}{}{}",
active.text_style,
if self.annotative { t!("Annotative") } else { t!("Drawing units") },
active.data_type,
active.unit_type,
if self.description.trim().is_empty() { "" } else { " · " },
self.description,
),
position: Point::new(10.0, bounds.height - 9.0),
color: ink.scale_alpha(0.65),
size: iced::Pixels(10.0),
align_y: iced::alignment::Vertical::Center,
..Default::default()
});
vec![frame.into_geometry()]
}
}
fn input_row<'a>(
label: Cow<'static, str>,
placeholder: &'static str,
value: &'a str,
message: impl Fn(String) -> Message + 'a,
) -> Element<'a, Message> {
row![
text(label).size(11).style(muted_style).width(155),
text_input(placeholder, value)
.on_input(message)
.size(11)
.width(170),
]
.spacing(8)
.align_y(iced::Center)
.into()
}
fn cell_editor<'a>(v: &TableStyleView<'a>, row_index: u8) -> Element<'a, Message> {
let Some(style) = v.style else {
return text(t!("Select a style to view details.")).into();
};
let row_style = match row_index {
0 => &style.data_row_style,
1 => &style.header_row_style,
_ => &style.title_row_style,
};
let index = row_index as usize;
let cell_input = |label, placeholder, value: &'a str, field| {
input_row(label, placeholder, value, move |value| Message::TableStyleCellEdit {
row: row_index,
field,
value,
})
};
let cell_color = |label: Cow<'static, str>, value: &'a str, field: &'static str| {
let current = crate::ui::color_select::aci_string_to_color(value);
let selector = crate::ui::color_select::color_selector(
current,
v.color_open == Some((row_index, field)),
crate::ui::color_select::ColorExtras { by_layer: true, by_block: true },
move |color| Message::TableStyleCellEdit {
row: row_index,
field,
value: crate::ui::color_select::color_to_aci_string(color),
},
Message::TableColorMore(row_index, field),
Message::OpenColorWindow(crate::app::ColorPickTarget::Table(row_index, field), current),
);
row![text(label).size(11).style(muted_style).width(155), selector]
.spacing(8)
.align_y(iced::Center)
.into()
};
// Shared colour selector — sends the chosen colour through the same
// cell edit as an ACI string.
let cell_color = |label: Cow<'static, str>, value: &'a str, field: &'static str| -> Element<'a, Message> {
let cur = crate::ui::color_select::aci_string_to_color(value);
let open = color_open == Some((row, field));
let selector = crate::ui::color_select::color_selector(
cur,
open,
crate::ui::color_select::ColorExtras {
by_layer: true,
by_block: true,
},
move |c| Message::TableStyleCellEdit {
row,
field,
value: crate::ui::color_select::color_to_aci_string(c),
},
Message::TableColorMore(row, field),
Message::OpenColorWindow(
crate::app::ColorPickTarget::Table(row, field),
cur,
),
);
row![text(label).size(11).style(muted_style).width(150), selector]
.spacing(8)
.align_y(iced::Center)
.into()
};
let mut col = Column::new()
.spacing(3)
.push(text(row_label).size(11).style(primary_style))
.push(cell_in(
t!(" Text style:"),
"Standard",
&cell_textstyle[r],
"textstyle",
))
.push(cell_in(t!(" Text height:"), "0.18", &cell_height[r], "height"))
.push(cell_color(t!(" Text color:"), &cell_textcolor[r], "textcolor"))
.push(cell_color(t!(" Fill color:"), &cell_fillcolor[r], "fillcolor"))
.push(
row![
text(t!(" Alignment:")).size(11).style(muted_style).width(150),
iced::widget::pick_list(
Some(EnumChoice(format!("{:?}", rs.alignment))),
enum_choices(&[
"TopLeft",
"TopCenter",
"TopRight",
"MiddleLeft",
"MiddleCenter",
"MiddleRight",
"BottomLeft",
"BottomCenter",
"BottomRight",
]),
|value| value.to_string(),
)
.on_select(move |choice| Message::TableStyleCellSetAlign {
row,
value: choice.0,
})
.text_size(11)
.width(140),
]
.spacing(8)
.align_y(iced::Center),
)
.push(
checkbox(rs.fill_enabled)
.label(t!(" Background fill enabled"))
.on_toggle(move |_| Message::TableStyleCellToggleFill(row))
.size(14)
.text_size(11),
)
.push(cell_in(t!(" Data type:"), "0", &cell_datatype[r], "datatype"))
.push(cell_in(t!(" Unit type:"), "0", &cell_unittype[r], "unittype"))
.push(cell_in(t!(" Format string:"), "", &cell_format[r], "format"))
.push(
text(t!(" Borders (type / weight / color / spacing / hidden)"))
.size(10)
.style(muted_style),
);
let borders: [(&'static str, &acadrust::objects::TableCellBorder); 6] = [
("L", &rs.left_border),
("R", &rs.right_border),
("T", &rs.top_border),
("B", &rs.bottom_border),
("H", &rs.horizontal_inside_border),
("V", &rs.vertical_inside_border),
];
for (b, (bname, bd)) in borders.into_iter().enumerate() {
let bu = b as u8;
col = col.push(
row![
text(format!(" {bname}")).size(11).style(muted_style).width(28),
iced::widget::pick_list(
Some(EnumChoice(format!("{:?}", bd.border_type))),
enum_choices(&["Single", "Double"]),
|value| value.to_string(),
)
.on_select(move |choice| Message::TableStyleBorderSetType {
cell: row,
border: bu,
value: choice.0,
})
.text_size(10)
.width(74),
text_input("", &border_lw[r][b])
.on_input(move |v| Message::TableStyleBorderEdit {
cell: row,
border: bu,
field: "lw",
value: v
})
.size(10)
.width(46),
text_input("", &border_color[r][b])
.on_input(move |v| Message::TableStyleBorderEdit {
cell: row,
border: bu,
field: "color",
value: v
})
.size(10)
.width(46),
text_input("", &border_spacing[r][b])
.on_input(move |v| Message::TableStyleBorderEdit {
cell: row,
border: bu,
field: "spacing",
value: v
})
.size(10)
.width(46),
checkbox(bd.is_invisible)
.on_toggle(move |_| Message::TableStyleBorderToggleInvisible {
cell: row,
border: bu
})
.size(13),
]
.spacing(5)
.align_y(iced::Center),
);
}
col.push(
button(text(t!("Apply cell")).size(11))
.on_press(Message::TableStyleCellApply(row))
.style(btn_s(true))
.padding([4, 12]),
)
.into()
};
let details: Element<'_, Message> = if let Some(s) = selected_style {
scrollable(
column![
info_row(t!("Name:"), s.name.clone()),
row![
text(t!("Description:")).size(11).style(muted_style).width(160),
text_input("", description_buf)
.on_input(|v| Message::TableStyleEdit {
field: "description",
value: v
})
.size(11)
.width(160),
]
.spacing(8)
.align_y(iced::Center),
row![
text(t!("Flow direction:")).size(11).style(muted_style).width(160),
iced::widget::pick_list(
Some(EnumChoice(format!("{:?}", s.flow_direction))),
enum_choices(&["Down", "Up"]),
|value| value.to_string(),
)
.on_select(|choice| Message::TableStyleSetFlow(choice.0))
.text_size(11)
.width(100),
]
.spacing(8)
.align_y(iced::Center),
row![
text(t!("H Margin:")).size(11).style(muted_style).width(160),
text_input("1.5", hmargin_buf)
.on_input(|v| Message::TableStyleEdit {
field: "hmargin",
value: v
})
.size(11)
.width(100),
]
.spacing(8)
.align_y(iced::Center),
row![
text(t!("V Margin:")).size(11).style(muted_style).width(160),
text_input("1.5", vmargin_buf)
.on_input(|v| Message::TableStyleEdit {
field: "vmargin",
value: v
})
.size(11)
.width(100),
]
.spacing(8)
.align_y(iced::Center),
checkbox(s.title_suppressed)
.label(t!("Title row suppressed"))
.on_toggle(|_| Message::TableStyleToggle("title_sup"))
.size(14)
.text_size(11),
checkbox(s.header_suppressed)
.label(t!("Header row suppressed"))
.on_toggle(|_| Message::TableStyleToggle("header_sup"))
.size(14)
.text_size(11),
button(text(t!("Apply margins")).size(11))
.on_press(Message::TableStyleApply)
.style(btn_s(true))
.padding([4, 12]),
cell_editor(t!("Data Row:"), 0, &s.data_row_style),
cell_editor(t!("Header Row:"), 1, &s.header_row_style),
cell_editor(t!("Title Row:"), 2, &s.title_row_style),
let selected_alignment = format!("{:?}", row_style.alignment);
let mut content = Column::new()
.spacing(7)
.push(cell_input(t!("Text style"), "Standard", &v.cell_textstyle[index], "textstyle"))
.push(cell_input(t!("Text height"), "0.18", &v.cell_height[index], "height"))
.push(cell_color(t!("Text color"), &v.cell_textcolor[index], "textcolor"))
.push(cell_color(t!("Fill color"), &v.cell_fillcolor[index], "fillcolor"))
.push(
row![
text(t!("Alignment")).size(11).style(muted_style).width(155),
iced::widget::pick_list(
Some(EnumChoice { code: selected_alignment.clone(), label: crate::i18n::translate(&selected_alignment) }),
choices(&[
("TopLeft", "Top left"), ("TopCenter", "Top center"), ("TopRight", "Top right"),
("MiddleLeft", "Middle left"), ("MiddleCenter", "Middle center"), ("MiddleRight", "Middle right"),
("BottomLeft", "Bottom left"), ("BottomCenter", "Bottom center"), ("BottomRight", "Bottom right"),
]),
|value| value.to_string(),
)
.on_select(move |choice| Message::TableStyleCellSetAlign { row: row_index, value: choice.code })
.text_size(11)
.width(170),
]
.spacing(6)
.padding([12, 12]),
.spacing(8)
.align_y(iced::Center),
)
.width(sizing.width)
.height(sizing.height)
.into()
} else {
container(text(t!("Select a style to view details.")).size(11).style(muted_style))
.padding([12, 12])
.into()
.push(
checkbox(row_style.fill_enabled)
.label(t!("Background fill enabled"))
.on_toggle(move |_| Message::TableStyleCellToggleFill(row_index))
.size(14)
.text_size(11),
)
.push(cell_input(t!("Data type"), "0", &v.cell_datatype[index], "datatype"))
.push(cell_input(t!("Unit type"), "0", &v.cell_unittype[index], "unittype"))
.push(cell_input(t!("Format string"), "", &v.cell_format[index], "format"))
.push(text(t!("Borders")).size(11).style(primary_style));
let borders = [
(t!("Left"), &row_style.left_border),
(t!("Right"), &row_style.right_border),
(t!("Top"), &row_style.top_border),
(t!("Bottom"), &row_style.bottom_border),
(t!("Inside horizontal"), &row_style.horizontal_inside_border),
(t!("Inside vertical"), &row_style.vertical_inside_border),
];
for (border_index, (label, border)) in borders.into_iter().enumerate() {
let border_index = border_index as u8;
let border_type = format!("{:?}", border.border_type);
content = content.push(
row![
text(label).size(10).style(muted_style).width(96),
iced::widget::pick_list(
Some(EnumChoice { code: border_type.clone(), label: crate::i18n::translate(&border_type) }),
choices(&[("Single", "Single"), ("Double", "Double")]),
|value| value.to_string(),
)
.on_select(move |choice| Message::TableStyleBorderSetType { cell: row_index, border: border_index, value: choice.code })
.text_size(10)
.width(82),
text_input(t!("Weight").as_ref(), &v.border_lw[index][border_index as usize])
.on_input(move |value| Message::TableStyleBorderEdit { cell: row_index, border: border_index, field: "lw", value })
.size(10).width(68),
text_input(t!("Color").as_ref(), &v.border_color[index][border_index as usize])
.on_input(move |value| Message::TableStyleBorderEdit { cell: row_index, border: border_index, field: "color", value })
.size(10).width(62),
text_input(t!("Spacing").as_ref(), &v.border_spacing[index][border_index as usize])
.on_input(move |value| Message::TableStyleBorderEdit { cell: row_index, border: border_index, field: "spacing", value })
.size(10).width(68),
checkbox(border.is_invisible)
.label(t!("Hidden"))
.on_toggle(move |_| Message::TableStyleBorderToggleInvisible { cell: row_index, border: border_index })
.size(13).text_size(10),
]
.spacing(5)
.align_y(iced::Center),
);
}
content.into()
}
fn preview_rows(v: &TableStyleView<'_>) -> Option<[PreviewRow; 3]> {
let style = v.style?;
let source = [&style.data_row_style, &style.header_row_style, &style.title_row_style];
Some(std::array::from_fn(|row| {
let borders = [
&source[row].left_border,
&source[row].right_border,
&source[row].top_border,
&source[row].bottom_border,
&source[row].horizontal_inside_border,
&source[row].vertical_inside_border,
];
PreviewRow {
label: [t!("Data"), t!("Header"), t!("Title")][row].to_string(),
text_style: v.cell_textstyle[row].clone(),
text_height: v.cell_height[row].clone(),
text_color: v.cell_textcolor[row].clone(),
fill_color: v.cell_fillcolor[row].clone(),
fill: source[row].fill_enabled,
alignment: format!("{:?}", source[row].alignment),
data_type: v.cell_datatype[row].clone(),
unit_type: v.cell_unittype[row].clone(),
format: v.cell_format[row].clone(),
borders: std::array::from_fn(|border| PreviewBorder {
color: v.border_color[row][border].clone(),
weight: v.border_lw[row][border].clone(),
spacing: v.border_spacing[row][border].clone(),
double: format!("{:?}", borders[border].border_type) == "Double",
hidden: borders[border].is_invisible,
}),
}
}))
}
pub fn view_window<'a>(
v: TableStyleView<'a>,
sizing: crate::ui::modal::ModalSizing,
) -> Element<'a, Message> {
let style = v.style;
let content: Element<'a, Message> = match (v.tab, style) {
(_, None) => text(t!("Select a style to view details.")).size(11).into(),
(0, Some(style)) => column![
input_row(t!("Description"), "", v.description, |value| Message::TableStyleEdit { field: "description", value }),
row![
text(t!("Flow direction")).size(11).style(muted_style).width(155),
iced::widget::pick_list(
Some(EnumChoice { code: format!("{:?}", style.flow_direction), label: crate::i18n::translate(&format!("{:?}", style.flow_direction)) }),
choices(&[("Down", "Top to bottom"), ("Up", "Bottom to top")]),
|value| value.to_string(),
)
.on_select(|choice| Message::TableStyleSetFlow(choice.code))
.text_size(11).width(170),
]
.spacing(8).align_y(iced::Center),
input_row(t!("Horizontal margin"), "1.5", v.hmargin, |value| Message::TableStyleEdit { field: "hmargin", value }),
input_row(t!("Vertical margin"), "1.5", v.vmargin, |value| Message::TableStyleEdit { field: "vmargin", value }),
checkbox(style.title_suppressed).label(t!("Suppress title row")).on_toggle(|_| Message::TableStyleToggle("title_sup")).size(14).text_size(11),
checkbox(style.header_suppressed).label(t!("Suppress header row")).on_toggle(|_| Message::TableStyleToggle("header_sup")).size(14).text_size(11),
checkbox(style.annotative).label(t!("Annotative")).on_toggle(|_| Message::TableStyleToggleAnnotative).size(14).text_size(11),
]
.spacing(9)
.into(),
(tab, Some(_)) => cell_editor(&v, tab.saturating_sub(1).min(2)),
};
let right_panel = container(details)
.width(sizing.width)
.height(sizing.height);
let rows = preview_rows(&v).unwrap_or_else(|| {
std::array::from_fn(|row| PreviewRow {
label: ["Data", "Header", "Title"][row].to_string(),
text_style: String::new(),
text_height: String::new(),
text_color: String::new(),
fill_color: String::new(),
fill: false,
alignment: "MiddleCenter".to_string(),
data_type: String::new(),
unit_type: String::new(),
format: String::new(),
borders: std::array::from_fn(|_| PreviewBorder {
color: String::new(), weight: String::new(), spacing: String::new(), double: false, hidden: false,
}),
})
});
let preview = canvas(TablePreviewCanvas {
rows,
active_row: v.tab.saturating_sub(1).min(2) as usize,
hmargin: v.hmargin.to_string(),
vmargin: v.vmargin.to_string(),
description: v.description.to_string(),
flow_up: style.is_some_and(|style| format!("{:?}", style.flow_direction) == "Up"),
title_suppressed: style.is_some_and(|style| style.title_suppressed),
header_suppressed: style.is_some_and(|style| style.header_suppressed),
annotative: style.is_some_and(|style| style.annotative),
})
.width(Length::Fill)
.height(150);
let status = if v.selected.eq_ignore_ascii_case(v.current) {
t!("Current style")
} else if v.in_use {
t!("Used in drawing")
} else {
t!("Available style")
};
let summary = if v.comparison_sections.is_empty() {
t!("No differences").into_owned()
} else {
format!("{}: {}", t!("Different"), v.comparison_sections.join(", "))
};
let editor = crate::ui::style::style_manager::editor_shell(
crate::ui::style::style_manager::EditorShell {
sizing,
selected: v.selected.to_string(),
status,
preview: preview.into(),
comparison: Some(crate::ui::style::style_manager::EditorComparison {
selected: v.compare_name,
options: v.compare_opts,
summary,
on_select: Message::TableStyleDialogCompare,
}),
tabs: [t!("General"), t!("Data Row"), t!("Header Row"), t!("Title Row")]
.into_iter()
.enumerate()
.map(|(tab, label)| crate::ui::style::style_manager::EditorTab {
label,
active: v.tab == tab as u8,
on_press: Message::TableStyleDialogTab(tab as u8),
})
.collect(),
content,
},
);
crate::ui::style::style_manager::view(crate::ui::style::style_manager::Scaffold {
sizing,
kind: crate::app::StyleKind::Table,
styles: &styles,
selected,
current: Some(current),
rename_active,
rename_buf,
styles: &v.styles,
selected: v.selected,
current: Some(v.current),
rename_active: v.rename_active,
rename_buf: v.rename_buf,
on_new: Message::TableStyleDialogNew,
on_copy: Message::TableStyleDialogCopy,
on_delete: Message::TableStyleDialogDelete,
on_select: Message::TableStyleDialogSelect,
on_set_current: Message::TableStyleDialogSetCurrent,
on_apply: Message::TableStyleApply,
editor: right_panel.into(),
read_only: false,
editor,
})
}

View file

@ -1,20 +1,21 @@
//! Text Style Font Browser window — fills the entire OS window.
//! Text style manager.
use crate::app::Message;
use crate::app::StyleKind;
use iced::widget::{
button, canvas, checkbox, column, container, row, scrollable, text, text_input, Space,
};
use iced::{mouse, Background, Border, Element, Length, Point, Rectangle, Theme};
use crate::app::{Message, StyleKind};
use crate::t;
use iced::widget::{button, canvas, checkbox, column, container, row, scrollable, text, text_input};
use iced::{mouse, Background, Border, Element, Length, Point, Rectangle, Theme};
use std::borrow::Cow;
/// View-model for the Text Style editor window.
pub struct TextStyleView<'a> {
pub styles: Vec<String>,
pub selected: &'a str,
/// Name of the current text style (marked with ✓ in the list).
pub current: &'a str,
pub tab: u8,
pub compare_name: String,
pub compare_opts: Vec<String>,
pub comparison_sections: Vec<String>,
pub read_only: bool,
pub in_use: bool,
pub font_buf: &'a str,
pub width_buf: &'a str,
pub oblique_buf: &'a str,
@ -23,57 +24,18 @@ pub struct TextStyleView<'a> {
pub ttf_buf: &'a str,
pub backward: bool,
pub upside_down: bool,
pub vertical: bool,
pub annotative: bool,
/// Name of the style being renamed inline (double-clicked), if any.
pub rename_active: Option<&'a str>,
/// Edit buffer for the inline rename text input.
pub rename_buf: &'a str,
}
const BUILTIN_FONTS: &[&str] = &[
"Standard", "ISO", "Simplex", "RomanS", "RomanD", "RomanC", "RomanT", "ItalicC", "ItalicT",
"ScriptS", "ScriptC", "GothGBT", "GothGRT", "GothITT", "GreekC", "Symbol",
"ISO3098", "Unicode",
"Standard", "ISO", "Simplex", "RomanS", "RomanD", "RomanC", "RomanT", "ItalicC",
"ItalicT", "ScriptS", "ScriptC", "GothGBT", "GothGRT", "GothITT", "GreekC",
"Symbol", "ISO3098", "Unicode",
];
fn list_item(active: bool) -> impl Fn(&Theme, button::Status) -> button::Style {
move |theme: &Theme, st| {
let palette = theme.palette();
let pair = match (active, st) {
(true, _) => Some(palette.primary.strong),
(false, button::Status::Hovered | button::Status::Pressed) => {
Some(palette.background.strong)
}
_ => None,
};
button::Style {
background: pair.map(|p| Background::Color(p.color)),
text_color: pair.map(|p| p.text).unwrap_or(palette.background.base.text),
..Default::default()
}
}
}
fn field_style(theme: &Theme, status: text_input::Status) -> text_input::Style {
let palette = theme.palette();
let border = match status {
text_input::Status::Focused { .. } => palette.primary.base.color,
_ => palette.background.neutral.color,
};
text_input::Style {
background: Background::Color(palette.background.base.color),
border: Border {
color: border,
width: 1.0,
radius: 3.0.into(),
},
icon: palette.background.base.text,
placeholder: palette.background.base.text.scale_alpha(0.48),
value: palette.background.base.text,
selection: palette.primary.base.color.scale_alpha(0.5),
}
}
fn muted_style(theme: &Theme) -> iced::widget::text::Style {
iced::widget::text::Style {
color: Some(theme.palette().background.base.text.scale_alpha(0.68)),
@ -86,33 +48,55 @@ fn primary_style(theme: &Theme) -> iced::widget::text::Style {
}
}
fn vsep<'a>(height: Length) -> Element<'a, Message> {
container(Space::new().width(1).height(height))
.width(1)
.height(height)
.style(|theme: &Theme| container::Style {
background: Some(Background::Color(
theme.palette().background.neutral.color
)),
..Default::default()
})
.into()
fn field_style(theme: &Theme, status: text_input::Status) -> text_input::Style {
let palette = theme.palette();
text_input::Style {
background: Background::Color(palette.background.base.color),
border: Border {
color: if matches!(status, text_input::Status::Focused { .. }) {
palette.primary.base.color
} else {
palette.background.neutral.color
},
width: 1.0,
radius: 3.0.into(),
},
icon: palette.background.base.text,
placeholder: palette.background.base.text.scale_alpha(0.48),
value: palette.background.base.text,
selection: palette.primary.base.color.scale_alpha(0.5),
}
}
fn list_item(active: bool) -> impl Fn(&Theme, button::Status) -> button::Style {
move |theme: &Theme, status| {
let palette = theme.palette();
let pair = match (active, status) {
(true, _) => Some(palette.primary.strong),
(false, button::Status::Hovered | button::Status::Pressed) => {
Some(palette.background.strong)
}
_ => None,
};
button::Style {
background: pair.map(|value| Background::Color(value.color)),
text_color: pair
.map(|value| value.text)
.unwrap_or(palette.background.base.text),
..Default::default()
}
}
}
/// Live sample-text preview. Tessellates a fixed sample string through the same
/// stroke path the text entities use (`lff::tessellate_text_ex`), so the chosen
/// font, width factor, oblique angle and backward/upside-down flags all show up,
/// then scales the result to fit the preview box (Y flipped: glyph space is
/// Y-up, screen is Y-down). Height is not bound — it only scales uniformly and
/// the fit cancels it.
struct TextPreviewCanvas {
font: String,
/// Negative mirrors left-right (backward).
big_font: String,
width_factor: f32,
/// Radians.
oblique: f32,
/// 0 or π (upside-down rotates 180° about the origin).
rotation: f32,
height: f32,
upside_down: bool,
vertical: bool,
annotative: bool,
}
impl canvas::Program<Message> for TextPreviewCanvas {
@ -127,314 +111,311 @@ impl canvas::Program<Message> for TextPreviewCanvas {
_cursor: mouse::Cursor,
) -> Vec<canvas::Geometry> {
let mut frame = canvas::Frame::new(renderer, bounds.size());
let (strokes, _) = crate::scene::text::lff::tessellate_text_ex(
[0.0, 0.0],
9.0,
self.rotation,
self.width_factor,
self.oblique,
&self.font,
"AaBbCc 0123",
);
let ink = theme.palette().background.base.text;
let glyph_height = if self.height <= 0.0 {
18.0
} else {
(self.height * 7.0).clamp(6.0, 52.0)
};
let rotation = if self.upside_down {
std::f32::consts::PI
} else {
0.0
};
let strokes = if self.vertical {
let mut result = Vec::new();
for (index, character) in "Ab3".chars().enumerate() {
let (mut glyph, _) = crate::scene::text::lff::tessellate_text_ex(
[0.0, -(index as f32) * glyph_height * 1.25],
glyph_height,
rotation,
self.width_factor,
self.oblique,
&self.font,
&character.to_string(),
);
result.append(&mut glyph);
}
result
} else {
crate::scene::text::lff::tessellate_text_ex(
[0.0, 0.0],
glyph_height,
rotation,
self.width_factor,
self.oblique,
&self.font,
"AaBbCc 0123",
)
.0
};
let mut min = [f32::MAX; 2];
let mut max = [f32::MIN; 2];
for s in &strokes {
for &[x, y] in s {
for stroke in &strokes {
for &[x, y] in stroke {
min[0] = min[0].min(x);
min[1] = min[1].min(y);
max[0] = max[0].max(x);
max[1] = max[1].max(y);
}
}
if min[0] > max[0] {
return vec![frame.into_geometry()];
}
let pad = 10.0;
let span = [(max[0] - min[0]).max(1e-3), (max[1] - min[1]).max(1e-3)];
let scale = ((bounds.width - 2.0 * pad) / span[0])
.min((bounds.height - 2.0 * pad) / span[1])
.max(0.0);
let mid = [(min[0] + max[0]) * 0.5, (min[1] + max[1]) * 0.5];
let center = [bounds.width * 0.5, bounds.height * 0.5];
let map = |x: f32, y: f32| {
Point::new(
center[0] + (x - mid[0]) * scale,
center[1] - (y - mid[1]) * scale,
)
};
let stroke = canvas::Stroke {
width: 1.4,
style: canvas::Style::Solid(theme.palette().background.base.text),
..Default::default()
};
for s in &strokes {
if s.len() < 2 {
continue;
}
let path = canvas::Path::new(|p| {
p.move_to(map(s[0][0], s[0][1]));
for &[x, y] in &s[1..] {
p.line_to(map(x, y));
if min[0] <= max[0] {
let span = [(max[0] - min[0]).max(1.0), (max[1] - min[1]).max(1.0)];
let available = [bounds.width - 24.0, bounds.height - 34.0];
let scale = (available[0] / span[0])
.min(available[1] / span[1])
.min(1.0)
.max(0.0);
let middle = [(min[0] + max[0]) * 0.5, (min[1] + max[1]) * 0.5];
let center = [bounds.width * 0.5, (bounds.height - 18.0) * 0.5];
let map = |x: f32, y: f32| {
Point::new(
center[0] + (x - middle[0]) * scale,
center[1] - (y - middle[1]) * scale,
)
};
for stroke in &strokes {
if stroke.len() < 2 {
continue;
}
});
frame.stroke(&path, stroke.clone());
let path = canvas::Path::new(|builder| {
builder.move_to(map(stroke[0][0], stroke[0][1]));
for &[x, y] in &stroke[1..] {
builder.line_to(map(x, y));
}
});
frame.stroke(
&path,
canvas::Stroke::default().with_color(ink).with_width(1.35),
);
}
}
let font_label = if self.big_font.trim().is_empty() {
self.font.clone()
} else {
format!("{} + {}", self.font, self.big_font)
};
let mode = if self.annotative {
t!("Paper height")
} else {
t!("Drawing height")
};
frame.fill_text(canvas::Text {
content: format!("{} · {} {:.3}", font_label, mode, self.height),
position: Point::new(10.0, bounds.height - 9.0),
color: ink.scale_alpha(0.65),
size: iced::Pixels(10.0),
align_y: iced::alignment::Vertical::Center,
..Default::default()
});
vec![frame.into_geometry()]
}
}
fn input_row<'a>(
label: Cow<'static, str>,
placeholder: Cow<'static, str>,
value: &'a str,
field: &'static str,
read_only: bool,
) -> Element<'a, Message> {
let control: Element<'a, Message> = if read_only {
container(text(value).size(11)).padding([5, 7]).width(180).into()
} else {
text_input(placeholder.as_ref(), value)
.on_input(move |value| Message::TextStyleEdit { field, value })
.style(field_style)
.size(11)
.width(180)
.into()
};
row![text(label).size(11).style(muted_style).width(150), control]
.spacing(8)
.align_y(iced::Center)
.into()
}
fn toggle<'a>(
label: Cow<'static, str>,
value: bool,
field: &'static str,
read_only: bool,
) -> Element<'a, Message> {
let checkbox = checkbox(value).label(label).size(14).text_size(11);
if read_only {
checkbox.into()
} else {
checkbox
.on_toggle(move |_| Message::TextStyleToggle(field))
.into()
}
}
fn font_list<'a>(
title: Cow<'static, str>,
values: Vec<String>,
selected: &'a str,
system: bool,
read_only: bool,
) -> Element<'a, Message> {
let items: Vec<Element<'a, Message>> = values
.into_iter()
.map(|font| {
let active = selected.eq_ignore_ascii_case(&font);
let button = button(text(font.clone()).size(10))
.style(list_item(active))
.padding([3, 8])
.width(Length::Fill);
if read_only {
button.into()
} else if system {
button
.on_press(Message::TextStyleEdit {
field: "ttf",
value: font,
})
.into()
} else {
button.on_press(Message::TextStyleFontPick(font)).into()
}
})
.collect();
container(column![text(title).size(10).style(muted_style), scrollable(column(items).spacing(1)).height(250)].spacing(5))
.width(Length::FillPortion(1))
.padding(4)
.into()
}
pub fn view_window<'a>(
v: TextStyleView<'a>,
sizing: crate::ui::modal::ModalSizing,
) -> Element<'a, Message> {
let TextStyleView {
styles,
selected,
current,
font_buf,
width_buf,
oblique_buf,
height_buf,
bigfont_buf,
ttf_buf,
backward,
upside_down,
annotative,
rename_active,
rename_buf,
} = v;
// ── Middle: Font browser ──────────────────────────────────────────────
let font_items: Vec<Element<'_, Message>> = BUILTIN_FONTS
.iter()
.map(|&f| {
let is_sel = font_buf == f;
button(text(f).size(10))
.on_press(Message::TextStyleFontPick(f.to_string()))
.style(list_item(is_sel))
.padding([3, 8])
.width(sizing.width)
.into()
})
.collect();
let font_panel = container(
column![
text(t!("Font File")).size(10).style(muted_style),
container(scrollable(column(font_items).spacing(1)).height(sizing.height))
.style(|theme: &Theme| {
let palette = theme.palette();
container::Style {
background: Some(Background::Color(palette.background.weak.color)),
border: Border {
color: palette.background.neutral.color,
width: 1.0,
radius: 3.0.into()
},
..Default::default()
}
})
.width(sizing.width)
.height(sizing.height)
.padding(2),
text_input(t!("font file…").as_ref(), font_buf)
.on_input(|v| Message::TextStyleEdit {
field: "font",
value: v
})
.style(field_style)
.size(11)
.width(sizing.width),
]
.spacing(6)
.height(sizing.height),
)
.width(190)
.height(sizing.height)
.padding([12, 8]);
// Labeled numeric/text field row → TextStyleEdit { field, value }.
fn frow<'a>(
label: impl Into<Cow<'static, str>>,
ph: impl Into<Cow<'static, str>>,
buf: &'a str,
field: &'static str,
) -> Element<'a, Message> {
row![
text(label.into()).size(11).style(muted_style).width(120),
text_input(ph.into().as_ref(), buf)
.on_input(move |v| Message::TextStyleEdit { field, value: v })
.style(field_style)
.size(11)
.width(140),
]
.spacing(6)
.align_y(iced::Center)
.into()
}
// Live preview reflecting the in-progress edits. Effective font follows the
// entity rule: TrueType name wins when set, else the stroke font file.
let eff_font = if !ttf_buf.trim().is_empty() {
ttf_buf
let effective_font = if v.ttf_buf.trim().is_empty() {
v.font_buf
} else {
font_buf
v.ttf_buf
};
let prev_base_wf = width_buf
let width = v
.width_buf
.trim()
.parse::<f32>()
.unwrap_or(1.0)
.abs()
.clamp(0.01, 100.0);
let preview = canvas(TextPreviewCanvas {
font: eff_font.to_string(),
width_factor: if backward { -prev_base_wf } else { prev_base_wf },
oblique: oblique_buf.trim().parse::<f32>().unwrap_or(0.0).to_radians(),
rotation: if upside_down { std::f32::consts::PI } else { 0.0 },
font: effective_font.to_string(),
big_font: v.bigfont_buf.to_string(),
width_factor: if v.backward { -width } else { width },
oblique: v.oblique_buf.trim().parse::<f32>().unwrap_or(0.0).to_radians(),
height: v.height_buf.trim().parse::<f32>().unwrap_or(0.0).max(0.0),
upside_down: v.upside_down,
vertical: v.vertical,
annotative: v.annotative,
})
.width(sizing.width)
.height(Length::Fixed(56.0));
.width(Length::Fill)
.height(112);
// ── Right: Properties ─────────────────────────────────────────────────
let props_panel = container(
column![
text(t!("Properties")).size(11).style(primary_style),
frow(t!("Big Font:"), t!("big-font file…"), bigfont_buf, "bigfont"),
frow(t!("TrueType Font:"), t!("e.g. Arial"), ttf_buf, "ttf"),
frow(
if annotative {
t!("Paper Text Height:")
} else {
t!("Fixed Height:")
},
t!("0 = variable"),
height_buf,
"height",
),
frow(t!("Width Factor:"), "1.0", width_buf, "width"),
frow(t!("Oblique (°):"), "0.0", oblique_buf, "oblique"),
row![
checkbox(backward)
.label(t!("Backward"))
.on_toggle(|_| Message::TextStyleToggle("backward"))
.size(15)
.text_size(11),
checkbox(upside_down)
.label(t!("Upside down"))
.on_toggle(|_| Message::TextStyleToggle("upside_down"))
.size(15)
.text_size(11),
let content: Element<'a, Message> = match v.tab {
0 => {
let built_in = BUILTIN_FONTS.iter().map(|value| (*value).to_string()).collect();
let system = crate::scene::text::sysfont::families().to_vec();
column![
row![
font_list(t!("Stroke fonts"), built_in, v.font_buf, false, v.read_only),
font_list(t!("System fonts"), system, v.ttf_buf, true, v.read_only),
]
.spacing(10),
input_row(t!("Font file"), t!("font file…"), v.font_buf, "font", v.read_only),
input_row(t!("Big font"), t!("big-font file…"), v.bigfont_buf, "bigfont", v.read_only),
input_row(t!("System font"), t!("font family…"), v.ttf_buf, "ttf", v.read_only),
]
.spacing(16),
checkbox(annotative)
.label(t!("Annotative"))
.on_toggle(|_| Message::TextStyleToggle("annotative"))
.size(15)
.text_size(11),
Space::new().height(8),
text(t!("Preview")).size(10).style(muted_style),
container(preview)
.style(|theme: &Theme| {
let palette = theme.palette();
container::Style {
background: Some(Background::Color(palette.background.base.color)),
border: Border {
color: palette.background.neutral.color,
width: 1.0,
radius: 4.0.into()
},
..Default::default()
}
})
.padding(8)
.width(sizing.width),
.spacing(8)
.into()
}
_ => column![
text(t!("Size")).size(11).style(primary_style),
input_row(
if v.annotative { t!("Paper text height") } else { t!("Fixed height") },
t!("0 = variable"),
v.height_buf,
"height",
v.read_only,
),
text(t!("Effects")).size(11).style(primary_style),
input_row(t!("Width factor"), "1.0".into(), v.width_buf, "width", v.read_only),
input_row(t!("Oblique angle"), "0.0".into(), v.oblique_buf, "oblique", v.read_only),
row![
toggle(t!("Backward"), v.backward, "backward", v.read_only),
toggle(t!("Upside down"), v.upside_down, "upside_down", v.read_only),
toggle(
t!("Vertical"),
v.vertical,
"vertical",
v.read_only || !v.ttf_buf.trim().is_empty(),
),
]
.spacing(18),
toggle(t!("Annotative"), v.annotative, "annotative", v.read_only),
]
.spacing(10)
.height(sizing.height),
)
.width(sizing.width)
.height(sizing.height)
.padding(iced::Padding {
top: 12.0,
right: 12.0,
bottom: 12.0,
left: 8.0,
});
// ── System TrueType fonts (read from the user's machine via fontdb) ──
let ttf_items: Vec<Element<'_, Message>> = crate::scene::text::sysfont::families()
.iter()
.map(|fam| {
let is_sel = ttf_buf.eq_ignore_ascii_case(fam);
button(text(fam).size(10))
.on_press(Message::TextStyleEdit {
field: "ttf",
value: fam.clone(),
})
.style(list_item(is_sel))
.padding([3, 8])
.width(sizing.width)
.into()
})
.collect();
let ttf_panel = container(
column![
text(t!("TrueType (system)")).size(10).style(muted_style),
container(scrollable(column(ttf_items).spacing(1)).height(sizing.height))
.style(|theme: &Theme| {
let palette = theme.palette();
container::Style {
background: Some(Background::Color(palette.background.weak.color)),
border: Border {
color: palette.background.neutral.color,
width: 1.0,
radius: 3.0.into()
},
..Default::default()
}
})
.width(sizing.width)
.height(sizing.height)
.padding(2),
text_input(t!("TrueType font…").as_ref(), ttf_buf)
.on_input(|v| Message::TextStyleEdit {
field: "ttf",
value: v
})
.style(field_style)
.size(11)
.width(sizing.width),
]
.spacing(6)
.height(sizing.height),
)
.width(190)
.height(sizing.height)
.padding([12, 8]);
let editor = row![
font_panel,
vsep(sizing.height),
ttf_panel,
vsep(sizing.height),
props_panel
]
.height(sizing.height);
.spacing(9)
.into(),
};
let status = if v.read_only {
t!("Referenced style · Read only")
} else if v.selected.eq_ignore_ascii_case(v.current) {
t!("Current style")
} else if v.in_use {
t!("Used in drawing")
} else {
t!("Available style")
};
let summary = if v.comparison_sections.is_empty() {
t!("No differences").into_owned()
} else {
format!("{}: {}", t!("Different"), v.comparison_sections.join(", "))
};
let editor = crate::ui::style::style_manager::editor_shell(
crate::ui::style::style_manager::EditorShell {
sizing,
selected: v.selected.to_string(),
status,
preview: preview.into(),
comparison: Some(crate::ui::style::style_manager::EditorComparison {
selected: v.compare_name,
options: v.compare_opts,
summary,
on_select: Message::TextStyleDialogCompare,
}),
tabs: vec![
crate::ui::style::style_manager::EditorTab {
label: t!("Fonts"),
active: v.tab == 0,
on_press: Message::TextStyleDialogTab(0),
},
crate::ui::style::style_manager::EditorTab {
label: t!("Size and Effects"),
active: v.tab == 1,
on_press: Message::TextStyleDialogTab(1),
},
],
content,
},
);
crate::ui::style::style_manager::view(crate::ui::style::style_manager::Scaffold {
sizing,
kind: StyleKind::Text,
styles: &styles,
selected,
current: Some(current),
rename_active,
rename_buf,
styles: &v.styles,
selected: v.selected,
current: Some(v.current),
rename_active: v.rename_active,
rename_buf: v.rename_buf,
on_new: Message::TextStyleDialogNew,
on_copy: Message::TextStyleDialogCopy,
on_delete: Message::TextStyleDialogDelete,
on_select: Message::TextStyleDialogSelect,
on_set_current: Message::TextStyleDialogSetCurrent,
on_apply: Message::TextStyleApply,
editor: editor.into(),
read_only: v.read_only,
editor,
})
}