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