Obligement - L'Amiga au maximum

Mercredi 26 juillet 2017 - 08:25  

Translate

En De Nl Nl
Es Pt It Nl


Rubriques

 · Accueil
 · A Propos
 · Articles
 · Galeries
 · Glossaire
 · Hit Parade
 · Liens
 · Liste jeux Amiga
 · Quizz
 · Téléchargements
 · Trucs et astuces


Articles

 · Actualité (récente)
 · Actualité (archive)
 · Comparatifs
 · Dossiers
 · Entrevues
 · Matériel (tests)
 · Matériel (bidouilles)
 · Points de vue
 · En pratique
 · Programmation
 · Reportages
 · Tests de jeux
 · Tests de logiciels
 · Tests de compilations
 · Articles divers

 · Articles in english
 · Articles in other languages


Twitter

Suivez-nous sur Twitter




Liens

 · Sites de téléchargements
 · Associations
 · Pages Personnelles
 · Moteurs de recherche
 · Pages de liens
 · Constructeurs matériels
 · Matériel
 · Autres sites de matériel
 · Réparateurs
 · Revendeurs
 · Presse et médias
 · Programmation
 · Développeurs logiciels
 · Logiciels
 · Développeurs de jeux
 · Jeux
 · Autres sites de jeux
 · Scène démo
 · Divers
 · Informatique générale


Jeux Amiga

0, A, B, C, D, E, F,
G, H, I, J, K, L, M,
N, O, P, Q, R, S, T,
U, V, W, X, Y, Z


Trucs et astuces

0, A, B, C, D, E, F,
G, H, I, J, K, L, M,
N, O, P, Q, R, S, T,
U, V, W, X, Y, Z


Glossaire

0, A, B, C, D, E, F,
G, H, I, J, K, L, M,
N, O, P, Q, R, S, T,
U, V, W, X, Y, Z


Partenaires

Annuaire Amiga

Amedia Computer

Relec

Hit Parade


Contact

David Brunet

Courriel

 


Programmation : MUI - amélioration de l'interface
(Article écrit par Mathias Parnaudeau - août 2004)


Chapitre 5

Nous avons abordé le maniement des classes externes qui augmentent la variété des classes disponibles. Mais il ne faut pas se précipiter dessus au détriment de l'étude du contenu des classes de base. C'est pourquoi nous commençons par rentrer dans le détail d'éléments apparemment simples comme les boutons et les labels.

mui.h, une mine d'or !

En consultant de nombreux sources, je m'étais trouvé nez à nez avec plusieurs écritures différentes pour des objets aussi basiques que les boutons et labels. Leur description se trouve dans l'include et c'est en remontant ainsi à la source qu'on constate que la notation SimpleButton n'est qu'une toute petite macro qui cache le texte "MUI_MakeObject(MUIO_Button,label)", parfois utilisé tel quel dans des exemples. Il y a donc bien un objet bouton ! C'est ce qu'on pourrait croire mais le code appelé derrière utilise bien un TextObjet avec un Button Frame. La notation SimpleButton possède des contraintes : elle ne gère ni les bulles d'aide ni la navigation entre composants avec la touche Tab (attribut MUIA_CycleChain).

On remarque aussi l'autre façon de créer un bouton passe par la macro KeyButton(), qui utilise un TextObject et semble plus paramétrable. Mais cette macro appartient à une zone marquée MUI_OBSOLETE, c'est-à-dire que son usage est à éviter bien que cela continue de fonctionner pour une raison évidente de compatibilité.

On en vient à ne plus savoir que faire entre un SimpleButton limité et un KeyButton déprécié. La marche à suivre la plus appropriée semble être de se créer soi-même dans son application une macro ou une fonction d'encapsulation sur la base du code contenu dans KeyButton.

 Object *_ KeyGadget (CONST_STRPTR content, BYTE controlchar)

{

    return TextObject,

        ButtonFrame,

        MUIA_Font,          MUIV_Font_Button,

        MUIA_Text_Contents, content,

        MUIA_Text_PreParse, "\33c",

        MUIA_Text_HiChar,   controlchar,

        MUIA_ControlChar,   controlchar,

        MUIA_InputMode,     MUIV_InputMode_RelVerify,

        MUIA_Background,    MUII_ButtonBack,

        MUIA_CycleChain,    TRUE,

    End;

}

Dans ce cas, le contenu est exactement le même que pour KeyButton auquel on a ajouté l'attribut MUIA_CycleChain, qu'il faudrait sinon fixer avec un appel à la méthode set() pour chaque bouton. On peut se demander ce qui est le plus élégant mais l'encapsulation personnelle semble être la voie choisie par MUI sans que ça n'ait été clairement énoncé.

Le cas des boutons est intéressant car on constate que pour ce composant incontournable, tout n'est pas aussi établi qu'on pourrait le penser. Et ce n'est pas plus simple avec les labels ! Le fichier est à consulter absolument, y compris pour ce point-là.

Retour sur interface

Repartons de notre code propre du chapitre précédent pour enrichir l'interface afin qu'elle ressemble réellement à un vrai lecteur de CD. Nous envisagerons deux onglets : le premier contenant les composants de l'interface telle qu'on la connaît jusqu'ici ; le deuxième dédié aux réglages du logiciel.

Pour mettre des onglets en place, il faut déjà savoir combien on en souhaite et quel sera le titre de chacun. Chaque titre est une chaîne de caractères que l'on doit consigner dans un tableau qui sera passé en paramètre à la construction des onglets. On a donc ici "utilisation" et "configuration" dans un tableau nommé "Pages". Ce tableau est passé à la macro MUI RegisterPages() qui déclare un groupe composé d'onglets. Les onglets ne font apparaître aucune difficulté ; au lieu d'avoir deux groupes, traditionnellement horizontaux ou verticaux, les voilà superposés, rien de plus. On trouve juste pour l'occasion le terme de RegisterGroups, auquel est passé le nom du tableau de chaînes.

Voici le code correspondant :

/*
 * DisKo5.c (21/08/04)
 * txt_info a été mis en global
 */

#include <stdio.h>
#include <libraries/mui.h>
#include <proto/intuition.h>
#include <proto/muimaster.h>
#include <proto/exec.h>
#include <clib/alib_protos.h>
#include <string.h>

#include <mui/Busy_mcc.h>

#include <SDI_hook.h>

#define MAKE_ID(a,b,c,d)  ((ULONG) (a)<<24 | (ULONG) (b)<<16 | (ULONG) (c)<<8 | (ULONG) (d))

struct Library *MUIMasterBase = NULL;
struct IntuitionBase *IntuitionBase = NULL;

#ifdef __amigaos4__
struct IntuitionIFace *IIntuition;
struct MUIMasterIFace *IMUIMaster;
#endif

#define	MUIA_Application_UsedClasses	0x8042e9a7	/* V20 STRPTR *	i..	*/

static char * ClassList[] =
{
	"Busy.mcc",
	NULL
};

static Object *app = NULL;
static Object *window = NULL;

static char *Pages[] = { "Utilisation", "Configuration", NULL };

struct Config {
	ULONG unit;
	char device[32];
} config;

#if defined(__SASC)
extern ULONG HookEntry( struct Hook *hookPtr, Object *obj, APTR message );
#endif

Object *txt_info;


/*
 * Hook lié à l'action 'changement de volume' via le slider
 */
#if 0
// Ancien hook : problème d'affichage du texte sur sortie standard sur certaines configurations (amifred)
static ULONG hook_ChangeVolumeFunc(struct Hook *hook, APTR obj, struct TagItem *tag_list)
{
	int val;

	get(obj, MUIA_Numeric_Value, &val);

	printf("Nouvelle valeur : %d\n", val);

	return TRUE;
}
#endif
#if 0
static ULONG hook_ChangeVolumeFunc(struct Hook *hook, APTR obj, struct TagItem *tag_list)
{
	int val;
	char text[5];

	get(obj, MUIA_Numeric_Value, &val);

	sprintf(text, "%d", val);
	set(txt_info, MUIA_Text_Contents, text);

	printf("Nouvelle valeur : %d\n", val);

	return TRUE;
}

struct Hook hook_ChangeVolume = 
{
	{NULL, NULL}, (HOOKFUNC) HookEntry, (HOOKFUNC) hook_ChangeVolumeFunc, NULL
};
#endif

HOOKPROTONH(ChangeVolume, ULONG, APTR obj, struct TagItem *tag_list)
{
	int val;
	char text[5];

	get(obj, MUIA_Numeric_Value, &val);

	sprintf(text, "%d", val);
	set(txt_info, MUIA_Text_Contents, text);

	printf("Nouvelle valeur : %d\n", val);

	return TRUE;
}

MakeStaticHook(hook_ChangeVolume, ChangeVolume);

/*
 * Construction et ouverture de la fenêtre principale.
 * Cette fonction est appelée quand on sait que tout a bien été initialisé.
 */
Object * OpenMainWindow(void)
{
	Object *bt_play, *bt_stop, *bt_previous, *bt_next, *bt_pause, *bt_eject;
	Object *busy;
	Object *lv_pistes;
	Object *sl_volume;
	Object *list;

	Object *sl_unit;
	Object *str_device;


	/* Description de l'interface et de ses propriétés */	

	app = (Object *)ApplicationObject,
		MUIA_Application_Author, "corto@guru-meditation.net",
		MUIA_Application_Base, "DISKO",
		MUIA_Application_Title, "DisKo - Exemple 5",
		MUIA_Application_Version, "$VER: DisKo 1.05 (04/08/04)",
		MUIA_Application_Copyright, "Mathias PARNAUDEAU",
		MUIA_Application_Description, "Player de CD audio minimaliste",
		MUIA_Application_HelpFile, NULL,
		MUIA_Application_UsedClasses, ClassList,

		SubWindow, window = WindowObject,
			MUIA_Window_Title, "DisKo - release 5",
			MUIA_Window_ID, MAKE_ID('W', 'I', 'N', '1'),
			WindowContents, VGroup,

				Child, RegisterGroup(Pages),
					MUIA_Register_Frame, TRUE,

					// Onglet utilisation

					Child, VGroup,
						Child, HGroup,
							Child, lv_pistes = ListviewObject,
								MUIA_Listview_List, list = ListObject,
									MUIA_Frame, MUIV_Frame_InputList,
									MUIA_List_Format, "P=\33r",
									MUIA_List_Active, MUIV_List_Active_Top,
								End,
							End,

							Child, VGroup,
								Child, Label("Volume"),
								Child, sl_volume = SliderObject,
									MUIA_Group_Horiz, FALSE,
									MUIA_Numeric_Min, 0,
									MUIA_Numeric_Max, 100,
									MUIA_Numeric_Value, 38,
									MUIA_Numeric_Reverse, TRUE,
								End,
							End,
						End,

						Child, VSpace(2),

						Child, HGroup,
							Child, txt_info = TextObject,
								MUIA_Frame, MUIV_Frame_Text,
								MUIA_Background, MUII_TextBack,
								MUIA_Text_Contents, "Information piste",
							End,
							Child, busy = BusyObject,
								MUIA_Busy_Speed, MUIV_Busy_Speed_Off,
							End,
						End,
						Child, HGroup,
							Child, bt_previous = KeyButton("Précédent", 'p'),
							Child, bt_next = KeyButton("Suivant", 'v'),
							Child, bt_play = KeyButton("Jouer", 'j'),
							Child, bt_pause = KeyButton("Pause", 'a'),
							Child, bt_stop = KeyButton("Stopper", 's'),
							Child, bt_eject = KeyButton("Ejecter", 'e'),
						End,

					End,

					// Onglet configuration

					Child, VGroup, GroupFrameT("Lecteur CD"),
						Child, ColGroup(2),
							Child, Label2("Device"),
							Child, str_device = String(config.device, 32),
							Child, Label1("Unit" ),
							Child, sl_unit = SliderObject,
								MUIA_Group_Horiz, TRUE,
								MUIA_Numeric_Min, 0,
								MUIA_Numeric_Max, 7,
								MUIA_Numeric_Value, config.unit,
							End,
						End,
						Child, KeyButton("Valider", 'd'),
					End,
				End,
			End,
		End,
	End;

	if (app){
	
		DoMethod(window,
			MUIM_Notify, MUIA_Window_CloseRequest, TRUE,
			app, 2,
			MUIM_Application_ReturnID, MUIV_Application_ReturnID_Quit);

		DoMethod(busy, MUIM_Busy_Move, FALSE);

		DoMethod(bt_play, MUIM_Notify, MUIA_Pressed, FALSE,
					busy, 3, MUIM_Set, MUIA_Busy_Speed, 20);
		DoMethod(bt_stop, MUIM_Notify, MUIA_Pressed, FALSE,
					busy, 3, MUIM_Set, MUIA_Busy_Speed, MUIV_Busy_Speed_Off);

		DoMethod(list, MUIM_List_InsertSingle, "1 - Première piste", MUIV_List_Insert_Bottom);
		DoMethod(list, MUIM_List_InsertSingle, "2 - Deuxième piste", MUIV_List_Insert_Bottom);

		DoMethod(sl_volume, MUIM_Notify, MUIA_Numeric_Value, MUIV_EveryTime,
					sl_volume, 2, MUIM_CallHook, &hook_ChangeVolume);

		set(list, MUIA_List_Active, MUIV_List_Active_Top);

		SetAttrs(window, MUIA_Window_Open, TRUE, TAG_END);
	}

	return app;
}


/*
 * Initialisation et vérification de tout ce qui est nécessaire à la bonne exécution
 * de l'application : ouverture des bibliothèques, test de présence des classes MCC, ...
 */
int Initialize(void)
{
	int res = 1;
	Object *busy = NULL;

	// Initialisation de la configuration (chargement éventuel à partir d'un fichier)
	config.unit = 2;
	strcpy(config.device, "ide.device");

	IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library", 39L);
	MUIMasterBase = OpenLibrary(MUIMASTER_NAME, MUIMASTER_VMIN);

	if (IntuitionBase == NULL){
		printf("Impossible d'ouvrir 'intuition.library' V39\n");
		res = 0;
	}
	if (MUIMasterBase == NULL){
		printf("Impossible d'ouvrir '%s' V%d\n", MUIMASTER_NAME, MUIMASTER_VMIN);
		res = 0;
	}

#ifdef __amigaos4__
	IIntuition = (struct IntuitionIFace *)GetInterface((struct Library *)IntuitionBase, "main", 1, NULL);
	if (!IIntuition){
		printf("Impossible d'obtenir l'interface IIntuition\n");
		res = 0;
	}
	IMUIMaster = (struct MUIMasterIFace *)GetInterface(MUIMasterBase, "main", 1, NULL);
	if (!IMUIMaster){
		printf("Impossible d'obtenir l'interface IMUIMaster\n");
		res = 0;
	}
#endif

	busy = BusyObject, End;
	if (busy == NULL){
		printf("Classe Busy manquante\n");
		res = 0;
	}
	MUI_DisposeObject(busy);

	return res;
}


/*
 * Fermeture et libération de tout ce qui a été initialisé au démarrage.
 */
void DeInitialize(void)
{
#ifdef __amigaos4__
	if (IMUIMaster) {
		DropInterface((struct Interface *)IMUIMaster);
	}
	if (IIntuition) {
		DropInterface((struct Interface *)IIntuition);
	}
#endif
	CloseLibrary(MUIMasterBase);
	CloseLibrary((struct Library *)IntuitionBase);
}


/*
 * Programme principal : il appelle les initialisations, ouvre la fenêtre puis gère
 * les événements jusqu'à ce qu'on ferme l'application, condition de libération
 * des ressources
 */
int main(int argc, char **argv)
{
	int res = 0;

	if (Initialize()){
		app = OpenMainWindow();
		if (app){
			/* Boucle de gestion des événements, toujours la même */
			ULONG sigs = 0;

			while (DoMethod(app,MUIM_Application_NewInput,&sigs) != MUIV_Application_ReturnID_Quit)
			{
				if (sigs)
				{
					sigs = Wait(sigs | SIGBREAKF_CTRL_C);
					if (sigs & SIGBREAKF_CTRL_C) break;
				}
			}

			/* Libération des ressources et fermeture */
			set(window, MUIA_Window_Open, FALSE);
			MUI_DisposeObject(app);
		}else{
			res = 2;
		}
	}else{
		res = 1;
	}

	DeInitialize();

	return res;
}

Le premier groupe (donc le premier onglet) présente les composants propres à l'utilisation classique d'un lecteur CD. On regroupe simplement tout ce qu'on avait jusque-là, avec en plus un nouveau composant : l'information sur la piste courante pourra indiquer le numéro, le titre, etc. et pourra servir au-delà ! ;-)

Le "VSpace(2)" se trouve là uniquement pour attirer l'attention sur lui et pour se donner l'occasion de découvrir un nouvel élément de MUI. Les espaces prennent leur importance dans le redimensionnement des interfaces, ce sont par exemple eux qui vont être étirés de préférence par rapport à d'autres composants.

Le contenu du deuxième onglet est nouveau et demande une légère anticipation sur le prochain chapitre. Pour qu'un CD puisse être joué, il va falloir que le logiciel sache à quel périphérique s'adresser. Cela passera de près ou de loin par un device donc il va falloir que son nom et son unité soient renseignés.

Voyons donc la partie configuration : elle se compose d'un encadré qui contient des labels et des champs texte, alignés proprement en colonnes. L'encadré est d'abord obtenu avec la macro GroupFrameT que l'on gère comme un groupe classique. La seule différence provient du fait qu'on lui passe un titre. A l'intérieur, on dispose des composants à loisirs. Pour l'occasion, deux colonnes sont définies avec ColGroup(). Les composants contenus seront placés naturellement de manière à remplir une ligne avant de passer à la suivante. Dans notre exemple, nous avons deux colonnes donc le troisième élément sera placé sur la deuxième ligne, etc.

Enfin, un bouton de validation permettra de prendre en compte dynamiquement le changement des réglages, ce qui ne sera d'ailleurs pas traité par la suite. Il s'agirait d'interrompre l'accès au disque et de le réinitialiser avec les nouvelles valeurs du device et de son unité.

Notions acquises dans ce chapitre
  • Le point sur les boutons MUI et ce que cachent les macros.
  • Onglets, groupes de type encadré, colonnes, espaces, etc.


[Retour en haut] / [Retour aux articles] [Article précédent] / [Article suivant]