Amulet Frequently Asked Questions (FAQ)

This FAQ is currently just a collection of responses to recent questions from Amulet users that may have some general interest.

Back to the Amulet Home Page.


Table of Contents

1. General

2. Mailing Lists

3. Compilers, Operating Systems, Frameworks, Contributions

4. Technical information, Am_Object, Objects

5. Am_Values, Am_Lists, Listboxes

6. Widgets, Wrappers

7. Graphics, drawing, interactors

8. Constraints

9. Animation

10. Errors, Debugging


1. General


1.1 What is Amulet?

AMULET is an entirely free, public domain user interface development environment in C++. Code written using Amulet will work with little or no changes on all platforms.

Now at Version 3.0, Amulet is more than just another free "virtual toolkit." Amulet includes many features specifically designed to make the creation of highly-interactive, graphical, direct manipulation user interfaces significantly easier. Important features of Amulet include: high-level support for interactive behaviors; built-in support for animation, UNDO, and gesture-recognition; a dynamic, prototype-instance object system that makes prototyping easier; automatic constraint solving integrated with the object system; a "structured-graphics" model (also called a "display list") that handles automatic refresh of objects when they change; a high-level input model that makes it easy to add behaviors to objects and also supports undo and help for operations; a full set of flexible widgets implemented using the Amulet intrinsics, so you can easily experiment with your own widgets; and high-level interactive debugging tools.  Widgets include: buttons, check boxes, radio buttons, menus, menu bars (pull-down menus), scroll bars, scrolling windows, and text input fields. Amulet comes with complete documentation including a tutorial.

Amulet has been downloaded over 10,000 times, and about 80 projects are listed in the Amulet Users web site. Amulet is listed in the C++ FAQ and sites about tools for Linux. Amulet is being developed by the User Interface Software Group in the Human Computer Interaction Institute in the School of Computer Science at Carnegie Mellon University. The primary research interest of the UISG is the development of tools to allow rapid development of graphical user interfaces.


1.2 How can I get Amulet?

Amulet is available for downloading from the Amulet web site.

http://www.cs.cmu.edu/~amulet/amulet3-release.html


1.3 Can I use Amulet to create commercial software?

Amulet is available for free by anonymous FTP or WWW. Amulet has been put into the public domain. This means that anyone can use Amulet for whatever they want. In particular, Amulet can be used for commercial development without any license or fees. The resulting binaries and libraries can also be distributed commercially or for free without payments or licenses to Carnegie Mellon University (CMU). You can even include portions of the Amulet source code in your projects or products. The only restriction is that the documentation for Amulet is copyrighted, so you cannot distribute the Amulet manual or papers without permission from CMU. In return, CMU assumes no responsibility for how well Amulet works, and will not guarantee to provide any support. If you need more formal legal language, see Section 1.12 of the manual. If you need this formally signed, then replace your company's name for COMPANY and send it back to us.

Of course, the Amulet research group would appreciate any corporate grants or donations to support the further development and maintenance of Amulet. We would also be interested in discussing grants to support adding specific features to the system that would make it more useful for your needs. Please contact Brad Myers at bam@cs.cmu.edu to discuss this.

If you decide to use Amulet, we would like to be able to mention this in our publicity and reports to our sponsors. (We get recognition for having users, both commercial and research projects.) Please send mail to amulet@cs.cmu.edu with the name of your project or product. We also like to receive screenshots. If you write papers or advertisements about systems built with Amulet, we would appreciate if you included a mention that you used Amulet, and a reference to this manual, and we would like a copy of your paper for our files.

For complete license and legal information, please see Section 1.12 of the manual.

"I notice the presence of the gpl COPYING disclosure in the src/gesture directory. Does this mean that I can't use amulet in my commercial project without adhering to the gpl constraints of providing my customers and competitors with my source code for free?"

Some of the gesture code was copied from Dean Rubine's code from his PhD thesis, and he put the GPL warning in his code. If you want to be really legal, you should probably not use the gesture recognition part of Amulet in commercial software without adhering to the GPL restrictions. We have evaluated the gesture code and feel that we could rewrite the necessary parts so we would not need to include the GPL copying notice. If someone would like to make a grant to the Amulet project to support this rewriting, we might be willing to do this; send mail to amulet@cs.cmu.edu. Then the entire Amulet system would be in the public domain.


1.4 Amulet will not uncompress with WinZip

Internet Explorer can be confused by the file name amulet.tar.gz. It renames the file to be more DOS-like as the file is brought across the Internet, amulet_tar.gz.  To get WinZip to decompress the file correctly, simply rename the downloaded file back to amulet.tar.gz and run WinZip on the file.


2. Mailing Lists


2.1 How do I get off and on the Amulet mailing lists:

For subscribing and unsubscribing to the amulet-users list send email to:  amulet-users-request@cs.cmu.edu


2.2 To contact the Amulet group:

Send mail to one of the amulet email addresses with problem reports and questions, to bring issues to the attention of the appropriate group within the project.

The amulet email addresses include:


2.3 To view archived indexed and hyperlinked messages from the amulet-users mailing list:

Link to the "Index of Messages on the Amulet-Users mailing list" from the Amulet home page. From the index, you can search for topics of interest.

You can go directly to the index using the URL

http://www.cs.cmu.edu/~amulet/hypermail/index.html


3. Compilers, Operating Systems, Frameworks, Contributions


3.1 What are the officially supported compilers/operating systems?

These are the compilers and platforms the Amulet developers have personally tested.

Supported Operating Systems and Compiler
Operating Systems Compiler(s)
SunOS gnu C++ 2.7.2; Centerline's Object Center 2.1
HP/UX gnu C++ 2.7.2; Centerline's Object Center 2.1
MacOS 7.6 and MacOS 8 CodeWarrior 10; CodeWarrior Pro 1
Windows 95 Microsoft Visual C++ V4.2;  Microsoft Visual C++ V 5.0
Windows NT 4.0 Microsoft Visual C++ V4.2; Microsoft Visual C++ V 5.0

Amulet shared libraries not supported on gcc versions before 2.7.0.

Others may be contributed and supported by users from time to time, but generally you will need to make certain changes to port to any other platforms. See the contributions page for details.

CodeWarrior 10 uses the older standard libraries, CodeWarrior Pro 1 requires MSL Standard C++ Libraries.


3.2 What the unofficially supported platforms contributed by Amulet users?

Users have made substantial contributions to Amulet in monetary contracts, suggestions and code. These include bug fixes, bug reports, and contributions of ported source code and make files.  Here is a partial list of contributed code that may be useful in your projects.

Make files

From time to time users port Amulet to other platforms and compilers. Please send complete files that contain updates/fixes to amulet@cs.cmu.edu Here is a list of contributed makefiles:

Contributed source code

Many Amulet users have created useful software that they are willing to contribute for the use of other people. These contributions are available can be found on the contributions page.

The software is not supported by the Amulet group. Any contribution may carry certain copyrights that are different from Amulet. Please consult the file or the author before using in commercial code.  These have not been tested by the Amulet staff. They may not even work on your particular platform.


3.3 Can I use Amulet with MFC?

Generally, Amulet and other toolkits do not coexist well together.  This includes MFC, which does not work with Amulet. The issue is that each framework likes to control the event loop and control the window drawing.  


3.4 Long compiles in VC 5

I've been astonished by the compilation time in VC 5. Or more accuratly by the linking time. To link the test examples (testopal, testgobs e.g.), it took about 10 min for each 'exe'. note: On a Cyrix 150+ with 32Mb RAM, HD Seagate 2.5Gb with NT 4.0.

Is there any software trick to decrease this linking time? If a small test sample takes 10 min. to link...What about a complete application ?

Its not Amulet's fault, it happens for all large apps. VC++ 4.2x did not have this problem.

VC++ 5.0 takes ages to link in release mode. The service pack (70MB!!) helps fix this problem.   That's it. Compilation time deacreased drastically from 10 min. to about 30 sec!  Here is the information:

http://www.microsoft.com/kb/articles/q168/9/12.htm

http://www.microsoft.com/kb/articles/Q151/5/01.htm


3.5 What about Java?

The User Interface Software Group first created a tool called Garnet in Lisp in 1988, and then in Summer of 1994 started working on Amulet.  It took about a calendar year, and over 4 man-years of work to create Amulet, without much research contributions.  Therefore, we are reticient to start yet another conversion. Java and C++ are enough different that we feel we would want to do a redesign and not just a transliteration.

However, we feel that Java would definitely benefit from many of the innovations in Amulet, including expecially the command object architecture (undo), constraints, input handling (interactors), and animation. We would certainly be interested in talking with anyone who wanted to fund the conversion with a grant, or do the conversion with our help!


3.6 How can I contribute to the Amulet project?

The Amulet project is currently funded mostly by a government grant, and we would certainly appreciate more industry support.  Please contact bam@cs.cmu.edu.  In exchange for a grant, we may be able to add new features that are important to your company, or possibly adjust the priorities of our enhancements to match your needs.

If we do not receive grants from users, support for Amulet will terminate soon. See the note about Amulet Support.

It is also useful to the Amulet project to have comments for the comments page, pictures of your applications for our pictures page, and a large list of users for our users page.  This helps with our presentations to demonstrate that Amulet is being widely used, for many different kinds of applications.

If you have created some software or widgets that you think other Amulet users might benefit from, we have a contributions page of user-contributed software.  Please send the information about your software to amulet@cs.cmu.edu.


3.7 Can I use Amulet with OpenGL?

One user has reported successfully using with OpenGL.  If you are interested in contributing code that adds OpenGL support to Amulet, wewould be most happy to make it available to other Amulet users.


3.8 How can I get Amulet to work with OpenWindows?

Apparently text data isn't sent to the input fields under OpenWindows unless you set a certain parameter. This should get around the problem. Add the following line to your .Xdefaults file:

OpenWindows.FocusLenience: True


3.9  Where are the user contribution files?

You can obtain contributions from the contributions web page.  Please be sure to read the disclaimers at the top of the page before downloading.


3.10 How does Amulet expect my compiler to find X11 libraries?

Sometimes users will encounter an error under Unix that is long and involved but includes a statement like this:

ld: cannot open -lX11: No such file or directory

The compiler cannot file the Xlib libraries or include files.  

In short, you may need to include the pathnames for you Xlib files in the AM_CFLAGS and the AM_LIBS lists in Makefile.vars.custom  the include path should be provided with the -I switch, and the library path should be provided with the -L switch. For more details see p 39 of the V3 manual which includes an example of what you need to do.


3.11 Why does Make show an error at the first line of Makefile?

This error typically appears when your make utility doesn't understand the include directive. You may want to try using another version of make.

Alternatively, you may be using the wrong version of the Makefile. Did you download the Unix version of Amulet, or the Windows 95/NT version? The Windows 95/NT version has a slightly different makefile, which uses "!include" as the include directive. You need the Unix version, which uses "include" as the include directive.


3.12 How can I fix so these errors in VC 5?

I get a list of errors that begins like and then goes on for a couple pages:

E:\amulet/include\amulet/types.h(32) : error C2371: 'bool' : redefinition; different basic types

E:\amulet/src/opal/opal.cc(960) : error C2440: 'type cast' : cannot  convert from 'const class Am_Value' to 'bool' Ambiguous user-defined-conversion

If you are using Microsoft Visual C++ 5.0, you should set your AMULET-VARS_FILE to Makefile.vars.MSVC5.win32. It omits the compiler switch -DNEED_BOOL that is required by previous versions of the Microsoft compiler.


3.13 How do I get Amulet to work with CodeWarrior Pro 2?

You can obtain a porting document from http://www.cs.cmu.edu/~amulet/CWPro2Port.txt


3.13.5 How about CodeWarrior Pro 3?

Date: Fri, 13 Nov 1998 13:17:54 -0500
To: amulet-users@cs.cmu.edu
From: David Kieras <kieras@eecs.umich.edu>
Subject: Re: Amulet and CodeWarrior3

I thought this might be useful for the group ...

  1. The distribution included some notes on updating to a version of CW subsequent to the original, which should be followed (as I recall, this involved things like different font names).
  2. The major problems concerned incompatibilities with fp.h and math.h - math.h now by standard includes some of the things previously in fp.h, and this could be dealt with only by a custom version of fp.h. I got amulet to work, giving set of problems #3:
  3. There were some puzzling problems in some of the examples - not working, or certain keystrokes not working. In at least one case, this was due to my not realizing that amulet knows only one run-time library at a time - if you build the no-debug library, it replaces the debug library, and so the inspector doesn't work! Others I am not sure about.
I found out from Metrowerks that the fp.h and math.h problems were supposed to be fixed in CWP4, and they sent a pre-release version of math.h that helped a lot; fp.h was under Apple control, so that had to wait for the official release. CWP4 should make bringing up amulet significantly easier.

I am now using CWP4, which version is even closer to standard in important ways, so I recommend it. But I haven't yet had a chance to get back to trying to bring up amulet under CWP4 - I'm planning to do that soon!

Please let me know more specifically what you are seeing, and I'll dredge my archives and see what I have that might be useful to you.

-- David Kieras, EECS Dept., Univ. of Michigan


3.14 How do I get Amulet to work on an SGI?

I have been having some problems compiling Amulet on a Silicon Graphics Indy R5000 under Irix 6.2....

Answer from Dean Edmonds <deane@gooroos.com>:

1) If you don't have GNU make installed (i.e. you are using SGI's standard make utility) then you will have to edit amulet/bin/Makefile and put a `-' immediately before each of the $(RM) commands. For example, the following:

       develop-shared:
			$(RM) $(ANY_OBJECT_FILE)
			$(MAKE) $(AS_SHARED) $(AS_DEVELOP)
would become:
       develop-shared:
			-$(RM) $(ANY_OBJECT_FILE)
			$(MAKE) $(AS_SHARED) $(AS_DEVELOP)
This is necessary because SGI's make dies whenever a file expansion (e.g. *.o) doesn't match any files.

2) Make the static version of the library. E.g:

       make develop-static
3) cd to the lib directory and create the shared version of the library by hand. E.g:
       cd ../lib
	   CC -w -shared -all libamulet.a -o libamulet.so

What about the following warning:

ld: WARNING 47: This module contains branch instruction(s) that might
degrade performance on an older version (rev. 2.2) R4000 processor.

Answer from Jay Gowdy <Jay_Gowdy@bagpipe.msl.ri.cmu.edu>:

I just ignore this, and it seems to have no practical impact. Does anyone really know what it means?

The tutorial's execution is good but when I pulse F1 to access the Inspector, tutorial make a core dumped?

Answer from Jay Gowdy <Jay_Gowdy@bagpipe.msl.ri.cmu.edu>:

Believe it or not, this is actually due to a relatively obscure bug in the old SGI C++ compiler (-o32). You can either change the definition of Am_Beep in src/opal/opal.cc to Am_Beep(const Am_Object& window=Am_No_object) or you can try to get amulet to compile with -n32. This takes a fair amount of work (including some source code changes to get over the fact the the newer MIPSpro SGI compilers are really insistent that bools are _not_ ints). I submitted those changes a while ago, but I can't remember if they made it into V3.0 or not (or if they are just in my copy).


3.15 How do I get Amulet to compile with gcc-2.8.x?

Answer from Michiel Ephraim <michiel.ephraim@research.techforce.nl>:

The definition of NULL was changed from gcc-2.7.x to gcc-2.8.x.

The quick and dirty solution is to replace "NULL" with "0" on the offending lines. Someone else on this list suggested "Am_No_Object" instead of "0".


4. Technical information, Am_Object, Objects


4.1 Amulet naming conventions:

See also the V3 manual on page 43.

All exported symbols start with Am_ except for C++ methods and C++ instance variables of objects (e.g, Am_Button, but obj.Create() ) since Create is a method).

All exported symbols use full words spelled out (e.g.: Command instead of Cmd)

All multi-word symbols used underscore between the words (e.g. Am_Menu_Line_Command).

The first letter of each word is capitalized.

All constants are in ALL CAPS (except for the preceeding Am_). Slot names are constants, so they are in all caps: Am_LEFT.


4.2 To retrieve an Amulet object by name:

See the V3 manual on page 94.

#include <amulet.h>
// create an object named "line5"
Am_Object new_line = Am_Line.Create("line5")
// retrieve the object named "line5"
Am_Value val = Am_Value::From_String("line5");
Am_Object obj = val;

Note that many different types can have a name, so the From_String call returns an Am_Value of the appropriate type.  To be more careful, you might check to see that the value is Valid and that it is an object:

if (val.Valid() && val.type == Am_OBJECT) 
	obj = v;

Also, be aware that this only works when Amulet is compiled for debugging (-DDEBUG). When Amulet is compiled with debugging turned off, the names of Amulet objects are just thrown away.

Here is some additional information about Amulet object names:

The object names:

o1 = Am_Rectangle.Create("R"); o2 = Am_Rectangle.Create("R");


4.3 To set environment variables under Windows95

The Amulet manual documents how to set environment variables under Windows NT. Under Windows 95, you need to set environment variables in the file AUTOEXEC.BAT, which you should find at the top level on your C: drive. The syntax is "set var=value", so if you wanted to set AMULET_DIR to C:\AMULET you would write:

SET AMULET_DIR=C:\AMULET


4.4 How can I call a C++ member function from an Amulet object?

Amulet methods use a pointer to the C++ function in order to store the method in a slot of the Amulet object.  As discussed in the standard C++ FAQs, you cannot generate a pointer to a C++ member function since it wouldn't know which C++ object the method should be associated with.  Instead, you should store the C++ object into a slot of the object,  (see FAQ item 5.2 about how to do this) and then write a new Amulet method (using Am_Define_Method) that calls the desired member function of that object.


4.5 How can I make Amulet executables smaller?

There is a discussion of this in the V3 manual on page 39.  Much of the size is taken up with debugging information, some generated by the compiler and some by Amulet.  Programs will be much smaller, and run somewhat faster, by recompiling the Amulet libraries will all debugging turned off.  The executable for a small application compiled with full optimizations and debugging off on the PC will be about 500K.  On Unix using gdb, you can also use shared libraries to make the size of the executable files be small.


4.6 To reference the same C++ object from multiple slots

Regular Amulet wrappers are specifically designed to NOT share the same C++ object among different Amulet objects. In particular, wrappers do not keep back-pointers to all the objects that use them. Therefore, when a wrapped C++ object is changed, it is not able to notify all the Amulet.  

However, this is not true of pointer_wrappers or objects stored into slots using Am_Ptr casts.  In this case, all objects will share a pointer to the same C++ object.  However, in this case, Amulet will not know when the pointed to C++ object changes, so the programmer should be sure to call Note_Changed on the Amulet object whenever the C++ object changes.

Alternatively, instead of referencing the same C++ object from multiple places, put the C++ object into one slot of one Amulet object (maybe a special off-screen Amulet object) and use constraints to reference that slot whereever else the value is needed. Then as long as the one main slot is notified (by Note_Changed or a Set on that slot) when the C++ object changes, then all the other uses will be automatically notified by the constraint system.


4.7 All about memory leaks

Amulet users will often run certain tools to help them debug their code and find memory leaks. When they do, Amulet reports what appear to be leaks. In fact, we shouldn't call them "memory leaks", because they don't cause memory exhaustion at runtime -- they're just not cleaned up at exit.

We made a valiant effort to remove all the causes of the memory leak warnings in V3, but discovered it was just too difficult. A number of global variables are initialized with data structures that do not get much bigger after initialization (so they shouldn't cause much problems for running programs), and we could not find a good way of cleaning them up on exit. We spent over a man-month on this issue and decided it was not worth any more time. If someone would like to make a grant or donation to the project to support this effort, we can spend the time to eliminate the rest of the leaks.


4.8 How to create a new, custom object

Sometimes Opal might not be fast enough.  In these cases, you might want to create your own new, custom object. NOTE: This is not particularly recommended, and should only be attempted by expert Amulet users.

Make a single Amulet object as a subclass (instance) of Am_Group that is the size of all the custom object, and then override the Draw method of the new object

What do you mean a subclass of Am_Group of the "size of all the moving rectangle?" Is it simply a drawable area whose Draw method can be overridden? Is there a way to use the GEM primitives for such a drawing area?

All Amulet objects need to have their size specified (left, top, width, height) and it is important that all object drawn are clipped to that bounding box.

Creating the new custom object as an instance (like a subclass) of one of the built-in graphical objects will allow it to inherit many of the standard methods. Am_Group seemed like the most appropriate for your application, but an instance of the fundamental Am_Graphical_Object might work just as well.

If you add new slots that control the drawing, you have to make sure Amulet knows that the object needs to be redrawn if these values change.  This is done using the demons.  For example:

  Am_Object_Advanced temp = (Am_Object_Advanced&)my_object
  temp.Get_Slot (SLOT_THAT_CHANGES).Set_Demon_Bits (Am_MOVING_REDRAW |
						Am_EAGER_DEMON);
  temp.Get_Slot (ANOTHER_SLOT).Set_Demon_Bits (Am_STATIONARY_REDRAW |
						Am_EAGER_DEMON);

Am_MOVING_REDRAW is used for slots that when changed cause the object to be in a different place or size, and Am_STATIONARY_REDRAW is used for slots that do not cause the object to be a different size or place.


5.  Am_Values, Am_Lists, Listboxes


5.1 To display a listbox

When using V3, you can put an Am_Menu inside an Am_Scrolling_Group as below:

Am_Object list_in_box = Am_Menu.Create("list in the box")
  .Set(Am_WIDTH, Am_From_Owner(Am_WIDTH))
  .Set(Am_HEIGHT, Am_From_Owner(Am_HEIGHT))
  .Set(Am_ITEMS, Am_Value_List()
  .Add("First Item")
  .Add("Second Item")
  .Add("Third Item"))
  ;
Am_Object list_box = Am_Scrolling_Group.Create("a list box")
  .Add_Part(list_in_box);

In the next version, there will be a built-in listbox widget.


5.2 To store a pointer to a custom data structure (or class) in an Am_Value_List or Object slot

V3 introduced the Am_Pointer_Wrapper to make it easy to "wrap" pointers to other data structures, to privide nice type checking and printing of external data structures.  See the V3 manual on page 112.  For example:

//In the .h file:
class my_class {
public:
  ... // whatever is required
};
Am_Define_Pointer_Wrapper(my_class)
// In the .cc file:
class my_class_wrapper_support : public Am_Type_Support {
public:
  void Print (ostream& os, const Am_Value& val) const
  { my_class * m = Am_my_class(val).value;
    os << print out my_class's data
  }
} my_class_wrapper_support_obj;
Am_Define_Pointer_Wrapper_Impl(my_class, &my_class_wrapper_support_obj);
my_class *ii = new my_class;
obj.Set(SLOT, Am_my_class(ii)); //wrap the pointer to my_class
my_class *ii2 = Am_my_class(obj.Get(SLOT)).value;

If you don't want to use the Pointer_Wrapper support, you should cast your pointers into the type Am_Ptr. This works better than (void*) or (char*) since Am_Ptrs will work on any platform.

CTest *pTest1 = new CTest, *pTest2;
Am_Value_List list;
list.Add( (Am_Ptr)pTest1);
list.Start();
pTest2 = (CTest *) (Am_Ptr) list.Get();

The (Am_Ptr) cast is needed because the compiler doesn't know how to convert a Am_Value to random pointer, but if you tell it to go through a (Am_Ptr) pointer first, it will work fine.  In addition, Am_Ptr correctly provide the correct cast depending on the platform and compiler, since some compilers require (void*) and others (char*).


5.3 To completely delete the Am_Value_List that has pointers (to custom data structures) in it

Since Amulet won't know anything about the pointers stored in the list, it cannot delete the storage, therefore, you should iterate through the list and delete all the objects explicitly before calling Make_Empty or deleting the Am_Value_List.


5.4 What will be the current position after I delete the item at the current position of a list?

Will it be the next one? Or will it be invalid?

Actually the answer is documented in the V3 manual, look in the index under "Delete (on lists) method"! (page 107)

The Delete method destroys the item at the current position. It is an error to call Delete if there is no current element. The current pointer is shifted to the element previous to the deleted one.

Note that this applies to Am_Value_List objects, not to other iterators.

One word of caution -- if you delete the element at the start of the list, then the current element will positioned at the NULL list item between the Last and First elements, and Get will fail. You have to force the current element past the last by calling Next.


5.5 What the meaning of Am_ID? How to use it?

As explained in the V3 manual on page 259, the Am_ID field will be the return value of the widget if it is set into a command. Otherwise, if the Am_ID slot is 0 or not present, then the Am_LABEL of the command is returned instead.

Sometimes my code will have problems at run-time. I have set the Am_VALUE to arrow_gif, so at run-time, the 3rd button should be displayed as it has been pressed (like a bounding box). However, it didn't. After I delete all the codes of the "Am_ID", it works.

If you use the Am_ID slot, then you need to set the Am_VALUE of the widget to the ID value you want, rather than the LABEL value you want (e.g., set it to be 1 instead of arrow_gif).


5.6 What are all these errors in converting bool to Am_Value?

The errors look like this:

'typecast' cannot convert from 'Const class Am_value' to 'bool'

The issue has to do with compiler support for the new C++ keyword "bool". It turns out that this can be a major problem when porting to new systems. We have accomodated both compilers that support it and those that do not. What I see happening is there is a mismatch in the Amulet headers and your compiler, meaning that bool is supported

Check to see how your compiler turns on and off support for bool. Or you can find a way to "force" the header files to accept, add a line in amulet.h if you need to, either

#define NEED_BOOL 1

or

#undef NEED_BOOL

depending on whether your compiler supports bool or not.

That should make turn on or off the Am_Value to bool and other conversions.

If you are using Microsoft Visual C++ 5.0, you should set your AMULET-VARS_FILE to Makefile.vars.MSVC5.win32. It omits the compiler switch -DNEED_BOOL that is required by previous versions of the Microsoft compiler.


6. Widgets, Wrappers


6.1 To create a new widget

It is generally pretty easy to creat new widgets using the Opal level graphics primitives and the Interactors. Using Gem (as some of the "built-in" widgets do) is only for optimizations.

We do not use the native widgets on the platforms because it would be MORE difficult and less functional than re-implementing them. We would appreciate any contributions from the community of implementations of widgets we have not yet had time to do.


6.2 To notify slot that a wrapper value or list has been changed

When C++ objects are stored as wrapper values in slots, Amulet cannot know when a program destructively modifies object behind its back. Slots must be notified explicitly in order to know that a wrapper value has changed.

The method Note_Changed provides a means to notify a slot that its value has changed through destructive modification.

Some_Wrapper wrapper;
obj.Set (FOO, wrapper);
wrapper.Destructively_Modify ();
obj.Note_Changed (FOO);

The details are given in the V3 manual page 127 and includes an example that shows how to let an Am_Value_List know when a list item has been changed.


6.3 How set the Am_VALUE of a Widget

Widgets interface to your application through command objects added as parts of the widgets.  But to either get or set the Am_VALUE of the widget, you should access the Am_VALUE slot of the widget itself, not the command object. This is described on page 254 of the V3 manual.

widget.Set(Am_VALUE, 3);

You can also put a constraint into the Am_VALUE slot, if you want the value shown by the widget to track a slot of another object.

It is a common mistake to set the value in the Am_COMMAND object inside the widget.  

See also


6.4 How can I press the button on a button panel? How do I get a button panel to show the current value?

Is there any methods I can set to "press the button" on the button panel? I am thinking when users select a line or a box, the program will detect its Am_LINE_FILL_STYLE, and see the correct button to reflect its style.But I don't know how to do it.

Setting the Am_VALUE of the widget to the correct value will make that button look pressed in.   NOTE: if it doesn't seem to be showing up, try setting the widget's Am_FINAL_FEEDBACK_WANTED slot to true (see the V3 manual on page 262).

If you can't tell what the right value is, you can always press the button as the user, then pop up the inspector on the widget and see what the value of the Am_VALUE slot is.

Note that the value you set must be the correct type. For example a radio button must be a single value, a checkbox must be an Am_Value_List of values, and buttons are single values.

If you want multiple items to be selectable in an Am_Button_Panel, set the Am_How_Set slot of the widget and you can select multiple items and then the Am_VALUE slot must be a Am_Value_List.


6.5 Menu updates to reflect the current style of the selected object

I need some hints to do this function: "The line style menu is updated to reflect the line style of the selected object." (I use the Am_Button_Panel to implement the line style menu)

You might have a constraint in the line style menu's Am_VALUE slot that depends on the value of the selection handle's value (which will be the selected object). Be sure to make this constraint be xxx.Multi_Constraint(true) since the Am_VALUE slot will also be directly set when the user clicks on the menu.

OR, you can add a DO_METHOD to the command in the selection handles widget that imperitively updates the menu.


6.6 How do I get a procedure to be called by a button?

You can't put your procedure into the button. You have to put the method into the Am_DO_METHOD slot of the command object that is attached to the button. Also, you have to use a method that is defined using Am_Define_Method, and not just a regular procedure.  This is shown on page 77 and the top of p 78 in the manual.


7. Graphics, drawing


7.1 To provide feedback on a background window

Amulet does not provide any way to draw on the background behind all windows (in the area where there aren't any windows).  However, there is a neat feature where you can drag around a little window and use that window as the feedback object, so it will appear wherever the cursor is.  The main disadvantage of this trick is that it is somewhat slow and the feedback must be a rectangle.  However, it does work on all platforms.  See the V3 documentation on page 216-217 (section 5.4.3).  To see this feature compile testinter and move the objects around after pressing capital W.


7.2 About dash lines

I cannot set the "edge of roundtangle" to dash lines. It didn't work for the edge of rectangle, either. I only can create dash lines.

On the PC, the line styles using dashed don't work, they just look solid. Maybe use Am_Red or something instead of dashed.


7.3 To add selection handles to my objects?

This is very easy.  You basically create an Am_Selection_Widget object and add it to the group the objects are in. The best example is in examples/example1.cc. There are several steps involved, but the example is complete.

Line 250 shows how to add an instance of the standard selection widget, and on line 259 attaches it to the window group.


7.4 To keep an object inside the window?

The move grow interactor lets me drag the mouse outside of a window, and then the Am_LEFT slot of the 'moved' object gets a negative value.

There are two ways to do this.

a) One way is to set the Am_RUNNING_WHERE_OBJECT slot to a containing graphical object.  When the object is stretched outside the containing graphical object, the interactor stops operating.  The result is that the object won't continue to grow past the boundary of the container.  If you want to refine the container further, set the Am_RUNNING_WHERE_TEST slot, which can check for the mouse movement and respond as you intend. You can see this on page 216 of the v3 manual.

Or

b) The more common solution is to use a grid method. The grid will be used hold the object inside the window or other rectangle regardless of where the mouse goes. Information about this is on p 202 of the manual.   There is an example in examples/space.cc. When you run space, in the lower right hand corner there is a box that slides adround that must stay within space game's universe. In it, we set the Am_GRID_METHOD slot to a method called keep_inside_window. keep_inside_window at around line 745 shows how this is done.


7.5 My object looks funny, clipped or wrong size, how come, how debug?

First check the inspector for Am_LEFT, Am_TOP, Am_HEIGHT, Am_WIDTH values to see if they are reasonable. Then, if these are set through constraints, set break points in your code to make sure the formulas are being called and are responding as you expect.  If you "flash" the object using the "Objects/Flash Object" command in the inspector, then this will often print a message to the console describing why the object isn't visible.

Also, remember that groups clip objects inside of them, so make sure that the groups that the objects are in are big enough.


7.6 How can I draw custom image formats in Amulet?

The only image type we support directly is GIF. Other image support is unfortunately lacking. We do not support any other types including any of the platform specific imaging. We would certainly like to add other image types, if someone is interested in contributing to the Amulet project.

However, Amulet does support most of the functions that draw commonly found in platform toolkits. These include line, rectangle, and a whole set of shapes. If you are able to parse your particular image type, you can use the many Gem functions in Amulet to draw the picture. And of course, when you use the Gem functions your drawing code will be cross platform.


7.7 How can I debug double clicking?

Sometimes the single click interactor might seem to steal the double clicks. The default start character for interactors is ANY_LEFT_DOWN which gets both single and double clicks. Therefore, the default interactors will operate on both single and double clicks. If you want an interactor to ONLY work on single click, then change its Am_START_WHEN slot to be "LEFT_DOWN" or equivalent, and then the double click interactor's Am_START_WHEN would be "DOUBLE_LEFT_DOWN" or equivalent. This is explained more completely on p 190-191 of the V3 manual.

Another way to do this is to make sure the double click interactor gets checked first. This can be insured by setting the priority of the double click interactor to be higher than the single click interactor. If you set the double click interactor priority to be greater than 101, double clicks will go to the interactor wanting double clicks. Priority levels are described on p 214-215 of the version 3 manual.


7.8 Is there an easy way to get the actual mouse-position?

You could create an interactor and attach it to a window, and make it always running.


7.9 How do I get an interactor to be always running?

To get the interactor to be always running, see the code snippet on page 218 of the Amulet V3 manual (section 5.4.5). If you want to get to see every mouse move event, you can set a method into the Am_INTERIM_DO method of the command object in the interactor, see page 222 (section 5.5.2) of the manual.


7.10 How do I display my own graphical object?

You might create a custom object with your own Draw method, and then put this object on top of the rectangle. Amulet will call the draw method of the object at the correct times. Objects can be moved to the top using Am_To_Top, and the draw method will be called whenever any of the slots with "demons" attached change values. You might look at the code of a widget, like the scroll widget (in src/widgets/scroll_widgets.cc) to see how a custom object is created. We should probably create a simpler example of how to make an object with a custom draw method.


8. Constraints


8.1 My constraint isn't working, how come, how debug?

First check the code to be sure your constraint is being called by putting a breakpoint  or print statements in your code. It may be that the constraint is not being called as you expect. If that is correct, display the object that the constraint is in using the Inspector.  If the slot doesn't have a constraint anymore, then probably the slot is being explicitly Set, and this is removing the constraint.  If you want the constraint to stay even when the slot is set, then make the constraint be .Multi_Constraint() (see page 132 of the manual).

If that isn't the problem and the constraint is there, double-click on the constraint, and then pop up the constraint dependencies window using the menu command Windows/Show Constraint Dependencies.  This window shows what the constraint depends on.  Also, in the Inspector, you can select the slot the constraint is in and set a trace or break on the slot to see when the slot is changing value.

If you find the constraint is not being re-evaluated when it should be, it is because a dependency is missing. Sometimes a constraint is re-evaluated before the object is created, in which case no dependency is created. This will be evident in the Inspector.  


9. Animations


9.1 Am_INTERRUPTIBLE doesn't seem to make my animation uninterruptible. Why doesn't it work?

You need to call Validate() after setting each point of the animation. This crucial observation was omitted from Section 6.9 of the Amulet 3.0 manual, where uninterruptible animations are discussed. The Validate() method ensures that the object system is consistent, by running all pending demons and evaluating invalid constraints. (Calling Get() on any slot would have the same effect, by the way.) For uninterruptible animations, calling Validate (or Get) performs a crucial role: it delimits the points of the animation. For example, this code creates a rectangle and animates it around a square path. Notice that only one coordinate needs to be changed for each point of the square:

Am_Object animator = Am_Animator.Create()
  .Set (Am_INTERRUPTIBLE, false);

Am_Object moving_rect = Am_Rectangle.Create()
  .Set (Am_LEFT, Am_Animate_With (animator))
  .Set (Am_TOP, Am_Animate_With (animator));
  .Set (Am_TOP, 20)      // animates from (0,0) to (0,20)
  .Validate ();
  .Set (Am_LEFT, 20)     // animates from (0,20) to (20,20)
  .Validate ();
  .Set (Am_TOP, 0)       // animates from (20,20) to (20,0)
  .Validate ();
  .Set (Am_LEFT, 0)      // animates from (20,0) to (0,0)
  .Validate ();

Without the Validate calls, this sequence of Sets would be indistinguishable from an animation that jumps directly to (20,20) and back to (0,0).

Since Get has a similar effect to Validate, you need to be careful not to use Get before you're done setting a point of the animation. So this wouldn't work as desired:

// Don't do this
moving_rect
  .Set (Am_LEFT, some_other_object.Get (Am_LEFT))
  .Set (Am_TOP, some_other_object.Get (Am_TOP))
  .Validate ();

Instead, make all your Get calls before setting the point:

// This should work
int l = some_other_object.Get (Am_LEFT);
int t = some_other_object.Get (Am_TOP);
moving_rect
  .Set (Am_LEFT, l)
  .Set (Am_TOP, t)
  .Validate ();


10. Errors, debugging


10.1 Getting a NULL object error

There are a number of common ways this happens:

	xxxx.Add_Part(o1 = xxx.Create()
 		      ...)
	    .Add_Part(o2 = o1.Create() //DOESN`T WORK

Another example is:

	widget.Set(Am_ITEMS, Am_Value_List()
                      .Add(c = Am_Command.Create() ...)
		  )
	      .Set(Am_VALUE, c); //DOESN'T WORK

Instead, you must terminate the statement and start a new statement:

	xxxx.Add_Part(o1 = xxx.Create()
 		      ...);
	xxxx.Add_Part(o2 = o1.Create() //fine
	widget.Set(Am_ITEMS, Am_Value_List()
                      .Add(c = Am_Command.Create() ...)
		  );
	widget.Set(Am_VALUE, c);  //fine


10.2 To get rid of the warning messages in my formulas

When I compile certain Am_Define_Formulas, I get warnings for each one of them that look like this:

clustervisr3.cc: In function `int right_of_printButton_proc(class Am_Object&)':
clustervisr3.cc:1409: warning: unused parameter `class Am_Object & self'

The reason you are getting the warnings is that we've turned on compiler warnings by default. You can certainly go back and change the warnings level in the command line.  That's one "fix". Or you can fix the code and instead of using Am_Define_Formula, you can use Am_Define_No_Self_Formula. This is described on p101 of the manual.

When you use Am_Define_No_Self_Formula it comments out the unused variable name in the macro so the compiler will know it isn't used inside the formula.


Back to the Amulet Home Page.

Maintained by:

Bruce D. Kyle (last updated Jan 9, 1998)