Updates from October, 2008 Toggle Comment Threads | Keyboard Shortcuts

  • Jonathan Dann 18:07 on October 24, 2008 Permalink | Reply  

    I Love Outline Views – Here’s Mine 

    Apps like Coda are the de-facto standard for good user-interface design nowadays. You can do a lot with the standard Cocoa controls provided by Apple, but you can’t always get exactly what you want out-of-the-box. For example, the CSS edit section of Coda has a fantastic way of dividing tasks: the animated outline view.

    Rather than having a monolithic view that has all the controls grouped with dividing lines; each section, “Text”, “Colors and Background”, “Dimensions”, all exist in their own collapsible view. Clicking the separating bar animatedly expands or collapses the view.


    To make one of these views isn’t quite as easy as you first think, and you can quickly go down the wrong road in the design. The super-secret trick is to *not* use Core Animation, or more precisely: ignore the lure of NSViews conformance to the NSAnimatablePropertyContainer protocol. As of Mac OS X 10.5, a few of the properties of a view or window can be animated simply be replacing calls like [view setFrame:newFrame]; with [[view animator] setFrame:newFrame];. This is fine when you have one or two views that you want to move but it’s impossible to coordinate the movements of multiple view using this API. After using Core Animation, one would expect that after a call such as [[view animator] setFrame:newFrame]; requesting the frame from the view would return newFrame. Unfortunatley it returns the original frame of the view. Only when the animation is done, do you get newFrame. Furthermore, just try setting the delegate of the CABasicAnimation object that handles the implicit animation and getting any form of useful information back. You can’t. You’re in for a world of pain if you try.

    The solution: use good-ol’ NSViewAnimation. That way you can create all the dictionaries containing the animations for all the views you want to, then instantiate one NSViewAnimation object to handle the lot and set them off at the same time. Simple.

    The Animating Outline View

    The outline view is made up of a few classes, the TLDisclosureBar, a subclass of the highly-configurable TLGradientView; the TLCollapsibleView which has a TLDisclosureBar and any NSView you like as its subviews. A TLCollapsibleView itself can be used alone, and will animate the collapse/expansion of the NSView subview (which I term the “detail view”).

    The fun part comes when TLCollapsibleViews are subviews of a TLAnimatingOutlineView. In this case, the TLAnimatingOutlineView takes over all the animations, simply asking the TLCollapsibleView that the user has selected for the NSDictionary object that describes the collapse/expansion animation. With this information, it constructs the movement animations for all the subviews below the collapsing/expanding view and handles the required change of frame size to accommodate the changing content size. It’s all quite elegant, if I do say so myself.

    Not being content with example code, I’ve made sure these classes are real-world useful. This view is integral to BibTeX management in Scribbler so it needs to be good. Some of the relevant parts of the NSOutlineView API are replicated and the delegate of the TLAnimatingOutlineView gets will/did/expand/collapse notifications, along with allowing the delegate to deny/allow animations, too. Each of the TLCollapsibleViews will also ask their detail views if the collapse/expansion is allowed if the TLCollapsibleDetailView protocol is implemented. The TLAnimatingOutlineView itself works when in an NSScrollView.

    The code, along with an example project, is hosted on Google Code here. It is distributed under the new BSD license.

    So why is is not ESAnimatingOutlineView, why the TL namespace? Well, I’m working on something big, at the same time as writing Scribbler. Start guessing.

    Update

    I’ve fixed a few bugs in the code, the current version can be checked out of the repository. Fixes include: proper support for hiding subviews of the TLDisclosureBars when the outline view is resized small, a correction to the autoresizing mask of the TLAnimatingOutlineView itself, declaration of keys that the TLCollapsibleView supplies with the animation dictionaries, the delegate of the outline view and subclasses of TLGradientView are no longer unregistered for notifications that client code specifies (i.e. no longer uses [[NSNotifcationCenter defaultCenter] removeObserver:_delegate];).

     
    • Mark Aufflick 14:38 on October 25, 2008 Permalink | Reply

      So happy to hear about the bibtex support! Oh, the animated views will be nice too, and thanks for sharing the example code.

    • Jonathan Dann 17:52 on October 25, 2008 Permalink | Reply

      Hi Mark,

      Thanks for the encouragement! I’m getting really excited about this app. I just hope that I can get it out asap :)

      Glad you like the sample code too. If you do manage to use it, let me know.

    • Brad Gibbs 17:45 on January 14, 2009 Permalink | Reply

      Thanks for the sample code. It’s been very helpful!

      The sample project failed to compile initially. I changed a #import from Espresso/TLGradientView to TLGradientView and it compiled and ran fine.

      I’m trying to integrate your code into an app. I’ve copied and pasted the AppController class in your sample project to an NSViewController subclass in my project. The app compiles and runs, but crashes when I try to expand or collapse an item. The Debugger stops on this line:

      if (![(id)self.delegate respondsToSelector:@selector(outlineView:shouldCollapseItem:)])

      The sample code I downloaded gives a warning stating that AppController may not conform to the TLAnimatingOutlineViewDelegate protocol. I added to my outline view controller, which shuts up the compiler, but the app still crashes.

      Any thoughts on what I might be doing wrong?

    • Markus 23:45 on August 6, 2009 Permalink | Reply

      Great stuff. Downloaded yesterday and works perfectly. One minor issue is the delegate method names set in -setDelegate: of TLAnimatingOutlineView in TLAnimatingOutlineView.m

      In your version they’re all tied to -outlineViewItemWillExpand:, they should be wired to Did/Will Expand/Collapse. This is the fix:

      - (void)setDelegate:(id )delegate;
      {
      if (_delegate == delegate)
      return;
      [self _removeDelegateAsObserver];
      _delegate = delegate;

      if ([(id)_delegate respondsToSelector:@selector(outlineViewItemWillExpand:)])
      [[NSNotificationCenter defaultCenter] addObserver:_delegate selector:@selector(outlineViewItemWillExpand:) name:TLAnimatingOutlineViewItemWillExpandNotification object:self];
      if ([(id)_delegate respondsToSelector:@selector(outlineViewItemDidExpand:)])
      [[NSNotificationCenter defaultCenter] addObserver:_delegate selector:@selector(outlineViewItemDidExpand:) name:TLAnimatingOutlineViewItemDidExpandNotification object:self];
      if ([(id)_delegate respondsToSelector:@selector(outlineViewItemWillCollapse:)])
      [[NSNotificationCenter defaultCenter] addObserver:_delegate selector:@selector(outlineViewItemWillCollapse:) name:TLAnimatingOutlineViewItemWillCollapseNotification object:self];
      if ([(id)_delegate respondsToSelector:@selector(outlineViewItemDidCollapse:)])
      [[NSNotificationCenter defaultCenter] addObserver:_delegate selector:@selector(outlineViewItemDidCollapse:) name:TLAnimatingOutlineViewItemDidCollapseNotification object:self];
      }

    • Jonathan 08:02 on August 7, 2009 Permalink | Reply

      Excellent, I’ll file it as a TODO :)

    • Dan Pahlajani 01:33 on March 8, 2010 Permalink | Reply

      Hi Jonathan,

      This is really fantastic code you have made available to write cool Cocoa apps and is greatly appreciated.

      I also have a couple of questions. Currently, the views are being setup in the awakeFromNib which is perfect but causes a little flashing from the window opens. Is there way that the views can be set in advance to avoid the flashing?

    • Robert Payne 03:03 on April 30, 2010 Permalink | Reply

      I know this is a relatively old post but great work Jonathan,

      I would like to note when using this code in a multi-window application ( I’m currently using it on every window for a document based application ) there is some huge performance hits when creating more than a single window.

      The TLGradientView adds listeners to the window become active / resign active notifications and send those calls directly to “display” which results in massive performance hits.

      The listeners should instead call [self setNeedsDisplay:YES]; instead of directly invoking the “display” command. This increases performance massively and my application can instead open 20 or so windows before feeling the performance hit that was occuring on the first window open.

      • Jonathan Dann 08:30 on April 30, 2010 Permalink | Reply

        Wow, I remember doing that now but I have no idea what I was thinking. You’re right, of course, -[NSView display] is almost always to be avoided.

    • Robert Payne 08:33 on April 30, 2010 Permalink | Reply

      Pretty easy fix. I was having performance issues for past week or so since I implemented the outline view ( which is AWESOME by the way great job! ) and found it was the outline view itself but it took awhile to find out the problem and then how to fix it directly.

    • Mark Aufflick 23:28 on May 20, 2010 Permalink | Reply

      Hi Jonathon,

      a) there’s a minor display glitch when used in a height adjustable context in that the view can be sized smaller than the clip view and thus when the height is reduced (eg. resizing the window) the view get’s hidden behind grey nothingness. The fix is simple:

      *** tlanimatingoutlineview-read-only/Classes/TLAnimatingOutlineView.m Sun May 16 17:33:10 2010
      — ../cocoa/mine/DailyImageWorkflow/TLAnimatingOutlineView.m Thu May 20 22:20:23 2010
      ***************
      *** 91,96 ****
      — 91,103 —-

      for (TLCollapsibleView *subview in [self subviews])
      newViewFrame.size.height += NSHeight([subview frame]) + [self.delegate rowSeparation];
      +
      + if ([self enclosingScrollView]) {
      + NSSize contentSize = [[self enclosingScrollView] contentSize];
      + if (newViewFrame.size.height < contentSize.height)
      + newViewFrame.size.height = contentSize.height;
      + }
      +
      [self setFrame:newViewFrame];
      }

      b) how far did you get with your image adjust view? IKImageView is killing me!

      c) when is Scribbler coming out?!

      Cheers,

      Mark.

      • Mark Aufflick 23:57 on May 20, 2010 Permalink | Reply

        Also I have a patch for the display/setNeedsDisplay: issue – if you want to add me to the google code project I’ll make both changes. My google code username is “aufflick”.

  • Jonathan Dann 00:00 on October 6, 2008 Permalink | Reply
    Tags: Core Image, Scribbler, vImage   

    Scribbler’s Image Editing Opensourced Part 1 

    Well since I no longer work at the NHS I’ve been working really hard on one of the great features of Scribbler, image editing. As something I wanted to put in at the very start, I was really enthusiastic to start using Apple’s Image Kit. It promised developers the chance to do very little work and still have fully-fledged image management, provided by IKImageBrowser (very good) and image editing thanks to IKImageView. Unfortunately, the latter does not live up to the hype. After battling with it for a while and trying to justify to myself that it would suffice for version 1.0 of Scribbler, it was just way too incomplete, buggy, and damn ugly to leave in. I try to work with the idea that if it bugs me, it’s not good enough.

    Image Loading

    Let me start with IKImageView. It loads images ok, although larger images aren’t loaded nicely: they’re drawn incrementally in a really jarring fashion, even if you pass the view a CGImageRef that’s already in memory.  That being said, it does handle quite a few different types of images, so we give it half a point.

    Image Editing

    The main function of such a view is not for viewing images, but for editing them within the application. Many users want to quickly change an image they’re working with and then get straight back work.  Taking our cues from iPhoto we guess that this editing will take the form of colour adjustments rotating and cropping. If we’re feeling really generous, then we can also include a straightening tool and some zooming (although the latter is relatively superfluous unless we have some sort of pixel-level editing like iPhoto’s red-eye removal or the touch-up tool).

    So we’ve put IKImageView in our app, and loaded an image, we then want to change the brightness and contrast, so we double-click on the image and open up the shared instance of the IKImageEditPanel (left).

      

    Compared to iPhoto’s panel (right), this is ridiculously ugly, has no icons, has an Aqua button at the bottom instead of a properly-rendered HUD button.  The biggest issue: it appears off-screen all the freaking time. Can you imagine editing a bunch of images and having to manually drag the panel to where you want it each time you open the damn thing up? No amount of setting the frame of the window or teaching it to autosave it’s position fix this, and even if we could, the first time you run the app it’s at the bottom of the screen with most of it hidden.

    Lastly, you just try setting a new image in the view and getting the edit panel to do anything anymore, as far as I can tell -reloadData is a no-op, it neither reloads the data for the panel, nor makes you more attractive. The only way to fix this is to close the panel, and reopen it (and then moving it so you can see the controls).

    Rotation

    If we want to rotate the image we (in code) select the IKToolModeRotate mode and we get our onscreen compass:

    The problem with this is two-fold: click on the image at about 3/4 the way up and the rotation compass is drawn outside the bounds of the view; secondly, the user interaction is all wrong. To rotate you click and hold ok the image and move the mouse around in a manner that’s so hard to control it’s useless. Then think about saving the image after a rotation. The view itself has no concept of a canvas, so we can’t save an angled image on a white background, and we can’t arbitrarily decide to ignore the user’s rotation setting an save an un-rotated image (rock – me – hard place). Basically the tool is broken and doesn’t provide useful functionality to users.

    Cropping

    Then we have IKToolModeCrop. “Fantastic!” I hear you cry. “No longer will my users have to open up another app to crop an image, and I won’t have to write that code”. You diligently select a region if the image, then call -setCurrentToolMode: and….

    Nothing. Nada. Zip.

    Reading through the programming guide tells us that Apple have declared the mode and not implemented it (apoordesignersayswhat). So we then have to do it, but can we get the selection rectangle? Of course we can’t! So that nice crop button we made goes to waste, unless you want to subclass, track the mouse, interrupt -drawRect:, apply the crop using core image (note to all that CICrop filter is not a magic bullet), draw a CGImage with the cropped version, then reset the image. No thanks. On it’s own that might be fine, but with all the other rubbish in this class you’re starting to flog a dead horse.

    So that’s why IKImageView will *not* be making an appearance in Scribbler, and if you find it in any other apps then… well… I heard that Windows Photo Viewer Deluxe Family Millennium Media Edition is fantastic.

     
    • David Allen Parizek Jr 20:59 on February 28, 2009 Permalink | Reply

      So what did you turn to instead?

      I am finding I have the exact same dilemma. I am more of a newbie though, and was now attempting to figure out how to do it elsewise by reading Programming with Quartz (Glephman, Laden) to get a clue and then thought I would go hunt for a Cocoa open source project I could mimic code from.

    • David Allen Parizek Jr 21:01 on February 28, 2009 Permalink | Reply

      What is vImage? It is mentioned as a tag, but their are no other posts on this site tagged that way, and no mention of it in the article…

      umm, nevermind, google says:

      http://developer.apple.com/documentation/performance/Conceptual/vImage/Introduction/chapter_1_section_1.html

    • David Allen Parizek Jr 21:19 on February 28, 2009 Permalink | Reply

      This being open source might help someone trying to add image editing features and figure out best way to do it sans IKImageView:

      http://seashore.sourceforge.net/index.php

    • Jonathan 21:20 on February 28, 2009 Permalink | Reply

      Hi David,

      Yeah so my solution is in the works at the moment. As part of Scribbler I’ve written my own image-editing view. As soon as I’m content that it’s working correctly then I’ll open it up.

      vImage is cool.

    • Jonathan 21:23 on February 28, 2009 Permalink | Reply

      The problem with Seashore is the license. GPL is no good to me. When I’m done ESImageView (as it’s called) will be BSD.

    • David Allen Parizek Jr 06:21 on March 1, 2009 Permalink | Reply

      Here we go, sample from apple, it is sweet as far as doing what I need:

      http://developer.apple.com/samplecode/Cropped_Image/index.html#//apple_ref/doc/uid/DTS10000388

    • David Allen Parizek Jr 06:23 on March 1, 2009 Permalink | Reply

      RE: above post, running the sample app is great, not sure how to get the pbx files updated to XCode… XCode does not want to deal with them, but can still look at all the code…

    • David Allen Parizek Jr 06:33 on March 1, 2009 Permalink | Reply

      Ok, it is an old pbx example. To get in to XCode just create new XCode project and add most all of the sample’s files into your new project and it built for me no problem.

    • Jonathan 11:55 on March 1, 2009 Permalink | Reply

      That’s a really interesting example actually, thanks David. I’ve implemented selection and crop in a completely different way, drawing my selection rect over my image with a CGLayer, then using the CGLayer as a mask so I can create a composite CIImage with the area that would be lost in crop processed with a blur filter. I’ll have to have a good look at this and see how well it works for large images.

      Also, all you need to do is change these old .pbproj files to .xcodeproj and xcode will handle them fine :)

      Thanks again, you’ve given me food for thought.

  • Jonathan Dann 22:07 on August 18, 2008 Permalink | Reply  

    Scribbler 

    I’ve been putting off writing about Scribbler for a while because it’s really difficult to put into words properly the ideas I want to convey. I’ve become very attached to my little application since its early inception, not only because of the time I’ve spent, but also for how it has helped me find my creative side. The only reason I haven’t put screenshots up yet is because I’ve been talking with a designer about making the icons, and developing the site and brand of Espresso Served Here (need to catch myself each time I write ‘severed’). They guys I’ve got to do that part of the app, which is completely beyond me, are really talented and I’m getting very excited about having all the artwork finished. As soon as it is ready, I’ll start posting screenshots.

    It was writing my MSc thesis that gave me the desire to write a new LaTeX editor. I decided that I needed an app that understands how people work with large documents. Specifically, people work on projects. Each of these projects can contain many source files: LaTeX source itself, images, BibTeX files and PDFs; and Scribbler knows how to handle them all. You organise your project in Scribbler just like you’d organise your iTunes or iPhoto library, while Scribbler takes care of files on your hard drive. You can make new LaTeX and BibTeX files within Scribbler itself, or simply drag-and-drop a file from any other program to add it to your project.

    When writing, having Scribbler keep track of your project soon shows its advantages over keeping each document separate. To include an image in your LaTeX source, just drop it on the text and Scribbler will write the code for you. You no longer need to care where the image file is in the filesystem, why should you?

    Another plus to this approach comes when writing labels and citations. As Scribbler looks after your project it knows all the \label{} keys you’ve written and will suggest them for you when you type \ref{} (for the LaTeX-uninitiated, that makes cross-referencing very, very easy). The same works for all your citations.

    One of the things I always found myself doing when writing in LaTeX was editing my images so I decided to add some image-editing functionality for common tasks. Scribbler allows you to re-colour, crop, rotate and apply filters to your images, so you only need to open up Pixelmator or Photoshop when you really need to.

    I’m really looking forward to showing off Scribbler to you all, and when you use it I’m sure you’ll agree that creating beautiful LaTeX documents can be done in a beautiful environment. After all, one of the reasons we all use LaTeX is because we care about how things look. I’m working really hard on some features that will blow you away, and I’ll keep-on making it better.

     
    • Mark Aufflick 13:00 on August 20, 2008 Permalink | Reply

      Hi Jonathan, Just heard you on the Mac Developer Roundtable. I’ve just made the switch from emacs for my latex/bibtex work to BibDesk and TexShop.

      I love BibDesk (and have already submitted one patch), but TexShop (and iTexMac2) are kind of lame so I’m very interested in a beautiful (lickable even?) latex application for the mac.

    • Zettt 23:21 on August 22, 2008 Permalink | Reply

      I heard your talk on the developer roundtable, too. Hope that this will be an amazing LaTeX app.
      Best would be to subscribe to your blog to get any news, or not?

    • Jonathan Dann 23:29 on August 22, 2008 Permalink | Reply

      Hi Mark and Zettt,

      Thanks for the comments and the kind words! I’ll be posting more as soon as I can so yeah subscribe to my RSS feed and you’ll be updated as soon as I post more information.

      Lickable? It’s gorgeous :)

    • Zettt 22:21 on August 23, 2008 Permalink | Reply

      I just subscribed. Hopefully there will be a testable beta out soon. How much will it cost?

    • Jonathan Dann 00:37 on August 24, 2008 Permalink | Reply

      Hi Zettt,

      I’m hoping to have a beta ready for testing in October, if there are issues I haven’t come across then the version 1.0 will be a little after that.

      As for price I’m not going to say anything at the moment. I’ll put more details up in the near future, though.

    • Zettt 07:12 on August 24, 2008 Permalink | Reply

      OK, thanks for the information. I’m waiting. ;)

    • Andrew Robinson 10:48 on September 19, 2008 Permalink | Reply

      Hey Jonathan, we met yesterday at IPEM – thought I’d check out your site! Keep my updated on the Scribbler app, sounds like a good piece of kit!

      Andy

    • Jonathan Dann 10:51 on September 19, 2008 Permalink | Reply

      Hi Andy,

      Glad you remembered the name of the site! My Nuclear Med went fine but then the Radiotherapy was awful, he kept interrupting me and then I lost my nerve! How’d your ones go in the end?

    • Andrew Robinson 22:54 on September 19, 2008 Permalink | Reply

      I love coffee so it wasn’t difficult!

      Who was your examiner? My RT went OK but wasn’t amazing, DR went a bit better though, just waiting in the results now…

    • Mark Aufflick 02:46 on October 16, 2008 Permalink | Reply

      How’s that beta coming along? I’m writing some papers at the moment…

      By the way – are you looking at any integration with BibDesk?

    • Jonathan Dann 20:25 on October 16, 2008 Permalink | Reply

      Hi Mark,

      It’s coming along… but a little slower than I hoped. I’ve finished at the NHS now, but that took up all my time the last couple of months, so I’ve fallen way behind my schedule. As soon as I can I’m going to get it out in beta. I just don’t want to release a product where I know that some areas need more attention :) I hope that when it’s done, you’ll like what I’ve come up with.

      As for BibDesk, version 1.0 won’t have integration with it as far as I can see. One of my reasons for this is being able to give the user a seamless experience when it comes to writing a LaTeX document. However, even when Scribbler is managing the bib files in the project, it’s real simple to just edit the bibliography part in BibDesk if the BibTeX editor in Scribbler doesn’t do all you need it to. As the product evolves I’ll add more integration where it’s necessary, though.

      Really glad you’re staying interested with my progress, I’m working as hard as I can now. I want to be able to open up my company with a real bang. :)

    • PC 07:10 on April 23, 2009 Permalink | Reply

      Hi Jonathan, long time no see!

      So what is happening with Scribbler? Did you quite its development or things are just going slow?

      Cheers

    • jay 13:46 on September 7, 2009 Permalink | Reply

      Hey,

      I am wondering what’s going on with scribbler too. It should be a very interesting app.

      Regards, J~

c
compose new post
j
next post/next comment
k
previous post/previous comment
r
reply
e
edit
o
show/hide comments
t
go to top
l
go to login
h
show/hide help
esc
cancel