Keilly

Wednesday, November 27, 2013

Fuzzy Remote Desktop / VNC with Retina Display

When viewing remote content on a retina display, it may appear fuzzier than when viewed on a non-retina display.
This is counter intuitive, after all the retina display is the ultimate in resolution no?
However it makes sense when you think about it as the machine doing the rendering of the text knows nothing about the retina display, so renders as usual for a regular one - doing antialiasing to smooth out the edges of text. The remote desktop/vnc app running on the local machine then takes that remote image and it must scale it up to fill the same physical area on the screen. So it doubles it and anti-aliases it again to smooth edges of shapes. It's this double anti-aliasing that makes text blurrier rather than smoother....

VNC viewed on a regular display:


VNC viewed on a retina display:

There is a general solution...

In Finder go to Applications, find the Remote/VNC program, right click and "Get Info".

Check on the "Open in Low Resolution", and things should be nice and crisp the next time it is launched.


Monday, June 17, 2013

Preferred Height of JTextComponents

Given some text and a text component (e.g. JTextArea), it is not obvious how to set the preferred size of the component to only show the current content.
Skip to Answer

This:
     JTextArea ta = new JTextArea();  
     ta.setLineWrap(true);  
     ta.setText("112 312 3 12 31 2432135r34534t 3 t3 4t34y4hthefbasdgagaergergwreg"  
         + "rwergerg ergergergefdav asdvsadg sadgsad gsdgsdgsadgsgd sdgsdg"  
         + "sdg sdgsdgsdg sdgsdgsdgsgh4hgaregwaegasdg sdgsdg sagae4gsaegs "  
         + " sdgsdg sdg s gs dg sd gs dg sdg sdg sadgsdg sad gsa dg s"  
         + "se gs eg se g saeg sa eg s eg sa eg e g eg aweg");  
     JScrollPane sp = new JScrollPane(ta);  
     System.out.println("TextArea Pref Size: " + ta.getPreferredSize());  
     System.out.println("ScrollPane Pref Size: " + sp.getPreferredSize());  

Gives:
TextArea Pref Size: java.awt.Dimension[width=100,height=16]
ScrollPane Pref Size: java.awt.Dimension[width=104,height=20]

The layout manager follows the preferred sizes and it looks like this:


Lets say we want a preferred width of 300, what do we put for the preferred height?
We can't put in an arbitrary preferred height and hope Swing will trim it down, instead it just obeys what we tell it:

     ta.setPreferredSize(new Dimension(300, 100000));

TextArea Pref Size: java.awt.Dimension[width=300,height=10000]
ScrollPane Pref Size: java.awt.Dimension[width=304,height=10004]




So the trick is to get Swing to calculate the height for a given width and text...

We're told never to user setSize() methods on components, we should let the layout manager set the size, we should always use setPreferredSize().
This is an exception, if we set our actual width and also pass an arbitrary and very large height: Swing will automatically set the preferred size to suit only the text at our given width. All the extra height will be ignored.

     JTextArea ta = new JTextArea();  
     ta.setLineWrap(true);  
     ta.setText("112 312 3 12 31 2432135r34534t 3 t3 4t34y4hthefbasdgagaergergwreg"  
         + "rwergerg ergergergefdav asdvsadg sadgsad gsdgsdgsadgsgd sdgsdg"  
         + "sdg sdgsdgsdg sdgsdgsdgsgh4hgaregwaegasdg sdgsdg sagae4gsaegs "  
         + " sdgsdg sdg s gs dg sd gs dg sdg sdg sadgsdg sad gsa dg s"  
         + "se gs eg se g saeg sa eg s eg sa eg e g eg aweg");  
     JScrollPane sp = new JScrollPane(ta);  
     ta.setSize(300, 100000); // desired width, but deliberately large height.  
     System.out.println("TextArea Pref Size: " + ta.getPreferredSize());  
     System.out.println("ScrollPane Pref Size: " + sp.getPreferredSize());  


TextArea Pref Size: java.awt.Dimension[width=300,height=112]
ScrollPane Pref Size: java.awt.Dimension[width=304,height=116]


Look, the component has been sized to exactly match our text at our preferred width!

Use textComponent.setSize(preferredWidth, 1000000)to set a preferred size for text components.

Saturday, October 24, 2009

Listen Again - Last Broadcast

Looks like the ListenAgain widget has played it's last tune.

The widget works by gathering the radio programme information from the iPlayer website. Sometimes the BBC changes the layout of the iPlayer site slightly forcing me to tweak the widget to adapt to the new layout. Unfortunately this time it looks like the changes were much larger, at least internally, and I can't seem to find the URL for the Real Audio stream of each programme. In fact it doesn't look like they use Real Audio at all anymore - only Flash.

This spells the end for the widget I think, from now on you'll have to listen directly with iPlayer.

Thursday, October 15, 2009

MyCaltrain back on sale!

I've reposted the MyCaltrain iPhone app to the app store and updated the schedule due to popular request - depending on your definition of popular - it's currently undergoing Apple review and if it passes it should be available in a few days.

If you like it, please take the time to give it a nice review.

Thanks,
Neil.

Wednesday, September 9, 2009

MyCaltrain Source Code

If you'd like to have a go at updating the Caltrain widget to the new schedule, then here's the source code.
The schedules are stored in the app as text files which were created by cut and pasting the timetable from a page on Caltrain's website.
As long as the text file format is the same, you should be able to do the update, rebuild and test.

The source code is licensed under the GPL.

Let me know if you get something working.

Sunday, August 30, 2009

MyCaltrain removed from sale


The Caltrain schedule undergoes a revision this week, as the app isn't up to date I am withdrawing it from sale to prevent confusion for riders.
As I currently don't ride Caltrain, and because the app is given away for free, I can't justify spending time on this project anymore - so I currently have no plans to update it and bring it back.
Thanks to everyone who used the app and liked it, especially the guy who gave it the stella review.

If you like the app and fancy a bit of iPhone development I am more than willing to send or post the code so you can update it and put it back up for (free) distribution. Please email me or post a comment if interested.

Sunday, April 26, 2009

Listen Again v3.5



Listen to the large archive of recent BBC Radio programmes directly from Dashboard.

Currently supports: Radio 1, 1xtra, Radio 2, Radio 3, Radio 4, 5 live, 5 extra, 6 Music, 7, Asian Network, Radio Scotland, Radio Ulster, Radio Wales, and all local radio. 55 stations in total.

Requires RealPlayer 10.1
Update, RealPlayer 11 doesn't play when Dashboard is hidden. Use RealPlayer 10.1

Download BBCListenAgain Widget

Shortcut Keys:
Space - Play/Pause
Up/Down - Volume
Left/Right - Skip
s - Stop
v - Voiceover feedback
p - Focus on station popup

What's new:
3.5
- Fixed to work with another iPlayer change
- Added local radio (55 stations in total)

3.4
- Fixed to work with another iPlayer change
- Fixed 'Listen Live'

3.33
- Fixed to work with another iPlayer change
- Added auto update mechanism
- Pressing the 'v' key will enable additional spoken feedback.

3.31
- Descriptions of programmes fixed (broken due to BBC slightly rearranging their iPlayer content)

3.3
- Works with new BBC iPlayer website
- Accessibility: Voiceover use is detected and certain actions are spoken if turned on.
- Better font resizing
- Busy feedback

This has been developed and tested on Mac 10.5

VoiceOver users: when selecting stations use VoiceOver keys with the arrows to select the station from the menu.

Troubleshooting:
Try and play directly from the BBC website. If it works there then it will almost certainly work in Dashboard. If not the problem has historically been issues with RealPlayer - try uninstalling and reinstalling RealPlayer using the version from the BBC website. Reboot after the reinstall to restart Dashboard.

Let me know any other problems.

Mac OS X 10.4 Tiger is required. If you're using Safari, click the download link. When the widget download is complete, Show Dashboard, click the Plus sign to display the Widget Bar and click the widget's icon in the Widget Bar to open it. If you're using a browser other than Safari, click the download link. When the widget download is complete, unarchive it and place it in /Library/Widgets/ in your home folder. Show Dashboard, click the Plus sign to display the Widget Bar and click the widget's icon in the Widget Bar to open it.

Sunday, November 30, 2008

Listen Again v3.4



Update: Widget currently broken due to BBC iPlayer update. Hope to get a fix soon....

Listen to the large archive of recent BBC Radio programmes directly from Dashboard.

Currently supports: Radio 1, 1xtra, Radio 2, Radio 3, Radio 4, 5 live, 5 extra, 6 Music, 7, Asian Network, Radio Scotland, Radio Ulster, Radio Wales

Requires RealPlayer 10.1
Update, RealPlayer 11 doesn't play when Dashboard is hidden. Use RealPlayer 10.1

Download BBCListenAgain Widget

Shortcut Keys:
Space - Play/Pause
Up/Down - Volume
Left/Right - Skip
s - Stop
v - Voiceover feedback
p - Focus on station popup

What's new:
3.4
- Fixed to work with another iPlayer change
- Fixed 'Listen Live'

3.33
- Fixed to work with another iPlayer change
- Added auto update mechanism
- Pressing the 'v' key will enable additional spoken feedback.

3.31
- Descriptions of programmes fixed (broken due to BBC slightly rearranging their iPlayer content)

3.3
- Works with new BBC iPlayer website
- Accessibility: Voiceover use is detected and certain actions are spoken if turned on.
- Better font resizing
- Busy feedback

This has been developed and tested on Mac 10.5

VoiceOver users: when selecting stations use VoiceOver keys with the arrows to select the station from the menu.

Troubleshooting:
Try and play directly from the BBC website. If it works there then it will almost certainly work in Dashboard. If not the problem has historically been issues with RealPlayer - try uninstalling and reinstalling RealPlayer using the version from the BBC website. Reboot after the reinstall to restart Dashboard.

Let me know any other problems.

Mac OS X 10.4 Tiger is required. If you're using Safari, click the download link. When the widget download is complete, Show Dashboard, click the Plus sign to display the Widget Bar and click the widget's icon in the Widget Bar to open it. If you're using a browser other than Safari, click the download link. When the widget download is complete, unarchive it and place it in /Library/Widgets/ in your home folder. Show Dashboard, click the Plus sign to display the Widget Bar and click the widget's icon in the Widget Bar to open it.

Thursday, November 20, 2008

MouseEvents for non-rectangluar components in Swing

Warning: Swing hack ahead!

In Swing component bounds are defined as x,y,width,height, i.e. rectangular.

Also in Swing it's very hard to trap mouse events only for a particular section of a component. Sure we can test in our mouse listener if the location of the event is in a particular section, but this isn't always good enough because the mere act of receiving a mouse event means that the parents of that component never get a crack at processing the event. (See here).

This means that in Swing it is very difficult to simulate non-rectangular components.

Consider the resize grip area in this custom text area:

Although it looks triangular, the grip is actually a (rectangular) component layered in front of the text area. We want the user to be able to grab the grip and drag to resize, but also click in the non-grip area and interact directly with the text field.

This is what we have by default:


This is what we want:


Visually its easy to split into two: make the component non-opaque and paint the corner section with some grip graphics in the paintComponent method - letting the parent show through in the unpainted corner.

However event-wise there's no API to split a component into responsive and non-responsive areas. It would be nice for example if JComponent.processMouseEvent call returned a boolean indicating if the event was actually processed. It doesn't, so we have to hack in a fix.

Luckily Component.getCursor() is continually polled as the mouse cursor moves over a component. Overriding this we can detect where the mouse location is over our grip area and act accordingly.
If it's over the visible grip area we can add a mouse listener and start receiving events, if it's over the transparent area we remove the listener and the events are automatically routed to the parent.

Here's the code for the grip:

public Cursor getCursor(){
PointerInfo info = MouseInfo.getPointerInfo();
Point p = info.getLocation();
SwingUtilities.convertPointFromScreen(p, this);

// Test if in the visible area
if (p.x+p.y > getHeight()){
if (!Arrays.asList(getMouseListeners()).contains(ml))
addMouseListener(ml);

return Cursor.getPredefinedCursor(
Cursor.SE_RESIZE_CURSOR);
}

// In the transparent area, stop listening
if (Arrays.asList(getMouseListeners()).contains(ml))
removeMouseListener(ml);

return super.getCursor();
}

Of course you can make the location test as complex as you like creating components of any shape.

Sunday, September 14, 2008

Word Check iPhone App

A version of the Word Checker App is now available for the iPhone and iPod Touch (Now called "Word Check". Grab it from the iTunes App Store and never have to carry a dictionary for Scrabble, Boggle, crosswords or any other kind of word game.

24-Dec-08 - I can now give out free promo copies of the application. Just email me your email address and I'll send you a code for a free copy. Just promise to leave an honest review (hopefully nice) in the iTunes store - Keilly

08-Oct-08 - A new version of the The Word Checker App has just been released. It sports the following new features:
- Anagram/Bingo Finder
- Crossword Helper
- New everyday English dictionaries.
- Huge Speed Increase.

A whopping 99c from the iTunes App store, or free upgrades for existing users. Search for "Word Check" in the iTunes Store.

  

Saturday, August 30, 2008

Listen Again v3.33



Listen to the large archive of recent BBC Radio programmes directly from Dashboard.

Currently supports: Radio 1, 1xtra, Radio 2, Radio 3, Radio 4, 5 live, 5 extra, 6 Music, 7, Asian Network, Radio Scotland, Radio Ulster, Radio Wales

Requires RealPlayer 10.1
Update, RealPlayer 11 doesn't play when Dashboard is hidden. Use RealPlayer 10.1

Download BBCListenAgain Widget

Shortcut Keys:
Space - Play/Pause
Up/Down - Volume
Left/Right - Skip
s - Stop
v - Voiceover feedback
p - Focus on station popup

What's new:
3.33
- Fixed to work with another iPlayer change
- Added auto update mechanism
- Pressing the 'v' key will enable additional spoken feedback.

3.31
- Descriptions of programmes fixed (broken due to BBC slightly rearranging their iPlayer content)

3.3
- Works with new BBC iPlayer website
- Accessibility: Voiceover use is detected and certain actions are spoken if turned on.
- Better font resizing
- Busy feedback

This has been developed and tested on Mac 10.5

VoiceOver users: when selecting stations use VoiceOver keys with the arrows to select the station from the menu.

Troubleshooting:
Try and play directly from the BBC website. If it works there then it will almost certainly work in Dashboard. If not the problem has historically been issues with RealPlayer - try uninstalling and reinstalling RealPlayer using the version from the BBC website. Reboot after the reinstall to restart Dashboard.

Let me know any other problems.

Mac OS X 10.4 Tiger is required. If you're using Safari, click the download link. When the widget download is complete, Show Dashboard, click the Plus sign to display the Widget Bar and click the widget's icon in the Widget Bar to open it. If you're using a browser other than Safari, click the download link. When the widget download is complete, unarchive it and place it in /Library/Widgets/ in your home folder. Show Dashboard, click the Plus sign to display the Widget Bar and click the widget's icon in the Widget Bar to open it.

Sunday, August 17, 2008

ListenAgain 3.31



Update: It seems the BBC have changed the format of their iPlayer pages again, causing the widget to not be able to play any of the streams. Look out for version 3.32 shortly

An upgrade to BBC ListenAgain. Programmes had started to disappear from the 3.2 version as the BBC moved its ListenAgain archive to its new iPlayer. This version of the widget restores those programmes.

What's new:
3.31
- Descriptions of programmes fixed (broken due to BBC slightly rearranging their iPlayer content)

3.3
- Works with new BBC iPlayer website
- Accessibility: Voiceover use is detected and certain actions are spoken if turned on.
- Better font resizing
- Busy feedback

This has been developed and tested on Mac 10.5

VoiceOver users: when selecting stations use VoiceOver keys with the arrows to select the station from the menu.

Requires RealPlayer 10.1
Update, RealPlayer 11 doesn't play when Dashboard is hidden. Use RealPlayer 10.1

Download BBCListenAgain Widget

For blind users there's also an experimental version that gives extra speech feedback if voice over is turned on.Download VoiceOver Version

Troubleshooting:
Try and play directly from the BBC website. If it works there then it will almost certainly work in Dashboard. If not the problem has historically been issues with RealPlayer - try uninstalling and reinstalling RealPlayer using the version from the BBC website. Reboot after the reinstall to restart Dashboard.

Let me know any other problems.

Mac OS X 10.4 Tiger is required. If you're using Safari, click the download link. When the widget download is complete, Show Dashboard, click the Plus sign to display the Widget Bar and click the widget's icon in the Widget Bar to open it. If you're using a browser other than Safari, click the download link. When the widget download is complete, unarchive it and place it in /Library/Widgets/ in your home folder. Show Dashboard, click the Plus sign to display the Widget Bar and click the widget's icon in the Widget Bar to open it.

Wednesday, July 30, 2008

ListenAgain 3.3


An upgrade to BBC ListenAgain. Programmes had started to disappear from the 3.2 version as the BBC moved its ListenAgain archive to its new iPlayer. This version of the widget restores those programmes.

What's new:

- Works with new BBC iPlayer website
- Accessibility: Voiceover use is detected and certain actions are spoken if turned on.
- Better font resizing
- Busy feedback

This has been developed and tested on Mac 10.5

VoiceOver users: when selecting stations use VoiceOver keys with the arrows to select the station from the menu.

Requires RealPlayer 10.1 Update, RealPlayer 11 doesn't play when Dashboard is hidden. Use RealPlayer 10.1

Download

For blind users there's also an experimental version that gives extra speech feedback if voice over is turned on. Mileage varies from machine to machine Download VoiceOver Version

Troubleshooting:
Try and play directly from the BBC website. If it works there then it will almost certainly work in Dashboard. If not the problem has historically been issues with RealPlayer - try uninstalling and reinstalling RealPlayer using the version from the BBC website. Reboot after the reinstall to restart Dashboard.

Let me know any other problems.

Mac OS X 10.4 Tiger is required. If you're using Safari, click the download link. When the widget download is complete, Show Dashboard, click the Plus sign to display the Widget Bar and click the widget's icon in the Widget Bar to open it. If you're using a browser other than Safari, click the download link. When the widget download is complete, unarchive it and place it in /Library/Widgets/ in your home folder. Show Dashboard, click the Plus sign to display the Widget Bar and click the widget's icon in the Widget Bar to open it.

Wednesday, June 11, 2008

Creating a Swing Dashboard Widget - Summary

So the original intention was to create a Dashboard style widget UI using Swing.

In nine fairly simple steps we've gone from a blue square:



...to a nice looking widget that hopefully looks at home on the modern Desktop:



The only shortcut I took was not to pull out the maths book and write my own transform filter.

I'm very pleased with the result, it was a lot easier than I thought it would be. Hopefully this exercise proves (again) that Swing can be more than just a boring, gray, toolkit suitable for boring, gray, form-filling applications.
The new transparency features especially allow vibrant, modern looking UI's that are relatively simple and quick to create.

So that's really it for the UI.

A few non-UI remarks...

Java widgets have a number of benefits over other widgets systems:
- No framework or widget manager needed
- Platform independent
- Installed from a web-page
- The extensive JDK library available as standard
- Sandboxed and secure automatically
- Familiar language with powerful UI toolkit
- Customizable, fast, accelerated painting (try that in Javascript)

There are still a few non-UI things to do before making this code truly useful: preferences and desktop startup spring immediately to mind.

Performance is also an issue. On my machine the two widgets take about 20 MB of RAM each and 0 CPU cycles when just sitting there. 20MB is considerably more than a simple Widget in Apple's Dashboard for example.
However, in modern machines with RAMs of 1GB+ as standard, and depending who you're asking, maybe this is an increasingly unimportant issue. Especially if the widget is useful.

Feel free to use the Source Code. Don't forget you'll need the filters classes from JHLabs.

Source Code Download

Tuesday, June 10, 2008

Creating a Swing Dashboard Widget - Part 9 (Examples)

So the widget code is beta complete. With some tidying and refactoring it's time to create some simple examples.

Clock Widget Launch
Weather Widget Launch
(Systems other than OSX* require Java 6 update 10)



With the widget specific code pushed into a base class, these two examples just needed code to gather some information and paint themselves: About 100 lines each.

ClockWidget Code:These examples are just a taste of what's possible, rather than meant be really useful as working widgets - e.g. the weather widget is hard coded to San Francisco and could do with some better graphics.
They also illustrate one real advantage over traditional Javascript widgets in the use of the familiar libraries which are shipped as part of the base JDK. The weather reads an Yahoo XML feed and the clock uses a date formatter, both easily done in Java with no external libraries to download, license, ship, or understand.

Source code and summary next.

*I managed to fix the earlier OSX rendering problems by explicitly clearing the graphics before each frame. The widgets will now run on OSX with no additional downloads (Java 1.5).

Wednesday, June 4, 2008

Creating a Swing Dashboard Widget - Part 8 (Close Animation)

To prove that its possible to produce, fairly easily, and faithful interpretation of a UI it's important to get the little touches right.

When I added the close button I mentioned that the close action has a nice swoosh animation as the widget is removed but conveniently didn't implement it.

So I took a shot, and it actually it wasn't too bad.

There's already the basis for it:
- The code that is used in the flipping animation snaps an image of a component and transforms it.
- The marvelous Filter library from JHLabs provides various image distortion filters, or if you want to use no libraries and are good at matrix maths then roll your own BufferedImageOp )

I factored out the general component animation from the flipping animation code to create a simple framework that can visually filter a component over time - just supply the distortion or adjustment.

Using the Image Processing Editor I tried out different filters with different setting. It looks like Dashboard is using a Pinch filter to distort the widget away to nothingness.

The distortion code is quite small: use a pinch filter and gradually adjust the pinch amount and radius over time (once per timerTick()). The same image is painted every few milliseconds, and using this filter it displays the animation.
Oh, and the widget should fade over time too, so gradually reduce the alpha:

Sccchhhuuuupppppppp.....


Webstart the demo (Java 6 update 10 is needed or it'll look funny). Hold 'Alt' to get the close button to appear.

Tuesday, June 3, 2008

Creating a Swing Dashboard Widget - Part 7 (Moving)

Widgets can be moved around by clicking almost anywhere their surface and dragging.
OSX provides this by default when the window decoration is turned off. On Windows a mouse listener has to be attached directly to the widget, and some simple repositioning code added.

With this, and some other tidying up, a demo of progress up till now is possible.

Remember you'll need the Java 6 update 10 for this to work properly. Anything less certainly won't do the transparency and will look poor.

OSX will run it but, as there's no Java 6 update 10 to try, you'll see bad transparency rendering issues (still worth a look though). I still hope the transparency can be fixed without using an additional external library.
Also the font alignment is frustratingly different on different platforms, making the 'Done' and 'i' text buttons look poor on OSX, but this will be fixed [at the cost of writing more code].

Launch Demo

Monday, June 2, 2008

Creating a Swing Dashboard Widget - Part 6 (Flipping)

When the info button is pressed the widget should flip over to reveal the back.
Using a flippable component to hold a blue front and green back, and hooking it up to the info button gives a very nice flipping transition, but with horrifying artifacts on OSX:



Also, on Windows the corners of the widget aren't transparent as expected:



After a little struggling I found that on Windows JPanels were causing the corner painting problem. Although marked as non-opaque their backgrounds were still being cleared to white every repaint! Turning off double buffering by passing false in the JPanel constructor fixed this:



OSX problems remain unresolved for now.

Sunday, June 1, 2008

Creating a Swing Dashboard Widget - Part 5 (Info Button)

Widgets have an info button which when pressed flips the widget over to the back so the user can edit their preferences.

It has a number of visual states:
- usually invisible
- when cursor is over the widget the 'i' fades in.
- when the cursor is over the button a background appears

Changing the state of the button's ButtonModel as the mouse cursor moves over various code is simple. The painting code looks at the model to decide what to paint.
Fading is more tricky, especially as the TimingFramework isn't integrated into the JDK.
So I just used a straight forward Swing Timer that varies the alpha value of the button 'i'. When the state changes the timer is kicked off, and for every timer beat the painting transparency is slightly altered until it's either completely transparent or completely opaque.
It would have been better to use a curve rather than the liner adjustment.


So now I have this: