Tuesday, September 27, 2011

A fishy, a fishy, a fishy, a fish...

My newest adventure in programming has been learning Python and Python's GTK+ bindings through PyGTK. Having barely skimmed the surface of Python before, I'm starting to enjoy programming with it. It not only comes with nearly every library needed "baked in", it has a great set of tools to help you produce valid, well structured (PyLint), and well documented code (docstrings and PyDoc). This adventure has lead to my first GUI app for the *NIX based OSes: Rockfish
I had been using the program Catfish for a GUI based local filesystem search program. The biggest problem I have with it was the way it sorted files by date in the results view. The dates are in the format of MM/dd/yyyy, and when sorting on this column, it sorts them as strings instead of dates
So if you have 3 files sorted by name:
  • bar.txt Last Modified: "01/25/2010"
  • file.txt Last Modified: "03/29/2009"
  • foo.txt  Last Modified: "01/22/2009"
When sorting by date you get:
  • foo.txt  Last Modified: "01/22/2009"
  • bar.txt Last Modified: "01/25/2010"
  • file.txt Last Modified: 03/29/2009"
Instead of the expected:
  • foo.txt  Last Modified: 01/22/2009
  • file.txt Last Modified: 03/29/2009
  • bar.txt Last Modified: 01/25/2010
I often sort files I'm looking for by last modified date, and this was driving me crazy—especially at first when I didn't realize what was happening.

At first I planned on looking at the Catfish code, fixing it to work for me, and then submitting a patch to the developer. However a couple things hit me when I started: not knowing Python, and not understanding GTK and PyGTK bindings. It made my brain hurt to look at the code (even though it is reasonably straight forward and well commented), and as noted on the Catfish page, development has stalled for the project. Given the relatively modest scope of a program like this, I felt it would make a good first app to create (or recreate as the case may be) while learning Python and GTK.

Thursday, July 14, 2011

A pain in my Flash -- Redux

So just when I thought this project was finished. I get the word that part of the presentation's slide controller is not there. From left to right, the controller has the standard previous, pause, and next slide buttons followed by 24 round buttons that let you goto an individual slide.

On my computer whether looking at the presentation by directly loading the file from my hard drive, or viewing it from an html page. I was only seeing 23 of the round buttons. The creation of the flash presentation was subcontracted, so I didn't know what the final product was supposed to look like. On mine it looked fine. The 24th button points to a brief "Thanks for your time" slide which I just thought was part of the 23rd slide.

After viewing the movie on a couple different machines, I could see that the 24th button was part of the movie controller, but it would be cropped on some machines, and not on others when viewing the file directly off a hard drive. It would always be cropped when viewing it from the html files.

After consulting the creator of the flash files, and learning that the presentation's original size is 1280x720px, I set the flash <object> tag width and height attributes to be 1280 and 720, respectively. This produced the same result as before: only 23 buttons showing. I then increased the width attribute by 100, and low and behold I could see the 24th button (along with a good bit of extra white space). I think this cropping issue has to do with a Flash movie's "staging area". If the staging area is the same size as the movie's original width, but and object within the movie is wider than the width of the staging area, then it is cropped from view (at least on Windows XP, and from within web pages--Vista and Win7 would show the object when loading from the hard drive).

Luckily with just a few modifications to my resize code, using the new ratio 720/1335 (I used 1335 for the width as it showed all the 24th button with just a little extra margin), I could see the 24th button and have the flash movie resize to the width of it's container.

Here is the modified code:

function initFlashResize () {
/* add resizeFlash function to the window.resize event for Firefox
* (and other browser's which use the addEventListner method).
*/
var addEvent = false;

if (window.addEventListener){
window.addEventListener('resize', function(){resizeFlash();}, false);
addEvent = true;
} else if (window.attachEvent){
window.attachEvent('onresize', function(){resizeFlash();});
addEvent = true;
}
if (addEvent===true) {
resizeFlash((720/1335));
}
}

function resizeFlash(screenRatio) {
/* Find the width of a parent node to the div holding the flash object,
* and use this value, modified by the desired viewing ratio, to set the
* containing div's height attribute.
*/
if(!screenRatio) {
var screenRatio = (720/1335); // default screen ration for flash movie
}
var parentalNode = document.getElementById('flash_screen').parentNode;
while (parentalNode.offsetWidth === 0) {
parentalNode = parentalNode.parentNode;
}
var divWidth = parentalNode.offsetWidth;
var container = document.getElementById('ob_flash');
container.style.width = (divWidth + 'px');
container.style.height = ((divWidth * screenRatio) + 'px');

container = document.getElementById('flash_screen');
container.style.width = (divWidth + 'px');
container.style.height = ((divWidth * screenRatio) + 'px');
}

I also made slight modifications to the html

<style type="text/css">
div#flash_screen {
margin-left:auto;
margin-right:auto;
padding:0;
width:668px;
height:360px;
border:thin black solid;
}
object#ob_flash {
margin-left:auto;
margin-right:auto;
padding:0;
width:668px;
height:360px;
}
</style>
</head>
<body onload="initFlashResize()">
<div id="flash_screen">
<object id="ob_flash" width="668" height="320" type="application/x-shockwave-flash" data="flash/flash_module.swf">
<param name="movie" value="flash/flash_module.swf" />
<param name="base" value="flash/" />
<param name="quality" value="best" />
</object>
</div>

Monday, July 11, 2011

A pain in my Flash

Another flash job. This time embedding it in a SCORM module. I used the program eXe to create the SCORM module, and it has a nice gui function to add a flash file to your project. Unfortunately I needed the flash object to be re-sizable to the width of it's containing tag, and couldn't figure out how to do this with eXe.

This lead to learning more about embedding flash in html than I really cared to know, but I came out on the other side with much leaner code which validates. A big thanks to The List Apart blog for trimming the fat from my embedding code.

The first part of my journey, was figuring out that it is fairly simple to have flash objects automatically resize themselves. All one has to do is set the width and height attributes of the object and/or embed tags to percentages. This works great, especially for Chrome (and I'm assuming other webkit based browsers, and IE [in quirks mode]), however does not work so great for Firefox. If the tag, lets say a <div> that contains the <object>/<embed> tag, has it's width and height attributes set automatically, and it contains only the flash object whose height and width attributes are set with percentages, then its height and width values will be zero—effectively making the flash object invisible.

Once I realized that I couldn't see my flash object in Firefox when it's width and height values were percentages, I knew it was time for a little help from ECMAscript (known as Javascript to its friends). I would have to hook a ride on the window.resize event and set the flash container's height or width to a non-percentage value. So without further ado, I give you my coded solution:

Put the following javascript in between script tags in the header of your web page, or place in a separate file and link to it.
function initFlashResize () {
/* add resizeFlash function to the window.resize event and set the initial
* width of the flash object.
*/
var addEvent = false;
// the most common method to attach an event to all browsers
if (window.addEventListener){
window.addEventListener('resize', function(){resizeFlash()}, false);
addEvent = true;
} else if (window.attachEvent){
// Attaching event to IE browsers pre version 8
window.attachEvent('onresize', function(){resizeFlash()});
addEvent = true;
}
if (addEvent=true) {
var container = document.getElementById('flash_obj');
container.style.height = "100%";
container.style.width = "100%";
container = document.getElementById('flash_screen');
container.style.width = "auto";
resizeFlash();
}
}
function resizeFlash() {
/* Find the width of a parent node to the div holding the flash object,
* and use this value, modified by the desired viewing ratio, to set the
* containing div's height attribute.
*/
var parentalNode = document.getElementById('flash_screen').parentNode;
while (parentalNode.offsetWidth == 0) {
parentalNode = parentalNode.parentNode;
}
var divWidth = parentalNode.offsetWidth;
document.getElementById('flash_screen').style.height = ((divWidth * 0.66) + 'px');
}


In your html page:
<body onload="initResizeFlash()">
<div id="flash_screen"><object id="flash_obj" type="application/x-shockwave-flash"
data="movie.swf" width="100%" height="100%">
<param name="movie" value="movie.swf" />
</object></div>

Example page