<?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>Carsonified &#187; Cappuccino</title>
	<atom:link href="http://carsonified.com/blog/category/dev/cappuccino/feed/" rel="self" type="application/rss+xml" />
	<link>http://carsonified.com</link>
	<description></description>
	<lastBuildDate>Tue, 16 Mar 2010 13:01:45 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Introducing Atlas: A Visual Development Tool for Creating Web Apps</title>
		<link>http://carsonified.com/blog/web-apps/introducing-atlas-a-visual-development-tool-for-creating-web-apps/</link>
		<comments>http://carsonified.com/blog/web-apps/introducing-atlas-a-visual-development-tool-for-creating-web-apps/#comments</comments>
		<pubDate>Wed, 07 Oct 2009 05:06:32 +0000</pubDate>
		<dc:creator>Francisco Tolmasky</dc:creator>
				<category><![CDATA[Cappuccino]]></category>
		<category><![CDATA[Dev]]></category>
		<category><![CDATA[Learn]]></category>
		<category><![CDATA[Web Apps]]></category>
		<category><![CDATA[fowa-london-09]]></category>

		<guid isPermaLink="false">http://carsonified.com/?p=3464</guid>
		<description><![CDATA[By <strong>Francisco Tolmasky</strong><br />In this video from FOWA London 2009, Francisco Tolmasky will demo Atlas, a new visual tool for building web apps and desktop apps. It will blow your mind and change what you thought was possible with web apps. This is new footage that has not been shown to the public ever before.
Editor&#8217;s Note: Only eight [...]]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style=""><a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fcarsonified.com%2Fblog%2Fweb-apps%2Fintroducing-atlas-a-visual-development-tool-for-creating-web-apps%2F"><img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fcarsonified.com%2Fblog%2Fweb-apps%2Fintroducing-atlas-a-visual-development-tool-for-creating-web-apps%2F" height="61" width="51" /></a></div><p>In this video from FOWA London 2009, Francisco Tolmasky will demo <a href="http://280atlas.com/">Atlas</a>, a new visual tool for building web apps and desktop apps. It will blow your mind and change what you thought was possible with web apps. This is new footage that has not been shown to the public ever before.</p>
<p><em>Editor&#8217;s Note: <strong>Only eight hours till we launch FOWA Miami 2010</strong>! There&#8217;s only 20 Super Early Bird tickets at 47% off, so be quick (only 440 seats total, so the show will definitely sell out early). Speakers include: Twitter, Reddit, Mint.com, jQuery, Palm Pre, FreshBooks, Opera and PayPal. Keep an eye on <a href="http://events.carsonified.com">events.carsonified.com</a> for the launch at 9am EST.</em></p>
<p><span id="more-3464"></span></p>
<p><object width="471" height="259"><param name="allowfullscreen" value="true" /><param name="allowscriptaccess" value="always" /><param name="movie" value="http://vimeo.com/moogaloop.swf?clip_id=6930037&amp;server=vimeo.com&amp;show_title=1&amp;show_byline=1&amp;show_portrait=0&amp;color=eb6f00&amp;fullscreen=1" /><embed src="http://vimeo.com/moogaloop.swf?clip_id=6930037&amp;server=vimeo.com&amp;show_title=1&amp;show_byline=1&amp;show_portrait=0&amp;color=eb6f00&amp;fullscreen=1" type="application/x-shockwave-flash" allowfullscreen="true" allowscriptaccess="always" width="471" height="259"></embed></object></p>
<img src="http://carsonified.com/?ak_action=api_record_view&id=3464&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://carsonified.com/blog/web-apps/introducing-atlas-a-visual-development-tool-for-creating-web-apps/feed/</wfw:commentRss>
		<slash:comments>18</slash:comments>
		</item>
		<item>
		<title>Atlas: Under the Hood</title>
		<link>http://carsonified.com/blog/carsonified/features/atlas-under-the-hood/</link>
		<comments>http://carsonified.com/blog/carsonified/features/atlas-under-the-hood/#comments</comments>
		<pubDate>Sat, 28 Feb 2009 21:02:52 +0000</pubDate>
		<dc:creator>Francisco Tolmasky</dc:creator>
				<category><![CDATA[Back-End]]></category>
		<category><![CDATA[Cappuccino]]></category>
		<category><![CDATA[Features]]></category>
		<category><![CDATA[iphone]]></category>

		<guid isPermaLink="false">http://thinkvitamin.com/?p=979</guid>
		<description><![CDATA[By <strong>Francisco Tolmasky</strong><br />At 280 North we&#8217;ve been working on a framework called Cappuccino for creating what we like to call desktop class applications. These are not your average web sites, but instead a new breed of web application that aims to replace many of the programs that currently run on your desktop. When we launched 280 Slides, [...]]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style=""><a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fcarsonified.com%2Fblog%2Fcarsonified%2Ffeatures%2Fatlas-under-the-hood%2F"><img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fcarsonified.com%2Fblog%2Fcarsonified%2Ffeatures%2Fatlas-under-the-hood%2F" height="61" width="51" /></a></div><p>At <a href="http://280north.com">280 North</a> we&#8217;ve been working on a framework called <a href="http://cappuccino.org">Cappuccino</a> for creating what we like to call desktop class applications. These are not your average web sites, but instead a new breed of web application that aims to replace many of the programs that currently run on your desktop. When we launched <a href="http://280slides.com">280 Slides</a>, the first application built on this framework, many people were surprised to see just what was possible in the browser. Since then, Cappuccino has been steadily progressing with over 40,000 downloads and code contributions from twenty-one individuals.</p>
<p>The goal of Cappuccino has always been to make it as simple as possible to build high quality applications in the browser, and up until now we&#8217;ve worked on providing built-in behavior for enabling such tasks as autosaving, undo/redo, and copy/paste.  But recently we&#8217;ve been focusing on an entirely new product: <a href="http://280atlas.com">Atlas</a>. Atlas is a new IDE and visual layout editor that leverages the power of Cappuccino, but drastically reduces the amount of work required for creating a truly rich application experience on the web.</p>
<p><strong>WYSIWYG</strong></p>
<p>With Atlas you can build and style your entire interface using drag and drop. By default we provide you with a large library of built in widgets along with the new Aristo open source theme, meaning your application will look fantastic with no additional work. However, you can also skin these applications entirely from the editor and extend the library of widgets with Atlas&#8217; plugin architecture. And unlike a lot of existing layout editor availabe today, Atlas is not a code generator. On the contrary, Atlas lets you edit the live JavaScript objects in memory and then takes a &#8220;snapshot&#8221; of them in place. When your application runs, it &#8216;thaws&#8217; these objects out, making sure that you see exactly how your application will look before you run it.</p>
<p><strong>Layout that Makes Sense</strong></p>
<p>Atlas provides a new take on web layout that make it easy to define precisely the behavior you want, while simultaneously doing away with existing browser inconsistencies.  Instead of having to learn the variety of different ways to position and resize elements in the browser, Atlas introduces the simple concept of &#8216;anchors and springs&#8217;. Anchoring an interface element to one of the edges around it ensures that it will stay &#8220;stuck&#8221; there when it&#8217;s container resizes. Activating the internal &#8217;springs&#8217; causes it to resize with its container.</p>
<p><object width="471" height="295"><param name="allowfullscreen" value="true" /><param name="allowscriptaccess" value="always" /><param name="movie" value="http://vimeo.com/moogaloop.swf?clip_id=3410186&amp;server=vimeo.com&amp;show_title=1&amp;show_byline=1&amp;show_portrait=0&amp;color=eb6f00&amp;fullscreen=1" /><embed src="http://vimeo.com/moogaloop.swf?clip_id=3410186&amp;server=vimeo.com&amp;show_title=1&amp;show_byline=1&amp;show_portrait=0&amp;color=eb6f00&amp;fullscreen=1" type="application/x-shockwave-flash" allowfullscreen="true" allowscriptaccess="always" width="471" height="295"></embed></object></p>
<p>While simple to learn, these two tools enable you to create incredibly complex and fluid layouts. More importantly, they&#8217;re guaranteed to behave the same way regardless of the browser you&#8217;re running your web app in. Atlas also provides a large selection of collection views to handle common layout tasks such as split views, table views, and scroll views.</p>
<p><strong>Connections Reduce Glue Code</strong></p>
<p>A common problem that has plagued layout editors in the past is the need for additional glue code to &#8220;talk&#8221; to the generated interface.  In Atlas, much of this work can be done with a technology called &#8216;connections&#8217;. Connections allow you to visually define the interactions between interface elements and other objects.  For example, you can define what action a slider should take when it is dragged:</p>
<p><a href="http://thinkvitamin.com/wp-content/uploads/2009/02/picture-1.jpg"><img class="alignnone" title="Screenshot of Atlas" src="http://thinkvitamin.com/wp-content/uploads/2009/01/280atlas.jpg" alt="" width="440" height="365" /><br />
</a></p>
<p>Similarly, you can &#8216;bind&#8217; the contents of an array to a table, so that when it changes the table automatically updates as well, all without having to ever touch the keyboard:</p>
<p><img class="alignnone" title="Atlas 02" src="http://thinkvitamin.com/wp-content/uploads/2009/01/atlas2.png" alt="" width="511" height="525" /></p>
<p><strong>Model View Controller Built-In</strong></p>
<p>Cappuccino is a Model-View-Controller framework, and Atlas takes this idea to the next level by allowing you to not only create visual elements, but abstract models and controllers as well. By allowing you to interact directly with the objects in your program visually, you can focus on building unique interactions instead of learning a myriad of APIs.</p>
<p>Atlas has gone a step further and provided a number of pre-built controllers to existing web services that you can simply drop in to their applications. You can then simply use connections to grab information from services like RSS and Twitter. Once again, Atlas&#8217; plugin architecture allows you to create controllers for your own web services as well, which you can then share with others.</p>
<p><img class="alignnone" title="Atlas 03" src="http://thinkvitamin.com/wp-content/uploads/2009/01/atlas3.png" alt="" width="515" height="542" /></p>
<p><strong>Multi-Platform Support</strong></p>
<p>Cappuccino was built from the ground up in preparation for a world of multiple platforms. It is becoming increasingly important for applications to run in several different environments: browsers, social networks, handheld devices, and much more. In general, very little application logic or backend code has to change from platform to platform, but the interface usually needs to be recreated from scratch.</p>
<p>With Atlas, it is drop dead simple to create a unique and custom interface for different platforms like the web browser and the iPhone. Cappuccino will then intelligently load the correct interface for your application depending on the environment it is being run on, allowing you to reduce the amount of code you need to rewrite and as well as using just one language and API for all the platforms you deploy on. We call this idea &#8216;Write once, layout everywhere&#8217;, and we feel it is the right way to gaurantee a high quality experience everywhere you ship your application.</p>
<p><a href="http://thinkvitamin.com/wp-content/uploads/2009/01/atlas4.png"><img class="alignnone" title="Atlas 04" src="http://thinkvitamin.com/wp-content/uploads/2009/01/atlas4.png" alt="" width="540" height="402" /></a><br />
View <a href="http://thinkvitamin.com/wp-content/uploads/2009/01/atlas4.png">full size</a></p>
<p><a href="http://thinkvitamin.com/wp-content/uploads/2009/01/atlas5.png"><img class="alignnone" title="Altas 5" src="http://thinkvitamin.com/wp-content/uploads/2009/01/atlas5.png" alt="" width="540" height="402" /></a><br />
View <a href="http://thinkvitamin.com/wp-content/uploads/2009/01/atlas5.png">full size</a></p>
<p>Atlas will be shipping this summer and you can sign up for email updates at <a href="http://280atlas.com">280atlas.com</a>.</p>
<p>[Photo credit: <a href="http://flickr.com/photos/atelier_tee/">flickr.com/photos/atelier_tee</a>]</p>
<img src="http://carsonified.com/?ak_action=api_record_view&id=979&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://carsonified.com/blog/carsonified/features/atlas-under-the-hood/feed/</wfw:commentRss>
		<slash:comments>58</slash:comments>
		</item>
		<item>
		<title>Add Undo and Redo to Your Web Application With Cappuccino</title>
		<link>http://carsonified.com/blog/web-apps/add-undo-and-redo-to-your-web-application-with-cappuccino/</link>
		<comments>http://carsonified.com/blog/web-apps/add-undo-and-redo-to-your-web-application-with-cappuccino/#comments</comments>
		<pubDate>Thu, 13 Nov 2008 17:32:17 +0000</pubDate>
		<dc:creator>Francisco Tolmasky</dc:creator>
				<category><![CDATA[Cappuccino]]></category>
		<category><![CDATA[Dev]]></category>
		<category><![CDATA[Features]]></category>
		<category><![CDATA[Web Apps]]></category>
		<category><![CDATA[Business]]></category>

		<guid isPermaLink="false">http://www.thinkvitamin.com/features/ajax/add-undo-and-redo-to-your-web-application-with-cappuccino</guid>
		<description><![CDATA[By <strong>Francisco Tolmasky</strong><br />Undo and redo are two of the most essential features in any real rich application experience. In many cases, your user has already turned these commands into reflexes, automatically hitting the proper keys and expecting the right thing to happen. Unfortunately, this is often left unimplemented by developers when making the transition from the desktop [...]]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style=""><a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fcarsonified.com%2Fblog%2Fweb-apps%2Fadd-undo-and-redo-to-your-web-application-with-cappuccino%2F"><img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fcarsonified.com%2Fblog%2Fweb-apps%2Fadd-undo-and-redo-to-your-web-application-with-cappuccino%2F" height="61" width="51" /></a></div><p>Undo and redo are two of the most essential features in any real rich application experience. In many cases, your user has already turned these commands into reflexes, automatically hitting the proper keys and expecting the right thing to happen. Unfortunately, this is often left unimplemented by developers when making the transition from the desktop to the web, serving as a rude awakening to your users when they make a mistake that can’t be undone. It makes sense that this doesn’t receive the attention it deserves since the actual functionality of your application should obviously come first, and it doesn’t help that implementing these features from scratch can be quite difficult. However, they add a necessary amount of polish that you should seriously consider adding to your web application.</p>
<p>Luckily for us, <a rel="nofollow" href="http://cappuccino.org/" target="_blank">Cappuccino</a> has built-in support that can allow you to plug undo and redo right in by just by adding a few lines of code. In this tutorial, we will be exploring how to add sophisticated undo and redo support to a graphical application in the browser. We won’t be creating the entire application from scratch however, but instead building off of an existing example. We’re doing this for two reasons. For starters, we don’t want to get distracted from our main task by having to wade through unrelated code. Instead we’ll simply review whatever code we need to as we get to it. More importantly, the sample provided is complex enough to serve as a true real-world example, as opposed to the contrived code we’d be forced to put together in the limited scope of space and time of this tutorial. This also has the benefit of displaying the modular nature of undo support in Cappuccino, and how we can add it to an application without knowing every detail of its implementation.</p>
<p>That being said, you can, of course, feel free to review the entire source of the application as well. The application itself is written entirely using Cappuccino, but you don’t really need any prior knowledge of Cappuccino to follow along with this tutorial. Feel free to review Cappuccino and Objective-J at <a rel="nofollow" href="http://cappuccino.org/learn/" target="_blank">cappuccino.org</a> before you dig in, but it’s not a requirement to follow along.</p>
<p>Let’s start by taking a look at the application we’ll be modifying. You can see it and play with it live <a rel="nofollow" href="http://cappuccino.org/learn/demos/FloorPlan/" target="_blank">here</a>. You’ll need to <a rel="nofollow" href="http://cappuccino.org/learn/demos/FloorPlan.zip " target="_blank">download the source</a> in order to follow along with the changes in this tutorial. As you’ve probably noticed, it’s a simple floor planning app that lets you drag and drop and arrange furniture into the layout of a small apartment:</p>
<p><img src="http://www.thinkvitamin.com/images/articles/cappuccino/Application.png" alt="screenshot of floor planning application, showing furniture on left and floorplan on right" /></p>
<p>Have a play with the app. As you can see, it supports three actions that we’ll want the user to be able to undo:</p>
<p><img src="http://www.thinkvitamin.com/images/articles/cappuccino/Actions.png" alt="actions the user should be able to undo: Drag-and-drop addition, drag-and-drop positioning, and rotation" /></p>
<ul>
<li>drag-and-drop to add furniture: should remove the furniture when hitting undo, and add back in when hitting redo</li>
<li>drag-and-drop to a new location: should revert to previous location when hitting undo</li>
<li>rotate: should revert to previous rotation when hitting undo</li>
</ul>
<p>Now, the main thing you should know before we dig into the code is we’ll be dealing with two classes, <code>FloorPlanView</code>, which represents the background and layout of the apartment:</p>
<p><img src="http://www.thinkvitamin.com/images/articles/cappuccino/FloorPlanView.png" alt="screenshot of application with layout highlighted" /></p>
<p>The other is <code>FurnitureView</code>, which displays each individual piece of furniture in the apartment:</p>
<p><img src="http://www.thinkvitamin.com/images/articles/cappuccino/FurnitureViews.png" alt="screenshot of application with furniture highlighted" /></p>
<p>The first action we’re going to tackle is undoing the movement of furniture pieces. All the code to handle moving furniture views is currently contained in two methods in FurnitureView.j: <code>mouseDown:</code> and <code>mouseDragged:</code>. Let’s review their current implementations:</p>
<pre><code>- (void)<em>mouseDown</em>:(CPEvent)anEvent
{ dragLocation = [anEvent <em>locationInWindow</em>]; [[EditorView <em>sharedEditorView</em>] 
<em>setFurnitureView:</em>self];</code></pre>
<pre><code>} - (void)<em>mouseDragged:</em>(CPEvent)anEvent
{ var location = [anEvent <em>locationInWindow</em>], origin = [self <em>frame</em>].origin;
[self <em>setFrameOrigin:</em>CGPointMake(origin.x + location.x - dragLocation.x,
origin.y + location.y - dragLocation.y)]; dragLocation = location;
}
</code></pre>
<p><code><em>mouseDown:</em></code> simply stores the mouse down position, and additionally sets the furniture view as selected through the EditorView, which we won’t need to concern ourselves with. <code><em>mouseDragged:</em></code> then proceeds to update the origin of the view on every drag event. Despite being where the actual changes take place, we don’t want to register our undo action in <code><em>mouseDragged:</em></code> because if we do we’ll be registering an undo action for every pixel the user drags! So instead, we’ll want to add a new method right below it called <code><em>mouseUp:</em></code>. The <code><em>mouseUp:</em></code> method gets called when the user lifts the mouse and is thus done dragging:</p>
<pre><code>- (void)<em>mouseUp:</em>(CPEvent)anEvent
{
// Register undo here.
}
</code></pre>
<p>Now, before we continue we’ll want to create one additional new method, <code><em>setEditedOrigin:</em></code>. The reason for this is that we want a way to change the furniture locations that notifies the undo architecture, and a way that doesn’t. Currently we’ve fullfilled one of these requirements: <code><em>setFrameOrigin:</em></code> can be used to change the position of a FurnitureView without registering any undos, so let’s now create an analog that will:</p>
<pre><code>- (void)<em>setEditedOrigin:</em>(CGPoint)aPoint
{ if (CGPointEqualToPoint(editedOrigin, aPoint)) return; [[[self <em>window</em>]
<em>undoManager</em>] <em>registerUndoWithTarget:</em>self <em>selector:</em>@selector(setEditedOrigin:)
<em>object:</em>editedOrigin]; editedOrigin = aPoint; [self <em>setFrameOrigin:</em>aPoint];
}
</code></pre>
<p>This method is relatively straightforward and shows us how to talk to Cappuccino’s undo support. We create a new instance variable called <code>editedOrigin</code> which keeps track of the last “undoable” position. This way we can ignore all the origin changes that take place during while a drag is mid-flight. When the user passes in a new position, we compare it to <code>editedOrigin</code> to make sure they’re not the same. We do this in order to prevent undos being placed in the stack that have no percievable difference to our user (making it appear that the undo “didn’t register”). After this we do the most important step, which is tell our undo manager that it should register an undo. Every view has a window, and every window has its own undo manager (that way, different windows can have different undo stacks). So we grab our undo manager from our window. We then call <code><em>registerUndoWithTarget:selector:object:</em></code>. This method tells the undo manager what to do when the user hits undo. In this case, we want to just call this very same method, but with the old origin, <code>editedOrigin</code>. We then set <code>editedOrigin</code> to the current position, and of course update our actual origin, and we’re done. We do need a bit of book-keeping however; namely we need to declare this new instance variable in the class definition:</p>
<pre><code>@implementation FurnitureView : CPView
{ CPString name; CPImage image; float rotationRadians; CGPoint dragLocation;
CGPoint editedOrigin;
}</code></pre>
<p>as well as set its initial value in <code><em>mouseDown:</em></code>:</p>
<pre><code>- (void)mouseDown:(CPEvent)anEvent
{ editedOrigin = [self <em>frame</em>].origin; dragLocation = [anEvent locationInWindow];
[[EditorView sharedEditorView] setFurnitureView:self];
}
</code></pre>
<p>You may be wondering why we need this new instance variable at all, since we can just query our frame for our current origin. The reason is because when we only want to “remember” origins that are to be undone. If you hit refresh in your browser, you should be able to undo moving a furniture item by hitting command-z on a Mac and ctrl-z on a PC. You’ll also notice that you are capable of redoing these actions as well. That’s because <code><em>setEditedOrigin:</em></code> gets called for the undo action as well, thus registering another undo on the stack, which Cappuccino is smart enough to know should actually be a redo.</p>
<p>We can now move on to undoing the rotations which are slightly more complex. As we saw earlier, the goal is always to register an undo once editing is complete. You’ll notice that there are two empty methods in FurnitureView.j, <code><em>willBeginLiveRotation</em></code> and <code><em>didEndLiveRotation</em></code>, which the editing system is kind enough to send to us when the user begins and ends rotating, respectively:</p>
<pre><code>- (void)<em>willBeginLiveRotation</em>
{
} - (void)<em>didEndLiveRotation</em>
{
}
</code></pre>
<p>Clearly we’ll want to add our actual undo action in <code><em>didEndLiveRotation</em></code>, but just as before we’re going to created an “Edited” version of <code><em>setRotationRadians:</em></code> for rotation actions that we want to register with the undo system:</p>
<pre><code>- (void)<em>setEditedRotationRadians:</em>(float)radians
{ if (editedRotationRadians == radians) return; [[[self <em>window</em>] <em>undoManager</em>]
<em>registerUndoWithTarget:</em>self <em>selector:</em>@selector(setEditedRotationRadians:)
<em>object:</em>editedRotationRadians]; [self <em>setRotationRadians:</em>radians];
editedRotationRadians = radians;
}
</code></pre>
<p>This should look very familiar. It’s almost identical to our previous implementation, except we are dealing with radians instead of positions. Let’s not forget to add our new <code>editedRotationRadians</code> to the other necessary places, namely the class declaration:</p>
<pre><code>@implementation FurnitureView : CPView
{ CPString name; CPImage image; float rotationRadians; float editedRotationRadians;
CGPoint dragLocation; CGPoint editedOrigin;
}</code></pre>
<p>and <code><em>willBeginLiveRotation</em></code>, which is analogous to our <code><em>mouseDown:</em></code> since it’s what kick starts the rotation process:</p>
<pre><code>- (void)<em>willBeginLiveRotation</em>
{ editedRotationRadians = rotationRadians;
}
</code></pre>
<p>Now all that’s left to do is to actually call <code>setEditedRotationRadians</code> when the user finishes rotating a furniture piece:</p>
<pre><code>- (void)<em>didEndLiveRotation</em>
{ [self setEditedRotationRadians:rotationRadians];
}
</code></pre>
<p>Once again, if you refresh you should be able to undo and redo rotating furniture items, as well as being able to undo their positioning.</p>
<p>We are now done with editing the <code>FurnitureView</code> class, and we can move on to the last action that the user should be able to undo: actually adding furniture to the apartment layout. To do this, we’ll have to move to FloorPlanView.j, where the <code>FloorPlanView</code> class is contained. The two methods we are primarily concerned with are <code><em>addFurnitureView:</em></code> and <code><em>removeFurnitureView:</em></code>, which do just that:</p>
<pre><code>- (void)<em>addFurnitureView:</em>(FurnitureView)aFurnitureView
{ [self <em>addSubview:</em>aFurnitureView]; [[EditorView <em>sharedEditorView</em>]
<em>setFurnitureView:</em>aFurnitureView];
} - (void)<em>removeFurnitureView:</em>(FurnitureView)aFurnitureView
{ var editorView = [EditorView <em>sharedEditorView</em>]; if ([editorView <em>furnitureView</em>]
== aFurnitureView) [editorView <em>setFurnitureView:</em>nil]; [aFurnitureView <em>removeFromSuperview</em>];
}
</code></pre>
<p>As you can see there’s quite a bit going on here, but again most of it is not of our concern. In fact, in this case, none of it is. This comes from one simple realization: these methods are opposites of each other, and thus <em>undo</em> each other. So to undo <code><em>addFurnitureView:</em></code>, we need to <code><em>removeFurnitureView:</em></code>, and vice versa, so the code is actually quite simple:</p>
<pre><code>- (void)addFurnitureView:(FurnitureView)aFurnitureView
{ [[[self <em>window</em>] <em>undoManager</em>] <em>registerUndoWithTarget:</em>self
<em>selector:</em>@selector(removeFurnitureView:) <em>object:</em>aFurnitureView];
[self addSubview:aFurnitureView]; [[EditorView sharedEditorView]
setFurnitureView:aFurnitureView];
}
- (void)removeFurnitureView:(FurnitureView)aFurnitureView
{ [[[self <em>window</em>] <em>undoManager</em>] <em>registerUndoWithTarget:</em>self
<em>selector:</em>@selector(addFurnitureView:) <em>object:</em>aFurnitureView];
var editorView = [EditorView sharedEditorView]; if ([editorView
furnitureView] == aFurnitureView) [editorView setFurnitureView:nil];
[aFurnitureView removeFromSuperview];
}</code></pre>
<p>And there it is, it’s that easy. All we had to do is register the opposite action in each method, and both of them are undable (and redoable) now.</p>
<h3>Make undo and redo discoverable</h3>
<p>Something interesting that I’ve noticed with undo and redo in our own applications is that many times people don’t realize they have this feature. When we first launched <a rel="nofollow" href="http://280slides.com/" target="_blank">280 Slides</a> we got a number of “feature requests” asking for undo and redo support. They were thrilled when we told them they could just use the key commands they were used to, but apparently this was not discoverable enough. Because of this, we decided to add actual undo and redo buttons to make these actions more explicit. Let’s go ahead and do the same here by adding the following snippet of code to the end of the <code><em>applicationDidFinishLaunching:</em></code> method in AppController.j:</p>
<pre><code>var undoButton = [[CPButton <em>alloc</em>] <em>initWithFrame:</em>CGRectMake(20.0, 400.0, 60.0, 18.0)],
redoButton = [[CPButton <em>alloc</em>] <em>initWithFrame:</em>CGRectMake(90.0, 400.0, 60.0, 18.0)];
[undoButton <em>setTitle:</em>“Undo”];
[undoButton <em>setTarget:</em>[theWindow <em>undoManager</em>]];
[undoButton <em>setAction:</em>@selector(undo)]; [redoButton <em>setTitle:</em>“Redo”];
[redoButton <em>setTarget:</em>[theWindow <em>undoManager</em>]];
[redoButton <em>setAction:</em>@selector(redo)]; [view <em>addSubview:</em>undoButton];
[view <em>addSubview:</em>redoButton];
</code></pre>
<p>Now if our users have “unlearned” expecting undo and redo to work, they’ll be able to idenitfy these buttons. With that, we’ve now made all the current actions in this application undoable and provided an easy way for our users to use this feature. As we continue to add new features to this application we can also incrementally add their associated undos. As we’ve seen here, it’s often a matter of just adding one or two lines of code per method, so it’s good to start early and not wait until the very end to begin incorporating this functionality. I hope you’ve enjoyed this tutorial and make sure to leave any questions you may have in the comments! The completed source with all the above additions is available <a rel="nofollow" href="http://thinkvitamin.com/downloads/cappuccino/FloorPlanEdited.zip" target="_blank">here</a> and you can give it a spin <a rel="nofollow" href="http://thinkvitamin.com/misc/cappuccino/FloorPlanEdited/" target="_blank">here</a>.</p>
<p><em>Francisco will be speaking at <a rel="nofollow" href="http://events.carsonified.com/fowa/2009/" target="_blank">The Future of Web Apps Miami</a></em></p>
<img src="http://carsonified.com/?ak_action=api_record_view&id=27&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://carsonified.com/blog/web-apps/add-undo-and-redo-to-your-web-application-with-cappuccino/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
	</channel>
</rss>
