
		      _____  _             _
		     |  __ \| |           (_)
		     | |__) | |_   _  __ _ _ _ __  ___
		     |  ___/| | | | |/ _` | | '_ \/ __|
		     | |    | | |_| | (_| | | | | \__ \
		     |_|    |_|\__,_|\__, |_|_| |_|___/
				      __/ |
				     |___/


			   by Shawn Hargreaves




Introduction
------------

   It is very easy to extend the grabber and other datafile tools by writing 
   new plugin modules. These can add support for totally new types of 
   object, or they can just provide some additional import/export routines 
   to make one of the existing types work with a wider range of file 
   formats. Plugins are also capable of hooking into the grabber menu 
   system, either by adding new functionality to one of the existing menus 
   or by creating whole new menu options of their own.

   Most of the standard grabber functionality is in fact implemented as 
   plugin modules. Try commenting out the contents of all the .inc files in 
   this directory, and then recompiling the grabber: you will find that 
   several of the menu items have gone missing, and it won't recognise 
   anything other than the basic file and binary data objects!

   This file is not a complete manual for the plugin architecture. It 
   assumes that you already have a pretty good idea about how datafiles and 
   the GUI system operate, and that you aren't afraid of reading sources to 
   learn how they work. Your best bet is to have a look through datedit.h to 
   see what functions are available, and then use one of the existing 
   plugins as a basis for your addition. Using this file together with the 
   sources should be enough to get you going, but as always, feel free to 
   ask for help if you get stuck...



The Basics
----------

   A plugin is implemented as a collection of files which are copied into 
   the tools/plugins directory, and will automatically be linked into the 
   grabber, dat utility, and other datafile tools. To install a plugin, you 
   can simply copy it to the plugins directory and then rebuild Allegro.

   At the very least, you must provide a .c source file and a .inc setup 
   file. The .inc file will be included directly into datedit.c, and will be 
   executed once when the system initialises. From here you can call 
   whatever routines are needed to activate your plugin, which will usually 
   include at least one of the datedit_register_*() functions.

   If a plugin makes use of external libraries, it can also provide a script 
   file, which contains additional linker options to be used when building 
   the datafile programs. This script has a different extension for each 
   supported platform, so that your plugin can use different linker options 
   depending on the compiler. The djgpp version uses .scr scripts, Watcom 
   uses .scw, MSVC/BCC use .scv, MinGW uses .scm and Unix uses .scu.

   There are no restrictions on what names you can give these files other 
   than the required extensions, but to minimise the danger of namespace 
   conflicts I recommend that you stick to my convention of calling them 
   dat{type}.*, where {type} is the ID for the type of object being 
   implemented by this plugin.

   There are three types of plugin interface, which can be used together or 
   in isolation. Object plugins add totally new types of datafile object, 
   and provide all the functions needed to manipulate and display this data. 
   Import/Export plugins provide the ability to read and write data from 
   external file formats, and can be used to add import and export functions 
   for both the predefined and custom object types. Finally, menu plugins 
   respond to user interface actions in the grabber, and can either hook 
   into the existing menu system or add completely new menu options of their 
   own.



Object Plugins
--------------

   An object plugin is installed by calling the function:

      void datedit_register_object(DATEDIT_OBJECT_INFO *info);

   These plugins are defined by a header structure in the form:

      typedef struct DATEDIT_OBJECT_INFO
      {
	 int type;
	 char *desc;
	 void (*get_desc)(DATAFILE *dat, char *s);
	 void *(*makenew)(long *size);
	 int (*save)(DATAFILE *dat, ..., PACKFILE *f);
	 void (*plot)(DATAFILE *dat, int x, int y);
	 int (*dclick)(DATAFILE *dat);
	 void (*dat2s)(DATAFILE *dat, char *name, FILE *file, FILE *header);
      } DATEDIT_OBJECT_INFO;

   Object plugins add support for completely new types of object, and it 
   does not make sense to install more than one of these for the same type 
   ID (if you do, the second plugin will simply never be used).

   The fields in this structure are:

   'type'
      The object type ID, as produced by the DAT_ID() macro.

   'desc'
      ASCII description of this object type.

   get_desc()
      Optional. Fills 's' with a description of the object. Implementing 
      this function allows you to provide a more detailed description (eg. 
      "32x32x8 bitmap" rather than just a generic "bitmap"). If you leave it 
      NULL, the 'desc' field will be displayed instead.

   makenew()
      Creates and returns a pointer to a new object of this type, and if the 
      object is going to use it, sets 'size' to the object size in bytes.

   save()
      Saves the object into an Allegro datafile. This takes quite a lot of 
      parameters, but you can ignore all of them except the 'dat' and 'f' 
      values: the others are only needed for nested datafiles. Returns TRUE
      on success and FALSE on failure.

   plot()
      Optional. Draws the object onto the grabber screen at the specified 
      location. You must be careful to make sure that this routine will work 
      in all screen resolutions and color depths!

   dclick()
      Optional. Called when the user double-clicks on an object in the 
      grabber.

   dat2s()
      Optional. Used by the dat2s utility to convert an object into 
      assembler source code. If you don't implement this, your custom object 
      type will not be supported by dat2s.

   You will notice that this interface does not provide any support for 
   loading these objects from datafiles, or for reading/writing external 
   file formats. That is because the datafile loading is handled internally 
   by the core Allegro lib (you should use register_datafile_object() to 
   install your load handler), and the import/export is handled by a 
   different type of plugin (see below).

   The 'datsample_info' interface from datsamp.c is a good basic example of 
   an object plugin.



Import/Export Plugins
---------------------

   An import/export plugin is installed by calling the function:

      void datedit_register_grabber(DATEDIT_GRABBER_INFO *info);

   These plugins are defined by a header structure in the form:

      typedef struct DATEDIT_GRABBER_INFO
	 {
	    int type;
	    char *grab_ext;
	    char *export_ext;
	    void *(*grab)(char *filename, long *size, ...);
	    int (*export)(DATAFILE *dat, char *filename);
	 } DATEDIT_GRABBER_INFO;

   Import/export plugins add file format support to existing types of 
   object. You will usually need at least one of these for each object 
   plugin that you install, but you can also use them to extend the 
   predefined object types. There is no limit on how many import/export 
   plugins can be attached to a single type of object, or on how many file 
   formats can be supported by a single plugin.

   The fields in this structure are:

   'type'
      The object type ID, as produced by the DAT_ID() macro.

   'grab_ext'
      List of the file extensions that are supported for reading data, 
      separated by semicolons. May be left blank if this plugin only 
      provides export functions.

   'export_ext'
      List of the file extensions that are supported for saving data, 
      separated by semicolons. May be left blank if this plugin only 
      provides import functions.

   grab()
      Reads a new object from the named file, returning a pointer to it. If 
      this type of object requires it, also sets 'size' to the size of the 
      object in bytes.

   export()
      Saves an object into the named file. Returns TRUE on success and FALSE
      on failure.

   The 'datfont_grabber' interface from datfont.c is a good example of an 
   import/export plugin that supports several different file formats.



Menu Plugins
------------

   A menu plugin is installed by calling the function:

      void datedit_register_menu(DATEDIT_MENU_INFO *info);

   These plugins are defined by a header structure in the form:

      typedef struct DATEDIT_MENU_INFO
      {
	 MENU *menu;
	 int (*query)(int popup);
	 int flags;
	 int key;
      } DATEDIT_MENU_INFO;

   Menu plugins are based on the Allegro GUI menu structure. If you install 
   a plugin for a menu option that already exists, it will hook into the 
   existing menu, but you can also add completely new options by specifying 
   a totally new menu text string.

   The fields in this structure are:

   'menu'
      Points to the Allegro menu structure for this option. Note that this 
      is only one single menu item, not a whole array of entries. The flags 
      and dp fields from this structure will be overridden by the grabber, 
      but you must fill in the text field with your menu text string, and 
      either the proc function pointer with your action routine (for simple 
      command menus like the "grab" function), or the child field with a 
      pointer to a nested menu (for hierarchical structures like the "new" 
      menu).

   query()
      Optional. If not NULL, this routine will be called to check whether 
      this plugin command is suitable for use in the current situation. For 
      normal pulldown menus, the 'popup' parameter will be FALSE, and you 
      have a chance to either return TRUE, in which case your command will 
      be used, or FALSE, in which case the default processing will be 
      carried out (this allows a plugin to take over standard commands like 
      "grab", but reject them when anything other than their specific type 
      of object is selected, so that the normal grab command will still work 
      for other object types). For popup (right mouse button) menus, this 
      routine will be called immediately before the menu is displayed, with 
      the 'popup' parameter set to TRUE. If you return FALSE from this call, 
      your command will not be included in the popup (this is how things 
      like 'autocrop' are able to only appear when you right-click on a 
      bitmap object).

   'flags'
      Indicates where in the menu system you would like your command to be 
      added. This is a bitfield containing any combination of the values:

	 DATEDIT_MENU_FILE    - add it to the File menu
	 DATEDIT_MENU_OBJECT  - add it to the Object menu
	 DATEDIT_MENU_HELP    - add it to the Help menu
	 DATEDIT_MENU_POPUP   - include it in right-click popup menus
	 DATEDIT_MENU_TOP     - a new entry in the topmost menu bar

   'key'
      If non-zero, this is the ASCII code of a keyboard shortcut for your 
      command. Please be cautious in your use of these, because if several 
      plugins try to hook the same keyboard shortcut, obviously only one of 
      them is going to be able to get it :-)

   The 'datworms_menu' interface from datworms.c is a good example of how to 
   add a new menu command, and 'datpal_grabber_menu' from datpal.c shows how 
   to hook into an existing command (it adds a custom function so that 
   palettes can be grabbed from a previously read bitmap, rather than 
   directly from a disk file).



Misc
----

   Bear in mind that these plugins are used by tha dat, dat2s, and pat2dat 
   utilities as well as the grabber, so you cannot assume anything about the 
   system setup while your code is run. The menu commands, view, and dclick 
   functions will only ever be used in a graphics mode (which could be any 
   resolution and color depth), but the other functions may equally well be 
   called from a graphics or text mode environment.

   For displaying messages, errors, prompting the user for input, etc, use 
   the datedit_msg(), datedit_error(), and datedit_ask() functions. These 
   are implemented as printf() calls by the text mode utilities and as alert 
   boxes by the grabber, so they will work correctly in any situation.

   There are lots of useful helper functions in datedit.h. Perhaps most 
   importantly when implementing menu commands, grabber_single_selection() 
   returns a pointer to the currently selected object (NULL if there is a 
   multiple selection), and grabber_foreach_selection() iterates through 
   every selected object, using a callback function to let you process 
   multiple objects with a minimum of hassle.



And Finally
-----------

   Good luck!
