2 /******************************************************************************
3 * MODULE : file_chooser.cpp
4 * DESCRIPTION: A file_chooser widget with horizontal and vertical scrollbars.
5 * COPYRIGHT : (C) 1999 Joris van der Hoeven
6 *******************************************************************************
7 * This software falls under the GNU general public license version 3 or later.
8 * It comes WITHOUT ANY WARRANTY WHATSOEVER. For details, see the file LICENSE
9 * in the root directory or <http://www.gnu.org/licenses/gpl-3.0.html>.
10 ******************************************************************************/
12 #include "Widkit/basic_widget.hpp"
13 #include "Widkit/attribute_widget.hpp"
14 #include "Widkit/layout.hpp"
16 #include "bitmap_font.hpp"
20 #include "image_files.hpp"
21 #include "analyze.hpp"
28 /******************************************************************************
29 * File chooser commands
30 ******************************************************************************/
35 #define BUTTON_TEXTS 3
36 #define BUTTON_FILE_OK 4
37 #define BUTTON_DIR_OK 5
38 #define BUTTON_CANCEL 6
41 #define IMAGE_CLIP_X1 9
42 #define IMAGE_CLIP_Y1 10
43 #define IMAGE_CLIP_X2 11
44 #define IMAGE_CLIP_Y2 12
45 #define CHANGE_SUFFIXES 13
47 class file_chooser_command_rep
: public command_rep
{
51 file_chooser_command_rep (wk_widget w
, int t
): fch(w
.rep
), type(t
) {}
53 tm_ostream
& print (tm_ostream
& out
) {
54 return out
<< "File chooser command (" << type
<< ")"; }
58 file_chooser_command_rep::apply () {
59 wk_widget
fch_wid (fch
);
64 fch_wid
[0]["file"]["input"] << get_string ("input", s
);
65 fch_wid
<< set_string ("return", scm_unquote (s
));
71 fch_wid
[0]["directory"]["input"] << get_string ("input", dir
);
72 if (dir
== "#f") fch_wid
<< set_string ("return", "#f");
74 dir
= scm_unquote (dir
);
75 fch_wid
<< set_string ("directory", dir
);
80 fch_wid
<< set_string ("directory", "~");
83 fch_wid
<< set_string ("directory",
84 as_string (url ("$TEXMACS_HOME_PATH", "texts")));
89 fch_wid
[0]["file"]["input"] << get_string ("input", s
);
90 fch_wid
<< set_string ("return", scm_unquote (s
));
96 fch_wid
[0]["directory"]["input"] << get_string ("input", s
);
97 fch_wid
<< set_string ("return", scm_unquote (s
));
101 fch_wid
<< set_string ("return", "#f");
103 case CHANGE_SUFFIXES
:
106 fch_wid
[0]["suffixes"]["input"] << get_string ("input", sxs
);
107 fch_wid
<< set_string ("suffixes", scm_unquote (sxs
));
113 if (type
== IMAGE_HSIZE
) which
= "hsize";
114 else if (type
== IMAGE_VSIZE
) which
= "vsize";
115 else if (type
== IMAGE_CLIP_X1
) which
= "clip-x1";
116 else if (type
== IMAGE_CLIP_Y1
) which
= "clip-y1";
117 else if (type
== IMAGE_CLIP_X2
) which
= "clip-x2";
118 else which
= "clip-y2";
119 wk_widget inp
= fch_wid
[0]["image"]["parameters"][which
]["input"];
120 inp
<< get_string ("input", s
);
121 if (s
== "#f") fch_wid
<< set_string ("return", "#f");
122 else inp
<< set_string ("input", scm_unquote (s
));
129 file_chooser_command (wk_widget fch
, int type
) {
130 return tm_new
<file_chooser_command_rep
> (fch
, type
);
133 /******************************************************************************
135 ******************************************************************************/
137 class file_list_widget_rep
: public attribute_widget_rep
{
142 array
<string
> suffix
;
147 file_list_widget_rep (wk_widget ch
, array
<string
> suffix
, bool dir_flag
);
150 wk_widget
get_canvas ();
152 void handle_get_size (get_size_event ev
);
153 void handle_repaint (repaint_event ev
);
154 void handle_mouse (mouse_event ev
);
155 void handle_set_string (set_string_event ev
);
158 /******************************************************************************
159 * Implementation of file_list widgets
160 ******************************************************************************/
162 file_list_widget_rep::file_list_widget_rep (
163 wk_widget c
, array
<string
> s
, bool f
):
164 attribute_widget_rep (0), fch (c
.rep
),
165 dir (""), suffix (s
), dir_flag (f
), hilight (-1) {}
167 file_list_widget_rep::operator tree () {
172 file_list_widget_rep::get_canvas () {
173 string
which (dir_flag
? string ("directories"): string ("files"));
174 wk_widget
fch_wid (fch
);
175 return fch_wid
[0]["list"][which
];
179 has_suffix (string name
, array
<string
> suffix
) {
181 for (i
=0; i
<N(suffix
); i
++)
182 if (ends (locase_all (name
), suffix
[i
])) return true;
187 list_in_directory (string dir
, string name
,
188 array
<string
> suffix
, bool dir_flag
)
190 if (name
== "") return false;
191 if (name
== "..") return dir_flag
;
192 if (name
[0]=='.') return false;
193 if (dir_flag
) return is_directory (url_system (dir
, name
));
194 else return is_regular (url_system (dir
, name
)) && has_suffix (name
, suffix
);
198 file_list_widget_rep::handle_get_size (get_size_event ev
) {
201 font fn
= get_default_font ();
203 for (i
=0; i
<N(names
); i
++)
205 fn
->var_get_extents (names
[i
], ex
);
206 ev
->w
= max (ev
->w
, ((ex
->x2
- ex
->x1
+ 2)/3) + (6*PIXEL
));
207 ev
->h
+= ((fn
->y2
- fn
->y1
+ 2)/3) + (4*PIXEL
);
209 abs_round (ev
->w
, ev
->h
);
213 file_list_widget_rep::handle_repaint (repaint_event ev
) { (void) ev
;
214 renderer ren
= win
->get_renderer ();
217 ren
->set_background (white
);
218 ren
->clear (0, -h
, w
, 0);
219 font fn
= get_default_font ();
220 ren
->set_shrinking_factor (3);
222 for (i
=0; i
<N(names
); i
++)
224 ren
->set_color (black
);
225 if (hilight
== i
) ren
->set_color (red
);
226 fn
->var_get_extents (names
[i
], ex
);
227 fn
->draw (ren
, names
[i
], 9*PIXEL
, y
-fn
->y2
-6*PIXEL
);
228 y
+= fn
->y1
- fn
->y2
- 12*PIXEL
;
230 ren
->set_shrinking_factor (1);
234 file_list_widget_rep::handle_mouse (mouse_event ev
) {
235 string type
= ev
->type
;
237 if ((type
== "release-left") || (type
== "release-right")) {
239 SI y
= 0, search
= ev
->y
*3;
241 font fn
= get_default_font ();
242 for (i
=0; i
<N(names
); i
++)
244 fn
->var_get_extents (names
[i
], ex
);
245 if ((search
>= (y
+ fn
->y1
- fn
->y2
- 12*PIXEL
)) && (search
< y
)) break;
246 y
+= fn
->y1
- fn
->y2
- 12*PIXEL
;
248 if (i
==N(names
)) return;
251 wk_widget
fch_wid (fch
);
254 string name
= as_string (url_system (dir
, s
));
255 fch_wid
<< set_string ("directory", name
);
257 else fch_wid
<< set_string ("return", s
);
261 if (!dir_flag
) fch_wid
<< set_string ("file", s
);
262 this << emit_invalidate_all ();
266 if ((type
== "press-up") || (type
== "press-down")) {
267 SI x
, y
, dy
= 100*PIXEL
;
268 if (type
== "press-down") dy
= -dy
;
269 get_canvas () << get_coord2 ("scroll position", x
, y
);
271 get_canvas () << set_scroll_pos (x
, y
);
276 file_list_widget_rep::handle_set_string (set_string_event ev
) {
277 if (ev
->which
== "directory") {
280 names
= read_directory (url_system (dir
), flag
);
281 lids
= array
<bool>(N(names
));
282 for (int i
=0; i
<N(names
); i
++)
283 lids
[i
]= list_in_directory (dir
, names
[i
], suffix
, dir_flag
);
285 this << get_size (w
, h
, 0);
286 get_canvas () << set_extents (0, -h
, w
, 0);
288 if (attached ()) this << emit_invalidate_all ();
290 else attribute_widget_rep::handle_set_string (ev
);
293 /******************************************************************************
295 ******************************************************************************/
297 class image_widget_rep
: public attribute_widget_rep
{
302 void handle_get_size (get_size_event ev
);
303 void handle_repaint (repaint_event ev
);
304 void handle_set_string (set_string_event ev
);
307 /******************************************************************************
308 * Implementation of image widgets
309 ******************************************************************************/
311 image_widget_rep::image_widget_rep ():
312 attribute_widget_rep (0, south_west
), file_name ("") {}
314 image_widget_rep::operator tree () {
319 image_widget_rep::handle_get_size (get_size_event ev
) {
324 image_widget_rep::handle_repaint (repaint_event ev
) { (void) ev
;
325 renderer ren
= win
->get_renderer ();
326 ren
->set_background (white
);
327 ren
->clear (0, 0, w
, h
);
328 layout_dark_outline (ren
, 0, 0, w
, h
);
329 if (file_name
!= "") {
331 image_size (url_system (file_name
), iw
, ih
);
333 SI ww
= w
-2*PIXEL
, hh
= h
-2*PIXEL
;
334 if ((ww
>0) && (hh
>0) && (iw
>0) && (ih
>0)) {
335 if (iw
* hh
> ih
* ww
)
337 else ww
= (hh
* iw
) / ih
;
340 ren
->image (url_system (file_name
),
341 ww
, hh
, PIXEL
, PIXEL
, 0.0, 0.0, 1.0, 1.0);
346 image_widget_rep::handle_set_string (set_string_event ev
) {
347 if (ev
->which
== "name") {
349 if (attached ()) this << emit_invalidate_all ();
351 else attribute_widget_rep::handle_set_string (ev
);
354 /******************************************************************************
355 * File_Chooser widgets
356 ******************************************************************************/
358 class file_chooser_widget_rep
: public attribute_widget_rep
{
361 array
<string
> suffix
;
365 file_chooser_widget_rep (command cmd
, string type
, string magn
);
368 wk_widget
input_widget (string what
, int type
);
369 wk_widget
button_widget (string what
, int type
);
371 void handle_get_size (get_size_event ev
);
372 void handle_set_string (set_string_event ev
);
373 void handle_get_string (get_string_event ev
);
374 void handle_destroy (destroy_event ev
);
377 /******************************************************************************
378 * Drives under Windows
379 ******************************************************************************/
382 class drive_menu_command_rep
: public command_rep
{
384 file_chooser_widget_rep
*fileChooser
;
387 drive_menu_command_rep (file_chooser_widget_rep
*fileChooser2
,
388 string driveLetter2
):
389 fileChooser (fileChooser2
), driveLetter(driveLetter2
) {}
391 fileChooser
<< set_string("directory", driveLetter
);
396 /******************************************************************************
397 * Implementation of file_chooser widgets
398 ******************************************************************************/
401 file_chooser_widget_rep::input_widget (string what
, int type
) {
402 array
<wk_widget
> ww (2);
403 array
<string
> nn (2);
404 ww
[0]= text_wk_widget (what
, false, "english");
405 ww
[1]= input_text_wk_widget (file_chooser_command (this, type
));
407 if (type
== CHANGE_DIR
) ww
[1] << set_string ("type", "directory");
408 return horizontal_list (ww
, nn
);
412 file_chooser_widget_rep::button_widget (string what
, int type
) {
413 return command_button (text_wk_widget (what
, false, "english"),
414 file_chooser_command (this, type
), true);
417 file_chooser_widget_rep::file_chooser_widget_rep (
418 command cmd2
, string type2
, string magn2
):
419 attribute_widget_rep (1), cmd (cmd2
), type (type2
), magn (magn2
)
423 tree t
= stree_to_tree (call ("format-get-suffixes*", type
));
426 suffix
<< ("." * as_string (t
[i
]));
427 if (n
== 0) suffix
<< string ("");
431 if (type
== "directory") cw2n
= 3;
432 array
<wk_widget
> cw2 (cw2n
);
433 array
<string
> cn2 (cw2n
);
434 cw2
[0]= glue_wk_widget (false, true, sep
);
436 canvas_widget (wk_widget (tm_new
<file_list_widget_rep
> (this, suffix
, true)));
437 cn2
[1]= "directories";
438 cw2
[2]= glue_wk_widget (false, true, sep
);
439 if (type
!= "directory") {
441 canvas_widget (wk_widget (tm_new
<file_list_widget_rep
> (this,suffix
,false)));
443 cw2
[4]= glue_wk_widget (false, true, sep
-PIXEL
);
447 wk_widget drive_menu
= vertical_menu (array
<wk_widget
> ());
448 unsigned int driveMask
= XGetDrivesMask();
449 char driveString
[4] = "A:\\";
450 for (char x
= 'A'; x
<= 'Z'; x
++)
451 if(driveMask
& (1 << (x
- 'A'))) {
453 drive_menu
<< emit_insert (driveString
,
454 command_button (text_wk_widget (driveString
),
455 tm_new
<drive_menu_command_rep
> (this, driveString
)));
457 array
<wk_widget
> drw (2);
458 drw
[0] = pullright_button (text_wk_widget ("Drive"), drive_menu
);
459 drw
[1] = text_wk_widget("");
460 // drw[1]= glue_wk_widget (false, true, sep);
463 int BUTTON_OK
= BUTTON_FILE_OK
;
464 if (type
== "directory") BUTTON_OK
= BUTTON_DIR_OK
;
467 array
<wk_widget
> cw3 (11);
468 cw3
[0]= glue_wk_widget (false, false, sep
);
469 cw3
[1]= pulldown_button (text_wk_widget ("Drive"), drive_menu
, true);
470 cw3
[2]= glue_wk_widget (false, false, sep
);
471 cw3
[3]= button_widget ("Home", BUTTON_HOME
);
472 cw3
[4]= glue_wk_widget (false, false, sep
);
473 cw3
[5]= button_widget ("Texts", BUTTON_TEXTS
);
474 cw3
[6]= glue_wk_widget (true, false);
475 cw3
[7]= button_widget ("Ok", BUTTON_OK
);
476 cw3
[8]= glue_wk_widget (false, false, sep
);
477 cw3
[9]= button_widget ("Cancel", BUTTON_CANCEL
);
478 cw3
[10]= glue_wk_widget (false, false, sep
);
480 array
<wk_widget
> cw3 (9);
481 cw3
[0]= glue_wk_widget (false, false, sep
);
482 cw3
[1]= button_widget ("Home", BUTTON_HOME
);
483 cw3
[2]= glue_wk_widget (false, false, sep
);
484 cw3
[3]= button_widget ("Texts", BUTTON_TEXTS
);
485 cw3
[4]= glue_wk_widget (true, false);
486 cw3
[5]= button_widget ("Ok", BUTTON_OK
);
487 cw3
[6]= glue_wk_widget (false, false, sep
);
488 cw3
[7]= button_widget ("Cancel", BUTTON_CANCEL
);
490 cw3
[8]= glue_wk_widget (false, false, sep
+ 14*PIXEL
);
492 cw3
[8]= glue_wk_widget (false, false, sep
);
497 if (type
== "image") cwn
= 17;
498 if (type
== "directory") cwn
= 7;
499 array
<wk_widget
> cw (cwn
);
500 array
<string
> cn (cwn
);
501 cw
[0]= glue_wk_widget (true, false, 0, sep
);
502 cw
[1]= input_widget ("Directory:", CHANGE_DIR
);
504 cw
[2]= glue_wk_widget (true, false, 0, sep
);
506 if (type
== "directory") {
507 cw
[3]= horizontal_list (cw2
, cn2
);
511 if (type
!= "directory") {
512 cw
[3]= input_widget ("File:", CHANGE_FILE
);
514 cw
[4]= glue_wk_widget (true, false, 0, sep
);
515 cw
[5]= input_widget ("Suffixes:", CHANGE_SUFFIXES
);
517 cw
[6]= glue_wk_widget (true, false, 0, sep
);
518 cw
[7]= horizontal_list (cw2
, cn2
);
522 if (type
== "image") {
523 array
<wk_widget
> imw (11);
524 array
<string
> ims (11);
525 imw
[ 0]= input_widget ("width:", IMAGE_HSIZE
);
527 imw
[ 1]= glue_wk_widget (true, false, 0, sep
);
528 imw
[ 2]= input_widget ("height:", IMAGE_VSIZE
);
530 imw
[ 3]= glue_wk_widget (true, false, 0, sep
);
531 imw
[ 4]= input_widget ("left border:", IMAGE_CLIP_X1
);
533 imw
[ 5]= glue_wk_widget (true, false, 0, sep
);
534 imw
[ 6]= input_widget ("lower border:", IMAGE_CLIP_Y1
);
536 imw
[ 7]= glue_wk_widget (true, false, 0, sep
);
537 imw
[ 8]= input_widget ("right border:", IMAGE_CLIP_X2
);
539 imw
[ 9]= glue_wk_widget (true, false, 0, sep
);
540 imw
[10]= input_widget ("upper border:", IMAGE_CLIP_Y2
);
543 array
<wk_widget
> cw4 (5);
544 array
<string
> cn4 (5);
545 cw4
[0] = glue_wk_widget (false, false, sep
);
546 cw4
[1] = vertical_list (imw
, ims
);
547 cn4
[1] = "parameters";
548 cw4
[2] = glue_wk_widget (false, false, sep
);
549 cw4
[3] = tm_new
<image_widget_rep
> ();
551 cw4
[4] = glue_wk_widget (false, false, sep
);
553 cw
[ 8] = separator_wk_widget ();
554 cw
[ 9] = glue_wk_widget (true, false, 0, sep
);
555 cw
[10] = horizontal_list (cw4
, cn4
);
557 cw
[11] = glue_wk_widget (true, false, 0, sep
);
558 cw
[12] = separator_wk_widget ();
559 cw
[13] = glue_wk_widget (true, false, 0, sep
);
562 cw
[cwn
-3]= glue_wk_widget (true, false, 0, sep
);
563 cw
[cwn
-2]= horizontal_list (cw3
);
564 cn
[cwn
-2]= "buttons";
565 cw
[cwn
-1]= glue_wk_widget (true, false, 0, sep
);
567 a
[0]= vertical_list (cw
, cn
);
569 if (type
!= "directory") {
571 for (i
=0; i
<N(suffix
); ++i
) {
575 a
[0]["suffixes"]["input"] << set_string ("input", s
);
581 file_chooser_widget_rep::operator tree () {
582 return tree (TUPLE
, "file_chooser", (tree
) a
[0]);
586 file_chooser_widget_rep::handle_get_size (get_size_event ev
) {
589 if (type
== "image") ev
->h
= 500*PIXEL
;
590 else ev
->h
= 350*PIXEL
;
592 else gui_maximal_extents (ev
->w
, ev
->h
);
596 file_chooser_widget_rep::handle_set_string (set_string_event ev
) {
597 if (ev
->which
== "directory") {
598 string dir
= as_string (url_pwd () * url_system (ev
->s
));
599 a
[0]["directory"]["input"] << set_string ("input", dir
);
600 a
[0]["list"]["directories"] << set_string ("directory", dir
);
601 if (type
!= "directory") {
602 // a[0]["file"]["input"] << set_string ("input", "");
603 a
[0]["list"]["files"] << set_string ("directory", dir
);
606 else if (ev
->which
== "file") {
607 if (type
== "directory") return;
608 a
[0]["file"]["input"] << set_string ("input", ev
->s
);
609 if (type
== "image") {
610 string dir
, name
= ev
->s
;
611 a
[0]["directory"]["input"] << get_string ("input", dir
);
612 if (name
!= "") name
= as_string (url_system (scm_unquote (dir
), name
));
613 a
[0]["image"]["image"] << set_string ("name", name
);
614 array
<string
> ps_suffix
;
615 ps_suffix
<< string (".ps") << string (".eps");
616 wk_widget par_wid
= a
[0]["image"]["parameters"];
617 if (has_suffix (name
, ps_suffix
)) {
618 par_wid
["hsize"]["input"] << set_string ("input", "");
619 par_wid
["vsize"]["input"] << set_string ("input", "");
622 par_wid
["hsize"]["input"] << set_string ("input", magn
);
623 par_wid
["vsize"]["input"] << set_string ("input", magn
);
627 else if (ev
->which
== "return") {
629 if (type
== "directory") {
630 a
[0]["directory"]["input"] << set_string ("input", s
);
634 if (s
!= "#f" && !has_suffix (s
, suffix
))
635 a
[0]["file"]["input"] << set_string ("input", s
* suffix
[0]);
637 a
[0]["file"]["input"] << set_string ("input", s
);
642 else if (ev
->which
== "suffixes") {
643 if (type
== "directory") return;
644 // surely the following can be done better:
647 string s
= scm_unquote (ev
->s
);
648 a
[0]["suffixes"]["input"] << set_string ("input", s
);
650 while (s
[i
]==' ') ++i
;
652 while (j
<N(s
) && s
[j
]!=' ') ++j
;
659 if (!any
) suffix
<< string ("");
662 a
[0]["directory"]["input"] << get_string ("input", dir
);
663 a
[0]["list"]["directories"] << set_string ("directory", scm_unquote (dir
));
664 a
[0]["list"]["files"] << set_string ("directory", scm_unquote (dir
));
666 else attribute_widget_rep::handle_set_string (ev
);
670 file_chooser_widget_rep::handle_get_string (get_string_event ev
) {
671 if (ev
->which
== "input") {
673 a
[0]["directory"]["input"] << get_string ("input", dir
);
674 if (type
== "directory") {
675 a
[0]["directory"]["input"] << get_string ("input", name
);
676 if (name
== "#f") { ev
->s
= "#f"; return; }
677 url u
= url_system (scm_unquote (dir
));
678 ev
->s
= "(url-system " * scm_quote (as_string (u
)) * ")";
681 a
[0]["file"]["input"] << get_string ("input", name
);
682 if (name
== "#f") { ev
->s
= "#f"; return; }
683 url u
= url_system (scm_unquote (dir
)) * url_system (scm_unquote (name
));
684 ev
->s
= "(url-system " * scm_quote (as_string (u
)) * ")";
686 if (type
== "image") {
687 string hsize
, vsize
, cx1
, cy1
, cx2
, cy2
;
688 wk_widget par
= a
[0]["image"]["parameters"];
689 par
["hsize"]["input"] << get_string ("input", hsize
);
690 par
["vsize"]["input"] << get_string ("input", vsize
);
691 par
["clip-x1"]["input"] << get_string ("input", cx1
);
692 par
["clip-y1"]["input"] << get_string ("input", cy1
);
693 par
["clip-x2"]["input"] << get_string ("input", cx2
);
694 par
["clip-y2"]["input"] << get_string ("input", cy2
);
696 "(list " * ev
->s
* " " * hsize
* " " * vsize
* " "
697 * cx1
* " " * cy1
* " " * cx2
* " " * cy2
* ")";
700 else attribute_widget_rep::handle_get_string (ev
);
704 file_chooser_widget_rep::handle_destroy (destroy_event ev
) {
706 this << set_string ("return", "#f");
709 /******************************************************************************
711 ******************************************************************************/
714 file_chooser_wk_widget (command cmd
, string type
, string magn
) {
715 return tm_new
<file_chooser_widget_rep
> (cmd
, type
, magn
);