static const char CVSID[] = "$Id: fontsel.c,v 1.28 2004/08/01 10:06:12 yooden Exp $"; /******************************************************************************* * * * fontsel.c -- Nirvana Font Selector * * * * Copyright (C) 1999 Mark Edel * * * * This is free software; you can redistribute it and/or modify it under the * * terms of the GNU General Public License as published by the Free Software * * Foundation; either version 2 of the License, or (at your option) any later * * version. In addition, you may distribute version of this program linked to * * Motif or Open Motif. See README for details. * * * * This software is distributed in the hope that it will be useful, but WITHOUT * * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * * for more details. * * * * You should have received a copy of the GNU General Public License along with * * software; if not, write to the Free Software Foundation, Inc., 59 Temple * * Place, Suite 330, Boston, MA 02111-1307 USA * * * * Nirvana Text Editor * * June 2, 1993 * * * * Written by Suresh Ravoor (assisted by Mark Edel) * * * *******************************************************************************/ #ifdef HAVE_CONFIG_H #include "../config.h" #endif #include "fontsel.h" #include "misc.h" #include "DialogF.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_DEBUG_H #include "../debug.h" #endif #define MAX_ARGS 20 #define MAX_NUM_FONTS 32767 #define MAX_FONT_NAME_LEN 256 #define MAX_ENTRIES_IN_LIST 5000 #define MAX_DISPLAY_SIZE 150 #define DELIM '-' #define NUM_COMPONENTS_FONT_NAME 14 #define TEMP_BUF_SIZE 256 #define DISPLAY_HEIGHT 90 enum listSpecifier { NONE, FONT, STYLE, SIZE }; /* local data structures and types */ typedef struct { Widget form; /* widget id */ Widget okButton; /* widget id */ Widget cancelButton; /* widget id */ Widget fontList; /* widget id */ Widget styleList; /* widget id */ Widget sizeList; /* widget id */ Widget fontNameField; /* widget id */ Widget sizeToggle; /* widget id */ Widget propFontToggle; /* widget id */ Widget dispField; /* widget id */ char **fontData; /* font name info */ int numFonts; /* number of fonts */ char *sel1; /* selection from list 1 */ char *sel2; /* selection from list 2 */ char *sel3; /* selection from list 3 */ int showPropFonts; /* toggle state - show prop fonts */ int showSizeInPixels;/* toggle state - size in pixels */ char *fontName; /* current font name */ XFontStruct *oldFont; /* font data structure for dispSample */ XmFontList oldFontList; /* font data structure for dispSample */ int exitFlag; /* used for program exit control */ int destroyedFlag; /* used to prevent double destruction */ Pixel sampleFG; /* Colors for the sample field */ Pixel sampleBG; } xfselControlBlkType; /* local function prototypes */ static void getStringComponent(const char *inStr, int pos, char *outStr); static void setupScrollLists(int dontChange, xfselControlBlkType ctrlBlk); static int notPropFont(const char *font); static int styleMatch(xfselControlBlkType *ctrlBlk, const char *font); static int sizeMatch(xfselControlBlkType *ctrlBlk, const char *font); static int fontMatch(xfselControlBlkType *ctrlBlk, const char *font); static void addItemToList(char **buf, const char *item, int *count); static void getFontPart(const char *font, char *buff1); static void getStylePart(const char *font, char *buff1); static void getSizePart(const char *font, char *buff1, int inPixels); static void propFontToggleAction(Widget widget, xfselControlBlkType *ctrlBlk, XmToggleButtonCallbackStruct *call_data); static void sizeToggleAction(Widget widget, xfselControlBlkType *ctrlBlk, XmToggleButtonCallbackStruct *call_data); static void fontAction(Widget widget, xfselControlBlkType *ctrlBlk, XmListCallbackStruct *call_data); static void styleAction(Widget widget, xfselControlBlkType *ctrlBlk, XmListCallbackStruct *call_data); static void sizeAction(Widget widget, xfselControlBlkType *ctrlBlk, XmListCallbackStruct *call_data); static void choiceMade(xfselControlBlkType *ctrlBlk); static void dispSample(xfselControlBlkType *ctrlBlk); static void destroyCB(Widget widget, xfselControlBlkType *ctrlBlk, XmListCallbackStruct *call_data); static void cancelAction(Widget widget, xfselControlBlkType *ctrlBlk, XmListCallbackStruct *call_data); static void okAction(Widget widget, xfselControlBlkType *ctrlBlk, XmPushButtonCallbackStruct *call_data); static void startupFont(xfselControlBlkType *ctrlBlk, const char *font); static void setFocus(Widget w, xfselControlBlkType *ctrlBlk, XEvent *event, Boolean *continueToDispatch); static void FindBigFont(xfselControlBlkType *ctrlBlk, char *bigFont); static void enableSample(xfselControlBlkType *ctrlBlk, Bool turn_on, XmFontList *fontList); /******************************************************************************* * * * FontSel () * * * * * * Function to put up a modal font selection dialog box. The purpose * * of this routine is to allow the user to interactively view sample * * fonts and to choose a font for current use. * * * * Arguments: * * * * Widget parent - parent widget ID * * * * int showPropFont - ONLY_FIXED : shows only fixed fonts * * doesn't show prop font * * toggle button also. * * PREF_FIXED : can select either fixed * * or proportional fonts; * * but starting option is * * Fixed fonts. * * PREF_PROP : can select either fixed * * or proportional fonts; * * but starting option is * * proportional fonts. * * * * char * currFont - ASCII string that contains the name * * of the currently selected font. * * * * Pixel sampleFG, sampleBG - Foreground/Background colors in * * which to display the sample * * text. * * * * * * Returns: * * * * pointer to an ASCII character string that contains the name of * * the selected font (in X format for naming fonts); it is the users * * responsibility to free the space allocated to this string. * * * * Comments: * * * * The calling function has to call the appropriate routines to set * * the current font to the one represented by the returned string. * * * *******************************************************************************/ char *FontSel(Widget parent, int showPropFonts, const char *currFont, Pixel sampleFG, Pixel sampleBG) { Widget dialog, form, okButton, cancelButton; Widget styleList, sizeList, fontName, fontList; Widget sizeToggle, propFontToggle = NULL, dispField; Widget nameLabel, sampleLabel; Arg args[MAX_ARGS]; int n; XmString tempStr; char bigFont[MAX_FONT_NAME_LEN]; xfselControlBlkType ctrlBlk; Display *theDisplay; ctrlBlk.fontData = XListFonts(XtDisplay(parent), "-*-*-*-*-*-*-*-*-*-*-*-*-*-*", MAX_NUM_FONTS, &ctrlBlk.numFonts); FindBigFont(&ctrlBlk, bigFont); ctrlBlk.oldFont = XLoadQueryFont(XtDisplay(parent), bigFont); ctrlBlk.oldFontList = XmFontListCreate(ctrlBlk.oldFont, XmSTRING_DEFAULT_CHARSET); ctrlBlk.sampleFG = sampleFG; ctrlBlk.sampleBG = sampleBG; dialog = CreateDialogShell(parent, "Font Selector", args, 0); /* Set up window sizes for form widget */ n = 0; XtSetArg(args[n], XmNautoUnmanage, FALSE); n++; XtSetArg(args[n], XmNdialogStyle, XmDIALOG_FULL_APPLICATION_MODAL); n++; /* Create form popup dialog widget */ form = XtCreateWidget ("Font Selector", xmFormWidgetClass, dialog, args, n); /* Create pushbutton widgets */ n = 0; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION); n++; XtSetArg(args[n], XmNbottomOffset, 4); n++; XtSetArg(args[n], XmNtopOffset, 1); n++; XtSetArg(args[n], XmNrightPosition, 45); n++; XtSetArg(args[n], XmNwidth, 110); n++; XtSetArg(args[n], XmNheight, 28); n++; XtSetArg(args[n], XmNshowAsDefault, TRUE); n++; okButton = XtCreateManagedWidget("OK", xmPushButtonWidgetClass, form, args, n); n = 0; XtSetArg(args[n], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_POSITION); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, okButton); n++; XtSetArg(args[n], XmNbottomWidget, okButton); n++; XtSetArg(args[n], XmNleftPosition, 55); n++; XtSetArg(args[n], XmNwidth, 110); n++; XtSetArg(args[n], XmNheight, 28); n++; cancelButton = XtCreateManagedWidget("Cancel", xmPushButtonWidgetClass, form, args, n); /* create font name text widget and the corresponding label */ n = 0; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_POSITION); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION); n++; XtSetArg(args[n], XmNbottomWidget, okButton); n++; XtSetArg(args[n], XmNleftPosition, 1); n++; XtSetArg(args[n], XmNrightPosition, 99); n++; XtSetArg(args[n], XmNeditable, True); n++; XtSetArg(args[n], XmNeditMode, XmSINGLE_LINE_EDIT); n++; XtSetArg(args[n], XmNmaxLength, MAX_FONT_NAME_LEN); n++; fontName = XtCreateManagedWidget("fontname", xmTextWidgetClass, form, args, n); RemapDeleteKey(fontName); /* kludge to handle delete and BS */ n = 0; tempStr = XmStringCreate("Font Name:", XmSTRING_DEFAULT_CHARSET); XtSetArg(args[n], XmNlabelString, tempStr); n++; XtSetArg(args[n], XmNmnemonic, 'N'); n++; XtSetArg(args[n], XmNuserData, fontName); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_OPPOSITE_WIDGET); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, fontName); n++; XtSetArg(args[n], XmNbottomWidget, fontName); n++; XtSetArg(args[n], XmNtopOffset, 1); n++; nameLabel = XtCreateManagedWidget("Font Name:", xmLabelWidgetClass, form, args, n); XmStringFree(tempStr); /* create sample display text field widget */ n = 0; XtSetArg(args[n], XmNleftAttachment, XmATTACH_POSITION); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION); n++; XtSetArg(args[n], XmNrightPosition, 99); n++; XtSetArg(args[n], XmNbottomWidget, nameLabel); n++; XtSetArg(args[n], XmNleftPosition, 1); n++; XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++; XtSetArg(args[n], XmNvalue, "ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz 0123456789"); n++; XtSetArg(args[n], XmNforeground, sampleFG); n++; XtSetArg(args[n], XmNbackground, sampleBG); n++; dispField = XtCreateManagedWidget(" ", xmTextFieldWidgetClass, form, args, n); n = 0; tempStr = XmStringCreate("Sample:", XmSTRING_DEFAULT_CHARSET); XtSetArg(args[n], XmNlabelString, tempStr); n++; XtSetArg(args[n], XmNmnemonic, 'S'); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_OPPOSITE_WIDGET); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, dispField); n++; XtSetArg(args[n], XmNbottomWidget, dispField); n++; XtSetArg(args[n], XmNtopOffset, 1); n++; sampleLabel = XtCreateManagedWidget("Font Name:", xmLabelWidgetClass, form, args, n); XmStringFree(tempStr); /* create toggle buttons */ n = 0; tempStr = XmStringCreate("Show Size in Points", XmSTRING_DEFAULT_CHARSET); XtSetArg(args[n], XmNlabelString, tempStr); n++; XtSetArg(args[n], XmNmnemonic, 'P'); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_POSITION); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftPosition, 2); n++; XtSetArg(args[n], XmNtopOffset, 1); n++; XtSetArg(args[n], XmNbottomWidget, sampleLabel); n++; sizeToggle = XtCreateManagedWidget("sizetoggle", xmToggleButtonWidgetClass, form, args, n); XmStringFree(tempStr); if (showPropFonts != ONLY_FIXED) { n = 0; tempStr = XmStringCreate("Show Proportional Width Fonts", XmSTRING_DEFAULT_CHARSET); XtSetArg(args[n], XmNlabelString, tempStr); n++; XtSetArg(args[n], XmNmnemonic, 'W'); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET); n++; XtSetArg(args[n], XmNrightPosition, 98); n++; XtSetArg(args[n], XmNtopWidget, sizeToggle); n++; XtSetArg(args[n], XmNbottomWidget, sizeToggle); n++; XtSetArg(args[n], XmNtopOffset, 1); n++; propFontToggle = XtCreateManagedWidget("propfonttoggle", xmToggleButtonWidgetClass, form, args, n); XmStringFree(tempStr); } /* create scroll list widgets */ /* "Font" list */ n = 0; tempStr = XmStringCreate("Font:", XmSTRING_DEFAULT_CHARSET); XtSetArg(args[n], XmNlabelString, tempStr); n++; XtSetArg(args[n], XmNmnemonic, 'F'); n++; XtSetArg(args[n], XmNtopOffset, 2); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_POSITION); n++; XtSetArg(args[n], XmNleftPosition, 1); n++; nameLabel = XtCreateManagedWidget("Font:", xmLabelWidgetClass, form, args, n); XmStringFree(tempStr); n = 0; XtSetArg(args[n], XmNvisibleItemCount, 15); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_OPPOSITE_WIDGET); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION); n++; XtSetArg(args[n], XmNbottomWidget, sizeToggle); n++; XtSetArg(args[n], XmNtopWidget, nameLabel); n++; XtSetArg(args[n], XmNleftWidget, nameLabel); n++; XtSetArg(args[n], XmNrightPosition, 52); n++; fontList = XmCreateScrolledList(form, "fontlist", args, n); AddMouseWheelSupport(fontList); XtManageChild(fontList); XtVaSetValues(nameLabel, XmNuserData, fontList, NULL); /* "Style" list */ n = 0; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION); n++; XtSetArg(args[n], XmNtopWidget, nameLabel); n++; XtSetArg(args[n], XmNleftOffset, 5); n++; XtSetArg(args[n], XmNleftWidget, XtParent(fontList)); n++; XtSetArg(args[n], XmNbottomWidget, XtParent(fontList)); n++; XtSetArg(args[n], XmNrightPosition, 85); n++; styleList = XmCreateScrolledList(form, "stylelist", args, n); AddMouseWheelSupport(styleList); XtManageChild(styleList); n = 0; tempStr = XmStringCreate("Style:", XmSTRING_DEFAULT_CHARSET); XtSetArg(args[n], XmNmnemonic, 'y'); n++; XtSetArg(args[n], XmNuserData, styleList); n++; XtSetArg(args[n], XmNlabelString, tempStr); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_OPPOSITE_WIDGET); n++; XtSetArg(args[n], XmNbottomWidget, XtParent(styleList)); n++; XtSetArg(args[n], XmNleftWidget, XtParent(styleList)); n++; XtCreateManagedWidget("Style:", xmLabelWidgetClass, form, args, n); XmStringFree(tempStr); /* "Size" list */ n = 0; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, nameLabel); n++; XtSetArg(args[n], XmNleftWidget, XtParent(styleList)); n++; XtSetArg(args[n], XmNbottomWidget, XtParent(fontList)); n++; XtSetArg(args[n], XmNleftOffset, 5); n++; XtSetArg(args[n], XmNrightPosition, 99); n++; sizeList = XmCreateScrolledList(form, "sizelist", args, n); AddMouseWheelSupport(sizeList); XtManageChild(sizeList); n = 0; tempStr = XmStringCreate("Size:", XmSTRING_DEFAULT_CHARSET); XtSetArg(args[n], XmNlabelString, tempStr); n++; XtSetArg(args[n], XmNmnemonic, 'z'); n++; XtSetArg(args[n], XmNuserData, sizeList); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_OPPOSITE_WIDGET); n++; XtSetArg(args[n], XmNbottomWidget, XtParent(sizeList)); n++; XtSetArg(args[n], XmNleftWidget, XtParent(sizeList)); n++; XtCreateManagedWidget("Size:", xmLabelWidgetClass, form, args, n); XmStringFree(tempStr); /* update form widgets cancel button */ n = 0; XtSetArg(args[n], XmNcancelButton, cancelButton); n++; XtSetValues(form, args, n); /* update application's control block structure */ ctrlBlk.form = form; ctrlBlk.okButton = okButton; ctrlBlk.cancelButton = cancelButton; ctrlBlk.fontList = fontList; ctrlBlk.styleList = styleList; ctrlBlk.sizeList = sizeList; ctrlBlk.fontNameField = fontName; ctrlBlk.sizeToggle = sizeToggle; if (showPropFonts != ONLY_FIXED) ctrlBlk.propFontToggle = propFontToggle; ctrlBlk.dispField = dispField; ctrlBlk.exitFlag = FALSE; ctrlBlk.destroyedFlag = FALSE; ctrlBlk.showPropFonts = showPropFonts; ctrlBlk.showSizeInPixels = TRUE; ctrlBlk.sel1 = NULL; ctrlBlk.sel2 = NULL; ctrlBlk.sel3 = NULL; ctrlBlk.fontName = NULL; setupScrollLists(NONE, ctrlBlk); /* update scroll lists */ if (showPropFonts == PREF_PROP) XmToggleButtonSetState(propFontToggle, TRUE, FALSE); /* Register callback functions */ if (showPropFonts != ONLY_FIXED) XtAddCallback(propFontToggle, XmNvalueChangedCallback, (XtCallbackProc)propFontToggleAction, (char *)&ctrlBlk); XtAddCallback(sizeToggle, XmNvalueChangedCallback, (XtCallbackProc)sizeToggleAction, (char *)&ctrlBlk); XtAddCallback(fontList, XmNbrowseSelectionCallback, (XtCallbackProc)fontAction, (char *)&ctrlBlk); XtAddCallback(styleList, XmNbrowseSelectionCallback, (XtCallbackProc)styleAction, (char *)&ctrlBlk); XtAddCallback(sizeList, XmNbrowseSelectionCallback, (XtCallbackProc)sizeAction, (char *)&ctrlBlk); XtAddCallback(okButton, XmNactivateCallback, (XtCallbackProc)okAction, (char *)&ctrlBlk); XtAddCallback(cancelButton, XmNactivateCallback, (XtCallbackProc)cancelAction, (char *)&ctrlBlk); /* add event handler to setup input focus at start to scroll list */ XtAddEventHandler(fontList, FocusChangeMask, FALSE, (XtEventHandler)setFocus, (char *)&ctrlBlk); XmProcessTraversal(fontList, XmTRAVERSE_CURRENT); /* setup tabgroups */ XmAddTabGroup(fontList); XmAddTabGroup(styleList); XmAddTabGroup(sizeList); XmAddTabGroup(sizeToggle); if (showPropFonts != ONLY_FIXED) XmAddTabGroup(propFontToggle); XmAddTabGroup(fontName); XmAddTabGroup(okButton); XmAddTabGroup(cancelButton); /* Make sure that we don't try to access the dialog if the user destroyed it (possibly indirectly, by destroying the parent). */ XtAddCallback(dialog, XmNdestroyCallback, (XtCallbackProc)destroyCB, (char *)&ctrlBlk); /* Link Motif Close option to cancel action */ AddMotifCloseCallback(dialog, (XtCallbackProc)cancelAction, &ctrlBlk); /* Handle dialog mnemonics */ AddDialogMnemonicHandler(form, FALSE); /* Realize Widgets */ ManageDialogCenteredOnPointer(form); /* set up current font parameters */ if (currFont[0] != '\0') startupFont(&ctrlBlk, currFont); /* Make sure that we can still access the display in case the form gets destroyed */ theDisplay = XtDisplay(form); /* enter event loop */ while (! ctrlBlk.exitFlag && ! ctrlBlk.destroyedFlag) XtAppProcessEvent(XtWidgetToApplicationContext(form), XtIMAll); if (! ctrlBlk.destroyedFlag) { /* Don't let the callback destroy the font name */ XtRemoveCallback(dialog, XmNdestroyCallback, (XtCallbackProc)destroyCB, (char *)&ctrlBlk); XtDestroyWidget(dialog); } if (ctrlBlk.oldFont != NULL) { XFreeFont(theDisplay, ctrlBlk.oldFont); XmFontListFree(ctrlBlk.oldFontList); } return(ctrlBlk.fontName); } /* gets a specific substring from a string */ static void getStringComponent(const char *inStr, int pos, char *outStr) { int i, j; *outStr = '\0'; if (pos > NUM_COMPONENTS_FONT_NAME) { fprintf(stderr, "Warning: getStringComponent being used for "); fprintf(stderr, "pos > %d\nIf such ", NUM_COMPONENTS_FONT_NAME); fprintf(stderr, "use is intended remove these warning lines\n"); } for (i = 0; (pos > 0) && (inStr[i] != '\0'); i++) if (inStr[i] == DELIM) pos--; if (inStr[i] == '\0') return; for (j = 0; (inStr[i] != DELIM) && (inStr[i] != '\0'); i++, j++) outStr[j] = inStr[i]; outStr[j] = '\0'; } /* parse through the fontlist data and set up the three scroll lists */ static void setupScrollLists(int dontChange, xfselControlBlkType ctrlBlk) { char *itemBuf1[MAX_ENTRIES_IN_LIST]; char *itemBuf2[MAX_ENTRIES_IN_LIST]; char *itemBuf3[MAX_ENTRIES_IN_LIST]; int itemCount1, itemCount2, itemCount3; char buff1[TEMP_BUF_SIZE]; XmString items[MAX_ENTRIES_IN_LIST]; int i; itemCount1 = 0; itemCount2 = 0; itemCount3 = 0; for (i = 0; i < ctrlBlk.numFonts && i < MAX_ENTRIES_IN_LIST; i++) { if ((dontChange != FONT) && (styleMatch(&ctrlBlk, ctrlBlk.fontData[i])) && (sizeMatch (&ctrlBlk, ctrlBlk.fontData[i])) && ((ctrlBlk.showPropFonts == PREF_PROP) || (notPropFont(ctrlBlk.fontData[i])))) { getFontPart(ctrlBlk.fontData[i], buff1); addItemToList(itemBuf1, buff1, &itemCount1); } if ((dontChange != STYLE) && (fontMatch(&ctrlBlk, ctrlBlk.fontData[i])) && (sizeMatch (&ctrlBlk, ctrlBlk.fontData[i])) && ((ctrlBlk.showPropFonts == PREF_PROP) || (notPropFont(ctrlBlk.fontData[i])))) { getStylePart(ctrlBlk.fontData[i], buff1); addItemToList(itemBuf2, buff1, &itemCount2); } if ((dontChange != SIZE) && (fontMatch(&ctrlBlk, ctrlBlk.fontData[i])) && (styleMatch (&ctrlBlk, ctrlBlk.fontData[i])) && ((ctrlBlk.showPropFonts == PREF_PROP) || (notPropFont(ctrlBlk.fontData[i])))) { getSizePart(ctrlBlk.fontData[i], buff1, ctrlBlk.showSizeInPixels); addItemToList(itemBuf3, buff1, &itemCount3); } } /* end - for (i = 0; i < ctrlBlk.numFonts; i++) */ /* recreate all three scroll lists where necessary */ if (dontChange != FONT) { for (i = 0; i < itemCount1; i++) { items[i] = XmStringCreate(itemBuf1[i], XmSTRING_DEFAULT_CHARSET); XtFree(itemBuf1[i]); } XmListDeleteAllItems(ctrlBlk.fontList); XmListAddItems(ctrlBlk.fontList, items, itemCount1, 1); if (ctrlBlk.sel1 != NULL) { XmStringFree(items[0]); items[0] = XmStringCreate(ctrlBlk.sel1, XmSTRING_DEFAULT_CHARSET); XmListSelectItem(ctrlBlk.fontList, items[0], FALSE); XmListSetBottomItem(ctrlBlk.fontList, items[0]); } for (i = 0; i < itemCount1; i++) XmStringFree(items[i]); } if (dontChange != STYLE) { for (i = 0; i < itemCount2; i++) { items[i] = XmStringCreate(itemBuf2[i], XmSTRING_DEFAULT_CHARSET); XtFree(itemBuf2[i]); } XmListDeleteAllItems(ctrlBlk.styleList); XmListAddItems(ctrlBlk.styleList, items, itemCount2, 1); if (ctrlBlk.sel2 != NULL) { XmStringFree(items[0]); items[0] = XmStringCreate(ctrlBlk.sel2, XmSTRING_DEFAULT_CHARSET); XmListSelectItem(ctrlBlk.styleList, items[0], FALSE); XmListSetBottomItem(ctrlBlk.styleList, items[0]); } for (i = 0; i < itemCount2; i++) XmStringFree(items[i]); } if (dontChange != SIZE) { for (i = 0; i < itemCount3; i++) { items[i] = XmStringCreate(itemBuf3[i], XmSTRING_DEFAULT_CHARSET); XtFree(itemBuf3[i]); } XmListDeleteAllItems(ctrlBlk.sizeList); XmListAddItems(ctrlBlk.sizeList, items, itemCount3, 1); if (ctrlBlk.sel3 != NULL) { XmStringFree(items[0]); items[0] = XmStringCreate(ctrlBlk.sel3, XmSTRING_DEFAULT_CHARSET); XmListSelectItem(ctrlBlk.sizeList, items[0], FALSE); XmListSetBottomItem(ctrlBlk.sizeList, items[0]); } for (i = 0; i < itemCount3; i++) XmStringFree(items[i]); } } /* returns TRUE if argument is not name of a proportional font */ static int notPropFont(const char *font) { char buff1[TEMP_BUF_SIZE]; getStringComponent(font, 11, buff1); if ((strcmp(buff1, "p") == 0) || (strcmp(buff1, "P") == 0)) return(FALSE); else return(TRUE); } /* returns TRUE if the style portion of the font matches the currently selected style */ static int styleMatch(xfselControlBlkType *ctrlBlk, const char *font) { char buff[TEMP_BUF_SIZE]; if (ctrlBlk->sel2 == NULL) return(TRUE); getStylePart(font, buff); if (strcmp(buff, ctrlBlk->sel2) == 0) return(TRUE); else return(FALSE); } /* returns TRUE if the size portion of the font matches the currently selected size */ static int sizeMatch(xfselControlBlkType *ctrlBlk, const char *font) { char buff[TEMP_BUF_SIZE]; if (ctrlBlk->sel3 == NULL) return(TRUE); getSizePart(font, buff, ctrlBlk->showSizeInPixels); if (strcmp(buff, ctrlBlk->sel3) == 0) return(TRUE); else return(FALSE); } /* returns TRUE if the font portion of the font matches the currently selected font */ static int fontMatch(xfselControlBlkType *ctrlBlk, const char *font) { char buff[TEMP_BUF_SIZE]; if (ctrlBlk->sel1 == NULL) return(TRUE); getFontPart(font, buff); if (strcmp(buff, ctrlBlk->sel1) == 0) return(TRUE); else return(FALSE); } /* inserts a string into correct sorted position in a list */ static void addItemToList(char **buf, const char *item, int *count) { int i, j; if (*count == MAX_ENTRIES_IN_LIST) { fprintf(stderr, "Trying to add more than MAX_ENTRIES_IN_LIST "); fprintf(stderr, "(%d) entries to array\n", MAX_ENTRIES_IN_LIST); return; } for (i = 0; i < *count; i++) { if (strcmp(buf[i], item) == 0) return; if (strcmp(buf[i], item) > 0) break; } for (j = *count; j > i; j--) buf[j] = buf[j-1]; buf[i] = XtMalloc(strlen(item) + 1); strcpy(buf[i], item); (*count)++; } /* given a font name this function returns the part used in the first scroll list */ static void getFontPart(const char *font, char *buff1) { char buff2[TEMP_BUF_SIZE], buff3[TEMP_BUF_SIZE]; char buff4[TEMP_BUF_SIZE]; getStringComponent(font, 2, buff1); getStringComponent(font, 1, buff2); sprintf(buff3, "%s (%s", buff1, buff2); getStringComponent(font, 13, buff1); getStringComponent(font, 14, buff4); if (((strncmp(buff1, "iso8859", 7) == 0) || (strncmp(buff1, "ISO8859", 7) == 0)) && (strcmp(buff4, "1") == 0)) sprintf(buff1, "%s)", buff3); else { sprintf(buff2, "%s, %s,", buff3, buff1); sprintf(buff1, "%s %s)", buff2, buff4); } } /* given a font name this function returns the part used in the second scroll list */ static void getStylePart(const char *font, char *buff1) { char buff2[TEMP_BUF_SIZE], buff3[TEMP_BUF_SIZE]; getStringComponent(font, 3, buff3); getStringComponent(font, 5, buff2); if ((strcmp(buff2, "normal") != 0) && (strcmp(buff2, "Normal") != 0) && (strcmp(buff2, "NORMAL") != 0)) sprintf(buff1, "%s %s", buff3, buff2); else strcpy(buff1, buff3); getStringComponent(font, 6, buff2); if (buff2[0] != '\0') sprintf(buff3, "%s %s", buff1, buff2); else strcpy(buff3, buff1); getStringComponent(font, 4, buff2); if ((strcmp(buff2, "o") == 0) || (strcmp(buff2, "O") == 0)) sprintf(buff1, "%s oblique", buff3); else if ((strcmp(buff2, "i") == 0) || (strcmp(buff2, "I") == 0)) sprintf(buff1, "%s italic", buff3); if (strcmp(buff1, " ") == 0) strcpy(buff1, "-"); } /* given a font name this function returns the part used in the third scroll list */ static void getSizePart(const char *font, char *buff1, int inPixels) { int size; if (inPixels) { getStringComponent(font, 7, buff1); size = atoi(buff1); sprintf(buff1, "%2d", size); } else { double temp; getStringComponent(font, 8, buff1); size = atoi(buff1); temp = (double)size / 10.0; if (buff1[strlen(buff1) - 1] == '0') { size = (int)floor(temp+0.5); sprintf(buff1, "%2d", size); } else sprintf(buff1, "%4.1f", temp); } } /* Call back functions start from here - suffix Action in the function name is for the callback function for the corresponding widget */ static void propFontToggleAction(Widget widget, xfselControlBlkType *ctrlBlk, XmToggleButtonCallbackStruct *call_data) { if (call_data->reason == XmCR_VALUE_CHANGED) { if (ctrlBlk->showPropFonts == PREF_FIXED) ctrlBlk->showPropFonts = PREF_PROP; else ctrlBlk->showPropFonts = PREF_FIXED; if (ctrlBlk->sel1 != NULL) XtFree(ctrlBlk->sel1); ctrlBlk->sel1 = NULL; if (ctrlBlk->sel2 != NULL) XtFree(ctrlBlk->sel2); ctrlBlk->sel2 = NULL; if (ctrlBlk->sel3 != NULL) XtFree(ctrlBlk->sel3); ctrlBlk->sel3 = NULL; setupScrollLists(NONE, *ctrlBlk); XmTextSetString(ctrlBlk->fontNameField, ""); enableSample(ctrlBlk, False, NULL); } } static void sizeToggleAction(Widget widget, xfselControlBlkType *ctrlBlk, XmToggleButtonCallbackStruct *call_data) { int i, makeSelection; char newSize[10]; XmString str; if (call_data->reason == XmCR_VALUE_CHANGED) { makeSelection = (ctrlBlk->sel3 != NULL); for (i = 0; (makeSelection) && (i < ctrlBlk->numFonts); i++) if ((fontMatch(ctrlBlk, ctrlBlk->fontData[i])) && (styleMatch(ctrlBlk, ctrlBlk->fontData[i])) && (sizeMatch(ctrlBlk, ctrlBlk->fontData[i]))) { getSizePart(ctrlBlk->fontData[i], newSize, !ctrlBlk->showSizeInPixels); break; } if (ctrlBlk->showSizeInPixels) ctrlBlk->showSizeInPixels = FALSE; else ctrlBlk->showSizeInPixels = TRUE; if (ctrlBlk->sel3 != NULL) XtFree(ctrlBlk->sel3); ctrlBlk->sel3 = NULL; setupScrollLists(NONE, *ctrlBlk); if (makeSelection) { str = XmStringCreate(newSize, XmSTRING_DEFAULT_CHARSET); XmListSelectItem(ctrlBlk->sizeList, str, TRUE); XmListSetBottomItem(ctrlBlk->sizeList, str); XmStringFree(str); } } } static void enableSample(xfselControlBlkType *ctrlBlk, Bool turn_on, XmFontList *fontList) { int n=0; Arg args[4]; XtSetArg(args[n], XmNeditable, turn_on); n++; XtSetArg(args[n], XmNcursorPositionVisible, turn_on); n++; if( turn_on ) { if( !fontList ) { fprintf(stderr, "nedit: Internal error in fontsel.c, line %i\n", \ __LINE__); } else { XtSetArg(args[n], XmNfontList, *fontList); n++; } XtSetArg(args[n], XmNforeground, ctrlBlk->sampleFG); n++; } else { XtSetArg(args[n], XmNforeground, ctrlBlk->sampleBG); n++; } XtSetValues(ctrlBlk->dispField, args, n); /* Make sure the sample area gets resized if the font size changes */ XtUnmanageChild(ctrlBlk->dispField); XtManageChild(ctrlBlk->dispField); } static void fontAction(Widget widget, xfselControlBlkType *ctrlBlk, XmListCallbackStruct *call_data) { char *sel; XmStringGetLtoR(call_data->item, XmSTRING_DEFAULT_CHARSET, &sel); if (ctrlBlk->sel1 == NULL) { ctrlBlk->sel1 = XtMalloc(strlen(sel) + 1); strcpy(ctrlBlk->sel1, sel); } else { if (strcmp(ctrlBlk->sel1, sel) == 0) { /* Unselecting current selection */ XtFree(ctrlBlk->sel1); ctrlBlk->sel1 = NULL; XmListDeselectItem(widget, call_data->item); } else { XtFree(ctrlBlk->sel1); ctrlBlk->sel1 = XtMalloc(strlen(sel) + 1); strcpy(ctrlBlk->sel1, sel); } } XtFree(sel); setupScrollLists(FONT, *ctrlBlk); if ((ctrlBlk->sel1 != NULL) && (ctrlBlk->sel2 != NULL) && (ctrlBlk->sel3 != NULL)) choiceMade(ctrlBlk); else { enableSample(ctrlBlk, False, NULL); XmTextSetString(ctrlBlk->fontNameField, ""); } } static void styleAction(Widget widget, xfselControlBlkType *ctrlBlk, XmListCallbackStruct *call_data) { char *sel; XmStringGetLtoR(call_data->item, XmSTRING_DEFAULT_CHARSET, &sel); if (ctrlBlk->sel2 == NULL) { ctrlBlk->sel2 = XtMalloc(strlen(sel) + 1); strcpy(ctrlBlk->sel2, sel); } else { if (strcmp(ctrlBlk->sel2, sel) == 0) { /* unselecting current selection */ XtFree(ctrlBlk->sel2); ctrlBlk->sel2 = NULL; XmListDeselectItem(widget, call_data->item); } else { XtFree(ctrlBlk->sel2); ctrlBlk->sel2 = XtMalloc(strlen(sel) + 1); strcpy(ctrlBlk->sel2, sel); } } XtFree(sel); setupScrollLists(STYLE, *ctrlBlk); if ((ctrlBlk->sel1 != NULL) && (ctrlBlk->sel2 != NULL) && (ctrlBlk->sel3 != NULL)) choiceMade(ctrlBlk); else { enableSample(ctrlBlk, False, NULL); XmTextSetString(ctrlBlk->fontNameField, ""); } } static void sizeAction(Widget widget, xfselControlBlkType *ctrlBlk, XmListCallbackStruct *call_data) { char *sel; XmStringGetLtoR(call_data->item, XmSTRING_DEFAULT_CHARSET, &sel); if (ctrlBlk->sel3 == NULL) { ctrlBlk->sel3 = XtMalloc(strlen(sel) + 1); strcpy(ctrlBlk->sel3, sel); } else { if (strcmp(ctrlBlk->sel3, sel) == 0) { /* unselecting current selection */ XtFree(ctrlBlk->sel3); ctrlBlk->sel3 = NULL; XmListDeselectItem(widget, call_data->item); } else { XtFree(ctrlBlk->sel3); ctrlBlk->sel3 = XtMalloc(strlen(sel) + 1); strcpy(ctrlBlk->sel3, sel); } } XtFree(sel); setupScrollLists(SIZE, *ctrlBlk); if ((ctrlBlk->sel1 != NULL) && (ctrlBlk->sel2 != NULL) && (ctrlBlk->sel3 != NULL)) choiceMade(ctrlBlk); else { enableSample(ctrlBlk, False, NULL); XmTextSetString(ctrlBlk->fontNameField, ""); } } /* function called when all three choices have been made; sets up font name and displays sample font */ static void choiceMade(xfselControlBlkType *ctrlBlk) { int i; if (ctrlBlk->fontName != NULL) XtFree(ctrlBlk->fontName); ctrlBlk->fontName = NULL; for (i = 0; i < ctrlBlk->numFonts; i++) { if ((fontMatch(ctrlBlk, ctrlBlk->fontData[i])) && (styleMatch(ctrlBlk, ctrlBlk->fontData[i])) && (sizeMatch (ctrlBlk, ctrlBlk->fontData[i]))) { ctrlBlk->fontName = XtMalloc( strlen(ctrlBlk->fontData[i]) + 1); strcpy(ctrlBlk->fontName, ctrlBlk->fontData[i]); break; } } if (ctrlBlk->fontName != NULL) { XmTextSetString(ctrlBlk->fontNameField, ctrlBlk->fontName); dispSample(ctrlBlk); } else { DialogF (DF_ERR, ctrlBlk->form, 1, "Font Specification", "Invalid Font Specification", "OK"); } } /* loads selected font and displays sample text in that font */ static void dispSample(xfselControlBlkType *ctrlBlk) { XFontStruct *font; XmFontList fontList; Display *display; display = XtDisplay(ctrlBlk->form); font = XLoadQueryFont(display, ctrlBlk->fontName); fontList = XmFontListCreate(font, XmSTRING_DEFAULT_CHARSET); enableSample(ctrlBlk, True, &fontList); if (ctrlBlk->oldFont != NULL) { XFreeFont(display, ctrlBlk->oldFont); XmFontListFree(ctrlBlk->oldFontList); } ctrlBlk->oldFont = font; ctrlBlk->oldFontList = fontList; } static void destroyCB(Widget widget, xfselControlBlkType *ctrlBlk, XmListCallbackStruct *call_data) { /* Prevent double destruction of the font selection dialog */ ctrlBlk->destroyedFlag = TRUE; cancelAction(widget, ctrlBlk, call_data); } static void cancelAction(Widget widget, xfselControlBlkType *ctrlBlk, XmListCallbackStruct *call_data) { if (ctrlBlk->sel1 != NULL) XtFree(ctrlBlk->sel1); if (ctrlBlk->sel2 != NULL) XtFree(ctrlBlk->sel2); if (ctrlBlk->sel3 != NULL) XtFree(ctrlBlk->sel3); if (ctrlBlk->fontName != NULL) XtFree(ctrlBlk->fontName); ctrlBlk->fontName = NULL; XFreeFontNames(ctrlBlk->fontData); ctrlBlk->exitFlag = TRUE; } static void okAction(Widget widget, xfselControlBlkType *ctrlBlk, XmPushButtonCallbackStruct *call_data) { char *fontPattern; char **fontName; int i; fontPattern = XmTextGetString(ctrlBlk->fontNameField); fontName = XListFonts(XtDisplay(ctrlBlk->form), fontPattern, 1, &i); XtFree(fontPattern); if (i != 1) { DialogF (DF_ERR, ctrlBlk->okButton, 1, "Font Specification", "Invalid Font Specification", "OK"); XFreeFontNames(fontName); } else { if (ctrlBlk->fontName != NULL) XtFree(ctrlBlk->fontName); ctrlBlk->fontName = XtMalloc(strlen(fontName[0]) + 1); strcpy(ctrlBlk->fontName, fontName[0]); if (ctrlBlk->sel1 != NULL) XtFree(ctrlBlk->sel1); if (ctrlBlk->sel2 != NULL) XtFree(ctrlBlk->sel2); if (ctrlBlk->sel3 != NULL) XtFree(ctrlBlk->sel3); XFreeFontNames(fontName); XFreeFontNames(ctrlBlk->fontData); ctrlBlk->exitFlag = TRUE; } } /* if current font is passed as an argument then this function is invoked and sets up initial entries */ static void startupFont(xfselControlBlkType *ctrlBlk, const char *font) { int i; char **fontName; char part[TEMP_BUF_SIZE]; XmString str; fontName = XListFonts(XtDisplay(ctrlBlk->form), font, 1, &i); if (i == 0) { /* invalid font passed in at startup */ XFreeFontNames(fontName); return; } ctrlBlk->fontName = XtMalloc(strlen(fontName[0]) + 1); strcpy(ctrlBlk->fontName, fontName[0]); getFontPart(fontName[0], part); XFreeFontNames(fontName); str = XmStringCreate(part, XmSTRING_DEFAULT_CHARSET); XmListSetBottomItem(ctrlBlk->fontList, str); XmListSelectItem(ctrlBlk->fontList, str, TRUE); XmListSelectItem(ctrlBlk->fontList, str, TRUE); XmStringFree(str); dispSample(ctrlBlk); XmTextSetString(ctrlBlk->fontNameField, ctrlBlk->fontName); } /* hacked code to move initial input focus to first scroll list and at the same time have the OK button as the default button */ static void setFocus(Widget w, xfselControlBlkType *ctrlBlk, XEvent *event, Boolean *continueToDispatch) { int n; Arg args[2]; *continueToDispatch = TRUE; n = 0; XtSetArg(args[n], XmNdefaultButton, ctrlBlk->okButton); n++; XtSetValues(ctrlBlk->form, args, n); } /* finds the name of the biggest font less than the given limit MAX_DISPLAY_SIZE used to set up the initial height of the display widget */ static void FindBigFont(xfselControlBlkType *ctrlBlk, char *bigFont) { int i, maxSize, ind = -1, size; char sizeStr[10]; for (i = 0, maxSize = 0; i < ctrlBlk->numFonts; i++) { getStringComponent(ctrlBlk->fontData[i], 7, sizeStr); size = atoi(sizeStr); if ((size > maxSize) && (size < MAX_DISPLAY_SIZE)) { ind = i; maxSize = size; } } if (ind >= 0) { strcpy(bigFont, ctrlBlk->fontData[ind]); } else { bigFont[0] = 0; } }