1 /**************************************************************************** 2 * Copyright (c) 1998,2000 Free Software Foundation, Inc. * 3 * * 4 * Permission is hereby granted, free of charge, to any person obtaining a * 5 * copy of this software and associated documentation files (the * 6 * "Software"), to deal in the Software without restriction, including * 7 * without limitation the rights to use, copy, modify, merge, publish, * 8 * distribute, distribute with modifications, sublicense, and/or sell * 9 * copies of the Software, and to permit persons to whom the Software is * 10 * furnished to do so, subject to the following conditions: * 11 * * 12 * The above copyright notice and this permission notice shall be included * 13 * in all copies or substantial portions of the Software. * 14 * * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * 16 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * 17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * 18 * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * 19 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * 20 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * 21 * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * 22 * * 23 * Except as contained in this notice, the name(s) of the above copyright * 24 * holders shall not be used in advertising or otherwise to promote the * 25 * sale, use or other dealings in this Software without prior written * 26 * authorization. * 27 ****************************************************************************/ 28 29 /**************************************************************************** 30 * Author: Juergen Pfeifer <juergen.pfeifer@gmx.net> 1995,1997 * 31 ****************************************************************************/ 32 33 /*************************************************************************** 34 * Module m_global * 35 * Globally used internal routines and the default menu and item structures * 36 ***************************************************************************/ 37 38 #include "menu.priv.h" 39 40 MODULE_ID("$Id: m_global.c,v 1.13 2002/06/01 16:16:44 tom Exp $") 41 42 static char mark[] = "-"; 43 44 NCURSES_EXPORT_VAR(MENU) _nc_Default_Menu = { 45 16, /* Nr. of chars high */ 46 1, /* Nr. of chars wide */ 47 16, /* Nr. of items high */ 48 1, /* Nr. of items wide */ 49 16, /* Nr. of formatted items high */ 50 1, /* Nr. of formatted items wide */ 51 16, /* Nr. of items high (actual) */ 52 0, /* length of widest name */ 53 0, /* length of widest description */ 54 1, /* length of mark */ 55 1, /* length of one item */ 56 1, /* Spacing for descriptor */ 57 1, /* Spacing for columns */ 58 1, /* Spacing for rows */ 59 (char *)0, /* buffer used to store match chars */ 60 0, /* Index into pattern buffer */ 61 (WINDOW *)0, /* Window containing entire menu */ 62 (WINDOW *)0, /* Portion of menu displayed */ 63 (WINDOW *)0, /* User's window */ 64 (WINDOW *)0, /* User's subwindow */ 65 (ITEM **)0, /* List of items */ 66 0, /* Total Nr. of items in menu */ 67 (ITEM *)0, /* Current item */ 68 0, /* Top row of menu */ 69 (chtype)A_REVERSE, /* Attribute for selection */ 70 (chtype)A_NORMAL, /* Attribute for nonselection */ 71 (chtype)A_UNDERLINE, /* Attribute for inactive */ 72 ' ', /* Pad character */ 73 (Menu_Hook)0, /* Menu init */ 74 (Menu_Hook)0, /* Menu term */ 75 (Menu_Hook)0, /* Item init */ 76 (Menu_Hook)0, /* Item term */ 77 (void *)0, /* userptr */ 78 mark, /* mark */ 79 ALL_MENU_OPTS, /* options */ 80 0 /* status */ 81 }; 82 83 NCURSES_EXPORT_VAR(ITEM) _nc_Default_Item = { 84 { (char *)0, 0 }, /* name */ 85 { (char *)0, 0 }, /* description */ 86 (MENU *)0, /* Pointer to parent menu */ 87 (char *)0, /* Userpointer */ 88 ALL_ITEM_OPTS, /* options */ 89 0, /* Item Nr. */ 90 0, /* y */ 91 0, /* x */ 92 FALSE, /* value */ 93 (ITEM *)0, /* left */ 94 (ITEM *)0, /* right */ 95 (ITEM *)0, /* up */ 96 (ITEM *)0 /* down */ 97 }; 98 99 /*--------------------------------------------------------------------------- 100 | Facility : libnmenu 101 | Function : static void ComputeMaximum_NameDesc_Lenths(MENU *menu) 102 | 103 | Description : Calculates the maximum name and description lengths 104 | of the items connected to the menu 105 | 106 | Return Values : - 107 +--------------------------------------------------------------------------*/ 108 INLINE static void ComputeMaximum_NameDesc_Lengths(MENU * menu) 109 { 110 unsigned MaximumNameLength = 0; 111 unsigned MaximumDescriptionLength = 0; 112 ITEM **items; 113 114 assert(menu && menu->items); 115 for( items = menu->items; *items ; items++ ) 116 { 117 if (items[0]->name.length > MaximumNameLength ) 118 MaximumNameLength = items[0]->name.length; 119 120 if (items[0]->description.length > MaximumDescriptionLength) 121 MaximumDescriptionLength = items[0]->description.length; 122 } 123 124 menu->namelen = MaximumNameLength; 125 menu->desclen = MaximumDescriptionLength; 126 } 127 128 /*--------------------------------------------------------------------------- 129 | Facility : libnmenu 130 | Function : static void ResetConnectionInfo(MENU *, ITEM **) 131 | 132 | Description : Reset all informations in the menu and the items in 133 | the item array that indicates a connection 134 | 135 | Return Values : - 136 +--------------------------------------------------------------------------*/ 137 INLINE static void ResetConnectionInfo(MENU *menu, ITEM **items) 138 { 139 ITEM **item; 140 141 assert(menu && items); 142 for(item=items; *item; item++) 143 { 144 (*item)->index = 0; 145 (*item)->imenu = (MENU *)0; 146 } 147 if (menu->pattern) 148 free(menu->pattern); 149 menu->pattern = (char *)0; 150 menu->pindex = 0; 151 menu->items = (ITEM **)0; 152 menu->nitems = 0; 153 } 154 155 /*--------------------------------------------------------------------------- 156 | Facility : libnmenu 157 | Function : bool _nc_Connect_Items(MENU *menu, ITEM **items) 158 | 159 | Description : Connect the items in the item array to the menu. 160 | Decorate all the items with a number and a backward 161 | pointer to the menu. 162 | 163 | Return Values : TRUE - successfull connection 164 | FALSE - connection failed 165 +--------------------------------------------------------------------------*/ 166 NCURSES_EXPORT(bool) 167 _nc_Connect_Items (MENU *menu, ITEM **items) 168 { 169 ITEM **item; 170 unsigned int ItemCount = 0; 171 172 if ( menu && items ) 173 { 174 for(item=items; *item ; item++) 175 { 176 if ( (*item)->imenu ) 177 { 178 /* if a item is already connected, reject connection */ 179 break; 180 } 181 } 182 if (! (*item) ) 183 /* we reached the end, so there was no connected item */ 184 { 185 for(item=items; *item ; item++) 186 { 187 if (menu->opt & O_ONEVALUE) 188 { 189 (*item)->value = FALSE; 190 } 191 (*item)->index = ItemCount++; 192 (*item)->imenu = menu; 193 } 194 } 195 } 196 else 197 return(FALSE); 198 199 if (ItemCount != 0) 200 { 201 menu->items = items; 202 menu->nitems = ItemCount; 203 ComputeMaximum_NameDesc_Lengths(menu); 204 if ( (menu->pattern = (char *)malloc( (unsigned)(1 + menu->namelen))) ) 205 { 206 Reset_Pattern(menu); 207 set_menu_format(menu,menu->frows,menu->fcols); 208 menu->curitem = *items; 209 menu->toprow = 0; 210 return(TRUE); 211 } 212 } 213 214 /* If we fall through to this point, we have to reset all items connection 215 and inform about a reject connection */ 216 ResetConnectionInfo( menu, items ); 217 return(FALSE); 218 } 219 220 /*--------------------------------------------------------------------------- 221 | Facility : libnmenu 222 | Function : void _nc_Disconnect_Items(MENU *menu) 223 | 224 | Description : Disconnect the menus item array from the menu 225 | 226 | Return Values : - 227 +--------------------------------------------------------------------------*/ 228 NCURSES_EXPORT(void) 229 _nc_Disconnect_Items (MENU * menu) 230 { 231 if (menu && menu->items) 232 ResetConnectionInfo( menu, menu->items ); 233 } 234 235 /*--------------------------------------------------------------------------- 236 | Facility : libnmenu 237 | Function : void _nc_Calculate_Item_Length_and_Width(MENU *menu) 238 | 239 | Description : Calculate the length of an item and the width of the 240 | whole menu. 241 | 242 | Return Values : - 243 +--------------------------------------------------------------------------*/ 244 NCURSES_EXPORT(void) 245 _nc_Calculate_Item_Length_and_Width (MENU * menu) 246 { 247 int l; 248 249 assert(menu); 250 251 menu->height = 1 + menu->spc_rows * (menu->arows - 1); 252 253 l = menu->namelen + menu->marklen; 254 if ( (menu->opt & O_SHOWDESC) && (menu->desclen > 0) ) 255 l += (menu->desclen + menu->spc_desc); 256 257 menu->itemlen = l; 258 l *= menu->cols; 259 l += (menu->cols-1)*menu->spc_cols; /* for the padding between the columns */ 260 menu->width = l; 261 } 262 263 /*--------------------------------------------------------------------------- 264 | Facility : libnmenu 265 | Function : void _nc_Link_Item(MENU *menu) 266 | 267 | Description : Statically calculate for every item its four neighbours. 268 | This depends on the orientation of the menu. This 269 | static aproach simplifies navigation in the menu a lot. 270 | 271 | Return Values : - 272 +--------------------------------------------------------------------------*/ 273 NCURSES_EXPORT(void) 274 _nc_Link_Items (MENU * menu) 275 { 276 if (menu && menu->items && *(menu->items)) 277 { 278 int i,j; 279 ITEM *item; 280 int Number_Of_Items = menu->nitems; 281 int col = 0, row = 0; 282 int Last_in_Row; 283 int Last_in_Column; 284 bool cycle = (menu->opt & O_NONCYCLIC) ? FALSE : TRUE; 285 286 menu->status &= ~_LINK_NEEDED; 287 288 if (menu->opt & O_ROWMAJOR) 289 { 290 int Number_Of_Columns = menu->cols; 291 292 for(i=0; i < Number_Of_Items; i++) 293 { 294 item = menu->items[i]; 295 296 Last_in_Row = row * Number_Of_Columns + (Number_Of_Columns-1); 297 298 item->left = (col) ? 299 /* if we are not in the leftmost column, we can use the 300 predecessor in the items array */ 301 menu->items[i-1] : 302 (cycle ? menu->items[(Last_in_Row>=Number_Of_Items) ? 303 Number_Of_Items-1: 304 Last_in_Row] : 305 (ITEM *)0 ); 306 307 item->right = ( (col < (Number_Of_Columns-1)) && 308 ((i+1) < Number_Of_Items) 309 ) ? 310 menu->items[i+1] : 311 ( cycle ? menu->items[row * Number_Of_Columns] : 312 (ITEM *)0 313 ); 314 315 Last_in_Column = (menu->rows-1) * Number_Of_Columns + col; 316 317 item->up = (row) ? menu->items[i-Number_Of_Columns] : 318 (cycle ? menu->items[(Last_in_Column>=Number_Of_Items) ? 319 Number_Of_Items-1 : 320 Last_in_Column] : 321 (ITEM *)0); 322 323 item->down = ( (i+Number_Of_Columns) < Number_Of_Items ) 324 ? 325 menu->items[i + Number_Of_Columns] : 326 (cycle ? menu->items[(row+1)<menu->rows ? 327 Number_Of_Items-1:col] : 328 (ITEM *)0); 329 item->x = col; 330 item->y = row; 331 if ( ++col == Number_Of_Columns ) 332 { 333 row++; 334 col = 0; 335 } 336 } 337 } 338 else 339 { 340 int Number_Of_Rows = menu->rows; 341 342 for(j=0; j<Number_Of_Items; j++) 343 { 344 item = menu->items[i=(col * Number_Of_Rows + row)]; 345 346 Last_in_Column = (menu->cols-1) * Number_Of_Rows + row; 347 348 item->left = (col) ? 349 menu->items[i - Number_Of_Rows] : 350 (cycle ? (Last_in_Column >= Number_Of_Items ) ? 351 menu->items[Last_in_Column-Number_Of_Rows] : 352 menu->items[Last_in_Column] : 353 (ITEM *)0 ); 354 355 item->right = ((i + Number_Of_Rows) <Number_Of_Items) 356 ? 357 menu->items[i + Number_Of_Rows] : 358 (cycle ? menu->items[row] : (ITEM *)0); 359 360 Last_in_Row = col * Number_Of_Rows + (Number_Of_Rows - 1); 361 362 item->up = (row) ? 363 menu->items[i-1] : 364 (cycle ? 365 menu->items[(Last_in_Row>=Number_Of_Items) ? 366 Number_Of_Items-1: 367 Last_in_Row] : 368 (ITEM *)0); 369 370 item->down = (row < (Number_Of_Rows-1)) 371 ? 372 (menu->items[((i+1)<Number_Of_Items) ? 373 i+1 : 374 (col-1)*Number_Of_Rows + row + 1]) : 375 (cycle ? 376 menu->items[col * Number_Of_Rows] : 377 (ITEM *)0 378 ); 379 380 item->x = col; 381 item->y = row; 382 if ( (++row) == Number_Of_Rows ) 383 { 384 col++; 385 row = 0; 386 } 387 } 388 } 389 } 390 } 391 392 /*--------------------------------------------------------------------------- 393 | Facility : libnmenu 394 | Function : void _nc_Show_Menu(const MENU *menu) 395 | 396 | Description : Update the window that is associated with the menu 397 | 398 | Return Values : - 399 +--------------------------------------------------------------------------*/ 400 NCURSES_EXPORT(void) 401 _nc_Show_Menu (const MENU *menu) 402 { 403 WINDOW *win; 404 int maxy, maxx; 405 406 assert(menu); 407 if ( (menu->status & _POSTED) && !(menu->status & _IN_DRIVER) ) 408 { 409 /* adjust the internal subwindow to start on the current top */ 410 assert(menu->sub); 411 mvderwin(menu->sub,menu->spc_rows * menu->toprow,0); 412 win = Get_Menu_Window(menu); 413 414 maxy = getmaxy(win); 415 maxx = getmaxx(win); 416 417 if (menu->height < maxy) 418 maxy = menu->height; 419 if (menu->width < maxx) 420 maxx = menu->width; 421 422 copywin(menu->sub,win,0,0,0,0,maxy-1,maxx-1,0); 423 pos_menu_cursor(menu); 424 } 425 } 426 427 /*--------------------------------------------------------------------------- 428 | Facility : libnmenu 429 | Function : void _nc_New_TopRow_and_CurrentItem( 430 | MENU *menu, 431 | int new_toprow, 432 | ITEM *new_current_item) 433 | 434 | Description : Redisplay the menu so that the given row becomes the 435 | top row and the given item becomes the new current 436 | item. 437 | 438 | Return Values : - 439 +--------------------------------------------------------------------------*/ 440 NCURSES_EXPORT(void) 441 _nc_New_TopRow_and_CurrentItem 442 (MENU *menu, int new_toprow, ITEM *new_current_item) 443 { 444 ITEM *cur_item; 445 bool mterm_called = FALSE; 446 bool iterm_called = FALSE; 447 448 assert(menu); 449 if (menu->status & _POSTED) 450 { 451 if (new_current_item != menu->curitem) 452 { 453 Call_Hook(menu,itemterm); 454 iterm_called = TRUE; 455 } 456 if (new_toprow != menu->toprow) 457 { 458 Call_Hook(menu,menuterm); 459 mterm_called = TRUE; 460 } 461 462 cur_item = menu->curitem; 463 assert(cur_item); 464 menu->toprow = new_toprow; 465 menu->curitem = new_current_item; 466 467 if (mterm_called) 468 { 469 Call_Hook(menu,menuinit); 470 } 471 if (iterm_called) 472 { 473 /* this means, move from the old current_item to the new one... */ 474 Move_To_Current_Item( menu, cur_item ); 475 Call_Hook(menu,iteminit); 476 } 477 if (mterm_called || iterm_called) 478 { 479 _nc_Show_Menu(menu); 480 } 481 else 482 pos_menu_cursor(menu); 483 } 484 else 485 { /* if we are not posted, this is quite simple */ 486 menu->toprow = new_toprow; 487 menu->curitem = new_current_item; 488 } 489 } 490 491 /* m_global.c ends here */ 492