listedit.c (48640B)
1 /* listedit.c 2 * (c) 2002 Petr 'Brain' Kulhavy 3 * This file is a part of the Links program, released under GPL. 4 */ 5 6 #include "links.h" 7 8 /* 9 (#####) 10 (#########) 11 )))) (######) 12 ,C--O (###) _________________ 13 |`:, \ ~~ |. , v , .| 14 `-__o ~~ ; | ZAKAZ KOURENI | 15 / _ \ ` |. .| 16 | ( \__`_=k== `~~~~~~~~~~~~~~~~~' 17 | `-/__---' 18 |=====C/ 19 `. ),' 20 \ / 21 ||_| 22 || |__ 23 ||____) 24 25 v v v , ,v 26 KONECNE NEJAKE KOMENTARE... 27 */ 28 29 /* Klikani myssi (nebo mysijou, jak rika Mikulas) v list-okne: 30 * (hrozne dulezity komentar ;-P ) 31 * 32 * Klikani je vyreseno nasledovne, pokud ma nekdo lepsi napad, nebo nejake 33 * vyhrady, tak at mi je posle. 34 * 35 * Prostredni tlacitko+pohyb je scroll nahoru/dolu. Levym tlacitkem se nastavi 36 * kurzor (cerna lista) na konkretni polozku. Kdyz se levym klikne na adresar 37 * (na ty graficke nesmysly, ne na ten text), tak se adresar toggle 38 * otevre/zavre. Prave tlacitko oznaci/odznaci polozku/adresar. 39 */ 40 41 /* Premistovani polozek: 42 * 43 * Pravym tlacitkem se oznaci/odznaci polozka. Cudlikem "Odznacit vse" se 44 * vsechny polozky odznaci. Cudlik "Prestehovat" presune vsechny oznacene 45 * polozky za aktualni pozici, v tom poradi, jak jsou v seznamu. Pri zavreni 46 * adresare se vsechny polozky v adresari odznaci. 47 */ 48 49 /* Prekreslovani grafickych nesmyslu v okenku je samozrejme bez jedineho 50 * v 51 * bliknuti. Ne jako nejmenovane browsery... Proste obraz jako BIC (TM) 52 */ 53 54 /* Ovladani klavesnici: 55 * sipky, page up, page down, home end pohyb 56 * + otevri adresar 57 * - zavri adresar 58 * mezera toggle adresar 59 * ins, *, 8, i toggle oznacit 60 * ?, /, N, n hledani nahoru, dolu, 61 * znova, znova na druhou stranu 62 */ 63 64 /* 65 * Struktura struct list_decription obsahuje popis seznamu. Tenhle file 66 * obsahuje obecne funkce k obsluze seznamu. Pomoci struct list_description se 67 * seznam customizuje. Obecne funkce volaji funkce z list_description. 68 * 69 * Jedina funkce z tohoto filu, ktera se vola zvenku, je create_list_window. Ta 70 * vyrobi a obstarava okno pro obsluhu seznamu. 71 * 72 * Obecny list neresi veci jako nahravani seznamu z filu, ukladani na disk 73 * atd.(tyhle funkce si uzivatel musi napsat sam). Resi vlastne jenom to velke 74 * okno na manipulaci se seznamem. 75 */ 76 77 /* 78 * Aby bylo konzistentni pridavani a editovani polozek, tak se musi pytlacit. 79 * 80 * To znamena, ze pri pridavani polozky do listu se vyrobi nova polozka 81 * (NEPRIDA se do seznamu), pusti se edit a po zmacknuti OK se polozka prida do 82 * seznamu. Pri zmacknuti cancel, se polozka smaze. 83 * 84 * Pri editovani polozky se vyrobi nova polozka, zkopiruje se do ni obsah te 85 * puvodni (od toho tam je funkce copy_item), pak se zavola edit a podobne jako 86 * v predchozim pripade: pri cancel se polozka smaze, pri OK se zkopiruje do 87 * puvodni polozky a smaze se taky. 88 * 89 * O smazani polozky pri cancelu se bude starat uzivatelska funkce edit_item 90 * sama. Funkce edit_item po zmacknuti OK zavola funkci, kterou dostane. Jako 91 * 1. argument ji da data, ktera dostane, jako 2. argument ji preda pointer na 92 * item. 93 */ 94 95 /* 96 * Seznam je definovan ve struct list. Muze byt bud placaty nebo stromovy. 97 * 98 * K placatemu asi neni co dodat. U placateho se ignoruje hloubka a neexistuji 99 * adresare - vsechny polozky jsou si rovny (typ polozky se ignoruje). 100 * 101 * Stromovy seznam: 102 * Kazdy clen seznamu ma flag sbaleno/rozbaleno. U itemy se to ignoruje, u 103 * adresare to znamena, zda se zobrazuje obsah nebo ne. Aby rozbaleno/sbaleno 104 * bylo u vsech prvku adresare, to by neslo: kdybych mel adresar a v nem dalsi 105 * adresar, tak bych u toho vnoreneho adresare nevedel, jestli to 106 * sbaleno/rozbaleno je od toho vnoreneho adresare, nebo od toho nad nim. 107 * 108 * Clenove seznamu maji hloubku - cislo od 0 vyse. Cim je prvek hloubeji ve 109 * strukture, tim je hloubka vyssi. Obsah adresare s hloubkou x je souvisly blok 110 * nasledujicich prvku s hloubkou >x. 111 * 112 * Hlava ma hloubku -1 a zobrazuje se taky jako clen seznamu (aby se dal 113 * zobrazit prazdny seznam a dalo se do nej pridavat), takze se da vlastne cely 114 * seznam zabalit/rozbalit. Hlava sice nema data, ale funkce type_item ji musi 115 * umet zobrazit. Jako popis bude psat fixni text, napriklad "Bookmarks". 116 * 117 * Pro urychleni vykreslovani kazdy prvek v seznamu s adresarema obsahuje 118 * pointer na otce (polozka fotr). U plocheho seznamu se tento pointer 119 * ignoruje. 120 * 121 * Strukturu stromu bude vykreslovat obecna funkce (v tomto filu), protoze v 122 * obecnem listu je struktura uz zachycena. 123 */ 124 125 /* 126 * V hlavnim okne se da nadefinovat 1 uzivatelske tlacitko. Polozka button ve 127 * struct list_description obsahuje popisku tlacitka (kod stringu v 128 * prekodovavacich tabulkach). Funkce button_fn je zavolana pri stisku 129 * tlacitka, jako argument (void *) dostane aktualni polozku. Pokud je 130 * button_fn NULL, tlacitko se nekona. 131 * 132 * Toto tlacitko se da vyuzit napriklad u bookmarku, kde je potreba [ Goto ]. 133 * 134 * Kdyz bude potreba predavat obsluzne funkci tlacitka nejake dalsi argumenty, 135 * tak se pripadne definice obsluzne funkce prepise. 136 * 137 * Tlacitko funguje jen na polozky. Nefunguje na adresare (pokud se jedna o 138 * stromovy list) ani na hlavu. 139 */ 140 141 /* Jak funguje default_value: 142 * kdyz se zmackne tlacitko add, zavola se funkce default_value, ktera si 143 * naalokuje nejaky data pro new_item. Do funkce default_value se treba u 144 * bookmarku umisti okopirovani altualniho nazvu a url stranky. Pak se zavola 145 * new_item, ktera si prislusne hodnoty dekoduje a pomoci nich vyplni novou 146 * polozku. Funkce new_item pak MUSI data dealokovat. Pokud funkce new_item 147 * dostane misto pointeru s daty NULL, vyrobi prazdnou polozku. 148 * 149 * Default value musi vratit hodnoty v kodovani uvedenem v list_description 150 */ 151 152 /* Pristupovani z vice linksu: 153 * 154 * ... se neresi - je zakazano. K tomu slouzi polozka open ve struct 155 * list_description, ktera rika, jestli je okno uz otevrene, nebo ne. 156 */ 157 158 /* Prekodovavani znakovych sad: 159 * 160 * type_item vraci text prekodovany do kodovani terminalu, ktery dostane. 161 */ 162 163 /* struct list *current_pos; current cursor position in the list */ 164 /* struct list *win_offset; item at the top of the window */ 165 /* int win_pos; current y position in the window */ 166 167 #define BOHNICE "+420-2-84016111" 168 169 #define BFU_ELEMENT_EMPTY 0 170 #define BFU_ELEMENT_PIPE 1 171 #define BFU_ELEMENT_L 2 172 #define BFU_ELEMENT_TEE 3 173 #define BFU_ELEMENT_CLOSED 4 174 #define BFU_ELEMENT_CLOSED_DOWN 5 175 #define BFU_ELEMENT_OPEN 6 176 #define BFU_ELEMENT_OPEN_DOWN 7 177 178 /* for mouse scrolling */ 179 static long last_mouse_y; 180 181 static void list_edit_toggle(struct dialog_data *dlg, 182 struct list_description *ld); 183 184 #define sirka_scrollovadla 0 185 186 /* This function uses these defines from setup.h: 187 * 188 * BFU_ELEMENT_WIDTH 189 */ 190 191 /* draws one of BFU elements: | |- [-] [+] */ 192 /* BFU elements are used in the list window */ 193 /* this function also defines shape and size of the elements */ 194 /* returns width of the BFU element (all elements have the same size, but sizes 195 * differ if we're in text mode or in graphics mode) */ 196 static int 197 draw_bfu_element(struct terminal *term, int x, int y, unsigned char c, long b, 198 long f, unsigned char type, unsigned char selected) 199 { 200 unsigned char vertical = 179; 201 unsigned char horizontal = 196; 202 unsigned char tee = 195; 203 unsigned char l = 192; 204 205 switch (type) { 206 case BFU_ELEMENT_EMPTY: 207 c |= ATTR_FRAME; 208 set_char(term, x, y, ' ', c); 209 set_char(term, x + 1, y, ' ', c); 210 set_char(term, x + 2, y, ' ', c); 211 set_char(term, x + 3, y, ' ', c); 212 set_char(term, x + 4, y, ' ', c); 213 break; 214 215 case BFU_ELEMENT_PIPE: 216 c |= ATTR_FRAME; 217 set_char(term, x, y, ' ', c); 218 set_char(term, x + 1, y, vertical, c); 219 set_char(term, x + 2, y, ' ', c); 220 set_char(term, x + 3, y, ' ', c); 221 set_char(term, x + 4, y, ' ', c); 222 break; 223 224 case BFU_ELEMENT_L: 225 c |= ATTR_FRAME; 226 set_char(term, x, y, ' ', c); 227 set_char(term, x + 1, y, l, c); 228 set_char(term, x + 2, y, horizontal, c); 229 set_char(term, x + 3, y, horizontal, c); 230 set_char(term, x + 4, y, ' ', c); 231 break; 232 233 case BFU_ELEMENT_TEE: 234 c |= ATTR_FRAME; 235 set_char(term, x, y, ' ', c); 236 set_char(term, x + 1, y, tee, c); 237 set_char(term, x + 2, y, horizontal, c); 238 set_char(term, x + 3, y, horizontal, c); 239 set_char(term, x + 4, y, ' ', c); 240 break; 241 242 case BFU_ELEMENT_CLOSED: 243 case BFU_ELEMENT_CLOSED_DOWN: 244 set_char(term, x, y, '[', c); 245 set_char(term, x + 1, y, '+', c); 246 set_char(term, x + 2, y, ']', c); 247 c |= ATTR_FRAME; 248 set_char(term, x + 3, y, horizontal, c); 249 set_char(term, x + 4, y, ' ', c); 250 break; 251 252 case BFU_ELEMENT_OPEN: 253 case BFU_ELEMENT_OPEN_DOWN: 254 set_char(term, x, y, '[', c); 255 set_char(term, x + 1, y, '-', c); 256 set_char(term, x + 2, y, ']', c); 257 c |= ATTR_FRAME; 258 set_char(term, x + 3, y, horizontal, c); 259 set_char(term, x + 4, y, ' ', c); 260 break; 261 262 default: 263 internal("draw_bfu_element: unknown BFU element type %d.\n", 264 type); 265 } 266 if (selected) 267 set_char(term, x + 4, y, '*', c); 268 return BFU_ELEMENT_WIDTH; /* BFU element size in text mode */ 269 } 270 271 /* aux structure for parameter exchange for redrawing list window */ 272 struct redraw_data { 273 struct list_description *ld; 274 struct dialog_data *dlg; 275 int n; 276 }; 277 278 static void redraw_list(struct terminal *term, void *bla); 279 280 /* returns next visible item in tree list */ 281 /* works only with visible items (head or any item returned by this function) */ 282 /* when list is flat returns next item */ 283 static struct list * 284 next_in_tree(struct list_description *ld, struct list *item) 285 { 286 int depth = item->depth; 287 288 /* flat list */ 289 if (!ld->type) 290 return list_next(item); 291 292 if (!(item->type & 1) || (item->type & 2)) /* item or opened folder */ 293 return list_next(item); 294 /* skip content of this folder */ 295 do 296 item = list_next(item); 297 while (item->depth 298 > depth); /* must stop on head 'cause it's depth is -1 */ 299 return item; 300 } 301 302 /* returns previous visible item in tree list */ 303 /* works only with visible items (head or any item returned by this function) */ 304 /* when list is flat returns previous item */ 305 static struct list * 306 prev_in_tree(struct list_description *ld, struct list *item) 307 { 308 struct list *last_closed; 309 int depth = item->depth; 310 311 /* flat list */ 312 if (!ld->type) 313 return list_prev(item); 314 315 if (item == ld->list) 316 depth = 0; 317 318 /* items with same or lower depth must be visible, because current item 319 * is visible */ 320 if (list_prev(item)->depth <= item->depth) 321 return list_prev(item); 322 323 /* find item followed with opened fotr's only */ 324 /* searched item is last closed folder (going up from item) or 325 * item->prev */ 326 last_closed = list_prev(item); 327 item = list_prev(item); 328 while (1) { 329 if ((item->type & 3) == 1) /* closed folder */ 330 last_closed = item; 331 if (item->depth <= depth) 332 break; 333 item = item->fotr; 334 } 335 return last_closed; 336 } 337 338 static int 339 get_win_pos(struct list_description *ld) 340 { 341 struct list *l; 342 int count = 0; 343 344 for (l = ld->win_offset; l != ld->current_pos; l = next_in_tree(ld, l)) 345 count++; 346 347 return count; 348 } 349 350 static void 351 unselect_in_folder(struct list_description *ld, struct list *l) 352 { 353 int depth; 354 355 depth = l->depth; 356 for (l = list_next(l); l != ld->list && l->depth > depth; 357 l = list_next(l)) 358 l->type &= ~4; 359 } 360 361 /* aux function for list_item_add */ 362 static void 363 list_insert_behind_item(struct dialog_data *dlg, struct list *pos, 364 struct list *item, struct list_description *ld) 365 { 366 struct list *a; 367 struct redraw_data rd; 368 369 /* BEFORE: ... <----> pos <--(possible invisible items)--> a <----> 370 * ... */ 371 /* AFTER: ... <----> pos <--(possible invisible items)--> item <----> 372 * a <----> ... */ 373 374 a = next_in_tree(ld, pos); 375 add_before_pos(a, item); 376 377 /* if list is flat a->fotr will contain nosenses, but it won't crash ;-) 378 */ 379 if ((pos->type & 3) == 3 || pos->depth == -1) { 380 item->fotr = pos; 381 item->depth = pos->depth + 1; 382 } /* open directory or head */ 383 else { 384 item->fotr = pos->fotr; 385 item->depth = pos->depth; 386 } 387 388 ld->current_pos = 389 next_in_tree(ld, ld->current_pos); /* ld->current_pos->next==item */ 390 ld->win_pos++; 391 if (ld->win_pos > ld->n_items - 1) { /* scroll down */ 392 ld->win_pos = ld->n_items - 1; 393 ld->win_offset = next_in_tree(ld, ld->win_offset); 394 } 395 396 ld->modified = 1; 397 398 rd.ld = ld; 399 rd.dlg = dlg; 400 rd.n = 0; 401 402 draw_to_window(dlg->win, redraw_list, &rd); 403 } 404 405 /* aux function for list_item_edit */ 406 /* copies data of src to dest and calls free on the src */ 407 /* first argument is argument passed to user function */ 408 static void 409 list_copy_item(struct dialog_data *dlg, struct list *dest, struct list *src, 410 struct list_description *ld) 411 { 412 struct redraw_data rd; 413 414 ld->copy_item(src, dest); 415 ld->delete_item(src); 416 417 ld->modified = 1; /* called after an successful edit */ 418 rd.ld = ld; 419 rd.dlg = dlg; 420 rd.n = 0; 421 422 draw_to_window(dlg->win, redraw_list, &rd); 423 } 424 425 /* creates new item (calling new_item function) and calls edit_item function */ 426 static int 427 list_item_add(struct dialog_data *dlg, struct dialog_item_data *useless) 428 { 429 struct list_description *ld = 430 (struct list_description *)dlg->dlg->udata2; 431 struct list *item = ld->current_pos; 432 struct list *new_item; 433 434 if (!(new_item = ld->new_item(ld->default_value ? ld->default_value( 435 (struct session *)dlg->dlg->udata, 0) 436 : NULL))) 437 return 1; 438 new_item->list_entry.prev = NULL; 439 new_item->list_entry.next = NULL; 440 new_item->type = 0; 441 new_item->depth = 0; 442 443 ld->edit_item(dlg, new_item, list_insert_behind_item, item, TITLE_ADD); 444 return 0; 445 } 446 447 /* like list_item_add but creates folder */ 448 static int 449 list_folder_add(struct dialog_data *dlg, struct dialog_item_data *useless) 450 { 451 struct list_description *ld = 452 (struct list_description *)dlg->dlg->udata2; 453 struct list *item = ld->current_pos; 454 struct list *new_item; 455 456 if (!(new_item = ld->new_item(NULL))) 457 return 1; 458 new_item->list_entry.prev = NULL; 459 new_item->list_entry.next = NULL; 460 new_item->type = 1 | 2; 461 new_item->depth = 0; 462 463 ld->edit_item(dlg, new_item, list_insert_behind_item, item, TITLE_ADD); 464 return 0; 465 } 466 467 static int 468 list_item_edit(struct dialog_data *dlg, struct dialog_item_data *useless) 469 { 470 struct list_description *ld = 471 (struct list_description *)dlg->dlg->udata2; 472 struct list *item = ld->current_pos; 473 struct list *new_item; 474 475 if (item == ld->list) 476 return 0; /* head */ 477 if (!(new_item = ld->new_item(NULL))) 478 return 1; 479 new_item->list_entry.prev = NULL; 480 new_item->list_entry.next = NULL; 481 482 ld->copy_item(item, new_item); 483 ld->edit_item(dlg, new_item, list_copy_item, item, TITLE_EDIT); 484 485 return 0; 486 } 487 488 static inline int 489 is_parent(struct list_description *ld, struct list *item, struct list *parent) 490 { 491 struct list *l; 492 493 if (ld->type) 494 for (l = item; l->depth >= 0; l = l->fotr) 495 if (l == parent) 496 return 1; 497 return 0; 498 } 499 500 static int 501 list_item_move(struct dialog_data *dlg, struct dialog_item_data *useless) 502 { 503 struct list_description *ld = 504 (struct list_description *)dlg->dlg->udata2; 505 struct list *i; 506 struct list *behind = ld->current_pos; 507 struct redraw_data rd; 508 int window_moved = 0; 509 int count = 0; 510 511 if (ld->current_pos->type 512 & 4) { /* odznacime current_pos, kdyby nahodou byla oznacena */ 513 count++; 514 ld->current_pos->type &= ~4; 515 } 516 517 for (i = list_next(ld->list); i != ld->list;) { 518 struct list *next = next_in_tree(ld, i); 519 struct list *prev = list_prev(i); 520 struct list *behind_next = next_in_tree( 521 ld, behind); /* to se musi pocitat pokazdy, protoze by se 522 nam mohlo stat, ze to je taky oznaceny */ 523 struct list *item_last = 524 list_prev(next); /* last item of moved block */ 525 526 if (!(i->type & 4)) { 527 i = next; 528 continue; 529 } 530 if (is_parent( 531 ld, ld->current_pos, 532 i)) { /* we're moving directory into itself - let's 533 behave like item was not selected */ 534 i->type &= ~4; 535 i = next; 536 count++; 537 continue; 538 } 539 540 if ((i->type & 3) == 3) { /* dirty trick */ 541 i->type &= ~2; 542 next = next_in_tree(ld, i); 543 prev = list_prev(i); 544 item_last = list_prev(next); 545 i->type |= 2; 546 } 547 548 if (i == ld->win_offset) { 549 window_moved = 1; 550 if (next != ld->list) 551 ld->win_offset = next; 552 } 553 554 /* upravime fotrisko a hloubku */ 555 if (ld->type) { 556 int a = i->depth; 557 struct list *l = i; 558 559 if ((behind->type & 3) == 3 560 || behind == ld->list) { /* open folder or head */ 561 i->fotr = behind; 562 i->depth = behind->depth + 1; 563 } else { 564 i->fotr = behind->fotr; 565 i->depth = behind->depth; 566 } 567 a = i->depth - a; 568 569 /* poopravime hloubku v adresari */ 570 while (l != item_last) { 571 l = list_next(l); 572 l->depth += a; 573 } 574 } 575 576 if (behind_next == i) 577 goto predratovano; /* to uz je vsechno, akorat menime 578 hloubku */ 579 580 /* predratujeme ukazatele kolem bloku na stare pozici */ 581 prev->list_entry.next = &next->list_entry; 582 next->list_entry.prev = &prev->list_entry; 583 584 /* posuneme na novou pozici (tesne pred behind_next) */ 585 i->list_entry.prev = behind_next->list_entry.prev; 586 behind_next->list_entry.prev->next = &i->list_entry; 587 item_last->list_entry.next = &behind_next->list_entry; 588 behind_next->list_entry.prev = &item_last->list_entry; 589 590 predratovano: 591 /* odznacime */ 592 i->type &= ~4; 593 unselect_in_folder(ld, i); 594 595 /* upravime pointery pro dalsi krok */ 596 behind = i; 597 i = next; 598 count++; 599 } 600 601 if (window_moved) { 602 ld->current_pos = ld->win_offset; 603 ld->win_pos = 0; 604 } else 605 ld->win_pos = get_win_pos(ld); 606 607 if (!count) { 608 msg_box(dlg->win->term, /* terminal */ 609 NULL, /* blocks to free */ 610 TEXT_(T_MOVE), /* title */ 611 AL_CENTER, /* alignment */ 612 TEXT_(T_NO_ITEMS_SELECTED), MSG_BOX_END, /* text */ 613 NULL, /* data */ 614 1, /* # of buttons */ 615 TEXT_(T_CANCEL), msg_box_null, 616 B_ESC | B_ENTER /* button1 */ 617 ); 618 } else { 619 ld->modified = 1; 620 rd.ld = ld; 621 rd.dlg = dlg; 622 rd.n = 0; 623 draw_to_window(dlg->win, redraw_list, &rd); 624 } 625 return 0; 626 } 627 628 /* unselect all items */ 629 static int 630 list_item_unselect(struct dialog_data *dlg, struct dialog_item_data *useless) 631 { 632 struct list_description *ld = 633 (struct list_description *)dlg->dlg->udata2; 634 struct list *item; 635 struct redraw_data rd; 636 637 item = ld->list; 638 do { 639 item->type &= ~4; 640 item = list_next(item); 641 } while (item != ld->list); 642 643 rd.ld = ld; 644 rd.dlg = dlg; 645 rd.n = 0; 646 647 draw_to_window(dlg->win, redraw_list, &rd); 648 return 0; 649 } 650 651 /* user button function - calls button_fn with current item */ 652 static int 653 list_item_button(struct dialog_data *dlg, struct dialog_item_data *useless) 654 { 655 struct list_description *ld = 656 (struct list_description *)dlg->dlg->udata2; 657 struct list *item = ld->current_pos; 658 struct session *ses = (struct session *)dlg->dlg->udata; 659 660 if (!ld->button_fn) 661 internal("Links got schizophrenia! Call " BOHNICE ".\n"); 662 663 if (item == ld->list || list_empty(item->list_entry)) 664 return 0; /* head or empty list */ 665 666 if (ld->type && (item->type & 1)) { 667 list_edit_toggle(dlg, ld); 668 return 0; /* this is tree list and item is directory */ 669 } 670 671 ld->button_fn(ses, item); 672 cancel_dialog(dlg, useless); 673 return 0; 674 } 675 676 struct ve_skodarne_je_jeste_vetsi_narez { 677 struct list_description *ld; 678 struct dialog_data *dlg; 679 struct list *item; 680 }; 681 682 /* when delete is confirmed adjusts current_pos and calls delete function */ 683 static void 684 delete_ok(void *data) 685 { 686 struct ve_skodarne_je_jeste_vetsi_narez *skd = 687 (struct ve_skodarne_je_jeste_vetsi_narez *)data; 688 struct list_description *ld = skd->ld; 689 struct list *item = skd->item; 690 struct dialog_data *dlg = skd->dlg; 691 struct redraw_data rd; 692 693 /* strong premise: we can't delete head of the list */ 694 if (list_next(ld->current_pos) != ld->list) { 695 if (ld->current_pos == ld->win_offset) 696 ld->win_offset = list_next(ld->current_pos); 697 ld->current_pos = list_next(ld->current_pos); 698 } else { /* last item */ 699 if (!ld->win_pos) /* only one line on the screen */ 700 ld->win_offset = prev_in_tree(ld, ld->win_offset); 701 else 702 ld->win_pos--; 703 ld->current_pos = prev_in_tree(ld, ld->current_pos); 704 } 705 706 ld->delete_item(item); 707 708 rd.ld = ld; 709 rd.dlg = dlg; 710 rd.n = 0; 711 712 ld->modified = 1; 713 draw_to_window(dlg->win, redraw_list, &rd); 714 } 715 716 /* when delete folder is confirmed adjusts current_pos and calls delete function 717 */ 718 static void 719 delete_folder_recursively(void *data) 720 { 721 struct ve_skodarne_je_jeste_vetsi_narez *skd = 722 (struct ve_skodarne_je_jeste_vetsi_narez *)data; 723 struct list_description *ld = skd->ld; 724 struct list *item = skd->item; 725 struct dialog_data *dlg = skd->dlg; 726 struct redraw_data rd; 727 struct list *i, *j; 728 int depth; 729 730 for (i = list_next(item), depth = item->depth; 731 i != ld->list && i->depth > depth;) { 732 j = i; 733 i = list_next(i); 734 ld->delete_item(j); 735 } 736 737 /* strong premise: we can't delete head of the list */ 738 if (list_next(ld->current_pos) != ld->list) { 739 if (ld->current_pos == ld->win_offset) 740 ld->win_offset = list_next(ld->current_pos); 741 ld->current_pos = list_next(ld->current_pos); 742 } else { /* last item */ 743 if (!ld->win_pos) /* only one line on the screen */ 744 ld->win_offset = prev_in_tree(ld, ld->win_offset); 745 else 746 ld->win_pos--; 747 ld->current_pos = prev_in_tree(ld, ld->current_pos); 748 } 749 750 ld->delete_item(item); 751 752 rd.ld = ld; 753 rd.dlg = dlg; 754 rd.n = 0; 755 756 ld->modified = 1; 757 draw_to_window(dlg->win, redraw_list, &rd); 758 } 759 760 /* tests if directory is emty */ 761 static int 762 is_empty_dir(struct list_description *ld, struct list *dir) 763 { 764 if (!ld->type) 765 return 1; /* flat list */ 766 if (!(dir->type & 1)) 767 return 1; /* not a directory */ 768 769 return list_next(dir)->depth <= dir->depth; /* head depth is -1 */ 770 } 771 772 /* delete dialog */ 773 static int 774 list_item_delete(struct dialog_data *dlg, struct dialog_item_data *useless) 775 { 776 struct terminal *term = dlg->win->term; 777 struct list_description *ld = 778 (struct list_description *)(dlg->dlg->udata2); 779 struct list *item = ld->current_pos; 780 unsigned char *txt; 781 struct ve_skodarne_je_jeste_vetsi_narez *narez; 782 783 if (item == ld->list || list_empty(item->list_entry)) 784 return 0; /* head or empty list */ 785 786 narez = xmalloc(sizeof(struct ve_skodarne_je_jeste_vetsi_narez)); 787 narez->ld = ld; 788 narez->item = item; 789 narez->dlg = dlg; 790 791 txt = ld->type_item(term, item, 0); 792 if (!txt) { 793 txt = stracpy(cast_uchar ""); 794 } 795 796 if ((item->type) & 1) /* folder */ 797 { 798 if (!is_empty_dir(ld, item)) 799 msg_box(term, /* terminal */ 800 getml(txt, narez, NULL), /* blocks to free */ 801 TEXT_(T_DELETE_FOLDER), /* title */ 802 AL_CENTER, /* alignment */ 803 TEXT_(T_FOLDER), cast_uchar " \"", txt, 804 cast_uchar "\" ", 805 TEXT_(T_NOT_EMPTY_SURE_DELETE), 806 MSG_BOX_END, /* text */ 807 (void *)narez, /* data for ld->delete_item */ 808 2, /* # of buttons */ 809 TEXT_(T_NO), msg_box_null, B_ESC, /* button1 */ 810 TEXT_(T_YES), delete_folder_recursively, 811 B_ENTER /* button2 */ 812 ); 813 else 814 msg_box(term, /* terminal */ 815 getml(txt, narez, NULL), /* blocks to free */ 816 TEXT_(T_DELETE_FOLDER), /* title */ 817 AL_CENTER, /* alignment */ 818 TEXT_(T_SURE_DELETE), cast_uchar " ", 819 TEXT_(T_fOLDER), cast_uchar " \"", txt, 820 cast_uchar "\"?", 821 MSG_BOX_END, /* null-terminated text */ 822 (void *)narez, /* data for ld->delete_item */ 823 2, /* # of buttons */ 824 TEXT_(T_YES), delete_ok, B_ENTER, /* button1 */ 825 TEXT_(T_NO), msg_box_null, B_ESC /* button2 */ 826 ); 827 } else /* item */ 828 msg_box(term, /* terminal */ 829 getml(txt, narez, NULL), /* blocks to free */ 830 TEXT_(ld->delete_dialog_title), /* title */ 831 AL_CENTER, /* alignment */ 832 TEXT_(T_SURE_DELETE), cast_uchar " ", 833 TEXT_(ld->item_description), cast_uchar " \"", txt, 834 cast_uchar "\"?", 835 MSG_BOX_END, /* null-terminated text */ 836 (void *)narez, /* data for ld->delete_item */ 837 2, /* # of buttons */ 838 TEXT_(T_YES), delete_ok, B_ENTER, /* button1 */ 839 TEXT_(T_NO), msg_box_null, B_ESC /* button2 */ 840 ); 841 return 0; 842 } 843 844 static void 845 redraw_list_element(struct terminal *term, struct dialog_data *dlg, int y, 846 int w, struct list_description *ld, struct list *l) 847 { 848 struct list *lx; 849 unsigned char *xp; 850 int xd; 851 unsigned char *txt; 852 int x = 0; 853 unsigned char color = 0; 854 long bgcolor = 0, fgcolor = 0; 855 int b; 856 unsigned char element; 857 858 color = l == ld->current_pos ? COLOR_MENU_SELECTED : COLOR_MENU_TEXT; 859 860 txt = ld->type_item(term, l, 1); 861 if (!txt) { 862 txt = stracpy(cast_uchar ""); 863 } 864 865 /* everything except head */ 866 867 if (l != ld->list) { 868 switch (ld->type) { 869 case 0: 870 element = BFU_ELEMENT_TEE; 871 if (list_next(l) == ld->list) 872 element = BFU_ELEMENT_L; 873 x += draw_bfu_element(term, dlg->x + DIALOG_LB, y, 874 color, bgcolor, fgcolor, element, 875 l->type & 4); 876 break; 877 case 1: 878 xp = xmalloc(l->depth + 1); 879 memset(xp, 0, l->depth + 1); 880 xd = l->depth + 1; 881 for (lx = list_next(l); lx != ld->list; 882 lx = list_next(lx)) { 883 if (lx->depth < xd) { 884 xd = lx->depth; 885 xp[xd] = 1; 886 if (!xd) 887 break; 888 } 889 } 890 for (b = 0; b < l->depth; b++) 891 x += draw_bfu_element(term, 892 dlg->x + DIALOG_LB + x, y, 893 color, bgcolor, fgcolor, 894 xp[b] ? BFU_ELEMENT_PIPE 895 : BFU_ELEMENT_EMPTY, 896 0); 897 if (l->depth >= 0) { /* everything except head */ 898 int o = xp[l->depth]; 899 switch (l->type & 1) { 900 case 0: /* item */ 901 element = 902 o ? BFU_ELEMENT_TEE : BFU_ELEMENT_L; 903 break; 904 905 case 1: /* directory */ 906 if (l->type & 2) { 907 element = 908 o ? BFU_ELEMENT_OPEN_DOWN 909 : BFU_ELEMENT_OPEN; 910 } else { 911 element = 912 o ? BFU_ELEMENT_CLOSED_DOWN 913 : BFU_ELEMENT_CLOSED; 914 } 915 break; 916 917 default: /* this should never happen */ 918 internal("=8-Q lunacy level too high! " 919 "Call " BOHNICE ".\n"); 920 element = BFU_ELEMENT_EMPTY; 921 } 922 x += draw_bfu_element( 923 term, dlg->x + DIALOG_LB + x, y, color, 924 bgcolor, fgcolor, element, l->type & 4); 925 } 926 free(xp); 927 break; 928 default: 929 internal("Invalid list description type.\n" 930 "Somebody's probably shooting into memory.\n" 931 "_______________\n" 932 "`--|_____|--|___ `\\\n" 933 " \" \\___\\\n"); 934 } 935 } 936 937 print_text(term, dlg->x + x + DIALOG_LB, y, w - x, txt, color); 938 x += strlen((char *)txt); 939 fill_area(term, dlg->x + DIALOG_LB + x, y, w - x, 1, ' ', 0); 940 set_line_color(term, dlg->x + DIALOG_LB + x, y, w - x, color); 941 free(txt); 942 } 943 944 /* redraws list */ 945 static void 946 redraw_list(struct terminal *term, void *bla) 947 { 948 struct redraw_data *rd = (struct redraw_data *)bla; 949 struct list_description *ld = rd->ld; 950 struct dialog_data *dlg = rd->dlg; 951 int y, a; 952 struct list *l; 953 int w = dlg->xw - 2 * DIALOG_LB; 954 y = dlg->y + DIALOG_TB; 955 956 for (a = 0, l = ld->win_offset; a < ld->n_items;) { 957 redraw_list_element(term, dlg, y, w, ld, l); 958 l = next_in_tree(ld, l); 959 a++; 960 y++; 961 if (l == ld->list) 962 break; 963 } 964 fill_area(term, dlg->x + DIALOG_LB, y, w, ld->n_items - a, ' ', 965 COLOR_MENU_TEXT); 966 } 967 968 /* moves cursor from old position to a new one */ 969 /* direction: -1=old is previous, +1=old is next */ 970 static void 971 redraw_list_line(struct terminal *term, void *bla) 972 { 973 struct redraw_data *rd = (struct redraw_data *)bla; 974 struct list_description *ld = rd->ld; 975 struct dialog_data *dlg = rd->dlg; 976 int direction = rd->n; 977 int w = dlg->xw - 2 * DIALOG_LB; 978 int y = dlg->y + DIALOG_TB + ld->win_pos; 979 struct list *l; 980 981 redraw_list_element(term, dlg, y, w, ld, ld->current_pos); 982 if (!term->spec->block_cursor) { 983 set_cursor(term, dlg->x + DIALOG_LB, y, dlg->x + DIALOG_LB, y); 984 } 985 y += direction; 986 switch (direction) { 987 case 0: 988 l = NULL; 989 break; 990 case 1: 991 l = next_in_tree(ld, ld->current_pos); 992 break; 993 case -1: 994 l = prev_in_tree(ld, ld->current_pos); 995 break; 996 default: 997 internal("redraw_list_line: invalid direction %d", direction); 998 l = NULL; 999 break; 1000 } 1001 if (l) 1002 redraw_list_element(term, dlg, y, w, ld, l); 1003 } 1004 1005 /* like redraw_list, but scrolls window, prints new line to top/bottom */ 1006 /* in text mode calls redraw list */ 1007 /* direction: -1=up, 1=down */ 1008 static void 1009 scroll_list(struct terminal *term, void *bla) 1010 { 1011 redraw_list(term, bla); 1012 } 1013 1014 static void 1015 list_find_next(struct redraw_data *rd, int direction) 1016 { 1017 struct list_description *ld = rd->ld; 1018 struct dialog_data *dlg = rd->dlg; 1019 struct session *ses = (struct session *)(dlg->dlg->udata); 1020 struct list *item; 1021 1022 if (!ld->search_word) { 1023 msg_box(ses->term, NULL, TEXT_(T_SEARCH), AL_CENTER, 1024 TEXT_(T_NO_PREVIOUS_SEARCH), MSG_BOX_END, NULL, 1, 1025 TEXT_(T_CANCEL), msg_box_null, B_ENTER | B_ESC); 1026 return; 1027 } 1028 1029 if ((item = 1030 ld->find_item(ld->current_pos, ld->search_word, direction))) { 1031 struct list *l; 1032 ld->current_pos = item; 1033 ld->win_offset = item; 1034 ld->win_pos = 0; 1035 if (ld->type) 1036 for (l = item; l->depth >= 0; l = l->fotr) 1037 if (l != item) 1038 l->type |= 2; 1039 1040 draw_to_window(dlg->win, redraw_list, rd); 1041 if (!ses->term->spec->block_cursor) 1042 set_cursor(ses->term, dlg->x + DIALOG_LB, 1043 dlg->y + DIALOG_TB + ld->win_pos, 1044 dlg->x + DIALOG_LB, 1045 dlg->y + DIALOG_TB + ld->win_pos); 1046 } else 1047 msg_box(ses->term, NULL, TEXT_(T_SEARCH), AL_CENTER, 1048 TEXT_(T_SEARCH_STRING_NOT_FOUND), MSG_BOX_END, NULL, 1, 1049 TEXT_(T_CANCEL), msg_box_null, B_ENTER | B_ESC); 1050 } 1051 1052 static void 1053 list_search_for_back(void *rd_, unsigned char *str) 1054 { 1055 struct redraw_data *rd = (struct redraw_data *)rd_; 1056 struct list_description *ld = rd->ld; 1057 1058 if (!*str) 1059 return; 1060 if (!ld->open) 1061 return; 1062 1063 free(ld->search_word); 1064 ld->search_word = to_utf8_upcase(str, 0); 1065 ld->search_direction = -1; 1066 1067 list_find_next(rd, ld->search_direction); 1068 } 1069 1070 static void 1071 list_search_for(void *rd_, unsigned char *str) 1072 { 1073 struct redraw_data *rd = (struct redraw_data *)rd_; 1074 struct list_description *ld = rd->ld; 1075 1076 if (!*str) 1077 return; 1078 if (!ld->open) 1079 return; 1080 1081 free(ld->search_word); 1082 ld->search_word = to_utf8_upcase(str, 0); 1083 ld->search_direction = 1; 1084 1085 list_find_next(rd, ld->search_direction); 1086 } 1087 1088 static void 1089 list_edit_toggle(struct dialog_data *dlg, struct list_description *ld) 1090 { 1091 static struct redraw_data rd; 1092 ld->current_pos->type ^= 2; 1093 if (!(ld->current_pos->type & 2)) 1094 unselect_in_folder(ld, ld->current_pos); 1095 rd.ld = ld; 1096 rd.dlg = dlg; 1097 rd.n = 0; 1098 draw_to_window(dlg->win, redraw_list, &rd); 1099 draw_to_window(dlg->win, redraw_list_line, &rd); /* set cursor */ 1100 } 1101 1102 static int 1103 list_event_handler(struct dialog_data *dlg, struct links_event *ev) 1104 { 1105 struct list_description *ld = 1106 (struct list_description *)(dlg->dlg->udata2); 1107 static struct redraw_data rd; 1108 struct session *ses = (struct session *)(dlg->dlg->udata); 1109 1110 rd.ld = ld; 1111 rd.dlg = dlg; 1112 rd.n = 0; 1113 1114 switch ((int)ev->ev) { 1115 case EV_KBD: 1116 if (ev->y & KBD_PASTING) 1117 break; 1118 if (ld->type == 1) /* tree list */ 1119 { 1120 if (ev->x == ' ') /* toggle folder */ 1121 { 1122 if (!((ld->current_pos->type) & 1)) 1123 return EVENT_PROCESSED; /* item */ 1124 1125 list_edit_toggle(dlg, ld); 1126 return EVENT_PROCESSED; 1127 } 1128 if (ev->x == '+' || ev->x == '=') /* open folder */ 1129 { 1130 if (!((ld->current_pos->type) & 1)) 1131 return EVENT_PROCESSED; /* item */ 1132 if ((ld->current_pos->type) & 2) 1133 return EVENT_PROCESSED; /* already open 1134 */ 1135 list_edit_toggle(dlg, ld); 1136 return EVENT_PROCESSED; 1137 } 1138 if (ev->x == '-') /* close folder */ 1139 { 1140 if (!((ld->current_pos->type) & 1)) 1141 return EVENT_PROCESSED; /* item */ 1142 if (!((ld->current_pos->type) & 2)) 1143 return EVENT_PROCESSED; /* already 1144 closed */ 1145 list_edit_toggle(dlg, ld); 1146 return EVENT_PROCESSED; 1147 } 1148 } 1149 if (ev->x == '/' 1150 || (ev->x == KBD_FIND 1151 && !(ev->y 1152 & (KBD_SHIFT | KBD_CTRL 1153 | KBD_ALT)))) /* search forward */ 1154 { 1155 struct redraw_data *r; 1156 1157 r = xmalloc(sizeof(struct redraw_data)); 1158 r->ld = ld; 1159 r->dlg = dlg; 1160 1161 input_field(ses->term, getml(r, NULL), TEXT_(T_SEARCH), 1162 TEXT_(T_SEARCH_FOR_TEXT), r, 1163 ld->search_history, MAX_INPUT_URL_LEN, 1164 cast_uchar "", 0, 0, NULL, 2, TEXT_(T_OK), 1165 list_search_for, TEXT_(T_CANCEL), 1166 input_field_null); 1167 return EVENT_PROCESSED; 1168 } 1169 if (ev->x == '?' 1170 || (ev->x == KBD_FIND 1171 && ev->y 1172 & (KBD_SHIFT | KBD_CTRL 1173 | KBD_ALT))) /* search back */ 1174 { 1175 struct redraw_data *r; 1176 1177 r = xmalloc(sizeof(struct redraw_data)); 1178 r->ld = ld; 1179 r->dlg = dlg; 1180 1181 input_field( 1182 ses->term, getml(r, NULL), TEXT_(T_SEARCH_BACK), 1183 TEXT_(T_SEARCH_FOR_TEXT), r, ld->search_history, 1184 MAX_INPUT_URL_LEN, cast_uchar "", 0, 0, NULL, 2, 1185 TEXT_(T_OK), list_search_for_back, TEXT_(T_CANCEL), 1186 input_field_null); 1187 return EVENT_PROCESSED; 1188 } 1189 if ((ev->x == 'n' && !(ev->y & KBD_ALT)) 1190 || ev->x == KBD_REDO) /* find next */ 1191 { 1192 list_find_next(&rd, ld->search_direction); 1193 return EVENT_PROCESSED; 1194 } 1195 if ((ev->x == 'N' && !(ev->y & KBD_ALT)) 1196 || ev->x == KBD_UNDO) /* find prev */ 1197 { 1198 list_find_next(&rd, -ld->search_direction); 1199 return EVENT_PROCESSED; 1200 } 1201 if (ev->x == KBD_UP) { 1202 if (ld->current_pos == ld->list) 1203 goto kbd_up_redraw_exit; /* already on the top 1204 */ 1205 ld->current_pos = prev_in_tree(ld, ld->current_pos); 1206 ld->win_pos--; 1207 rd.n = 1; 1208 if (ld->win_pos < 0) /* scroll up */ 1209 { 1210 ld->win_pos = 0; 1211 ld->win_offset = 1212 prev_in_tree(ld, ld->win_offset); 1213 draw_to_window(dlg->win, scroll_list, &rd); 1214 } 1215 kbd_up_redraw_exit: 1216 draw_to_window(dlg->win, redraw_list_line, &rd); 1217 return EVENT_PROCESSED; 1218 } 1219 if (ev->x == 'i' || ev->x == '*' || ev->x == '8' 1220 || ev->x == KBD_INS || ev->x == KBD_SELECT) { 1221 if (ld->current_pos != ld->list) 1222 ld->current_pos->type ^= 4; 1223 rd.n = -1; 1224 if (next_in_tree(ld, ld->current_pos) 1225 == ld->list) /* already at the bottom */ 1226 { 1227 draw_to_window(dlg->win, redraw_list_line, &rd); 1228 return EVENT_PROCESSED; 1229 } 1230 ld->current_pos = next_in_tree(ld, ld->current_pos); 1231 ld->win_pos++; 1232 if (ld->win_pos > ld->n_items - 1) /* scroll down */ 1233 { 1234 ld->win_pos = ld->n_items - 1; 1235 ld->win_offset = 1236 next_in_tree(ld, ld->win_offset); 1237 draw_to_window(dlg->win, scroll_list, &rd); 1238 } 1239 draw_to_window(dlg->win, redraw_list_line, &rd); 1240 return EVENT_PROCESSED; 1241 } 1242 if (ev->x == KBD_DOWN) { 1243 if (next_in_tree(ld, ld->current_pos) == ld->list) 1244 goto kbd_down_redraw_exit; /* already at the 1245 bottom */ 1246 ld->current_pos = next_in_tree(ld, ld->current_pos); 1247 ld->win_pos++; 1248 rd.n = -1; 1249 if (ld->win_pos > ld->n_items - 1) /* scroll down */ 1250 { 1251 ld->win_pos = ld->n_items - 1; 1252 ld->win_offset = 1253 next_in_tree(ld, ld->win_offset); 1254 draw_to_window(dlg->win, scroll_list, &rd); 1255 } 1256 kbd_down_redraw_exit: 1257 draw_to_window(dlg->win, redraw_list_line, &rd); 1258 return EVENT_PROCESSED; 1259 } 1260 if (ev->x == KBD_HOME 1261 || (upcase(ev->x) == 'A' && ev->y & KBD_CTRL)) { 1262 if (ld->current_pos == ld->list) 1263 goto kbd_home_redraw_exit; /* already on the top 1264 */ 1265 ld->win_offset = ld->list; 1266 ld->current_pos = ld->win_offset; 1267 ld->win_pos = 0; 1268 rd.n = 0; 1269 draw_to_window(dlg->win, redraw_list, &rd); 1270 kbd_home_redraw_exit: 1271 draw_to_window(dlg->win, redraw_list_line, 1272 &rd); /* set cursor */ 1273 return EVENT_PROCESSED; 1274 } 1275 if (ev->x == KBD_END 1276 || (upcase(ev->x) == 'E' && ev->y & KBD_CTRL)) { 1277 int a; 1278 1279 if (ld->current_pos == prev_in_tree(ld, ld->list)) 1280 goto kbd_end_redraw_exit; /* already on the top 1281 */ 1282 ld->win_offset = prev_in_tree(ld, ld->list); 1283 for (a = 1; 1284 a < ld->n_items && ld->win_offset != ld->list; a++) 1285 ld->win_offset = 1286 prev_in_tree(ld, ld->win_offset); 1287 ld->current_pos = prev_in_tree(ld, ld->list); 1288 ld->win_pos = a - 1; 1289 rd.n = 0; 1290 draw_to_window(dlg->win, redraw_list, &rd); 1291 kbd_end_redraw_exit: 1292 draw_to_window(dlg->win, redraw_list_line, 1293 &rd); /* set cursor */ 1294 return EVENT_PROCESSED; 1295 } 1296 if (ev->x == KBD_PAGE_UP 1297 || (upcase(ev->x) == 'B' && ev->y & KBD_CTRL)) { 1298 int a; 1299 1300 if (ld->current_pos == ld->list) 1301 goto kbd_page_up_redraw_exit; /* already on the 1302 top */ 1303 for (a = 0; 1304 a < ld->n_items && ld->win_offset != ld->list; 1305 a++) { 1306 ld->win_offset = 1307 prev_in_tree(ld, ld->win_offset); 1308 ld->current_pos = 1309 prev_in_tree(ld, ld->current_pos); 1310 } 1311 if (a < ld->n_items) { 1312 ld->current_pos = ld->win_offset; 1313 ld->win_pos = 0; 1314 } 1315 rd.n = 0; 1316 draw_to_window(dlg->win, redraw_list, &rd); 1317 kbd_page_up_redraw_exit: 1318 draw_to_window(dlg->win, redraw_list_line, 1319 &rd); /* set cursor */ 1320 return EVENT_PROCESSED; 1321 } 1322 if (ev->x == KBD_PAGE_DOWN 1323 || (upcase(ev->x) == 'F' && ev->y & KBD_CTRL)) { 1324 int a; 1325 struct list *p = ld->win_offset; 1326 1327 if (ld->current_pos == prev_in_tree(ld, ld->list)) 1328 goto kbd_page_down_redraw_exit; /* already on 1329 the bottom */ 1330 for (a = 0; 1331 a < ld->n_items && ld->list != next_in_tree(ld, p); 1332 a++) 1333 p = next_in_tree(ld, p); 1334 if (a < ld->n_items) /* already last screen */ 1335 { 1336 ld->current_pos = p; 1337 ld->win_pos = a; 1338 rd.n = 0; 1339 draw_to_window(dlg->win, redraw_list, &rd); 1340 draw_to_window(dlg->win, redraw_list_line, 1341 &rd); /* set cursor */ 1342 return EVENT_PROCESSED; 1343 } 1344 /* here is whole screen only - the window was full 1345 * before pressing the page-down key */ 1346 /* p is pointing behind last item of the window (behind 1347 * last visible item in the window) */ 1348 for (a = 0; a < ld->n_items && p != ld->list; a++) { 1349 ld->win_offset = 1350 next_in_tree(ld, ld->win_offset); 1351 ld->current_pos = 1352 next_in_tree(ld, ld->current_pos); 1353 p = next_in_tree(ld, p); 1354 } 1355 if (a < ld->n_items) { 1356 ld->current_pos = prev_in_tree(ld, ld->list); 1357 ld->win_pos = ld->n_items - 1; 1358 } 1359 rd.n = 0; 1360 draw_to_window(dlg->win, redraw_list, &rd); 1361 kbd_page_down_redraw_exit: 1362 draw_to_window(dlg->win, redraw_list_line, 1363 &rd); /* set cursor */ 1364 return EVENT_PROCESSED; 1365 } 1366 break; 1367 1368 case EV_MOUSE: 1369 /* toggle select item */ 1370 if ((ev->b & BM_ACT) == B_DOWN 1371 && (ev->b & BM_BUTT) == B_RIGHT) { 1372 int n, a; 1373 struct list *l = ld->win_offset; 1374 1375 last_mouse_y = ev->y; 1376 1377 if ((ev->y) < (dlg->y + DIALOG_TB) 1378 || ev->y >= (dlg->y + DIALOG_TB + ld->n_items) 1379 || (ev->x) < (dlg->x + DIALOG_LB) 1380 || (ev->x) > (dlg->x + dlg->xw - DIALOG_LB)) 1381 break; /* out of the dialog */ 1382 1383 n = ev->y - dlg->y - DIALOG_TB; 1384 for (a = 0; a < n; a++) { 1385 struct list *l1; 1386 l1 = 1387 next_in_tree(ld, l); /* current item under 1388 the mouse pointer */ 1389 if (l1 == ld->list) 1390 goto break2; 1391 else 1392 l = l1; 1393 } 1394 1395 l->type ^= 4; 1396 ld->current_pos = l; 1397 ld->win_pos = n; 1398 rd.n = 0; 1399 draw_to_window(dlg->win, redraw_list, &rd); 1400 draw_to_window(dlg->win, redraw_list_line, 1401 &rd); /* set cursor */ 1402 return EVENT_PROCESSED; 1403 } 1404 /* click on item */ 1405 if (((ev->b & BM_ACT) == B_DOWN || (ev->b & BM_ACT) == B_DRAG) 1406 && (ev->b & BM_BUTT) == B_LEFT) { 1407 int n, a; 1408 struct list *l = ld->win_offset; 1409 1410 last_mouse_y = ev->y; 1411 1412 if ((ev->y) < (dlg->y + DIALOG_TB) 1413 || ev->y >= (dlg->y + DIALOG_TB + ld->n_items) 1414 || (ev->x) < (dlg->x + DIALOG_LB) 1415 || (ev->x) > (dlg->x + dlg->xw - DIALOG_LB)) 1416 goto skip_item_click; /* out of the dialog */ 1417 1418 n = ev->y - dlg->y - DIALOG_TB; 1419 for (a = 0; a < n; a++) { 1420 struct list *l1; 1421 l1 = 1422 next_in_tree(ld, l); /* current item under 1423 the mouse pointer */ 1424 if (l1 == ld->list) { 1425 n = a; 1426 break; 1427 } else 1428 l = l1; 1429 } 1430 a = ld->type ? ((l->depth) >= 0 ? (l->depth) + 1 : 0) 1431 : (l->depth >= 0); 1432 1433 ld->current_pos = l; 1434 1435 /* clicked on directory graphical stuff */ 1436 if ((ev->b & BM_ACT) == B_DOWN && ld->type 1437 && ev->x < (dlg->x + DIALOG_LB 1438 + a * BFU_ELEMENT_WIDTH) 1439 && (l->type & 1)) { 1440 l->type ^= 2; 1441 if (!(l->type & 2)) 1442 unselect_in_folder(ld, ld->current_pos); 1443 } 1444 ld->win_pos = n; 1445 rd.n = 0; 1446 draw_to_window(dlg->win, redraw_list, &rd); 1447 draw_to_window(dlg->win, redraw_list_line, 1448 &rd); /* set cursor */ 1449 return EVENT_PROCESSED; 1450 } 1451 /* scroll with the bar */ 1452 skip_item_click: 1453 if ((ev->b & BM_ACT) == B_DRAG 1454 && (ev->b & BM_BUTT) == B_MIDDLE) { 1455 long delta = ev->y - last_mouse_y; 1456 1457 last_mouse_y = ev->y; 1458 if (delta > 0) /* scroll down */ 1459 { 1460 if (next_in_tree(ld, ld->current_pos) 1461 == ld->list) 1462 return EVENT_PROCESSED; /* already at 1463 the bottom */ 1464 ld->current_pos = 1465 next_in_tree(ld, ld->current_pos); 1466 ld->win_pos++; 1467 rd.n = -1; 1468 if (ld->win_pos 1469 > ld->n_items - 1) /* scroll down */ 1470 { 1471 ld->win_pos = ld->n_items - 1; 1472 ld->win_offset = 1473 next_in_tree(ld, ld->win_offset); 1474 draw_to_window(dlg->win, scroll_list, 1475 &rd); 1476 } 1477 draw_to_window(dlg->win, redraw_list_line, &rd); 1478 } 1479 if (delta < 0) /* scroll up */ 1480 { 1481 if (ld->current_pos == ld->list) 1482 return EVENT_PROCESSED; /* already on 1483 the top */ 1484 ld->current_pos = 1485 prev_in_tree(ld, ld->current_pos); 1486 ld->win_pos--; 1487 rd.n = +1; 1488 if (ld->win_pos < 0) /* scroll up */ 1489 { 1490 ld->win_pos = 0; 1491 ld->win_offset = 1492 prev_in_tree(ld, ld->win_offset); 1493 draw_to_window(dlg->win, scroll_list, 1494 &rd); 1495 } 1496 draw_to_window(dlg->win, redraw_list_line, &rd); 1497 } 1498 return EVENT_PROCESSED; 1499 } 1500 /* mouse wheel */ 1501 if ((ev->b & BM_ACT) == B_MOVE 1502 && ((ev->b & BM_BUTT) == B_WHEELUP 1503 || (ev->b & BM_BUTT) == B_WHEELDOWN 1504 || (ev->b & BM_BUTT) == B_WHEELDOWN1 1505 || (ev->b & BM_BUTT) == B_WHEELUP1)) { 1506 int button = (int)ev->b & BM_BUTT; 1507 last_mouse_y = ev->y; 1508 1509 if (button == B_WHEELDOWN 1510 || button == B_WHEELDOWN1) /* scroll down */ 1511 { 1512 if (next_in_tree(ld, ld->current_pos) 1513 == ld->list) 1514 return EVENT_PROCESSED; /* already at 1515 the bottom */ 1516 ld->current_pos = 1517 next_in_tree(ld, ld->current_pos); 1518 ld->win_pos++; 1519 rd.n = -1; 1520 if (ld->win_pos 1521 > ld->n_items - 1) /* scroll down */ 1522 { 1523 ld->win_pos = ld->n_items - 1; 1524 ld->win_offset = 1525 next_in_tree(ld, ld->win_offset); 1526 draw_to_window(dlg->win, scroll_list, 1527 &rd); 1528 } 1529 draw_to_window(dlg->win, redraw_list_line, &rd); 1530 } 1531 if (button == B_WHEELUP 1532 || button == B_WHEELUP1) /* scroll up */ 1533 { 1534 if (ld->current_pos == ld->list) 1535 return EVENT_PROCESSED; /* already on 1536 the top */ 1537 ld->current_pos = 1538 prev_in_tree(ld, ld->current_pos); 1539 ld->win_pos--; 1540 rd.n = +1; 1541 if (ld->win_pos < 0) /* scroll up */ 1542 { 1543 ld->win_pos = 0; 1544 ld->win_offset = 1545 prev_in_tree(ld, ld->win_offset); 1546 draw_to_window(dlg->win, scroll_list, 1547 &rd); 1548 } 1549 draw_to_window(dlg->win, redraw_list_line, &rd); 1550 } 1551 return EVENT_PROCESSED; 1552 } 1553 break2: 1554 break; 1555 1556 case EV_INIT: 1557 case EV_RESIZE: 1558 case EV_REDRAW: 1559 case EV_ABORT: 1560 break; 1561 1562 default: 1563 break; 1564 } 1565 return EVENT_NOT_PROCESSED; 1566 } 1567 1568 /* display function for the list window */ 1569 static void 1570 create_list_window_fn(struct dialog_data *dlg) 1571 { 1572 struct terminal *term = dlg->win->term; 1573 struct list_description *ld = 1574 (struct list_description *)(dlg->dlg->udata2); 1575 int min = 0; 1576 int w, rw, y; 1577 int n_items; 1578 struct redraw_data rd; 1579 1580 int a = 6; 1581 1582 ld->dlg = dlg; 1583 if (ld->button_fn) 1584 a++; /* user button */ 1585 if (ld->type == 1) 1586 a++; /* add directory button */ 1587 1588 y = 0; 1589 min_buttons_width(term, dlg->items, a, &min); 1590 1591 w = term->x * 19 / 20 - 2 * DIALOG_LB; 1592 if (w < min) 1593 w = min; 1594 if (w > term->x - 2 * DIALOG_LB) 1595 w = term->x - 2 * DIALOG_LB; 1596 if (w < 5) 1597 w = 5; 1598 1599 rw = 0; 1600 dlg_format_buttons(dlg, NULL, dlg->items, a, 0, &y, w, &rw, AL_CENTER); 1601 1602 n_items = term->y - y; 1603 n_items -= 2 * DIALOG_TB + 2; 1604 if (n_items < 2) 1605 n_items = 2; 1606 ld->n_items = n_items; 1607 1608 while (ld->win_pos > ld->n_items - 1) { 1609 ld->current_pos = prev_in_tree(ld, ld->current_pos); 1610 ld->win_pos--; 1611 } 1612 1613 y += ld->n_items; 1614 1615 rw = w; 1616 dlg->xw = rw + 2 * DIALOG_LB; 1617 dlg->yw = y + 2 * DIALOG_TB; 1618 center_dlg(dlg); 1619 draw_dlg(dlg); 1620 1621 rd.ld = ld; 1622 rd.dlg = dlg; 1623 rd.n = 0; 1624 1625 draw_to_window(dlg->win, redraw_list, &rd); 1626 1627 y = dlg->y + DIALOG_TB + ld->n_items + 1; 1628 dlg_format_buttons(dlg, term, dlg->items, a, dlg->x + DIALOG_LB, &y, w, 1629 &rw, AL_CENTER); 1630 } 1631 1632 static void 1633 close_list_window(struct dialog_data *dlg) 1634 { 1635 struct dialog *d = dlg->dlg; 1636 struct list_description *ld = (struct list_description *)(d->udata2); 1637 1638 ld->open = 0; 1639 ld->dlg = NULL; 1640 free(ld->search_word); 1641 ld->search_word = NULL; 1642 if (ld->save) 1643 ld->save(d->udata); 1644 } 1645 1646 int 1647 test_list_window_in_use(struct list_description *ld, struct terminal *term) 1648 { 1649 if (ld->open) { 1650 if (term) 1651 msg_box(term, NULL, TEXT_(T_INFO), AL_CENTER, 1652 TEXT_(ld->already_in_use), MSG_BOX_END, NULL, 1, 1653 TEXT_(T_CANCEL), msg_box_null, B_ENTER | B_ESC); 1654 return 1; 1655 } 1656 return 0; 1657 } 1658 1659 /* dialog->udata2 ... list_description */ 1660 /* dialog->udata ... session */ 1661 int 1662 create_list_window(struct list_description *ld, struct list *list, 1663 struct terminal *term, struct session *ses) 1664 { 1665 struct dialog *d; 1666 int a; 1667 1668 /* zavodime, zavodime... */ 1669 if (test_list_window_in_use(ld, term)) 1670 return 1; 1671 ld->open = 1; 1672 1673 if (!ld->current_pos) { 1674 ld->current_pos = list; 1675 ld->win_offset = list; 1676 ld->win_pos = 0; 1677 ld->dlg = NULL; 1678 } 1679 1680 a = 7; 1681 if (ld->button_fn) 1682 a++; 1683 if (ld->type == 1) 1684 a++; 1685 1686 d = mem_calloc(sizeof(struct dialog) + a * sizeof(struct dialog_item)); 1687 1688 d->title = TEXT_(ld->window_title); 1689 d->fn = create_list_window_fn; 1690 d->abort = close_list_window; 1691 d->handle_event = list_event_handler; 1692 d->udata = ses; 1693 d->udata2 = ld; 1694 1695 a = 0; 1696 1697 if (ld->button_fn) { 1698 d->items[a].type = D_BUTTON; 1699 d->items[a].fn = list_item_button; 1700 d->items[a].text = TEXT_(ld->button); 1701 a++; 1702 } 1703 1704 if (ld->type == 1) { 1705 d->items[a].type = D_BUTTON; 1706 d->items[a].text = TEXT_(T_FOLDER); 1707 d->items[a].fn = list_folder_add; 1708 a++; 1709 } 1710 1711 d->items[a].type = D_BUTTON; 1712 d->items[a].text = TEXT_(T_ADD); 1713 d->items[a].fn = list_item_add; 1714 1715 d->items[a + 1].type = D_BUTTON; 1716 d->items[a + 1].text = TEXT_(T_DELETE); 1717 d->items[a + 1].fn = list_item_delete; 1718 1719 d->items[a + 2].type = D_BUTTON; 1720 d->items[a + 2].text = TEXT_(T_EDIT); 1721 d->items[a + 2].fn = list_item_edit; 1722 1723 d->items[a + 3].type = D_BUTTON; 1724 d->items[a + 3].text = TEXT_(T_MOVE); 1725 d->items[a + 3].fn = list_item_move; 1726 1727 d->items[a + 4].type = D_BUTTON; 1728 d->items[a + 4].text = TEXT_(T_UNSELECT_ALL); 1729 d->items[a + 4].fn = list_item_unselect; 1730 1731 d->items[a + 5].type = D_BUTTON; 1732 d->items[a + 5].gid = B_ESC; 1733 d->items[a + 5].fn = cancel_dialog; 1734 d->items[a + 5].text = TEXT_(T_CLOSE); 1735 1736 d->items[a + 6].type = D_END; 1737 do_dialog(term, d, getml(d, NULL)); 1738 return 0; 1739 } 1740 1741 void 1742 reinit_list_window(struct list_description *ld) 1743 { 1744 ld->current_pos = ld->list; 1745 ld->win_offset = ld->list; 1746 ld->win_pos = 0; 1747 1748 if (ld->open) 1749 internal("reinit_list_window: calling reinit while open"); 1750 }