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                              ))))  (######)
13                             ,C--O   (###)      _________________
14                             |`:, \  ~~        |.  ,       v  , .|
15                             `-__o  ~~  ;      |  ZAKAZ KOURENI  |
16                             / _  \     `      |.               .|
17                            | ( \__`_=k==      `~~~~~~~~~~~~~~~~~'
18                            | `-/__---'
19                            |=====C/
20                            `.   ),'
21                              \  /
22                              ||_|
23                              || |__
24                              ||____)
25 
26                          v v  v   ,       ,v
27                      KONECNE NEJAKE KOMENTARE...
28 */
29 
30 /* Klikani myssi (nebo mysijou, jak rika Mikulas) v list-okne:
31  * (hrozne dulezity komentar ;-P )
32  *
33  * Klikani je vyreseno nasledovne, pokud ma nekdo lepsi napad, nebo nejake
34  * vyhrady, tak at mi je posle.
35  *
36  * Prostredni tlacitko+pohyb je scroll nahoru/dolu. Levym tlacitkem se nastavi
37  * kurzor (cerna lista) na konkretni polozku. Kdyz se levym klikne na adresar
38  * (na ty graficke nesmysly, ne na ten text), tak se adresar toggle
39  * otevre/zavre. Prave tlacitko oznaci/odznaci polozku/adresar.
40  */
41 
42 /* Premistovani polozek:
43  *
44  * Pravym tlacitkem se oznaci/odznaci polozka. Cudlikem "Odznacit vse" se
45  * vsechny polozky odznaci. Cudlik "Prestehovat" presune vsechny oznacene
46  * polozky za aktualni pozici, v tom poradi, jak jsou v seznamu. Pri zavreni
47  * adresare se vsechny polozky v adresari odznaci.
48  */
49 
50 /* Prekreslovani grafickych nesmyslu v okenku je samozrejme bez jedineho
51  *                                                               v
52  * bliknuti. Ne jako nejmenovane browsery... Proste obraz jako BIC (TM)
53  */
54 
55 /* Ovladani klavesnici:
56  * sipky, page up, page down, home end			pohyb
57  * +							otevri adresar
58  * -							zavri adresar
59  * mezera						toggle adresar
60  * ins, *, 8, i						toggle oznacit
61  * ?, /, N, n						hledani nahoru, dolu, 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 
164 /* struct list *current_pos;   current cursor position in the list */
165 /* struct list *win_offset;    item at the top of the window */
166 /* int win_pos;                current y position in the window */
167 
168 #define BOHNICE "+420-2-84016111"
169 
170 #define BFU_ELEMENT_EMPTY	0
171 #define BFU_ELEMENT_PIPE	1
172 #define BFU_ELEMENT_L		2
173 #define BFU_ELEMENT_TEE		3
174 #define BFU_ELEMENT_CLOSED	4
175 #define BFU_ELEMENT_CLOSED_DOWN	5
176 #define BFU_ELEMENT_OPEN	6
177 #define BFU_ELEMENT_OPEN_DOWN	7
178 
179 /* for mouse scrolling */
180 static long last_mouse_y;
181 
182 static void list_edit_toggle(struct dialog_data *dlg, struct list_description *ld);
183 
184 #ifdef G
185 #define sirka_scrollovadla (G_SCROLL_BAR_WIDTH<<1)
186 #else
187 #define sirka_scrollovadla 0
188 #endif
189 
190 
191 /* This function uses these defines from setup.h:
192  *
193  * BFU_GRX_WIDTH
194  * BFU_GRX_HEIGHT
195  * BFU_ELEMENT_WIDTH
196  */
197 
198 /* draws one of BFU elements: | |- [-] [+] */
199 /* BFU elements are used in the list window */
200 /* this function also defines shape and size of the elements */
201 /* 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) */
draw_bfu_element(struct terminal * term,int x,int y,unsigned char c,long b,long f,unsigned char type,unsigned char selected)202 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)
203 {
204 #ifdef G
205 	if (!F){
206 #endif
207 		unsigned char vertical=179;
208 		unsigned char horizontal=196;
209 		unsigned char tee=195;
210 		unsigned char l=192;
211 
212 		switch (type)
213 		{
214 			case BFU_ELEMENT_EMPTY:
215 			c|=ATTR_FRAME;
216 			set_char(term,x,y,' ',c);
217 			set_char(term,x+1,y,' ',c);
218 			set_char(term,x+2,y,' ',c);
219 			set_char(term,x+3,y,' ',c);
220 			set_char(term,x+4,y,' ',c);
221 			break;
222 
223 			case BFU_ELEMENT_PIPE:
224 			c|=ATTR_FRAME;
225 			set_char(term,x,y,' ',c);
226 			set_char(term,x+1,y,vertical,c);
227 			set_char(term,x+2,y,' ',c);
228 			set_char(term,x+3,y,' ',c);
229 			set_char(term,x+4,y,' ',c);
230 			break;
231 
232 			case BFU_ELEMENT_L:
233 			c|=ATTR_FRAME;
234 			set_char(term,x,y,' ',c);
235 			set_char(term,x+1,y,l,c);
236 			set_char(term,x+2,y,horizontal,c);
237 			set_char(term,x+3,y,horizontal,c);
238 			set_char(term,x+4,y,' ',c);
239 			break;
240 
241 			case BFU_ELEMENT_TEE:
242 			c|=ATTR_FRAME;
243 			set_char(term,x,y,' ',c);
244 			set_char(term,x+1,y,tee,c);
245 			set_char(term,x+2,y,horizontal,c);
246 			set_char(term,x+3,y,horizontal,c);
247 			set_char(term,x+4,y,' ',c);
248 			break;
249 
250 			case BFU_ELEMENT_CLOSED:
251 			case BFU_ELEMENT_CLOSED_DOWN:
252 			set_char(term,x,y,'[',c);
253 			set_char(term,x+1,y,'+',c);
254 			set_char(term,x+2,y,']',c);
255 			c|=ATTR_FRAME;
256 			set_char(term,x+3,y,horizontal,c);
257 			set_char(term,x+4,y,' ',c);
258 			break;
259 
260 			case BFU_ELEMENT_OPEN:
261 			case BFU_ELEMENT_OPEN_DOWN:
262 			set_char(term,x,y,'[',c);
263 			set_char(term,x+1,y,'-',c);
264 			set_char(term,x+2,y,']',c);
265 			c|=ATTR_FRAME;
266 			set_char(term,x+3,y,horizontal,c);
267 			set_char(term,x+4,y,' ',c);
268 			break;
269 
270 			default:
271 			internal_error("draw_bfu_element: unknown BFU element type %d.\n",type);
272 		}
273 		if (selected)set_char(term,x+4,y,'*',c);
274 		return BFU_ELEMENT_WIDTH;  /* BFU element size in text mode */
275 #ifdef G
276 	}else{
277 		struct graphics_device *dev=term->dev;
278 		struct rect r;
279 
280 		restrict_clip_area(dev,&r,x,y,x+5*BFU_GRX_WIDTH,y+BFU_GRX_HEIGHT);
281 
282 		switch (type)
283 		{
284 			case BFU_ELEMENT_EMPTY:
285 			drv->fill_area(dev,x,y,x+4*BFU_GRX_WIDTH,y+BFU_GRX_HEIGHT,b);
286 			break;
287 
288 			case BFU_ELEMENT_PIPE:
289 			/* pipe */
290 			drv->draw_vline(dev,x+1*BFU_GRX_WIDTH,y,y+BFU_GRX_HEIGHT,f);
291 			drv->draw_vline(dev,x+1+1*BFU_GRX_WIDTH,y,y+BFU_GRX_HEIGHT,f);
292 			/* clear the rest */
293 			drv->fill_area(dev,x,y,x+1*BFU_GRX_WIDTH,y+BFU_GRX_HEIGHT,b);
294 			drv->fill_area(dev,x+2+1*BFU_GRX_WIDTH,y,x+4*BFU_GRX_WIDTH,y+BFU_GRX_HEIGHT,b);
295 			break;
296 
297 			case BFU_ELEMENT_L:
298 			/* l */
299 			drv->draw_vline(dev,x+1*BFU_GRX_WIDTH,y,y+(int)(.5*BFU_GRX_HEIGHT),f);
300 			drv->draw_vline(dev,x+1+1*BFU_GRX_WIDTH,y,y+(int)(.5*BFU_GRX_HEIGHT),f);
301 			drv->draw_hline(dev,x+1*BFU_GRX_WIDTH,y+(int)(.5*BFU_GRX_HEIGHT),x+1+(int)(3.5*BFU_GRX_WIDTH),f);
302 			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);
303 			/* clear the rest */
304 			drv->fill_area(dev,x,y,x+1*BFU_GRX_WIDTH,y+BFU_GRX_HEIGHT,b);
305 			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);
306 			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);
307 			drv->fill_area(dev,x+1+(int)(3.5*BFU_GRX_WIDTH),y,x+4*BFU_GRX_WIDTH,y+BFU_GRX_HEIGHT,b);
308 			break;
309 
310 			case BFU_ELEMENT_TEE:
311 			/* tee */
312 			drv->draw_vline(dev,x+1*BFU_GRX_WIDTH,y,y+BFU_GRX_HEIGHT,f);
313 			drv->draw_vline(dev,x+1+1*BFU_GRX_WIDTH,y,y+BFU_GRX_HEIGHT,f);
314 			drv->draw_hline(dev,x+1*BFU_GRX_WIDTH,y+(int)(.5*BFU_GRX_HEIGHT),x+1+(int)(3.5*BFU_GRX_WIDTH),f);
315 			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);
316 			/* clear the rest */
317 			drv->fill_area(dev,x,y,x+1*BFU_GRX_WIDTH,y+BFU_GRX_HEIGHT,b);
318 			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);
319 			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);
320 			drv->fill_area(dev,x+1+(int)(3.5*BFU_GRX_WIDTH),y,x+4*BFU_GRX_WIDTH,y+BFU_GRX_HEIGHT,b);
321 			break;
322 
323 			case BFU_ELEMENT_CLOSED:
324 			case BFU_ELEMENT_CLOSED_DOWN:
325 			/* vertical line of the + */
326 			drv->draw_vline(dev,x+1*BFU_GRX_WIDTH,y+1+(int)(.25*BFU_GRX_HEIGHT),y-1+(int)(.75*BFU_GRX_HEIGHT),f);
327 			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);
328 
329 			/* clear around the + */
330 			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);
331 			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);
332 
333 			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);
334 			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);
335 
336 			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);
337 			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);
338 			/*-fallthrough*/
339 
340 			case BFU_ELEMENT_OPEN:
341 			case BFU_ELEMENT_OPEN_DOWN:
342 			/* box */
343 			drv->draw_vline(dev,x+2,y+1,y-1+BFU_GRX_HEIGHT,f);
344 			drv->draw_vline(dev,x+3,y+1,y-1+BFU_GRX_HEIGHT,f);
345 			drv->draw_vline(dev,x-1+2*BFU_GRX_WIDTH,y+1,y-1+BFU_GRX_HEIGHT,f);
346 			drv->draw_vline(dev,x-2+2*BFU_GRX_WIDTH,y+1,y-1+BFU_GRX_HEIGHT,f);
347 			drv->draw_hline(dev,x+4,y+1,x-2+2*BFU_GRX_WIDTH,f);
348 			drv->draw_hline(dev,x+4,y+2,x-2+2*BFU_GRX_WIDTH,f);
349 			drv->draw_hline(dev,x+4,y-2+BFU_GRX_HEIGHT,x-2+2*BFU_GRX_WIDTH,f);
350 			drv->draw_hline(dev,x+4,y-3+BFU_GRX_HEIGHT,x-2+2*BFU_GRX_WIDTH,f);
351 
352 			/* horizontal line of the - */
353 			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);
354 			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);
355 
356 			/* line to title */
357 			drv->draw_hline(dev,x+2*BFU_GRX_WIDTH,y+(BFU_GRX_HEIGHT>>1),x+1+(int)(3.5*BFU_GRX_WIDTH),f);
358 			drv->draw_hline(dev,x+2*BFU_GRX_WIDTH,y-1+(BFU_GRX_HEIGHT>>1),x+1+(int)(3.5*BFU_GRX_WIDTH),f);
359 
360 			/* top and bottom short vertical line */
361 			drv->draw_hline(dev,x+1*BFU_GRX_WIDTH,y,x+2+1*BFU_GRX_WIDTH,f);
362 			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);
363 
364 			/* clear the rest */
365 			drv->draw_vline(dev,x,y,y+BFU_GRX_HEIGHT,b);
366 			drv->draw_vline(dev,x+1,y,y+BFU_GRX_HEIGHT,b);
367 			drv->draw_hline(dev,x+2,y,x+BFU_GRX_WIDTH,b);
368 			drv->draw_hline(dev,x+2,y-1+BFU_GRX_HEIGHT,x+BFU_GRX_WIDTH,b);
369 			drv->draw_hline(dev,x+2+BFU_GRX_WIDTH,y,x+2*BFU_GRX_WIDTH,b);
370 			drv->draw_hline(dev,x+2+BFU_GRX_WIDTH,y-1+BFU_GRX_HEIGHT,x+2*BFU_GRX_WIDTH,b);
371 			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);
372 			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);
373 			drv->fill_area(dev,x+4,y+3,x+2+(int)(.5*BFU_GRX_WIDTH),y-3+BFU_GRX_HEIGHT,b);
374 			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);
375 			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);
376 			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);
377 			if (type==BFU_ELEMENT_OPEN || type == BFU_ELEMENT_OPEN_DOWN)
378 			{
379 				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);
380 				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);
381 			}
382 			drv->fill_area(dev,x+1+(int)(3.5*BFU_GRX_WIDTH),y,x+4*BFU_GRX_WIDTH,y+BFU_GRX_HEIGHT,b);
383 			break;
384 
385 			default:
386 			internal_error("draw_bfu_element: unknown BFU element type %d.\n",type);
387 		}
388 		if (!selected)
389 			drv->fill_area(dev,x+4*BFU_GRX_WIDTH,y,x+5*BFU_GRX_WIDTH,y+BFU_GRX_HEIGHT,b);
390 		else
391 		{
392 			drv->fill_area(dev,x+4*BFU_GRX_WIDTH,y,x+(int)(4.25*BFU_GRX_WIDTH),y+BFU_GRX_HEIGHT,b);
393 			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);
394 			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);
395 			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);
396 			drv->fill_area(dev,x+(int)(4.75*BFU_GRX_WIDTH),y,x+5*BFU_GRX_WIDTH,y+BFU_GRX_HEIGHT,b);
397 		}
398 
399 		set_clip_area(dev, &r);
400 		return BFU_ELEMENT_WIDTH;
401 	}
402 #endif
403 }
404 
405 
406 /* aux structure for parameter exchange for redrawing list window */
407 struct redraw_data
408 {
409 	struct list_description *ld;
410 	struct dialog_data *dlg;
411 	int n;
412 };
413 
414 
415 static void redraw_list(struct terminal *term, void *bla);
416 
417 /* returns next visible item in tree list */
418 /* works only with visible items (head or any item returned by this function) */
419 /* when list is flat returns next item */
next_in_tree(struct list_description * ld,struct list * item)420 static struct list *next_in_tree(struct list_description *ld, struct list *item)
421 {
422 	int depth = item->depth;
423 
424 	/* flat list */
425 	if (!ld->type)
426 		return list_next(item);
427 
428 	if (!(item->type & 1) || (item->type & 2))  /* item or opened folder */
429 		return list_next(item);
430 	/* skip content of this folder */
431 	do item = list_next(item); while (item->depth > depth);   /* must stop on head 'cause it's depth is -1 */
432 	return item;
433 }
434 
435 
436 /* returns previous visible item in tree list */
437 /* works only with visible items (head or any item returned by this function) */
438 /* when list is flat returns previous item */
prev_in_tree(struct list_description * ld,struct list * item)439 static struct list *prev_in_tree(struct list_description *ld, struct list *item)
440 {
441 	struct list *last_closed;
442 	int depth = item->depth;
443 
444 	/* flat list */
445 	if (!ld->type)
446 		return list_prev(item);
447 
448 	if (item == ld->list)
449 		depth=0;
450 
451 	/* items with same or lower depth must be visible, because current item is visible */
452 	if (list_prev(item)->depth <= item->depth)
453 		return list_prev(item);
454 
455 	/* find item followed with opened fotr's only */
456 	/* searched item is last closed folder (going up from item) or item->prev */
457 	last_closed = list_prev(item);
458 	item = list_prev(item);
459 	while (1) {
460 		if ((item->type & 3) == 1)	/* closed folder */
461 			last_closed = item;
462 		if (item->depth <= depth)
463 			break;
464 		item = item->fotr;
465 	}
466 	return last_closed;
467 }
468 
469 
470 #ifdef G
get_total_items(struct list_description * ld)471 static int get_total_items(struct list_description *ld)
472 {
473 	struct list *l = ld->list;
474 	int count = 0;
475 
476 	do{
477 		l = next_in_tree(ld, l);
478 		count++;
479 	} while (l != ld->list);
480 
481 	return count;
482 }
483 
484 
get_scroll_pos(struct list_description * ld)485 static int get_scroll_pos(struct list_description *ld)
486 {
487 	struct list *l;
488 	int count = 0;
489 
490 	for (l = ld->list; l != ld->win_offset; l = next_in_tree(ld,l))
491 		count++;
492 
493 	return count;
494 }
495 
496 
get_visible_items(struct list_description * ld)497 static int get_visible_items(struct list_description *ld)
498 {
499 	struct list *l = ld->win_offset;
500 	int count = 0;
501 
502 	do{
503 		l = next_in_tree(ld,l);
504 		count++;
505 	} while (count < ld->n_items && l != ld->list);
506 
507 	return count;
508 }
509 
510 
find_last_in_window(struct list_description * ld)511 static struct list *find_last_in_window(struct list_description *ld)
512 {
513 	struct list *l = ld->win_offset;
514 	struct list *x = l;
515 	int count = 0;
516 
517 	do{
518 		l = next_in_tree(ld, l);
519 		count++;
520 		if (l != ld->list && count != ld->n_items)
521 			x = l;
522 	} while (count < ld->n_items && l != ld->list);
523 
524 	return x;
525 }
526 
527 #endif
528 
529 
get_win_pos(struct list_description * ld)530 static int get_win_pos(struct list_description *ld)
531 {
532 	struct list *l;
533 	int count = 0;
534 
535 	for (l = ld->win_offset; l != ld->current_pos; l = next_in_tree(ld, l))
536 		count++;
537 
538 	return count;
539 }
540 
541 
unselect_in_folder(struct list_description * ld,struct list * l)542 static void unselect_in_folder(struct list_description *ld, struct list *l)
543 {
544 	int depth;
545 
546 	depth = l->depth;
547 	for (l = list_next(l); l != ld->list && l->depth > depth; l = list_next(l))
548 		l->type &= ~4;
549 }
550 
551 
552 /* aux function for list_item_add */
list_insert_behind_item(struct dialog_data * dlg,struct list * pos,struct list * item,struct list_description * ld)553 static void list_insert_behind_item(struct dialog_data *dlg, struct list *pos, struct list *item, struct list_description *ld)
554 {
555 	struct list *a;
556 	struct redraw_data rd;
557 
558 /*  BEFORE:  ... <----> pos <--(possible invisible items)--> a <----> ... */
559 /*  AFTER:   ... <----> pos <--(possible invisible items)--> item <----> a <----> ... */
560 
561 	a = next_in_tree(ld,pos);
562 	add_before_pos(a, item);
563 
564 	/* if list is flat a->fotr will contain nosenses, but it won't crash ;-) */
565 	if ((pos->type & 3) == 3 || pos->depth == -1) { item->fotr=pos; item->depth=pos->depth+1; }  /* open directory or head */
566 	else { item->fotr = pos->fotr; item->depth = pos->depth; }
567 
568 	ld->current_pos = next_in_tree(ld, ld->current_pos);   /* ld->current_pos->next==item */
569 	ld->win_pos++;
570 	if (ld->win_pos > ld->n_items - 1) {  /* scroll down */
571 		ld->win_pos = ld->n_items - 1;
572 		ld->win_offset = next_in_tree(ld, ld->win_offset);
573 	}
574 
575 	ld->modified = 1;
576 
577 	rd.ld = ld;
578 	rd.dlg = dlg;
579 	rd.n = 0;
580 
581 	draw_to_window(dlg->win, redraw_list, &rd);
582 }
583 
584 
585 /* aux function for list_item_edit */
586 /* copies data of src to dest and calls free on the src */
587 /* first argument is argument passed to user function */
list_copy_item(struct dialog_data * dlg,struct list * dest,struct list * src,struct list_description * ld)588 static void list_copy_item(struct dialog_data *dlg, struct list *dest, struct list *src, struct list_description *ld)
589 {
590 	struct redraw_data rd;
591 
592 	ld->copy_item(src, dest);
593 	ld->delete_item(src);
594 
595 	ld->modified = 1;  /* called after an successful edit */
596 	rd.ld = ld;
597 	rd.dlg = dlg;
598 	rd.n = 0;
599 
600 	draw_to_window(dlg->win, redraw_list, &rd);
601 }
602 
603 
604 /* creates new item (calling new_item function) and calls edit_item function */
list_item_add(struct dialog_data * dlg,struct dialog_item_data * useless)605 static int list_item_add(struct dialog_data *dlg, struct dialog_item_data *useless)
606 {
607 	struct list_description *ld = (struct list_description *)dlg->dlg->udata2;
608 	struct list *item = ld->current_pos;
609 	struct list *new_item;
610 
611 	if (!(new_item = ld->new_item(ld->default_value ? ld->default_value((struct session *)dlg->dlg->udata, 0) : NULL)))
612 		return 1;
613 	new_item->list_entry.prev = NULL;
614 	new_item->list_entry.next = NULL;
615 	new_item->type = 0;
616 	new_item->depth = 0;
617 
618 	ld->edit_item(dlg,new_item, list_insert_behind_item, item, TITLE_ADD);
619 	return 0;
620 }
621 
622 
623 /* like list_item_add but creates folder */
list_folder_add(struct dialog_data * dlg,struct dialog_item_data * useless)624 static int list_folder_add(struct dialog_data *dlg, struct dialog_item_data *useless)
625 {
626 	struct list_description *ld = (struct list_description *)dlg->dlg->udata2;
627 	struct list *item = ld->current_pos;
628 	struct list *new_item;
629 
630 	if (!(new_item = ld->new_item(NULL)))
631 		return 1;
632 	new_item->list_entry.prev = NULL;
633 	new_item->list_entry.next = NULL;
634 	new_item->type = 1 | 2;
635 	new_item->depth = 0;
636 
637 	ld->edit_item(dlg, new_item, list_insert_behind_item, item, TITLE_ADD);
638 	return 0;
639 }
640 
641 
list_item_edit(struct dialog_data * dlg,struct dialog_item_data * useless)642 static int list_item_edit(struct dialog_data *dlg,struct dialog_item_data *useless)
643 {
644 	struct list_description *ld = (struct list_description *)dlg->dlg->udata2;
645 	struct list *item = ld->current_pos;
646 	struct list *new_item;
647 
648 	if (item == ld->list) return 0;  /* head */
649 	if (!(new_item = ld->new_item(NULL))) return 1;
650 	new_item->list_entry.prev = NULL;
651 	new_item->list_entry.next = NULL;
652 
653 	ld->copy_item(item, new_item);
654 	ld->edit_item(dlg, new_item, list_copy_item, item, TITLE_EDIT);
655 
656 	return 0;
657 }
658 
659 
is_parent(struct list_description * ld,struct list * item,struct list * parent)660 static inline int is_parent(struct list_description *ld, struct list *item, struct list *parent)
661 {
662 	struct list *l;
663 
664 	if (ld->type)
665 		for (l=item;l->depth>=0;l=l->fotr)
666 			if (l==parent) return 1;
667 	return 0;
668 }
669 
list_item_move(struct dialog_data * dlg,struct dialog_item_data * useless)670 static int list_item_move(struct dialog_data *dlg, struct dialog_item_data *useless)
671 {
672 	struct list_description *ld = (struct list_description *)dlg->dlg->udata2;
673 	struct list *i;
674 	struct list *behind = ld->current_pos;
675 	struct redraw_data rd;
676 	int window_moved = 0;
677 	int count = 0;
678 
679 	if (ld->current_pos->type & 4) {  /* odznacime current_pos, kdyby nahodou byla oznacena */
680 		count++;
681 		ld->current_pos->type &= ~4;
682 	}
683 
684 	for (i = list_next(ld->list); i != ld->list; ) {
685 		struct list *next = next_in_tree(ld, i);
686 		struct list *prev = list_prev(i);
687 		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 */
688 		struct list *item_last = list_prev(next); /* last item of moved block */
689 
690 		if (!(i->type & 4)) { i = next; continue; }
691 		if (is_parent(ld, ld->current_pos, i)) { /* we're moving directory into itself - let's behave like item was not selected */
692 			i->type &= ~4;
693 			i = next;
694 			count++;
695 			continue;
696 		}
697 
698 		if ((i->type & 3) == 3) { /* dirty trick */
699 			i->type &= ~2;
700 			next = next_in_tree(ld, i);
701 			prev = list_prev(i);
702 			item_last = list_prev(next);
703 			i->type |= 2;
704 		}
705 
706 		if (i == ld->win_offset) {
707 			window_moved = 1;
708 			if (next != ld->list) ld->win_offset = next;
709 		}
710 
711 		/* upravime fotrisko a hloubku */
712 		if (ld->type) {
713 			int a = i->depth;
714 			struct list *l = i;
715 
716 			if ((behind->type & 3) == 3 || behind == ld->list) { /* open folder or head */
717 				i->fotr = behind;
718 				i->depth = behind->depth + 1;
719 			} else {
720 				i->fotr = behind->fotr;
721 				i->depth = behind->depth;
722 			}
723 			a = i->depth - a;
724 
725 			/* poopravime hloubku v adresari */
726 			while (l != item_last) {
727 				l = list_next(l);
728 				l->depth += a;
729 			}
730 		}
731 
732 		if (behind_next == i) goto predratovano;	/* to uz je vsechno, akorat menime hloubku */
733 
734 		/* predratujeme ukazatele kolem bloku na stare pozici */
735 		prev->list_entry.next = &next->list_entry;
736 		next->list_entry.prev = &prev->list_entry;
737 
738 		/* posuneme na novou pozici (tesne pred behind_next) */
739 		i->list_entry.prev = behind_next->list_entry.prev;
740 		behind_next->list_entry.prev->next = &i->list_entry;
741 		item_last->list_entry.next = &behind_next->list_entry;
742 		behind_next->list_entry.prev = &item_last->list_entry;
743 
744 predratovano:
745 		/* odznacime */
746 		i->type &= ~4;
747 		unselect_in_folder(ld, i);
748 
749 		/* upravime pointery pro dalsi krok */
750 		behind = i;
751 		i = next;
752 		count++;
753 	}
754 
755 	if (window_moved) {
756 		ld->current_pos = ld->win_offset;
757 		ld->win_pos = 0;
758 	} else
759 		ld->win_pos = get_win_pos(ld);
760 
761 	if (!count) {
762 		msg_box(
763 			dlg->win->term,   /* terminal */
764 			NULL,  /* blocks to free */
765 			TEXT_(T_MOVE),  /* title */
766 			AL_CENTER,  /* alignment */
767 			TEXT_(T_NO_ITEMS_SELECTED),MSG_BOX_END,  /* text */
768 			NULL,  /* data */
769 			1,  /* # of buttons */
770 			TEXT_(T_CANCEL), msg_box_null, B_ESC|B_ENTER  /* button1 */
771 		);
772 	} else {
773 		ld->modified = 1;
774 		rd.ld = ld;
775 		rd.dlg = dlg;
776 		rd.n = 0;
777 		draw_to_window(dlg->win, redraw_list, &rd);
778 	}
779 	return 0;
780 }
781 
782 
783 /* unselect all items */
list_item_unselect(struct dialog_data * dlg,struct dialog_item_data * useless)784 static int list_item_unselect(struct dialog_data *dlg, struct dialog_item_data *useless)
785 {
786 	struct list_description *ld = (struct list_description *)dlg->dlg->udata2;
787 	struct list *item;
788 	struct redraw_data rd;
789 
790 	item = ld->list;
791 	do {
792 		item->type &= ~4;
793 		item = list_next(item);
794 	} while (item != ld->list);
795 
796 	rd.ld = ld;
797 	rd.dlg = dlg;
798 	rd.n = 0;
799 
800 	draw_to_window(dlg->win, redraw_list, &rd);
801 	return 0;
802 }
803 
804 
805 /* user button function - calls button_fn with current item */
list_item_button(struct dialog_data * dlg,struct dialog_item_data * useless)806 static int list_item_button(struct dialog_data *dlg, struct dialog_item_data *useless)
807 {
808 	struct list_description *ld = (struct list_description *)dlg->dlg->udata2;
809 	struct list *item = ld->current_pos;
810 	struct session *ses = (struct session *)dlg->dlg->udata;
811 
812 	if (!ld->button_fn) internal_error("Links got schizophrenia! Call "BOHNICE".\n");
813 
814 	if (item == ld->list || list_empty(item->list_entry)) return 0;  /* head or empty list */
815 
816 	if (ld->type && (item->type & 1)) {
817 		list_edit_toggle(dlg, ld);
818 		return 0;  /* this is tree list and item is directory */
819 	}
820 
821 	ld->button_fn(ses,item);
822 	cancel_dialog(dlg, useless);
823 	return 0;
824 }
825 
826 
827 struct ve_skodarne_je_jeste_vetsi_narez {
828 	struct list_description *ld;
829 	struct dialog_data *dlg;
830 	struct list *item;
831 };
832 
833 
834 /* when delete is confirmed adjusts current_pos and calls delete function */
delete_ok(void * data)835 static void delete_ok(void *data)
836 {
837 	struct ve_skodarne_je_jeste_vetsi_narez *skd = (struct ve_skodarne_je_jeste_vetsi_narez *)data;
838 	struct list_description *ld = skd->ld;
839 	struct list *item = skd->item;
840 	struct dialog_data *dlg = skd->dlg;
841 	struct redraw_data rd;
842 
843 	/* strong premise: we can't delete head of the list */
844 	if (list_next(ld->current_pos) != ld->list) {
845 		if (ld->current_pos == ld->win_offset) ld->win_offset = list_next(ld->current_pos);
846 		ld->current_pos = list_next(ld->current_pos);
847 	} else { /* last item */
848 		if (!ld->win_pos)  /* only one line on the screen */
849 			ld->win_offset = prev_in_tree(ld, ld->win_offset);
850 		else
851 			ld->win_pos--;
852 		ld->current_pos = prev_in_tree(ld, ld->current_pos);
853 	}
854 
855 	ld->delete_item(item);
856 
857 	rd.ld = ld;
858 	rd.dlg = dlg;
859 	rd.n = 0;
860 
861 	ld->modified = 1;
862 	draw_to_window(dlg->win, redraw_list, &rd);
863 }
864 
865 
866 /* when delete folder is confirmed adjusts current_pos and calls delete function */
delete_folder_recursively(void * data)867 static void delete_folder_recursively(void *data)
868 {
869 	struct ve_skodarne_je_jeste_vetsi_narez *skd = (struct ve_skodarne_je_jeste_vetsi_narez *)data;
870 	struct list_description *ld = skd->ld;
871 	struct list *item = skd->item;
872 	struct dialog_data *dlg = skd->dlg;
873 	struct redraw_data rd;
874 	struct list *i, *j;
875 	int depth;
876 
877 	for (i = list_next(item), depth = item->depth; i != ld->list && i->depth > depth; ) {
878 		j = i;
879 		i = list_next(i);
880 		ld->delete_item(j);
881 	}
882 
883 	/* strong premise: we can't delete head of the list */
884 	if (list_next(ld->current_pos) != ld->list) {
885 		if (ld->current_pos == ld->win_offset) ld->win_offset = list_next(ld->current_pos);
886 		ld->current_pos = list_next(ld->current_pos);
887 	} else { /* last item */
888 		if (!ld->win_pos)  /* only one line on the screen */
889 			ld->win_offset = prev_in_tree(ld, ld->win_offset);
890 		else
891 			ld->win_pos--;
892 		ld->current_pos = prev_in_tree(ld, ld->current_pos);
893 	}
894 
895 	ld->delete_item(item);
896 
897 	rd.ld = ld;
898 	rd.dlg = dlg;
899 	rd.n = 0;
900 
901 	ld->modified = 1;
902 	draw_to_window(dlg->win, redraw_list, &rd);
903 }
904 
905 
906 /* tests if directory is emty */
is_empty_dir(struct list_description * ld,struct list * dir)907 static int is_empty_dir(struct list_description *ld, struct list *dir)
908 {
909 	if (!ld->type) return 1;  /* flat list */
910 	if (!(dir->type & 1)) return 1;   /* not a directory */
911 
912 	return list_next(dir)->depth <= dir->depth;  /* head depth is -1 */
913 }
914 
915 
916 /* delete dialog */
list_item_delete(struct dialog_data * dlg,struct dialog_item_data * useless)917 static int list_item_delete(struct dialog_data *dlg,struct dialog_item_data *useless)
918 {
919 	struct terminal *term=dlg->win->term;
920 	struct list_description *ld=(struct list_description*)(dlg->dlg->udata2);
921 	struct list *item=ld->current_pos;
922 	unsigned char *txt;
923 	struct ve_skodarne_je_jeste_vetsi_narez *narez;
924 
925 	if (item==ld->list||list_empty(item->list_entry))return 0;  /* head or empty list */
926 
927 	narez=mem_alloc(sizeof(struct ve_skodarne_je_jeste_vetsi_narez));
928 	narez->ld=ld;narez->item=item;narez->dlg=dlg;
929 
930 	txt=ld->type_item(term, item,0);
931 	if (!txt)
932 	{
933 		txt = stracpy(cast_uchar "");
934 	}
935 
936 	if ((item->type)&1)   /* folder */
937 	{
938 		if (!is_empty_dir(ld,item))
939 			msg_box(
940 				term,   /* terminal */
941 				getml(txt,narez,NULL),  /* blocks to free */
942 				TEXT_(T_DELETE_FOLDER),  /* title */
943 				AL_CENTER,  /* alignment */
944 				TEXT_(T_FOLDER),cast_uchar " \"",txt,cast_uchar "\" ",TEXT_(T_NOT_EMPTY_SURE_DELETE),MSG_BOX_END,  /* text */
945 				(void *)narez,  /* data for ld->delete_item */
946 				2,  /* # of buttons */
947 				TEXT_(T_NO),msg_box_null,B_ESC,  /* button1 */
948 				TEXT_(T_YES),delete_folder_recursively,B_ENTER  /* button2 */
949 			);
950 		else
951 			msg_box(
952 				term,   /* terminal */
953 				getml(txt,narez,NULL),  /* blocks to free */
954 				TEXT_(T_DELETE_FOLDER),  /* title */
955 				AL_CENTER,  /* alignment */
956 				TEXT_(T_SURE_DELETE),cast_uchar " ",TEXT_(T_fOLDER),cast_uchar " \"",txt,cast_uchar "\"?",MSG_BOX_END,  /* null-terminated text */
957 				(void *)narez,  /* data for ld->delete_item */
958 				2,  /* # of buttons */
959 				TEXT_(T_YES),delete_ok,B_ENTER,  /* button1 */
960 				TEXT_(T_NO),msg_box_null,B_ESC  /* button2 */
961 			);
962 	}
963 	else   /* item */
964 		msg_box(
965 			term,   /* terminal */
966 			getml(txt,narez,NULL),  /* blocks to free */
967 			TEXT_(ld->delete_dialog_title),  /* title */
968 			AL_CENTER,  /* alignment */
969 			TEXT_(T_SURE_DELETE),cast_uchar " ",TEXT_(ld->item_description),cast_uchar " \"",txt,cast_uchar "\"?",MSG_BOX_END,  /* null-terminated text */
970 			(void *)narez,  /* data for ld->delete_item */
971 			2,  /* # of buttons */
972 			TEXT_(T_YES),delete_ok,B_ENTER,  /* button1 */
973 			TEXT_(T_NO),msg_box_null,B_ESC  /* button2 */
974 		);
975 	return 0;
976 }
977 
redraw_list_element(struct terminal * term,struct dialog_data * dlg,int y,int w,struct list_description * ld,struct list * l)978 static void redraw_list_element(struct terminal *term, struct dialog_data *dlg, int y, int w, struct list_description *ld, struct list *l)
979 {
980 	struct list *lx;
981 	unsigned char *xp;
982 	int xd;
983 	unsigned char *txt;
984 	int x=0;
985 	unsigned char color = 0;
986 	long bgcolor = 0, fgcolor = 0;
987 	int b;
988 	unsigned char element;
989 
990 	if (!F) {
991 		color = l == ld->current_pos ? COLOR_MENU_SELECTED : COLOR_MENU_TEXT;
992 	}
993 #ifdef G
994 	else {
995 		struct rect r;
996 		r.x1 = dlg->x + DIALOG_LB;
997 		r.x2 = dlg->x + DIALOG_LB + w;
998 		r.y1 = y;
999 		r.y2 = y + G_BFU_FONT_SIZE;
1000 		if (dlg->s) exclude_rect_from_set(&dlg->s, &r);
1001 		if (!do_rects_intersect(&r, &term->dev->clip))
1002 			return;
1003 		bgcolor = l == ld->current_pos ? bfu_fg_color : bfu_bg_color;
1004 		fgcolor = l == ld->current_pos ? bfu_bg_color : bfu_fg_color;
1005 	}
1006 #endif
1007 
1008 	txt = ld->type_item(term, l, 1);
1009 	if (!txt) {
1010 		txt = stracpy(cast_uchar "");
1011 	}
1012 
1013 	/* everything except head */
1014 
1015 	if (l != ld->list) {
1016 		switch (ld->type) {
1017 		case 0:
1018 			element = BFU_ELEMENT_TEE;
1019 			if (list_next(l) == ld->list)
1020 				element = BFU_ELEMENT_L;
1021 			x += draw_bfu_element(term, dlg->x + DIALOG_LB, y, color, bgcolor, fgcolor, element, l->type & 4);
1022 			break;
1023 		case 1:
1024 			xp = mem_alloc(l->depth + 1);
1025 			memset(xp, 0, l->depth + 1);
1026 			xd = l->depth + 1;
1027 			for (lx = list_next(l); lx != ld->list; lx = list_next(lx)) {
1028 				if (lx->depth < xd) {
1029 					xd = lx->depth;
1030 					xp[xd] = 1;
1031 					if (!xd) break;
1032 				}
1033 			}
1034 			for (b = 0; b < l->depth; b++)
1035 				x += draw_bfu_element(term, dlg->x + DIALOG_LB+x, y, color, bgcolor, fgcolor, xp[b] ? BFU_ELEMENT_PIPE : BFU_ELEMENT_EMPTY, 0);
1036 			if (l->depth >= 0) {  /* everything except head */
1037 				int o = xp[l->depth];
1038 				switch (l->type & 1) {
1039 					case 0:  /* item */
1040 						element = o ? BFU_ELEMENT_TEE : BFU_ELEMENT_L;
1041 						break;
1042 
1043 					case 1:  /* directory */
1044 						if (l->type & 2) {
1045 							element = o ? BFU_ELEMENT_OPEN_DOWN : BFU_ELEMENT_OPEN;
1046 						} else {
1047 							element = o ? BFU_ELEMENT_CLOSED_DOWN : BFU_ELEMENT_CLOSED;
1048 						}
1049 						break;
1050 
1051 					default:  /* this should never happen */
1052 						internal_error("=8-Q  lunacy level too high! Call "BOHNICE".\n");
1053 						element = BFU_ELEMENT_EMPTY;
1054 
1055 				}
1056 				x += draw_bfu_element(term, dlg->x + DIALOG_LB + x, y, color, bgcolor, fgcolor, element, l->type & 4);
1057 			}
1058 			mem_free(xp);
1059 			break;
1060 		default:
1061 			internal_error(
1062 				"Invalid list description type.\n"
1063 				"Somebody's probably shooting into memory.\n"
1064 				"_______________\n"
1065 				"`--|_____|--|___ `\\\n"
1066 				"             \"  \\___\\\n");
1067 		}
1068 	}
1069 
1070 	if (!F) {
1071 		print_text(term, dlg->x + x + DIALOG_LB, y, w-x, txt, color);
1072 		x+=cp_len(term_charset(term), txt);
1073 		fill_area(term, dlg->x+DIALOG_LB+x, y, w-x, 1, ' ', 0);
1074 		set_line_color(term, dlg->x + DIALOG_LB + x, y, w-x, color);
1075 	}
1076 #ifdef G
1077 	else {
1078 		struct rect old_area;
1079 		struct style *stl = l == ld->current_pos ? bfu_style_wb : bfu_style_bw;
1080 
1081 		restrict_clip_area(term->dev, &old_area, dlg->x + x + DIALOG_LB, y, dlg->x + DIALOG_LB + w, y + G_BFU_FONT_SIZE);
1082 		g_print_text(term->dev, dlg->x + x + DIALOG_LB, y, stl, txt, NULL);
1083 		x += g_text_width(stl, txt);
1084 		drv->fill_area(term->dev, dlg->x + DIALOG_LB + x, y, dlg->x + DIALOG_LB + w, y + G_BFU_FONT_SIZE, bgcolor);
1085 		set_clip_area(term->dev, &old_area);
1086 	}
1087 #endif
1088 	mem_free(txt);
1089 }
1090 
1091 /* redraws list */
redraw_list(struct terminal * term,void * bla)1092 static void redraw_list(struct terminal *term, void *bla)
1093 {
1094 	struct redraw_data* rd = (struct redraw_data *)bla;
1095 	struct list_description *ld = rd->ld;
1096 	struct dialog_data *dlg = rd->dlg;
1097 	int y, a;
1098 	struct list *l;
1099 	int w = dlg->xw - 2 * DIALOG_LB - (F ? sirka_scrollovadla : 0);
1100 	y = dlg->y + DIALOG_TB;
1101 
1102 #ifdef G
1103 	if (F) {
1104 		int total = get_total_items(ld);
1105 		int visible = get_visible_items(ld);
1106 		int pos = get_scroll_pos(ld);
1107 		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);
1108 		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);
1109 	}
1110 #endif
1111 
1112 	for (a = 0, l = ld->win_offset; a < ld->n_items; ) {
1113 		redraw_list_element(term, dlg, y, w, ld, l);
1114 		l = next_in_tree(ld, l);
1115 		a++;
1116 		y += gf_val(1, G_BFU_FONT_SIZE);
1117 		if (l == ld->list) break;
1118 	}
1119 	if (!F) fill_area(term, dlg->x + DIALOG_LB, y, w, ld->n_items-a, ' ', COLOR_MENU_TEXT);
1120 #ifdef G
1121 	else {
1122 		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));
1123 		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);
1124 	}
1125 #endif
1126 }
1127 
1128 
1129 /* moves cursor from old position to a new one */
1130 /* direction: -1=old is previous, +1=old is next */
redraw_list_line(struct terminal * term,void * bla)1131 static void redraw_list_line(struct terminal *term, void *bla)
1132 {
1133 	struct redraw_data *rd = (struct redraw_data *)bla;
1134 	struct list_description *ld = rd->ld;
1135 	struct dialog_data *dlg = rd->dlg;
1136 	int direction = rd->n;
1137 	int w = dlg->xw - 2 * DIALOG_LB - (F ? sirka_scrollovadla : 0);
1138 	int y = dlg->y + DIALOG_TB + gf_val(ld->win_pos, ld->win_pos * G_BFU_FONT_SIZE);
1139 	struct list *l;
1140 
1141 	redraw_list_element(term, dlg, y, w, ld, ld->current_pos);
1142 	if (!F && (!term->spec->block_cursor || term->spec->braille)) {
1143 		set_cursor(term, dlg->x + DIALOG_LB, y, dlg->x + DIALOG_LB, y);
1144 	}
1145 	y += gf_val(direction, direction*G_BFU_FONT_SIZE);
1146 	switch (direction) {
1147 		case 0:
1148 			l = NULL;
1149 			break;
1150 		case 1:
1151 			l = next_in_tree(ld, ld->current_pos);
1152 			break;
1153 		case -1:
1154 			l = prev_in_tree(ld, ld->current_pos);
1155 			break;
1156 		default:
1157 			internal_error("redraw_list_line: invalid direction %d", direction);
1158 			l = NULL;
1159 			break;
1160 	}
1161 	if (l) redraw_list_element(term, dlg, y, w, ld, l);
1162 }
1163 
1164 
1165 /* like redraw_list, but scrolls window, prints new line to top/bottom */
1166 /* in text mode calls redraw list */
1167 /* direction: -1=up, 1=down */
scroll_list(struct terminal * term,void * bla)1168 static void scroll_list(struct terminal *term, void *bla)
1169 {
1170 #ifdef G
1171 	struct redraw_data *rd = (struct redraw_data *)bla;
1172 	struct list_description *ld = rd->ld;
1173 	struct dialog_data *dlg = rd->dlg;
1174 	int direction = rd->n;
1175 #endif
1176 
1177 	if (!F) {
1178 		redraw_list(term, bla);
1179 	}
1180 #ifdef G
1181 	else {
1182 		struct rect old_area;
1183 		struct graphics_device *dev = term->dev;
1184 		int w = dlg->xw - 2 * DIALOG_LB - sirka_scrollovadla;
1185 		int y = dlg->y + DIALOG_TB;
1186 		int top = 0, bottom = 0;
1187 
1188 		switch (direction) {
1189 			case 1:  /* down */
1190 				top = G_BFU_FONT_SIZE;
1191 				break;
1192 
1193 			case -1:  /* up */
1194 				bottom = -G_BFU_FONT_SIZE;
1195 				break;
1196 
1197 			default:
1198 				internal_error("Wrong direction %d in function scroll_list.\n",direction);
1199 		}
1200 
1201 		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);
1202 		if (drv->flags & GD_DONT_USE_SCROLL && overwrite_instead_of_scroll) {
1203 			redraw_list(term, bla);
1204 		} else {
1205 			int j;
1206 			struct rect_set *rs = g_scroll(dev, 0, top + bottom);
1207 			for (j = 0; j < rs->m; j++) {
1208 				struct rect *r = &rs->r[j];
1209 				struct rect clip1;
1210 				restrict_clip_area(term->dev, &clip1, r->x1, r->y1, r->x2, r->y2);
1211 				redraw_list(term, bla);
1212 				set_clip_area(term->dev, &clip1);
1213 			}
1214 			mem_free(rs);
1215 		}
1216 		set_clip_area(term->dev, &old_area);
1217 
1218 		/* redraw scroll bar */
1219 		{
1220 			int total = get_total_items(ld);
1221 			int visible = get_visible_items(ld);
1222 			int pos = get_scroll_pos(ld);
1223 			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);
1224 			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);
1225 		}
1226 
1227 	}
1228 #endif
1229 }
1230 
list_item_mark(struct dialog_data * dlg,struct dialog_item_data * useless)1231 static int list_item_mark(struct dialog_data *dlg, struct dialog_item_data *useless)
1232 {
1233 	struct list_description *ld = (struct list_description *)dlg->dlg->udata2;
1234 	static struct redraw_data rd;
1235 
1236 	rd.ld = ld;
1237 	rd.dlg = dlg;
1238 	rd.n = 0;
1239 
1240 	if (ld->current_pos != ld->list) ld->current_pos->type ^= 4;
1241 	rd.n = -1;
1242 	if (next_in_tree(ld, ld->current_pos) == ld->list) /* already at the bottom */
1243 	{
1244 		draw_to_window(dlg->win, redraw_list_line, &rd);
1245 		return 0;
1246 	}
1247 	ld->current_pos = next_in_tree(ld, ld->current_pos);
1248 	ld->win_pos++;
1249 	if (ld->win_pos > ld->n_items - 1)  /* scroll down */
1250 	{
1251 		ld->win_pos = ld->n_items - 1;
1252 		ld->win_offset = next_in_tree(ld, ld->win_offset);
1253 		draw_to_window(dlg->win, scroll_list, &rd);
1254 	}
1255 	draw_to_window(dlg->win, redraw_list_line, &rd);
1256 	return 0;
1257 }
1258 
1259 
list_find_next(struct redraw_data * rd,int direction)1260 static void list_find_next(struct redraw_data *rd, int direction)
1261 {
1262 	struct list_description *ld=rd->ld;
1263 	struct dialog_data *dlg=rd->dlg;
1264 	struct session *ses=(struct session *)(dlg->dlg->udata);
1265 	struct list* item;
1266 
1267 	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;}
1268 
1269 	if ((item=ld->find_item(ld->current_pos,ld->search_word,direction)))
1270 	{
1271 		struct list *l;
1272 		ld->current_pos=item;
1273 		ld->win_offset=item;
1274 		ld->win_pos=0;
1275 		if (ld->type)
1276 			for (l=item;l->depth>=0;l=l->fotr)
1277 				if (l!=item) l->type|=2;
1278 
1279 		draw_to_window(dlg->win,redraw_list,rd);
1280 		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);
1281 	}
1282 	else
1283 		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);
1284 }
1285 
list_search_for_back(void * rd_,unsigned char * str)1286 static void list_search_for_back(void *rd_, unsigned char *str)
1287 {
1288 	struct redraw_data *rd = (struct redraw_data *)rd_;
1289 	struct list_description *ld = rd->ld;
1290 
1291 	if (!*str) return;
1292 	if (!ld->open) return;
1293 
1294 	if (ld->search_word) mem_free(ld->search_word);
1295 	ld->search_word = to_utf8_upcase(str, term_charset(rd->dlg->win->term));
1296 	ld->search_direction = -1;
1297 
1298 	list_find_next(rd, ld->search_direction);
1299 }
1300 
list_search_for(void * rd_,unsigned char * str)1301 static void list_search_for(void *rd_, unsigned char *str)
1302 {
1303 	struct redraw_data *rd = (struct redraw_data *)rd_;
1304 	struct list_description *ld = rd->ld;
1305 
1306 	if (!*str) return;
1307 	if (!ld->open) return;
1308 
1309 	if (ld->search_word) mem_free(ld->search_word);
1310 	ld->search_word = to_utf8_upcase(str, term_charset(rd->dlg->win->term));
1311 	ld->search_direction = 1;
1312 
1313 	list_find_next(rd, ld->search_direction);
1314 }
1315 
list_edit_toggle(struct dialog_data * dlg,struct list_description * ld)1316 static void list_edit_toggle(struct dialog_data *dlg, struct list_description *ld)
1317 {
1318 	static struct redraw_data rd;
1319 	ld->current_pos->type^=2;
1320 	if (!(ld->current_pos->type&2))unselect_in_folder(ld, ld->current_pos);
1321 	rd.ld=ld;
1322 	rd.dlg=dlg;
1323 	rd.n=0;
1324 	draw_to_window(dlg->win,redraw_list,&rd);
1325 	draw_to_window(dlg->win,redraw_list_line,&rd);	/* set cursor */
1326 }
1327 
list_event_handler(struct dialog_data * dlg,struct links_event * ev)1328 static int list_event_handler(struct dialog_data *dlg, struct links_event *ev)
1329 {
1330 	struct list_description *ld=(struct list_description*)(dlg->dlg->udata2);
1331 	static struct redraw_data rd;
1332 	struct session *ses=(struct session *)(dlg->dlg->udata);
1333 
1334 	rd.ld=ld;
1335 	rd.dlg=dlg;
1336 	rd.n=0;
1337 
1338 	switch ((int)ev->ev)
1339 	{
1340 		case EV_KBD:
1341 		if (ev->y & KBD_PASTING) break;
1342 		if (ld->type==1)  /* tree list */
1343 		{
1344 			if (ev->x==' ')  /* toggle folder */
1345 			{
1346 				if (!((ld->current_pos->type)&1))return EVENT_PROCESSED;  /* item */
1347 
1348 				list_edit_toggle(dlg, ld);
1349 				return EVENT_PROCESSED;
1350 			}
1351 			if (ev->x=='+'||ev->x=='=')  /* open folder */
1352 			{
1353 				if (!((ld->current_pos->type)&1))return EVENT_PROCESSED;  /* item */
1354 				if ((ld->current_pos->type)&2)return EVENT_PROCESSED; /* already open */
1355 				list_edit_toggle(dlg, ld);
1356 				return EVENT_PROCESSED;
1357 			}
1358 			if (ev->x=='-')  /* close folder */
1359 			{
1360 				if (!((ld->current_pos->type)&1))return EVENT_PROCESSED;  /* item */
1361 				if (!((ld->current_pos->type)&2))return EVENT_PROCESSED; /* already closed */
1362 				list_edit_toggle(dlg, ld);
1363 				return EVENT_PROCESSED;
1364 			}
1365 		}
1366 		if (ev->x == '/' || (ev->x == KBD_FIND && !(ev->y & (KBD_SHIFT | KBD_CTRL | KBD_ALT)))) /* search forward */
1367 		{
1368 			struct redraw_data *r;
1369 
1370 			r=mem_alloc(sizeof(struct redraw_data));
1371 			r->ld=ld;
1372 			r->dlg=dlg;
1373 
1374 			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);
1375 			return EVENT_PROCESSED;
1376 		}
1377 		if (ev->x == '?' || (ev->x == KBD_FIND && ev->y & (KBD_SHIFT | KBD_CTRL | KBD_ALT))) /* search back */
1378 		{
1379 			struct redraw_data *r;
1380 
1381 			r=mem_alloc(sizeof(struct redraw_data));
1382 			r->ld=ld;
1383 			r->dlg=dlg;
1384 
1385 			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);
1386 			return EVENT_PROCESSED;
1387 		}
1388 		if ((ev->x == 'n' && !(ev->y & KBD_ALT)) || ev->x == KBD_REDO) /* find next */
1389 		{
1390 			list_find_next(&rd, ld->search_direction);
1391 			return EVENT_PROCESSED;
1392 		}
1393 		if ((ev->x == 'N' && !(ev->y & KBD_ALT)) || ev->x == KBD_UNDO) /* find prev */
1394 		{
1395 			list_find_next(&rd, - ld->search_direction);
1396 			return EVENT_PROCESSED;
1397 		}
1398 		if (ev->x == KBD_UP)
1399 		{
1400 			if (ld->current_pos==ld->list) goto kbd_up_redraw_exit;  /* already on the top */
1401 			ld->current_pos=prev_in_tree(ld,ld->current_pos);
1402 			ld->win_pos--;
1403 			rd.n=1;
1404 			if (ld->win_pos<0)  /* scroll up */
1405 			{
1406 				ld->win_pos=0;
1407 				ld->win_offset=prev_in_tree(ld,ld->win_offset);
1408 				draw_to_window(dlg->win,scroll_list,&rd);
1409 			}
1410 			kbd_up_redraw_exit:
1411 			draw_to_window(dlg->win,redraw_list_line,&rd);
1412 			return EVENT_PROCESSED;
1413 		}
1414 		if (ev->x == 'i' || ev->x == '*' || ev->x == '8' || ev->x == KBD_INS || ev->x == KBD_SELECT)
1415 		{
1416 			list_item_mark(dlg, NULL);
1417 			return EVENT_PROCESSED;
1418 		}
1419 		if (ev->x == KBD_DOWN)
1420 		{
1421 			if (next_in_tree(ld,ld->current_pos)==ld->list) goto kbd_down_redraw_exit;  /* already at the bottom */
1422 			ld->current_pos=next_in_tree(ld,ld->current_pos);
1423 			ld->win_pos++;
1424 			rd.n=-1;
1425 			if (ld->win_pos>ld->n_items-1)  /* scroll down */
1426 			{
1427 				ld->win_pos=ld->n_items-1;
1428 				ld->win_offset=next_in_tree(ld,ld->win_offset);
1429 				draw_to_window(dlg->win,scroll_list,&rd);
1430 			}
1431 			kbd_down_redraw_exit:
1432 			draw_to_window(dlg->win,redraw_list_line,&rd);
1433 			return EVENT_PROCESSED;
1434 		}
1435 		if (ev->x == KBD_HOME || (upcase(ev->x) == 'A' && ev->y & KBD_CTRL))
1436 		{
1437 			if (ld->current_pos==ld->list) goto kbd_home_redraw_exit;  /* already on the top */
1438 			ld->win_offset=ld->list;
1439 			ld->current_pos=ld->win_offset;
1440 			ld->win_pos=0;
1441 			rd.n=0;
1442 			draw_to_window(dlg->win,redraw_list,&rd);
1443 			kbd_home_redraw_exit:
1444 			draw_to_window(dlg->win,redraw_list_line,&rd);	/* set cursor */
1445 			return EVENT_PROCESSED;
1446 		}
1447 		if (ev->x == KBD_END || (upcase(ev->x) == 'E' && ev->y & KBD_CTRL))
1448 		{
1449 			int a;
1450 
1451 			if (ld->current_pos==prev_in_tree(ld,ld->list)) goto kbd_end_redraw_exit;  /* already on the top */
1452 			ld->win_offset=prev_in_tree(ld,ld->list);
1453 			for (a=1;a<ld->n_items&&ld->win_offset!=ld->list;a++)
1454 				ld->win_offset=prev_in_tree(ld,ld->win_offset);
1455 			ld->current_pos=prev_in_tree(ld,ld->list);
1456 			ld->win_pos=a-1;
1457 			rd.n=0;
1458 			draw_to_window(dlg->win,redraw_list,&rd);
1459 			kbd_end_redraw_exit:
1460 			draw_to_window(dlg->win,redraw_list_line,&rd);	/* set cursor */
1461 			return EVENT_PROCESSED;
1462 		}
1463 		if (ev->x == KBD_PAGE_UP || (upcase(ev->x) == 'B' && ev->y & KBD_CTRL))
1464 		{
1465 			int a;
1466 
1467 			if (ld->current_pos==ld->list) goto kbd_page_up_redraw_exit;  /* already on the top */
1468 			for (a=0;a<ld->n_items&&ld->win_offset!=ld->list;a++)
1469 			{
1470 				ld->win_offset=prev_in_tree(ld,ld->win_offset);
1471 				ld->current_pos=prev_in_tree(ld,ld->current_pos);
1472 			}
1473 			if (a<ld->n_items){ld->current_pos=ld->win_offset;ld->win_pos=0;}
1474 			rd.n=0;
1475 			draw_to_window(dlg->win,redraw_list,&rd);
1476 			kbd_page_up_redraw_exit:
1477 			draw_to_window(dlg->win,redraw_list_line,&rd);	/* set cursor */
1478 			return EVENT_PROCESSED;
1479 		}
1480 		if (ev->x == KBD_PAGE_DOWN || (upcase(ev->x) == 'F' && ev->y & KBD_CTRL))
1481 		{
1482 			int a;
1483 			struct list*p=ld->win_offset;
1484 
1485 			if (ld->current_pos==prev_in_tree(ld,ld->list)) goto kbd_page_down_redraw_exit;  /* already on the bottom */
1486 			for (a=0;a<ld->n_items&&ld->list!=next_in_tree(ld,p);a++)
1487 				p=next_in_tree(ld,p);
1488 			if (a<ld->n_items)  /* already last screen */
1489 			{
1490 				ld->current_pos=p;
1491 				ld->win_pos=a;
1492 				rd.n=0;
1493 				draw_to_window(dlg->win,redraw_list,&rd);
1494 				draw_to_window(dlg->win,redraw_list_line,&rd);	/* set cursor */
1495 				return EVENT_PROCESSED;
1496 			}
1497 			/* here is whole screen only - the window was full before pressing the page-down key */
1498 			/* p is pointing behind last item of the window (behind last visible item in the window) */
1499 			for (a=0;a<ld->n_items&&p!=ld->list;a++)
1500 			{
1501 				ld->win_offset=next_in_tree(ld,ld->win_offset);
1502 				ld->current_pos=next_in_tree(ld,ld->current_pos);
1503 				p=next_in_tree(ld,p);
1504 			}
1505 			if (a<ld->n_items){ld->current_pos=prev_in_tree(ld,ld->list);ld->win_pos=ld->n_items-1;}
1506 			rd.n=0;
1507 			draw_to_window(dlg->win,redraw_list,&rd);
1508 			kbd_page_down_redraw_exit:
1509 			draw_to_window(dlg->win,redraw_list_line,&rd);	/* set cursor */
1510 			return EVENT_PROCESSED;
1511 		}
1512 		break;
1513 
1514 		case EV_MOUSE:
1515 		/* toggle select item */
1516 		if ((ev->b & BM_ACT) == B_DOWN && (ev->b & BM_BUTT) == B_RIGHT) {
1517 			int n,a;
1518 			struct list *l=ld->win_offset;
1519 
1520 			last_mouse_y=ev->y;
1521 
1522 			if (
1523 				(ev->y)<(dlg->y+DIALOG_TB)||
1524 				(ev->y)>=(dlg->y+DIALOG_TB+gf_val(ld->n_items,G_BFU_FONT_SIZE*(ld->n_items)))||
1525 				(ev->x)<(dlg->x+DIALOG_LB)||
1526 				(ev->x)>(dlg->x+dlg->xw-DIALOG_LB-(F?sirka_scrollovadla:0))
1527 			)break;  /* out of the dialog */
1528 
1529 			n=(ev->y-dlg->y-DIALOG_TB)/gf_val(1,G_BFU_FONT_SIZE);
1530 			for (a=0;a<n;a++)
1531 			{
1532 				struct list *l1;
1533 				l1=next_in_tree(ld,l);  /* current item under the mouse pointer */
1534 				if (l1==ld->list)goto break2;
1535 				else l=l1;
1536 			}
1537 			/*a=ld->type?((l->depth)>=0?(l->depth)+1:0):(l->depth>=0);*/
1538 
1539 			l->type^=4;
1540 			ld->current_pos=l;
1541 			ld->win_pos=n;
1542 			rd.n=0;
1543 			draw_to_window(dlg->win,redraw_list,&rd);
1544 			draw_to_window(dlg->win,redraw_list_line,&rd);	/* set cursor */
1545 			return EVENT_PROCESSED;
1546 		}
1547 		/* click on item */
1548 		if (((ev->b & BM_ACT) == B_DOWN || (ev->b & BM_ACT) == B_DRAG) && (ev->b & BM_BUTT) == B_LEFT) {
1549 			int n,a;
1550 			struct list *l=ld->win_offset;
1551 
1552 			last_mouse_y=ev->y;
1553 
1554 			if (
1555 				(ev->y)<(dlg->y+DIALOG_TB)||
1556 				(ev->y)>=(dlg->y+DIALOG_TB+gf_val(ld->n_items,G_BFU_FONT_SIZE*(ld->n_items)))||
1557 				(ev->x)<(dlg->x+DIALOG_LB)||
1558 				(ev->x)>(dlg->x+dlg->xw-DIALOG_LB-(F?sirka_scrollovadla:0))
1559 			)goto skip_item_click;  /* out of the dialog */
1560 
1561 			n=(ev->y-dlg->y-DIALOG_TB)/gf_val(1,G_BFU_FONT_SIZE);
1562 			for (a=0;a<n;a++)
1563 			{
1564 				struct list *l1;
1565 				l1=next_in_tree(ld,l);  /* current item under the mouse pointer */
1566 				if (l1==ld->list) {
1567 					n=a;
1568 					break;
1569 				}
1570 				else l=l1;
1571 			}
1572 			a=ld->type?((l->depth)>=0?(l->depth)+1:0):(l->depth>=0);
1573 
1574 			ld->current_pos=l;
1575 
1576 			/* clicked on directory graphical stuff */
1577 			if ((ev->b & BM_ACT) == B_DOWN && ld->type && ev->x < (dlg->x + DIALOG_LB + a * BFU_ELEMENT_WIDTH) && (l->type & 1)) {
1578 				l->type^=2;
1579 				if (!(l->type&2))unselect_in_folder(ld, ld->current_pos);
1580 			}
1581 			ld->win_pos=n;
1582 			rd.n=0;
1583 			draw_to_window(dlg->win,redraw_list,&rd);
1584 			draw_to_window(dlg->win,redraw_list_line,&rd);	/* set cursor */
1585 			return EVENT_PROCESSED;
1586 		}
1587 		/* scroll with the bar */
1588 		skip_item_click:
1589 #ifdef G
1590 		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)) {
1591 			int total=get_total_items(ld);
1592 			int scroll_pos;
1593 			int redraw_all;
1594 			int rep = 0;
1595 			long delta;
1596 			long h=ld->n_items*G_BFU_FONT_SIZE;
1597 
1598 			if (
1599 				(ev->y)<(dlg->y+DIALOG_TB)||
1600 				(ev->y)>=(dlg->y+DIALOG_TB+G_BFU_FONT_SIZE*(ld->n_items))||
1601 				(ev->x)<(dlg->x+dlg->xw-DIALOG_LB-G_SCROLL_BAR_WIDTH)||
1602 				(ev->x)>(dlg->x+dlg->xw-DIALOG_LB)
1603 			)break;  /* out of the dialog */
1604 
1605 			again:
1606 			rep++;
1607 			if (rep > total) return EVENT_PROCESSED;
1608 			scroll_pos=get_scroll_pos(ld);
1609 			delta=(ev->y-dlg->y-DIALOG_TB)*total/h-scroll_pos;
1610 
1611 			last_mouse_y=ev->y;
1612 
1613 			if (delta>0)  /* scroll down */
1614 			{
1615 				struct list *lll=find_last_in_window(ld);
1616 
1617 				if (next_in_tree(ld,lll)==ld->list)return EVENT_PROCESSED;  /* already at the bottom */
1618 				redraw_all = ld->current_pos != lll;
1619 				ld->current_pos=next_in_tree(ld,lll);
1620 				ld->win_offset=next_in_tree(ld,ld->win_offset);
1621 				ld->win_pos=ld->n_items-1;
1622 				rd.n=-1;
1623 				if (!redraw_all) {
1624 					draw_to_window(dlg->win,scroll_list,&rd);
1625 					draw_to_window(dlg->win,redraw_list_line,&rd);
1626 				} else {
1627 					draw_to_window(dlg->win,redraw_list,&rd);
1628 				}
1629 				goto again;
1630 			}
1631 			if (delta<0)  /* scroll up */
1632 			{
1633 				if (ld->win_offset==ld->list)return EVENT_PROCESSED;  /* already on the top */
1634 				redraw_all = ld->current_pos != ld->win_offset;
1635 				ld->win_offset=prev_in_tree(ld,ld->win_offset);
1636 				ld->current_pos=ld->win_offset;
1637 				ld->win_pos=0;
1638 				rd.n=+1;
1639 				if (!redraw_all) {
1640 					draw_to_window(dlg->win,scroll_list,&rd);
1641 					draw_to_window(dlg->win,redraw_list_line,&rd);
1642 				} else {
1643 					draw_to_window(dlg->win,redraw_list,&rd);
1644 				}
1645 				goto again;
1646 			}
1647 			return EVENT_PROCESSED;
1648 
1649 		}
1650 #endif
1651 		if ((ev->b & BM_ACT) == B_DRAG && (ev->b & BM_BUTT) == B_MIDDLE) {
1652 			long delta=(ev->y-last_mouse_y)/MOUSE_SCROLL_DIVIDER;
1653 
1654 			last_mouse_y=ev->y;
1655 			if (delta>0)  /* scroll down */
1656 			{
1657 				if (next_in_tree(ld,ld->current_pos)==ld->list)return EVENT_PROCESSED;  /* already at the bottom */
1658 				ld->current_pos=next_in_tree(ld,ld->current_pos);
1659 				ld->win_pos++;
1660 				rd.n=-1;
1661 				if (ld->win_pos>ld->n_items-1)  /* scroll down */
1662 				{
1663 					ld->win_pos=ld->n_items-1;
1664 					ld->win_offset=next_in_tree(ld,ld->win_offset);
1665 					draw_to_window(dlg->win,scroll_list,&rd);
1666 				}
1667 				draw_to_window(dlg->win,redraw_list_line,&rd);
1668 			}
1669 			if (delta<0)  /* scroll up */
1670 			{
1671 				if (ld->current_pos==ld->list)return EVENT_PROCESSED;  /* already on the top */
1672 				ld->current_pos=prev_in_tree(ld,ld->current_pos);
1673 				ld->win_pos--;
1674 				rd.n=+1;
1675 				if (ld->win_pos<0)  /* scroll up */
1676 				{
1677 					ld->win_pos=0;
1678 					ld->win_offset=prev_in_tree(ld,ld->win_offset);
1679 					draw_to_window(dlg->win,scroll_list,&rd);
1680 				}
1681 				draw_to_window(dlg->win,redraw_list_line,&rd);
1682 			}
1683 			return EVENT_PROCESSED;
1684 
1685 		}
1686 		/* mouse wheel */
1687 		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)) {
1688 			int button=(int)ev->b&BM_BUTT;
1689 			last_mouse_y=ev->y;
1690 
1691 			if (button==B_WHEELDOWN||button==B_WHEELDOWN1)  /* scroll down */
1692 			{
1693 				if (next_in_tree(ld,ld->current_pos)==ld->list)return EVENT_PROCESSED;  /* already at the bottom */
1694 				ld->current_pos=next_in_tree(ld,ld->current_pos);
1695 				ld->win_pos++;
1696 				rd.n=-1;
1697 				if (ld->win_pos>ld->n_items-1)  /* scroll down */
1698 				{
1699 					ld->win_pos=ld->n_items-1;
1700 					ld->win_offset=next_in_tree(ld,ld->win_offset);
1701 					draw_to_window(dlg->win,scroll_list,&rd);
1702 				}
1703 				draw_to_window(dlg->win,redraw_list_line,&rd);
1704 			}
1705 			if (button==B_WHEELUP||button==B_WHEELUP1)  /* scroll up */
1706 			{
1707 				if (ld->current_pos==ld->list)return EVENT_PROCESSED;  /* already on the top */
1708 				ld->current_pos=prev_in_tree(ld,ld->current_pos);
1709 				ld->win_pos--;
1710 				rd.n=+1;
1711 				if (ld->win_pos<0)  /* scroll up */
1712 				{
1713 					ld->win_pos=0;
1714 					ld->win_offset=prev_in_tree(ld,ld->win_offset);
1715 					draw_to_window(dlg->win,scroll_list,&rd);
1716 				}
1717 				draw_to_window(dlg->win,redraw_list_line,&rd);
1718 			}
1719 			return EVENT_PROCESSED;
1720 
1721 		}
1722 		break2:
1723 		break;
1724 
1725 		case EV_INIT:
1726 		case EV_RESIZE:
1727 		case EV_REDRAW:
1728 		case EV_ABORT:
1729 		break;
1730 
1731 		default:
1732 		break;
1733 
1734 	}
1735 	return EVENT_NOT_PROCESSED;
1736 }
1737 
1738 
1739 /* display function for the list window */
create_list_window_fn(struct dialog_data * dlg)1740 static void create_list_window_fn(struct dialog_data *dlg)
1741 {
1742 	struct terminal *term=dlg->win->term;
1743 	struct list_description *ld=(struct list_description*)(dlg->dlg->udata2);
1744 	int min=0;
1745 	int w,rw,y;
1746 	int n_items;
1747 	struct redraw_data rd;
1748 
1749 	int a=7;
1750 
1751 	ld->dlg=dlg;
1752 	if (ld->button_fn)a++;  /* user button */
1753 	if (ld->type==1)a++;  /* add directory button */
1754 
1755 	y = 0;
1756 	min_buttons_width(term, dlg->items, a, &min);
1757 
1758 	w = term->x * 19 / 20 - 2 * DIALOG_LB;
1759 	if (w<min)w=min;
1760 	if (w>term->x-2*DIALOG_LB)w=term->x-2*DIALOG_LB;
1761 	if (w<5)w=5;
1762 
1763 	rw=0;
1764 	dlg_format_buttons(dlg, NULL, dlg->items, a, 0, &y, w, &rw, AL_CENTER);
1765 
1766 	n_items = term->y - y;
1767 	if (!term->spec->braille)
1768 		n_items -= gf_val(2, 3) * DIALOG_TB + gf_val(2, 2*G_BFU_FONT_SIZE);
1769 	else
1770 		n_items -= 2;
1771 #ifdef G
1772 	if (F) n_items /= G_BFU_FONT_SIZE;
1773 #endif
1774 	if (n_items < 2) n_items = 2;
1775 	ld->n_items = n_items;
1776 
1777 	while (ld->win_pos > ld->n_items - 1) {
1778 		ld->current_pos=prev_in_tree(ld,ld->current_pos);
1779 		ld->win_pos--;
1780 	}
1781 
1782 	y += gf_val(ld->n_items,ld->n_items*G_BFU_FONT_SIZE);
1783 
1784 	rw=w;
1785 	dlg->xw=rw+2*DIALOG_LB;
1786 	dlg->yw=y+2*DIALOG_TB;
1787 	center_dlg(dlg);
1788 	draw_dlg(dlg);
1789 
1790 	rd.ld=ld;
1791 	rd.dlg=dlg;
1792 	rd.n=0;
1793 
1794 	draw_to_window(dlg->win,redraw_list,&rd);
1795 
1796 	y=dlg->y+DIALOG_TB+gf_val(ld->n_items+1,(ld->n_items+1)*G_BFU_FONT_SIZE);
1797 	dlg_format_buttons(dlg, term, dlg->items, a, dlg->x+DIALOG_LB, &y, w, &rw, AL_CENTER);
1798 }
1799 
1800 
close_list_window(struct dialog_data * dlg)1801 static void close_list_window(struct dialog_data *dlg)
1802 {
1803 	struct dialog *d=dlg->dlg;
1804 	struct list_description *ld=(struct list_description*)(d->udata2);
1805 
1806 	ld->open=0;
1807 	ld->dlg=NULL;
1808 	if (ld->search_word) mem_free(ld->search_word);
1809 	ld->search_word=NULL;
1810 	if (ld->save) ld->save(d->udata);
1811 }
1812 
test_list_window_in_use(struct list_description * ld,struct terminal * term)1813 int test_list_window_in_use(struct list_description *ld, struct terminal *term)
1814 {
1815 	if (ld->open) {
1816 		if (term)
1817 			msg_box(
1818 				term,
1819 				NULL,
1820 				TEXT_(T_INFO),
1821 				AL_CENTER,
1822 				TEXT_(ld->already_in_use),MSG_BOX_END,
1823 				NULL,
1824 				1,
1825 				TEXT_(T_CANCEL),msg_box_null,B_ENTER|B_ESC
1826 			);
1827 		return 1;
1828 	}
1829 	return 0;
1830 }
1831 
1832 /* dialog->udata2  ...  list_description  */
1833 /* dialog->udata   ...  session */
create_list_window(struct list_description * ld,struct list * list,struct terminal * term,struct session * ses)1834 int create_list_window(
1835 	struct list_description *ld,
1836 	struct list *list,
1837 	struct terminal *term,
1838 	struct session *ses
1839 	)
1840 {
1841 	struct dialog *d;
1842 	int a;
1843 
1844 	/* zavodime, zavodime... */
1845 	if (test_list_window_in_use(ld, term))
1846 		return 1;
1847 	ld->open=1;
1848 
1849 	if (!ld->current_pos)
1850 	{
1851 		ld->current_pos=list;
1852 		ld->win_offset=list;
1853 		ld->win_pos=0;
1854 		ld->dlg=NULL;
1855 	}
1856 
1857 	a=8;
1858 	if (ld->button_fn)a++;
1859 	if (ld->type==1)a++;
1860 
1861 	d = mem_calloc(sizeof(struct dialog) + a * sizeof(struct dialog_item));
1862 
1863 	d->title=TEXT_(ld->window_title);
1864 	d->fn=create_list_window_fn;
1865 	d->abort=close_list_window;
1866 	d->handle_event=list_event_handler;
1867 	d->udata=ses;
1868 	d->udata2=ld;
1869 
1870 	a=0;
1871 
1872 	if (ld->button_fn)
1873 	{
1874 		d->items[a].type=D_BUTTON;
1875 		d->items[a].fn=list_item_button;
1876 		d->items[a].text=TEXT_(ld->button);
1877 		a++;
1878 	}
1879 
1880 	if (ld->type==1)
1881 	{
1882 		d->items[a].type=D_BUTTON;
1883 		d->items[a].text=TEXT_(T_FOLDER);
1884 		d->items[a].fn=list_folder_add;
1885 		a++;
1886 	}
1887 
1888 	d->items[a].type=D_BUTTON;
1889 	d->items[a].text=TEXT_(T_ADD);
1890 	d->items[a].fn=list_item_add;
1891 
1892 	d->items[a+1].type=D_BUTTON;
1893 	d->items[a+1].text=TEXT_(T_DELETE);
1894 	d->items[a+1].fn=list_item_delete;
1895 
1896 	d->items[a+2].type=D_BUTTON;
1897 	d->items[a+2].text=TEXT_(T_EDIT);
1898 	d->items[a+2].fn=list_item_edit;
1899 
1900 	d->items[a+3].type=D_BUTTON;
1901 	d->items[a+3].text=TEXT_(T_SELECT);
1902 	d->items[a+3].fn=list_item_mark;
1903 
1904 	d->items[a+4].type=D_BUTTON;
1905 	d->items[a+4].text=TEXT_(T_MOVE);
1906 	d->items[a+4].fn=list_item_move;
1907 
1908 	d->items[a+5].type=D_BUTTON;
1909 	d->items[a+5].text=TEXT_(T_UNSELECT_ALL);
1910 	d->items[a+5].fn=list_item_unselect;
1911 
1912 	d->items[a+6].type=D_BUTTON;
1913 	d->items[a+6].gid=B_ESC;
1914 	d->items[a+6].fn=cancel_dialog;
1915 	d->items[a+6].text=TEXT_(T_CLOSE);
1916 
1917 	d->items[a+7].type=D_END;
1918 	do_dialog(term, d, getml(d, NULL));
1919 	return 0;
1920 }
1921 
1922 
reinit_list_window(struct list_description * ld)1923 void reinit_list_window(struct list_description *ld)
1924 {
1925 	ld->current_pos=ld->list;
1926 	ld->win_offset=ld->list;
1927 	ld->win_pos=0;
1928 
1929 	if (ld->open) internal_error("reinit_list_window: calling reinit while open");
1930 }
1931 
1932 
1933