Redtools requester library

Redtools requester library is a small library that offers simple requesters and dialogs for user disposal. Detroit engine has bindings to use Redtools library if it is compiled and installed.

Redtools library can be compiled along with the Detroit engine by giving --with-redtools parameter to configure script. Redtools library needs Motif (that is, libXm and libXt) in order to work. Also use of Xft fonts, its default typeface and size can be given as a configure parameter:

--with-redtools \
--with-redtools-xft \
--with-redtools-xft-typeface=Noto \
--with-redtools-xft-fontsize=12

When Redtools library is installed, any program using Detroit engine can use it to output messages when -pm command line switch is used.

 -pm, --popup_messages
	Use graphical dialog popup messages if possible.

Redtools requester library can be used with any other program too, it is not bolted to Detroit engine too tight. Below is working example how to write standalone program that makes use one of the Redtools requesters. See engine/redtools/example.c how to use other dialogs offered by Redtools library. Example pops up a dialog which looks like this:

Simple Redtools dialog

Example source code to produce this and other dialogs. Example code is available in engine/redtools directory. libredtools.so and its header file redtools.h must be accessible if you want to try the examples. Steps to compile it:

$ cd engine/redtools
$ make example

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#include "redtools.h"

int main() {
	REDTOOLS rt;

	unsigned int c;

	/* Predefined dialog buttons */
	const char *buttons[] = {
		"Cheese", "Ham", "Prawn", "Tuna", "Plain green",
		NULL
	};

	/* Initialize the redtools library, if returned handle is NULL,
	   initialization was not succesful, and program must not call any
	   redtools functions */

	if((rt = red_initialize()) == NULL) {
		fprintf(stderr,
			"!\n! failed to initialize redtools library\n!\n");

		exit(1);
	}

	/* Add dialog title... */
	(void) red_dialog_add_title(rt,
		"What kind of starter salad would you like?");

	/* ...then the buttons... */
	(void) red_dialog_add_buttons(rt, buttons);

	/* ...and display it to the user */
	c = red_question_dialog(rt);

	if(c != 0) {
		fprintf(stdout,
			"selected: %u (%s)\n", c, buttons[c - 1]);
	}

	/* Free resources allocated by the redtools library, library is not
	   useable after this */

	(void) red_finalize(rt);

	exit(0);
}
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#include "redtools.h"

int main() {
	REDTOOLS rt;

	/* Initialize the redtools library, if returned handle is NULL,
	   initialization was not succesful, and program must not call any
	   redtools functions */

	if((rt = red_initialize()) == NULL) {
		fprintf(stderr,
			"!\n! failed to initialize redtools library\n!\n");

		exit(1);
	}

{ /* Button dialog example */
	unsigned int c;

	/* Predefined dialog buttons */
	const char *buttons[] = {
		"Cheese", "Ham", "Prawn", "Tuna", "Plain green",
		NULL
	};

	fprintf(stdout,
		"#\n# dialog example\n#\n");

	/* Add dialog title... */
	(void) red_dialog_add_title(rt,
		"What kind of starter salad would you like?");

	/* ...then the buttons... */
	(void) red_dialog_add_buttons(rt, buttons);

	/* ...and display it to the user */
	c = red_question_dialog(rt);

	if(c != 0) {
		fprintf(stdout,
			"selected: %u (%s)\n", c, buttons[c - 1]);
	}
}

{ /* List example */
	int i;

	unsigned int *c;

	/* Predefined dialog selections */
	const char *items[] = {
		"Salt", "Pepper", "Vinegar", "Olive oil", "None, thanks",
		NULL
	};

	fprintf(stdout,
		"#\n# list example\n#\n");

	/* Add dialog title and list header... */
	(void) red_list_add_title(rt,
		"List example",
		"Please select one or more for seasoning the salad");

	/* ...then the selections... */
	(void) red_list_add_items(rt, items);

	/* ...and display it to the user... */
	if((c = red_list(rt)) != NULL) {
		/* ...then check which ones user selected, zero ends the
		      returned list of selections, as item index starts
		      counting from one */
		for(i = 0; ; i++) {
			if(c[i] == 0) {
				break;
			}

			fprintf(stdout,
				"selected: %u (%s)\n", c[i], items[c[i] - 1]);
		}
	}

	/* Free the returned list of selections */
	(void) red_list_free(c);
}

{ /* Radio button example */
	unsigned int c, p;

	/* Predefined dialog selections */
	const char *items[] = {
		"Chicken parmesan", "Daily soup", "Grilled fish",
		"Macaroni and cheese", "Meat loaf", "Pulled pork",
		"Sausage gravy", "Houses special", "No, thanks",
		NULL
	};

	/* First item is set by default, zero means no preselection */
	p = 1;

	fprintf(stdout,
		"#\n# radiobutton example\n#\n");

	/* Add dialog title and list header... */
	(void) red_radio_add_title(rt,
		"Radiobutton example",
		"Would you like to order the main dish?");

	/* ...then the selections and set the item selected by default... */
	(void) red_radio_add_items(rt, items);
	(void) red_radio_add_preset(rt, p);

	/* ...and display dialog to the user */
	c = red_radio(rt);

	/* Selected item index starts from one, zero means no selection was
	   made */
	if(c != 0) {
		fprintf(stdout,
			"selected: %u (%s)\n", c, items[c - 1]);
	}
}

{ /* Toggle button example */
	int i;

	unsigned int *c;
	unsigned int p[1];

	/* Predefined dialog selections */
	const char *items[] = {
		"Bill, please", "Clean tablecloth", "Chili sauce", "Bread",
		"Butter", "Ketchup", "Mustard", "Pepper", "Salt", "Soda water",
		"Still water",
		NULL
	};

	/* Second (0x2 = 00010b) and fourth (0x8 = 01000b) items are set by
	   default, there must be enough int's in array to cover every dialog
	   selection */
	p[0] = 0x2 | 0x8;

	fprintf(stdout,
		"#\n# togglebutton example\n#\n");

	/* Add dialog title and list header... */
	(void) red_button_add_title(rt,
		"Togglebutton example",
		"Any extra wishes?");

	/* ...then the selections and set the item(s) selected by default using
	      bitmask set above... */
	(void) red_button_add_items(rt, items);
	(void) red_button_add_preset(rt, p);

	/* ...and display it to the user... */
	if((c = red_button(rt)) != NULL) {
		/* ...then check which ones user selected, zero means this item
		      was not checked */
		for(i = 0; ; i++) {
			if(items[i] == NULL) {
				break;
			}

			if(c[i] != 0) {
				fprintf(stdout,
					"selected: %d (%s)\n", i, items[i]);
			}
		}
	}

	/* Free the returned list of selections */
	(void) red_button_free(c);
}

{ /* Prompt example */
	const char *s;

	fprintf(stdout,
		"#\n# prompt example\n#\n");

	/* Add dialog title... */
	(void) red_prompt_add_title(rt,
		"Prompt example",
		"Feedback to the restaurant");

	/* ...but do not prefill the text field... */
	(void) red_prompt_add_value(rt, NULL);

	/* ...then display it to the user... */
	if((s = red_prompt(rt)) != NULL) {
		fprintf(stdout,
			"prompt: %s\n", s);
	}

	/* ...and free the returned string what user possibly wrote */
	(void) red_prompt_free(s);
}

{ /* File selector example */
	const char *s;

	fprintf(stdout,
		"#\n# file selector example\n#\n");

	/* Add dialog title... */
	(void) red_file_add_title(rt,
		"File selection example");

	/* ...preselected path and possibly a file selection mask... */
	(void) red_file_add_path(rt, "/tmp");
	(void) red_file_add_mask(rt, NULL);

	/* ...then display it to the user... */
	if((s = red_file(rt)) != NULL) {
		fprintf(stdout,
			"selected: %s\n", s);
	}

	/* ...and free the file name string what user possibly selected */
	(void) red_file_free(s);
}

	/* Free resources allocated by the redtools library, library is not
	   useable after this */

	(void) red_finalize(rt);

	exit(0);
}

X resources

To get Redtools requesters and dialogs look like the screenshot above, following .Xresources can be used:

*background:				#aeb2c3
*foreground:				#000000

*XmList*background:			#fff7e9
*XmText*background:			#fff7e9
*XmTextField*background:		#fff7e9

*.renderTable:				variable
*.renderTable.variable.fontName:	Source Sans Pro
*.renderTable.variable.fontSize:	12
*.renderTable.variable.fontType:	FONT_IS_XFT

Xft.antialias:				1
Xft.autohint:				0
Xft.dpi:				96
Xft.hinting:				1
Xft.hintstyle:				hintfull
Xft.lcdfilter:				lcddefault
Xft.rgba:				rgb

Screenshots

Rest of the dialogs and their look:

Simple dialog
List selector
Radio selector
Togglebutton selector
Prompt dialog
File selector

Copyright © 2024, Jani Salonen <salojan at goto10 piste co>. Piste is finnish word and means dot. All rights reserved.