Skip to content

Commit 3da3d4d

Browse files
committed
Huge refactoring : now uses a custom NSScrollView subclass : SCMiniMapView
Add a show/hide menu item (under "Edit" menu)
1 parent abe581c commit 3da3d4d

File tree

8 files changed

+314
-200
lines changed

8 files changed

+314
-200
lines changed

SCXcodeMinimap.xcodeproj/project.pbxproj

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
18D2B13117244C0A0026D09F /* SCSelectionView.m in Sources */ = {isa = PBXBuildFile; fileRef = 18D2B13017244C0A0026D09F /* SCSelectionView.m */; };
1111
18FE09B61707639E00118FEB /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 18FE09B51707639E00118FEB /* Cocoa.framework */; };
1212
18FE09C9170764E400118FEB /* SCXcodeMinimap.m in Sources */ = {isa = PBXBuildFile; fileRef = 18FE09C8170764E400118FEB /* SCXcodeMinimap.m */; };
13+
B25F211C172FE208001A9E6E /* SCMiniMapView.m in Sources */ = {isa = PBXBuildFile; fileRef = B25F211B172FE208001A9E6E /* SCMiniMapView.m */; };
1314
B2A3E44A172E714F004A56C1 /* SCTextView.m in Sources */ = {isa = PBXBuildFile; fileRef = B2A3E449172E714F004A56C1 /* SCTextView.m */; };
1415
/* End PBXBuildFile section */
1516

@@ -25,6 +26,9 @@
2526
18FE09C11707639E00118FEB /* SCXcodeMinimap-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "SCXcodeMinimap-Prefix.pch"; sourceTree = "<group>"; };
2627
18FE09C7170764E400118FEB /* SCXcodeMinimap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SCXcodeMinimap.h; sourceTree = "<group>"; };
2728
18FE09C8170764E400118FEB /* SCXcodeMinimap.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SCXcodeMinimap.m; sourceTree = "<group>"; };
29+
B25F211A172FE208001A9E6E /* SCMiniMapView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SCMiniMapView.h; sourceTree = "<group>"; };
30+
B25F211B172FE208001A9E6E /* SCMiniMapView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SCMiniMapView.m; sourceTree = "<group>"; };
31+
B25F211D172FE3B3001A9E6E /* Conf.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Conf.h; sourceTree = "<group>"; };
2832
B2A3E448172E714F004A56C1 /* SCTextView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SCTextView.h; sourceTree = "<group>"; };
2933
B2A3E449172E714F004A56C1 /* SCTextView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SCTextView.m; sourceTree = "<group>"; };
3034
/* End PBXFileReference section */
@@ -80,8 +84,11 @@
8084
18FE09BB1707639E00118FEB /* SCXcodeMinimap */ = {
8185
isa = PBXGroup;
8286
children = (
87+
B25F211D172FE3B3001A9E6E /* Conf.h */,
8388
18FE09C7170764E400118FEB /* SCXcodeMinimap.h */,
8489
18FE09C8170764E400118FEB /* SCXcodeMinimap.m */,
90+
B25F211A172FE208001A9E6E /* SCMiniMapView.h */,
91+
B25F211B172FE208001A9E6E /* SCMiniMapView.m */,
8592
18D2B12F17244C0A0026D09F /* SCSelectionView.h */,
8693
18D2B13017244C0A0026D09F /* SCSelectionView.m */,
8794
B2A3E448172E714F004A56C1 /* SCTextView.h */,
@@ -164,6 +171,7 @@
164171
18FE09C9170764E400118FEB /* SCXcodeMinimap.m in Sources */,
165172
18D2B13117244C0A0026D09F /* SCSelectionView.m in Sources */,
166173
B2A3E44A172E714F004A56C1 /* SCTextView.m in Sources */,
174+
B25F211C172FE208001A9E6E /* SCMiniMapView.m in Sources */,
167175
);
168176
runOnlyForDeploymentPostprocessing = 0;
169177
};

SCXcodeMinimap/Conf.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
//
2+
// Conf.h
3+
// SCXcodeMinimap
4+
//
5+
// Created by Jérôme ALVES on 30/04/13.
6+
// Copyright (c) 2013 Stefan Ceriu. All rights reserved.
7+
//
8+
9+
#ifndef SCXcodeMinimap_Conf_h
10+
#define SCXcodeMinimap_Conf_h
11+
12+
13+
#define kDefaultZoomLevel 0.1f
14+
#define kRightSidePadding 10.0f
15+
#define kDefaultShadowLevel 0.1f
16+
17+
18+
#endif

SCXcodeMinimap/SCMiniMapView.h

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
//
2+
// SCMiniMapView.h
3+
// SCXcodeMinimap
4+
//
5+
// Created by Jérôme ALVES on 30/04/13.
6+
// Copyright (c) 2013 Stefan Ceriu. All rights reserved.
7+
//
8+
9+
#import <Cocoa/Cocoa.h>
10+
#import "SCTextView.h"
11+
#import "SCSelectionView.h"
12+
13+
@interface SCMiniMapView : NSScrollView <NSLayoutManagerDelegate, SCTextViewDelegate>
14+
15+
@property (nonatomic, retain) SCTextView *textView;
16+
@property (nonatomic, retain) SCSelectionView *selectionView;
17+
18+
@property (nonatomic, assign) NSScrollView *editorScrollView;
19+
@property (nonatomic, assign) NSTextView *editorTextView;
20+
21+
- (void)updateTextView;
22+
- (void)updateSelectionView;
23+
24+
- (void) show;
25+
- (void) hide;
26+
27+
@end

SCXcodeMinimap/SCMiniMapView.m

Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
//
2+
// SCMiniMapView.m
3+
// SCXcodeMinimap
4+
//
5+
// Created by Jérôme ALVES on 30/04/13.
6+
// Copyright (c) 2013 Stefan Ceriu. All rights reserved.
7+
//
8+
9+
#import "SCMiniMapView.h"
10+
#import "SCXcodeMinimap.h"
11+
12+
@implementation SCMiniMapView
13+
14+
- (id)initWithFrame:(NSRect)frame
15+
{
16+
self = [super initWithFrame:frame];
17+
if (self) {
18+
19+
/* Configure ScrollView */
20+
[self setWantsLayer:YES];
21+
[self setAutoresizingMask: NSViewMinXMargin | NSViewWidthSizable | NSViewHeightSizable];
22+
[self setDrawsBackground:NO];
23+
[self setHorizontalScrollElasticity:NSScrollElasticityNone];
24+
[self setVerticalScrollElasticity:NSScrollElasticityNone];
25+
26+
/* Configure Text View */
27+
SCTextView *miniMapTextView = [[SCTextView alloc] initWithFrame:self.bounds];
28+
[miniMapTextView setAutoresizingMask: NSViewMinXMargin | NSViewMaxXMargin | NSViewWidthSizable | NSViewHeightSizable];
29+
[miniMapTextView.textContainer setLineFragmentPadding:0.0f];
30+
[miniMapTextView setSelectable:NO];
31+
[miniMapTextView.layoutManager setDelegate:self];
32+
[miniMapTextView setDelegate:self];
33+
34+
[self setDocumentView:miniMapTextView];
35+
36+
NSColor *miniMapBackgroundColor = [NSColor clearColor];
37+
Class DVTFontAndColorThemeClass = NSClassFromString(@"DVTFontAndColorTheme");
38+
if([DVTFontAndColorThemeClass respondsToSelector:@selector(currentTheme)]) {
39+
NSObject *theme = [DVTFontAndColorThemeClass performSelector:@selector(currentTheme)];
40+
41+
if([theme respondsToSelector:@selector(sourceTextBackgroundColor)]) {
42+
miniMapBackgroundColor = [theme performSelector:@selector(sourceTextBackgroundColor)];
43+
44+
}
45+
}
46+
47+
[miniMapTextView setBackgroundColor:[miniMapBackgroundColor shadowWithLevel:kDefaultShadowLevel]];
48+
49+
self.textView = miniMapTextView;
50+
51+
[miniMapTextView release];
52+
53+
/* Configure Selection View */
54+
SCSelectionView *miniMapSelectionView = [[SCSelectionView alloc] init];
55+
[miniMapSelectionView setAutoresizingMask: NSViewMinXMargin | NSViewMaxXMargin | NSViewWidthSizable | NSViewHeightSizable | NSViewMinYMargin | NSViewMaxYMargin];
56+
//[miniMapSelectionView setShouldInverseColors:YES];
57+
[self addSubview:miniMapSelectionView];
58+
59+
self.selectionView = miniMapSelectionView;
60+
[miniMapSelectionView release];
61+
62+
/* Subscribe to show/hide notifications */
63+
[[NSNotificationCenter defaultCenter] addObserver:self
64+
selector:@selector(show)
65+
name:SCXodeMinimapWantsToBeShownNotification
66+
object:nil];
67+
68+
[[NSNotificationCenter defaultCenter] addObserver:self
69+
selector:@selector(hide)
70+
name:SCXodeMinimapWantsToBeHiddenNotification
71+
object:nil];
72+
}
73+
return self;
74+
}
75+
76+
- (void)dealloc
77+
{
78+
[[NSNotificationCenter defaultCenter] removeObserver:self];
79+
80+
[_selectionView release];
81+
[_textView release];
82+
[super dealloc];
83+
}
84+
85+
#pragma mark - Show/Hide
86+
87+
- (void) show
88+
{
89+
self.hidden = NO;
90+
91+
NSRect editorTextViewFrame = self.editorTextView.frame;
92+
editorTextViewFrame.size.width = self.editorTextView.superview.frame.size.width - self.bounds.size.width - kRightSidePadding;
93+
self.editorTextView.frame = editorTextViewFrame;
94+
}
95+
96+
- (void) hide
97+
{
98+
self.hidden = YES;
99+
100+
NSRect editorTextViewFrame = self.editorTextView.frame;
101+
editorTextViewFrame.size.width = self.editorTextView.superview.frame.size.width;
102+
self.editorTextView.frame = editorTextViewFrame;
103+
}
104+
105+
#pragma mark - Updating
106+
107+
- (void)updateTextView
108+
{
109+
NSMutableAttributedString *mutableAttributedString = [self.editorTextView.textStorage mutableCopy];
110+
111+
if(mutableAttributedString == nil) {
112+
return;
113+
}
114+
115+
[mutableAttributedString enumerateAttributesInRange:NSMakeRange(0, mutableAttributedString.length) options:NSAttributedStringEnumerationReverse usingBlock:
116+
^(NSDictionary *attributes, NSRange range, BOOL *stop) {
117+
118+
NSFont *font = [attributes objectForKey:NSFontAttributeName];
119+
NSFont *newFont = [NSFont fontWithName:font.familyName size:font.pointSize * kDefaultZoomLevel];
120+
121+
NSMutableDictionary *mutableAttributes = [NSMutableDictionary dictionaryWithDictionary:attributes];
122+
[mutableAttributes setObject:newFont forKey:NSFontAttributeName];
123+
[mutableAttributedString setAttributes:mutableAttributes range:range];
124+
}];
125+
126+
[self.textView.textStorage setAttributedString:mutableAttributedString];
127+
[mutableAttributedString release];
128+
}
129+
130+
- (void)updateSelectionView
131+
{
132+
NSRect selectionViewFrame = NSMakeRect(0,
133+
0,
134+
self.bounds.size.width,
135+
self.editorScrollView.visibleRect.size.height * kDefaultZoomLevel);
136+
137+
138+
CGFloat editorContentHeight = [self.editorScrollView.documentView frame].size.height - self.editorScrollView.bounds.size.height;
139+
140+
if(editorContentHeight == 0) {
141+
selectionViewFrame.origin.y = 0;
142+
}
143+
else {
144+
CGFloat ratio = ([self.documentView frame].size.height - self.bounds.size.height) / editorContentHeight;
145+
[self.contentView scrollToPoint:NSMakePoint(0, floorf(self.editorScrollView.contentView.bounds.origin.y * ratio))];
146+
147+
CGFloat textHeight = [self.textView.layoutManager usedRectForTextContainer:self.textView.textContainer].size.height;
148+
ratio = (textHeight - self.selectionView.bounds.size.height) / editorContentHeight;
149+
selectionViewFrame.origin.y = self.editorScrollView.contentView.bounds.origin.y * ratio;
150+
}
151+
152+
self.selectionView.frame = selectionViewFrame;
153+
}
154+
155+
#pragma mark - NSLayoutManagerDelegate
156+
157+
- (void)layoutManager:(NSLayoutManager *)layoutManager didCompleteLayoutForTextContainer:(NSTextContainer *)textContainer atEnd:(BOOL)layoutFinished
158+
{
159+
if(layoutFinished) {
160+
[self updateSelectionView];
161+
}
162+
}
163+
164+
- (NSDictionary *)layoutManager:(NSLayoutManager *)layoutManager shouldUseTemporaryAttributes:(NSDictionary *)attrs forDrawingToScreen:(BOOL)toScreen atCharacterIndex:(NSUInteger)charIndex effectiveRange:(NSRangePointer)effectiveCharRange
165+
{
166+
return [(id<NSLayoutManagerDelegate>)self.editorTextView layoutManager:layoutManager
167+
shouldUseTemporaryAttributes:attrs
168+
forDrawingToScreen:toScreen
169+
atCharacterIndex:charIndex
170+
effectiveRange:effectiveCharRange];
171+
}
172+
173+
#pragma mark - SCTextViewDelegate
174+
175+
- (void)textView:(SCTextView *)textView goAtRelativePosition:(NSPoint)position
176+
{
177+
CGFloat documentHeight = [self.editorScrollView.documentView frame].size.height;
178+
CGSize boundsSize = self.editorScrollView.bounds.size;
179+
CGFloat maxOffset = documentHeight - boundsSize.height;
180+
181+
CGFloat offset = floor(documentHeight * position.y - boundsSize.height/2);
182+
183+
offset = MIN(MAX(0, offset), maxOffset);
184+
185+
[self.editorTextView scrollRectToVisible:NSMakeRect(0, offset, boundsSize.width, boundsSize.height)];
186+
}
187+
188+
@end

SCXcodeMinimap/SCTextView.m

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -10,21 +10,6 @@
1010

1111
@implementation SCTextView
1212

13-
- (id)initWithFrame:(NSRect)frameRect
14-
{
15-
self = [super initWithFrame:frameRect];
16-
if (self) {
17-
NSLog(@"INIT TEXT VIEW");
18-
}
19-
return self;
20-
}
21-
22-
- (void)dealloc
23-
{
24-
NSLog(@"DEALLOC TEXT VIEW");
25-
[super dealloc];
26-
}
27-
2813
- (void)mouseDown:(NSEvent *)theEvent
2914
{
3015
[super mouseDown:theEvent];

SCXcodeMinimap/SCXcodeMinimap-Prefix.pch

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,5 @@
44

55
#ifdef __OBJC__
66
#import <Cocoa/Cocoa.h>
7+
#import "Conf.h"
78
#endif

SCXcodeMinimap/SCXcodeMinimap.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@
99
#import <Cocoa/Cocoa.h>
1010
#import "SCTextView.h"
1111

12-
@interface SCXcodeMinimap : NSObject <SCTextViewDelegate>
12+
extern NSString *const SCXodeMinimapWantsToBeShownNotification;
13+
extern NSString *const SCXodeMinimapWantsToBeHiddenNotification;
14+
15+
@interface SCXcodeMinimap : NSObject
1316

1417
@end

0 commit comments

Comments
 (0)