Community Pick: Many members of our community have endorsed this article.

Create a Win7 Gadget with a Flyout Panel

DanRollins
CERTIFIED EXPERT
Published:
This article shows how to make a Windows 7 gadget that extends its U/I with a flyout panel -- a window that pops out next to the gadget.  The example gadget shows several additional techniques:  How to automatically resize a gadget or flyout panel to fit its contents, how to use an ActiveX object in a gadget, and how to use the System.Shell.chooseFile method.
A Gadget with a Flyout PanelIn a previous article, Create a Win7 Gadget, we covered the basics of creating a Windows 7/Vista gadget -- a small application program with an HTML U/I that you can drag from the Win7 Gadget Gallery and drop onto your desktop.  Please read that article, and those listed in the References section below, for background information.  

Flyout Panel
To add a flyout panel, you need only add a line like this to your gadget's main HTML file script:
System.Gadget.Flyout.file = "MyFlyout.html";

Open in new window

The HTML for the flyout panel is nothing special... any collection of input items and display areas.  You will need to provide the script code to support the functionality you want, and you'll most often want to provide an onload handler to run code that should be executed when the flyout opens.

Triggering the Flyout
Unlike with the settings-box handling that we worked with here, the system does not provide a gadget toolbar control to open the flyout.  You must provide a triggering mechanism yourself -- a click, a mouse roll-over, or other activity.  To open the flyout, use code like:
System.Gadget.Flyout.show= true;

Open in new window

It does not require focus or user interaction; for instance, if you create a gadget to remind yourself about the afternoon staff meeting, it could be opened by a window timer.  In that case, I suggest that you use a full-screen layout with big red letters.  The handy System.Sound.playSound() method could be used to crank up some John Phillips Sousa selections, if that's what it takes to wake you up.

Here's the HTML for the today's gadget's main window:

MyGadget.html
<html>
                      <head>
                      <script type="text/javascript" src="common.js"></script>
                      <title="Flyout Gadget Main"></title>
                      <script type="text/jscript">
                      function DoInit() {
                          System.Gadget.Flyout.file = "MyFlyout.html";
                          window.setTimeout("ResizeWindowTo('gadgetDiv');", 1);
                      }
                      function DoClick() {
                          System.Gadget.Flyout.show = true;
                      }
                      </script>
                      </head>
                      <body onload="DoInit();">
                      <div id="gadgetDiv"><table border="5" ><tr>
                      <td><input type=button onclick="DoClick();" 
                          value="Click Me For Flyout!" />
                      </td></tr></table>
                      </div>
                      </body>
                      </html>

Open in new window

Which produces this:
Gadget main window sizes itself to its contents... but only after the magic sequence in line 8.  

Sizing the Window to the Contents
In previous gadget examples, we have set the size of the gadget main window using, for instance:
document.body.style.width = 100;
                      document.body.style.height= 50;

Open in new window

 
And that's probably the normal way to do things.  Setting the size of an HTML document is a technique that's rarely needed when the HTML is displayed by a web browser.  But it's useful in gadgets, which are usually designed to be a specific size.   Anyway, I worked out this sequence of JavaScript to force the document to be sized to fit the contents:

(from common.js)
window.setTimeout("ResizeWindowTo('FlyoutContentDiv');", 1);
                        ... 
                      function ResizeWindowTo(sElemId) {
                          document.body.leftMargin = 0;
                          document.body.topMargin = 0;
                          var oElem = document.getElementById(sElemId);
                          var nHigh = oElem.offsetHeight;
                          var nWide = oElem.offsetWidth;
                          document.body.style.height = nHigh;
                          document.body.style.width = nWide;
                      }

Open in new window

The issue is that HTML elements don't always know their own size, and the offsetHeight property, for instance, is often 0.  But once the element has been rendered, you can read the values and then apply them to the whole window (in this case, document.body).  By using window.setTimeout() as in line 1 above, I give the document a chance to "pre-render" the content, and that lets me get useful measurements a millisecond later.

The Flyout Panel
The HTML for the flyout panel is simple because most of the interesting stuff is in the external .JS file.  Here's the flyout HTML:

MyFlyout.html
<html>
                      <head>
                      <script type="text/javascript" src="common.js"></script>
                      <script>
                      function DoInit() {
                          document.body.style.width = 300; // fixed width, variable height
                          BuildInfoTable();
                          window.setTimeout("ResizeWindowTo('FlyoutContentDiv');", 1);
                      }
                      function CloseFlyout() {
                          System.Gadget.Flyout.show = false;
                      }
                      </script>
                      </head>
                      <body onload="DoInit();">
                      <div id="FlyoutContentDiv">
                      <div align=right><br /><br /> 
                      <input type=button onclick="BrowseForFile();" value="Browse..." />
                      <input type=button onclick="CloseFlyout();" value="Close" />
                      </div><div id="InfoDiv"> please wait... </div>
                      </div>
                      </body>
                      </html>

Open in new window

As before, I have put most of the script code in a separate .JS file.  If you use the Trial-And-Error Design Pattern,  like I do, this makes your task much easier.  The Visual Studio Just-in-Time debugger works best when the script code is in a separate file.

ActiveX and System.Shell Objects
I recently worked on a question here at EE where the asker wanted to know how to get a list of all shell "action verbs" that can be applied to to a particular file.  The System.Shell object that is provided by the gadget runtime environment exposes a lot of functionality, but that's an example of something it can't do.  

However, the COM interface exposed by the shell itself does provide a Verbs() function.  So I decided to use that as an example of using an ActiveX module in a gadget.

common.js
var goVerbs;
                      var gsFile = "c:\\temp\\test.doc";  // for sample purposes
                      
                      // called from DoInit() of MyFlyout.html
                      function BuildInfoTable() {
                          var sFile= gsFile;
                          var nOffset = sFile.lastIndexOf("\\");
                          var sFolder = sFile.substr(0, nOffset);
                          var sFileName = sFile.substr(nOffset + 1);
                          
                          var objShell = new ActiveXObject("Shell.Application");
                          var objFolder = objShell.NameSpace( sFolder );
                          var objFolderItem = objFolder.ParseName(sFileName );
                      
                          var sHtml = "VERBS FOR <b>" + sFile + "</b><br>";
                      
                          if (objFolderItem == null) {
                              sHtml += "FILE NOT FOUND ";
                          }
                          else {
                              goVerbs = objFolderItem.Verbs();
                              sHtml += "<table border='5'  style='font: 10pt Arial'>";
                              for (var j = 0; j < goVerbs.Count; j++) {
                                  var sName = goVerbs.item(j).Name;
                                  sName = sName.replace("&", "");
                                  sHtml += "<tr><td>";
                                  sHtml += sName;
                                  sHtml += "</td>"
                                  sHtml += "<td><input type=button value='DoIt'"
                                  sHtml += "onclick='goVerbs.item(" + j + ").Doit();'/>";
                                  sHtml += "</td></tr>\r\n";
                              }
                          }
                          sHtml += "</table>";
                          document.getElementById("InfoDiv").innerHTML = sHtml;
                      }
                      // an onClick handler used in MyGadget.html
                      function BrowseForFile() {
                          var oShellItem = System.Shell.chooseFile(true, "All Files:*.*::", "C:\\", "");
                          if ( oShellItem == null ) { // user cancelled
                              System.Sound.beep();
                              return;
                          }
                          gsFile = oShellItem.path;
                          DoInit();  
                      }
                      // handy function for gadgets...
                      //
                      function ResizeWindowTo(sElemId) {
                          document.body.leftMargin = 0;
                          document.body.topMargin = 0;
                          var oElem = document.getElementById(sElemId);
                          var nHigh = oElem.offsetHeight;
                          var nWide = oElem.offsetWidth;
                          documillisecondment.body.style.height = nHigh;
                          document.body.style.width = nWide;
                      }

Open in new window

The above code creates an ActiveX object, the Windows Shell object (line 11), which provides the methods I want to excercise.  The code obtains a Folder object and a FolderItem object and cycles through the Verbs collection to list them all.

The script generates the HTML to define a table (lines 22-34), including a command button to execute the verb.  It then populates the <div> from the flyout document with (line 35).  Because the table will vary in length, we again use the "size-to-content" technique to give the flyout panel a dynamic height.

[step=""]Note:  I used a global variable to set the name of the initial file.  If you intend to write a gadget that takes actions related to files and folders, you will probably want to implement drag-and-drop handling.  See Create a Win7 Drop Target Gadget for help with that.[/step]

Closing the Flyout
The flyout panel closes automatically the moment it loses focus.  You can click on the desktop to make it go away.  It can also be closed programmatically, and in the example, I added a "Close" button to show the technique.
System.Gadget.Flyout.show = false;

Open in new window


Summary
In this article, we created self-sizing gadget with a self-sizing flyout panel.  Creating the Flyout involves using the System.Gadget.Flyout object to identify an HTML file and set a mechanism to trigger the display when wanted.

We also looked at how to use both System.Shell (provided by the gadet infrastructure) and the richer Windows Shell COM object to do some exploring of the potential applications for these nifty gadgets.

Resources:

Create a Win7 Gadget  (getting started)

Create a Win7 Maze Gadget

Create a Win7 Drop Target Gadget

System.Shell Object (part of the built-in gadget support)
http://msdn.microsoft.com/en-us/library/ms723241(VS.85).aspx

System.Shell.Item Object
http://msdn.microsoft.com/en-us/library/ms723202(VS.85).aspx

Windows Shell (ActiveX object)
http://msdn.microsoft.com/en-us/library/bb773177(VS.85).aspx

=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
If you liked this article and want to see more from this author,  please click the Yes button near the:
      Was this article helpful?
label that is just below and to the right of this text.   Thanks!
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
3
19,955 Views
DanRollins
CERTIFIED EXPERT

Comments (3)

Commented:
hi Dan, please send the zip file of this gadget.Thanks in advance.
CERTIFIED EXPERT
Author of the Year 2009

Author

Commented:
Rename the attached .ZIP file with an extension of .GADGET and then double-click

Note that this is just a tutorial example and you are expected to make changes (for instance, it expects to see a particular file:  c:\temp\test.doc)

-- Dan
FlyoutTest.zip

Commented:
it is really nice.
thanx a lot Dan.. really really really thank you...

Have a question about something in this article? You can receive help directly from the article author. Sign up for a free trial to get started.