Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Beginning Mac OS X Tiger Dashboard Widget Development (2006)

.pdf
Скачиваний:
17
Добавлен:
17.08.2013
Размер:
9.7 Mб
Скачать

Adding to the Widget Interface

document.getElementById(“backgroundImage”).width = x; document.getElementById(“backgroundImage”).height = y;

// resize the widget window.resizeTo(x,y);

event.stopPropagation();

event.preventDefault();

}

// called after the mouse button is released function mouseUp(event) {

//stop tracking the move document.removeEventListener(“mousemove”, mouseMove, true);

//and notify if the mouse goes down again document.removeEventListener(“mouseup”, mouseUp, true);

event.stopPropagation();

event.preventDefault();

}

// called when the widget loads function setup() {

}

Try It Out

Relative Resizing with a Single Panel

In addition to creating a tiled version of your widget background for resizing, you can also use a single background panel and resize it. The additions to your files are basically the same, but you have fewer pieces to keep track of and less code to accomplish the same effect.

1.Create a single panel background for your widget (Figure 8-9). You can also create a backside.png for the reverse side of your widget.

Figure 8-9

2.Create a resize.html file similar to the tiled version above. Include the links for the resize.png thumb image and the mouseDown(event).

141

Chapter 8

<html>

<head>

<style type=”text/css”> @import “resize.css”;

</style>

<script type=’text/javascript’ src=’AppleClasses/AppleInfoButton.js’ charset=’utf-8’ />

<script type=’text/javascript’ src=’AppleClasses/AppleAnimator.js’ charset=’utf-8’ />

<script type=’text/javascript’ src=’AppleClasses/AppleButton.js’ charset=’utf- 8’ />

<script type=”text/javascript” src=”resize.js” charset=”utf-8”></script> </head>

<body onload=”setup();”> <div id=”front”>

<img id=”backgroundImage” src=”Default.png”> <div id=”title”>

resize </div>

<div id=”resize” onMouseDown=”mouseDown(event);”> <img id=”resizeThumb”

src=”/System/Library/WidgetResources/resize.png”></img>

</div>

</div>

<div id=”back”> </div>

</body>

</html>

3.Create a resize.css file with the selector for the resize control and the control rectangle.

body { margin:0;

}

/* widget front */

#front {

position: absolute; top: 0px;

left: 0px; width: 170px; height: 170px; display: block;

text-align: center;

}

#title {

font: 12px “Helvetica Neue”; color: white;

position: absolute;

142

Adding to the Widget Interface

top: 10px; left: 65px;

}

#resize {

position: absolute; /*bottom: 22px; right: 18px;*/ bottom: 24px; right: 24px; width: 12px; height: 12px; z-index: 2;

-apple-dashboard-region: dashboard-region(control rectangle 0px 0px 0px 0px);

}

/* widget back */

#back { display: none;

}

4.Add the handlers to the JavaScript file for dealing with the user’s dragging of the resize box.

//tracks where the last mouse position was throughout the drag

var resizeInset;

//the right offset of the grow thumb vs. the edge of widget window var rightEdgeOffset;

//the bottom offset of the grow thumb vs. the edge of widget window var bottomEdgeOffset;

//called when the mouse first clicks upon the resize

function mouseDown(event) {

//begin tracking the move document.addEventListener(“mousemove”, mouseMove, true);

//and notify when the drag ends document.addEventListener(“mouseup”, mouseUp, true);

//resizeInset tracks where the actual mouse click happened vs. the right and

//bottom edges of the widget

resizeInset = {x:(window.innerWidth - event.x), y:(window.innerHeight - event.y)};

event.stopPropagation();

event.preventDefault();

}

// called as the mouse button is down and the mouse moves function mouseMove(event) {

//x and y track where bottom-right corner of the widget should be, with relation

//to the event.

143

Chapter 8

var x = event.x + resizeInset.x; var y = event.y + resizeInset.y;

//an arbitrary minimum width if(x < 105)

x = 105;

//an arbitrary minimum height if(y < 37)

y = 37;

//an arbitrary maximum width if(x > 210)

x = 210;

//an arbitrary maximum height if(y > 210)

y = 210;

//resize background document.getElementById(“front”).style.width = x; document.getElementById(“front”).style.height = y; document.getElementById(“backgroundImage”).width = x; document.getElementById(“backgroundImage”).height = y;

//resize the widget

window.resizeTo(x,y);

event.stopPropagation();

event.preventDefault();

}

// called after the mouse button is released function mouseUp(event) {

//stop tracking the move document.removeEventListener(“mousemove”, mouseMove, true);

//and notify if the mouse goes down again document.removeEventListener(“mouseup”, mouseUp, true);

event.stopPropagation();

event.preventDefault();

}

// called when the widget loads function setup() {{

}

5.Create an info.plist file to make the widget work.

<plist version=”1.0”> <dict>

<key>BackwardsCompatibleClassLookup</key>

<true/>

<key>CFBundleDisplayName</key>

<string>resize</string>

<key>CFBundleIdentifier</key>

<string>com.deadtrees.widget.resize</string>

144

Adding to the Widget Interface

<key>CFBundleName</key>

<string>resize</string>

<key>CFBundleShortVersionString</key>

<string>1.0</string>

<key>CFBundleVersion</key>

<string>1.0</string>

<key>CloseBoxInsetX</key>

<integer>13</integer>

<key>CloseBoxInsetY</key>

<integer>13</integer>

<key>MainHTML</key>

<string>resize.html</string>

</dict>

</plist>

6.Add the AppleClasses folder for backward compatibility.

7.Drop the files in a folder, rename it Resize.wdgt, and then install the widget.

What you’ll notice immediately from this example is that the amount of code required for resizing is noticeably smaller than that required for the tiled version of the widget. As stated earlier, how you decide to create the widget background for resizing is a matter of personal preference, but you have to track fewer details and pieces when the widget is constructed from a single panel. That also means this version is easier to debug.

Moving the Close Box

The location of the close box is an issue whether widgets are resizable or not. If you have widgets tightly packed on your screen, when you try to click the close box of one, you may be showing the close box on another (Figure 8-10) if the close box hasn’t been properly placed.

Figure 8-10

In situations where you have your widgets overlapping (of course that never happens), you’ll experience dueling close boxes. As you try to close one, the other one will flash. This may cause you to accidentally close the wrong widget — an annoying event that you want to avoid.

The improper placement of the close box can become even more pronounced when the widget is being resized. As the widget’s size changes, the placement of the close box may need to be moved. Dashboard has a setCloseBoxOffset(x,y) method that allows you to adjust dynamically where the close box is situated.

145

Chapter 8

The x and y in the method are the coordinates that you give Dashboard and place the close box relative to the top-left corner of the widget. If, for example, you give it the values (0,0), Dashboard places the center of the close box over the widget’s top-left corner. Here is an example of the setCloseBoxOffset(x,y) method used in Apple’s Weather widget.

if (lastTopOffset != topOffset || lastLeftOffset != leftOffset)

{

// 13 and 10 are the hardcoded start offsets widget.setCloseBoxOffset (leftOffset + 13, topOffset+10); widget.setPositionOffset (leftOffset, topOffset);

}

Now that you see how to add resizing to your widget, let’s turn our attention to another way that you can display more information for the user.

Scrolling

Another way that you can provide the user with more information than what fits within your widget is to add scrolling. If you are displaying text or lists, this allows you to maintain a minimum size for your widget while still accommodating dynamic information.

When to Add Scrolling

You add scrolling to your widget for the same reasons that you add resizing: the information that you want to display in the widget is dynamic and larger than the widget.

You may have noticed that widgets for RSS feeds can be resized and also have a scroll bar. This is the maximum flexibility that you can give the user short of closing Dashboard and opening the browser with the link to the RSS feed. If you want to allow the user to get the information without having to load an application, you can provide your widget with the ability to display the content in a growable window with scrolling.

The HTML File

As with resizing, you’ll have to make additions to your widget’s HTML, CSS, and JavaScript files. In the HTML file, you’ll need to add Apple’s classes for the scroll bar and the scroll area. Like the button classes, the AppleScrollbar.js and AppleScrollArea.js files are part of the WidgetResources directory and provide the functionality for working with scroll bars. You could write your own functions, but you should try using Apple’s first.

<html>

<head>

<style type=”text/css”> @import “resize.css”;

</style>

<script type=’text/javascript’ src=’AppleClasses/AppleInfoButton.js’ charset= ’utf-8’ />

<script type=’text/javascript’ src=’AppleClasses/AppleAnimator.js’ charset= ’utf-8’ />

146

Adding to the Widget Interface

<script type=’text/javascript’ src=’AppleClasses/AppleButton.js’ charset=’utf- 8’ />

<script type=’text/javascript’ src=’/System/Library/WidgetResources/AppleClasses/AppleScrollArea.js’></script>

<script type=’text/javascript’ src=’/System/Library/WidgetResources/AppleClasses/AppleScrollbar.js’></script>

<script type=’text/javascript’ src=’resize.js’></script> <body onload=”setup();”>

<div id=”front”>

<img id=”backgroundImage” src=”Default.png”> <div id=”title”>Reslide</div>

</div>

<div id=”theImage”>

<img id=”png” src=”Images/intel_mini.png” height=”90px” width=”140px”></img>

</div>

<div id=”scalerSlider”></div>

<div id=”resize” onMouseDown=”mouseDown(event);”> <img id=”resizeThumb”

src=”/System/Library/WidgetResources/resize.png”></img>

</div>

</div>

<div id=”back”> </div>

</body>

</html>

The CSS File

In the CSS file of your widget, you’ll need to add selectors for the content that you are scrolling and the scroll bar or slider that you are using.

body { margin:0;

}

/* widget front */

#front {

position: absolute; top: 0px;

left: 0px; width: 170px; height: 170px; display: block;

text-align: center;

}

#title {

font: 12px “Helvetica Neue”; color: white;

147

Chapter 8

position: absolute; top: 10px;

left: 65px;

}

#theImage {

position: absolute; top: 30px;

bottom: 48px; left: 15px; right: 15px; overflow: auto;

}

#scalerSlider { position: absolute; bottom: 28px; left: 15px;

right: 15px;

}

#resize {

position: absolute; bottom: 24px; right: 24px; width: 12px; height: 12px; z-index: 2;

-apple-dashboard-region: dashboard-region(control rectangle 0px 0px 0px 0px);

}

/* widget back */

#back { display: none;

}

Notice that the image file content and the scalarSlider selectors are grouped together. As your CSS files become longer, grouping all of the related selectors together makes the file easier to maintain.

The JavaScript File

In the JavaScript file, you will need to add functions for the scroll bar and the content area. If you are using Apple’s classes, all of the work is done in them, and your JavaScript needs only to pass the correct values. In this example, variables are added for the scalarSlider at the beginning of the file. Notice the use of global variables and how the JavaScript references the selectors used in the HTML file.

//tracks where the last mouse position was throughout the drag var resizeInset;

//the right offset of the grow thumb vs. the edge of widget window var rightEdgeOffset;

//the bottom offset of the grow thumb vs. the edge of widget window var bottomEdgeOffset;

//slider variables

148

Adding to the Widget Interface

var scalerSlider;

var lastScalerSliderValue;

// called when the mouse first clicks upon the resize function mouseDown(event) {

//begin tracking the move document.addEventListener(“mousemove”, mouseMove, true);

//and notify when the drag ends document.addEventListener(“mouseup”, mouseUp, true);

//resizeInset tracks where the actual mouse click happened vs. the right and

//bottom edges of the widget

resizeInset = {x:(window.innerWidth - event.x), y:(window.innerHeight - event.y)};

event.stopPropagation();

event.preventDefault();

}

// called as the mouse button is down and the mouse moves function mouseMove(event) {

//x and y track where bottom-right corner of the widget should be, with relation

//to the event.

var x = event.x + resizeInset.x; var y = event.y + resizeInset.y;

//an arbitrary minimum width if(x < 105)

x = 105;

//an arbitrary minimum height if(y < 37)

y = 37;

//an arbitrary maximum width if(x > 210)

x = 210;

//an arbitrary maximum height if(y > 210)

y = 210;

//resize background document.getElementById(“front”).style.width = x; document.getElementById(“front”).style.height = y; document.getElementById(“backgroundImage”).width = x; document.getElementById(“backgroundImage”).height = y;

//resize the widget

window.resizeTo(x,y);

event.stopPropagation();

event.preventDefault();

}

// called after the mouse button is released

149

Chapter 8

function mouseUp(event) {

//stop tracking the move document.removeEventListener(“mousemove”, mouseMove, true);

//and notify if the mouse goes down again document.removeEventListener(“mouseup”, mouseUp, true);

event.stopPropagation();

event.preventDefault();

}

// called when the widget loads function setup() {

alert(“entered setup”);

scalerSlider = new AppleHorizontalSlider(document.getElementById(“scalerSlider”), sliderChanged);

alert(“setup: scalerSlider.size: “ + scalerSlider.size.toString()); alert(“leaving setup”);

}

function sliderChanged(currentValue) { if (currentValue <= 0.01) {

return; } else {

// check the direction of the slider move: if (currentValue < lastScalerSliderValue) {

// shrinking

var theImage = document.getElementById(“png”); var preHeight = theImage.height;

var preWidth = theImage.width;

var postHeight = preHeight / (1+ scalerSlider.value); var postWidth = preWidth / (1+ scalerSlider.value);

//arbitrary minimum size if (postHeight > 90) {

document.getElementById(“png”).height = postHeight; document.getElementById(“png”).width = postWidth;

}

lastScalerSliderValue = currentValue;

}else {

//enlarging

var theImage = document.getElementById(“png”); var preHeight = theImage.height;

var preWidth = theImage.width;

var postHeight = preHeight * (1 + scalerSlider.value); var postWidth = preWidth * (1 + scalerSlider.value); // arbitrary maximum size

if (postHeight < 616) { document.getElementById(“png”).height = postHeight; document.getElementById(“png”).width = postWidth;

}

lastScalerSliderValue = currentValue;

}

}

}

150