subclass text field. for added flavor

This commit is contained in:
samhenrigold
2025-09-06 16:19:22 -04:00
parent f4ca510ade
commit 8eea875d37
3 changed files with 112 additions and 76 deletions

View File

@@ -8,14 +8,15 @@
#import "AppDelegate.h" #import "AppDelegate.h"
#import "LidAngleSensor.h" #import "LidAngleSensor.h"
#import "CreakAudioEngine.h" #import "CreakAudioEngine.h"
#import "NSLabel.h"
@interface AppDelegate () @interface AppDelegate ()
@property (strong, nonatomic) LidAngleSensor *lidSensor; @property (strong, nonatomic) LidAngleSensor *lidSensor;
@property (strong, nonatomic) CreakAudioEngine *audioEngine; @property (strong, nonatomic) CreakAudioEngine *audioEngine;
@property (strong, nonatomic) NSTextField *angleLabel; @property (strong, nonatomic) NSLabel *angleLabel;
@property (strong, nonatomic) NSTextField *statusLabel; @property (strong, nonatomic) NSLabel *statusLabel;
@property (strong, nonatomic) NSTextField *velocityLabel; @property (strong, nonatomic) NSLabel *velocityLabel;
@property (strong, nonatomic) NSTextField *audioStatusLabel; @property (strong, nonatomic) NSLabel *audioStatusLabel;
@property (strong, nonatomic) NSButton *audioToggleButton; @property (strong, nonatomic) NSButton *audioToggleButton;
@property (strong, nonatomic) NSTimer *updateTimer; @property (strong, nonatomic) NSTimer *updateTimer;
@end @end
@@ -49,7 +50,7 @@
backing:NSBackingStoreBuffered backing:NSBackingStoreBuffered
defer:NO]; defer:NO];
[self.window setTitle:@"MacBook Lid Creak Sensor"]; [self.window setTitle:@"MacBook Lid Angle Sensor"];
[self.window makeKeyAndOrderFront:nil]; [self.window makeKeyAndOrderFront:nil];
[self.window center]; [self.window center];
@@ -57,84 +58,75 @@
NSView *contentView = [[NSView alloc] initWithFrame:windowFrame]; NSView *contentView = [[NSView alloc] initWithFrame:windowFrame];
[self.window setContentView:contentView]; [self.window setContentView:contentView];
// Create title label // Create angle display label with tabular numbers (larger, light font)
NSTextField *titleLabel = [[NSTextField alloc] initWithFrame:NSMakeRect(50, 360, 350, 40)]; self.angleLabel = [[NSLabel alloc] init];
[titleLabel setStringValue:@"MacBook Lid Creak Sensor"];
[titleLabel setFont:[NSFont boldSystemFontOfSize:18]];
[titleLabel setBezeled:NO];
[titleLabel setDrawsBackground:NO];
[titleLabel setEditable:NO];
[titleLabel setSelectable:NO];
[titleLabel setAlignment:NSTextAlignmentCenter];
[contentView addSubview:titleLabel];
// Create angle display label
self.angleLabel = [[NSTextField alloc] initWithFrame:NSMakeRect(50, 280, 350, 40)];
[self.angleLabel setStringValue:@"Initializing..."]; [self.angleLabel setStringValue:@"Initializing..."];
[self.angleLabel setFont:[NSFont monospacedSystemFontOfSize:20 weight:NSFontWeightMedium]]; [self.angleLabel setFont:[NSFont monospacedDigitSystemFontOfSize:48 weight:NSFontWeightLight]];
[self.angleLabel setBezeled:NO];
[self.angleLabel setDrawsBackground:NO];
[self.angleLabel setEditable:NO];
[self.angleLabel setSelectable:NO];
[self.angleLabel setAlignment:NSTextAlignmentCenter]; [self.angleLabel setAlignment:NSTextAlignmentCenter];
[self.angleLabel setTextColor:[NSColor systemBlueColor]]; [self.angleLabel setTextColor:[NSColor systemBlueColor]];
[contentView addSubview:self.angleLabel]; [contentView addSubview:self.angleLabel];
// Create velocity display label // Create velocity display label with tabular numbers
self.velocityLabel = [[NSTextField alloc] initWithFrame:NSMakeRect(50, 240, 350, 30)]; self.velocityLabel = [[NSLabel alloc] init];
[self.velocityLabel setStringValue:@"Velocity: 0.0 deg/s"]; [self.velocityLabel setStringValue:@"Velocity: 00 deg/s"];
[self.velocityLabel setFont:[NSFont monospacedSystemFontOfSize:14 weight:NSFontWeightRegular]]; [self.velocityLabel setFont:[NSFont monospacedDigitSystemFontOfSize:14 weight:NSFontWeightRegular]];
[self.velocityLabel setBezeled:NO];
[self.velocityLabel setDrawsBackground:NO];
[self.velocityLabel setEditable:NO];
[self.velocityLabel setSelectable:NO];
[self.velocityLabel setAlignment:NSTextAlignmentCenter]; [self.velocityLabel setAlignment:NSTextAlignmentCenter];
[self.velocityLabel setTextColor:[NSColor systemGreenColor]];
[contentView addSubview:self.velocityLabel]; [contentView addSubview:self.velocityLabel];
// Create status label // Create status label
self.statusLabel = [[NSTextField alloc] initWithFrame:NSMakeRect(50, 200, 350, 30)]; self.statusLabel = [[NSLabel alloc] init];
[self.statusLabel setStringValue:@"Detecting sensor..."]; [self.statusLabel setStringValue:@"Detecting sensor..."];
[self.statusLabel setFont:[NSFont systemFontOfSize:14]]; [self.statusLabel setFont:[NSFont systemFontOfSize:14]];
[self.statusLabel setBezeled:NO];
[self.statusLabel setDrawsBackground:NO];
[self.statusLabel setEditable:NO];
[self.statusLabel setSelectable:NO];
[self.statusLabel setAlignment:NSTextAlignmentCenter]; [self.statusLabel setAlignment:NSTextAlignmentCenter];
[self.statusLabel setTextColor:[NSColor secondaryLabelColor]]; [self.statusLabel setTextColor:[NSColor secondaryLabelColor]];
[contentView addSubview:self.statusLabel]; [contentView addSubview:self.statusLabel];
// Create audio toggle button // Create audio toggle button
self.audioToggleButton = [[NSButton alloc] initWithFrame:NSMakeRect(175, 150, 100, 30)]; self.audioToggleButton = [[NSButton alloc] init];
[self.audioToggleButton setTitle:@"Start Audio"]; [self.audioToggleButton setTitle:@"Start Audio"];
[self.audioToggleButton setBezelStyle:NSBezelStyleRounded]; [self.audioToggleButton setBezelStyle:NSBezelStyleRounded];
[self.audioToggleButton setTarget:self]; [self.audioToggleButton setTarget:self];
[self.audioToggleButton setAction:@selector(toggleAudio:)]; [self.audioToggleButton setAction:@selector(toggleAudio:)];
[self.audioToggleButton setTranslatesAutoresizingMaskIntoConstraints:NO];
[contentView addSubview:self.audioToggleButton]; [contentView addSubview:self.audioToggleButton];
// Create audio status label // Create audio status label
self.audioStatusLabel = [[NSTextField alloc] initWithFrame:NSMakeRect(50, 110, 350, 30)]; self.audioStatusLabel = [[NSLabel alloc] init];
[self.audioStatusLabel setStringValue:@"Audio: Stopped"]; [self.audioStatusLabel setStringValue:@""];
[self.audioStatusLabel setFont:[NSFont systemFontOfSize:14]]; [self.audioStatusLabel setFont:[NSFont systemFontOfSize:14]];
[self.audioStatusLabel setBezeled:NO];
[self.audioStatusLabel setDrawsBackground:NO];
[self.audioStatusLabel setEditable:NO];
[self.audioStatusLabel setSelectable:NO];
[self.audioStatusLabel setAlignment:NSTextAlignmentCenter]; [self.audioStatusLabel setAlignment:NSTextAlignmentCenter];
[self.audioStatusLabel setTextColor:[NSColor secondaryLabelColor]]; [self.audioStatusLabel setTextColor:[NSColor secondaryLabelColor]];
[contentView addSubview:self.audioStatusLabel]; [contentView addSubview:self.audioStatusLabel];
// Create info label // Set up auto layout constraints
NSTextField *infoLabel = [[NSTextField alloc] initWithFrame:NSMakeRect(50, 30, 350, 60)]; [NSLayoutConstraint activateConstraints:@[
[infoLabel setStringValue:@"Real-time door creak audio responds to lid movement.\nSlow movement = louder creak, fast movement = silent."]; // Angle label (main display, now at top)
[infoLabel setFont:[NSFont systemFontOfSize:12]]; [self.angleLabel.topAnchor constraintEqualToAnchor:contentView.topAnchor constant:40],
[infoLabel setBezeled:NO]; [self.angleLabel.centerXAnchor constraintEqualToAnchor:contentView.centerXAnchor],
[infoLabel setDrawsBackground:NO]; [self.angleLabel.widthAnchor constraintLessThanOrEqualToAnchor:contentView.widthAnchor constant:-40],
[infoLabel setEditable:NO];
[infoLabel setSelectable:NO]; // Velocity label
[infoLabel setAlignment:NSTextAlignmentCenter]; [self.velocityLabel.topAnchor constraintEqualToAnchor:self.angleLabel.bottomAnchor constant:15],
[infoLabel setTextColor:[NSColor tertiaryLabelColor]]; [self.velocityLabel.centerXAnchor constraintEqualToAnchor:contentView.centerXAnchor],
[contentView addSubview:infoLabel]; [self.velocityLabel.widthAnchor constraintLessThanOrEqualToAnchor:contentView.widthAnchor constant:-40],
// Status label
[self.statusLabel.topAnchor constraintEqualToAnchor:self.velocityLabel.bottomAnchor constant:15],
[self.statusLabel.centerXAnchor constraintEqualToAnchor:contentView.centerXAnchor],
[self.statusLabel.widthAnchor constraintLessThanOrEqualToAnchor:contentView.widthAnchor constant:-40],
// Audio toggle button
[self.audioToggleButton.topAnchor constraintEqualToAnchor:self.statusLabel.bottomAnchor constant:25],
[self.audioToggleButton.centerXAnchor constraintEqualToAnchor:contentView.centerXAnchor],
[self.audioToggleButton.widthAnchor constraintEqualToConstant:120],
[self.audioToggleButton.heightAnchor constraintEqualToConstant:32],
// Audio status label
[self.audioStatusLabel.topAnchor constraintEqualToAnchor:self.audioToggleButton.bottomAnchor constant:15],
[self.audioStatusLabel.centerXAnchor constraintEqualToAnchor:contentView.centerXAnchor],
[self.audioStatusLabel.widthAnchor constraintLessThanOrEqualToAnchor:contentView.widthAnchor constant:-40],
[self.audioStatusLabel.bottomAnchor constraintLessThanOrEqualToAnchor:contentView.bottomAnchor constant:-20]
]];
} }
- (void)initializeLidSensor { - (void)initializeLidSensor {
@@ -155,10 +147,9 @@
self.audioEngine = [[CreakAudioEngine alloc] init]; self.audioEngine = [[CreakAudioEngine alloc] init];
if (self.audioEngine) { if (self.audioEngine) {
[self.audioStatusLabel setStringValue:@"Audio: Ready (stopped)"]; [self.audioStatusLabel setStringValue:@""];
[self.audioStatusLabel setTextColor:[NSColor systemOrangeColor]];
} else { } else {
[self.audioStatusLabel setStringValue:@"Audio: Failed to initialize"]; [self.audioStatusLabel setStringValue:@"Audio initialization failed"];
[self.audioStatusLabel setTextColor:[NSColor systemRedColor]]; [self.audioStatusLabel setTextColor:[NSColor systemRedColor]];
[self.audioToggleButton setEnabled:NO]; [self.audioToggleButton setEnabled:NO];
} }
@@ -172,13 +163,11 @@
if (self.audioEngine.isEngineRunning) { if (self.audioEngine.isEngineRunning) {
[self.audioEngine stopEngine]; [self.audioEngine stopEngine];
[self.audioToggleButton setTitle:@"Start Audio"]; [self.audioToggleButton setTitle:@"Start Audio"];
[self.audioStatusLabel setStringValue:@"Audio: Stopped"]; [self.audioStatusLabel setStringValue:@""];
[self.audioStatusLabel setTextColor:[NSColor systemOrangeColor]];
} else { } else {
[self.audioEngine startEngine]; [self.audioEngine startEngine];
[self.audioToggleButton setTitle:@"Stop Audio"]; [self.audioToggleButton setTitle:@"Stop Audio"];
[self.audioStatusLabel setStringValue:@"Audio: Running"]; [self.audioStatusLabel setStringValue:@""];
[self.audioStatusLabel setTextColor:[NSColor systemGreenColor]];
} }
} }
@@ -211,27 +200,22 @@
if (self.audioEngine) { if (self.audioEngine) {
[self.audioEngine updateWithLidAngle:angle]; [self.audioEngine updateWithLidAngle:angle];
// Update velocity display // Update velocity display with leading zero and whole numbers
double velocity = self.audioEngine.currentVelocity; double velocity = self.audioEngine.currentVelocity;
[self.velocityLabel setStringValue:[NSString stringWithFormat:@"Velocity: %.1f deg/s", velocity]]; int roundedVelocity = (int)round(velocity);
if (roundedVelocity < 100) {
// Color velocity based on magnitude [self.velocityLabel setStringValue:[NSString stringWithFormat:@"Velocity: %02d deg/s", roundedVelocity]];
double absVelocity = fabs(velocity);
if (absVelocity < 0.3) {
[self.velocityLabel setTextColor:[NSColor systemGrayColor]];
} else if (absVelocity < 2.0) {
[self.velocityLabel setTextColor:[NSColor systemGreenColor]];
} else if (absVelocity < 10.0) {
[self.velocityLabel setTextColor:[NSColor systemYellowColor]];
} else { } else {
[self.velocityLabel setTextColor:[NSColor systemRedColor]]; [self.velocityLabel setStringValue:[NSString stringWithFormat:@"Velocity: %d deg/s", roundedVelocity]];
} }
// Update audio status with gain/rate info if running // Keep velocity label color consistent
// Show audio parameters when running
if (self.audioEngine.isEngineRunning) { if (self.audioEngine.isEngineRunning) {
double gain = self.audioEngine.currentGain; double gain = self.audioEngine.currentGain;
double rate = self.audioEngine.currentRate; double rate = self.audioEngine.currentRate;
[self.audioStatusLabel setStringValue:[NSString stringWithFormat:@"Audio: Running (Gain: %.2f, Rate: %.2f)", gain, rate]]; [self.audioStatusLabel setStringValue:[NSString stringWithFormat:@"Gain: %.2f, Rate: %.2f", gain, rate]];
} }
} }

16
LidAngleSensor/NSLabel.h Normal file
View File

@@ -0,0 +1,16 @@
//
// NSLabel.h
// LidAngleSensor
//
// Created by Sam on 2025-01-16.
//
#import <Cocoa/Cocoa.h>
/**
* NSLabel is a simple NSTextField subclass configured as a non-editable label.
* Automatically handles common label properties like bezeled, background, and editability.
*/
@interface NSLabel : NSTextField
@end

36
LidAngleSensor/NSLabel.m Normal file
View File

@@ -0,0 +1,36 @@
//
// NSLabel.m
// LidAngleSensor
//
// Created by Sam on 2025-01-16.
//
#import "NSLabel.h"
@implementation NSLabel
- (instancetype)init {
self = [super init];
if (self) {
[self configureAsLabel];
}
return self;
}
- (instancetype)initWithFrame:(NSRect)frameRect {
self = [super initWithFrame:frameRect];
if (self) {
[self configureAsLabel];
}
return self;
}
- (void)configureAsLabel {
[self setBezeled:NO];
[self setDrawsBackground:NO];
[self setEditable:NO];
[self setSelectable:NO];
[self setTranslatesAutoresizingMaskIntoConstraints:NO];
}
@end