Add ability to draw invisibles to find panel fields

This commit is contained in:
1024jp 2015-03-05 03:21:51 +09:00
parent 2732985c09
commit dd57aeb50b
5 changed files with 227 additions and 0 deletions

View File

@ -10,6 +10,7 @@ Change Log
- Change place to create backup files (Now, backup files are always created in `~/Library/Autosave Information/`).
- Improve find panel:
- Add scroll bars to the text fields.
- Show invisible characters in text fields.
- Now, “Swap Yen and backslash keys” option is also applied to the fields in the find panel.
- Remove “Escape Character” option for regular expression search.
- Add “Cyrillic (Windows)” to the encoding list.

View File

@ -124,6 +124,7 @@
2AD5322A19779FD000A925CA /* CELineHeightTransformer.m in Sources */ = {isa = PBXBuildFile; fileRef = 2AD5322919779FD000A925CA /* CELineHeightTransformer.m */; };
2AD67C241AA7285F0078BB95 /* CEFindPanelTextView.m in Sources */ = {isa = PBXBuildFile; fileRef = 2AD67C231AA7285F0078BB95 /* CEFindPanelTextView.m */; };
2AD67C2A1AA75E7F0078BB95 /* CEFindPanelTextClipView.m in Sources */ = {isa = PBXBuildFile; fileRef = 2AD67C291AA75E7F0078BB95 /* CEFindPanelTextClipView.m */; };
2AD67C2F1AA7651B0078BB95 /* CEFindPanelLayoutManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 2AD67C2E1AA7651B0078BB95 /* CEFindPanelLayoutManager.m */; };
2AD84CAA1966314100DE49BD /* CEODBEventSender.m in Sources */ = {isa = PBXBuildFile; fileRef = 2AD84CA91966314100DE49BD /* CEODBEventSender.m */; };
2AE2E9D519D2CF00000D66A9 /* CEEncodingManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 2AE2E9D419D2CF00000D66A9 /* CEEncodingManager.m */; };
2AE356461A86D32500E29FEF /* CEClipView.m in Sources */ = {isa = PBXBuildFile; fileRef = 2AE356451A86D32500E29FEF /* CEClipView.m */; };
@ -487,6 +488,8 @@
2AD67C231AA7285F0078BB95 /* CEFindPanelTextView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CEFindPanelTextView.m; sourceTree = "<group>"; };
2AD67C281AA75E7F0078BB95 /* CEFindPanelTextClipView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CEFindPanelTextClipView.h; sourceTree = "<group>"; };
2AD67C291AA75E7F0078BB95 /* CEFindPanelTextClipView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CEFindPanelTextClipView.m; sourceTree = "<group>"; };
2AD67C2D1AA7651B0078BB95 /* CEFindPanelLayoutManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CEFindPanelLayoutManager.h; sourceTree = "<group>"; };
2AD67C2E1AA7651B0078BB95 /* CEFindPanelLayoutManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CEFindPanelLayoutManager.m; sourceTree = "<group>"; };
2AD84CA81966314100DE49BD /* CEODBEventSender.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CEODBEventSender.h; sourceTree = "<group>"; };
2AD84CA91966314100DE49BD /* CEODBEventSender.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CEODBEventSender.m; sourceTree = "<group>"; };
2AE2E9D319D2CF00000D66A9 /* CEEncodingManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CEEncodingManager.h; sourceTree = "<group>"; };
@ -1043,6 +1046,8 @@
2A009AD01A58ED1D00C3D542 /* CEFindResultViewController.m */,
2AD67C221AA7285F0078BB95 /* CEFindPanelTextView.h */,
2AD67C231AA7285F0078BB95 /* CEFindPanelTextView.m */,
2AD67C2D1AA7651B0078BB95 /* CEFindPanelLayoutManager.h */,
2AD67C2E1AA7651B0078BB95 /* CEFindPanelLayoutManager.m */,
2A009ADB1A5AB96F00C3D542 /* Views */,
);
name = "Text Finder";
@ -1437,6 +1442,7 @@
2A3A759419E77D66001DAB88 /* CEMigrationWindowController.m in Sources */,
2A51793A1A40A3B500A3F852 /* CEShortcutKeyField.m in Sources */,
2AD67C2A1AA75E7F0078BB95 /* CEFindPanelTextClipView.m in Sources */,
2AD67C2F1AA7651B0078BB95 /* CEFindPanelLayoutManager.m in Sources */,
2A7846DE18FE0C0C006BDF00 /* CETheme.m in Sources */,
2A68F93818FB04F400673440 /* CEMenuItemCell.m in Sources */,
2AB432711912AF7200835004 /* CEGlyphPopoverController.m in Sources */,

View File

@ -0,0 +1,35 @@
/*
==============================================================================
CEFindPanelLayoutManager
CotEditor
http://coteditor.com
Created on 2015-03-04 by 1024jp
encoding="UTF-8"
------------------------------------------------------------------------------
© 2015 1024jp
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place - Suite 330, Boston, MA 02111-1307, USA.
==============================================================================
*/
@import Cocoa;
@interface CEFindPanelLayoutManager : NSLayoutManager
@end

View File

@ -0,0 +1,180 @@
/*
==============================================================================
CEFindPanelLayoutManager
CotEditor
http://coteditor.com
Created on 2015-03-04 by 1024jp
encoding="UTF-8"
------------------------------------------------------------------------------
© 2015 1024jp
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place - Suite 330, Boston, MA 02111-1307, USA.
==============================================================================
*/
#import "CEFindPanelLayoutManager.h"
#import "CEUtils.h"
#import "constants.h"
// constants
static const CGFloat kLineSpacing = 4.0;
@interface CEFindPanelLayoutManager ()
@property (nonatomic, copy) NSDictionary *invisibleAttributes;
@end
#pragma mark -
@implementation CEFindPanelLayoutManager
#pragma mark Superclass Methods
// ------------------------------------------------------
/// initialize instance
- (instancetype)init
// ------------------------------------------------------
{
self = [super init];
if (self) {
[self setUsesScreenFonts:YES];
}
return self;
}
// ------------------------------------------------------
/// show invisible characters
- (void)drawGlyphsForGlyphRange:(NSRange)glyphsToShow atPoint:(NSPoint)origin
// ------------------------------------------------------
{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
BOOL showInvisibles = YES;
if (showInvisibles) {
NSTextView *textView = [self firstTextView];
NSString *completeStr = [[self textStorage] string];
NSUInteger lengthToRedraw = NSMaxRange(glyphsToShow);
NSSize size = [textView textContainerInset];
NSColor *color;
if (floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_9) {
color = [NSColor tertiaryLabelColor];
} else {
color = [NSColor colorWithCalibratedWhite:0.0 alpha:0.25];
}
NSFont *font = [[self firstTextView] font];
font = [font screenFont] ? : font;
NSFont *fullwidthFont = [[NSFont fontWithName:@"HiraKakuProN-W3" size:[font pointSize]] screenFont] ? : font;
NSDictionary *attributes = @{NSFontAttributeName: font,
NSForegroundColorAttributeName: color};
NSDictionary *fullwidthAttributes = @{NSFontAttributeName: fullwidthFont,
NSForegroundColorAttributeName: color};
BOOL showsSpace = [defaults boolForKey:CEDefaultShowInvisibleSpaceKey];
BOOL showsTab = [defaults boolForKey:CEDefaultShowInvisibleTabKey];
BOOL showsNewLine = [defaults boolForKey:CEDefaultShowInvisibleNewLineKey];
BOOL showsFullwidthSpace = [defaults boolForKey:CEDefaultShowInvisibleFullwidthSpaceKey];
BOOL showsOtherInvisibles = [defaults boolForKey:CEDefaultShowOtherInvisibleCharsKey];
unichar spaceCharacter = [CEUtils invisibleSpaceChar:[defaults integerForKey:CEDefaultInvisibleSpaceKey]];
NSAttributedString *space = [[NSAttributedString alloc] initWithString:[NSString stringWithCharacters:&spaceCharacter length:1]
attributes:attributes];
unichar tabCharacter = [CEUtils invisibleTabChar:[defaults integerForKey:CEDefaultInvisibleTabKey]];
NSAttributedString *tab = [[NSAttributedString alloc] initWithString:[NSString stringWithCharacters:&tabCharacter length:1]
attributes:attributes];
unichar newLineCharacter = [CEUtils invisibleNewLineChar:[defaults integerForKey:CEDefaultInvisibleNewLineKey]];
NSAttributedString *newLine = [[NSAttributedString alloc] initWithString:[NSString stringWithCharacters:&newLineCharacter length:1]
attributes:attributes];
unichar fullwidthSpaceCharacter = [CEUtils invisibleFullwidthSpaceChar:[defaults integerForKey:CEDefaultInvisibleFullwidthSpaceKey]];
NSAttributedString *fullwidthSpace = [[NSAttributedString alloc] initWithString:[NSString stringWithCharacters:&fullwidthSpaceCharacter length:1]
attributes:fullwidthAttributes];
for (NSUInteger glyphIndex = glyphsToShow.location; glyphIndex < lengthToRedraw; glyphIndex++) {
NSUInteger charIndex = [self characterIndexForGlyphAtIndex:glyphIndex];
unichar character = [completeStr characterAtIndex:charIndex];
if (showsSpace && ((character == ' ') || (character == 0x00A0))) {
NSPoint pointToDraw = [self pointToDrawGlyphAtIndex:glyphIndex adjust:size];
[space drawAtPoint:pointToDraw];
} else if (showsTab && (character == '\t')) {
NSPoint pointToDraw = [self pointToDrawGlyphAtIndex:glyphIndex adjust:size];
[tab drawAtPoint:pointToDraw];
} else if (showsNewLine && (character == '\n')) {
NSPoint pointToDraw = [self pointToDrawGlyphAtIndex:glyphIndex adjust:size];
[newLine drawAtPoint:pointToDraw];
} else if (showsFullwidthSpace && (character == 0x3000)) { // Fullwidth-space (JP)
NSPoint pointToDraw = [self pointToDrawGlyphAtIndex:glyphIndex adjust:size];
[fullwidthSpace drawAtPoint:pointToDraw];
} else if (showsOtherInvisibles && ([self glyphAtIndex:glyphIndex] == NSControlGlyph)) {
NSFont *replaceFont = [NSFont fontWithName:@"Lucida Grande" size:[font pointSize]];
NSGlyph replaceGlyph = [replaceFont glyphWithName:@"replacement"];
NSUInteger charLength = CFStringIsSurrogateHighCharacter(character) ? 2 : 1;
NSRange charRange = NSMakeRange(charIndex, charLength);
NSString *baseStr = [completeStr substringWithRange:charRange];
NSGlyphInfo *glyphInfo = [NSGlyphInfo glyphInfoWithGlyph:replaceGlyph forFont:replaceFont baseString:baseStr];
if (glyphInfo) {
NSDictionary *replaceAttrs = @{NSGlyphInfoAttributeName: glyphInfo,
NSFontAttributeName: replaceFont,
NSForegroundColorAttributeName: color};
NSDictionary *attrs = [[self textStorage] attributesAtIndex:charIndex effectiveRange:NULL];
if (attrs[NSGlyphInfoAttributeName] == nil) {
[[self textStorage] addAttributes:replaceAttrs range:charRange];
}
}
}
}
}
[super drawGlyphsForGlyphRange:glyphsToShow atPoint:origin];
}
#pragma mark Private Methods
//------------------------------------------------------
/// calculate point to draw invisible character
- (NSPoint)pointToDrawGlyphAtIndex:(NSUInteger)glyphIndex adjust:(NSSize)size
//------------------------------------------------------
{
NSPoint drawPoint = [self locationForGlyphAtIndex:glyphIndex];
NSRect theGlyphRect = [self lineFragmentRectForGlyphAtIndex:glyphIndex effectiveRange:NULL];
drawPoint.x += size.width;
drawPoint.y = theGlyphRect.origin.y + size.height;
return drawPoint;
}
@end

View File

@ -28,6 +28,7 @@
*/
#import "CEFindPanelTextView.h"
#import "CEFindPanelLayoutManager.h"
#import "CEFindPanelController.h"
#import "constants.h"
@ -65,6 +66,10 @@
[[self textContainer] setWidthTracksTextView:NO];
[[self textContainer] setContainerSize:NSMakeSize(CGFLOAT_MAX, CGFLOAT_MAX)];
[self setHorizontallyResizable:YES];
// set subclassed layout manager for invisible characters
CEFindPanelLayoutManager *layoutManager = [[CEFindPanelLayoutManager alloc] init];
[[self textContainer] replaceLayoutManager:layoutManager];
}
return self;
}