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