Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .envrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# -*- mode: sh -*-
PATH_add scripts

# Set all Locale to en_US.UTF-8
export LANG="en_US.UTF-8"
export LANGUAGE="en_US.UTF-8"

# Avoid "direnv: PS1 cannot be exported" error
unset PS1
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@
.DS_Store
project.xcworkspace/
xcuserdata/
/.DerivedData

12 changes: 6 additions & 6 deletions Base.lproj/PrefsWin.xib
Original file line number Diff line number Diff line change
Expand Up @@ -18,20 +18,20 @@
<window title="Preferences" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" visibleAtLaunch="NO" animationBehavior="default" id="394" userLabel="Prefs Panel" customClass="NSPanel">
<windowStyleMask key="styleMask" titled="YES" closable="YES"/>
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
<rect key="contentRect" x="121" y="439" width="493" height="476"/>
<rect key="contentRect" x="121" y="439" width="650" height="476"/>
<rect key="screenRect" x="0.0" y="0.0" width="2560" height="1415"/>
<value key="minSize" type="size" width="213" height="107"/>
<view key="contentView" id="395">
<rect key="frame" x="0.0" y="0.0" width="493" height="476"/>
<rect key="frame" x="0.0" y="0.0" width="650" height="476"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<tabView drawsBackground="NO" translatesAutoresizingMaskIntoConstraints="NO" id="587">
<rect key="frame" x="-7" y="-10" width="507" height="492"/>
<rect key="frame" x="-7" y="-10" width="664" height="492"/>
<font key="font" metaFont="system"/>
<tabViewItems>
<tabViewItem label="General" identifier="general" id="588">
<view key="view" id="590">
<rect key="frame" x="10" y="33" width="487" height="448"/>
<rect key="frame" x="10" y="33" width="644" height="448"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<textField focusRingType="none" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="398">
Expand Down Expand Up @@ -354,7 +354,7 @@
</tabViewItem>
<tabViewItem label="Slideshow" identifier="slideshow" id="589">
<view key="view" id="591">
<rect key="frame" x="10" y="33" width="487" height="446"/>
<rect key="frame" x="10" y="33" width="644" height="446"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<textField focusRingType="none" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="595">
Expand Down Expand Up @@ -625,7 +625,7 @@
</tabViewItem>
<tabViewItem label="File Types" identifier="multipledocs" id="lds-PP-VGR">
<view key="view" id="6cs-hl-yOr">
<rect key="frame" x="10" y="33" width="487" height="446"/>
<rect key="frame" x="10" y="33" width="644" height="446"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<scrollView autohidesScrollers="YES" horizontalLineScroll="19" horizontalPageScroll="10" verticalLineScroll="19" verticalPageScroll="10" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="q81-3A-Deg">
Expand Down
74 changes: 74 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Project Overview

Phoenix Slides (originally codenamed "creevey") is a fast macOS image browser and slideshow application written in Objective-C. The application has been in development since 2005 and uses Cocoa/AppKit frameworks.

## Build Commands

```bash
# Build application
scripts/build # debug
scripts/build d # debug
scripts/build r # release

# Run the
scripts/run # debug
scripts/run d # debug
scripts/run r # release

# Open xcode
scripts/ide
```

## Architecture

### Core Components

**Main Window & Browser**
- `CreeveyMainWindowController`: Central controller managing the main window, containing both the directory browser and thumbnail grid
- `DYCreeveyBrowser`: Custom NSBrowser subclass for directory navigation with typing support and drag/drop
- `DirBrowserDelegate`: Handles directory browser logic and path management

**Image Display & Caching**
- `DYImageView`: Custom view handling image display with zoom, rotation, and flip capabilities
- `DYImageCache`: Manages thumbnail caching for performance
- `DYWrappingMatrix`: Custom matrix view for thumbnail grid display

**Slideshow**
- `SlideshowWindow`: Full-screen or windowed slideshow presentation
- Supports random, loop, and auto-advance modes

**File Management**
- `DYFileWatcher`: Monitors file system changes using VDKQueue
- `DYRandomizableArray`: Array with randomization support for slideshow ordering

### External Dependencies

The project includes embedded libraries:
- `libjpeg`: For JPEG manipulation
- `exiftags`: For EXIF metadata extraction
- `DYjpegtran`: Wrapper for lossless JPEG transformations

### Key Features Implementation

- **Fast thumbnailing**: Uses embedded EXIF/JPEG previews when available, falls back to macOS Image I/O
- **EXIF sorting**: Custom comparator implementation in `CreeveyMainWindowController`
- **Animated GIF/WebP**: Handled through CGImageSource in `DYImageView`

## Interface Files

- `Base.lproj/CreeveyWindow.xib`: Main window layout
- `Base.lproj/MainMenu.xib`: Application menu
- `Base.lproj/PrefsWin.xib`: Preferences window
- `Base.lproj/DYJpegtranPanel.xib`: JPEG transformation panel
- `Base.lproj/ThumbnailContextMenu.xib`: Right-click menu for thumbnails

## Development Notes

- The project requires the latest version of Xcode to build from the master branch
- Code uses modern Objective-C with ARC (Automatic Reference Counting)
- The application supports macOS 10.14+ features when available
- Localization support exists but translations are managed through Google Translate
4 changes: 4 additions & 0 deletions CreeveyController.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,10 @@ NSDirectoryEnumerator *CreeveyEnumerator(NSString *path, BOOL recurseSubfolders)
- (IBAction)applySlideshowPrefs:(id)sender;
- (IBAction)slideshowDefaultsChanged:(id)sender;
- (IBAction)chooseDefaultSlideshowMode:(id)sender;
- (IBAction)folderBrowserFontSizeChanged:(id)sender;
- (IBAction)thumbnailLabelFontSizeChanged:(id)sender;
- (IBAction)resetFolderBrowserFontSize:(id)sender;
- (IBAction)resetThumbnailLabelFontSize:(id)sender;

// info window
- (IBAction)openGetInfoPanel:(id)sender;
Expand Down
83 changes: 83 additions & 0 deletions CreeveyController.m
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#import "DYJpegtranPanel.h"
#import "DYVersChecker.h"
#import "DYExiftags.h"
#import "UKPrefsPanel.h"

// The thumbs cache should always store images using the resolved filename as the key.
// This prevents duplication somewhat, but it means when you look things up
Expand Down Expand Up @@ -158,6 +159,8 @@ +(void)initialize
@"startupSlideshowSuppressNewWindows":@NO,
@"slideshowDefaultMode":@0,
@"MainWindowSplitViewTopHeight":@151.0f,
@"folderBrowserFontSize":@0.0f, // 0 means use default (NSFont.systemFontSize)
@"thumbnailLabelFontSize":@0.0f, // 0 means use automatic sizing
}];

// migrate old RBSplitView pref
Expand Down Expand Up @@ -1078,6 +1081,86 @@ - (IBAction)chooseDefaultSlideshowMode:(id)sender {
[self updateAlternateSlideshowMenuItem];
}

- (IBAction)folderBrowserFontSizeChanged:(id)sender {
CGFloat fontSize = [sender floatValue];
[NSUserDefaults.standardUserDefaults setFloat:fontSize forKey:@"folderBrowserFontSize"];
// Update the label in preferences
NSTextField *label = [prefsWin.contentView viewWithTag:1001];
if (label) {
label.stringValue = [NSString stringWithFormat:@"%.0f pt", fontSize];
}
// Notify all windows to update their folder browser font
[creeveyWindows makeObjectsPerformSelector:@selector(updateFolderBrowserFont)];
}

- (IBAction)thumbnailLabelFontSizeChanged:(id)sender {
CGFloat fontSize = [sender floatValue];
[NSUserDefaults.standardUserDefaults setFloat:fontSize forKey:@"thumbnailLabelFontSize"];
// Update the label in preferences
NSTextField *label = [prefsWin.contentView viewWithTag:1002];
if (label) {
if (fontSize <= 0) {
label.stringValue = NSLocalizedString(@"Auto", @"");
} else {
label.stringValue = [NSString stringWithFormat:@"%.0f pt", fontSize];
}
}
// Notify all windows to update their thumbnail label font
[creeveyWindows makeObjectsPerformSelector:@selector(updateThumbnailLabelFont)];
}

- (IBAction)resetFolderBrowserFontSize:(id)sender {
[NSUserDefaults.standardUserDefaults setFloat:0.0f forKey:@"folderBrowserFontSize"];
// Update the slider and label
for (NSView *view in prefsWin.contentView.subviews) {
if ([view isKindOfClass:[NSTabView class]]) {
NSTabView *tabView = (NSTabView *)view;
for (NSTabViewItem *item in tabView.tabViewItems) {
if ([item.identifier isEqualToString:@"fonts"]) {
for (NSView *subview in item.view.subviews) {
if ([subview isKindOfClass:[NSSlider class]]) {
NSSlider *slider = (NSSlider *)subview;
if (slider.action == @selector(folderBrowserFontSizeChanged:)) {
slider.floatValue = NSFont.systemFontSize;
[self folderBrowserFontSizeChanged:slider];
break;
}
}
}
}
}
}
}
// Notify all windows to update their folder browser font
[creeveyWindows makeObjectsPerformSelector:@selector(updateFolderBrowserFont)];
}

- (IBAction)resetThumbnailLabelFontSize:(id)sender {
[NSUserDefaults.standardUserDefaults setFloat:0.0f forKey:@"thumbnailLabelFontSize"];
// Update the slider and label
for (NSView *view in prefsWin.contentView.subviews) {
if ([view isKindOfClass:[NSTabView class]]) {
NSTabView *tabView = (NSTabView *)view;
for (NSTabViewItem *item in tabView.tabViewItems) {
if ([item.identifier isEqualToString:@"fonts"]) {
for (NSView *subview in item.view.subviews) {
if ([subview isKindOfClass:[NSSlider class]]) {
NSSlider *slider = (NSSlider *)subview;
if (slider.action == @selector(thumbnailLabelFontSizeChanged:)) {
slider.floatValue = 0.0;
[self thumbnailLabelFontSizeChanged:slider];
break;
}
}
}
}
}
}
}
// Notify all windows to update their thumbnail label font
[creeveyWindows makeObjectsPerformSelector:@selector(updateThumbnailLabelFont)];
}

- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)c
Expand Down
2 changes: 2 additions & 0 deletions CreeveyMainWindowController.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@
- (void)fileWasDeleted:(NSString *)s;
- (void)filesWereUndeleted:(NSArray *)a;
- (void)updateExifInfo;
- (void)updateFolderBrowserFont;
- (void)updateThumbnailLabelFont;

@end

Expand Down
26 changes: 26 additions & 0 deletions CreeveyMainWindowController.m
Original file line number Diff line number Diff line change
Expand Up @@ -922,6 +922,32 @@ - (void)updateExifInfo {
[self updateExifInfo:nil];
}

- (void)updateFolderBrowserFont {
// Update the folder browser font size
CGFloat fontSize = [NSUserDefaults.standardUserDefaults floatForKey:@"folderBrowserFontSize"];
if (fontSize <= 0) fontSize = NSFont.systemFontSize;

// Save the current path
NSString *currentPath = dirBrowser.path;

// Update the cell prototype font
NSFont *font = [NSFont systemFontOfSize:fontSize];
[dirBrowser.cellPrototype setFont:font];

// Reload the browser to apply the new font
[dirBrowser loadColumnZero];

// Restore the path if needed
if (currentPath) {
[dirBrowser setPath:currentPath];
}
}

- (void)updateThumbnailLabelFont {
// Force the image matrix to redraw with new font size
[imgMatrix setNeedsDisplay:YES];
}

#pragma mark splitview delegate

- (void)splitViewDidResizeSubviews:(NSNotification *)notification
Expand Down
6 changes: 5 additions & 1 deletion DYCreeveyBrowser.m
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,11 @@ - (instancetype)initWithFrame:(NSRect)frameRect {
self.titled = NO;
self.hasHorizontalScroller = YES;
[self setCellClass:[DYBrowserCell class]];
[self.cellPrototype setFont:[NSFont systemFontOfSize:NSFont.smallSystemFontSize-1]];
// Use font size from preferences, defaulting to system font size if not set
CGFloat fontSize = [NSUserDefaults.standardUserDefaults floatForKey:@"folderBrowserFontSize"];
if (fontSize <= 0) fontSize = NSFont.systemFontSize;
NSFont *font = [NSFont systemFontOfSize:fontSize];
[self.cellPrototype setFont:font];
self.allowsEmptySelection = NO;
self.columnResizingType = NSBrowserUserColumnResizing;
self.prefersAllColumnUserResizing = NO;
Expand Down
8 changes: 7 additions & 1 deletion DYWrappingMatrix.m
Original file line number Diff line number Diff line change
Expand Up @@ -569,7 +569,13 @@ - (void)drawRect:(NSRect)rect {
NSRect textCellRect = NSMakeRect(0, 0, area_w, textHeight + _vPadding/2);
NSRect cellRect;
NSWindow *myWindow = self.window;
myTextCell.font = [NSFont systemFontOfSize:cellWidth >= 160 ? 12 : 4+cellWidth/20]; // ranges from 6 to 12: 6 + 6*(cellWidth-40)/(160-40)
// Use font size from preferences, or automatic sizing if not set
CGFloat fontSize = [NSUserDefaults.standardUserDefaults floatForKey:@"thumbnailLabelFontSize"];
if (fontSize <= 0) {
// Automatic sizing: ranges from 6 to 12 based on cell width
fontSize = cellWidth >= 160 ? 12 : 4+cellWidth/20;
}
myTextCell.font = [NSFont systemFontOfSize:fontSize];
myTextCell.textColor = bgColor.bestTextColor;
for (i=0; i<numCells; ++i) {
row = i/numCols;
Expand Down
Loading