1932 lines
58 KiB
C
1932 lines
58 KiB
C
/* listedit.c
|
|
* (c) 2002 Petr 'Brain' Kulhavy
|
|
* This file is a part of the Links program, released under GPL.
|
|
*/
|
|
|
|
#include "links.h"
|
|
|
|
|
|
/*
|
|
(#####)
|
|
(#########)
|
|
)))) (######)
|
|
,C--O (###) _________________
|
|
|`:, \ ~~ |. , v , .|
|
|
`-__o ~~ ; | ZAKAZ KOURENI |
|
|
/ _ \ ` |. .|
|
|
| ( \__`_=k== `~~~~~~~~~~~~~~~~~'
|
|
| `-/__---'
|
|
|=====C/
|
|
`. ),'
|
|
\ /
|
|
||_|
|
|
|| |__
|
|
||____)
|
|
|
|
v v v , ,v
|
|
KONECNE NEJAKE KOMENTARE...
|
|
*/
|
|
|
|
/* Klikani myssi (nebo mysijou, jak rika Mikulas) v list-okne:
|
|
* (hrozne dulezity komentar ;-P )
|
|
*
|
|
* Klikani je vyreseno nasledovne, pokud ma nekdo lepsi napad, nebo nejake
|
|
* vyhrady, tak at mi je posle.
|
|
*
|
|
* Prostredni tlacitko+pohyb je scroll nahoru/dolu. Levym tlacitkem se nastavi
|
|
* kurzor (cerna lista) na konkretni polozku. Kdyz se levym klikne na adresar
|
|
* (na ty graficke nesmysly, ne na ten text), tak se adresar toggle
|
|
* otevre/zavre. Prave tlacitko oznaci/odznaci polozku/adresar.
|
|
*/
|
|
|
|
/* Premistovani polozek:
|
|
*
|
|
* Pravym tlacitkem se oznaci/odznaci polozka. Cudlikem "Odznacit vse" se
|
|
* vsechny polozky odznaci. Cudlik "Prestehovat" presune vsechny oznacene
|
|
* polozky za aktualni pozici, v tom poradi, jak jsou v seznamu. Pri zavreni
|
|
* adresare se vsechny polozky v adresari odznaci.
|
|
*/
|
|
|
|
/* Prekreslovani grafickych nesmyslu v okenku je samozrejme bez jedineho
|
|
* v
|
|
* bliknuti. Ne jako nejmenovane browsery... Proste obraz jako BIC (TM)
|
|
*/
|
|
|
|
/* Ovladani klavesnici:
|
|
* sipky, page up, page down, home end pohyb
|
|
* + otevri adresar
|
|
* - zavri adresar
|
|
* mezera toggle adresar
|
|
* ins, *, 8, i toggle oznacit
|
|
* ?, /, N, n hledani nahoru, dolu, znova, znova na druhou stranu
|
|
*/
|
|
|
|
/*
|
|
* Struktura struct list_decription obsahuje popis seznamu. Tenhle file
|
|
* obsahuje obecne funkce k obsluze seznamu. Pomoci struct list_description se
|
|
* seznam customizuje. Obecne funkce volaji funkce z list_description.
|
|
*
|
|
* Jedina funkce z tohoto filu, ktera se vola zvenku, je create_list_window. Ta
|
|
* vyrobi a obstarava okno pro obsluhu seznamu.
|
|
*
|
|
* Obecny list neresi veci jako nahravani seznamu z filu, ukladani na disk
|
|
* atd.(tyhle funkce si uzivatel musi napsat sam). Resi vlastne jenom to velke
|
|
* okno na manipulaci se seznamem.
|
|
*/
|
|
|
|
/*
|
|
* Aby bylo konzistentni pridavani a editovani polozek, tak se musi pytlacit.
|
|
*
|
|
* To znamena, ze pri pridavani polozky do listu se vyrobi nova polozka
|
|
* (NEPRIDA se do seznamu), pusti se edit a po zmacknuti OK se polozka prida do
|
|
* seznamu. Pri zmacknuti cancel, se polozka smaze.
|
|
*
|
|
* Pri editovani polozky se vyrobi nova polozka, zkopiruje se do ni obsah te
|
|
* puvodni (od toho tam je funkce copy_item), pak se zavola edit a podobne jako
|
|
* v predchozim pripade: pri cancel se polozka smaze, pri OK se zkopiruje do
|
|
* puvodni polozky a smaze se taky.
|
|
*
|
|
* O smazani polozky pri cancelu se bude starat uzivatelska funkce edit_item
|
|
* sama. Funkce edit_item po zmacknuti OK zavola funkci, kterou dostane. Jako
|
|
* 1. argument ji da data, ktera dostane, jako 2. argument ji preda pointer na
|
|
* item.
|
|
*/
|
|
|
|
/*
|
|
* Seznam je definovan ve struct list. Muze byt bud placaty nebo stromovy.
|
|
*
|
|
* K placatemu asi neni co dodat. U placateho se ignoruje hloubka a neexistuji
|
|
* adresare - vsechny polozky jsou si rovny (typ polozky se ignoruje).
|
|
*
|
|
* Stromovy seznam:
|
|
* Kazdy clen seznamu ma flag sbaleno/rozbaleno. U itemy se to ignoruje, u
|
|
* adresare to znamena, zda se zobrazuje obsah nebo ne. Aby rozbaleno/sbaleno
|
|
* bylo u vsech prvku adresare, to by neslo: kdybych mel adresar a v nem dalsi
|
|
* adresar, tak bych u toho vnoreneho adresare nevedel, jestli to
|
|
* sbaleno/rozbaleno je od toho vnoreneho adresare, nebo od toho nad nim.
|
|
*
|
|
* Clenove seznamu maji hloubku - cislo od 0 vyse. Cim je prvek hloubeji ve
|
|
* strukture, tim je hloubka vyssi. Obsah adresare s hloubkou x je souvisly blok
|
|
* nasledujicich prvku s hloubkou >x.
|
|
*
|
|
* Hlava ma hloubku -1 a zobrazuje se taky jako clen seznamu (aby se dal
|
|
* zobrazit prazdny seznam a dalo se do nej pridavat), takze se da vlastne cely
|
|
* seznam zabalit/rozbalit. Hlava sice nema data, ale funkce type_item ji musi
|
|
* umet zobrazit. Jako popis bude psat fixni text, napriklad "Bookmarks".
|
|
*
|
|
* Pro urychleni vykreslovani kazdy prvek v seznamu s adresarema obsahuje
|
|
* pointer na otce (polozka fotr). U plocheho seznamu se tento pointer
|
|
* ignoruje.
|
|
*
|
|
* Strukturu stromu bude vykreslovat obecna funkce (v tomto filu), protoze v
|
|
* obecnem listu je struktura uz zachycena.
|
|
*/
|
|
|
|
/*
|
|
* V hlavnim okne se da nadefinovat 1 uzivatelske tlacitko. Polozka button ve
|
|
* struct list_description obsahuje popisku tlacitka (kod stringu v
|
|
* prekodovavacich tabulkach). Funkce button_fn je zavolana pri stisku
|
|
* tlacitka, jako argument (void *) dostane aktualni polozku. Pokud je
|
|
* button_fn NULL, tlacitko se nekona.
|
|
*
|
|
* Toto tlacitko se da vyuzit napriklad u bookmarku, kde je potreba [ Goto ].
|
|
*
|
|
* Kdyz bude potreba predavat obsluzne funkci tlacitka nejake dalsi argumenty,
|
|
* tak se pripadne definice obsluzne funkce prepise.
|
|
*
|
|
* Tlacitko funguje jen na polozky. Nefunguje na adresare (pokud se jedna o
|
|
* stromovy list) ani na hlavu.
|
|
*/
|
|
|
|
/* Jak funguje default_value:
|
|
* kdyz se zmackne tlacitko add, zavola se funkce default_value, ktera si
|
|
* naalokuje nejaky data pro new_item. Do funkce default_value se treba u
|
|
* bookmarku umisti okopirovani altualniho nazvu a url stranky. Pak se zavola
|
|
* new_item, ktera si prislusne hodnoty dekoduje a pomoci nich vyplni novou
|
|
* polozku. Funkce new_item pak MUSI data dealokovat. Pokud funkce new_item
|
|
* dostane misto pointeru s daty NULL, vyrobi prazdnou polozku.
|
|
*
|
|
* Default value musi vratit hodnoty v kodovani uvedenem v list_description
|
|
*/
|
|
|
|
/* Pristupovani z vice linksu:
|
|
*
|
|
* ... se neresi - je zakazano. K tomu slouzi polozka open ve struct
|
|
* list_description, ktera rika, jestli je okno uz otevrene, nebo ne.
|
|
*/
|
|
|
|
/* Prekodovavani znakovych sad:
|
|
*
|
|
* type_item vraci text prekodovany do kodovani terminalu, ktery dostane.
|
|
*/
|
|
|
|
|
|
/* struct list *current_pos; current cursor position in the list */
|
|
/* struct list *win_offset; item at the top of the window */
|
|
/* int win_pos; current y position in the window */
|
|
|
|
#define BOHNICE "+420-2-84016111"
|
|
|
|
#define BFU_ELEMENT_EMPTY 0
|
|
#define BFU_ELEMENT_PIPE 1
|
|
#define BFU_ELEMENT_L 2
|
|
#define BFU_ELEMENT_TEE 3
|
|
#define BFU_ELEMENT_CLOSED 4
|
|
#define BFU_ELEMENT_CLOSED_DOWN 5
|
|
#define BFU_ELEMENT_OPEN 6
|
|
#define BFU_ELEMENT_OPEN_DOWN 7
|
|
|
|
/* for mouse scrolling */
|
|
static long last_mouse_y;
|
|
|
|
static void list_edit_toggle(struct dialog_data *dlg, struct list_description *ld);
|
|
|
|
#ifdef G
|
|
#define sirka_scrollovadla (G_SCROLL_BAR_WIDTH<<1)
|
|
#else
|
|
#define sirka_scrollovadla 0
|
|
#endif
|
|
|
|
|
|
/* This function uses these defines from setup.h:
|
|
*
|
|
* BFU_GRX_WIDTH
|
|
* BFU_GRX_HEIGHT
|
|
* BFU_ELEMENT_WIDTH
|
|
*/
|
|
|
|
/* draws one of BFU elements: | |- [-] [+] */
|
|
/* BFU elements are used in the list window */
|
|
/* this function also defines shape and size of the elements */
|
|
/* returns width of the BFU element (all elements have the same size, but sizes differ if we're in text mode or in graphics mode) */
|
|
static int draw_bfu_element(struct terminal * term, int x, int y, unsigned char c, long b, long f, unsigned char type, unsigned char selected)
|
|
{
|
|
#ifdef G
|
|
if (!F){
|
|
#endif
|
|
unsigned char vertical=179;
|
|
unsigned char horizontal=196;
|
|
unsigned char tee=195;
|
|
unsigned char l=192;
|
|
|
|
switch (type)
|
|
{
|
|
case BFU_ELEMENT_EMPTY:
|
|
c|=ATTR_FRAME;
|
|
set_char(term,x,y,' ',c);
|
|
set_char(term,x+1,y,' ',c);
|
|
set_char(term,x+2,y,' ',c);
|
|
set_char(term,x+3,y,' ',c);
|
|
set_char(term,x+4,y,' ',c);
|
|
break;
|
|
|
|
case BFU_ELEMENT_PIPE:
|
|
c|=ATTR_FRAME;
|
|
set_char(term,x,y,' ',c);
|
|
set_char(term,x+1,y,vertical,c);
|
|
set_char(term,x+2,y,' ',c);
|
|
set_char(term,x+3,y,' ',c);
|
|
set_char(term,x+4,y,' ',c);
|
|
break;
|
|
|
|
case BFU_ELEMENT_L:
|
|
c|=ATTR_FRAME;
|
|
set_char(term,x,y,' ',c);
|
|
set_char(term,x+1,y,l,c);
|
|
set_char(term,x+2,y,horizontal,c);
|
|
set_char(term,x+3,y,horizontal,c);
|
|
set_char(term,x+4,y,' ',c);
|
|
break;
|
|
|
|
case BFU_ELEMENT_TEE:
|
|
c|=ATTR_FRAME;
|
|
set_char(term,x,y,' ',c);
|
|
set_char(term,x+1,y,tee,c);
|
|
set_char(term,x+2,y,horizontal,c);
|
|
set_char(term,x+3,y,horizontal,c);
|
|
set_char(term,x+4,y,' ',c);
|
|
break;
|
|
|
|
case BFU_ELEMENT_CLOSED:
|
|
case BFU_ELEMENT_CLOSED_DOWN:
|
|
set_char(term,x,y,'[',c);
|
|
set_char(term,x+1,y,'+',c);
|
|
set_char(term,x+2,y,']',c);
|
|
c|=ATTR_FRAME;
|
|
set_char(term,x+3,y,horizontal,c);
|
|
set_char(term,x+4,y,' ',c);
|
|
break;
|
|
|
|
case BFU_ELEMENT_OPEN:
|
|
case BFU_ELEMENT_OPEN_DOWN:
|
|
set_char(term,x,y,'[',c);
|
|
set_char(term,x+1,y,'-',c);
|
|
set_char(term,x+2,y,']',c);
|
|
c|=ATTR_FRAME;
|
|
set_char(term,x+3,y,horizontal,c);
|
|
set_char(term,x+4,y,' ',c);
|
|
break;
|
|
|
|
default:
|
|
internal_error("draw_bfu_element: unknown BFU element type %d.\n",type);
|
|
}
|
|
if (selected)set_char(term,x+4,y,'*',c);
|
|
return BFU_ELEMENT_WIDTH; /* BFU element size in text mode */
|
|
#ifdef G
|
|
}else{
|
|
struct graphics_device *dev=term->dev;
|
|
struct rect r;
|
|
|
|
restrict_clip_area(dev,&r,x,y,x+5*BFU_GRX_WIDTH,y+BFU_GRX_HEIGHT);
|
|
|
|
switch (type)
|
|
{
|
|
case BFU_ELEMENT_EMPTY:
|
|
drv->fill_area(dev,x,y,x+4*BFU_GRX_WIDTH,y+BFU_GRX_HEIGHT,b);
|
|
break;
|
|
|
|
case BFU_ELEMENT_PIPE:
|
|
/* pipe */
|
|
drv->draw_vline(dev,x+1*BFU_GRX_WIDTH,y,y+BFU_GRX_HEIGHT,f);
|
|
drv->draw_vline(dev,x+1+1*BFU_GRX_WIDTH,y,y+BFU_GRX_HEIGHT,f);
|
|
/* clear the rest */
|
|
drv->fill_area(dev,x,y,x+1*BFU_GRX_WIDTH,y+BFU_GRX_HEIGHT,b);
|
|
drv->fill_area(dev,x+2+1*BFU_GRX_WIDTH,y,x+4*BFU_GRX_WIDTH,y+BFU_GRX_HEIGHT,b);
|
|
break;
|
|
|
|
case BFU_ELEMENT_L:
|
|
/* l */
|
|
drv->draw_vline(dev,x+1*BFU_GRX_WIDTH,y,y+(int)(.5*BFU_GRX_HEIGHT),f);
|
|
drv->draw_vline(dev,x+1+1*BFU_GRX_WIDTH,y,y+(int)(.5*BFU_GRX_HEIGHT),f);
|
|
drv->draw_hline(dev,x+1*BFU_GRX_WIDTH,y+(int)(.5*BFU_GRX_HEIGHT),x+1+(int)(3.5*BFU_GRX_WIDTH),f);
|
|
drv->draw_hline(dev,x+1*BFU_GRX_WIDTH,y-1+(int)(.5*BFU_GRX_HEIGHT),x+1+(int)(3.5*BFU_GRX_WIDTH),f);
|
|
/* clear the rest */
|
|
drv->fill_area(dev,x,y,x+1*BFU_GRX_WIDTH,y+BFU_GRX_HEIGHT,b);
|
|
drv->fill_area(dev,x+BFU_GRX_WIDTH,y+(int)(.5*BFU_GRX_HEIGHT)+1,x+1+(int)(3.5*BFU_GRX_WIDTH),y+BFU_GRX_HEIGHT,b);
|
|
drv->fill_area(dev,x+2+BFU_GRX_WIDTH,y,x+1+(int)(3.5*BFU_GRX_WIDTH),y-1+(int)(.5*BFU_GRX_HEIGHT),b);
|
|
drv->fill_area(dev,x+1+(int)(3.5*BFU_GRX_WIDTH),y,x+4*BFU_GRX_WIDTH,y+BFU_GRX_HEIGHT,b);
|
|
break;
|
|
|
|
case BFU_ELEMENT_TEE:
|
|
/* tee */
|
|
drv->draw_vline(dev,x+1*BFU_GRX_WIDTH,y,y+BFU_GRX_HEIGHT,f);
|
|
drv->draw_vline(dev,x+1+1*BFU_GRX_WIDTH,y,y+BFU_GRX_HEIGHT,f);
|
|
drv->draw_hline(dev,x+1*BFU_GRX_WIDTH,y+(int)(.5*BFU_GRX_HEIGHT),x+1+(int)(3.5*BFU_GRX_WIDTH),f);
|
|
drv->draw_hline(dev,x+1*BFU_GRX_WIDTH,y-1+(int)(.5*BFU_GRX_HEIGHT),x+1+(int)(3.5*BFU_GRX_WIDTH),f);
|
|
/* clear the rest */
|
|
drv->fill_area(dev,x,y,x+1*BFU_GRX_WIDTH,y+BFU_GRX_HEIGHT,b);
|
|
drv->fill_area(dev,x+2+BFU_GRX_WIDTH,y+(int)(.5*BFU_GRX_HEIGHT)+1,x+1+(int)(3.5*BFU_GRX_WIDTH),y+BFU_GRX_HEIGHT,b);
|
|
drv->fill_area(dev,x+2+BFU_GRX_WIDTH,y,x+1+(int)(3.5*BFU_GRX_WIDTH),y-1+(int)(.5*BFU_GRX_HEIGHT),b);
|
|
drv->fill_area(dev,x+1+(int)(3.5*BFU_GRX_WIDTH),y,x+4*BFU_GRX_WIDTH,y+BFU_GRX_HEIGHT,b);
|
|
break;
|
|
|
|
case BFU_ELEMENT_CLOSED:
|
|
case BFU_ELEMENT_CLOSED_DOWN:
|
|
/* vertical line of the + */
|
|
drv->draw_vline(dev,x+1*BFU_GRX_WIDTH,y+1+(int)(.25*BFU_GRX_HEIGHT),y-1+(int)(.75*BFU_GRX_HEIGHT),f);
|
|
drv->draw_vline(dev,x+1+1*BFU_GRX_WIDTH,y+1+(int)(.25*BFU_GRX_HEIGHT),y-1+(int)(.75*BFU_GRX_HEIGHT),f);
|
|
|
|
/* clear around the + */
|
|
drv->fill_area(dev,x+2+(int)(.5*BFU_GRX_WIDTH),y+3,x+(int)(1.5*BFU_GRX_WIDTH),y+1+(int)(.25*BFU_GRX_HEIGHT),b);
|
|
drv->fill_area(dev,x+2+(int)(.5*BFU_GRX_WIDTH),y-1+(int)(.75*BFU_GRX_HEIGHT),x+(int)(1.5*BFU_GRX_WIDTH),y-3+BFU_GRX_HEIGHT,b);
|
|
|
|
drv->fill_area(dev,x+2+(int)(.5*BFU_GRX_WIDTH),y+1+(int)(.25*BFU_GRX_HEIGHT),x+BFU_GRX_WIDTH,y-1+(int)(.5*BFU_GRX_HEIGHT),b);
|
|
drv->fill_area(dev,x+2+BFU_GRX_WIDTH,y+1+(int)(.25*BFU_GRX_HEIGHT),x+(int)(1.5*BFU_GRX_WIDTH),y-1+(int)(.5*BFU_GRX_HEIGHT),b);
|
|
|
|
drv->fill_area(dev,x+2+(int)(.5*BFU_GRX_WIDTH),y+1+(int)(.5*BFU_GRX_HEIGHT),x+BFU_GRX_WIDTH,y-3+BFU_GRX_HEIGHT,b);
|
|
drv->fill_area(dev,x+2+BFU_GRX_WIDTH,y+1+(int)(.5*BFU_GRX_HEIGHT),x+(int)(1.5*BFU_GRX_WIDTH),y-3+BFU_GRX_HEIGHT,b);
|
|
/*-fallthrough*/
|
|
|
|
case BFU_ELEMENT_OPEN:
|
|
case BFU_ELEMENT_OPEN_DOWN:
|
|
/* box */
|
|
drv->draw_vline(dev,x+2,y+1,y-1+BFU_GRX_HEIGHT,f);
|
|
drv->draw_vline(dev,x+3,y+1,y-1+BFU_GRX_HEIGHT,f);
|
|
drv->draw_vline(dev,x-1+2*BFU_GRX_WIDTH,y+1,y-1+BFU_GRX_HEIGHT,f);
|
|
drv->draw_vline(dev,x-2+2*BFU_GRX_WIDTH,y+1,y-1+BFU_GRX_HEIGHT,f);
|
|
drv->draw_hline(dev,x+4,y+1,x-2+2*BFU_GRX_WIDTH,f);
|
|
drv->draw_hline(dev,x+4,y+2,x-2+2*BFU_GRX_WIDTH,f);
|
|
drv->draw_hline(dev,x+4,y-2+BFU_GRX_HEIGHT,x-2+2*BFU_GRX_WIDTH,f);
|
|
drv->draw_hline(dev,x+4,y-3+BFU_GRX_HEIGHT,x-2+2*BFU_GRX_WIDTH,f);
|
|
|
|
/* horizontal line of the - */
|
|
drv->draw_hline(dev,x+2+(int)(.5*BFU_GRX_WIDTH),y+(int)(.5*BFU_GRX_HEIGHT),x+(int)(1.5*BFU_GRX_WIDTH),f);
|
|
drv->draw_hline(dev,x+2+(int)(.5*BFU_GRX_WIDTH),y-1+(int)(.5*BFU_GRX_HEIGHT),x+(int)(1.5*BFU_GRX_WIDTH),f);
|
|
|
|
/* line to title */
|
|
drv->draw_hline(dev,x+2*BFU_GRX_WIDTH,y+(BFU_GRX_HEIGHT>>1),x+1+(int)(3.5*BFU_GRX_WIDTH),f);
|
|
drv->draw_hline(dev,x+2*BFU_GRX_WIDTH,y-1+(BFU_GRX_HEIGHT>>1),x+1+(int)(3.5*BFU_GRX_WIDTH),f);
|
|
|
|
/* top and bottom short vertical line */
|
|
drv->draw_hline(dev,x+1*BFU_GRX_WIDTH,y,x+2+1*BFU_GRX_WIDTH,f);
|
|
drv->draw_hline(dev,x+1*BFU_GRX_WIDTH,y-1+BFU_GRX_HEIGHT,x+2+1*BFU_GRX_WIDTH,type == BFU_ELEMENT_OPEN || type == BFU_ELEMENT_CLOSED ? b : f);
|
|
|
|
/* clear the rest */
|
|
drv->draw_vline(dev,x,y,y+BFU_GRX_HEIGHT,b);
|
|
drv->draw_vline(dev,x+1,y,y+BFU_GRX_HEIGHT,b);
|
|
drv->draw_hline(dev,x+2,y,x+BFU_GRX_WIDTH,b);
|
|
drv->draw_hline(dev,x+2,y-1+BFU_GRX_HEIGHT,x+BFU_GRX_WIDTH,b);
|
|
drv->draw_hline(dev,x+2+BFU_GRX_WIDTH,y,x+2*BFU_GRX_WIDTH,b);
|
|
drv->draw_hline(dev,x+2+BFU_GRX_WIDTH,y-1+BFU_GRX_HEIGHT,x+2*BFU_GRX_WIDTH,b);
|
|
drv->fill_area(dev,x+2*BFU_GRX_WIDTH,y,x+1+(int)(3.5*BFU_GRX_WIDTH),y+(int)(.5*BFU_GRX_HEIGHT)-1,b);
|
|
drv->fill_area(dev,x+2*BFU_GRX_WIDTH,y+1+(int)(.5*BFU_GRX_HEIGHT),x+1+(int)(3.5*BFU_GRX_WIDTH),y+BFU_GRX_HEIGHT,b);
|
|
drv->fill_area(dev,x+4,y+3,x+2+(int)(.5*BFU_GRX_WIDTH),y-3+BFU_GRX_HEIGHT,b);
|
|
drv->fill_area(dev,x+(int)(1.5*BFU_GRX_WIDTH),y+3,x-2+2*BFU_GRX_WIDTH,y-3+BFU_GRX_HEIGHT,b);
|
|
drv->fill_area(dev,x+2+(int)(.5*BFU_GRX_WIDTH),y+3,x+(int)(1.5*BFU_GRX_WIDTH),y+1+(int)(.25*BFU_GRX_HEIGHT),b);
|
|
drv->fill_area(dev,x+2+(int)(.5*BFU_GRX_WIDTH),y-1+(int)(.75*BFU_GRX_HEIGHT),x+(int)(1.5*BFU_GRX_WIDTH),y-3+BFU_GRX_HEIGHT,b);
|
|
if (type==BFU_ELEMENT_OPEN || type == BFU_ELEMENT_OPEN_DOWN)
|
|
{
|
|
drv->fill_area(dev,x+2+(int)(.5*BFU_GRX_WIDTH),y+3,x+(int)(1.5*BFU_GRX_WIDTH),y-1+(int)(.5*BFU_GRX_HEIGHT),b);
|
|
drv->fill_area(dev,x+2+(int)(.5*BFU_GRX_WIDTH),y+1+(int)(.5*BFU_GRX_HEIGHT),x+(int)(1.5*BFU_GRX_WIDTH),y-3+BFU_GRX_HEIGHT,b);
|
|
}
|
|
drv->fill_area(dev,x+1+(int)(3.5*BFU_GRX_WIDTH),y,x+4*BFU_GRX_WIDTH,y+BFU_GRX_HEIGHT,b);
|
|
break;
|
|
|
|
default:
|
|
internal_error("draw_bfu_element: unknown BFU element type %d.\n",type);
|
|
}
|
|
if (!selected)
|
|
drv->fill_area(dev,x+4*BFU_GRX_WIDTH,y,x+5*BFU_GRX_WIDTH,y+BFU_GRX_HEIGHT,b);
|
|
else
|
|
{
|
|
drv->fill_area(dev,x+4*BFU_GRX_WIDTH,y,x+(int)(4.25*BFU_GRX_WIDTH),y+BFU_GRX_HEIGHT,b);
|
|
drv->fill_area(dev,x+(int)(4.25*BFU_GRX_WIDTH),y,x+(int)(4.75*BFU_GRX_WIDTH),y+(int)(2.5*BFU_GRX_HEIGHT),b);
|
|
drv->fill_area(dev,x+(int)(4.25*BFU_GRX_WIDTH),y+(int)(.25*BFU_GRX_HEIGHT),x+(int)(4.75*BFU_GRX_WIDTH),y+(int)(.75*BFU_GRX_HEIGHT),f);
|
|
drv->fill_area(dev,x+(int)(4.25*BFU_GRX_WIDTH),y+(int)(.75*BFU_GRX_HEIGHT),x+(int)(4.75*BFU_GRX_WIDTH),y+BFU_GRX_HEIGHT,b);
|
|
drv->fill_area(dev,x+(int)(4.75*BFU_GRX_WIDTH),y,x+5*BFU_GRX_WIDTH,y+BFU_GRX_HEIGHT,b);
|
|
}
|
|
|
|
set_clip_area(dev, &r);
|
|
return BFU_ELEMENT_WIDTH;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
|
|
/* aux structure for parameter exchange for redrawing list window */
|
|
struct redraw_data
|
|
{
|
|
struct list_description *ld;
|
|
struct dialog_data *dlg;
|
|
int n;
|
|
};
|
|
|
|
|
|
static void redraw_list(struct terminal *term, void *bla);
|
|
|
|
/* returns next visible item in tree list */
|
|
/* works only with visible items (head or any item returned by this function) */
|
|
/* when list is flat returns next item */
|
|
static struct list *next_in_tree(struct list_description *ld, struct list *item)
|
|
{
|
|
int depth = item->depth;
|
|
|
|
/* flat list */
|
|
if (!ld->type)
|
|
return list_next(item);
|
|
|
|
if (!(item->type & 1) || (item->type & 2)) /* item or opened folder */
|
|
return list_next(item);
|
|
/* skip content of this folder */
|
|
do item = list_next(item); while (item->depth > depth); /* must stop on head 'cause it's depth is -1 */
|
|
return item;
|
|
}
|
|
|
|
|
|
/* returns previous visible item in tree list */
|
|
/* works only with visible items (head or any item returned by this function) */
|
|
/* when list is flat returns previous item */
|
|
static struct list *prev_in_tree(struct list_description *ld, struct list *item)
|
|
{
|
|
struct list *last_closed;
|
|
int depth = item->depth;
|
|
|
|
/* flat list */
|
|
if (!ld->type)
|
|
return list_prev(item);
|
|
|
|
if (item == ld->list)
|
|
depth=0;
|
|
|
|
/* items with same or lower depth must be visible, because current item is visible */
|
|
if (list_prev(item)->depth <= item->depth)
|
|
return list_prev(item);
|
|
|
|
/* find item followed with opened fotr's only */
|
|
/* searched item is last closed folder (going up from item) or item->prev */
|
|
last_closed = list_prev(item);
|
|
item = list_prev(item);
|
|
while (1) {
|
|
if ((item->type & 3) == 1) /* closed folder */
|
|
last_closed = item;
|
|
if (item->depth <= depth)
|
|
break;
|
|
item = item->fotr;
|
|
}
|
|
return last_closed;
|
|
}
|
|
|
|
|
|
#ifdef G
|
|
static int get_total_items(struct list_description *ld)
|
|
{
|
|
struct list *l = ld->list;
|
|
int count = 0;
|
|
|
|
do{
|
|
l = next_in_tree(ld, l);
|
|
count++;
|
|
} while (l != ld->list);
|
|
|
|
return count;
|
|
}
|
|
|
|
|
|
static int get_scroll_pos(struct list_description *ld)
|
|
{
|
|
struct list *l;
|
|
int count = 0;
|
|
|
|
for (l = ld->list; l != ld->win_offset; l = next_in_tree(ld,l))
|
|
count++;
|
|
|
|
return count;
|
|
}
|
|
|
|
|
|
static int get_visible_items(struct list_description *ld)
|
|
{
|
|
struct list *l = ld->win_offset;
|
|
int count = 0;
|
|
|
|
do{
|
|
l = next_in_tree(ld,l);
|
|
count++;
|
|
} while (count < ld->n_items && l != ld->list);
|
|
|
|
return count;
|
|
}
|
|
|
|
|
|
static struct list *find_last_in_window(struct list_description *ld)
|
|
{
|
|
struct list *l = ld->win_offset;
|
|
struct list *x = l;
|
|
int count = 0;
|
|
|
|
do{
|
|
l = next_in_tree(ld, l);
|
|
count++;
|
|
if (l != ld->list && count != ld->n_items)
|
|
x = l;
|
|
} while (count < ld->n_items && l != ld->list);
|
|
|
|
return x;
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
static int get_win_pos(struct list_description *ld)
|
|
{
|
|
struct list *l;
|
|
int count = 0;
|
|
|
|
for (l = ld->win_offset; l != ld->current_pos; l = next_in_tree(ld, l))
|
|
count++;
|
|
|
|
return count;
|
|
}
|
|
|
|
|
|
static void unselect_in_folder(struct list_description *ld, struct list *l)
|
|
{
|
|
int depth;
|
|
|
|
depth = l->depth;
|
|
for (l = list_next(l); l != ld->list && l->depth > depth; l = list_next(l))
|
|
l->type &= ~4;
|
|
}
|
|
|
|
|
|
/* aux function for list_item_add */
|
|
static void list_insert_behind_item(struct dialog_data *dlg, struct list *pos, struct list *item, struct list_description *ld)
|
|
{
|
|
struct list *a;
|
|
struct redraw_data rd;
|
|
|
|
/* BEFORE: ... <----> pos <--(possible invisible items)--> a <----> ... */
|
|
/* AFTER: ... <----> pos <--(possible invisible items)--> item <----> a <----> ... */
|
|
|
|
a = next_in_tree(ld,pos);
|
|
add_before_pos(a, item);
|
|
|
|
/* if list is flat a->fotr will contain nosenses, but it won't crash ;-) */
|
|
if ((pos->type & 3) == 3 || pos->depth == -1) { item->fotr=pos; item->depth=pos->depth+1; } /* open directory or head */
|
|
else { item->fotr = pos->fotr; item->depth = pos->depth; }
|
|
|
|
ld->current_pos = next_in_tree(ld, ld->current_pos); /* ld->current_pos->next==item */
|
|
ld->win_pos++;
|
|
if (ld->win_pos > ld->n_items - 1) { /* scroll down */
|
|
ld->win_pos = ld->n_items - 1;
|
|
ld->win_offset = next_in_tree(ld, ld->win_offset);
|
|
}
|
|
|
|
ld->modified = 1;
|
|
|
|
rd.ld = ld;
|
|
rd.dlg = dlg;
|
|
rd.n = 0;
|
|
|
|
draw_to_window(dlg->win, redraw_list, &rd);
|
|
}
|
|
|
|
|
|
/* aux function for list_item_edit */
|
|
/* copies data of src to dest and calls free on the src */
|
|
/* first argument is argument passed to user function */
|
|
static void list_copy_item(struct dialog_data *dlg, struct list *dest, struct list *src, struct list_description *ld)
|
|
{
|
|
struct redraw_data rd;
|
|
|
|
ld->copy_item(src, dest);
|
|
ld->delete_item(src);
|
|
|
|
ld->modified = 1; /* called after an successful edit */
|
|
rd.ld = ld;
|
|
rd.dlg = dlg;
|
|
rd.n = 0;
|
|
|
|
draw_to_window(dlg->win, redraw_list, &rd);
|
|
}
|
|
|
|
|
|
/* creates new item (calling new_item function) and calls edit_item function */
|
|
static int list_item_add(struct dialog_data *dlg, struct dialog_item_data *useless)
|
|
{
|
|
struct list_description *ld = (struct list_description *)dlg->dlg->udata2;
|
|
struct list *item = ld->current_pos;
|
|
struct list *new_item;
|
|
|
|
if (!(new_item = ld->new_item(ld->default_value ? ld->default_value((struct session *)dlg->dlg->udata, 0) : NULL)))
|
|
return 1;
|
|
new_item->list_entry.prev = NULL;
|
|
new_item->list_entry.next = NULL;
|
|
new_item->type = 0;
|
|
new_item->depth = 0;
|
|
|
|
ld->edit_item(dlg,new_item, list_insert_behind_item, item, TITLE_ADD);
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* like list_item_add but creates folder */
|
|
static int list_folder_add(struct dialog_data *dlg, struct dialog_item_data *useless)
|
|
{
|
|
struct list_description *ld = (struct list_description *)dlg->dlg->udata2;
|
|
struct list *item = ld->current_pos;
|
|
struct list *new_item;
|
|
|
|
if (!(new_item = ld->new_item(NULL)))
|
|
return 1;
|
|
new_item->list_entry.prev = NULL;
|
|
new_item->list_entry.next = NULL;
|
|
new_item->type = 1 | 2;
|
|
new_item->depth = 0;
|
|
|
|
ld->edit_item(dlg, new_item, list_insert_behind_item, item, TITLE_ADD);
|
|
return 0;
|
|
}
|
|
|
|
|
|
static int list_item_edit(struct dialog_data *dlg,struct dialog_item_data *useless)
|
|
{
|
|
struct list_description *ld = (struct list_description *)dlg->dlg->udata2;
|
|
struct list *item = ld->current_pos;
|
|
struct list *new_item;
|
|
|
|
if (item == ld->list) return 0; /* head */
|
|
if (!(new_item = ld->new_item(NULL))) return 1;
|
|
new_item->list_entry.prev = NULL;
|
|
new_item->list_entry.next = NULL;
|
|
|
|
ld->copy_item(item, new_item);
|
|
ld->edit_item(dlg, new_item, list_copy_item, item, TITLE_EDIT);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
static inline int is_parent(struct list_description *ld, struct list *item, struct list *parent)
|
|
{
|
|
struct list *l;
|
|
|
|
if (ld->type)
|
|
for (l=item;l->depth>=0;l=l->fotr)
|
|
if (l==parent) return 1;
|
|
return 0;
|
|
}
|
|
|
|
static int list_item_move(struct dialog_data *dlg, struct dialog_item_data *useless)
|
|
{
|
|
struct list_description *ld = (struct list_description *)dlg->dlg->udata2;
|
|
struct list *i;
|
|
struct list *behind = ld->current_pos;
|
|
struct redraw_data rd;
|
|
int window_moved = 0;
|
|
int count = 0;
|
|
|
|
if (ld->current_pos->type & 4) { /* odznacime current_pos, kdyby nahodou byla oznacena */
|
|
count++;
|
|
ld->current_pos->type &= ~4;
|
|
}
|
|
|
|
for (i = list_next(ld->list); i != ld->list; ) {
|
|
struct list *next = next_in_tree(ld, i);
|
|
struct list *prev = list_prev(i);
|
|
struct list *behind_next = next_in_tree(ld, behind); /* to se musi pocitat pokazdy, protoze by se nam mohlo stat, ze to je taky oznaceny */
|
|
struct list *item_last = list_prev(next); /* last item of moved block */
|
|
|
|
if (!(i->type & 4)) { i = next; continue; }
|
|
if (is_parent(ld, ld->current_pos, i)) { /* we're moving directory into itself - let's behave like item was not selected */
|
|
i->type &= ~4;
|
|
i = next;
|
|
count++;
|
|
continue;
|
|
}
|
|
|
|
if ((i->type & 3) == 3) { /* dirty trick */
|
|
i->type &= ~2;
|
|
next = next_in_tree(ld, i);
|
|
prev = list_prev(i);
|
|
item_last = list_prev(next);
|
|
i->type |= 2;
|
|
}
|
|
|
|
if (i == ld->win_offset) {
|
|
window_moved = 1;
|
|
if (next != ld->list) ld->win_offset = next;
|
|
}
|
|
|
|
/* upravime fotrisko a hloubku */
|
|
if (ld->type) {
|
|
int a = i->depth;
|
|
struct list *l = i;
|
|
|
|
if ((behind->type & 3) == 3 || behind == ld->list) { /* open folder or head */
|
|
i->fotr = behind;
|
|
i->depth = behind->depth + 1;
|
|
} else {
|
|
i->fotr = behind->fotr;
|
|
i->depth = behind->depth;
|
|
}
|
|
a = i->depth - a;
|
|
|
|
/* poopravime hloubku v adresari */
|
|
while (l != item_last) {
|
|
l = list_next(l);
|
|
l->depth += a;
|
|
}
|
|
}
|
|
|
|
if (behind_next == i) goto predratovano; /* to uz je vsechno, akorat menime hloubku */
|
|
|
|
/* predratujeme ukazatele kolem bloku na stare pozici */
|
|
prev->list_entry.next = &next->list_entry;
|
|
next->list_entry.prev = &prev->list_entry;
|
|
|
|
/* posuneme na novou pozici (tesne pred behind_next) */
|
|
i->list_entry.prev = behind_next->list_entry.prev;
|
|
behind_next->list_entry.prev->next = &i->list_entry;
|
|
item_last->list_entry.next = &behind_next->list_entry;
|
|
behind_next->list_entry.prev = &item_last->list_entry;
|
|
|
|
predratovano:
|
|
/* odznacime */
|
|
i->type &= ~4;
|
|
unselect_in_folder(ld, i);
|
|
|
|
/* upravime pointery pro dalsi krok */
|
|
behind = i;
|
|
i = next;
|
|
count++;
|
|
}
|
|
|
|
if (window_moved) {
|
|
ld->current_pos = ld->win_offset;
|
|
ld->win_pos = 0;
|
|
} else
|
|
ld->win_pos = get_win_pos(ld);
|
|
|
|
if (!count) {
|
|
msg_box(
|
|
dlg->win->term, /* terminal */
|
|
NULL, /* blocks to free */
|
|
TEXT_(T_MOVE), /* title */
|
|
AL_CENTER, /* alignment */
|
|
TEXT_(T_NO_ITEMS_SELECTED),MSG_BOX_END, /* text */
|
|
NULL, /* data */
|
|
1, /* # of buttons */
|
|
TEXT_(T_CANCEL), msg_box_null, B_ESC|B_ENTER /* button1 */
|
|
);
|
|
} else {
|
|
ld->modified = 1;
|
|
rd.ld = ld;
|
|
rd.dlg = dlg;
|
|
rd.n = 0;
|
|
draw_to_window(dlg->win, redraw_list, &rd);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* unselect all items */
|
|
static int list_item_unselect(struct dialog_data *dlg, struct dialog_item_data *useless)
|
|
{
|
|
struct list_description *ld = (struct list_description *)dlg->dlg->udata2;
|
|
struct list *item;
|
|
struct redraw_data rd;
|
|
|
|
item = ld->list;
|
|
do {
|
|
item->type &= ~4;
|
|
item = list_next(item);
|
|
} while (item != ld->list);
|
|
|
|
rd.ld = ld;
|
|
rd.dlg = dlg;
|
|
rd.n = 0;
|
|
|
|
draw_to_window(dlg->win, redraw_list, &rd);
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* user button function - calls button_fn with current item */
|
|
static int list_item_button(struct dialog_data *dlg, struct dialog_item_data *useless)
|
|
{
|
|
struct list_description *ld = (struct list_description *)dlg->dlg->udata2;
|
|
struct list *item = ld->current_pos;
|
|
struct session *ses = (struct session *)dlg->dlg->udata;
|
|
|
|
if (!ld->button_fn) internal_error("Links got schizophrenia! Call "BOHNICE".\n");
|
|
|
|
if (item == ld->list || list_empty(item->list_entry)) return 0; /* head or empty list */
|
|
|
|
if (ld->type && (item->type & 1)) {
|
|
list_edit_toggle(dlg, ld);
|
|
return 0; /* this is tree list and item is directory */
|
|
}
|
|
|
|
ld->button_fn(ses,item);
|
|
cancel_dialog(dlg, useless);
|
|
return 0;
|
|
}
|
|
|
|
|
|
struct ve_skodarne_je_jeste_vetsi_narez {
|
|
struct list_description *ld;
|
|
struct dialog_data *dlg;
|
|
struct list *item;
|
|
};
|
|
|
|
|
|
/* when delete is confirmed adjusts current_pos and calls delete function */
|
|
static void delete_ok(void *data)
|
|
{
|
|
struct ve_skodarne_je_jeste_vetsi_narez *skd = (struct ve_skodarne_je_jeste_vetsi_narez *)data;
|
|
struct list_description *ld = skd->ld;
|
|
struct list *item = skd->item;
|
|
struct dialog_data *dlg = skd->dlg;
|
|
struct redraw_data rd;
|
|
|
|
/* strong premise: we can't delete head of the list */
|
|
if (list_next(ld->current_pos) != ld->list) {
|
|
if (ld->current_pos == ld->win_offset) ld->win_offset = list_next(ld->current_pos);
|
|
ld->current_pos = list_next(ld->current_pos);
|
|
} else { /* last item */
|
|
if (!ld->win_pos) /* only one line on the screen */
|
|
ld->win_offset = prev_in_tree(ld, ld->win_offset);
|
|
else
|
|
ld->win_pos--;
|
|
ld->current_pos = prev_in_tree(ld, ld->current_pos);
|
|
}
|
|
|
|
ld->delete_item(item);
|
|
|
|
rd.ld = ld;
|
|
rd.dlg = dlg;
|
|
rd.n = 0;
|
|
|
|
ld->modified = 1;
|
|
draw_to_window(dlg->win, redraw_list, &rd);
|
|
}
|
|
|
|
|
|
/* when delete folder is confirmed adjusts current_pos and calls delete function */
|
|
static void delete_folder_recursively(void *data)
|
|
{
|
|
struct ve_skodarne_je_jeste_vetsi_narez *skd = (struct ve_skodarne_je_jeste_vetsi_narez *)data;
|
|
struct list_description *ld = skd->ld;
|
|
struct list *item = skd->item;
|
|
struct dialog_data *dlg = skd->dlg;
|
|
struct redraw_data rd;
|
|
struct list *i, *j;
|
|
int depth;
|
|
|
|
for (i = list_next(item), depth = item->depth; i != ld->list && i->depth > depth; ) {
|
|
j = i;
|
|
i = list_next(i);
|
|
ld->delete_item(j);
|
|
}
|
|
|
|
/* strong premise: we can't delete head of the list */
|
|
if (list_next(ld->current_pos) != ld->list) {
|
|
if (ld->current_pos == ld->win_offset) ld->win_offset = list_next(ld->current_pos);
|
|
ld->current_pos = list_next(ld->current_pos);
|
|
} else { /* last item */
|
|
if (!ld->win_pos) /* only one line on the screen */
|
|
ld->win_offset = prev_in_tree(ld, ld->win_offset);
|
|
else
|
|
ld->win_pos--;
|
|
ld->current_pos = prev_in_tree(ld, ld->current_pos);
|
|
}
|
|
|
|
ld->delete_item(item);
|
|
|
|
rd.ld = ld;
|
|
rd.dlg = dlg;
|
|
rd.n = 0;
|
|
|
|
ld->modified = 1;
|
|
draw_to_window(dlg->win, redraw_list, &rd);
|
|
}
|
|
|
|
|
|
/* tests if directory is emty */
|
|
static int is_empty_dir(struct list_description *ld, struct list *dir)
|
|
{
|
|
if (!ld->type) return 1; /* flat list */
|
|
if (!(dir->type & 1)) return 1; /* not a directory */
|
|
|
|
return list_next(dir)->depth <= dir->depth; /* head depth is -1 */
|
|
}
|
|
|
|
|
|
/* delete dialog */
|
|
static int list_item_delete(struct dialog_data *dlg,struct dialog_item_data *useless)
|
|
{
|
|
struct terminal *term=dlg->win->term;
|
|
struct list_description *ld=(struct list_description*)(dlg->dlg->udata2);
|
|
struct list *item=ld->current_pos;
|
|
unsigned char *txt;
|
|
struct ve_skodarne_je_jeste_vetsi_narez *narez;
|
|
|
|
if (item==ld->list||list_empty(item->list_entry))return 0; /* head or empty list */
|
|
|
|
narez=mem_alloc(sizeof(struct ve_skodarne_je_jeste_vetsi_narez));
|
|
narez->ld=ld;narez->item=item;narez->dlg=dlg;
|
|
|
|
txt=ld->type_item(term, item,0);
|
|
if (!txt)
|
|
{
|
|
txt = stracpy(cast_uchar "");
|
|
}
|
|
|
|
if ((item->type)&1) /* folder */
|
|
{
|
|
if (!is_empty_dir(ld,item))
|
|
msg_box(
|
|
term, /* terminal */
|
|
getml(txt,narez,NULL), /* blocks to free */
|
|
TEXT_(T_DELETE_FOLDER), /* title */
|
|
AL_CENTER, /* alignment */
|
|
TEXT_(T_FOLDER),cast_uchar " \"",txt,cast_uchar "\" ",TEXT_(T_NOT_EMPTY_SURE_DELETE),MSG_BOX_END, /* text */
|
|
(void *)narez, /* data for ld->delete_item */
|
|
2, /* # of buttons */
|
|
TEXT_(T_NO),msg_box_null,B_ESC, /* button1 */
|
|
TEXT_(T_YES),delete_folder_recursively,B_ENTER /* button2 */
|
|
);
|
|
else
|
|
msg_box(
|
|
term, /* terminal */
|
|
getml(txt,narez,NULL), /* blocks to free */
|
|
TEXT_(T_DELETE_FOLDER), /* title */
|
|
AL_CENTER, /* alignment */
|
|
TEXT_(T_SURE_DELETE),cast_uchar " ",TEXT_(T_fOLDER),cast_uchar " \"",txt,cast_uchar "\"?",MSG_BOX_END, /* null-terminated text */
|
|
(void *)narez, /* data for ld->delete_item */
|
|
2, /* # of buttons */
|
|
TEXT_(T_YES),delete_ok,B_ENTER, /* button1 */
|
|
TEXT_(T_NO),msg_box_null,B_ESC /* button2 */
|
|
);
|
|
}
|
|
else /* item */
|
|
msg_box(
|
|
term, /* terminal */
|
|
getml(txt,narez,NULL), /* blocks to free */
|
|
TEXT_(ld->delete_dialog_title), /* title */
|
|
AL_CENTER, /* alignment */
|
|
TEXT_(T_SURE_DELETE),cast_uchar " ",TEXT_(ld->item_description),cast_uchar " \"",txt,cast_uchar "\"?",MSG_BOX_END, /* null-terminated text */
|
|
(void *)narez, /* data for ld->delete_item */
|
|
2, /* # of buttons */
|
|
TEXT_(T_YES),delete_ok,B_ENTER, /* button1 */
|
|
TEXT_(T_NO),msg_box_null,B_ESC /* button2 */
|
|
);
|
|
return 0;
|
|
}
|
|
|
|
static void redraw_list_element(struct terminal *term, struct dialog_data *dlg, int y, int w, struct list_description *ld, struct list *l)
|
|
{
|
|
struct list *lx;
|
|
unsigned char *xp;
|
|
int xd;
|
|
unsigned char *txt;
|
|
int x=0;
|
|
unsigned char color = 0;
|
|
long bgcolor = 0, fgcolor = 0;
|
|
int b;
|
|
unsigned char element;
|
|
|
|
if (!F) {
|
|
color = l == ld->current_pos ? COLOR_MENU_SELECTED : COLOR_MENU_TEXT;
|
|
}
|
|
#ifdef G
|
|
else {
|
|
struct rect r;
|
|
r.x1 = dlg->x + DIALOG_LB;
|
|
r.x2 = dlg->x + DIALOG_LB + w;
|
|
r.y1 = y;
|
|
r.y2 = y + G_BFU_FONT_SIZE;
|
|
if (dlg->s) exclude_rect_from_set(&dlg->s, &r);
|
|
if (!do_rects_intersect(&r, &term->dev->clip))
|
|
return;
|
|
bgcolor = l == ld->current_pos ? bfu_fg_color : bfu_bg_color;
|
|
fgcolor = l == ld->current_pos ? bfu_bg_color : bfu_fg_color;
|
|
}
|
|
#endif
|
|
|
|
txt = ld->type_item(term, l, 1);
|
|
if (!txt) {
|
|
txt = stracpy(cast_uchar "");
|
|
}
|
|
|
|
/* everything except head */
|
|
|
|
if (l != ld->list) {
|
|
switch (ld->type) {
|
|
case 0:
|
|
element = BFU_ELEMENT_TEE;
|
|
if (list_next(l) == ld->list)
|
|
element = BFU_ELEMENT_L;
|
|
x += draw_bfu_element(term, dlg->x + DIALOG_LB, y, color, bgcolor, fgcolor, element, l->type & 4);
|
|
break;
|
|
case 1:
|
|
xp = mem_alloc(l->depth + 1);
|
|
memset(xp, 0, l->depth + 1);
|
|
xd = l->depth + 1;
|
|
for (lx = list_next(l); lx != ld->list; lx = list_next(lx)) {
|
|
if (lx->depth < xd) {
|
|
xd = lx->depth;
|
|
xp[xd] = 1;
|
|
if (!xd) break;
|
|
}
|
|
}
|
|
for (b = 0; b < l->depth; b++)
|
|
x += draw_bfu_element(term, dlg->x + DIALOG_LB+x, y, color, bgcolor, fgcolor, xp[b] ? BFU_ELEMENT_PIPE : BFU_ELEMENT_EMPTY, 0);
|
|
if (l->depth >= 0) { /* everything except head */
|
|
int o = xp[l->depth];
|
|
switch (l->type & 1) {
|
|
case 0: /* item */
|
|
element = o ? BFU_ELEMENT_TEE : BFU_ELEMENT_L;
|
|
break;
|
|
|
|
case 1: /* directory */
|
|
if (l->type & 2) {
|
|
element = o ? BFU_ELEMENT_OPEN_DOWN : BFU_ELEMENT_OPEN;
|
|
} else {
|
|
element = o ? BFU_ELEMENT_CLOSED_DOWN : BFU_ELEMENT_CLOSED;
|
|
}
|
|
break;
|
|
|
|
default: /* this should never happen */
|
|
internal_error("=8-Q lunacy level too high! Call "BOHNICE".\n");
|
|
element = BFU_ELEMENT_EMPTY;
|
|
|
|
}
|
|
x += draw_bfu_element(term, dlg->x + DIALOG_LB + x, y, color, bgcolor, fgcolor, element, l->type & 4);
|
|
}
|
|
mem_free(xp);
|
|
break;
|
|
default:
|
|
internal_error(
|
|
"Invalid list description type.\n"
|
|
"Somebody's probably shooting into memory.\n"
|
|
"_______________\n"
|
|
"`--|_____|--|___ `\\\n"
|
|
" \" \\___\\\n");
|
|
}
|
|
}
|
|
|
|
if (!F) {
|
|
print_text(term, dlg->x + x + DIALOG_LB, y, w-x, txt, color);
|
|
x+=cp_len(term_charset(term), txt);
|
|
fill_area(term, dlg->x+DIALOG_LB+x, y, w-x, 1, ' ', 0);
|
|
set_line_color(term, dlg->x + DIALOG_LB + x, y, w-x, color);
|
|
}
|
|
#ifdef G
|
|
else {
|
|
struct rect old_area;
|
|
struct style *stl = l == ld->current_pos ? bfu_style_wb : bfu_style_bw;
|
|
|
|
restrict_clip_area(term->dev, &old_area, dlg->x + x + DIALOG_LB, y, dlg->x + DIALOG_LB + w, y + G_BFU_FONT_SIZE);
|
|
g_print_text(term->dev, dlg->x + x + DIALOG_LB, y, stl, txt, NULL);
|
|
x += g_text_width(stl, txt);
|
|
drv->fill_area(term->dev, dlg->x + DIALOG_LB + x, y, dlg->x + DIALOG_LB + w, y + G_BFU_FONT_SIZE, bgcolor);
|
|
set_clip_area(term->dev, &old_area);
|
|
}
|
|
#endif
|
|
mem_free(txt);
|
|
}
|
|
|
|
/* redraws list */
|
|
static void redraw_list(struct terminal *term, void *bla)
|
|
{
|
|
struct redraw_data* rd = (struct redraw_data *)bla;
|
|
struct list_description *ld = rd->ld;
|
|
struct dialog_data *dlg = rd->dlg;
|
|
int y, a;
|
|
struct list *l;
|
|
int w = dlg->xw - 2 * DIALOG_LB - (F ? sirka_scrollovadla : 0);
|
|
y = dlg->y + DIALOG_TB;
|
|
|
|
#ifdef G
|
|
if (F) {
|
|
int total = get_total_items(ld);
|
|
int visible = get_visible_items(ld);
|
|
int pos = get_scroll_pos(ld);
|
|
draw_vscroll_bar(term->dev, dlg->x + DIALOG_LB + w + G_SCROLL_BAR_WIDTH, y, G_BFU_FONT_SIZE * ld->n_items, total, visible, pos);
|
|
if (dlg->s) exclude_from_set(&dlg->s, dlg->x + DIALOG_LB + w + G_SCROLL_BAR_WIDTH, y, dlg->x + DIALOG_LB + w + sirka_scrollovadla, y + G_BFU_FONT_SIZE * ld->n_items);
|
|
}
|
|
#endif
|
|
|
|
for (a = 0, l = ld->win_offset; a < ld->n_items; ) {
|
|
redraw_list_element(term, dlg, y, w, ld, l);
|
|
l = next_in_tree(ld, l);
|
|
a++;
|
|
y += gf_val(1, G_BFU_FONT_SIZE);
|
|
if (l == ld->list) break;
|
|
}
|
|
if (!F) fill_area(term, dlg->x + DIALOG_LB, y, w, ld->n_items-a, ' ', COLOR_MENU_TEXT);
|
|
#ifdef G
|
|
else {
|
|
drv->fill_area(term->dev, dlg->x + DIALOG_LB, y, dlg->x + DIALOG_LB + w, dlg->y + DIALOG_TB + ld->n_items * G_BFU_FONT_SIZE, dip_get_color_sRGB(G_BFU_BG_COLOR));
|
|
if (dlg->s) exclude_from_set(&dlg->s, dlg->x + DIALOG_LB, y, dlg->x + DIALOG_LB + w, dlg->y + DIALOG_TB + ld->n_items * G_BFU_FONT_SIZE);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
|
|
/* moves cursor from old position to a new one */
|
|
/* direction: -1=old is previous, +1=old is next */
|
|
static void redraw_list_line(struct terminal *term, void *bla)
|
|
{
|
|
struct redraw_data *rd = (struct redraw_data *)bla;
|
|
struct list_description *ld = rd->ld;
|
|
struct dialog_data *dlg = rd->dlg;
|
|
int direction = rd->n;
|
|
int w = dlg->xw - 2 * DIALOG_LB - (F ? sirka_scrollovadla : 0);
|
|
int y = dlg->y + DIALOG_TB + gf_val(ld->win_pos, ld->win_pos * G_BFU_FONT_SIZE);
|
|
struct list *l;
|
|
|
|
redraw_list_element(term, dlg, y, w, ld, ld->current_pos);
|
|
if (!F && (!term->spec->block_cursor || term->spec->braille)) {
|
|
set_cursor(term, dlg->x + DIALOG_LB, y, dlg->x + DIALOG_LB, y);
|
|
}
|
|
y += gf_val(direction, direction*G_BFU_FONT_SIZE);
|
|
switch (direction) {
|
|
case 0:
|
|
l = NULL;
|
|
break;
|
|
case 1:
|
|
l = next_in_tree(ld, ld->current_pos);
|
|
break;
|
|
case -1:
|
|
l = prev_in_tree(ld, ld->current_pos);
|
|
break;
|
|
default:
|
|
internal_error("redraw_list_line: invalid direction %d", direction);
|
|
l = NULL;
|
|
break;
|
|
}
|
|
if (l) redraw_list_element(term, dlg, y, w, ld, l);
|
|
}
|
|
|
|
|
|
/* like redraw_list, but scrolls window, prints new line to top/bottom */
|
|
/* in text mode calls redraw list */
|
|
/* direction: -1=up, 1=down */
|
|
static void scroll_list(struct terminal *term, void *bla)
|
|
{
|
|
#ifdef G
|
|
struct redraw_data *rd = (struct redraw_data *)bla;
|
|
struct list_description *ld = rd->ld;
|
|
struct dialog_data *dlg = rd->dlg;
|
|
int direction = rd->n;
|
|
#endif
|
|
|
|
if (!F) {
|
|
redraw_list(term, bla);
|
|
}
|
|
#ifdef G
|
|
else {
|
|
struct rect old_area;
|
|
struct graphics_device *dev = term->dev;
|
|
int w = dlg->xw - 2 * DIALOG_LB - sirka_scrollovadla;
|
|
int y = dlg->y + DIALOG_TB;
|
|
int top = 0, bottom = 0;
|
|
|
|
switch (direction) {
|
|
case 1: /* down */
|
|
top = G_BFU_FONT_SIZE;
|
|
break;
|
|
|
|
case -1: /* up */
|
|
bottom = -G_BFU_FONT_SIZE;
|
|
break;
|
|
|
|
default:
|
|
internal_error("Wrong direction %d in function scroll_list.\n",direction);
|
|
}
|
|
|
|
restrict_clip_area(term->dev, &old_area, dlg->x + DIALOG_LB, y + top, dlg->x + DIALOG_LB + w, y + bottom + G_BFU_FONT_SIZE * ld->n_items);
|
|
if (drv->flags & GD_DONT_USE_SCROLL && overwrite_instead_of_scroll) {
|
|
redraw_list(term, bla);
|
|
} else {
|
|
int j;
|
|
struct rect_set *rs = g_scroll(dev, 0, top + bottom);
|
|
for (j = 0; j < rs->m; j++) {
|
|
struct rect *r = &rs->r[j];
|
|
struct rect clip1;
|
|
restrict_clip_area(term->dev, &clip1, r->x1, r->y1, r->x2, r->y2);
|
|
redraw_list(term, bla);
|
|
set_clip_area(term->dev, &clip1);
|
|
}
|
|
mem_free(rs);
|
|
}
|
|
set_clip_area(term->dev, &old_area);
|
|
|
|
/* redraw scroll bar */
|
|
{
|
|
int total = get_total_items(ld);
|
|
int visible = get_visible_items(ld);
|
|
int pos = get_scroll_pos(ld);
|
|
draw_vscroll_bar(term->dev, dlg->x + DIALOG_LB + w + G_SCROLL_BAR_WIDTH, y, G_BFU_FONT_SIZE * ld->n_items, total, visible, pos);
|
|
if (dlg->s) exclude_from_set(&dlg->s, dlg->x + DIALOG_LB + w + G_SCROLL_BAR_WIDTH, y, dlg->x + DIALOG_LB + w + sirka_scrollovadla, y + G_BFU_FONT_SIZE * ld->n_items);
|
|
}
|
|
|
|
}
|
|
#endif
|
|
}
|
|
|
|
static int list_item_mark(struct dialog_data *dlg, struct dialog_item_data *useless)
|
|
{
|
|
struct list_description *ld = (struct list_description *)dlg->dlg->udata2;
|
|
static struct redraw_data rd;
|
|
|
|
rd.ld = ld;
|
|
rd.dlg = dlg;
|
|
rd.n = 0;
|
|
|
|
if (ld->current_pos != ld->list) ld->current_pos->type ^= 4;
|
|
if (next_in_tree(ld, ld->current_pos) == ld->list) /* already at the bottom */
|
|
{
|
|
draw_to_window(dlg->win, redraw_list_line, &rd);
|
|
return 0;
|
|
}
|
|
rd.n = -1;
|
|
ld->current_pos = next_in_tree(ld, ld->current_pos);
|
|
ld->win_pos++;
|
|
if (ld->win_pos > ld->n_items - 1) /* scroll down */
|
|
{
|
|
ld->win_pos = ld->n_items - 1;
|
|
ld->win_offset = next_in_tree(ld, ld->win_offset);
|
|
draw_to_window(dlg->win, scroll_list, &rd);
|
|
}
|
|
draw_to_window(dlg->win, redraw_list_line, &rd);
|
|
return 0;
|
|
}
|
|
|
|
|
|
static void list_find_next(struct redraw_data *rd, int direction)
|
|
{
|
|
struct list_description *ld=rd->ld;
|
|
struct dialog_data *dlg=rd->dlg;
|
|
struct session *ses=(struct session *)(dlg->dlg->udata);
|
|
struct list* item;
|
|
|
|
if (!ld->search_word) {msg_box(ses->term, NULL, TEXT_(T_SEARCH), AL_CENTER, TEXT_(T_NO_PREVIOUS_SEARCH), MSG_BOX_END, NULL, 1, TEXT_(T_CANCEL), msg_box_null, B_ENTER | B_ESC); return;}
|
|
|
|
if ((item=ld->find_item(ld->current_pos,ld->search_word,direction)))
|
|
{
|
|
struct list *l;
|
|
ld->current_pos=item;
|
|
ld->win_offset=item;
|
|
ld->win_pos=0;
|
|
if (ld->type)
|
|
for (l=item;l->depth>=0;l=l->fotr)
|
|
if (l!=item) l->type|=2;
|
|
|
|
draw_to_window(dlg->win,redraw_list,rd);
|
|
if (!F) if (!ses->term->spec->block_cursor || ses->term->spec->braille) set_cursor(ses->term, dlg->x + DIALOG_LB, dlg->y+DIALOG_TB+ld->win_pos, dlg->x + DIALOG_LB, dlg->y+DIALOG_TB+ld->win_pos);
|
|
}
|
|
else
|
|
msg_box(ses->term, NULL, TEXT_(T_SEARCH), AL_CENTER, TEXT_(T_SEARCH_STRING_NOT_FOUND), MSG_BOX_END, NULL, 1, TEXT_(T_CANCEL), msg_box_null, B_ENTER | B_ESC);
|
|
}
|
|
|
|
static void list_search_for_back(void *rd_, unsigned char *str)
|
|
{
|
|
struct redraw_data *rd = (struct redraw_data *)rd_;
|
|
struct list_description *ld = rd->ld;
|
|
|
|
if (!*str) return;
|
|
if (!ld->open) return;
|
|
|
|
if (ld->search_word) mem_free(ld->search_word);
|
|
ld->search_word = to_utf8_upcase(str, term_charset(rd->dlg->win->term));
|
|
ld->search_direction = -1;
|
|
|
|
list_find_next(rd, ld->search_direction);
|
|
}
|
|
|
|
static void list_search_for(void *rd_, unsigned char *str)
|
|
{
|
|
struct redraw_data *rd = (struct redraw_data *)rd_;
|
|
struct list_description *ld = rd->ld;
|
|
|
|
if (!*str) return;
|
|
if (!ld->open) return;
|
|
|
|
if (ld->search_word) mem_free(ld->search_word);
|
|
ld->search_word = to_utf8_upcase(str, term_charset(rd->dlg->win->term));
|
|
ld->search_direction = 1;
|
|
|
|
list_find_next(rd, ld->search_direction);
|
|
}
|
|
|
|
static void list_edit_toggle(struct dialog_data *dlg, struct list_description *ld)
|
|
{
|
|
static struct redraw_data rd;
|
|
ld->current_pos->type^=2;
|
|
if (!(ld->current_pos->type&2))unselect_in_folder(ld, ld->current_pos);
|
|
rd.ld=ld;
|
|
rd.dlg=dlg;
|
|
rd.n=0;
|
|
draw_to_window(dlg->win,redraw_list,&rd);
|
|
draw_to_window(dlg->win,redraw_list_line,&rd); /* set cursor */
|
|
}
|
|
|
|
static int list_event_handler(struct dialog_data *dlg, struct links_event *ev)
|
|
{
|
|
struct list_description *ld=(struct list_description*)(dlg->dlg->udata2);
|
|
static struct redraw_data rd;
|
|
struct session *ses=(struct session *)(dlg->dlg->udata);
|
|
|
|
rd.ld=ld;
|
|
rd.dlg=dlg;
|
|
rd.n=0;
|
|
|
|
switch ((int)ev->ev)
|
|
{
|
|
case EV_KBD:
|
|
if (ev->y & KBD_PASTING) break;
|
|
if (ld->type==1) /* tree list */
|
|
{
|
|
if (ev->x==' ') /* toggle folder */
|
|
{
|
|
if (!((ld->current_pos->type)&1))return EVENT_PROCESSED; /* item */
|
|
|
|
list_edit_toggle(dlg, ld);
|
|
return EVENT_PROCESSED;
|
|
}
|
|
if (ev->x=='+'||ev->x=='=') /* open folder */
|
|
{
|
|
if (!((ld->current_pos->type)&1))return EVENT_PROCESSED; /* item */
|
|
if ((ld->current_pos->type)&2)return EVENT_PROCESSED; /* already open */
|
|
list_edit_toggle(dlg, ld);
|
|
return EVENT_PROCESSED;
|
|
}
|
|
if (ev->x=='-') /* close folder */
|
|
{
|
|
if (!((ld->current_pos->type)&1))return EVENT_PROCESSED; /* item */
|
|
if (!((ld->current_pos->type)&2))return EVENT_PROCESSED; /* already closed */
|
|
list_edit_toggle(dlg, ld);
|
|
return EVENT_PROCESSED;
|
|
}
|
|
}
|
|
if (ev->x == '/' || (ev->x == KBD_FIND && !(ev->y & (KBD_SHIFT | KBD_CTRL | KBD_ALT)))) /* search forward */
|
|
{
|
|
struct redraw_data *r;
|
|
|
|
r=mem_alloc(sizeof(struct redraw_data));
|
|
r->ld=ld;
|
|
r->dlg=dlg;
|
|
|
|
input_field(ses->term, getml(r,NULL), TEXT_(T_SEARCH), TEXT_(T_SEARCH_FOR_TEXT), r, ld->search_history, MAX_INPUT_URL_LEN, cast_uchar "", 0, 0, NULL, 2, TEXT_(T_OK), list_search_for, TEXT_(T_CANCEL), input_field_null);
|
|
return EVENT_PROCESSED;
|
|
}
|
|
if (ev->x == '?' || (ev->x == KBD_FIND && ev->y & (KBD_SHIFT | KBD_CTRL | KBD_ALT))) /* search back */
|
|
{
|
|
struct redraw_data *r;
|
|
|
|
r=mem_alloc(sizeof(struct redraw_data));
|
|
r->ld=ld;
|
|
r->dlg=dlg;
|
|
|
|
input_field(ses->term, getml(r,NULL), TEXT_(T_SEARCH_BACK), TEXT_(T_SEARCH_FOR_TEXT), r, ld->search_history, MAX_INPUT_URL_LEN, cast_uchar "", 0, 0, NULL, 2, TEXT_(T_OK), list_search_for_back, TEXT_(T_CANCEL), input_field_null);
|
|
return EVENT_PROCESSED;
|
|
}
|
|
if ((ev->x == 'n' && !(ev->y & KBD_ALT)) || ev->x == KBD_REDO) /* find next */
|
|
{
|
|
list_find_next(&rd, ld->search_direction);
|
|
return EVENT_PROCESSED;
|
|
}
|
|
if ((ev->x == 'N' && !(ev->y & KBD_ALT)) || ev->x == KBD_UNDO) /* find prev */
|
|
{
|
|
list_find_next(&rd, - ld->search_direction);
|
|
return EVENT_PROCESSED;
|
|
}
|
|
if (ev->x == KBD_UP)
|
|
{
|
|
if (ld->current_pos==ld->list) goto kbd_up_redraw_exit; /* already on the top */
|
|
ld->current_pos=prev_in_tree(ld,ld->current_pos);
|
|
ld->win_pos--;
|
|
rd.n=1;
|
|
if (ld->win_pos<0) /* scroll up */
|
|
{
|
|
ld->win_pos=0;
|
|
ld->win_offset=prev_in_tree(ld,ld->win_offset);
|
|
draw_to_window(dlg->win,scroll_list,&rd);
|
|
}
|
|
kbd_up_redraw_exit:
|
|
draw_to_window(dlg->win,redraw_list_line,&rd);
|
|
return EVENT_PROCESSED;
|
|
}
|
|
if (ev->x == 'i' || ev->x == '*' || ev->x == '8' || ev->x == KBD_INS || ev->x == KBD_SELECT)
|
|
{
|
|
list_item_mark(dlg, NULL);
|
|
return EVENT_PROCESSED;
|
|
}
|
|
if (ev->x == KBD_DOWN)
|
|
{
|
|
if (next_in_tree(ld,ld->current_pos)==ld->list) goto kbd_down_redraw_exit; /* already at the bottom */
|
|
ld->current_pos=next_in_tree(ld,ld->current_pos);
|
|
ld->win_pos++;
|
|
rd.n=-1;
|
|
if (ld->win_pos>ld->n_items-1) /* scroll down */
|
|
{
|
|
ld->win_pos=ld->n_items-1;
|
|
ld->win_offset=next_in_tree(ld,ld->win_offset);
|
|
draw_to_window(dlg->win,scroll_list,&rd);
|
|
}
|
|
kbd_down_redraw_exit:
|
|
draw_to_window(dlg->win,redraw_list_line,&rd);
|
|
return EVENT_PROCESSED;
|
|
}
|
|
if (ev->x == KBD_HOME || (upcase(ev->x) == 'A' && ev->y & KBD_CTRL))
|
|
{
|
|
if (ld->current_pos==ld->list) goto kbd_home_redraw_exit; /* already on the top */
|
|
ld->win_offset=ld->list;
|
|
ld->current_pos=ld->win_offset;
|
|
ld->win_pos=0;
|
|
rd.n=0;
|
|
draw_to_window(dlg->win,redraw_list,&rd);
|
|
kbd_home_redraw_exit:
|
|
draw_to_window(dlg->win,redraw_list_line,&rd); /* set cursor */
|
|
return EVENT_PROCESSED;
|
|
}
|
|
if (ev->x == KBD_END || (upcase(ev->x) == 'E' && ev->y & KBD_CTRL))
|
|
{
|
|
int a;
|
|
|
|
if (ld->current_pos==prev_in_tree(ld,ld->list)) goto kbd_end_redraw_exit; /* already on the top */
|
|
ld->win_offset=prev_in_tree(ld,ld->list);
|
|
for (a=1;a<ld->n_items&&ld->win_offset!=ld->list;a++)
|
|
ld->win_offset=prev_in_tree(ld,ld->win_offset);
|
|
ld->current_pos=prev_in_tree(ld,ld->list);
|
|
ld->win_pos=a-1;
|
|
rd.n=0;
|
|
draw_to_window(dlg->win,redraw_list,&rd);
|
|
kbd_end_redraw_exit:
|
|
draw_to_window(dlg->win,redraw_list_line,&rd); /* set cursor */
|
|
return EVENT_PROCESSED;
|
|
}
|
|
if (ev->x == KBD_PAGE_UP || (upcase(ev->x) == 'B' && ev->y & KBD_CTRL))
|
|
{
|
|
int a;
|
|
|
|
if (ld->current_pos==ld->list) goto kbd_page_up_redraw_exit; /* already on the top */
|
|
for (a=0;a<ld->n_items&&ld->win_offset!=ld->list;a++)
|
|
{
|
|
ld->win_offset=prev_in_tree(ld,ld->win_offset);
|
|
ld->current_pos=prev_in_tree(ld,ld->current_pos);
|
|
}
|
|
if (a<ld->n_items){ld->current_pos=ld->win_offset;ld->win_pos=0;}
|
|
rd.n=0;
|
|
draw_to_window(dlg->win,redraw_list,&rd);
|
|
kbd_page_up_redraw_exit:
|
|
draw_to_window(dlg->win,redraw_list_line,&rd); /* set cursor */
|
|
return EVENT_PROCESSED;
|
|
}
|
|
if (ev->x == KBD_PAGE_DOWN || (upcase(ev->x) == 'F' && ev->y & KBD_CTRL))
|
|
{
|
|
int a;
|
|
struct list*p=ld->win_offset;
|
|
|
|
if (ld->current_pos==prev_in_tree(ld,ld->list)) goto kbd_page_down_redraw_exit; /* already on the bottom */
|
|
for (a=0;a<ld->n_items&&ld->list!=next_in_tree(ld,p);a++)
|
|
p=next_in_tree(ld,p);
|
|
if (a<ld->n_items) /* already last screen */
|
|
{
|
|
ld->current_pos=p;
|
|
ld->win_pos=a;
|
|
rd.n=0;
|
|
draw_to_window(dlg->win,redraw_list,&rd);
|
|
draw_to_window(dlg->win,redraw_list_line,&rd); /* set cursor */
|
|
return EVENT_PROCESSED;
|
|
}
|
|
/* here is whole screen only - the window was full before pressing the page-down key */
|
|
/* p is pointing behind last item of the window (behind last visible item in the window) */
|
|
for (a=0;a<ld->n_items&&p!=ld->list;a++)
|
|
{
|
|
ld->win_offset=next_in_tree(ld,ld->win_offset);
|
|
ld->current_pos=next_in_tree(ld,ld->current_pos);
|
|
p=next_in_tree(ld,p);
|
|
}
|
|
if (a<ld->n_items){ld->current_pos=prev_in_tree(ld,ld->list);ld->win_pos=ld->n_items-1;}
|
|
rd.n=0;
|
|
draw_to_window(dlg->win,redraw_list,&rd);
|
|
kbd_page_down_redraw_exit:
|
|
draw_to_window(dlg->win,redraw_list_line,&rd); /* set cursor */
|
|
return EVENT_PROCESSED;
|
|
}
|
|
break;
|
|
|
|
case EV_MOUSE:
|
|
/* toggle select item */
|
|
if ((ev->b & BM_ACT) == B_DOWN && (ev->b & BM_BUTT) == B_RIGHT) {
|
|
int n,a;
|
|
struct list *l=ld->win_offset;
|
|
|
|
last_mouse_y=ev->y;
|
|
|
|
if (
|
|
(ev->y)<(dlg->y+DIALOG_TB)||
|
|
(ev->y)>=(dlg->y+DIALOG_TB+gf_val(ld->n_items,G_BFU_FONT_SIZE*(ld->n_items)))||
|
|
(ev->x)<(dlg->x+DIALOG_LB)||
|
|
(ev->x)>(dlg->x+dlg->xw-DIALOG_LB-(F?sirka_scrollovadla:0))
|
|
)break; /* out of the dialog */
|
|
|
|
n=(ev->y-dlg->y-DIALOG_TB)/gf_val(1,G_BFU_FONT_SIZE);
|
|
for (a=0;a<n;a++)
|
|
{
|
|
struct list *l1;
|
|
l1=next_in_tree(ld,l); /* current item under the mouse pointer */
|
|
if (l1==ld->list)goto break2;
|
|
else l=l1;
|
|
}
|
|
/*a=ld->type?((l->depth)>=0?(l->depth)+1:0):(l->depth>=0);*/
|
|
|
|
l->type^=4;
|
|
ld->current_pos=l;
|
|
ld->win_pos=n;
|
|
rd.n=0;
|
|
draw_to_window(dlg->win,redraw_list,&rd);
|
|
draw_to_window(dlg->win,redraw_list_line,&rd); /* set cursor */
|
|
return EVENT_PROCESSED;
|
|
}
|
|
/* click on item */
|
|
if (((ev->b & BM_ACT) == B_DOWN || (ev->b & BM_ACT) == B_DRAG) && (ev->b & BM_BUTT) == B_LEFT) {
|
|
int n,a;
|
|
struct list *l=ld->win_offset;
|
|
|
|
last_mouse_y=ev->y;
|
|
|
|
if (
|
|
(ev->y)<(dlg->y+DIALOG_TB)||
|
|
(ev->y)>=(dlg->y+DIALOG_TB+gf_val(ld->n_items,G_BFU_FONT_SIZE*(ld->n_items)))||
|
|
(ev->x)<(dlg->x+DIALOG_LB)||
|
|
(ev->x)>(dlg->x+dlg->xw-DIALOG_LB-(F?sirka_scrollovadla:0))
|
|
)goto skip_item_click; /* out of the dialog */
|
|
|
|
n=(ev->y-dlg->y-DIALOG_TB)/gf_val(1,G_BFU_FONT_SIZE);
|
|
for (a=0;a<n;a++)
|
|
{
|
|
struct list *l1;
|
|
l1=next_in_tree(ld,l); /* current item under the mouse pointer */
|
|
if (l1==ld->list) {
|
|
n=a;
|
|
break;
|
|
}
|
|
else l=l1;
|
|
}
|
|
a=ld->type?((l->depth)>=0?(l->depth)+1:0):(l->depth>=0);
|
|
|
|
ld->current_pos=l;
|
|
|
|
/* clicked on directory graphical stuff */
|
|
if ((ev->b & BM_ACT) == B_DOWN && ld->type && ev->x < (dlg->x + DIALOG_LB + a * BFU_ELEMENT_WIDTH) && (l->type & 1)) {
|
|
l->type^=2;
|
|
if (!(l->type&2))unselect_in_folder(ld, ld->current_pos);
|
|
}
|
|
ld->win_pos=n;
|
|
rd.n=0;
|
|
draw_to_window(dlg->win,redraw_list,&rd);
|
|
draw_to_window(dlg->win,redraw_list_line,&rd); /* set cursor */
|
|
return EVENT_PROCESSED;
|
|
}
|
|
/* scroll with the bar */
|
|
skip_item_click:
|
|
#ifdef G
|
|
if (F && (((ev->b & BM_ACT) == B_DRAG || (ev->b & BM_ACT) == B_DOWN || (ev->b & BM_ACT) == B_UP) && (ev->b & BM_BUTT) == B_LEFT)) {
|
|
int total=get_total_items(ld);
|
|
int scroll_pos;
|
|
int redraw_all;
|
|
int rep = 0;
|
|
long delta;
|
|
long h=ld->n_items*G_BFU_FONT_SIZE;
|
|
|
|
if (
|
|
(ev->y)<(dlg->y+DIALOG_TB)||
|
|
(ev->y)>=(dlg->y+DIALOG_TB+G_BFU_FONT_SIZE*(ld->n_items))||
|
|
(ev->x)<(dlg->x+dlg->xw-DIALOG_LB-G_SCROLL_BAR_WIDTH)||
|
|
(ev->x)>(dlg->x+dlg->xw-DIALOG_LB)
|
|
)break; /* out of the dialog */
|
|
|
|
again:
|
|
rep++;
|
|
if (rep > total) return EVENT_PROCESSED;
|
|
scroll_pos=get_scroll_pos(ld);
|
|
delta=(ev->y-dlg->y-DIALOG_TB)*total/h-scroll_pos;
|
|
|
|
last_mouse_y=ev->y;
|
|
|
|
if (delta>0) /* scroll down */
|
|
{
|
|
struct list *lll=find_last_in_window(ld);
|
|
|
|
if (next_in_tree(ld,lll)==ld->list)return EVENT_PROCESSED; /* already at the bottom */
|
|
redraw_all = ld->current_pos != lll;
|
|
ld->current_pos=next_in_tree(ld,lll);
|
|
ld->win_offset=next_in_tree(ld,ld->win_offset);
|
|
ld->win_pos=ld->n_items-1;
|
|
rd.n=-1;
|
|
if (!redraw_all) {
|
|
draw_to_window(dlg->win,scroll_list,&rd);
|
|
draw_to_window(dlg->win,redraw_list_line,&rd);
|
|
} else {
|
|
draw_to_window(dlg->win,redraw_list,&rd);
|
|
}
|
|
goto again;
|
|
}
|
|
if (delta<0) /* scroll up */
|
|
{
|
|
if (ld->win_offset==ld->list)return EVENT_PROCESSED; /* already on the top */
|
|
redraw_all = ld->current_pos != ld->win_offset;
|
|
ld->win_offset=prev_in_tree(ld,ld->win_offset);
|
|
ld->current_pos=ld->win_offset;
|
|
ld->win_pos=0;
|
|
rd.n=+1;
|
|
if (!redraw_all) {
|
|
draw_to_window(dlg->win,scroll_list,&rd);
|
|
draw_to_window(dlg->win,redraw_list_line,&rd);
|
|
} else {
|
|
draw_to_window(dlg->win,redraw_list,&rd);
|
|
}
|
|
goto again;
|
|
}
|
|
return EVENT_PROCESSED;
|
|
|
|
}
|
|
#endif
|
|
if ((ev->b & BM_ACT) == B_DRAG && (ev->b & BM_BUTT) == B_MIDDLE) {
|
|
long delta=(ev->y-last_mouse_y)/MOUSE_SCROLL_DIVIDER;
|
|
|
|
last_mouse_y=ev->y;
|
|
if (delta>0) /* scroll down */
|
|
{
|
|
if (next_in_tree(ld,ld->current_pos)==ld->list)return EVENT_PROCESSED; /* already at the bottom */
|
|
ld->current_pos=next_in_tree(ld,ld->current_pos);
|
|
ld->win_pos++;
|
|
rd.n=-1;
|
|
if (ld->win_pos>ld->n_items-1) /* scroll down */
|
|
{
|
|
ld->win_pos=ld->n_items-1;
|
|
ld->win_offset=next_in_tree(ld,ld->win_offset);
|
|
draw_to_window(dlg->win,scroll_list,&rd);
|
|
}
|
|
draw_to_window(dlg->win,redraw_list_line,&rd);
|
|
}
|
|
if (delta<0) /* scroll up */
|
|
{
|
|
if (ld->current_pos==ld->list)return EVENT_PROCESSED; /* already on the top */
|
|
ld->current_pos=prev_in_tree(ld,ld->current_pos);
|
|
ld->win_pos--;
|
|
rd.n=+1;
|
|
if (ld->win_pos<0) /* scroll up */
|
|
{
|
|
ld->win_pos=0;
|
|
ld->win_offset=prev_in_tree(ld,ld->win_offset);
|
|
draw_to_window(dlg->win,scroll_list,&rd);
|
|
}
|
|
draw_to_window(dlg->win,redraw_list_line,&rd);
|
|
}
|
|
return EVENT_PROCESSED;
|
|
|
|
}
|
|
/* mouse wheel */
|
|
if ((ev->b & BM_ACT) == B_MOVE && ((ev->b & BM_BUTT) == B_WHEELUP || (ev->b & BM_BUTT) == B_WHEELDOWN || (ev->b & BM_BUTT) == B_WHEELDOWN1 || (ev->b & BM_BUTT) == B_WHEELUP1)) {
|
|
int button=(int)ev->b&BM_BUTT;
|
|
last_mouse_y=ev->y;
|
|
|
|
if (button==B_WHEELDOWN||button==B_WHEELDOWN1) /* scroll down */
|
|
{
|
|
if (next_in_tree(ld,ld->current_pos)==ld->list)return EVENT_PROCESSED; /* already at the bottom */
|
|
ld->current_pos=next_in_tree(ld,ld->current_pos);
|
|
ld->win_pos++;
|
|
rd.n=-1;
|
|
if (ld->win_pos>ld->n_items-1) /* scroll down */
|
|
{
|
|
ld->win_pos=ld->n_items-1;
|
|
ld->win_offset=next_in_tree(ld,ld->win_offset);
|
|
draw_to_window(dlg->win,scroll_list,&rd);
|
|
}
|
|
draw_to_window(dlg->win,redraw_list_line,&rd);
|
|
}
|
|
if (button==B_WHEELUP||button==B_WHEELUP1) /* scroll up */
|
|
{
|
|
if (ld->current_pos==ld->list)return EVENT_PROCESSED; /* already on the top */
|
|
ld->current_pos=prev_in_tree(ld,ld->current_pos);
|
|
ld->win_pos--;
|
|
rd.n=+1;
|
|
if (ld->win_pos<0) /* scroll up */
|
|
{
|
|
ld->win_pos=0;
|
|
ld->win_offset=prev_in_tree(ld,ld->win_offset);
|
|
draw_to_window(dlg->win,scroll_list,&rd);
|
|
}
|
|
draw_to_window(dlg->win,redraw_list_line,&rd);
|
|
}
|
|
return EVENT_PROCESSED;
|
|
|
|
}
|
|
break2:
|
|
break;
|
|
|
|
case EV_INIT:
|
|
case EV_RESIZE:
|
|
case EV_REDRAW:
|
|
case EV_ABORT:
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
|
|
}
|
|
return EVENT_NOT_PROCESSED;
|
|
}
|
|
|
|
|
|
/* display function for the list window */
|
|
static void create_list_window_fn(struct dialog_data *dlg)
|
|
{
|
|
struct terminal *term=dlg->win->term;
|
|
struct list_description *ld=(struct list_description*)(dlg->dlg->udata2);
|
|
int min=0;
|
|
int w,rw,y;
|
|
int n_items;
|
|
struct redraw_data rd;
|
|
|
|
int a=7;
|
|
|
|
ld->dlg=dlg;
|
|
if (ld->button_fn)a++; /* user button */
|
|
if (ld->type==1)a++; /* add directory button */
|
|
|
|
y = 0;
|
|
min_buttons_width(term, dlg->items, a, &min);
|
|
|
|
w = term->x * 19 / 20 - 2 * DIALOG_LB;
|
|
if (w<min)w=min;
|
|
if (w>term->x-2*DIALOG_LB)w=term->x-2*DIALOG_LB;
|
|
if (w<5)w=5;
|
|
|
|
rw=0;
|
|
dlg_format_buttons(dlg, NULL, dlg->items, a, 0, &y, w, &rw, AL_CENTER);
|
|
|
|
n_items = term->y - y;
|
|
if (!term->spec->braille)
|
|
n_items -= gf_val(2, 3) * DIALOG_TB + gf_val(2, 2*G_BFU_FONT_SIZE);
|
|
else
|
|
n_items -= 2;
|
|
#ifdef G
|
|
if (F) n_items /= G_BFU_FONT_SIZE;
|
|
#endif
|
|
if (n_items < 2) n_items = 2;
|
|
ld->n_items = n_items;
|
|
|
|
while (ld->win_pos > ld->n_items - 1) {
|
|
ld->current_pos=prev_in_tree(ld,ld->current_pos);
|
|
ld->win_pos--;
|
|
}
|
|
|
|
y += gf_val(ld->n_items,ld->n_items*G_BFU_FONT_SIZE);
|
|
|
|
rw=w;
|
|
dlg->xw=rw+2*DIALOG_LB;
|
|
dlg->yw=y+2*DIALOG_TB;
|
|
center_dlg(dlg);
|
|
draw_dlg(dlg);
|
|
|
|
rd.ld=ld;
|
|
rd.dlg=dlg;
|
|
rd.n=0;
|
|
|
|
draw_to_window(dlg->win,redraw_list,&rd);
|
|
|
|
y=dlg->y+DIALOG_TB+gf_val(ld->n_items+1,(ld->n_items+1)*G_BFU_FONT_SIZE);
|
|
dlg_format_buttons(dlg, term, dlg->items, a, dlg->x+DIALOG_LB, &y, w, &rw, AL_CENTER);
|
|
}
|
|
|
|
|
|
static void close_list_window(struct dialog_data *dlg)
|
|
{
|
|
struct dialog *d=dlg->dlg;
|
|
struct list_description *ld=(struct list_description*)(d->udata2);
|
|
|
|
ld->open=0;
|
|
ld->dlg=NULL;
|
|
if (ld->search_word) mem_free(ld->search_word);
|
|
ld->search_word=NULL;
|
|
if (ld->save) ld->save(d->udata);
|
|
}
|
|
|
|
int test_list_window_in_use(struct list_description *ld, struct terminal *term)
|
|
{
|
|
if (ld->open) {
|
|
if (term)
|
|
msg_box(
|
|
term,
|
|
NULL,
|
|
TEXT_(T_INFO),
|
|
AL_CENTER,
|
|
TEXT_(ld->already_in_use),MSG_BOX_END,
|
|
NULL,
|
|
1,
|
|
TEXT_(T_CANCEL),msg_box_null,B_ENTER|B_ESC
|
|
);
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* dialog->udata2 ... list_description */
|
|
/* dialog->udata ... session */
|
|
int create_list_window(
|
|
struct list_description *ld,
|
|
struct list *list,
|
|
struct terminal *term,
|
|
struct session *ses
|
|
)
|
|
{
|
|
struct dialog *d;
|
|
int a;
|
|
|
|
/* zavodime, zavodime... */
|
|
if (test_list_window_in_use(ld, term))
|
|
return 1;
|
|
ld->open=1;
|
|
|
|
if (!ld->current_pos)
|
|
{
|
|
ld->current_pos=list;
|
|
ld->win_offset=list;
|
|
ld->win_pos=0;
|
|
ld->dlg=NULL;
|
|
}
|
|
|
|
a=8;
|
|
if (ld->button_fn)a++;
|
|
if (ld->type==1)a++;
|
|
|
|
d = mem_calloc(sizeof(struct dialog) + a * sizeof(struct dialog_item));
|
|
|
|
d->title=TEXT_(ld->window_title);
|
|
d->fn=create_list_window_fn;
|
|
d->abort=close_list_window;
|
|
d->handle_event=list_event_handler;
|
|
d->udata=ses;
|
|
d->udata2=ld;
|
|
|
|
a=0;
|
|
|
|
if (ld->button_fn)
|
|
{
|
|
d->items[a].type=D_BUTTON;
|
|
d->items[a].fn=list_item_button;
|
|
d->items[a].text=TEXT_(ld->button);
|
|
a++;
|
|
}
|
|
|
|
if (ld->type==1)
|
|
{
|
|
d->items[a].type=D_BUTTON;
|
|
d->items[a].text=TEXT_(T_FOLDER);
|
|
d->items[a].fn=list_folder_add;
|
|
a++;
|
|
}
|
|
|
|
d->items[a].type=D_BUTTON;
|
|
d->items[a].text=TEXT_(T_ADD);
|
|
d->items[a].fn=list_item_add;
|
|
|
|
d->items[a+1].type=D_BUTTON;
|
|
d->items[a+1].text=TEXT_(T_DELETE);
|
|
d->items[a+1].fn=list_item_delete;
|
|
|
|
d->items[a+2].type=D_BUTTON;
|
|
d->items[a+2].text=TEXT_(T_EDIT);
|
|
d->items[a+2].fn=list_item_edit;
|
|
|
|
d->items[a+3].type=D_BUTTON;
|
|
d->items[a+3].text=TEXT_(T_SELECT);
|
|
d->items[a+3].fn=list_item_mark;
|
|
|
|
d->items[a+4].type=D_BUTTON;
|
|
d->items[a+4].text=TEXT_(T_MOVE);
|
|
d->items[a+4].fn=list_item_move;
|
|
|
|
d->items[a+5].type=D_BUTTON;
|
|
d->items[a+5].text=TEXT_(T_UNSELECT_ALL);
|
|
d->items[a+5].fn=list_item_unselect;
|
|
|
|
d->items[a+6].type=D_BUTTON;
|
|
d->items[a+6].gid=B_ESC;
|
|
d->items[a+6].fn=cancel_dialog;
|
|
d->items[a+6].text=TEXT_(T_CLOSE);
|
|
|
|
d->items[a+7].type=D_END;
|
|
do_dialog(term, d, getml(d, NULL));
|
|
return 0;
|
|
}
|
|
|
|
|
|
void reinit_list_window(struct list_description *ld)
|
|
{
|
|
ld->current_pos=ld->list;
|
|
ld->win_offset=ld->list;
|
|
ld->win_pos=0;
|
|
|
|
if (ld->open) internal_error("reinit_list_window: calling reinit while open");
|
|
}
|
|
|
|
|