Nachgemessen statt geraten. Das Netzwerkelement war 69 Punkte breit, meine Rechnung ergab 47 — und die anderen Module lagen konstant 16 darüber. Sechs Punkte hatte allein das Netzwerk zusätzlich. Zwei Ursachen. Die Hysterese hielt die Breite auf dem Höchstwert der letzten zwanzig Sekunden; bei einem Wert, der im Sekundentakt schwankt, ist der fast immer größer als der aktuelle. Und der Text wurde linksbündig gezeichnet, die Differenz stand also komplett rechts als Lücke. Jetzt wird die Breite für die **Gestalt** reserviert: alle Ziffern auf 9 gesetzt, das ergibt die breiteste Zeichenfolge derselben Form. Von 14 auf 37 KB/s bewegt sich damit nichts, und breiter wird es nur, wenn eine Stelle dazukommt. Gezeichnet wird mittig, damit ein Rest sich auf beide Seiten verteilt statt rechts zu stehen. Ergebnis: 69 → 57 Punkte. Die verbleibenden rund 16 Punkte je Element legt macOS selbst um jedes Statuselement; die Lücken zwischen benachbarten Elementen sind gemessen 0. Neue Menüleistenmodule starten jetzt mit „Symbol + Wert" statt „Wert" — bestehende Einstellungen bleiben, wie sie sind. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
94 lines
3.6 KiB
Swift
94 lines
3.6 KiB
Swift
import Testing
|
||
import AppKit
|
||
@testable import OnyxMenuBar
|
||
|
||
@Suite("Breite in der Menüleiste")
|
||
struct MenuBarTextTests {
|
||
|
||
@Test("Die Breite folgt dem Text und nicht einer Schätzung")
|
||
func widthFollowsText() {
|
||
// Genau das war der Fehler: eine feste Zahl je Darstellungsart, so
|
||
// großzügig, dass neben jedem Wert Platz für ein weiteres Symbol blieb.
|
||
let short = MenuBarText.itemWidth(textWidth: 20, includesSymbol: false)
|
||
let long = MenuBarText.itemWidth(textWidth: 60, includesSymbol: false)
|
||
#expect(long > short)
|
||
#expect(short == 20 + 2 * MenuBarText.sidePadding)
|
||
}
|
||
|
||
@Test("Ein Symbol daneben braucht seinen Platz")
|
||
func symbolAddsWidth() {
|
||
let without = MenuBarText.itemWidth(textWidth: 40, includesSymbol: false)
|
||
let with = MenuBarText.itemWidth(textWidth: 40, includesSymbol: true)
|
||
#expect(with - without == MenuBarText.symbolWidth + MenuBarText.innerGap)
|
||
}
|
||
|
||
@Test("Ohne Text bleibt die Mindestbreite")
|
||
func emptyKeepsMinimum() {
|
||
// Ein Element ohne Zahl zeigt ein Glyph. Schrumpfte es auf null,
|
||
// verschwände es aus der Leiste.
|
||
#expect(MenuBarText.itemWidth(textWidth: 0, includesSymbol: false)
|
||
== MenuBarText.minimumWidth)
|
||
}
|
||
|
||
@Test("Die Breite wird aufgerundet")
|
||
func roundsUp() {
|
||
// Gebrochene Breiten führen zu unscharfem Text, weil die Zeichenfolge
|
||
// dann auf einem halben Bildpunkt sitzt.
|
||
let width = MenuBarText.itemWidth(textWidth: 20.3, includesSymbol: false)
|
||
#expect(width == width.rounded())
|
||
}
|
||
|
||
@Test("Ein längerer Verweistext ergibt ein breiteres Element")
|
||
func referenceDrivesWidth() {
|
||
#expect(MenuBarText.width(for: "100 %") > MenuBarText.width(for: "9 %"))
|
||
}
|
||
|
||
@Test("Gleich lange Zahlen sind gleich breit")
|
||
func digitsAreMonospaced() {
|
||
// Ohne feste Ziffernbreite springt die Leiste bei jedem Messwert.
|
||
#expect(MenuBarText.width(of: "111") == MenuBarText.width(of: "888"))
|
||
}
|
||
}
|
||
|
||
// Eine Breite, die dem Höchstwert der letzten Messungen folgt, ist bei einem
|
||
// Wert, der ständig schwankt, fast immer zu groß: der Netzwerkdurchsatz
|
||
// wechselt im Sekundentakt, und das Element blieb dauerhaft auf der Breite
|
||
// eines vergangenen Ausschlags stehen. Die Differenz stand als Lücke daneben.
|
||
//
|
||
// Stattdessen: die Ziffern durch Neunen ersetzen. Das ergibt die breiteste
|
||
// Zeichenfolge **derselben Gestalt** — die Breite ändert sich dann nur noch,
|
||
// wenn eine Stelle dazukommt oder die Einheit wechselt.
|
||
|
||
@Suite("Breite gleicher Gestalt")
|
||
struct DigitShapeTests {
|
||
|
||
@Test("Ziffern werden zu Neunen")
|
||
func digitsBecomeNines() {
|
||
#expect(MenuBarText.widestOfSameShape("↓ 14 KB/s") == "↓ 99 KB/s")
|
||
#expect(MenuBarText.widestOfSameShape("34 %") == "99 %")
|
||
}
|
||
|
||
@Test("Alles außer Ziffern bleibt stehen")
|
||
func nonDigitsSurvive() {
|
||
#expect(MenuBarText.widestOfSameShape("↑ 2,4 MB/s") == "↑ 9,9 MB/s")
|
||
}
|
||
|
||
@Test("Gleich lange Zahlen ergeben dieselbe Gestalt")
|
||
func sameLengthIsStable() {
|
||
// Genau darum geht es: von 14 auf 37 KB/s darf sich nichts bewegen.
|
||
#expect(MenuBarText.widestOfSameShape("↓ 14 KB/s")
|
||
== MenuBarText.widestOfSameShape("↓ 37 KB/s"))
|
||
}
|
||
|
||
@Test("Eine Stelle mehr ist eine andere Gestalt")
|
||
func moreDigitsIsWider() {
|
||
#expect(MenuBarText.widestOfSameShape("↓ 999 KB/s")
|
||
!= MenuBarText.widestOfSameShape("↓ 99 KB/s"))
|
||
}
|
||
|
||
@Test("Ohne Ziffern bleibt der Text, wie er ist")
|
||
func textWithoutDigitsIsUnchanged() {
|
||
#expect(MenuBarText.widestOfSameShape("–") == "–")
|
||
}
|
||
}
|