1 /**************************************************************************** 2 * Copyright (c) 1998 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.11 1999/05/16 17:25:14 juergen Exp $") 41 42 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 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 bool _nc_Connect_Items(MENU *menu, ITEM **items) 165 { 166 ITEM **item; 167 unsigned int ItemCount = 0; 168 169 if ( menu && items ) 170 { 171 for(item=items; *item ; item++) 172 { 173 if ( (*item)->imenu ) 174 { 175 /* if a item is already connected, reject connection */ 176 break; 177 } 178 } 179 if (! (*item) ) 180 /* we reached the end, so there was no connected item */ 181 { 182 for(item=items; *item ; item++) 183 { 184 if (menu->opt & O_ONEVALUE) 185 { 186 (*item)->value = FALSE; 187 } 188 (*item)->index = ItemCount++; 189 (*item)->imenu = menu; 190 } 191 } 192 } 193 else 194 return(FALSE); 195 196 if (ItemCount != 0) 197 { 198 menu->items = items; 199 menu->nitems = ItemCount; 200 ComputeMaximum_NameDesc_Lengths(menu); 201 if ( (menu->pattern = (char *)malloc( (unsigned)(1 + menu->namelen))) ) 202 { 203 Reset_Pattern(menu); 204 set_menu_format(menu,menu->frows,menu->fcols); 205 menu->curitem = *items; 206 menu->toprow = 0; 207 return(TRUE); 208 } 209 } 210 211 /* If we fall through to this point, we have to reset all items connection 212 and inform about a reject connection */ 213 ResetConnectionInfo( menu, items ); 214 return(FALSE); 215 } 216 217 /*--------------------------------------------------------------------------- 218 | Facility : libnmenu 219 | Function : void _nc_Disconnect_Items(MENU *menu) 220 | 221 | Description : Disconnect the menus item array from the menu 222 | 223 | Return Values : - 224 +--------------------------------------------------------------------------*/ 225 void _nc_Disconnect_Items(MENU * menu) 226 { 227 if (menu && menu->items) 228 ResetConnectionInfo( menu, menu->items ); 229 } 230 231 /*--------------------------------------------------------------------------- 232 | Facility : libnmenu 233 | Function : void _nc_Calculate_Item_Length_and_Width(MENU *menu) 234 | 235 | Description : Calculate the length of an item and the width of the 236 | whole menu. 237 | 238 | Return Values : - 239 +--------------------------------------------------------------------------*/ 240 void _nc_Calculate_Item_Length_and_Width(MENU * menu) 241 { 242 int l; 243 244 assert(menu); 245 246 menu->height = 1 + menu->spc_rows * (menu->arows - 1); 247 248 l = menu->namelen + menu->marklen; 249 if ( (menu->opt & O_SHOWDESC) && (menu->desclen > 0) ) 250 l += (menu->desclen + menu->spc_desc); 251 252 menu->itemlen = l; 253 l *= menu->cols; 254 l += (menu->cols-1)*menu->spc_cols; /* for the padding between the columns */ 255 menu->width = l; 256 } 257 258 /*--------------------------------------------------------------------------- 259 | Facility : libnmenu 260 | Function : void _nc_Link_Item(MENU *menu) 261 | 262 | Description : Statically calculate for every item its four neighbours. 263 | This depends on the orientation of the menu. This 264 | static aproach simplifies navigation in the menu a lot. 265 | 266 | Return Values : - 267 +--------------------------------------------------------------------------*/ 268 void _nc_Link_Items(MENU * menu) 269 { 270 if (menu && menu->items && *(menu->items)) 271 { 272 int i,j; 273 ITEM *item; 274 int Number_Of_Items = menu->nitems; 275 int col = 0, row = 0; 276 int Last_in_Row; 277 int Last_in_Column; 278 bool cycle = (menu->opt & O_NONCYCLIC) ? FALSE : TRUE; 279 280 menu->status &= ~_LINK_NEEDED; 281 282 if (menu->opt & O_ROWMAJOR) 283 { 284 int Number_Of_Columns = menu->cols; 285 286 for(i=0; i < Number_Of_Items; i++) 287 { 288 item = menu->items[i]; 289 290 Last_in_Row = row * Number_Of_Columns + (Number_Of_Columns-1); 291 292 item->left = (col) ? 293 /* if we are not in the leftmost column, we can use the 294 predecessor in the items array */ 295 menu->items[i-1] : 296 (cycle ? menu->items[(Last_in_Row>=Number_Of_Items) ? 297 Number_Of_Items-1: 298 Last_in_Row] : 299 (ITEM *)0 ); 300 301 item->right = ( (col < (Number_Of_Columns-1)) && 302 ((i+1) < Number_Of_Items) 303 ) ? 304 menu->items[i+1] : 305 ( cycle ? menu->items[row * Number_Of_Columns] : 306 (ITEM *)0 307 ); 308 309 Last_in_Column = (menu->rows-1) * Number_Of_Columns + col; 310 311 item->up = (row) ? menu->items[i-Number_Of_Columns] : 312 (cycle ? menu->items[(Last_in_Column>=Number_Of_Items) ? 313 Number_Of_Items-1 : 314 Last_in_Column] : 315 (ITEM *)0); 316 317 item->down = ( (i+Number_Of_Columns) < Number_Of_Items ) 318 ? 319 menu->items[i + Number_Of_Columns] : 320 (cycle ? menu->items[(row+1)<menu->rows ? 321 Number_Of_Items-1:col] : 322 (ITEM *)0); 323 item->x = col; 324 item->y = row; 325 if ( ++col == Number_Of_Columns ) 326 { 327 row++; 328 col = 0; 329 } 330 } 331 } 332 else 333 { 334 int Number_Of_Rows = menu->rows; 335 336 for(j=0; j<Number_Of_Items; j++) 337 { 338 item = menu->items[i=(col * Number_Of_Rows + row)]; 339 340 Last_in_Column = (menu->cols-1) * Number_Of_Rows + row; 341 342 item->left = (col) ? 343 menu->items[i - Number_Of_Rows] : 344 (cycle ? (Last_in_Column >= Number_Of_Items ) ? 345 menu->items[Last_in_Column-Number_Of_Rows] : 346 menu->items[Last_in_Column] : 347 (ITEM *)0 ); 348 349 item->right = ((i + Number_Of_Rows) <Number_Of_Items) 350 ? 351 menu->items[i + Number_Of_Rows] : 352 (cycle ? menu->items[row] : (ITEM *)0); 353 354 Last_in_Row = col * Number_Of_Rows + (Number_Of_Rows - 1); 355 356 item->up = (row) ? 357 menu->items[i-1] : 358 (cycle ? 359 menu->items[(Last_in_Row>=Number_Of_Items) ? 360 Number_Of_Items-1: 361 Last_in_Row] : 362 (ITEM *)0); 363 364 item->down = (row < (Number_Of_Rows-1)) 365 ? 366 (menu->items[((i+1)<Number_Of_Items) ? 367 i+1 : 368 (col-1)*Number_Of_Rows + row + 1]) : 369 (cycle ? 370 menu->items[col * Number_Of_Rows] : 371 (ITEM *)0 372 ); 373 374 item->x = col; 375 item->y = row; 376 if ( (++row) == Number_Of_Rows ) 377 { 378 col++; 379 row = 0; 380 } 381 } 382 } 383 } 384 } 385 386 /*--------------------------------------------------------------------------- 387 | Facility : libnmenu 388 | Function : void _nc_Show_Menu(const MENU *menu) 389 | 390 | Description : Update the window that is associated with the menu 391 | 392 | Return Values : - 393 +--------------------------------------------------------------------------*/ 394 void _nc_Show_Menu(const MENU *menu) 395 { 396 WINDOW *win; 397 int maxy, maxx; 398 399 assert(menu); 400 if ( (menu->status & _POSTED) && !(menu->status & _IN_DRIVER) ) 401 { 402 /* adjust the internal subwindow to start on the current top */ 403 assert(menu->sub); 404 mvderwin(menu->sub,menu->spc_rows * menu->toprow,0); 405 win = Get_Menu_Window(menu); 406 407 maxy = getmaxy(win); 408 maxx = getmaxx(win); 409 410 if (menu->height < maxy) 411 maxy = menu->height; 412 if (menu->width < maxx) 413 maxx = menu->width; 414 415 copywin(menu->sub,win,0,0,0,0,maxy-1,maxx-1,0); 416 pos_menu_cursor(menu); 417 } 418 } 419 420 /*--------------------------------------------------------------------------- 421 | Facility : libnmenu 422 | Function : void _nc_New_TopRow_and_CurrentItem( 423 | MENU *menu, 424 | int new_toprow, 425 | ITEM *new_current_item) 426 | 427 | Description : Redisplay the menu so that the given row becomes the 428 | top row and the given item becomes the new current 429 | item. 430 | 431 | Return Values : - 432 +--------------------------------------------------------------------------*/ 433 void _nc_New_TopRow_and_CurrentItem(MENU *menu, int new_toprow, 434 ITEM *new_current_item) 435 { 436 ITEM *cur_item; 437 bool mterm_called = FALSE; 438 bool iterm_called = FALSE; 439 440 assert(menu); 441 if (menu->status & _POSTED) 442 { 443 if (new_current_item != menu->curitem) 444 { 445 Call_Hook(menu,itemterm); 446 iterm_called = TRUE; 447 } 448 if (new_toprow != menu->toprow) 449 { 450 Call_Hook(menu,menuterm); 451 mterm_called = TRUE; 452 } 453 454 cur_item = menu->curitem; 455 assert(cur_item); 456 menu->toprow = new_toprow; 457 menu->curitem = new_current_item; 458 459 if (mterm_called) 460 { 461 Call_Hook(menu,menuinit); 462 } 463 if (iterm_called) 464 { 465 /* this means, move from the old current_item to the new one... */ 466 Move_To_Current_Item( menu, cur_item ); 467 Call_Hook(menu,iteminit); 468 } 469 if (mterm_called || iterm_called) 470 { 471 _nc_Show_Menu(menu); 472 } 473 else 474 pos_menu_cursor(menu); 475 } 476 else 477 { /* if we are not posted, this is quite simple */ 478 menu->toprow = new_toprow; 479 menu->curitem = new_current_item; 480 } 481 } 482 483 /* m_global.c ends here */ 484