
<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Codex &#187; scrollbar position</title>
	<atom:link href="http://www.codexsoftware.co.uk/blog/tag/scrollbar-position/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.codexsoftware.co.uk/blog</link>
	<description>Computer topics and random rants!</description>
	<lastBuildDate>Wed, 07 Dec 2011 22:18:58 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<item>
		<title>How to determine if an NSTextView is scrolled to the end</title>
		<link>http://www.codexsoftware.co.uk/blog/computers/programming/how-to-determine-if-an-nstextview-is-scrolled-to-the-end/</link>
		<comments>http://www.codexsoftware.co.uk/blog/computers/programming/how-to-determine-if-an-nstextview-is-scrolled-to-the-end/#comments</comments>
		<pubDate>Mon, 29 Mar 2010 21:52:33 +0000</pubDate>
		<dc:creator>arcana</dc:creator>
				<category><![CDATA[Mac]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Cocoa]]></category>
		<category><![CDATA[NSScrollView]]></category>
		<category><![CDATA[NSTextView]]></category>
		<category><![CDATA[Objective-C]]></category>
		<category><![CDATA[scroll to end]]></category>
		<category><![CDATA[scrollbar]]></category>
		<category><![CDATA[scrollbar position]]></category>
		<category><![CDATA[scrolling]]></category>

		<guid isPermaLink="false">http://www.codexsoftware.co.uk/blog/?p=269</guid>
		<description><![CDATA[I found a several articles explaining how to scroll an NSTextView to the end, but I didn&#8217;t find any that explained how to do it only if it was already at the end before new text was appended. Consider this scenario.  You have an NSTextView scrolled to the end and as new text appears in [...]]]></description>
			<content:encoded><![CDATA[<p>I found a several articles explaining how to scroll an NSTextView to the end, but I didn&#8217;t find any that explained how to do it only if it was already at the end before new text was appended.</p>
<p>Consider this scenario.  You have an NSTextView scrolled to the end and as new text appears in the window, you want to see the new text immediately, so it scrolls to the very bottom for you.  Now you decide you want to read some text further up, so you scroll the text upwards.  As you&#8217;re reading, new text gets appended and suddenly it all scrolls down to the bottom again, causing you to lose your place.</p>
<p><span id="more-269"></span>We&#8217;re going to assume the NSTextView is named textView.  Imaginative, I know.</p>
<p>Usually we could append some coloured text and scroll to the end with something like this&#8230;</p>
<pre class="brush: objc; title: ; notranslate">
- (void)writeText:(NSString *)text
{
	// append some blue text
	NSDictionary *attribs = [NSDictionary dictionaryWithObject:[NSColor blueColor] forKey:NSForegroundColorAttributeName];
	NSAttributedString *stringToAppend = [[NSAttributedString alloc] initWithString:text attributes:attribs];
	[[textView textStorage] appendAttributedString:stringToAppend];
	[stringToAppend release];

	// scroll to the end
	NSRange range = NSMakeRange ([[textView string] length], 0);
	[textView scrollRangeToVisible: range];
}
</pre>
<p>Assuming you&#8217;ve just dropped the NSTextView on to a window or view from Interface Builder, the NSTextView will have been placed inside of an NSScrollView.  That NSScrollView can be queried to determine if the scrollbar was already at the bottom.  You should do this before you append any text.</p>
<pre class="brush: objc; title: ; notranslate">
	bool scrollToEnd = YES;

	id scrollView = (NSScrollView *)textView.superview.superview;
	if ([scrollView isKindOfClass:[NSScrollView class]]) {
		if ([scrollView hasVerticalScroller]) {
			if (textView.frame.size.height &gt; [scrollView frame].size.height) {
				if (1.0f != [scrollView verticalScroller].floatValue)
					scrollToEnd = NO;
			}
		}
	}
</pre>
<p>Firstly we default scrollToEnd to YES.  Next we check the NSTextView&#8217;s superview&#8217;s superview to make sure it is actually an NSScrollView.  If it is, and if it has a vertical scrollbar and our NSTextView is large enough to require scrolling, then we look at how far the scroll bar has moved.  This can be done by looking at its floatValue.</p>
<p>The floatValue can range from 0.0 to 1.0.  If a scrollbar is at the very bottom (or all the way over to the right if it&#8217;s horizontal) then it&#8217;s floatValue will be 1.0.</p>
<p>Here&#8217;s the complete code.</p>
<pre class="brush: objc; title: ; notranslate">
- (void)writeText:(NSString *)text
{
	// determine if we should scroll to the end
	bool scrollToEnd = YES;

	id scrollView = (NSScrollView *)textView.superview.superview;
	if ([scrollView isKindOfClass:[NSScrollView class]]) {
		if ([scrollView hasVerticalScroller]) {
			if (textView.frame.size.height &gt; [scrollView frame].size.height) {
				if (1.0f != [scrollView verticalScroller].floatValue)
					scrollToEnd = NO;
			}
		}
	}

	// append some coloured text
	NSDictionary *attribs = [NSDictionary dictionaryWithObject:[NSColor blueColor] forKey:NSForegroundColorAttributeName];
	NSAttributedString *stringToAppend = [[NSAttributedString alloc] initWithString:text attributes:attribs];
	[[textView textStorage] appendAttributedString:stringToAppend];
	[stringToAppend release];

	if (scrollToEnd) {
		// scroll to the end
		NSRange range = NSMakeRange ([[textView string] length], 0);
		[textView scrollRangeToVisible: range];
	}
}
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.codexsoftware.co.uk/blog/computers/programming/how-to-determine-if-an-nstextview-is-scrolled-to-the-end/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>

