My hobbyist coding updates and releases as the mysterious "Mr. Tines"

Tuesday 16 December 2008

More Silverlight Clock

I could, I suppose, have implemented this project in JavaScript -- that language has all the tools to get the current URL query string and set a permalink to a custom URL, one that wouldn't need clicking, but could be right-clicked; and save the self-inflicted DLR download hit.

If I wanted to, I could put the permalink URL out to an element in the DOM with Silverlight, too, which negates one perceived advantage. And using Silverlight gives me something extra -- multithreading.

Yes, there are JavaScript clocks, like this annoying mouse-following one, but they have to fake such things because they are running full-time in the UI thread. By using a BackgroundWorker to prompt a redraw at intervals (and, later, perform updates on the positions of celestial bodies), with Silverlight, I can offload everything but the painting from the UI thread.

Sunday 14 December 2008

Persisting user settings in Silverlight

Many years ago, the first GUI application I wrote (in X with Motif) was a little orrery-cum-clock thing, with the clock face doubling as a view of the sky, showing the classical planets. Some time in the intermediate past, I thought about doing this as a Java applet, but it never got anywhere, because out on the web, it would have to be settable to the user's geographic location, and I never figured a good way to persist that data between page visits.

Having done the basic tinkering with IronPython and Silverlight to get the two working together, I thought about resurrecting the project. And the first thing to solve is the settings persistence.

But now, I have an easy API to get at the current URL and such via System.Windows.Browser.HtmlPage.Document -- so I can read the values from its query string; and set the values in a hyperlink for bookmarking purposes, thus (app.py):

from System.Windows import Application
from System.Windows.Controls import Canvas
import System
import System.Windows.Browser

xaml = Application.Current.LoadRootVisual(Canvas(), "astroclock.xaml")
xaml.hyperlink.NavigateUri = System.Windows.Browser.HtmlPage.Document.DocumentUri
thisPage = System.Windows.Browser.HtmlPage.Document.DocumentUri.GetComponents(
  System.UriComponents.SchemeAndServer | System.UriComponents.Path,
  System.UriFormat.SafeUnescaped)
query = System.Windows.Browser.HtmlPage.Document.QueryString
  
try:
  xaml.slider1.Value = float(query['lat'])
except:
  pass
try:
  xaml.slider2.Value = float(query['long'])
except:
  pass
 
def latValueChanged(s, e):
  v = xaml.slider1.Value
  if v > 0:
 xaml.label1.Text = "Latitude %.2fN" % (v)
  elif v < 0:
 xaml.label1.Text = "Latitude %.2fS" % (-v)
  else: 
 xaml.label1.Text = "Latitude 0"
 xaml.hyperlink.NavigateUri = System.Uri("%s?lat=%f&long=%f" % (thisPage, v, xaml.slider2.Value))

xaml.slider1.ValueChanged += latValueChanged
latValueChanged(None, None)

def longValueChanged(s, e):
  v = xaml.slider2.Value
  if v > 0:
 xaml.label2.Text = "Longitude %.2fE" % (v)
  elif v < 0:
 xaml.label2.Text = "Longitude %.2fW" % (-v)
  else:
 xaml.label2.Text = "Longitude 0"
 xaml.hyperlink.NavigateUri = System.Uri("%s?lat=%f&long=%f" % (thisPage, xaml.slider1.Value, v))
 
xaml.slider2.ValueChanged += longValueChanged
longValueChanged(None, None)

driving some UI described by (astroclock.xaml)

<Canvas 
  x:Class="System.Windows.Controls.Canvas"
  xmlns="http://schemas.microsoft.com/client/2007"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  x:Name="parentCanvas">
    <Grid>
        <Canvas Name="canvas1" Margin="0,0,0,129" Background="Black" Width="480" Height="240"/>
        <Slider Height="22" Margin="128,0,0,93" Name="slider1" VerticalAlignment="Bottom" Maximum="90" Minimum="-90" Value="52" LargeChange="10" SmallChange="1" Width="360"/>
        <TextBlock Height="28" Margin="0,0,0,87" Name="label1" VerticalAlignment="Bottom" HorizontalAlignment="Left" Width="120">Latitude</TextBlock>
        <TextBlock Height="28" HorizontalAlignment="Left" Margin="0,0,0,62" Name="label2" VerticalAlignment="Bottom" Width="120">Longitude</TextBlock>
        <Slider Height="22" Margin="128,0,0,65" Name="slider2" VerticalAlignment="Bottom" Maximum="180" Minimum="-180" LargeChange="10" SmallChange="1" Width="360"/>
        <HyperlinkButton Height="28" HorizontalAlignment="Left" Margin="0,0,0,17" Name="hyperlink" VerticalAlignment="Bottom" Width="87" NavigateUri="astroclock.html" Content="Permalink" />
    </Grid>
</Canvas>

Evolving implementation here.

Tuesday 2 December 2008

Syntax highlighting

Following on from Scott Hanselman's post about the SyntaxHighlighter script, here's the secret sauce I needed to get it to work.

The separate hosting is the easy bit -- the trick was getting the code I needed to run the repainting into a window.onload, and to keep Blogger from mutilating the code by use of a CDATA section.

Et voilà!

<link href='.../SyntaxHighlighter.css' rel='stylesheet' type='text/css'/>
<script src='.../shCore.js' type='text/javascript'/>
<script src='.../shBrushPython.js' type='text/javascript'/>
<script src='.../shBrushRuby.js' type='text/javascript'/>
...
<script type='text/javascript'>//<![CDATA[
window.onload = function () {
    dp.SyntaxHighlighter.ClipboardSwf = ".../clipboard.swf";
    dp.SyntaxHighlighter.BloggerMode();
    dp.SyntaxHighlighter.HighlightAll("code",true,false,false,1,false);
}
//]]></script>

There is also a Scala brush for this -- but F# or Erlang will need to be hand-cranked first.

Later: hand cranking done & linked.