Este fichero es una traducción al español del fichero allegro/tools/plugins/plugins.txt en el original. ============================================================================ _____ _ _ | __ \| | (_) | |__) | |_ _ __ _ _ _ __ ___ | ___/| | | | |/ _` | | '_ \/ __| | | | | |_| | (_| | | | | \__ \ |_| |_|\__,_|\__, |_|_| |_|___/ __/ | |___/ por Shawn Hargreaves Introducción ------------ Es muy sencillo extender el grabber y otras utilidades de ficheros de datos escribiendo nuevos módulos plugin. Estos pueden añadir soporte para tipos de objetos totalmente nuevos, o pueden añadir algunas rutinas funcionales importar/exportar para hacer que un tipo existente pueda trabajar con un rango más amplio de formatos de fichero. Los plugins también son capaces de enganchar el sistema de menú de grabber, añadiendo nuevas funciones a un menú existente o creado todo un nuevo menú de opciones propias. La mayoría de las funciones estándar están implementadas de hecho como módulos plugin. Pruebe renombrar todos los ficheros .inc del directorio tools/plugins a otra extensión, y recompile grabber: descubrirá que faltan algunas opciones de los menús, y ¡ya no podrá reconocer otra cosa que no sean los objetos básicos de fichero y datos binarios! Este fichero no es un manual completo sobre la arquitectura plugin. Asume que ya tiene una buena idea sobre cómo funcionan los ficheros de datos y el sistema GUI, y que no tiene miedo de leer el código fuente y aprender qué es lo que hace. Su mejor apuesta es mirar el fichero datedit.h para ver qué funciones están disponibles, y usar alguno de los plugins existentes como base del suyo. Usando este fichero junto con el código fuente debería ponerle en buen camino, pero como siempre, puede pedir ayuda si se queda atascado... Lo Básico --------- Un plugin es implementado como un conjunto de ficheros que son copiados en el directorio tools/plugins, y serán enlazados automáticamente con las utilidades grabber, dat y otras. Para instalar un plugin, sólo debe copiarlo al directorio de plugins y reconstruir Allegro. Como mínimo, debe crear un fichero .c de código fuente y un fichero .inc de configuración. El fichero .inc será incluido directamente en datedit.c, y será ejecutado una vez cuando el sistema se inicialice. Desde ese momento puede llamar cualquier rutina que necesite para activar su plugin, que normalmente incluirá como mínimo una de las funciones datedit_register_*(). Si un plugin hace uso de bibliotecas externas, puede proveer un fichero de comando .scr, que contenga las opciones adicionales de enlace que requiera su plugin. No hay restricciones sobre qué nombres puede dar a estos ficheros aparte de la extensión, pero para minimizar el peligro de conflictos de nombre, le recomiendo que use mi convenio en llamarlos dat{tipo}.*, donde {tipo} es la identificación ID del tipo de objeto implementado por el plugin. Hay tres tipos de interfaz de plugin, que pueden ser usados en conjunto o aisladamente. Los plugins de objeto añaden nuevos tipos de objeto a los ficheros de datos, y proveen todas las funciones necesarias para manipular y visualizar los datos. Los plugins Importar/Exportar le dan la posibilidad de leer y escribir datos de tipos de ficheros externos, y pueden ser usados para importar y exportar funciones para tanto objetos predefinidos como propios. Finalmente, los plugins de menú responden a acciones del usuario con la interfaz del grabber, y pueden añadirse al sistema de menú existente o añadir opciones propias completamente nuevas. Plugins Objeto -------------- Un plugin objeto es instalado llamando la función: void datedit_register_object(DATEDIT_OBJECT_INFO *info); Estos plugins están definidos por una estructura que es: typedef struct DATEDIT_OBJECT_INFO { int type; char *desc; void (*get_desc)(DATAFILE *dat, char *s); void *(*makenew)(long *size); void (*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; Los plugins objeto añaden soporte para nuevos tipos de objeto, y no tiene sentido instalar más de uno de estos para la misma identificación ID (si lo hace, el segundo plugin simplemente será ignorado). Los campos de la estructura son: 'type' El tipo ID de objeto, tal y como lo produce la macro DAT_ID(). 'desc' Descripción ASCII de este tipo de objeto. get_desc() Opcional, Rellene 's' con una descripción del objeto. Implementar esta función permite ver una descripción más detallada (ejemplo: "bitmap de 32x32x8"). Si lo deja a NULL, el campo 'desc' será visualizado, makenew() Crea y devuelve un puntero al nuevo objeto de este tipo, y si el objeto lo va a usar, pone en 'size' el tamaño del objeto en bytes. save() Salva el objeto en un fichero de datos de Allegro. Esto requiere bastantes parámetros, pero puede ignorarlos excepto los valores 'dat' y 'f': los otros sólo son necesarios para ficheros de datos anidados. plot() Opcional. Dibuja el objeto en la pantalla del grabber en la posición especificada. ¡Debe asegurarse de que esta rutina funcionará en todas las resoluciones y profundidades de color posibles! dclick() Opcional. Llamado cuando el usuario hace doble click en el objeto dentro del grabber. dat2s() Opcional. Usado por la utilidad dat2s para convertir el objeto en código ensamblador. Si no implementa esto, su tipo de objeto no será soportado por dat2s. Se habrá dado cuenta que esta interfaz no provee ningún soporte para cargar estos objetos desde ficheros de datos, o para leer/escribir formatos de ficheros externos. Esto es porque la carga de ficheros de datos es controlada internamente por el núcleo de la biblioteca Allegro (debería usar register_datafile_object() para instalar su cargador), y el importar/exportar es controlado por un tipo diferente de plugin (lea más abajo). La interfaz 'datsample_info' de datsamp.c es un buen ejemplo básico de un plugin objeto. Plugins Importar/Exportar ------------------------- Un plugin importar/exportar es instalado llamando la función: void datedit_register_grabber(DATEDIT_GRABBER_INFO *info); Estos plugins están definidos por una estructura que es: 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; Los plugins importar/exportar añaden soporte de fichero a tipos de objetos existentes. Normalmente necesitará uno de estos por cada plugin objeto que instale, pero puede usarlos para extender tipos de objetos predefinidos. No hay límite sobre cuántos plugins importar/exportar pueden funcionar con un solo tipo de objeto, o cuántos formatos de fichero pueden ser soportados por un solo plugin. Los campos de la estructura son: 'type' El tipo ID de objeto, tal y como lo produce la macro DAT_ID(). 'grab_ext' Lista de extensiones de fichero que son soportadas al leer datos, separadas por punto y coma. Puede dejarse vacío si este plugin sólo soporta funciones para exportar. 'export_ext' Lista de extensiones de fichero que son soportadas al salvar datos, separadas por punto y coma. Puede dejarse vacío si este plugin sólo soporta funciones para importar. grab() Lee un nuevo objeto del fichero mencionado, devolviendo un puntero a él. Si este tipo de objeto lo requiere, pone en 'size' el tamaño del objeto en bytes. export() Salva un objeto en el fichero mencionado. La interfaz 'datfont_grabber' de datfont.c es un buen ejemplo de un plugin importar/exportar que soporta diferentes tipos de formato. Plugins de Menú --------------- Un plugin de menú es instalado llamando a la función: void datedit_register_menu(DATEDIT_MENU_INFO *info); Estos plugins están definidos por una estructura que es: typedef struct DATEDIT_MENU_INFO { MENU *menu; int (*query)(int popup); int flags; int key; } DATEDIT_MENU_INFO; Los plugins de menú están basados en la estructura de menús GUI de Allegro. Si instala un plugin para una opción de menú que ya existe, enganchará el menú existente, pero también puede añadir nuevas opciones especificando una nueva cadena de texto para el menú. Los campos de la estructura son: 'menú' Apunta a una estructura de menú de Allegro para esta opción. Tenga en cuenta que esto sólo es un ítem de menú, no todo el array de entradas. Los campos flags y dp de la estructura serán sobreescritos por el grabber, pero debe rellenar el texto de menú con, y al menos el puntero a función proc con su rutina de acción (para comandos simples del menú como la función "grab"), o el campo hijo con un puntero a un menú anidado (para estructuras jerárquicas como el menú "new"). query() Opcional. Si no es NULL, esta rutina será llamada para comprobar que la opción de menú del plugin es utilizable en la situación actual. Para menús desplegables de persiana normales, el parámetro 'popup' será FALSE, y tendrá la ocasión de devolver TRUE, en cuyo caso su comando será usado, o FALSE, en cuyo caso el procedimiento por defecto será llevado a cabo (esto le permite al plugin tomar control sobre comandos estándar como "grab", pero ignorarlos cuando cualquier otra cosa que no sea su tipo de objeto sea seleccionada, para que el comando grab normal siga funcionando con otros tipos de objeto. Para menús emergentes (botón derecho del ratón), esta rutina será llamada inmediatamente antes de que el menú sea visualizado, con el parámetro 'popup' puesto a TRUE. Si devuelve FALSE a esta llamada, su comando no será incluido en el menú emergente (así es como cosas como 'autocrop' son capaces de aparecer sólo al pinchar con el botón derecho en objetos tipo bitmap). 'flags' Indica dónde en el sistema de menú quiere que su comando sea añadido. Esto es un campo de bits que contiene cualquier combinación de los siguientes valores: DATEDIT_MENU_FILE - se añade al menú File DATEDIT_MENU_OBJECT - se añade al menú Object DATEDIT_MENU_HELP - se añade al menú Help DATEDIT_MENU_POPUP - se incluye en los menús emergentes DATEDIT_MENU_TOP - nueva entrada en la barra de menú 'key' Si no es cero, será el código ASCII del atajo de teclado para usar el comando. Por favor, tenga cuidado al usar esto, porque si varios plugins quieren enganchar el mismo atajo, obviamente sólo un de ellos lo conseguirá :-) La interfaz 'datworms_menu' de datworms.c es un buen ejemplo de cómo añadir un nuevo comando de menú, y 'datpal_grabber_menu' de datpal.c enseña cómo enganchar un comando existente (añade una función propia para que las paletas puedan ser recogidas de un bitmap leído previamente, en vez de leerlas directamente desde un fichero de disco). Miscelánea ---------- Tenga en cuenta que estos plugins son usados por las utilidades dat, dat2s, pat2dat y grabber, por lo que no puede asumir nada sobre la configuración del sistema mientras su código es ejecutado. Los menús de comando y las funciones ver/doble-click serán usadas sólo en modo gráfico (pero en cualquier resolución y profundidad de color), y las otras funciones también pueden ser llamadas desde un entorno gráfico o en modo texto. Para enseñar mensajes, errores, pedir un dato al usuario, etc, use las funciones datedit_msg(), datedit_error(), y datedit_ask(). Estas son implementadas en modo texto como llamadas a printf(), y son cajas de alerta en el grabber, por lo que funcionarán en cualquier situación. Hay montones de funciones de ayuda útiles en datedit.h. Quizás lo más importante es que cuando implemente comandos de menú, grabber_single_selection() devuelve un puntero al objeto seleccionado actualmente (NULL si es una selección múltiple), y grabber_foreach_selection() itera sobre cada objeto seleccionado, usando una función callback para permitirle procesar objetos múltiples con el mínimo esfuerzo. Y Finalmente ------------ ¡Buena suerte!