Revision: 16200
          http://sourceforge.net/p/skim-app/code/16200
Author:   hofman
Date:     2026-05-02 17:44:29 +0000 (Sat, 02 May 2026)
Log Message:
-----------
Display find results wrapping possibly on mutliple lines, with a max of 5 
lines, with variable height rows

Modified Paths:
--------------
    trunk/LeftSideView.xib
    trunk/NSParagraphStyle_SKExtensions.h
    trunk/NSParagraphStyle_SKExtensions.m
    trunk/PDFSelection_SKExtensions.h
    trunk/PDFSelection_SKExtensions.m
    trunk/SKMainWindowController.h
    trunk/SKMainWindowController.m
    trunk/SKMainWindowController_UI.m
    trunk/SKTableView.h
    trunk/SKTableView.m

Modified: trunk/LeftSideView.xib
===================================================================
--- trunk/LeftSideView.xib      2026-05-01 20:54:31 UTC (rev 16199)
+++ trunk/LeftSideView.xib      2026-05-02 17:44:29 UTC (rev 16200)
@@ -394,9 +394,10 @@
                                             </textField>
                                         </subviews>
                                         <constraints>
+                                            <constraint firstItem="5CV-AT-Wi3" 
firstAttribute="top" secondItem="rTN-Wm-aea" secondAttribute="top" 
priority="260" constant="3" id="17P-N4-VSY"/>
                                             <constraint firstItem="5CV-AT-Wi3" 
firstAttribute="leading" secondItem="rTN-Wm-aea" secondAttribute="leading" 
constant="2" id="1af-hZ-zDh"/>
                                             <constraint 
firstAttribute="trailing" secondItem="5CV-AT-Wi3" secondAttribute="trailing" 
constant="2" id="SHs-Ad-Ow7"/>
-                                            <constraint firstItem="5CV-AT-Wi3" 
firstAttribute="centerY" secondItem="rTN-Wm-aea" secondAttribute="centerY" 
id="vbK-eq-WEx"/>
+                                            <constraint firstItem="5CV-AT-Wi3" 
firstAttribute="centerY" relation="lessThanOrEqual" secondItem="rTN-Wm-aea" 
secondAttribute="centerY" id="vbK-eq-WEx"/>
                                         </constraints>
                                         <connections>
                                             <outlet property="textField" 
destination="5CV-AT-Wi3" id="phD-a5-G8O"/>
@@ -409,7 +410,7 @@
                                     <color key="textColor" 
name="headerTextColor" catalog="System" colorSpace="catalog"/>
                                     <color key="backgroundColor" 
white="0.33333298560000002" alpha="1" colorSpace="calibratedWhite"/>
                                 </tableHeaderCell>
-                                <textFieldCell key="dataCell" 
lineBreakMode="truncatingTail" alignment="left" id="115">
+                                <textFieldCell key="dataCell" 
truncatesLastVisibleLine="YES" sendsActionOnEndEditing="YES" alignment="left" 
id="115">
                                     <font key="font" metaFont="cellTitle"/>
                                     <color key="textColor" name="labelColor" 
catalog="System" colorSpace="catalog"/>
                                     <color key="backgroundColor" 
name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
@@ -420,9 +421,9 @@
                                         <rect key="frame" x="61" y="0.0" 
width="127" height="17"/>
                                         <autoresizingMask 
key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                                         <subviews>
-                                            <textField 
verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" 
allowsExpansionToolTips="YES" translatesAutoresizingMaskIntoConstraints="NO" 
id="EK0-Iy-KhJ">
-                                                <rect key="frame" x="0.0" 
y="1" width="127" height="15"/>
-                                                <textFieldCell key="cell" 
lineBreakMode="truncatingTail" sendsActionOnEndEditing="YES" alignment="left" 
id="t89-Nc-Fkj">
+                                            <textField 
verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" 
verticalCompressionResistancePriority="250" allowsExpansionToolTips="YES" 
translatesAutoresizingMaskIntoConstraints="NO" id="EK0-Iy-KhJ">
+                                                <rect key="frame" x="0.0" 
y="3" width="127" height="11"/>
+                                                <textFieldCell key="cell" 
truncatesLastVisibleLine="YES" sendsActionOnEndEditing="YES" alignment="left" 
id="t89-Nc-Fkj">
                                                     <font key="font" 
metaFont="cellTitle"/>
                                                     <color key="textColor" 
name="labelColor" catalog="System" colorSpace="catalog"/>
                                                     <color 
key="backgroundColor" name="textBackgroundColor" catalog="System" 
colorSpace="catalog"/>
@@ -433,8 +434,9 @@
                                             </textField>
                                         </subviews>
                                         <constraints>
-                                            <constraint firstItem="EK0-Iy-KhJ" 
firstAttribute="centerY" secondItem="yHY-cQ-hrW" secondAttribute="centerY" 
id="I0A-CW-rEo"/>
-                                            <constraint 
firstAttribute="trailing" secondItem="EK0-Iy-KhJ" secondAttribute="trailing" 
priority="251" constant="2" id="Ihy-Fe-pIN"/>
+                                            <constraint 
firstAttribute="trailing" secondItem="EK0-Iy-KhJ" secondAttribute="trailing" 
constant="2" id="Ihy-Fe-pIN"/>
+                                            <constraint firstItem="EK0-Iy-KhJ" 
firstAttribute="top" secondItem="yHY-cQ-hrW" secondAttribute="top" constant="3" 
id="TmG-Ui-8dT"/>
+                                            <constraint 
firstAttribute="bottom" relation="greaterThanOrEqual" secondItem="EK0-Iy-KhJ" 
secondAttribute="bottom" constant="3" id="Vqb-Ta-cSY"/>
                                             <constraint firstItem="EK0-Iy-KhJ" 
firstAttribute="leading" secondItem="yHY-cQ-hrW" secondAttribute="leading" 
constant="2" id="lWu-vh-s2s"/>
                                         </constraints>
                                         <connections>
@@ -449,7 +451,7 @@
                                                 <rect key="frame" x="0.0" 
y="0.0" width="127" height="17"/>
                                             </visualEffectView>
                                             <textField 
verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" 
allowsExpansionToolTips="YES" translatesAutoresizingMaskIntoConstraints="NO" 
id="6Fy-Cz-Uit">
-                                                <rect key="frame" x="0.0" 
y="1" width="127" height="15"/>
+                                                <rect key="frame" x="1" y="1" 
width="125" height="15"/>
                                                 <textFieldCell key="cell" 
lineBreakMode="truncatingTail" sendsActionOnEndEditing="YES" alignment="center" 
id="W4J-nI-eOk">
                                                     <font key="font" 
metaFont="cellTitle"/>
                                                     <color key="textColor" 
name="labelColor" catalog="System" colorSpace="catalog"/>
@@ -465,9 +467,9 @@
                                             <constraint 
firstAttribute="trailing" secondItem="JPg-TA-CTy" secondAttribute="trailing" 
id="3ix-Qp-JTR"/>
                                             <constraint firstItem="JPg-TA-CTy" 
firstAttribute="leading" secondItem="J7W-Ii-xfs" secondAttribute="leading" 
id="7mF-oe-xcQ"/>
                                             <constraint firstItem="JPg-TA-CTy" 
firstAttribute="top" secondItem="J7W-Ii-xfs" secondAttribute="top" 
id="HXm-ID-lvc"/>
-                                            <constraint firstItem="6Fy-Cz-Uit" 
firstAttribute="leading" secondItem="J7W-Ii-xfs" secondAttribute="leading" 
constant="2" id="Ov9-R3-f5H"/>
+                                            <constraint firstItem="6Fy-Cz-Uit" 
firstAttribute="leading" secondItem="J7W-Ii-xfs" secondAttribute="leading" 
constant="3" id="Ov9-R3-f5H"/>
                                             <constraint 
firstAttribute="bottom" secondItem="JPg-TA-CTy" secondAttribute="bottom" 
id="P9C-56-Pl1"/>
-                                            <constraint 
firstAttribute="trailing" secondItem="6Fy-Cz-Uit" secondAttribute="trailing" 
priority="251" constant="2" id="awE-wD-FnJ"/>
+                                            <constraint 
firstAttribute="trailing" secondItem="6Fy-Cz-Uit" secondAttribute="trailing" 
priority="251" constant="3" id="awE-wD-FnJ"/>
                                         </constraints>
                                         <connections>
                                             <outlet property="textField" 
destination="6Fy-Cz-Uit" id="dNo-ri-DUe"/>

Modified: trunk/NSParagraphStyle_SKExtensions.h
===================================================================
--- trunk/NSParagraphStyle_SKExtensions.h       2026-05-01 20:54:31 UTC (rev 
16199)
+++ trunk/NSParagraphStyle_SKExtensions.h       2026-05-02 17:44:29 UTC (rev 
16200)
@@ -43,6 +43,7 @@
 @interface NSParagraphStyle (SKExtensions)
 @property (class, nonatomic, readonly) NSParagraphStyle 
*defaultClippingParagraphStyle;
 @property (class, nonatomic, readonly) NSParagraphStyle 
*defaultTruncatingTailParagraphStyle;
+@property (class, nonatomic, readonly) NSParagraphStyle 
*defaultWrappingParagraphStyle;
 @end
 
 NS_ASSUME_NONNULL_END

Modified: trunk/NSParagraphStyle_SKExtensions.m
===================================================================
--- trunk/NSParagraphStyle_SKExtensions.m       2026-05-01 20:54:31 UTC (rev 
16199)
+++ trunk/NSParagraphStyle_SKExtensions.m       2026-05-02 17:44:29 UTC (rev 
16200)
@@ -61,4 +61,16 @@
     return defaultTruncatingTailParagraphStyle;
 }
 
++ (NSParagraphStyle *)defaultWrappingParagraphStyle {
+    static NSParagraphStyle *defaultWrappingParagraphStyle = nil;
+    if (defaultWrappingParagraphStyle == nil) {
+        NSMutableParagraphStyle *tmpParagraphStyle = [[NSParagraphStyle 
defaultParagraphStyle] mutableCopy];
+        [tmpParagraphStyle setLineBreakMode:NSLineBreakByWordWrapping];
+        if (@available(macOS 11.0, *))
+            [tmpParagraphStyle 
setLineBreakStrategy:NSLineBreakStrategyStandard];
+        defaultWrappingParagraphStyle = [tmpParagraphStyle copy];
+    }
+    return defaultWrappingParagraphStyle;
+}
+
 @end

Modified: trunk/PDFSelection_SKExtensions.h
===================================================================
--- trunk/PDFSelection_SKExtensions.h   2026-05-01 20:54:31 UTC (rev 16199)
+++ trunk/PDFSelection_SKExtensions.h   2026-05-02 17:44:29 UTC (rev 16200)
@@ -49,6 +49,8 @@
 @property (nonatomic, nullable, readonly) NSString *cleanedString;
 @property (nonatomic, nullable, readonly) NSAttributedString *contextString;
 
+- (void)invalidateContextString;
+
 @property (nonatomic, nullable, readonly) PDFDestination *destination;
 
 - (NSUInteger)safeIndexOfFirstCharacterOnPage:(PDFPage *)page;

Modified: trunk/PDFSelection_SKExtensions.m
===================================================================
--- trunk/PDFSelection_SKExtensions.m   2026-05-01 20:54:31 UTC (rev 16199)
+++ trunk/PDFSelection_SKExtensions.m   2026-05-02 17:44:29 UTC (rev 16200)
@@ -45,6 +45,7 @@
 #import "NSPointerArray_SKExtensions.h"
 #import "NSColor_SKExtensions.h"
 #import "NSCharacterSet_SKExtensions.h"
+#import <objc/objc-runtime.h>
 
 #define SKIncludeNewlinesFromEnclosedTextKey 
@"SKIncludeNewlinesFromEnclosedText"
 
@@ -52,6 +53,8 @@
 #define HYPHEN_CHARACTER (unichar)0x002D
 #define SOFT_HYPHEN_CHARACTER (unichar)0x00AD
 
+static char SKContextStringKey;
+
 @interface NSTextStorage (SKNSSubTextStoragePrivateDeclarations)
 - (NSRange)range;
 @end
@@ -115,7 +118,7 @@
     return [self compactedCleanedString];
 }
 
-- (NSAttributedString *)contextString {
+- (NSAttributedString *)_contextString {
        NSMutableAttributedString *attributedSample;
     NSString *searchString = [self compactedCleanedString] ?: @"";
     PDFSelection *extendedSelection;
@@ -124,7 +127,7 @@
        NSString *ellipse = [NSString stringWithFormat:@"%C", 
ELLIPSIS_CHARACTER];
        NSRange foundRange;
     CGFloat fontSize = [[NSUserDefaults standardUserDefaults] 
doubleForKey:SKTableFontSizeKey] - 2.0;
-    NSDictionary *attributes = [[NSDictionary alloc] 
initWithObjectsAndKeys:[NSFont systemFontOfSize:fontSize], NSFontAttributeName, 
[NSParagraphStyle defaultTruncatingTailParagraphStyle], 
NSParagraphStyleAttributeName, nil];
+    NSDictionary *attributes = [[NSDictionary alloc] 
initWithObjectsAndKeys:[NSFont systemFontOfSize:fontSize], NSFontAttributeName, 
[NSParagraphStyle defaultWrappingParagraphStyle], 
NSParagraphStyleAttributeName, nil];
     PDFPage *page = [self safeFirstPage];
     NSString *pageString = [page string];
     NSUInteger length = [pageString length];
@@ -173,6 +176,21 @@
        return attributedSample;
 }
 
+- (NSAttributedString *)contextString {
+    NSAttributedString *contextString = objc_getAssociatedObject(self, 
&SKContextStringKey);
+    if (contextString == nil) {
+        contextString = [self _contextString];
+        objc_setAssociatedObject(self, &SKContextStringKey, contextString, 
OBJC_ASSOCIATION_RETAIN_NONATOMIC);
+    }
+    return contextString;
+}
+
+- (void)invalidateContextString {
+    [self willChangeValueForKey:@"contextString"];
+    objc_setAssociatedObject(self, &SKContextStringKey, nil, 
OBJC_ASSOCIATION_RETAIN_NONATOMIC);
+    [self didChangeValueForKey:@"contextString"];
+}
+
 - (PDFDestination *)destination {
     PDFDestination *destination = nil;
     PDFPage *page = [self safeFirstPage];

Modified: trunk/SKMainWindowController.h
===================================================================
--- trunk/SKMainWindowController.h      2026-05-01 20:54:31 UTC (rev 16199)
+++ trunk/SKMainWindowController.h      2026-05-02 17:44:29 UTC (rev 16200)
@@ -194,6 +194,7 @@
         unsigned int needsCleanup:1;
         unsigned int thumbnailsNeedUpdateAfterPresentaton:1;
         unsigned int thumbnailsUpdatedDuringPresentaton:1;
+        unsigned int findRowHeightsNeedUpdate:1;
     } mwcFlags;
 }
 

Modified: trunk/SKMainWindowController.m
===================================================================
--- trunk/SKMainWindowController.m      2026-05-01 20:54:31 UTC (rev 16199)
+++ trunk/SKMainWindowController.m      2026-05-02 17:44:29 UTC (rev 16200)
@@ -2673,10 +2673,10 @@
             [secondaryPdfView setNeedsDisplay:YES];
             [self allThumbnailsNeedUpdate];
         } else if ([keyPath isEqualToString:SKTableFontSizeKey]) {
+            if ([searchResults count] > 1)
+                [[searchResults subarrayWithRange:NSMakeRange(1, 
[searchResults count] - 1)] 
makeObjectsPerformSelector:@selector(invalidateContextString)];
             [self updateTableFont];
             [self updatePageColumnWidthForTableViews:[NSArray 
arrayWithObjects:leftSideController.tocOutlineView, 
rightSideController.noteOutlineView, leftSideController.findTableView, 
leftSideController.groupedFindTableView, nil]];
-            if ([searchResults count] > 1)
-                [leftSideController.findTableView 
reloadDataForRowIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(1, 
[searchResults count] - 1)] columnIndexes:[NSIndexSet 
indexSetWithIndexesInRange:NSMakeRange(0, 2)]];
         }
         
     } else if (context == &SKMainWindowAppObservationContext) {

Modified: trunk/SKMainWindowController_UI.m
===================================================================
--- trunk/SKMainWindowController_UI.m   2026-05-01 20:54:31 UTC (rev 16199)
+++ trunk/SKMainWindowController_UI.m   2026-05-02 17:44:29 UTC (rev 16200)
@@ -100,6 +100,7 @@
 #define AUTHOR_COLUMNID     @"author"
 #define DATE_COLUMNID       @"date"
 #define IMAGE_COLUMNID      @"image"
+#define RESULTS_COLUMNID    @"results"
 #define RELEVANCE_COLUMNID  @"relevance"
 
 #define HEADER_IDENTIFIER @"header"
@@ -115,8 +116,9 @@
 #define DEFAULT_TEXT_ROW_HEIGHT 85.0
 #define DEFAULT_MARKUP_ROW_HEIGHT 50.0
 
-#define EXTRA_FIND_ROW_WIDTH 4.0
+#define EXTRA_FIND_ROW_HEIGHT 6.0
 #define FIND_HEADER_ROW_HEIGHT 16.0
+#define MAX_FIND_LINES 5
 
 @interface SKMainWindowController (SKPrivateMain)
 
@@ -531,17 +533,33 @@
     }
     return NO;
 }
-
+   
 - (void)tableViewColumnDidResize:(NSNotification *)aNotification {
-    if ([[[[aNotification userInfo] objectForKey:@"NSTableColumn"] identifier] 
isEqualToString:IMAGE_COLUMNID]) {
-        NSTableView *tv = [aNotification object];
+    NSString *tcID = [[[aNotification userInfo] objectForKey:@"NSTableColumn"] 
identifier];
+    if ([tcID isEqualToString:IMAGE_COLUMNID]) {
+        SKTableView *tv = [aNotification object];
         if ([tv isEqual:leftSideController.thumbnailTableView] || [tv 
isEqual:rightSideController.snapshotTableView]) {
-            [self 
performSelectorOnce:@selector(invalidateRowHeightsForTableView:) withObject:tv 
afterDelay:0.0];
-            [(SKTableView *)tv noteHeightOfRowsChangedAnimating:NO];
+            [tv noteHeightOfRowsChangedAnimating:NO];
         }
+    } else if ([tcID isEqualToString:RESULTS_COLUMNID]) {
+        SKTableView *tv = [aNotification object];
+        if ([tv isEqual:leftSideController.findTableView]) {
+            if ([tv inLiveResize])
+                mwcFlags.findRowHeightsNeedUpdate = YES;
+            else
+                [tv noteHeightOfRowsChangedAnimating:NO];
+        }
     }
 }
 
+- (void)tableViewDidEndLiveResize:(NSTableView *)tv {
+    if ([tv isEqual:leftSideController.findTableView] && 
mwcFlags.findRowHeightsNeedUpdate) {
+        if ([searchResults count] > 1)
+            [leftSideController.findTableView 
noteHeightOfRowsWithIndexesChanged:[NSIndexSet 
indexSetWithIndexesInRange:NSMakeRange(1, [searchResults count] - 1)]];
+        mwcFlags.findRowHeightsNeedUpdate = NO;
+    }
+}
+
 - (CGFloat)tableView:(NSTableView *)tv heightOfRow:(NSInteger)row {
     NSSize thumbSize = NSZeroSize;
     CGFloat thumbHeight = 0.0, rowHeight = [tv rowHeight];
@@ -552,7 +570,15 @@
         thumbSize = [[(SKSnapshotWindowController 
*)[[rightSideController.snapshotArrayController arrangedObjects] 
objectAtIndex:row] thumbnail] size];
         thumbHeight = snapshotThumbnailSize;
     } else if ([tv isEqual:leftSideController.findTableView]) {
-        return row == 0 ? FIND_HEADER_ROW_HEIGHT : rowHeight + 
EXTRA_FIND_ROW_WIDTH;
+        if (row == 0)
+            return FIND_HEADER_ROW_HEIGHT;
+        NSTableColumn *tc = [tv tableColumnWithIdentifier:RESULTS_COLUMNID];
+        NSTextFieldCell *cell = [tc dataCell];
+        [cell setObjectValue:[[[leftSideController.findArrayController 
arrangedObjects] objectAtIndex:row] contextString]];
+        CGFloat height = [cell cellSizeForBounds:NSMakeRect(0.0, 0.0, [tc 
width], CGFLOAT_MAX)].height;
+        if (height > MAX_FIND_LINES * (rowHeight - 3.0))
+            height = fmin(height, MAX_FIND_LINES * [cell 
cellSizeForBounds:NSMakeRect(0.0, 0.0, CGFLOAT_MAX, CGFLOAT_MAX)].height);
+        return fmax(rowHeight, height + EXTRA_FIND_ROW_HEIGHT);
     } else if ([tv isEqual:leftSideController.groupedFindTableView]) {
         return row == 0 ? FIND_HEADER_ROW_HEIGHT : rowHeight;
     } else {

Modified: trunk/SKTableView.h
===================================================================
--- trunk/SKTableView.h 2026-05-01 20:54:31 UTC (rev 16199)
+++ trunk/SKTableView.h 2026-05-02 17:44:29 UTC (rev 16200)
@@ -67,6 +67,8 @@
 - (void)tableView:(NSTableView *)aTableView 
typeSelectHelperDidFailToFindMatchForSearchString:(NSString *)searchString;
 - (void)tableView:(NSTableView *)aTableView 
typeSelectHelperUpdateSearchString:(NSString *)searchString;
 
+- (void)tableViewDidEndLiveResize:(NSTableView *)aTableView;
+
 @end
 
 typedef NS_ENUM(NSInteger, SKTableImageToolTipLayout) {

Modified: trunk/SKTableView.m
===================================================================
--- trunk/SKTableView.m 2026-05-01 20:54:31 UTC (rev 16199)
+++ trunk/SKTableView.m 2026-05-02 17:44:29 UTC (rev 16200)
@@ -274,11 +274,18 @@
         [self enumerateAvailableRowViewsUsingBlock:^(NSTableRowView *rowView, 
NSInteger row){ [rowView setEmphasized:NO]; }];
 }
 
+- (void)viewDidEndLiveResize {
+    [super viewDidEndLiveResize];
+    if ([[self delegate] 
respondsToSelector:@selector(tableViewDidEndLiveResize:)])
+        [[self delegate] tableViewDidEndLiveResize:self];
+}
+
 - (void)draggingSession:(NSDraggingSession *)session 
endedAtPoint:(NSPoint)screenPoint operation:(NSDragOperation)operation {
     if ([[SKTableView superclass] instancesRespondToSelector:_cmd])
         [super draggingSession:session endedAtPoint:screenPoint 
operation:operation];
     [[session draggingPasteboard] clearContents];
 }
+
 #pragma mark Tracking
 
 - (BOOL)hasRowImageToolTips {

This was sent by the SourceForge.net collaborative development platform, the 
world's largest Open Source development site.



_______________________________________________
Skim-app-commit mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/skim-app-commit

Reply via email to