X-Git-Url: https://ncurses.scripts.mit.edu/?p=ncurses.git;a=blobdiff_plain;f=menu%2Fm_global.c;h=489987febaa161c3e2de483c06221fbf9af2fd99;hp=09b4572723056a788ccdd8fe5c4ac0ed4bf757dd;hb=c976a90788f3e50afc773670ff74c5270ecb48df;hpb=661078ddbde3ce0f3b06e95642fbb9b5fef7dca1 diff --git a/menu/m_global.c b/menu/m_global.c index 09b45727..489987fe 100644 --- a/menu/m_global.c +++ b/menu/m_global.c @@ -1,5 +1,6 @@ /**************************************************************************** - * Copyright (c) 1998 Free Software Foundation, Inc. * + * Copyright 2020 Thomas E. Dickey * + * Copyright 1998-2012,2014 Free Software Foundation, Inc. * * * * Permission is hereby granted, free of charge, to any person obtaining a * * copy of this software and associated documentation files (the * @@ -27,7 +28,7 @@ ****************************************************************************/ /**************************************************************************** - * Author: Juergen Pfeifer 1995,1997 * + * Author: Juergen Pfeifer, 1995,1997 * ****************************************************************************/ /*************************************************************************** @@ -37,9 +38,11 @@ #include "menu.priv.h" -MODULE_ID("$Id: m_global.c,v 1.9 1998/02/11 12:13:49 tom Exp $") +MODULE_ID("$Id: m_global.c,v 1.30 2020/02/02 23:34:34 tom Exp $") -MENU _nc_Default_Menu = { +static char mark[] = "-"; +/* *INDENT-OFF* */ +NCURSES_EXPORT_VAR(MENU) _nc_Default_Menu = { 16, /* Nr. of chars high */ 1, /* Nr. of chars wide */ 16, /* Nr. of items high */ @@ -51,7 +54,7 @@ MENU _nc_Default_Menu = { 0, /* length of widest description */ 1, /* length of mark */ 1, /* length of one item */ - 1, /* Spacing for descriptor */ + 1, /* Spacing for descriptor */ 1, /* Spacing for columns */ 1, /* Spacing for rows */ (char *)0, /* buffer used to store match chars */ @@ -66,19 +69,19 @@ MENU _nc_Default_Menu = { 0, /* Top row of menu */ (chtype)A_REVERSE, /* Attribute for selection */ (chtype)A_NORMAL, /* Attribute for nonselection */ - (chtype)A_UNDERLINE, /* Attribute for inactive */ + (chtype)A_UNDERLINE, /* Attribute for inactive */ ' ', /* Pad character */ (Menu_Hook)0, /* Menu init */ (Menu_Hook)0, /* Menu term */ (Menu_Hook)0, /* Item init */ (Menu_Hook)0, /* Item term */ (void *)0, /* userptr */ - "-", /* mark */ + mark, /* mark */ ALL_MENU_OPTS, /* options */ - 0 /* status */ + 0 /* status */ }; -ITEM _nc_Default_Item = { +NCURSES_EXPORT_VAR(ITEM) _nc_Default_Item = { { (char *)0, 0 }, /* name */ { (char *)0, 0 }, /* description */ (MENU *)0, /* Pointer to parent menu */ @@ -93,236 +96,345 @@ ITEM _nc_Default_Item = { (ITEM *)0, /* up */ (ITEM *)0 /* down */ }; +/* *INDENT-ON* */ /*--------------------------------------------------------------------------- -| Facility : libnmenu +| Facility : libnmenu | Function : static void ComputeMaximum_NameDesc_Lenths(MENU *menu) -| +| | Description : Calculates the maximum name and description lengths | of the items connected to the menu | | Return Values : - +--------------------------------------------------------------------------*/ -INLINE static void ComputeMaximum_NameDesc_Lengths(MENU * menu) +NCURSES_INLINE static void +ComputeMaximum_NameDesc_Lengths(MENU * menu) { - unsigned MaximumNameLength = 0; + unsigned MaximumNameLength = 0; unsigned MaximumDescriptionLength = 0; ITEM **items; - + unsigned check; + assert(menu && menu->items); - for( items = menu->items; *items ; items++ ) + for (items = menu->items; *items; items++) { - if (items[0]->name.length > MaximumNameLength ) - MaximumNameLength = items[0]->name.length; - - if (items[0]->description.length > MaximumDescriptionLength) - MaximumDescriptionLength = items[0]->description.length; + check = (unsigned)_nc_Calculate_Text_Width(&((*items)->name)); + if (check > MaximumNameLength) + MaximumNameLength = check; + + check = (unsigned)_nc_Calculate_Text_Width(&((*items)->description)); + if (check > MaximumDescriptionLength) + MaximumDescriptionLength = check; } - - menu->namelen = MaximumNameLength; - menu->desclen = MaximumDescriptionLength; + + menu->namelen = (short)MaximumNameLength; + menu->desclen = (short)MaximumDescriptionLength; + T(("ComputeMaximum_NameDesc_Lengths %d,%d", menu->namelen, menu->desclen)); } /*--------------------------------------------------------------------------- -| Facility : libnmenu +| Facility : libnmenu | Function : static void ResetConnectionInfo(MENU *, ITEM **) -| -| Description : Reset all informations in the menu and the items in +| +| Description : Reset all information in the menu and the items in | the item array that indicates a connection | | Return Values : - +--------------------------------------------------------------------------*/ -INLINE static void ResetConnectionInfo(MENU *menu, ITEM **items) +NCURSES_INLINE static void +ResetConnectionInfo(MENU * menu, ITEM ** items) { ITEM **item; - + assert(menu && items); - for(item=items; *item; item++) + for (item = items; *item; item++) { (*item)->index = 0; - (*item)->imenu = (MENU *)0; + (*item)->imenu = (MENU *) 0; } if (menu->pattern) free(menu->pattern); menu->pattern = (char *)0; - menu->pindex = 0; - menu->items = (ITEM **)0; - menu->nitems = 0; + menu->pindex = 0; + menu->items = (ITEM **) 0; + menu->nitems = 0; } /*--------------------------------------------------------------------------- -| Facility : libnmenu +| Facility : libnmenu | Function : bool _nc_Connect_Items(MENU *menu, ITEM **items) | | Description : Connect the items in the item array to the menu. | Decorate all the items with a number and a backward | pointer to the menu. | -| Return Values : TRUE - successfull connection +| Return Values : TRUE - successful connection | FALSE - connection failed +--------------------------------------------------------------------------*/ -bool _nc_Connect_Items(MENU *menu, ITEM **items) +NCURSES_EXPORT(bool) +_nc_Connect_Items(MENU * menu, ITEM ** items) { ITEM **item; unsigned int ItemCount = 0; - - if ( menu && items ) - { - for(item=items; *item ; item++) + + if (menu && items) + { + for (item = items; *item; item++) { - if ( (*item)->imenu ) + if ((*item)->imenu) { /* if a item is already connected, reject connection */ break; } } - if (! (*item) ) + if (!(*item)) /* we reached the end, so there was no connected item */ { - for(item=items; *item ; item++) + for (item = items; *item; item++) { if (menu->opt & O_ONEVALUE) { (*item)->value = FALSE; } - (*item)->index = ItemCount++; + (*item)->index = (short)ItemCount++; (*item)->imenu = menu; - } + } } } else - return(FALSE); - + return (FALSE); + if (ItemCount != 0) { - menu->items = items; - menu->nitems = ItemCount; + menu->items = items; + menu->nitems = (short)ItemCount; ComputeMaximum_NameDesc_Lengths(menu); - if ( (menu->pattern = (char *)malloc( (unsigned)(1 + menu->namelen))) ) + if ((menu->pattern = typeMalloc(char, (unsigned)(1 + menu->namelen)))) { - Reset_Pattern(menu); - set_menu_format(menu,menu->frows,menu->fcols); + Reset_Pattern(menu); + set_menu_format(menu, menu->frows, menu->fcols); menu->curitem = *items; menu->toprow = 0; - return(TRUE); + return (TRUE); } } - - /* If we fall through to this point, we have to reset all items connection + + /* If we fall through to this point, we have to reset all items connection and inform about a reject connection */ - ResetConnectionInfo( menu, items ); - return(FALSE); + ResetConnectionInfo(menu, items); + return (FALSE); } /*--------------------------------------------------------------------------- -| Facility : libnmenu +| Facility : libnmenu | Function : void _nc_Disconnect_Items(MENU *menu) -| +| | Description : Disconnect the menus item array from the menu | | Return Values : - +--------------------------------------------------------------------------*/ -void _nc_Disconnect_Items(MENU * menu) +NCURSES_EXPORT(void) +_nc_Disconnect_Items(MENU * menu) { if (menu && menu->items) - ResetConnectionInfo( menu, menu->items ); + ResetConnectionInfo(menu, menu->items); } /*--------------------------------------------------------------------------- -| Facility : libnmenu +| Facility : libnmenu +| Function : int _nc_Calculate_Text_Width(const TEXT * item) +| +| Description : Calculate the number of columns for a TEXT. +| +| Return Values : the width ++--------------------------------------------------------------------------*/ +NCURSES_EXPORT(int) +_nc_Calculate_Text_Width(const TEXT * item /*FIXME: limit length */ ) +{ +#if USE_WIDEC_SUPPORT + int result = item->length; + + T((T_CALLED("_nc_menu_text_width(%p)"), (const void *)item)); + if (result != 0 && item->str != 0) + { + int count = (int)mbstowcs(0, item->str, 0); + wchar_t *temp = 0; + + if (count > 0 + && (temp = typeMalloc(wchar_t, 2 + count)) != 0) + { + int n; + + result = 0; + mbstowcs(temp, item->str, (unsigned)count); + for (n = 0; n < count; ++n) + { + int test = wcwidth(temp[n]); + + if (test <= 0) + test = 1; + result += test; + } + free(temp); + } + } + returnCode(result); +#else + return item->length; +#endif +} + +/* + * Calculate the actual width of a menu entry for wide-characters. + */ +#if USE_WIDEC_SUPPORT +static int +calculate_actual_width(MENU * menu, bool name) +{ + int width = 0; + int check = 0; + ITEM **items; + + assert(menu && menu->items); + + if (menu->items != 0) + { + for (items = menu->items; *items; items++) + { + if (name) + { + check = _nc_Calculate_Text_Width(&((*items)->name)); + } + else + { + check = _nc_Calculate_Text_Width(&((*items)->description)); + } + if (check > width) + width = check; + } + } + else + { + width = (name ? menu->namelen : menu->desclen); + } + + T(("calculate_actual_width %s = %d/%d", + name ? "name" : "desc", + width, + name ? menu->namelen : menu->desclen)); + return width; +} +#else +#define calculate_actual_width(menu, name) (name ? menu->namelen : menu->desclen) +#endif + +/*--------------------------------------------------------------------------- +| Facility : libnmenu | Function : void _nc_Calculate_Item_Length_and_Width(MENU *menu) -| +| | Description : Calculate the length of an item and the width of the | whole menu. | | Return Values : - +--------------------------------------------------------------------------*/ -void _nc_Calculate_Item_Length_and_Width(MENU * menu) +NCURSES_EXPORT(void) +_nc_Calculate_Item_Length_and_Width(MENU * menu) { int l; - + assert(menu); - menu->height = 1 + menu->spc_rows * (menu->arows - 1); + menu->height = (short)(1 + menu->spc_rows * (menu->arows - 1)); - l = menu->namelen + menu->marklen; - if ( (menu->opt & O_SHOWDESC) && (menu->desclen > 0) ) - l += (menu->desclen + menu->spc_desc); - - menu->itemlen = l; + l = calculate_actual_width(menu, TRUE); + l += menu->marklen; + + if ((menu->opt & O_SHOWDESC) && (menu->desclen > 0)) + { + l += calculate_actual_width(menu, FALSE); + l += menu->spc_desc; + } + + menu->itemlen = (short)l; l *= menu->cols; - l += (menu->cols-1)*menu->spc_cols; /* for the padding between the columns */ - menu->width = l; -} + l += (menu->cols - 1) * menu->spc_cols; /* for the padding between the columns */ + menu->width = (short)l; + + T(("_nc_CalculateItem_Length_and_Width columns %d, item %d, width %d", + menu->cols, + menu->itemlen, + menu->width)); +} /*--------------------------------------------------------------------------- -| Facility : libnmenu +| Facility : libnmenu | Function : void _nc_Link_Item(MENU *menu) -| -| Description : Statically calculate for every item its four neighbours. +| +| Description : Statically calculate for every item its four neighbors. | This depends on the orientation of the menu. This -| static aproach simplifies navigation in the menu a lot. +| static approach simplifies navigation in the menu a lot. | | Return Values : - +--------------------------------------------------------------------------*/ -void _nc_Link_Items(MENU * menu) +NCURSES_EXPORT(void) +_nc_Link_Items(MENU * menu) { if (menu && menu->items && *(menu->items)) { - int i,j; + int i, j; ITEM *item; int Number_Of_Items = menu->nitems; int col = 0, row = 0; int Last_in_Row; int Last_in_Column; bool cycle = (menu->opt & O_NONCYCLIC) ? FALSE : TRUE; - - menu->status &= ~_LINK_NEEDED; - + + ClrStatus(menu, _LINK_NEEDED); + if (menu->opt & O_ROWMAJOR) { int Number_Of_Columns = menu->cols; - - for(i=0; i < Number_Of_Items; i++) + + for (i = 0; i < Number_Of_Items; i++) { item = menu->items[i]; - - Last_in_Row = row * Number_Of_Columns + (Number_Of_Columns-1); - - item->left = (col) ? - /* if we are not in the leftmost column, we can use the - predecessor in the items array */ - menu->items[i-1] : - (cycle ? menu->items[(Last_in_Row>=Number_Of_Items) ? - Number_Of_Items-1: - Last_in_Row] : - (ITEM *)0 ); - - item->right = ( (col < (Number_Of_Columns-1)) && - ((i+1) < Number_Of_Items) - ) ? - menu->items[i+1] : - ( cycle ? menu->items[row * Number_Of_Columns] : - (ITEM *)0 - ); - - Last_in_Column = (menu->rows-1) * Number_Of_Columns + col; - - item->up = (row) ? menu->items[i-Number_Of_Columns] : - (cycle ? menu->items[(Last_in_Column>=Number_Of_Items) ? - Number_Of_Items-1 : - Last_in_Column] : - (ITEM *)0); - - item->down = ( (i+Number_Of_Columns) < Number_Of_Items ) - ? - menu->items[i + Number_Of_Columns] : - (cycle ? menu->items[(row+1)rows ? - Number_Of_Items-1:col] : - (ITEM *)0); - item->x = col; - item->y = row; - if ( ++col == Number_Of_Columns ) + + Last_in_Row = row * Number_Of_Columns + (Number_Of_Columns - 1); + + item->left = (col) ? + /* if we are not in the leftmost column, we can use the + predecessor in the items array */ + menu->items[i - 1] : + (cycle ? menu->items[(Last_in_Row >= Number_Of_Items) ? + Number_Of_Items - 1 : + Last_in_Row] : + (ITEM *) 0); + + item->right = ((col < (Number_Of_Columns - 1)) && + ((i + 1) < Number_Of_Items) + )? + menu->items[i + 1] : + (cycle ? menu->items[row * Number_Of_Columns] : + (ITEM *) 0 + ); + + Last_in_Column = (menu->rows - 1) * Number_Of_Columns + col; + + item->up = (row) ? menu->items[i - Number_Of_Columns] : + (cycle ? menu->items[(Last_in_Column >= Number_Of_Items) ? + Number_Of_Items - 1 : + Last_in_Column] : + (ITEM *) 0); + + item->down = ((i + Number_Of_Columns) < Number_Of_Items) + ? + menu->items[i + Number_Of_Columns] : + (cycle ? menu->items[(row + 1) < menu->rows ? + Number_Of_Items - 1 : col] : + (ITEM *) 0); + item->x = (short)col; + item->y = (short)row; + if (++col == Number_Of_Columns) { row++; col = 0; @@ -332,48 +444,48 @@ void _nc_Link_Items(MENU * menu) else { int Number_Of_Rows = menu->rows; - - for(j=0; jitems[i=(col * Number_Of_Rows + row)]; - - Last_in_Column = (menu->cols-1) * Number_Of_Rows + row; - - item->left = (col) ? + item = menu->items[i = (col * Number_Of_Rows + row)]; + + Last_in_Column = (menu->cols - 1) * Number_Of_Rows + row; + + item->left = (col) ? menu->items[i - Number_Of_Rows] : - (cycle ? (Last_in_Column >= Number_Of_Items ) ? - menu->items[Last_in_Column-Number_Of_Rows] : - menu->items[Last_in_Column] : - (ITEM *)0 ); - - item->right = ((i + Number_Of_Rows) items[i + Number_Of_Rows] : - (cycle ? menu->items[row] : (ITEM *)0); - + (cycle ? (Last_in_Column >= Number_Of_Items) ? + menu->items[Last_in_Column - Number_Of_Rows] : + menu->items[Last_in_Column] : + (ITEM *) 0); + + item->right = ((i + Number_Of_Rows) < Number_Of_Items) + ? + menu->items[i + Number_Of_Rows] : + (cycle ? menu->items[row] : (ITEM *) 0); + Last_in_Row = col * Number_Of_Rows + (Number_Of_Rows - 1); - - item->up = (row) ? - menu->items[i-1] : - (cycle ? - menu->items[(Last_in_Row>=Number_Of_Items) ? - Number_Of_Items-1: - Last_in_Row] : - (ITEM *)0); - - item->down = (row < (Number_Of_Rows-1)) - ? - (menu->items[((i+1)items[col * Number_Of_Rows] : - (ITEM *)0 - ); - - item->x = col; - item->y = row; - if ( (++row) == Number_Of_Rows ) + + item->up = (row) ? + menu->items[i - 1] : + (cycle ? + menu->items[(Last_in_Row >= Number_Of_Items) ? + Number_Of_Items - 1 : + Last_in_Row] : + (ITEM *) 0); + + item->down = (row < (Number_Of_Rows - 1)) + ? + (menu->items[((i + 1) < Number_Of_Items) ? + i + 1 : + (col - 1) * Number_Of_Rows + row + 1]) : + (cycle ? + menu->items[col * Number_Of_Rows] : + (ITEM *) 0 + ); + + item->x = (short)col; + item->y = (short)row; + if ((++row) == Number_Of_Rows) { col++; row = 0; @@ -384,87 +496,93 @@ void _nc_Link_Items(MENU * menu) } /*--------------------------------------------------------------------------- -| Facility : libnmenu -| Function : void _nc_Show_Menu(const MENU *menu) -| +| Facility : libnmenu +| Function : void _nc_Show_Menu(const MENU* menu) +| | Description : Update the window that is associated with the menu | | Return Values : - +--------------------------------------------------------------------------*/ -void _nc_Show_Menu(const MENU *menu) +NCURSES_EXPORT(void) +_nc_Show_Menu(const MENU * menu) { WINDOW *win; int maxy, maxx; - + assert(menu); - if ( (menu->status & _POSTED) && !(menu->status & _IN_DRIVER) ) + if ((menu->status & _POSTED) && !(menu->status & _IN_DRIVER)) { /* adjust the internal subwindow to start on the current top */ assert(menu->sub); - mvderwin(menu->sub,menu->spc_rows * menu->toprow,0); + mvderwin(menu->sub, menu->spc_rows * menu->toprow, 0); win = Get_Menu_Window(menu); - + maxy = getmaxy(win); - maxx = getmaxx(win); - - if (menu->height < maxy) + maxx = getmaxx(win); + + if (menu->height < maxy) maxy = menu->height; - if (menu->width < maxx) + if (menu->width < maxx) maxx = menu->width; - - copywin(menu->sub,win,0,0,0,0,maxy-1,maxx-1,0); + + copywin(menu->sub, win, 0, 0, 0, 0, maxy - 1, maxx - 1, 0); pos_menu_cursor(menu); - } -} + } +} /*--------------------------------------------------------------------------- -| Facility : libnmenu +| Facility : libnmenu | Function : void _nc_New_TopRow_and_CurrentItem( -| MENU *menu, -| int new_toprow, +| MENU *menu, +| int new_toprow, | ITEM *new_current_item) -| +| | Description : Redisplay the menu so that the given row becomes the | top row and the given item becomes the new current | item. | | Return Values : - +--------------------------------------------------------------------------*/ -void _nc_New_TopRow_and_CurrentItem(MENU *menu, int new_toprow, - ITEM *new_current_item) +NCURSES_EXPORT(void) +_nc_New_TopRow_and_CurrentItem( + MENU * menu, + int new_toprow, + ITEM * new_current_item) { ITEM *cur_item; bool mterm_called = FALSE; bool iterm_called = FALSE; - + assert(menu); if (menu->status & _POSTED) { if (new_current_item != menu->curitem) { - Call_Hook(menu,itemterm); + Call_Hook(menu, itemterm); iterm_called = TRUE; } if (new_toprow != menu->toprow) { - Call_Hook(menu,menuterm); + Call_Hook(menu, menuterm); mterm_called = TRUE; - } - - cur_item = menu->curitem; + } + + cur_item = menu->curitem; assert(cur_item); - menu->toprow = new_toprow; - menu->curitem = new_current_item; - + menu->toprow = (short)(((menu->rows - menu->frows) >= 0) + ? min(menu->rows - menu->frows, new_toprow) + : 0); + menu->curitem = new_current_item; + if (mterm_called) { - Call_Hook(menu,menuinit); + Call_Hook(menu, menuinit); } if (iterm_called) { /* this means, move from the old current_item to the new one... */ - Move_To_Current_Item( menu, cur_item ); - Call_Hook(menu,iteminit); + Move_To_Current_Item(menu, cur_item); + Call_Hook(menu, iteminit); } if (mterm_called || iterm_called) { @@ -474,8 +592,10 @@ void _nc_New_TopRow_and_CurrentItem(MENU *menu, int new_toprow, pos_menu_cursor(menu); } else - { /* if we are not posted, this is quite simple */ - menu->toprow = new_toprow; + { /* if we are not posted, this is quite simple */ + menu->toprow = (short)(((menu->rows - menu->frows) >= 0) + ? min(menu->rows - menu->frows, new_toprow) + : 0); menu->curitem = new_current_item; } }