<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
 
  <title>Elucidata</title>
  <subtitle>Notes blog</subtitle>
  <link href="http://elucidata.net/feed.xml" rel="self" />
  <link href="http://elucidata.net/" />
  <updated>2008-11-30T22:59:30-06:00</updated>
  <author>
    <name>M@ McCray</name>
    <email>matt@elucidata.net</email>
  </author>
  <id>http://elucidata.net/</id>
  
  <entry>
    <title>TaskTHIS Is Online</title>
    <link href="/notebook/2008/11/taskthis-is-online.html" />
    <id>tag:elucidata.net,2008-11-30:1228104122</id>
    <updated>2008-11-30T22:02:02-06:00</updated>
    <content type="html"><p><a href="http://taskthis.elucidata-apps.com">TaskTHIS</a> is back online now. Sorry for the interruption.</p>
<p>If you have any problems, please use our support forum: <a href="http://support.elucidata-apps.com/">http://support.elucidata-apps.com</a></p></content>
  </entry>
  
  <entry>
    <title>Hosting Changes</title>
    <link href="/notebook/2008/11/moving-servers.html" />
    <id>tag:elucidata.net,2008-11-22:1227402008</id>
    <updated>2008-11-22T19:00:08-06:00</updated>
    <content type="html"><p>We&#8217;re in the process of moving our sites to a new hosting center so some of our applications may be inaccessible for a little while.</p>
<p>They&#8217;ll be back soon, promise!</p>
<p><strong>Note:</strong> This change is only effecting our free applications. This move does NOT impact any of our clients or their sites.</p></content>
  </entry>
  
  <entry>
    <title>Site Refresh</title>
    <link href="/notebook/2008/05/site-refresh.html" />
    <id>tag:elucidata.net,2008-05-05:1210016588</id>
    <updated>2008-05-05T14:43:08-05:00</updated>
    <content type="html"><p>Welcome to the new and hopefully improved site. I&#8217;ve added a <a href="/notebook/index.html">notebook</a> section for technical articles and whatnots.</p>
<p>If you find any issues with this site in the dreaded IE(Internet Explorer), please let me know.</p>
<p>Also, the contact form is back and in working order.</p></content>
  </entry>
  
  <entry>
    <title>Animating NSViews in RubyCocoa</title>
    <link href="/notebook/2008/01/animating-nsviews-in-rubycocoa.html" />
    <id>tag:elucidata.net,2008-01-30:1201721063</id>
    <updated>2008-01-30T13:24:23-06:00</updated>
    <content type="html"><p>Yesterday we talked about how to make nifty <a href="/notebook/2008/01/selectable-toolbar-icons-in-rubycocoa.html">selectable toolbars</a> like this:</p>

<p style="text-align:center;"><img src="http://www.mattmccray.com/images/selectable-toolbar.png" alt="selectable-toolbar.png" border="0" width="366" height="80" /></p>

<p>Now let's look at the finishing touch for our Preferences window; Animating the panel changes. We'll be flying through this at a pretty good clip, but don't worry. I'll provide the full source for your inspection.</p>

<p>First off, let's add some new outlets to our window controller:</p>

<div class="UltraViolet"><pre class="mac_classic">
ib_outlets <span class="UserDefinedConstant"><span class="UserDefinedConstant">:</span>generalPrefsView</span>,
           <span class="UserDefinedConstant"><span class="UserDefinedConstant">:</span>advancedPrefsView</span>
</pre></div>

<img src="http://www.mattmccray.com/images/CustomView.png" alt="CustomView.png" border="0" width="135" height="54" align="right" />

<p>Now in Interface Builder, we'll create the views for each preference pane by dragging Custom Views from the Library onto our Preferences.nib.</p>

<p><em>Note:</em> Be sure to drop the Custom Views on the main nib window in IB, not on the Preferences <code>NSWindow</code>. Your project (in IB) should look something like this:</p>

<div style="text-align:center;"><img src="http://www.mattmccray.com/images/Prefs-IB.png" alt="Prefs-IB.png" border="0" width="385" height="337" /></div>

<p>Hook up the outlets to the new views, and edit your preference panels to your heart's desire. From here, we go back to the code.</p>

<p><em>Tip:</em> Be sure to set the auto-sizing on your preference panels (the <code>NSView</code>s) so that it matches the <code>NSWindow</code>'s <code>contentView</code>.</p>

<p style="text-align:center;"><img src="http://www.mattmccray.com/images/Picture 5.png" alt="Picture 5.png" border="0" width="232" height="120"/></p>

<p>Next up are some helper methods for our window controller. I won't spend too much time explaining these, but they're pretty straight forward.</p>

<div class="UltraViolet"><pre class="mac_classic">
<span class="Keyword">def</span> <span class="FunctionName">viewForTag</span>(<span class="FunctionParameter">tag</span>)
  <span class="Keyword">case</span> tag
    <span class="Keyword">when</span> <span class="Number">0</span>: [<span class="Variable"><span class="Variable">@</span>generalPrefsView</span>,  <span class="String"><span class="String">&quot;</span>General<span class="String">&quot;</span></span>]
    <span class="Keyword">when</span> <span class="Number">1</span>: [<span class="Variable"><span class="Variable">@</span>advancedPrefsView</span>, <span class="String"><span class="String">&quot;</span>Advanced<span class="String">&quot;</span></span>]
  <span class="Keyword">end</span>
<span class="Keyword">end</span>
</pre></div>

<p><code>#viewForTag</code> actually returns our <code>NSView</code> and a title string.</p>

<div class="UltraViolet"><pre class="mac_classic">
<span class="Keyword">def</span> <span class="FunctionName">newFrameForNewContentView</span>(<span class="FunctionParameter">view</span>)
  newFrameRect <span class="Keyword">=</span> window.<span class="FunctionName">frameRectForContentRect</span>(view.<span class="FunctionName">frame</span>)
  oldFrameRect <span class="Keyword">=</span> window.<span class="FunctionName">frame</span>
  newSize <span class="Keyword">=</span> newFrameRect.<span class="FunctionName">size</span>
  oldSize <span class="Keyword">=</span> oldFrameRect.<span class="FunctionName">size</span>
  frame <span class="Keyword">=</span> window.<span class="FunctionName">frame</span>
  frame.<span class="FunctionName">size</span> <span class="Keyword">=</span> newSize
  frame.<span class="FunctionName">origin</span>.<span class="FunctionName">y</span> <span class="Keyword">=</span> frame.<span class="FunctionName">origin</span>.<span class="FunctionName">y</span> <span class="Keyword">-</span> (newSize.<span class="FunctionName">height</span> <span class="Keyword">-</span> oldSize.<span class="FunctionName">height</span>)
  frame
<span class="Keyword">end</span>
</pre></div>

<p><code>#newFrameForNewContentView</code> calculates the new frame rectangle for the window based on the new view (preference pane).</p>

<p>Now we're ready to fill out our <code>selectPrefPanel</code> action:</p>

<div class="UltraViolet"><pre class="mac_classic">
ib_action <span class="UserDefinedConstant"><span class="UserDefinedConstant">:</span>selectPrefPanel</span> <span class="Keyword">do </span>|<span class="Variable">sender</span>|
  tag <span class="Keyword">=</span>  sender.<span class="FunctionName">tag</span>
  view, title <span class="Keyword">=</span> <span class="Variable">self</span>.<span class="FunctionName">viewForTag</span>(tag)
  previousView, prevTitle <span class="Keyword">=</span> <span class="Variable">self</span>.<span class="FunctionName">viewForTag</span>(<span class="Variable"><span class="Variable">@</span>currentViewTag</span>)
  <span class="Variable"><span class="Variable">@</span>currentViewTag</span> <span class="Keyword">=</span> tag
  newFrame <span class="Keyword">=</span> <span class="Variable">self</span>.<span class="FunctionName">newFrameForNewContentView</span>(view)
  window.<span class="FunctionName">title</span> <span class="Keyword">=</span> <span class="String"><span class="String">&quot;</span><span class="StringInterpolation"><span class="StringInterpolation">#{</span>title<span class="StringInterpolation">}</span></span> Preferences<span class="String">&quot;</span></span>
<span class="Comment">  <span class="Comment">#</span> Using an animation grouping because we may be changing the duration</span>
  <span class="Variable">NSAnimationContext</span>.<span class="FunctionName">beginGrouping</span>
<span class="Comment">    <span class="Comment">#</span> Call the animator instead of the view / window directly</span>
    window.<span class="FunctionName">contentView</span>.<span class="FunctionName">animator</span>.<span class="FunctionName">replaceSubview_with</span>(previousView, view)
    window.<span class="FunctionName">animator</span>.<span class="FunctionName">setFrame_display</span> newFrame, <span class="BuiltInConstant">true</span>
  <span class="Variable">NSAnimationContext</span>.<span class="FunctionName">endGrouping</span>
<span class="Keyword">end</span>
</pre></div>

<p>Right on! Now we setup the initial pane when the window loads:</p>

<div class="UltraViolet"><pre class="mac_classic">
<span class="Keyword">def</span> <span class="FunctionName">awakeFromNib</span>
  window.<span class="FunctionName">setContentSize</span> <span class="Variable"><span class="Variable">@</span>generalPrefsView</span>.<span class="FunctionName">frame</span>.<span class="FunctionName">size</span> 
  window.<span class="FunctionName">contentView</span>.<span class="FunctionName">addSubview</span> <span class="Variable"><span class="Variable">@</span>generalPrefsView</span>
  window.<span class="FunctionName">title</span> <span class="Keyword">=</span> <span class="String"><span class="String">&quot;</span>General Preferences<span class="String">&quot;</span></span>
  <span class="Variable"><span class="Variable">@</span>currentViewTag</span> <span class="Keyword">=</span> <span class="Number">0</span>
<span class="Comment">  <span class="Comment">#</span> Will use CoreAnimation for the panel changes:</span>
  window.<span class="FunctionName">contentView</span>.<span class="FunctionName">wantsLayer</span> <span class="Keyword">=</span> <span class="BuiltInConstant">true</span>
<span class="Keyword">end</span>
</pre></div>

<p>That pretty much does it. Now you have a professional looking preferences window. So enough of those dang blasted <code>NSTabView</code>s!</p>

<p>Here's the completed <a href="http://pastie.textmate.org/140681">PreferencesController.rb</a>. Or, you can download the <a href="http://www.mattmccray.com/downloads/PreferencesExample.zip">full Xcode project</a>. (Requires Leopard, Xcode 3, and Interface Builder 3)</p>

<p>Happy coding!</p></content>
  </entry>
  
  <entry>
    <title>Selectable Toolbar Icons in RubyCocoa</title>
    <link href="/notebook/2008/01/selectable-toolbar-icons-in-rubycocoa.html" />
    <id>tag:elucidata.net,2008-01-17:1200599396</id>
    <updated>2008-01-17T13:49:56-06:00</updated>
    <content type="html"><p>So you'd like to have some nifty selectable toolbar items to make your preferences window really polished? Or maybe you'd like to use the toolbar as a tab-set like <a href="http://www.panic.com/coda/">Coda</a> does. No problem, here's how to do it.</p>


<p><em>Note:</em> I'm using Leopard & Interface Builder 3. You can create selectable toolbars in Tiger, but the process is different and not within the scope of this article.</p>

<p>To start, in the window controller, add an <code>ib_action:</code></p>

<div class="UltraViolet"><pre class="mac_classic">
ib_action <span class="UserDefinedConstant"><span class="UserDefinedConstant">:</span>selectPrefPanel</span> <span class="Keyword">do </span>|<span class="Variable">sender</span>|
<span class="Comment">  <span class="Comment">#</span> We'll do stuff here later...</span>
<span class="Keyword">end</span>
</pre></div>

<p>Then in Interface Builder, create the toolbar and the toolbar items. For each toolbar item:</p>

<ul>
<li>Turn off the 'autovalidates' option</li>
<li>Set the action to target the <code>selectPrefPanel:</code> action on your window controller (probably the File's Owner)</li>
</ul>

<p>Before you save the Nib, be sure and set the toolbar's <code>delegate</code> to the window controller.</p>

<p>Now back in the window controller code, implement a <code>toolbarSelectableItemIdentifiers</code> method in your controller:</p>

<div class="UltraViolet"><pre class="mac_classic">
<span class="Keyword">def</span> <span class="FunctionName">toolbarSelectableItemIdentifiers</span>(<span class="FunctionParameter">toolbar</span>)
  <span class="Variable"><span class="Variable">@</span>toolbaridents</span> <span class="Keyword">||=</span> <span class="Keyword">begin</span>
    window.<span class="FunctionName">toolbar</span>.<span class="FunctionName">toolbaritems</span>.<span class="FunctionName">collect</span> {|<span class="Variable">i</span>| i.<span class="FunctionName">itemIdentifier</span> }
  <span class="Keyword">end</span>
<span class="Keyword">end</span>
</pre></div>

<p>Lastly, when the window loads, select the first toolbar item:</p>

<div class="UltraViolet"><pre class="mac_classic">
<span class="Keyword">def</span> <span class="FunctionName">awakeFromNib</span>
  tb <span class="Keyword">=</span> window.<span class="FunctionName">toolbar</span>
  tb.<span class="FunctionName">selectedItemIdentifier</span> <span class="Keyword">=</span> tb.<span class="FunctionName">toolbarItems</span>[<span class="Number">0</span>].<span class="FunctionName">itemIdentifier</span>
<span class="Keyword">end</span>
</pre></div>

<p>Viola! Now you have selectable toolbar items.</p>

<p>Here's the <a href="http://pastie.textmate.org/140682"><strong>full source</strong> for the window controller</a>.</p>

<p>It's worth mentioning that this isn't specific to RubyCocoa. You can do the same thing in Objective-C, Python, or Nu (<a href="http://pastie.textmate.org/139630">example</a>).</p>

<p>Next, I'll show you how to create the views that will go within your preferences window, and how to animate them to really finish it off.</p>

<p><em>Update:</em> Find the next article <a href="/notebook/2008/01/animating-nsviews-in-rubycocoa.html">here</a>.</p></content>
  </entry>
  
</feed>
