/* This file is part of the FElt finite element analysis package. Copyright (C) 1993-2000 Jason I. Gobat and Darren C. Atkinson This program 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. This program 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 this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /************************************************************************ * File: tabgroup.c * * * * Description: This file contains the private and public function and * * type definitions for the tab group mechanism. * ************************************************************************/ # include # include # include # include # include # include "TabGroup.h" # ifndef XtNshadowWidth # define XtNshadowWidth "shadowWidth" # endif # if NeedWidePrototypes # define BOOLEAN int # else # define BOOLEAN Boolean # endif # define MaxTabGroups 64 # define TranslationTable \ "NoneTab: ChangeFocus(%d,next)\n\ !ShiftTab: ChangeFocus(%d,prev)\n\ : ChangeFocus(%d,request)" typedef struct tab_group { Widget ancestor; WidgetList members; Cardinal num_members; Cardinal focused; Pixel highlight; Pixel border_color; Pixmap border_pixmap; Boolean clear_caret; } *TabGroup; static TabGroup group_list [MaxTabGroups]; static Cardinal num_groups = 0; static Widget focused_widget; /************************************************************************ * Function: ChangeFocusProc * * * * Description: Changes the focused widget in a tab group by restoring * * the original appearance of the widget, determining the * * newly focused widget, saving its appearance, and * * highlighting the widget. * ************************************************************************/ static void ChangeFocusProc (w, event, params, num_params) Widget w; XEvent *event; String *params; Cardinal *num_params; { Arg args [2]; Cardinal offset; Cardinal focused; Cardinal group_number; TabGroup group; sscanf (params [0], "%u", &group_number); group = group_list [group_number]; focused = group -> focused; /* Determine if a request was made. */ if (!strcmp (params [1], "request")) if (!strcmp (event -> xclient.data.b, "get")) { focused_widget = group -> members [focused]; return; } /* Restore the original appearance of the widget if necessary. */ if (focused != group -> num_members) { XtSetArg (args [0], XtNborderColor, group -> border_color); XtSetArg (args [1], XtNborderPixmap, group -> border_pixmap); XtSetValues (group -> members [focused], args, XtNumber (args)); if (group -> clear_caret == True) { XtSetArg (args [0], XtNdisplayCaret, False); XtSetValues (group -> members [focused], args, 1); } } /* Determine the index of the newly focused widget. */ offset = 1; if (!strcmp (params [1], "prev")) offset = group -> num_members - 1; if (!strcmp (params [1], "next")) focused = (focused + 1) % group -> num_members; else if (!strcmp (params [1], "prev")) focused = (group -> num_members + focused - 1) % group -> num_members; else for (focused = 0; focused < group -> num_members; focused ++) if (w == group -> members [focused]) break; /* Move off the widget if it is not sensitive or managed. */ while (!XtIsSensitive (group -> members [focused]) || !XtIsManaged (group -> members [focused])) focused = (focused + offset) % group -> num_members; /* Save the original appearance. */ XtSetArg (args [0], XtNborderColor, &group -> border_color); XtSetArg (args [1], XtNborderPixmap, &group -> border_pixmap); XtGetValues (group -> members [focused], args, XtNumber (args)); /* Highlight the widget. */ XtSetArg (args [0], XtNborderColor, group -> highlight); XtSetArg (args [1], XtNborderPixmap, XtUnspecifiedPixmap); XtSetValues (group -> members [focused], args, XtNumber (args)); if (group -> clear_caret == True) { XtSetArg (args [0], XtNdisplayCaret, True); XtSetValues (group -> members [focused], args, 1); } XtSetKeyboardFocus (group -> ancestor, group -> members [focused]); group -> focused = focused; } /************************************************************************ * Function: SetFocusProc * * * * Description: Sets the focus to the specified widget by simulating * * an appropriate client message event. * ************************************************************************/ static void SetFocusProc (w, event, params, num_params) Widget w; XEvent *event; String *params; Cardinal *num_params; { XEvent synthetic_event; synthetic_event.type = ClientMessage; synthetic_event.xclient.display = XtDisplay (w); synthetic_event.xclient.window = XtWindow (w); synthetic_event.xclient.format = 8; strcpy (synthetic_event.xclient.data.b, "set"); XtDispatchEvent (&synthetic_event); } /************************************************************************ * Function: CreateTabGroup * * * * Description: Creates a new tab group by adding actions on each * * member of group and initializes the appearance of each * * widget. * ************************************************************************/ void CreateTabGroup (ancestor, members, num_members, highlight, clear_caret) Widget ancestor; WidgetList members; Cardinal num_members; Pixel highlight; BOOLEAN clear_caret; { int depth; char table [256]; Arg args [5]; Pixel border_color; Pixel background; Pixel parent_background; Pixmap border_pixmap; Dimension border_width; Dimension shadow_width; Cardinal i; TabGroup group; XtTranslations translations; static XtAppContext app_context = NULL; static XtActionsRec actions [ ] = {{"ChangeFocus", ChangeFocusProc}, {"SetFocus", SetFocusProc}}; /* Add the actions to the application context if necessary. */ if (app_context == NULL) { app_context = XtWidgetToApplicationContext (ancestor); XtAppAddActions (app_context, actions, XtNumber (actions)); } /* Create and initialize the tab group structure. */ group = XtNew (struct tab_group); group -> members = (WidgetList) XtMalloc (sizeof (Widget) * num_members); group -> num_members = num_members; group -> focused = num_members; group -> ancestor = ancestor; group -> clear_caret = clear_caret; /* Create and parse the translations. */ sprintf (table, TranslationTable, num_groups, num_groups, num_groups); translations = XtParseTranslationTable (table); /* Configure each widget. */ for (i = 0; i < num_members; i ++) { group -> members [i] = members [i]; XtOverrideTranslations (members [i], translations); /* Retrieve information about the widget's appearance. */ shadow_width = 0; border_pixmap = XtUnspecifiedPixmap; XtSetArg (args [0], XtNdepth, &depth); XtSetArg (args [1], XtNbackground, &background); XtSetArg (args [2], XtNborderColor, &border_color); XtSetArg (args [3], XtNborderWidth, &border_width); XtSetArg (args [4], XtNshadowWidth, &shadow_width); XtGetValues (members [i], args, 5); XtSetArg (args [0], XtNbackground, &parent_background); XtGetValues (XtParent (members [i]), args, 1); /* If the widget is monochrome then we don't have a lot of options. We need to make sure the highlight color is visible. If the widget is 3d and doesn't have a border then make its border color the same as its parent's background color as below. Otherwise, give the widget a stippled pixmap as a border so that it can be distinguished from its parent and visible when highlighted. */ if (depth == 1) { highlight = !background; if (shadow_width != 0 && border_width == 0) border_color = parent_background; else border_pixmap = XmuCreateStippledPixmap (XtScreen (members [i]), !background, background, depth); /* The widget is color. If it has no border then make its border color its parent's background color so it "appears" to have no border. */ } else if (border_width == 0) border_color = parent_background; /* Set the final appearance of the widget. */ XtSetArg (args [0], XtNborderWidth, 2); XtSetArg (args [1], XtNborderColor, border_color); XtSetArg (args [2], XtNborderPixmap, border_pixmap); XtSetValues (members [i], args, 3); /* Clear the caret if necessary. */ if (group -> clear_caret == True) { XtSetArg (args [0], XtNdisplayCaret, False); XtSetValues (members [i], args, 1); } } /* Add the group to the list of tab groups. */ group_list [num_groups ++] = group; group -> highlight = highlight; } /************************************************************************ * Function: SetFocus * * * * Description: Sets the keyboard focus to the specified widget by * * calling the SetFocus() action procedure. * ************************************************************************/ void SetFocus (member) Widget member; { XtCallActionProc (member, "SetFocus", NULL, NULL, 0); } /************************************************************************ * Function: GetFocus * * * * Description: Returns which widget has the keyboard focus. * ************************************************************************/ Widget GetFocus (member) Widget member; { XEvent synthetic_event; synthetic_event.type = ClientMessage; synthetic_event.xclient.display = XtDisplay (member); synthetic_event.xclient.window = XtWindow (member); synthetic_event.xclient.format = 8; strcpy (synthetic_event.xclient.data.b, "get"); XtDispatchEvent (&synthetic_event); return focused_widget; } /************************************************************************ * Function: HasFocus * * * * Description: Determines if the specified widget has the keyboard * * focus. * ************************************************************************/ Boolean HasFocus (member) Widget member; { return GetFocus (member) == member ? True : False; }