Because of the constant attack by the wiki spam bots, accounts that are created and not used will be deleted. If you are a legitimate user, and your IP was blocked, please contact any active administrator - look at Special:RecentChanges and see who is busy fighting spam.

Widget

From SWFTools
Jump to: navigation, search

A widget (or control) is an element of a graphical user interface (GUI) that displays an information arrangement changeable by the user, such as a window or a text box. The defining characteristic of a widget is to provide a single interaction point for the direct manipulation of a given kind of data. In other words, widgets are basic visual building blocks which, combined in an application, hold all the data processed by the application and the available interactions on this data.[1]

swfc includes many widgets, most of them have examples in Swfc Code Snippets or Sc file format

  • box - a simple rectangle.
  • circle - a circle.
  • button - a clickable button.
  • text - a fixed text
  • edittext - text that can be changed (by the program) or used to input (by the user)
  • jpeg - a jpeg image
  • png - a png image
  • sprite - can be anything, imagine a sprite as a swf file inside another swf file.
  • swf - includes another swf file.

Placement of Widgets

In a flash application that uses many widgets, they are placed, sequentially, as if each one lies over the previous one. And, unless coordinates are declared, they are also placed in the left upper corner. The dimensions of the flash application adapt to the maximum sizes of the widgets, the horizontal size (width) and the vertical size (height). The example, below, places five different boxes. Notice that the most recent boxes cover part of the previous boxes.

.flash bbox=autocrop fps=50 background=white
  .box bluebox 100 600 color=blue fill
  .box redbox 500 500 color=red fill
  .box greenbox 400 400 color=green fill
  .box yellowbox 600 300 color=yellow
  .box transparentbox 450 450 color=black

  .put bluebox
  .put redbox
  .put greenbox
  .put yellowbox
  .put transparentbox
.end

Moving Widgets

As seen in the example, above, each widget has three coordinates. Two of them are explicit, and easy to define, the horizontal and vertical coordinates. These coordinates are x and y. By default, the top-left corner is (0, 0), and x increases from top to bottom, and y increases from left to right.

There's a third coordinate, and this one is almost unchangeable. It's called depth. For now, let's just say that the first widgets that are placed in the application are lower, and the next widgets are higher.

Moving widgets is the process of changing these coordinates, however, in this chapter the only coordinates that will be changed are x and y.

Let's begin with an exercise. The purpose is to write a flash application in a 400x400 screen with two 50x50 squares. The red square will begin in the top-left corner, the blue square in the top-right corner, and move to the bottom-left corner in 10 seconds.

A simple way to do it is:

.flash bbox=400x400 fps=50 background=white
  .box redbox 50 50 color=red fill
  .box bluebox 50 50 color=blue fill

  .put redbox x=0 y=0
  .put bluebox x=350 y=0

  .frame 50
  .move bluebox x=315 y=35

  .frame 100
  .move bluebox x=280 y=70

  .frame 150
  .move bluebox x=245 y=105

  .frame 200
  .move bluebox x=210 y=140

  .frame 250
  .move bluebox x=175 y=175

  .frame 300
  .move bluebox x=140 y=210

  .frame 350
  .move bluebox x=105 y=245

  .frame 400
  .move bluebox x=70 y=280

  .frame 450
  .move bluebox x=35 y=315

  .frame 500
  .move bluebox x=0 y=350
  .stop
.end

The instruction

.flash bbox=400x400 fps=50 background=white

sets up the flash application with the size of 400x400, with 50 frames per second and a white background.

Next, we place the two boxes, and then we start moving the blue box. The instruction .frame 50 tells what we will do with the bluebox after 1 second, and so on.

However, something interesting happens. Instead of jumping 35 coordinates each second, the blue box seems to be moving smoothly. The reason is that the meaning of move is to move smoothly. So, it's not really necessary to interpolate for each second, but just to declare the first position and the last.

Also, the flash application can compute its size based on where the widgets will be. So, this script is equivalent to the much more simple, elegant and (probably) more efficient:

.flash bbox=autocrop fps=50 background=white
  .box redbox 50 50 color=red fill
  .box bluebox 50 50 color=blue fill

  .put redbox x=0 y=0
  .put bluebox x=350 y=0

  .frame 500
  .move bluebox x=0 y=350
  .stop
.end

Now, since move is a smooth move, is there any way to have an instantaneous move, like a jump? One simple and quite obvious way to do this is by keeping the box in the same position just before the 10th second, and then moving it to the final position:

.flash bbox=autocrop fps=50 background=white
  .box redbox 50 50 color=red fill
  .box bluebox 50 50 color=blue fill

  .put redbox x=0 y=0
  .put bluebox x=350 y=0

  .frame 499
  .move bluebox x=350 y=0
  .frame 500
  .move bluebox x=0 y=350
  .stop
.end

Or, alternatively, if you want to jump, just use the command .jump!

.flash bbox=autocrop fps=50 background=white
  .box redbox 50 50 color=red fill
  .box bluebox 50 50 color=blue fill

  .put redbox x=0 y=0
  .put bluebox x=350 y=0

  .frame 500
  .jump bluebox x=0 y=350
  .stop
.end

Pinning Widgets

Let's suppose you have a 500x500 flash application and you want to place a jpeg image right in the middle of it. One way is to get its width and height, and do the math. But we are lazy, why do the job when the computer can do it for us?

The simplest way to do it is to use the parameter pin. Imagine that, when you place a widget, it's as if you pin it by its left-top corner. It's possible to change that, just define pin=center, and the x and y coordinates that you give refer to the center, and not to the left-top corner, of the widget.

The example, below, places a square box and a circle:

.flash bbox=500x500 fps=50 background=white
  .box bluebox width=400 height=400 color=blue fill
  .circle redcircle r=150 color=red fill
  .put bluebox x=250 y=250 pin=center
  .put redcircle x=250 y=250 pin=center
.end


Moving Widgets using Action

Action is the way programming can be inserted into a .sc script.

It should be very simple to move a widget using action, just redefine the members _x and _y of the object that represents the widget (the terms "member" and "object" come from object oriented programming).

Let's try this example. Apparently, it relocates a green circle to the position previously occupied by the blue circle:

.flash bbox=400x400 fps=50 background=white
  .circle redcircle r=30 color=red fill
  .circle bluecircle r=30 color=blue fill
  .circle greencircle r=30 color=green fill

  .frame 1
  .put redcircle x=300 y=300
  .put bluecircle x=200 y=200
  .put greencircle x=100 y=100 

  .frame 100
  .action:
     greencircle._x = 200;
     greencircle._y = 200;
  .end
  .stop
.end

However, two unexpected things happened here. First, the green circle did not move to the position of the blue circle (200, 200), but to the position of the red circle (300, 300). Second, both circles (the red and the blue) vanished. What's wrong?

Let's do a little debugging! This debugging will display a dynamic text, how the debug works is not explained here, but see articles Font and Edittext. If the code below does not work, replace "myfont.ttf" in the line, below:

  .font myfont "myfont.ttf"

with a full path declaration of where you have this font.

The first debug: let's show where is greencircle before the action. Try the code, below:

.flash bbox=400x400 fps=50 background=white
  .circle redcircle r=30 color=red fill
  .circle bluecircle r=30 color=blue fill
  .circle greencircle r=30 color=green fill
  .font myfont "myfont.ttf"
  .edittext debugmessage font=myfont size=25pt text="" width=400 height=50 color=black border readonly

  .frame 1
  .put redcircle x=300 y=300
  .put bluecircle x=200 y=200
  .put greencircle x=100 y=100 
  .put debugmessage x=0 y=350

  .frame 100
  .action:
     x = greencircle._x;
     y = greencircle._y;
     debugmessage.text = "(" + x + "," + y + ")";
  .end
  .stop
.end

Uh? What's wrong with that? (x,y) = (0,0)?

The reason is that mixing move instructions (which includes put) with action is not a good idea. Let's do it differently, and try not to put the circles in any position.

.flash bbox=400x400 fps=50 background=white
  .circle redcircle r=30 color=red fill
  .circle bluecircle r=30 color=blue fill
  .circle greencircle r=30 color=green fill

  .put redcircle
  .put bluecircle
  .put greencircle

  .frame 1
  .action:
     redcircle._x = 300;
     redcircle._y = 300;
     bluecircle._x = 200;
     bluecircle._y = 200;
     greencircle._x = 100;
     greencircle._y = 100;
  .end

 .frame 100
 .action:
    greencircle._x = 200;
    greencircle._y = 200;
 .end
 .stop
.end

The code is still wrong. Ok, the green circle moves as expected, but there was never any blue or red circles! The reason for that is that's it's not a good idea to mix instructions (like put) with action. So, as soon as the green circle is declared, it's like the flash application "forgets" that there were red or blue circles. Try this:

.flash bbox=400x400 fps=50 background=white
  .circle redcircle r=30 color=red fill
  .circle bluecircle r=30 color=blue fill
  .circle greencircle r=30 color=green fill

  .put redcircle
  .put bluecircle
  .put greencircle

  .frame 1
  .action:
     redcircle._x = 300;
     redcircle._y = 300;
  .end

  .frame 100
  .action:
     bluecircle._x = 200;
     bluecircle._y = 200;
  .end

  .frame 200
  .action:
     greencircle._x = 100;
     greencircle._y = 100;
  .end

  .frame 300
  .action:
    greencircle._x = 200;
    greencircle._y = 200;
  .end
  .stop
.end

The code is still not working properly. Even though circles appear at the desired locations, (300, 300), (200, 200) and (100, 100), they vanish after another circle appears, and they are not red or blue, all of them are green!

The solution to this problem requires the use of Sprites, that is a way to insert one flash application inside the other. Then, let's have two sprites: the lower sprite will have the green and blue circles, and the upper sprite will have the green circle.

.flash bbox=400x400 fps=50 background=white
  .circle redcircle r=30 color=red fill
  .circle bluecircle r=30 color=blue fill
  .circle greencircle r=30 color=green fill

  .sprite lower
    .put redcircle x=300 y=300
    .put bluecircle x=200 y=200
  .end

  .sprite upper
    .put greencircle
    .frame 1
    .action:
       greencircle._x = 100;
       greencircle._y = 100;
    .end

    .frame 100
    .action:
      greencircle._x = 200;
      greencircle._y = 200;
    .end
    .stop
  .end

  .put lower
  .put upper
.end

Now, the code works as expected.

Creating Widgets using Action

It's possible to create widgets using Action, the function that does it is called createEmptyMovieClip. This function creates an empty movie, and then it's the programmer's job to "populate" the object with other widgets, or clone another widget into this widget using attachMovie.

Here is a simple example. This example includes two sprites. The upper sprite consists of some random lines. The lower sprite is a copy of the circle widget.

A few details (but in case of doubt, consult the appropriate articles): both sprites are created, but they are empty. Nonetheless, it's required that they include the .end instruction, otherwise the next lines will be interpreted by swfc as part of the sprite, resulting in an obscurely arcane error message. Hint: don't try to understand swfc's error messages, their purpose is to stripe out the sanity of the programmer. lineStyle is the action function that declares a line, its arguments are thickness, color (hexadecimal) and alpha. moveTo and lineTo build a line.

.flash bbox=400x400 fps=50 background=black
  .circle yellowcircle r=100 color=yellow fill
  .sprite lower
  .end
  .sprite upper
  .end

  .action:
     // upper sprite action
     r = upper.createEmptyMovieClip("random_lines", 1);
     r.moveTo(50 + random(300), 50 + random(300));
     for (i = 0; i < 10; i++) {
       r.lineStyle(1, random(0xFFFFFF), 100);
       r.lineTo(50 + random(300), 50 + random(300));
     }

     // lower sprite action
     lower.attachMovie("yellowcircle", "newcircle", 1);
  .end

  .put lower
  .put upper

  # Now, let´s move those sprites a little bit
  .frame 100
  .move lower x=50

  .frame 150
  .move upper y=50

  .frame 200
  .move lower x=25 y=25

  .frame 300
  .move upper x=10 y=0

  .frame 400
  .move upper x=0 y=0
  .move lower x=0 y=0

.end

The example, above, has some curious features. The yellow circle begins in the upper right corner, not in the center. Also, the random lines are re-generated after each cycle (400 / 50 = 8 seconds). Exercise: try to work around these features.

References

  1. Text taken from Wikipedia, it's ok to do that, because of Wikipedia's license, http://en.wikipedia.org/wiki/GUI_widget