You are on page 1of 11

Sylladex Development

A reference guide

Version 2.0 (O)

0. A brief introduction
This guide will show you how to write basic fetch modi and widgets. To do more
complicated things than are described in this guide, it is advised that you learn
by example from the code available at github.com/gumptiousCreator/Sylladex-Captchalogue-Deck.

1. Setting up the workspace


There are two ways of setting up the workspace. You can download the source
code and debug against that, or you can use the current release (.jar file).

Using the .jar file


Download Eclipse, and the Sylladex .jar file. Then open Eclipse, set up a new
project, and import the .jar.
Click on Add External JARs... and browse for the .jar file.
Create a new class in the default package. This will contain all the code for your
modus.
(If you want to create a widget, the process is the same).

Using the source code


Download the code from github. A link is provided in the introduction. Then create a new project in
Eclipse called 'Sylladex Program'. Tell Eclipse to use the 'program-dev' folder.
Create another project called 'Sylladex Modi'. Tell Eclipse to use the 'modus-dev' folder. If you want
to create widgets, create a project called 'Sylladex Widgets' and use the 'widget-dev' folder. Add the
'Sylladex Program' project to the build path of each.
Note: Code will compile into modus-dev/bin and widget-dev/bin.
Either change the output directories or write a batch file to copy
the files into program-dev/modi and program-dev/widgets.
Create a class in the default package of 'Sylladex Modi'. This will contain all the code for your
modus. Alternatively, create a class in 'Sylladex Widgets'.

Part 1: Fetch Modi


0. Constructor
The constructor contains information about the fetch modus which is read by the rest of the program
(i.e. by DeckPreferences when it creates the modus browser). Take a look at the HASHMAP
code and change it to suit your needs.
The line of the constructor should always be this.m = m;

Version 2.0 (O)

Important note: Do not perform initial set-up within the


constructor. Use the prepare() method instead.

1. addGenericItem() and open()


These are the most important functions of a fetch modus. Obviously.
There are four different types of item which can be added to the Sylladex: files,
images, text (strings) and widgets. To make things easier for you, I've added
some generic functions which accept Objects as parameters.
Adding items usually involves the following steps:

Determine whether the item can be added at all. For the HASHMAP modus,
this means calculating which card the item would be added to and
checking various variables, such as whether the card is empty and
whether detect collisions is enabled. STACK and QUEUE check whether
there is room, and eject a card if there is not.

Add the item to the card.

Create the dock icon (a JLabel), assign it to the card, and add it to
icons. Update the dock icons.

If the modus uses an internal data structure to store references to the


cards (for instance, the STACK modus uses a LinkedList<SylladexCard>
called stack), update this.

Arrange the cards properly within the card holder.

Below is how it works in the STACK modus. The generic functions are suitable
for most modi, but if you want to treat each type of item differently, the
functions you need to override are called addItem(). They take either a File,
Image or String as the parameter, and won't call addGenericItem() if
overridden.
public void addGenericItem(Object o)
{
checkBottomCard();
SylladexCard card = m.getNextEmptyCard();
card.setItem(o);

stack.addFirst(card);
JLabel icon = m.getIconLabelFromObject(o);
icons.add(0, icon);
m.setIcons(icons);
card.setIcon(icon);
arrangeCards();

open() is the function to use to manage the actual


opening of a card. For simple fetch modi, rely on it
being called when the user left-clicks on a card
marked as accessible. More complicated modi, like
MEMORY, will mark all cards as inaccessible and use a
selection window to access them (in that case, it's
Version 2.0 (O)

Note: there is no
reason why
showSelectionWindow()
should actually open a
window. You could, for
example, make a modus
which opens a random
card when the user
clicks on the dock.

the Memory game). showSelectionWindow() is called when the user left-clicks


on the dock.
Regardless, open() is an abstract function within FetchModus, so you might as
well use it.
public void open(SylladexCard card)
{
icons.remove(card.getIcon());
icons.trimToSize();
m.setIcons(icons);
stack.remove(card);
arrangeCards();
m.open(card);
}

This code
1. (internal) Removes the card's dock icon from the ArrayList of icons
2. (internal) Trims this ArrayList to its new size
3. (external) Updates the dock to reflect this change
4. (internal) Removes the card from the stack
5. (internal) Updates the positions of the cards on-screen.

2. Saving, loading and initial set-up


Loading the state of a sylladex requires knowledge of the items stored, as well
as which cards they were stored in. Fetch modi which allow cards to be added
to the deck must also have a way of keeping track of this.
Files I have called item lists are therefore stored by the program, the simplest
example of which is called queuestack.txt. As its name suggests, it stores the
contents of the STACK, QUEUE and QUEUESTACK modi. Using one file is preferable
to three, as it means the user sees the same files whichever fetch modus he or
she happens to have enabled.
In order to use queuestack.txt, a fetch modus must meet these requirements:

Each line must contain either an absolute path, a relative path, or a


single-line string. Relative paths should start with files/.

Saving and loading without any other user input must not alter the order
of the items.

The number of cards in the deck is the number of non-blank lines. If this
number exceeds startcards, the modus should be able to grow to
match the number of saved items.

There are two other item files in use: hashmap.txt and tree.txt. These should
not be used by custom fetch modi. However, I have created a file called
array.txt, for which the requirements are:

Each line must contain either an absolute path, a relative path, or a


single-line string. Relative paths should start with files/.

The order of the items must not be important to a fetch modus using this

Version 2.0 (O)

file.

The number of cards in the deck is the number of lines in the file, minus
one blank line at the end (added by DeckPreferences). If this number
exceeds startcards, the modus should be able to grow to match the
number of saved items.

If your modus does not meet the requirements for one of the default item files,
you must use your own.
When the program closes, DeckPreferences will request an ArrayList of
Strings, via the getItems() method. Here is what it looks like in the STACK
modus.
public ArrayList<String> getItems()
{
ArrayList<String> items = new ArrayList<String>();
if(stack.size()>0)
{
for(SylladexCard card : stack)
{
items.add(card.getSaveString());
}
}
else { items.add(""); }
return items;
}

SylladexCard.getSaveString() is a function which returns the appropriate


string for a card. For a file, it returns the absolute path (or relative path if
portable mode is enabled). For an image, it creates an image called
captchalogued_image_xxxxxxxxxxxxxxxxx.png within the files folder and
returns its relative path. For a string, it returns the string with the system's new
line sequence replaced by SYLLADEX_NL. For a widget, it returns
[WIDGET]/path/to/widget/widget.class[/WIDGET]widget save data.
Do not call getSaveString() more than once on each card! If you do, you'll
end up with duplicate captchalogued images in the files folder.
Fetch modi should perform initial set-up, such as positioning cards on-screen, in
the prepare() method, not the constructor. This is also the point at which
items should be loaded.
Here's what the STACK modus does. items is set by the program automatically
before prepare() is called.
public void prepare()
{
for(String string : items)
{
if(!string.equals(""))
{
if(m.getNextEmptyCard()==null) { m.addCard(); }
SylladexCard card = m.getNextEmptyCard();
Object o = m.getItem(string);
card.setItem(o);
stack.addLast(card);
JLabel icon = m.getIconLabelFromObject(o);
icons.add(icon);
Version 2.0 (O)

}
}

m.setIcons(icons);
card.setIcon(icon);
arrangeCards();

The function which does all the messy work for you here is
Main.getItem(String). It is basically the reverse of
SylladexCard.getSaveString(), and returns a File, Image , String or
Widget object. It also deletes captchalogued_image_xxxxxxxxxxxxxxxxx.png
files and replaces SYLLADEX_NL with the system's line separator.

3. Responding to mouse events


Responding to the cursor moving into or out of a card is simple. Just listen for
ActionEvents with the command card mouse enter and card mouse exit.
The appropriate SylladexCard will be available via ActionEvent.getSource().

4. Preferences
preferences is an ArrayList of Strings which is ready by the time the
prepare() method is called. An ArrayList is hard to work with since you have
to keep track of which index refers to which preference. I find it helps to use an
enum for this purpose:
enum PrefLabels
{
SELECTED_MAPPING (0),
DETECT_COLLISIONS (1);
public int index;
PrefLabels(int i)
{ index = i; }
}

Preferences can be accessed thus:


preferences.get(PrefLabels.DETECT_COLLISIONS.index);
preferences.set(PrefLabels.DETECT_COLLISIONS.index, value);

Remember that non-String values still have to be converted to and from


Strings.

5. Animation
5.1 Using the built-in class
The Animation class provides a few basic animations. To use them, you need to
import sylladex.Animation.AnimationType. There are two types of
constructor.
public Animation(JComponent/SylladexCard comp, Point finalposition,
AnimationType type, ActionListener listener, String command)
public Animation(AnimationType type, int duration, ActionListener listener,
String command)

With the first constructor, you can create MOVE, BOUNCE and BOUNCE_SPOT
Version 2.0 (O)

animations. Each of these are two-frame animations which last for 100ms.
The second constructor is for WAIT 'animations'. These are just a simple way to
create timers. Whatever AnimationType you put in will be converted to WAIT;
it's included in the constructor simply to improve code readability.
You can animate any JComponent, or a SylladexCard.
command is the ActionCommand which is sent to the listener when the
animation completes.
Here's an example:
anim = new Animation(box, new Point(0,244), AnimationType.MOVE, this, "box");
anim.run();

run() starts the animation and stop() stops it (and moves the component to
its final position).
Chaining animations together is possible by setting the listener to another
animation, and the command string to run:
new Animation(box, new Point(0,244), AnimationType.MOVE, anim2, "run").run();

5.2 Using animated .gif files


Swing supports animated .gifs in JLabels, which is a good option for more
complicated animations. The HASHMAP modus uses one called animation.gif
which uncovers the hash function box line by line.
There is a problem with this approach, however, which is that Java seems to reuse the same resource once it's been loaded. This means that if you create a
JLabel containing an animated .gif, destroy the label after the animation
completes and then create another identical one, the new JLabel will display
only the last frame of the animation.
If the .gif doesn't loop. Originally, I set animation.gif to run once, and
experienced the problem described above. However, I found that looping
animations work differently. When they're re-created, they restart, if they'd
reached the last frame before they were destroyed. Weird.
Anyway, this technique still won't work if you want multiple asynchronous
animations.

6. Drawing on the dock, drawing on the cards


Some modi need to add components to the dock and/or to the cards. To
facilitate this, I've created some blank JPanels, which are accessible using the
following:
FetchModus.foreground and FetchModus.background are already
instantiated. These are panels on the dock which appear on top of and behind
the dock icons, respectively.
To draw on the cards, use SylladexCard.getForeground().
If you really need access to the card holder window, you can have it. Use
Main.getCardHolder().

Version 2.0 (O)

Part 2: Widgets
Widgets don't need a very large section. They don't have constructors; m is set
automatically before prepare() is called.
A few things to note:

prepare() is called when the widget is added to the deck by the user.
This is for first-time set-up.

load(String) is called when the widget is loaded (i.e. when the program
starts and loads an already-captchalogued widget).

This means that any initial set-up required every time the widget starts
must be performed by each of these functions. (I'd advise you create
your own set-up function and call it from each of the above.)

open() is called when the user tries to open the widget. If you want to
respond to mouse events on the widget, take a look at the code for
RPObject.

panel is what will appear on the card. dock_icon is self-explanatory.

The return value of getString() is used by some modi (e.g. HASHMAP and
TREE) to determine which card to put the widget in. getSaveString()
should return data required to load the widget's current state. It is the
string passed back in again by load(String).

Appendix: Function Reference


Main
ArrayList<SylladexCard> getCards()

Returns all the cards in the deck.

boolean isLinux()

Returns true on Linux.

boolean isMac()

Returns true if the system is running


MacOS.

boolean isTransparencySupported()

Tries to determine whether the window


manager supports per-pixel
translucent windows.

boolean isWindows()

Returns true if this is a Windows


system.

DeckPreferences getPreferences()

Returns the preferences (see below).

Dimension getScreenSize()

Returns the size of the user's screen


as a Dimension object.

Icon getDockIcon(Image image)

Re-sizes the image for use as a dock


icon.

Icon getIconFromFile(File file)

Returns the system's default icon for


this file.

Icon getSizedIcon(Image image, int


width, int height)

Re-sizes the image, maintaining its

Version 2.0 (O)

aspect ratio. The returned Icon is


guaranteed to fit within the specified
bounds.
ImageIcon createImageIcon(String path)

Returns an ImageIcon created from


the specified absolute or relative path.

int getDockIconYPosition()

Returns the y-position of the dock


icons, according to whether the dock
is at the top or bottom of the screen.
This is useful for positioning
components in the dock.

JLabel getIconLabelFromObject(Object o)

When fed a valid card item (File,


Image, String or Widget), this returns
a JLabel suitable for use as a dock
icon.

JWindow getCardHolder()

Returns a handle to the card holder.


Be careful with it!

Object getItem(String string)

Interprets the String, and returns an


item suitable for adding to a card. See
Saving, loading and initial set-up.

SylladexCard getCardAtPosition(Point
position)

Returns the card whose top-left corner


is at precisely the point specified, or
null if there is no such card.

SylladexCard getCardWithIndex(int
index)

Returns the card with the given index.


A shortcut for
Main.getCards().get(index).
Throws an exception if there is no card
with that index.

SylladexCard getNextEmptyCard()

Returns an empty card, or null if


there are none.

void actionPerformed(ActionEvent e)

Fools the program into thinking the


user did something.

void addCard()

Adds one card to the deck and


refreshes the dock.

void
void
void
void

Processes the input parameter and


then calls the appropriate
FetchModus.addItem() method. You
shouldn't need to call this.

addItem(File file)
addItem(Image image)
addItem(String string)
addItem(Widget widget)

void hideDock()

Hides the dock.

void open(SylladexCard card)

Opens the card's item and removes it


from the card.

void openWithoutRemoval(SylladexCard
card)

Opens the card's item without


removing it from the card.

void refreshCardHolder()

Forces a repaint of the card holder.

Version 2.0 (O)

void refreshDock()

Re-creates the dock.

void refreshDockIcons()

Clears and re-creates the dock icons.

void removeCard(SylladexCard card)

Removes the card from the deck.

void setCardHolderSize(int w, int h)

Re-sizes the card holder to width w and


height h.

void setIcons(ArrayList<JLabel>
newicons)

Sets the dock icons to newicons and


refreshes the dock.

void setTransparent(JWindow window)

Attempts to make the window


transparent.

void showDock()

Shows the dock.

You can call the WindowListener events, but NOTHING GOOD WILL COME OF IT.

SylladexCard
boolean isAccessible()
boolean isEmpty()
File getFile()
Image getImage()
String getString()
Widget getWidget()
int getHeight()
int getId()

int getWidth()
JLabel getIcon()
JPanel getForeground()
Point getPosition()
setAccessible(boolean accessible)
String getItemString()

String getSaveString()

void
void
void
void
void

addToCardHolder()
removeFromCardHolder()
setFile(File file)
setImage(Image image)
setString(String string)

Version 2.0 (O)

Returns whether the user can open the


card by clicking on it.
Returns true if the card is empty.
Returns the card's
file/image/string/widget, or null if the
card does not contain a
file/image/string/widget.
Dunno why you'd want this. You're the
one who set it, by using card_height.
Returns the card's ID. As for why you'd
want to know that, I have no idea. Noone uses IDs any more.
Dunno why you'd want this. You're the
one who set it, by using card_width.
Returns the icon label associated with
this card.
Returns a panel you can use to draw on
the card.
Returns the position of the card's
upper-left corner.
If a card is accessible, the user can
open the card by clicking on it.
A lot of modi need to refer to items by
name. This returns the 'name' of the
item contained in the card.
Returns a good string to use for saving.
Returns null if the card is empty. See
Saving, loading and initial set-up for
details on this function.
Does what it says on the tin.
Removes the card from the card holder.
Sets the card's file/image/string/widget,
setting the others to null.

void setWidget(Widget widget)


void setIcon(JLabel newicon)
void setImageString

void setItem(Object o)
void setLayer(int layer)

void setPosition(Point position)

Sets the card's icon label.


Sets the card's image string. This will
be returned by getItemString() if the
card holds an image.
Sets the card's item to o, if o is of a
valid type.
Sets the card's layer. A higher number
means the card is drawn above other
cards.
Moves the card's upper-left corner to
the specified position.

Preferences
ArrayList<String> getModusItems()
ArrayList<String> getModusPreferences()
boolean always_on_top_cards()
boolean always_on_top_dock()
boolean autohide_cards()
boolean autohide_dock()

boolean copy_instead_of_move()
boolean top()
boolean usb_mode()
FetchModus getModus()
void actionPerformed(ActionEvent e)
void createAndShowModusBrowser()
void showPreferencesFrame()
void windowClosing(WindowEvent w)

No point in calling this.


No point in calling this.
Returns true if the card holder is set
always to be on top.
Same, but for the dock.
Returns true if the cards auto-hide.
Look, I can't be bothered to explain all
these. Just look at the function names,
OK?

You might as well just write this.


Do you really need to use this?
Shows the preferences window.
Saves the preferences. But don't call
this, because it might do more in
future.

Animation
new Animation(JComponent comp, Point
finalposition, AnimationType type,
ActionListener listener, String
command),
new Animation(SylladexCard card,...)
JComponent getComponent()
void run()
void stop()
void actionPerformed(ActionEvent e)

Version 2.0 (O)

Constructors.

Returns the animated component.


Starts the animation.
Stops the animation, and moves the
component to its final position.
If e's action command is run, this
starts the animation. Useful for
chaining several animations together.

You might also like