Codepage messages related translated & other stuff...
[midnight-commander.git] / src / screen.c
blob40cac178387eb80ee4b01c550d03235cb032d68b
1 /* Panel managing.
2 Copyright (C) 1994, 1995 Miguel de Icaza.
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 Written by: 1995 Miguel de Icaza
15 1997, 1999 Timur Bakeyev
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
21 #include <config.h>
22 #include "tty.h"
23 #include <sys/param.h>
24 #include <string.h>
25 #include <stdio.h>
26 #include <errno.h>
27 #ifdef HAVE_UNISTD_H
28 # include <unistd.h> /* For chdir(), readlink() and getwd()/getcwd() */
29 #endif
30 #include "global.h"
31 #include "dir.h"
32 #include "panel.h"
33 #include "color.h"
34 #include "tree.h"
35 #include "win.h"
36 #include "main.h"
37 #include "ext.h" /* regexp_command */
38 #include "mouse.h" /* For Gpm_Event */
39 #include "cons.saver.h" /* For console_flag */
40 #include "layout.h" /* Most layout variables are here */
41 #include "dialog.h" /* for message (...) */
42 #include "cmd.h"
43 #include "key.h" /* XCTRL and ALT macros */
44 #include "setup.h" /* For loading/saving panel options */
45 #include "user.h"
46 #include "profile.h"
47 #include "widget.h"
48 #include "../vfs/vfs.h"
49 #include "../vfs/extfs.h"
50 #ifdef NEEDS_DRIVE_H
51 # include "drive.h"
52 #endif
54 #include "x.h"
56 #define ELEMENTS(arr) ( sizeof(arr) / sizeof((arr)[0]) )
58 /* If true, show the mini-info on the panel */
59 int show_mini_info = 1;
61 /* If true, then use stat() on the cwd to determine directory changes */
62 int fast_reload = 0;
64 /* If true, use some usability hacks by Torben */
65 int torben_fj_mode = 0;
67 /* If true, up/down keys scroll the pane listing by pages */
68 int panel_scroll_pages = 1;
70 /* If 1, we use permission hilighting */
71 int permission_mode = 0;
73 /* If 1 - then add per file type hilighting */
74 int filetype_mode = 1;
76 /* This gives abilitiy to determine colored user priveleges */
77 extern user_in_groups *current_user_gid;
78 extern uid_t current_user_uid;
80 /* If we have an info panel, this points to it */
81 WPanel *the_info_panel = 0;
83 /* The hook list for the select file function */
84 Hook *select_file_hook = 0;
86 static int panel_callback (Dlg_head *h, WPanel *p, int Msg, int Par);
87 static int panel_event (Gpm_Event *event, WPanel *panel);
89 #ifndef PORT_HAS_PANEL_ADJUST_TOP_FILE
90 # define x_adjust_top_file(p)
91 #endif
93 #ifndef PORT_HAS_PANEL_RESET_SORT_LABELS
94 # define x_reset_sort_labels(x)
95 #endif
97 /* This macro extracts the number of available lines in a panel */
98 #ifndef PORT_HAS_LLINES
99 #define llines(p) (p->widget.lines-3 - (show_mini_info ? 2 : 0))
100 #else
101 #define llines(p) (p->widget.lines)
102 #endif
104 #ifdef PORT_NOT_FOCUS_SELECT_ITEM
105 # define focus_select_item(x)
106 #else
107 # define focus_select_item(x) select_item(x)
108 #endif
110 #ifdef PORT_NOT_UNFOCUS_UNSELECT_ITEM
111 # define unfocus_unselect_item(x)
112 #else
113 # define unfocus_unselect_item(x) unselect_item(x)
114 #endif
116 #ifdef HAVE_X
117 # define set_colors(x)
118 #else
119 # define x_create_panel(x,y,z) 1;
120 # define x_panel_load_index(p,x)
121 # define x_panel_select_item(a,b,c)
122 # define x_panel_destroy(p)
124 void
125 set_colors (WPanel *panel)
127 standend ();
128 if (hascolors)
129 attrset (NORMAL_COLOR);
131 #endif
133 #ifndef ICONS_PER_ROW
134 # define ICONS_PER_ROW(x) 1
135 #endif
137 /* Delete format string, it is a linked list */
138 static void
139 delete_format (format_e *format)
141 format_e *next;
143 while (format){
144 next = format->next;
145 g_free (format);
146 format = next;
150 #ifndef HAVE_X
151 /* This code relies on the default justification!!! */
152 static void
153 add_permission_string (char *dest, int width, file_entry *fe, int attr, int color, int is_octal)
155 int i, r, l;
157 l = get_user_rights (&fe->buf);
159 if (is_octal){
160 /* Place of the access bit in octal mode */
161 l = width + l - 3;
162 r = l + 1;
163 } else {
164 /* The same to the triplet in string mode */
165 l = l * 3 + 1;
166 r = l + 3;
169 for(i = 0; i < width; i++){
170 if (i >= l && i < r){
171 if (attr == SELECTED || attr == MARKED_SELECTED)
172 attrset (MARKED_SELECTED_COLOR);
173 else
174 attrset (MARKED_COLOR);
175 } else
176 attrset (color);
178 addch (dest[i]);
181 #endif /* HAVE_X */
183 /* String representations of various file attributes */
184 /* name */
185 char *
186 string_file_name (file_entry *fe, int len)
188 return fe->fname;
191 /* size */
192 char *
193 string_file_size (file_entry *fe, int len)
195 static char buffer [BUF_TINY];
196 int i;
198 #ifdef HAVE_ST_RDEV
199 if (S_ISBLK (fe->buf.st_mode) || S_ISCHR (fe->buf.st_mode))
200 g_snprintf (buffer, sizeof (buffer), "%3d,%3d",
201 (int) ((fe->buf.st_rdev >> 8) & 0xff),
202 (int) (fe->buf.st_rdev & 0xff));
203 else
204 #endif
206 g_snprintf (buffer, sizeof (buffer), "%lu", (unsigned long) fe->buf.st_size);
207 if (len && (i = strlen (buffer)) > len) {
208 if (i - 2 > len) {
209 if (i - 5 > len)
210 g_snprintf (buffer, sizeof (buffer), "%luG", (unsigned long) ((fe->buf.st_size) >> 30));
211 else
212 g_snprintf (buffer, sizeof (buffer), "%luM", (unsigned long) ((fe->buf.st_size) >> 20));
213 } else
214 g_snprintf (buffer, sizeof (buffer), "%luK", (unsigned long) ((fe->buf.st_size) >> 10));
217 return buffer;
220 /* bsize */
221 char *
222 string_file_size_brief (file_entry *fe, int len)
224 static char buffer [BUF_TINY];
226 if (S_ISDIR (fe->buf.st_mode)){
227 strcpy (buffer, _(strcmp (fe->fname, "..") ? N_("SUB-DIR") : N_("UP--DIR")));
228 return buffer;
231 return string_file_size (fe, len);
234 /* This functions return a string representation of a file entry */
235 /* type */
236 char *
237 string_file_type (file_entry *fe, int len)
239 static char buffer [2];
241 if (S_ISDIR (fe->buf.st_mode))
242 buffer [0] = PATH_SEP;
243 else if (S_ISLNK (fe->buf.st_mode)) {
244 if (fe->f.link_to_dir)
245 buffer [0] = '~';
246 else if (fe->f.stalled_link)
247 buffer [0] = '!';
248 else
249 buffer [0] = '@';
250 } else if (S_ISSOCK (fe->buf.st_mode))
251 buffer [0] = '=';
252 else if (S_ISCHR (fe->buf.st_mode))
253 buffer [0] = '-';
254 else if (S_ISBLK (fe->buf.st_mode))
255 buffer [0] = '+';
256 else if (S_ISFIFO (fe->buf.st_mode))
257 buffer [0] = '|';
258 else if (is_exe (fe->buf.st_mode))
259 buffer [0] = '*';
260 else
261 buffer [0] = ' ';
262 buffer [1] = '\0';
263 return buffer;
266 /* mtime */
267 char *
268 string_file_mtime (file_entry *fe, int len)
270 #ifdef PORT_STATIC_IN_STRING_FILE_XTIME
271 static char timebuf [MAX_I18NTIMELENGTH + 1];
273 return strcpy (timebuf, file_date (fe->buf.st_mtime));
274 #else
275 return file_date (fe->buf.st_mtime);
276 #endif
279 /* atime */
280 char *
281 string_file_atime (file_entry *fe, int len)
283 #ifdef PORT_STATIC_IN_STRING_FILE_XTIME
284 static char timebuf [MAX_I18NTIMELENGTH + 1];
286 return strcpy (timebuf, file_date (fe->buf.st_atime));
287 #else
288 return file_date (fe->buf.st_atime);
289 #endif
292 /* ctime */
293 char *
294 string_file_ctime (file_entry *fe, int len)
296 #ifdef PORT_STATIC_IN_STRING_FILE_XTIME
297 static char timebuf [MAX_I18NTIMELENGTH + 1];
299 return strcpy (timebuf, file_date (fe->buf.st_ctime));
300 #else
301 return file_date (fe->buf.st_ctime);
302 #endif
305 /* perm */
306 char *
307 string_file_permission (file_entry *fe, int len)
309 return string_perm (fe->buf.st_mode);
312 /* mode */
313 char *
314 string_file_perm_octal (file_entry *fe, int len)
316 static char buffer [10];
318 g_snprintf (buffer, sizeof (buffer), "0%06o", fe->buf.st_mode);
319 return buffer;
322 /* nlink */
323 char *
324 string_file_nlinks (file_entry *fe, int len)
326 static char buffer [BUF_TINY];
328 g_snprintf (buffer, sizeof (buffer), "%16d", fe->buf.st_nlink);
329 return buffer;
332 /* inode */
333 char *
334 string_inode (file_entry *fe, int len)
336 static char buffer [10];
338 g_snprintf (buffer, sizeof (buffer), "%lu", (unsigned long) fe->buf.st_ino);
339 return buffer;
342 /* nuid */
343 char *
344 string_file_nuid (file_entry *fe, int len)
346 static char buffer [10];
348 g_snprintf (buffer, sizeof (buffer), "%d", fe->buf.st_uid);
349 return buffer;
352 /* ngid */
353 char *
354 string_file_ngid (file_entry *fe, int len)
356 static char buffer [10];
358 g_snprintf (buffer, sizeof (buffer), "%d", fe->buf.st_gid);
359 return buffer;
362 /* owner */
363 char *
364 string_file_owner (file_entry *fe, int len)
366 return get_owner (fe->buf.st_uid);
369 /* group */
370 char *
371 string_file_group (file_entry *fe, int len)
373 return get_group (fe->buf.st_gid);
376 /* mark */
377 char *
378 string_marked (file_entry *fe, int len)
380 return fe->f.marked ? "*" : " ";
383 /* space */
384 char *
385 string_space (file_entry *fe, int len)
387 return " ";
390 /* dot */
391 char *
392 string_dot (file_entry *fe, int len)
394 return ".";
397 #ifdef HAVE_GNOME
398 # define GT 2
399 #else
400 # define GT 1
401 #endif
403 static struct {
404 char *id;
405 int min_size;
406 int expands;
407 int default_just;
408 char *title;
409 int use_in_gui;
410 char *(*string_fn)(file_entry *, int);
411 sortfn *sort_routine;
412 } formats [] = {
413 { "name", 12, 1, J_LEFT_FIT, N_("Name"), 1, string_file_name, (sortfn *) sort_name },
414 { "size", 7, 0, J_RIGHT, N_("Size"), 1, string_file_size, (sortfn *) sort_size },
415 { "bsize", 7, 0, J_RIGHT, N_("Size"), 1, string_file_size_brief, (sortfn *) sort_size },
416 { "type", GT, 0, J_LEFT, "", 2, string_file_type, (sortfn *) sort_type },
417 { "mtime", 12, 0, J_RIGHT, N_("MTime"), 1, string_file_mtime, (sortfn *) sort_time },
418 { "atime", 12, 0, J_RIGHT, N_("ATime"), 1, string_file_atime, (sortfn *) sort_atime },
419 { "ctime", 12, 0, J_RIGHT, N_("CTime"), 1, string_file_ctime, (sortfn *) sort_ctime },
420 { "perm", 10, 0, J_LEFT, N_("Permission"),1,string_file_permission, NULL },
421 { "mode", 6, 0, J_RIGHT, N_("Perm"), 1, string_file_perm_octal, NULL },
422 { "nlink", 2, 0, J_RIGHT, N_("Nl"), 1, string_file_nlinks, (sortfn *) sort_links },
423 { "inode", 5, 0, J_RIGHT, N_("Inode"), 1, string_inode, (sortfn *) sort_inode },
424 { "nuid", 5, 0, J_RIGHT, N_("UID"), 1, string_file_nuid, (sortfn *) sort_nuid },
425 { "ngid", 5, 0, J_RIGHT, N_("GID"), 1, string_file_ngid, (sortfn *) sort_ngid },
426 { "owner", 8, 0, J_LEFT_FIT, N_("Owner"), 1, string_file_owner, (sortfn *) sort_owner },
427 { "group", 8, 0, J_LEFT_FIT, N_("Group"), 1, string_file_group, (sortfn *) sort_group },
428 { "mark", 1, 0, J_RIGHT, " ", 1, string_marked, NULL },
429 { "|", 1, 0, J_RIGHT, " ", 0, NULL, NULL },
430 { "space", 1, 0, J_RIGHT, " ", 0, string_space, NULL },
431 { "dot", 1, 0, J_RIGHT, " ", 0, string_dot, NULL },
434 static char *
435 to_buffer (char *dest, int just_mode, int len, char *txt)
437 int txtlen = strlen (txt);
438 int still, over;
440 /* Fill buffer with spaces */
441 memset (dest, ' ', len);
443 still = (over=(txtlen > len)) ? (txtlen - len) : (len - txtlen);
445 switch (HIDE_FIT(just_mode)){
446 case J_LEFT:
447 still = 0;
448 break;
449 case J_CENTER:
450 still /= 2;
451 break;
452 case J_RIGHT:
453 default:
454 break;
457 if (over){
458 if (IS_FIT(just_mode))
459 strcpy (dest, name_trunc(txt, len));
460 else
461 strncpy (dest, txt+still, len);
462 } else
463 strncpy (dest+still, txt, txtlen);
465 dest[len] = '\0';
467 return (dest + len);
471 file_compute_color (int attr, file_entry *fe)
473 switch (attr){
474 case SELECTED:
475 return (SELECTED_COLOR);
476 case MARKED:
477 return (MARKED_COLOR);
478 case MARKED_SELECTED:
479 return (MARKED_SELECTED_COLOR);
480 case STATUS:
481 return (NORMAL_COLOR);
482 case NORMAL:
483 default:
484 if (!filetype_mode)
485 return (NORMAL_COLOR);
488 /* if filetype_mode == true */
489 if (S_ISDIR (fe->buf.st_mode))
490 return (DIRECTORY_COLOR);
491 else if (S_ISLNK (fe->buf.st_mode)){
492 if (fe->f.link_to_dir)
493 return (DIRECTORY_COLOR);
494 else if (fe->f.stalled_link)
495 return (STALLED_LINK_COLOR);
496 else
497 return (LINK_COLOR);
498 } else if (S_ISSOCK (fe->buf.st_mode))
499 return (SPECIAL_COLOR);
500 else if (S_ISCHR (fe->buf.st_mode))
501 return (DEVICE_COLOR);
502 else if (S_ISBLK (fe->buf.st_mode))
503 return (DEVICE_COLOR);
504 else if (S_ISFIFO (fe->buf.st_mode))
505 return (SPECIAL_COLOR);
506 else if (is_exe (fe->buf.st_mode))
507 return (EXECUTABLE_COLOR);
508 else if (fe->fname && (!strcmp (fe->fname, "core") || !strcmp (extension(fe->fname), "core")))
509 return (CORE_COLOR);
511 return (NORMAL_COLOR); /* just for safeness */
514 /* Formats the file number file_index of panel in the buffer dest */
515 void
516 format_file (char *dest, WPanel *panel, int file_index, int width, int attr, int isstatus)
518 int color, length, empty_line;
519 char *txt;
520 char *old_pos;
521 char *cdest = dest;
522 format_e *format, *home;
523 file_entry *fe;
525 length = 0;
526 empty_line = (file_index >= panel->count);
527 home = (isstatus) ? panel->status_format : panel->format;
528 fe = &panel->dir.list [file_index];
530 if (!empty_line)
531 color = file_compute_color (attr, fe);
532 else
533 color = NORMAL_COLOR;
535 for (format = home; format; format = format->next){
537 if (length == width)
538 break;
540 if (format->string_fn){
541 int len;
543 if (empty_line)
544 txt = " ";
545 else
546 txt = (*format->string_fn)(fe, format->field_len);
548 old_pos = cdest;
550 len = format->field_len;
551 if (len + length > width)
552 len = width - length;
553 cdest = to_buffer (cdest, format->just_mode, len, txt);
554 length += len;
556 #ifndef HAVE_X
557 attrset (color);
559 if (permission_mode && !strcmp(format->id, "perm"))
560 add_permission_string (old_pos, format->field_len, fe, attr, color, 0);
561 else if (permission_mode && !strcmp(format->id, "mode"))
562 add_permission_string (old_pos, format->field_len, fe, attr, color, 1);
563 else
564 addstr (old_pos);
566 #endif
567 } else {
568 #ifndef HAVE_X
569 if (attr == SELECTED || attr == MARKED_SELECTED)
570 attrset (SELECTED_COLOR);
571 else
572 attrset (NORMAL_COLOR);
573 one_vline ();
574 #else
575 *cdest++ = ' ';
576 #endif
577 length++;
581 if (length < width){
582 int still = width - length;
583 while (still--)
584 #ifdef HAVE_X
585 *cdest++ = ' ';
586 *cdest = '\0';
587 #else
588 addch (' ');
589 #endif
593 #ifndef HAVE_X
594 void
595 repaint_file (WPanel *panel, int file_index, int mv, int attr, int isstatus)
597 int second_column = 0;
598 int width, offset;
599 char buffer [BUF_MEDIUM];
601 offset = 0;
602 if (!isstatus && panel->split){
604 second_column = (file_index - panel->top_file) / llines (panel);
605 width = (panel->widget.cols - 2)/2 - 1;
607 if (second_column){
608 offset = 1 + width;
609 width = (panel->widget.cols-2) - (panel->widget.cols-2)/2 - 1;
611 } else
612 width = (panel->widget.cols - 2);
614 if (mv){
615 if (!isstatus && panel->split){
616 widget_move (&panel->widget,
617 (file_index - panel->top_file) %
618 llines (panel) + 2,
619 (offset + 1));
620 } else
621 widget_move (&panel->widget, file_index - panel->top_file + 2, 1);
624 format_file (buffer, panel, file_index, width, attr, isstatus);
626 if (!isstatus && panel->split){
627 if (second_column)
628 addch (' ');
629 else {
630 attrset (NORMAL_COLOR);
631 one_vline ();
635 #endif
637 #ifndef PORT_HAS_DISPLAY_MINI_INFO
638 void
639 display_mini_info (WPanel *panel)
641 if (!show_mini_info)
642 return;
644 widget_move (&panel->widget, llines (panel)+3, 1);
646 if (panel->searching){
647 attrset (INPUT_COLOR);
648 printw ("/%-*s", panel->widget.cols-3, panel->search_buffer);
649 attrset (NORMAL_COLOR);
650 return;
653 /* Status displays total marked size */
654 if (panel->marked){
655 char buffer [BUF_SMALL];
656 char *p = " %-*s";
657 int cols = panel->widget.cols-2;
659 attrset (MARKED_COLOR);
660 printw ("%*s", cols, " ");
661 widget_move (&panel->widget, llines (panel)+3, 1);
662 g_snprintf (buffer, sizeof (buffer), _((panel->marked == 1) ?
663 N_("%s bytes in %d file") : N_("%s bytes in %d files")),
664 size_trunc_sep (panel->total), panel->marked);
665 if (strlen (buffer) > cols-2){
666 buffer [cols] = 0;
667 p += 2;
668 } else
669 cols -= 2;
670 printw (p, cols, buffer);
671 return;
674 /* Status resolves links and show them */
675 set_colors (panel);
676 #ifndef OS2_NT
677 if (S_ISLNK (panel->dir.list [panel->selected].buf.st_mode)){
678 char *link, link_target [MC_MAXPATHLEN];
679 int len;
681 link = concat_dir_and_file (panel->cwd, panel->dir.list [panel->selected].fname);
682 len = mc_readlink (link, link_target, MC_MAXPATHLEN);
683 g_free (link);
684 if (len > 0){
685 link_target[len] = 0;
686 printw ("-> %-*s", panel->widget.cols - 5,
687 name_trunc (link_target, panel->widget.cols - 5));
688 } else
689 addstr (_("<readlink failed>"));
690 return;
692 #endif
693 /* Default behaviour */
694 repaint_file (panel, panel->selected, 0, STATUS, 1);
695 return;
697 #endif
699 #ifndef HAVE_X
700 void
701 paint_dir (WPanel *panel)
703 int i;
704 int color; /* Color value of the line */
705 int items; /* Number of items */
707 items = llines (panel) * (panel->split ? 2 : 1);
709 for (i = 0; i < items; i++){
710 if (i+panel->top_file >= panel->count)
711 color = 0;
712 else {
713 color = 2 * (panel->dir.list [i+panel->top_file].f.marked);
714 color += (panel->selected==i+panel->top_file && panel->active);
716 repaint_file (panel, i+panel->top_file, 1, color, 0);
718 standend ();
719 panel->dirty = 0;
721 #endif
723 #ifdef HAVE_X
724 #define mini_info_separator(x)
725 #else
726 static void
727 mini_info_separator (WPanel *panel)
729 if (!show_mini_info)
730 return;
732 standend ();
733 widget_move (&panel->widget, llines (panel)+2, 1);
734 #ifdef HAVE_SLANG
735 attrset (NORMAL_COLOR);
736 hline (ACS_HLINE, panel->widget.cols-2);
737 #else
738 hline ((slow_terminal ? '-' : ACS_HLINE) | NORMAL_COLOR,
739 panel->widget.cols-2);
740 #endif
743 void
744 show_dir (WPanel *panel)
746 char tmp [200];
748 set_colors (panel);
749 draw_double_box (panel->widget.parent,
750 panel->widget.y, panel->widget.x,
751 panel->widget.lines, panel->widget.cols);
753 #ifdef HAVE_SLANG
754 if (show_mini_info) {
755 #ifdef linux_unicode
756 if (SLtt_Unicode) {
757 SLsmg_draw_unicode (panel->widget.y + llines (panel) + 2,
758 panel->widget.x, SLUNI_DSLTEE_CHAR);
759 SLsmg_draw_unicode (panel->widget.y + llines (panel) + 2,
760 panel->widget.x + panel->widget.cols - 1, SLUNI_DSRTEE_CHAR);
761 } else
762 #endif /* linux_unicode */
764 SLsmg_draw_object (panel->widget.y + llines (panel) + 2,
765 panel->widget.x, SLSMG_LTEE_CHAR);
766 SLsmg_draw_object (panel->widget.y + llines (panel) + 2,
767 panel->widget.x + panel->widget.cols - 1, SLSMG_RTEE_CHAR);
770 #endif /* have_slang */
772 if (panel->active)
773 attrset (REVERSE_COLOR);
775 widget_move (&panel->widget, 0, 3);
777 trim (strip_home_and_password (panel->cwd), tmp, panel->widget.cols-7);
778 addstr (tmp);
779 widget_move (&panel->widget, 0, 1);
780 addstr ("<");
781 widget_move (&panel->widget, 0, panel->widget.cols-2);
782 addstr (">");
783 widget_move (&panel->widget, 0, panel->widget.cols-3);
784 addstr ("v");
786 if (panel->active)
787 standend ();
789 #endif
791 #ifndef PORT_HAS_PAINT_FRAME
792 /* To be used only by long_frame and full_frame to adjust top_file */
793 static void
794 adjust_top_file (WPanel *panel)
796 int old_top = panel->top_file;
798 if (panel->selected - old_top > llines (panel))
799 panel->top_file = panel->selected;
800 if (old_top - panel->count > llines (panel))
801 panel->top_file = panel->count - llines (panel);
803 #endif
805 /* Repaints the information that changes after a command */
806 void
807 panel_update_contents (WPanel *panel)
809 show_dir (panel);
810 #ifdef HAVE_X
811 x_fill_panel (panel);
812 #else
813 paint_dir (panel);
814 #endif
815 display_mini_info (panel);
818 void
819 paint_panel (WPanel *panel)
821 paint_frame (panel);
822 panel_update_contents (panel);
823 mini_info_separator (panel);
826 static void
827 do_select (WPanel *panel, int i)
829 if (i != panel->selected){
830 panel->selected = i;
831 panel->top_file = panel->selected - (panel->widget.lines-2)/2;
832 if (panel->top_file < 0)
833 panel->top_file = 0;
834 x_adjust_top_file (panel);
838 void
839 Xtry_to_select (WPanel *panel, char *name)
841 int i;
842 char *subdir;
844 if (!name) {
845 do_select(panel, 0);
846 return;
849 /* We only want the last component of the directory */
850 subdir = x_basename (name);
852 subdir = vfs_strip_suffix_from_filename (subdir);
854 /* Search that subdirectory, if found select it */
855 for (i = 0; i < panel->count; i++){
856 if (strcmp (subdir, panel->dir.list [i].fname) == 0) {
857 do_select (panel, i);
858 g_free (subdir);
859 return;
863 /* Try to select a file near the file that is missing */
864 if (panel->selected >= panel->count)
865 do_select (panel, panel->count-1);
866 g_free (subdir);
869 #ifndef PORT_HAS_PANEL_UPDATE_COLS
870 void
871 panel_update_cols (Widget *widget, int frame_size)
873 int cols, origin;
875 if (horizontal_split){
876 widget->cols = COLS;
877 return;
880 if (frame_size == frame_full){
881 cols = COLS;
882 origin = 0;
883 } else {
884 if (widget == get_panel_widget (0)){
885 cols = first_panel_size;
886 origin = 0;
887 } else {
888 cols = COLS-first_panel_size;
889 origin = first_panel_size;
893 widget->cols = cols;
894 widget->x = origin;
896 #endif
898 static char *
899 panel_save_name (WPanel *panel)
901 extern int saving_setup;
903 /* If the program is shuting down */
904 if ((midnight_shutdown && auto_save_setup) || saving_setup)
905 return g_strdup (panel->panel_name);
906 else
907 return g_strconcat ("Temporal:", panel->panel_name, NULL);
910 static void
911 panel_destroy (WPanel *p)
913 int i;
915 char *name = panel_save_name (p);
917 panel_save_setup (p, name);
918 x_panel_destroy (p);
919 panel_clean_dir (p);
921 /* save and clean history */
922 if (p->dir_history){
923 Hist *current, *old;
924 history_put (p->hist_name, p->dir_history);
925 current = p->dir_history;
926 while (current->next)
927 current = current->next;
928 while (current){
929 old = current;
930 current = current->prev;
931 g_free (old->text);
932 g_free (old);
935 g_free (p->hist_name);
937 delete_format (p->format);
938 delete_format (p->status_format);
940 g_free (p->user_format);
941 for (i = 0; i < LIST_TYPES; i++)
942 g_free (p->user_status_format [i]);
943 g_free (p->dir.list);
944 g_free (p->panel_name);
945 g_free (name);
948 static void
949 panel_format_modified (WPanel *panel)
951 panel->format_modified = 1;
952 x_reset_sort_labels (panel);
956 is_a_panel (Widget *w)
958 return (w->callback == (void *) panel_callback);
961 /* Panel creation */
962 /* The parameter specifies the name of the panel for setup retieving */
963 WPanel *
964 panel_new (const char *panel_name)
966 #ifdef HAVE_GNOME
967 static int panel_id = 0;
968 #endif
969 WPanel *panel;
970 char *section;
971 int i, err;
973 panel = g_new0 (WPanel, 1);
975 /* No know sizes of the panel at startup */
976 init_widget (&panel->widget, 0, 0, 0, 0, (callback_fn)
977 panel_callback, (destroy_fn) panel_destroy,
978 (mouse_h) panel_event, NULL);
980 /* We do not want the cursor */
981 widget_want_cursor (panel->widget, 0);
983 mc_get_current_wd (panel->cwd, sizeof (panel->cwd)-2);
984 strcpy (panel->lwd, ".");
986 panel->hist_name = g_strconcat ("Dir Hist ", panel_name, NULL);
987 panel->dir_history = history_get (panel->hist_name);
988 directory_history_add (panel, panel->cwd);
990 panel->dir.list = g_new (file_entry, MIN_FILES);
991 panel->dir.size = MIN_FILES;
992 panel->active = 0;
993 panel->filter = 0;
994 panel->split = 0;
995 panel->top_file = 0;
996 panel->selected = 0;
997 panel->marked = 0;
998 panel->total = 0;
999 panel->reverse = 0;
1000 panel->dirty = 1;
1001 panel->searching = 0;
1002 panel->dirs_marked = 0;
1003 panel->is_panelized = 0;
1004 panel->format = 0;
1005 panel->status_format = 0;
1006 panel->format_modified = 1;
1007 #ifdef HAVE_GNOME
1008 panel->drag_tree_row = -1;
1009 panel->is_a_desktop_panel = FALSE;
1010 panel->id = panel_id++;
1011 panel->servant = NULL;
1012 #endif
1014 panel->panel_name = g_strdup (panel_name);
1015 panel->user_format = g_strdup (DEFAULT_USER_FORMAT);
1017 for(i = 0; i < LIST_TYPES; i++)
1018 panel->user_status_format [i] = g_strdup (DEFAULT_USER_FORMAT);
1020 panel->search_buffer [0] = 0;
1021 panel->frame_size = frame_half;
1022 section = g_strconcat ("Temporal:", panel->panel_name, NULL);
1023 if (!profile_has_section (section, profile_name)){
1024 g_free (section);
1025 section = g_strdup (panel->panel_name);
1027 panel_load_setup (panel, section);
1028 g_free (section);
1030 /* Load format strings */
1031 err = set_panel_formats (panel);
1032 if (err){
1033 set_panel_formats (panel);
1036 /* Load the default format */
1037 panel->count = do_load_dir (&panel->dir, panel->sort_type,
1038 panel->reverse, panel->case_sensitive, panel->filter);
1039 return panel;
1042 void
1043 panel_reload (WPanel *panel)
1045 struct stat current_stat;
1047 if (fast_reload
1048 && !stat (panel->cwd, &current_stat)
1049 && current_stat.st_ctime == panel->dir_stat.st_ctime
1050 && current_stat.st_mtime == panel->dir_stat.st_mtime)
1051 return;
1053 while (mc_chdir (panel->cwd) == -1){
1054 char *last_slash;
1056 if (panel->cwd [0] == PATH_SEP && panel->cwd [1] == 0){
1057 panel_clean_dir (panel);
1058 panel->count = set_zero_dir (&panel->dir);
1059 return;
1061 last_slash = strrchr (panel->cwd, PATH_SEP);
1062 if (!last_slash || last_slash == panel->cwd)
1063 strcpy (panel->cwd, PATH_SEP_STR);
1064 else
1065 *last_slash = 0;
1066 memset (&(panel->dir_stat), 0, sizeof (panel->dir_stat));
1067 show_dir (panel);
1070 panel->count = do_reload_dir (&panel->dir, panel->sort_type, panel->count,
1071 panel->reverse, panel->case_sensitive, panel->filter);
1073 panel->dirty = 1;
1074 if (panel->selected >= panel->count)
1075 do_select (panel, panel->count-1);
1077 recalculate_panel_summary (panel);
1080 #ifndef PORT_HAS_PAINT_FRAME
1081 void
1082 paint_frame (WPanel *panel)
1084 int header_len;
1085 int spaces, extra;
1086 int side, width;
1088 char *txt, buffer[30]; /*Hope that this is enough ;-) */
1089 if (!panel->split)
1090 adjust_top_file (panel);
1092 widget_erase (&panel->widget);
1093 show_dir (panel);
1095 widget_move (&panel->widget, 1, 1);
1097 for (side = 0; side <= panel->split; side++){
1098 format_e *format;
1100 if (side){
1101 attrset (NORMAL_COLOR);
1102 one_vline ();
1103 width = panel->widget.cols - panel->widget.cols/2 - 1;
1104 } else if (panel->split)
1105 width = panel->widget.cols/2 - 3;
1106 else
1107 width = panel->widget.cols - 2;
1109 for (format = panel->format; format; format = format->next){
1110 if (format->string_fn){
1111 txt = format->title;
1113 header_len = strlen (txt);
1114 if (header_len > format->field_len){
1115 strcpy (buffer, txt);
1116 txt = buffer;
1117 txt [format->field_len] = 0;
1118 header_len = strlen (txt);
1121 attrset (MARKED_COLOR);
1122 spaces = (format->field_len - header_len) / 2;
1123 extra = (format->field_len - header_len) % 2;
1124 printw ("%*s%-s%*s", spaces, "",
1125 txt, spaces+extra, "");
1126 width -= 2 * spaces + extra + header_len;
1127 } else {
1128 attrset (NORMAL_COLOR);
1129 one_vline ();
1130 width --;
1131 continue;
1135 if (width > 0)
1136 printw ("%*s", width, "");
1139 #endif
1141 static char *
1142 parse_panel_size (WPanel *panel, char *format, int isstatus)
1144 int frame = frame_half;
1145 format = skip_separators (format);
1147 if (!strncmp (format, "full", 4)){
1148 frame = frame_full;
1149 format += 4;
1150 } else if (!strncmp (format, "half", 4)){
1151 frame = frame_half;
1152 format += 4;
1155 if (!isstatus){
1156 panel->frame_size = frame;
1157 panel->split = 0;
1160 /* Now, the optional column specifier */
1161 format = skip_separators (format);
1163 if (*format == '1' || *format == '2'){
1164 if (!isstatus)
1165 panel->split = *format == '2';
1166 format++;
1169 if (!isstatus)
1170 panel_update_cols (&(panel->widget), panel->frame_size);
1172 return skip_separators (format);
1175 /* Format is:
1177 all := panel_format? format
1178 panel_format := [full|half] [1|2]
1179 format := one_format_e
1180 | format , one_format_e
1182 one_format_e := just format.id [opt_size]
1183 just := [<=>]
1184 opt_size := : size [opt_expand]
1185 size := [0-9]+
1186 opt_expand := +
1190 static format_e *
1191 parse_display_format (WPanel *panel, char *format, char **error, int isstatus, int *res_total_cols)
1193 format_e *darr, *old, *home = 0; /* The formats we return */
1194 int total_cols = 0; /* Used columns by the format */
1195 int set_justify; /* flag: set justification mode? */
1196 int justify = 0; /* Which mode. */
1197 int items = 0; /* Number of items in the format */
1198 int i;
1200 static size_t i18n_timelength = 0; /* flag: check ?Time length at startup */
1202 *error = 0;
1204 if (i18n_timelength == 0) {
1205 i18n_timelength = i18n_checktimelength (); /* Musn't be 0 */
1207 for (i = 0; i < ELEMENTS(formats); i++)
1208 if (strcmp ("time", formats [i].id+1) == 0)
1209 formats [i].min_size = i18n_timelength;
1213 * This makes sure that the panel and mini status full/half mode
1214 * setting is equal
1216 format = parse_panel_size (panel, format, isstatus);
1218 while (*format){ /* format can be an empty string */
1219 int found = 0;
1221 darr = g_new (format_e, 1);
1223 /* I'm so ugly, don't look at me :-) */
1224 if (!home)
1225 home = old = darr;
1227 old->next = darr;
1228 darr->next = 0;
1229 old = darr;
1231 format = skip_separators (format);
1233 if (strchr ("<=>", *format)){
1234 set_justify = 1;
1235 switch (*format)
1237 case '<':
1238 justify = J_LEFT;
1239 break;
1240 case '=':
1241 justify = J_CENTER;
1242 break;
1243 case '>':
1244 default:
1245 justify = J_RIGHT;
1246 break;
1248 format = skip_separators (format+1);
1249 } else
1250 set_justify = 0;
1252 for (i = 0; i < ELEMENTS(formats); i++){
1253 int klen = strlen (formats [i].id);
1255 if (strncmp (format, formats [i].id, klen) != 0)
1256 continue;
1258 format += klen;
1260 if (formats [i].use_in_gui)
1261 items++;
1263 darr->use_in_gui = formats [i].use_in_gui;
1264 darr->requested_field_len = formats [i].min_size;
1265 darr->string_fn = formats [i].string_fn;
1266 if (formats [i].title [0])
1267 darr->title = _(formats [i].title);
1268 else
1269 darr->title = "";
1270 darr->id = formats [i].id;
1271 darr->expand = formats [i].expands;
1272 darr->just_mode = formats [i].default_just;
1274 if (set_justify) {
1275 if (IS_FIT(darr->just_mode))
1276 darr->just_mode = MAKE_FIT(justify);
1277 else
1278 darr->just_mode = justify;
1280 found = 1;
1282 format = skip_separators (format);
1284 /* If we have a size specifier */
1285 if (*format == ':'){
1286 int req_length;
1288 /* If the size was specified, we don't want
1289 * auto-expansion by default
1291 darr->expand = 0;
1292 format++;
1293 req_length = atoi (format);
1294 darr->requested_field_len = req_length;
1296 format = skip_numbers (format);
1298 /* Now, if they insist on expansion */
1299 if (*format == '+'){
1300 darr->expand = 1;
1301 format++;
1306 break;
1308 if (!found){
1309 char old_char;
1311 int pos = min (8, strlen (format));
1312 delete_format (home);
1313 old_char = format [pos];
1314 format [pos] = 0;
1315 *error = g_strconcat (_("Unknow tag on display format: "), format, NULL);
1316 format [pos] = old_char;
1317 return 0;
1319 total_cols += darr->requested_field_len;
1322 *res_total_cols = total_cols;
1323 if (home)
1324 home->items = items;
1325 return home;
1328 format_e *
1329 use_display_format (WPanel *panel, char *format, char **error, int isstatus)
1331 #define MAX_EXPAND 4
1332 int expand_top = 0; /* Max used element in expand */
1333 int usable_columns; /* Usable columns in the panel */
1334 int total_cols;
1335 char *expand_list [MAX_EXPAND]; /* Expand at most 4 fields. */
1336 int i;
1337 format_e *darr, *home;
1339 if (!format)
1340 format = DEFAULT_USER_FORMAT;
1342 home = parse_display_format (panel, format, error, isstatus, &total_cols);
1344 if (*error)
1345 return 0;
1347 /* Status needn't to be split */
1348 usable_columns = ((panel->widget.cols-2)/((isstatus)
1350 : (panel->split+1))) - (!isstatus && panel->split);
1352 /* Clean expand list */
1353 for (i = 0; i < MAX_EXPAND; i++)
1354 expand_list [i] = '\0';
1357 /* Look for the expandable fields and set field_len based on the requested field len */
1358 for (darr = home; darr && expand_top < MAX_EXPAND; darr = darr->next){
1359 darr->field_len = darr->requested_field_len;
1360 if (darr->expand)
1361 expand_list [expand_top++] = darr->id;
1364 /* If we used more columns than the available columns, adjust that */
1365 if (total_cols > usable_columns){
1366 int pdif, dif = total_cols - usable_columns;
1368 while (dif){
1369 pdif = dif;
1370 for (darr = home; darr; darr = darr->next){
1371 if (dif && darr->field_len - 1){
1372 darr->field_len--;
1373 dif--;
1377 /* avoid endless loop if num fields > 40 */
1378 if (pdif == dif)
1379 break;
1381 total_cols = usable_columns; /* give up, the rest should be truncated */
1384 /* Expand the available space */
1385 if ((usable_columns > total_cols) && expand_top){
1386 int spaces = (usable_columns - total_cols) / expand_top;
1387 int extra = (usable_columns - total_cols) % expand_top;
1389 for (i = 0, darr = home; darr && (i < expand_top); darr = darr->next)
1390 if (darr->expand){
1391 darr->field_len += (spaces + ((i == 0) ? extra : 0));
1392 i++;
1395 return home;
1398 /* Switches the panel to the mode specified in the format */
1399 /* Seting up both format and status string. Return: 0 - on success; */
1400 /* 1 - format error; 2 - status error; 3 - errors in both formats. */
1402 set_panel_formats (WPanel *p)
1404 format_e *form;
1405 char *err;
1406 int retcode = 0;
1408 form = use_display_format (p, panel_format (p), &err, 0);
1410 if (err){
1411 g_free (err);
1412 retcode = 1;
1414 else {
1415 if (p->format)
1416 delete_format (p->format);
1418 p->format = form;
1421 if (show_mini_info){
1423 form = use_display_format (p, mini_status_format (p), &err, 1);
1425 if (err){
1426 g_free (err);
1427 retcode += 2;
1429 else {
1430 if (p->status_format)
1431 delete_format (p->status_format);
1433 p->status_format = form;
1437 panel_format_modified (p);
1438 panel_update_cols (&(p->widget), p->frame_size);
1440 if (retcode)
1441 message( 1, _(" Warning " ), _( "User suplied format looks invalid, reverting to default." ) );
1442 if (retcode & 0x01){
1443 g_free (p->user_format);
1444 p->user_format = g_strdup (DEFAULT_USER_FORMAT);
1446 if (retcode & 0x02){
1447 g_free (p->user_status_format [p->list_type]);
1448 p->user_status_format [p->list_type] = g_strdup (DEFAULT_USER_FORMAT);
1451 return retcode;
1454 /* Given the panel->view_type returns the format string to be parsed */
1455 char *
1456 panel_format (WPanel *panel)
1458 switch (panel->list_type){
1460 case list_long:
1461 return "full perm,space,nlink,space,owner,space,group,space,size,space,mtime,space,name";
1463 case list_brief:
1464 return "half 2,type,name";
1466 case list_user:
1467 return panel->user_format;
1469 default:
1470 case list_full:
1471 return "half type,name,|,size,|,mtime";
1475 char *
1476 mini_status_format (WPanel *panel)
1478 if (panel->user_mini_status)
1479 return panel->user_status_format [panel->list_type];
1481 switch (panel->list_type){
1483 case list_long:
1484 return "full perm,space,nlink,space,owner,space,group,space,size,space,mtime,space,name";
1486 case list_brief:
1487 return "half type,name,space,bsize,space,perm,space";
1489 case list_full:
1490 return "half type,name";
1492 default:
1493 case list_user:
1494 return panel->user_format;
1498 /* */
1499 /* Panel operation commands */
1500 /* */
1502 /* Returns the number of items in the given panel */
1504 ITEMS (WPanel *p)
1506 if (p->split)
1507 return llines (p) * 2;
1508 else
1509 return llines (p);
1512 /* This function sets redisplays the selection */
1513 void
1514 select_item (WPanel *panel)
1516 int repaint = 0;
1517 int items = ITEMS (panel);
1519 /* Although currently all over the code we set the selection and
1520 top file to decent values before calling select_item, I could
1521 forget it someday, so it's better to do the actual fitting here */
1523 #ifdef HAVE_X
1524 int old_top;
1525 old_top = panel->top_file;
1526 #endif
1528 if (is_a_desktop_panel (panel))
1529 return;
1531 if (panel->top_file < 0){
1532 repaint = 1;
1533 panel->top_file = 0;
1536 if (panel->selected < 0)
1537 panel->selected = 0;
1539 if (panel->selected > panel->count-1)
1540 panel->selected = panel->count - 1;
1542 if (panel->top_file > panel->count-1){
1543 repaint = 1;
1544 panel->top_file = panel->count-1;
1547 if ((panel->count - panel->top_file) < items){
1548 repaint = 1;
1549 panel->top_file = panel->count - items;
1550 if (panel->top_file < 0)
1551 panel->top_file = 0;
1554 if (panel->selected < panel->top_file){
1555 repaint = 1;
1556 panel->top_file = panel->selected;
1559 if ((panel->selected - panel->top_file) >= items){
1560 repaint = 1;
1561 panel->top_file = panel->selected - items + 1;
1564 #ifndef HAVE_X
1565 if (repaint)
1566 paint_panel (panel);
1567 else
1568 repaint_file (panel, panel->selected, 1, 2*selection (panel)->f.marked+1, 0);
1569 #else
1570 if (old_top != panel->top_file)
1571 x_adjust_top_file (panel);
1572 x_select_item (panel);
1573 #endif
1575 display_mini_info (panel);
1577 execute_hooks (select_file_hook);
1580 /* Clears all files in the panel, used only when one file was marked */
1581 void
1582 unmark_files (WPanel *panel)
1584 int i;
1586 if (!panel->marked)
1587 return;
1588 for (i = 0; i < panel->count; i++)
1589 file_mark (panel, i, 0);
1591 panel->dirs_marked = 0;
1592 panel->marked = 0;
1593 panel->total = 0;
1596 #ifdef HAVE_X
1597 void
1598 unselect_item (WPanel *panel)
1600 x_unselect_item (panel);
1602 #else
1603 void
1604 unselect_item (WPanel *panel)
1606 repaint_file (panel, panel->selected, 1, 2*selection (panel)->f.marked, 0);
1608 #endif
1610 static void
1611 do_move_down (WPanel *panel)
1613 if (panel->selected+1 == panel->count)
1614 return;
1616 unselect_item (panel);
1617 panel->selected++;
1619 #ifndef HAVE_X
1620 if (panel->selected - panel->top_file == ITEMS (panel) &&
1621 panel_scroll_pages){
1622 /* Scroll window half screen */
1623 panel->top_file += ITEMS (panel)/2;
1624 if (panel->top_file > panel->count - ITEMS (panel))
1625 panel->top_file = panel->count - ITEMS (panel);
1626 paint_dir (panel);
1627 select_item (panel);
1629 #endif
1630 select_item (panel);
1633 static void
1634 do_move_up (WPanel *panel)
1636 if (panel->selected == 0)
1637 return;
1639 unselect_item (panel);
1640 panel->selected--;
1641 #ifndef HAVE_X
1642 if (panel->selected < panel->top_file && panel_scroll_pages){
1643 /* Scroll window half screen */
1644 panel->top_file -= ITEMS (panel)/2;
1645 if (panel->top_file < 0) panel->top_file = 0;
1646 paint_dir (panel);
1648 #endif
1649 select_item (panel);
1652 static void
1653 move_rel (WPanel *panel, int rel)
1655 unselect_item (panel);
1657 if (rel < 0){
1658 if (panel->selected + rel < 0)
1659 panel->selected = 0;
1660 else
1661 panel->selected = panel->selected + rel;
1662 } else {
1663 if (panel->selected + rel >= panel->count)
1664 panel->selected = panel->count - 1;
1665 else
1666 panel->selected = panel->selected + rel;
1668 select_item (panel);
1671 /* */
1672 /* Panel key binded commands */
1673 /* */
1674 static void
1675 move_up (WPanel *panel)
1677 if (panel->list_type == list_icons){
1678 move_rel (panel, -ICONS_PER_ROW (panel));
1679 } else
1680 do_move_up (panel);
1683 static void
1684 move_down (WPanel *panel)
1686 if (panel->list_type == list_icons){
1687 move_rel (panel, ICONS_PER_ROW (panel));
1688 } else
1689 do_move_down (panel);
1692 /* Changes the selection by lines (may be negative) */
1693 static void
1694 move_selection (WPanel *panel, int lines)
1696 int new_pos;
1697 #ifndef HAVE_X
1698 int adjust = 0;
1699 #endif
1701 new_pos = panel->selected + lines;
1702 if (new_pos >= panel->count)
1703 new_pos = panel->count-1;
1705 if (new_pos < 0)
1706 new_pos = 0;
1708 unselect_item (panel);
1709 panel->selected = new_pos;
1711 #ifndef HAVE_X
1712 if (panel->selected - panel->top_file >= ITEMS (panel)){
1713 panel->top_file += lines;
1714 adjust = 1;
1717 if (panel->selected - panel->top_file < 0){
1718 panel->top_file += lines;
1719 adjust = 1;
1722 if (adjust){
1723 if (panel->top_file > panel->selected)
1724 panel->top_file = panel->selected;
1725 if (panel->top_file < 0)
1726 panel->top_file = 0;
1727 paint_dir (panel);
1729 #endif
1730 select_item (panel);
1733 static int
1734 move_left (WPanel *panel, int c_code)
1736 if (panel->list_type == list_icons){
1737 do_move_up (panel);
1738 return 1;
1739 } else {
1740 if (panel->split){
1741 move_selection (panel, -llines (panel));
1742 return 1;
1743 } else
1744 return maybe_cd (c_code, 0);
1748 static int
1749 move_right (WPanel *panel, int c_code)
1751 if (panel->list_type == list_icons){
1752 do_move_down (panel);
1753 return 1;
1754 } else {
1755 if (panel->split){
1756 move_selection (panel, llines (panel));
1757 return 1;
1758 } else
1759 return maybe_cd (c_code, 1);
1763 static void
1764 prev_page (WPanel *panel)
1766 int items;
1768 if (!panel->selected && !panel->top_file)
1769 return;
1770 unselect_item (panel);
1771 items = ITEMS (panel);
1772 if (panel->top_file < items)
1773 items = panel->top_file;
1774 if (!items)
1775 panel->selected = 0;
1776 else
1777 panel->selected -= items;
1778 panel->top_file -= items;
1780 /* This keeps the selection in a reasonable place */
1781 if (panel->selected < 0)
1782 panel->selected = 0;
1783 if (panel->top_file < 0)
1784 panel->top_file = 0;
1785 x_adjust_top_file (panel);
1786 select_item (panel);
1787 #ifndef HAVE_X
1788 paint_dir (panel);
1789 #endif
1792 static void
1793 prev_page_key (WPanel *panel)
1795 if (console_flag && ctrl_pressed ()){
1796 do_cd ("..", cd_exact);
1797 } else
1798 prev_page (panel);
1801 static void
1802 next_page (WPanel *panel)
1804 int items;
1806 if (panel->selected == panel->count - 1)
1807 return;
1808 unselect_item (panel);
1809 items = ITEMS (panel);
1810 if (panel->top_file > panel->count - 2 * items)
1811 items = panel->count - items - panel->top_file;
1812 if (panel->top_file + items < 0)
1813 items = - panel->top_file;
1814 if (!items)
1815 panel->selected = panel->count - 1;
1816 else
1817 panel->selected += items;
1818 panel->top_file += items;
1820 /* This keeps the selection in it's relative position */
1821 if (panel->selected >= panel->count)
1822 panel->selected = panel->count - 1;
1823 if (panel->top_file >= panel->count)
1824 panel->top_file = panel->count - 1;
1825 x_adjust_top_file (panel);
1826 select_item (panel);
1827 #ifndef HAVE_X
1828 paint_dir (panel);
1829 #endif
1832 static void next_page_key (WPanel *panel)
1834 if (console_flag&&ctrl_pressed()&&
1835 (S_ISDIR(selection (panel)->buf.st_mode) ||
1836 link_isdir (selection (panel))))
1837 do_cd (selection (panel)->fname, cd_exact);
1838 else
1839 next_page (panel);
1842 static void
1843 goto_top_file (WPanel *panel)
1845 unselect_item (panel);
1846 panel->selected = panel->top_file;
1847 select_item (panel);
1850 static void
1851 goto_middle_file (WPanel *panel)
1853 unselect_item (panel);
1854 panel->selected = panel->top_file + (ITEMS (panel)/2);
1855 if (panel->selected >= panel->count)
1856 panel->selected = panel->count - 1;
1857 select_item (panel);
1860 static void
1861 goto_bottom_file (WPanel *panel)
1863 unselect_item (panel);
1864 panel->selected = panel->top_file + ITEMS (panel)-1;
1865 if (panel->selected >= panel->count)
1866 panel->selected = panel->count - 1;
1867 select_item (panel);
1870 static void
1871 move_home (WPanel *panel)
1873 if (panel->selected == 0)
1874 return;
1875 unselect_item (panel);
1877 if (torben_fj_mode){
1878 int middle_pos = panel->top_file + (ITEMS (panel)/2);
1880 if (panel->selected > middle_pos){
1881 goto_middle_file (panel);
1882 return;
1884 if (panel->selected != panel->top_file){
1885 goto_top_file (panel);
1886 return;
1890 panel->top_file = 0;
1891 panel->selected = 0;
1893 #ifndef HAVE_X
1894 paint_dir (panel);
1895 #endif
1896 select_item (panel);
1899 static void
1900 move_end (WPanel *panel)
1902 if (panel->selected == panel->count-1)
1903 return;
1904 unselect_item (panel);
1905 if (torben_fj_mode){
1906 int middle_pos = panel->top_file + (ITEMS (panel)/2);
1908 if (panel->selected < middle_pos){
1909 goto_middle_file (panel);
1910 return;
1912 if (panel->selected != (panel->top_file + ITEMS(panel)-1)){
1913 goto_bottom_file (panel);
1914 return;
1918 panel->selected = panel->count-1;
1919 #ifndef HAVE_X
1920 paint_dir (panel);
1921 #endif
1922 select_item (panel);
1925 /* Recalculate the panels summary information, used e.g. when marked
1926 files might have been removed by an external command */
1927 void
1928 recalculate_panel_summary (WPanel *panel)
1930 int i;
1932 panel->marked = 0;
1933 panel->dirs_marked = 0;
1934 panel->total = 0;
1936 for (i = 0; i < panel->count; i++)
1937 if (panel->dir.list [i].f.marked){
1938 /* do_file_mark will return immediately if newmark == oldmark.
1939 So we have to first unmark it to get panel's summary information
1940 updated. (Norbert) */
1941 panel->dir.list [i].f.marked = 0;
1942 do_file_mark (panel, i, 1);
1946 /* This routine marks a file or a directory */
1947 void
1948 do_file_mark (WPanel *panel, int idx, int mark)
1950 if (panel->dir.list [idx].f.marked == mark)
1951 return;
1953 * Only '..' can't be marked, '.' isn't visible.
1955 if (strcmp (panel->dir.list [idx].fname, "..")){
1956 file_mark (panel, idx, mark);
1957 if (panel->dir.list [idx].f.marked){
1958 panel->marked++;
1959 if (S_ISDIR (panel->dir.list [idx].buf.st_mode)) {
1960 if (panel->dir.list [idx].f.dir_size_computed)
1961 panel->total += panel->dir.list [idx].buf.st_size;
1962 panel->dirs_marked++;
1963 } else
1964 panel->total += panel->dir.list [idx].buf.st_size;
1965 set_colors (panel);
1966 } else {
1967 if (S_ISDIR(panel->dir.list [idx].buf.st_mode)) {
1968 if (panel->dir.list [idx].f.dir_size_computed)
1969 panel->total -= panel->dir.list [idx].buf.st_size;
1970 panel->dirs_marked--;
1971 } else
1972 panel->total -= panel->dir.list [idx].buf.st_size;
1973 panel->marked--;
1978 void
1979 do_file_mark_range (WPanel *panel, int r1, int r2)
1981 const int start = min (r1, r2);
1982 const int end = max (r1, r2);
1983 int i, mark;
1985 mark = !panel->dir.list [start].f.marked;
1987 for (i = start; i < end; i++)
1988 do_file_mark (panel, i, mark);
1991 static void
1992 do_mark_file (WPanel *panel, int do_move)
1994 int idx = panel->selected;
1996 do_file_mark (panel, idx, selection (panel)->f.marked ? 0 : 1);
1997 repaint_file (panel, idx, 1, 2*panel->dir.list [idx].f.marked+1, 0);
1999 if (mark_moves_down && do_move)
2000 move_down (panel);
2001 display_mini_info (panel);
2004 static void
2005 mark_file (WPanel *panel)
2007 do_mark_file (panel, 1);
2010 /* Incremental search of a file name in the panel */
2011 static void
2012 do_search (WPanel *panel, int c_code)
2014 int l, i;
2015 int wrapped = 0;
2016 int found;
2018 l = strlen (panel->search_buffer);
2019 if (l && (c_code == 8 || c_code == 0177 || c_code == KEY_BACKSPACE))
2020 panel->search_buffer [--l] = 0;
2021 else {
2022 if (c_code && l < sizeof (panel->search_buffer)){
2023 panel->search_buffer [l] = c_code;
2024 panel->search_buffer [l+1] = 0;
2025 l++;
2029 found = 0;
2030 for (i = panel->selected; !wrapped || i != panel->selected; i++){
2031 if (i >= panel->count){
2032 i = 0;
2033 if (wrapped)
2034 break;
2035 wrapped = 1;
2037 if (STRNCOMP (panel->dir.list [i].fname, panel->search_buffer, l) == 0){
2038 unselect_item (panel);
2039 panel->selected = i;
2040 select_item (panel);
2041 found = 1;
2042 break;
2045 if (!found)
2046 panel->search_buffer [--l] = 0;
2047 #ifndef HAVE_X
2048 paint_panel (panel);
2049 #endif
2052 void
2053 start_search (WPanel *panel)
2055 if (panel->searching){
2056 if (panel->selected+1 == panel->count)
2057 panel->selected = 0;
2058 else
2059 do_move_down (panel);
2060 do_search (panel, 0);
2061 } else {
2062 panel->searching = 1;
2063 panel->search_buffer [0] = 0;
2064 display_mini_info (panel);
2065 mc_refresh ();
2068 /* This procedure was getting really messy with all the rewriting and ifdef's
2069 * so I just splet them out. -jrb */
2070 #ifdef HAVE_GNOME
2071 extern void set_cursor_busy (WPanel *panel);
2072 extern void set_cursor_normal (WPanel *panel);
2074 do_enter_on_file_entry (file_entry *fe)
2076 gint retval;
2077 char *full_name;
2079 set_cursor_busy (cpanel);
2080 /* Can we change dirs? */
2081 if (S_ISDIR (fe->buf.st_mode) || link_isdir (fe)) {
2082 do_cd (fe->fname, cd_exact);
2083 set_cursor_normal (cpanel);
2084 return 1;
2086 /* do metadata/mime stuff tell us anything? */
2087 if (gmc_open (fe) != 0) {
2088 set_cursor_normal (cpanel);
2089 return 1;
2091 /* can we change dirs? */
2092 full_name = concat_dir_and_file (cpanel->cwd, fe->fname);
2093 if (is_exe (fe->buf.st_mode) && if_link_is_exe (full_name, fe)) {
2094 g_free (full_name);
2095 #ifdef USE_VFS
2096 if (vfs_current_is_local ())
2097 #endif
2099 char *tmp = name_quote (fe->fname, 0);
2100 char *cmd = g_strconcat (".", PATH_SEP_STR, tmp, NULL);
2101 g_free (tmp);
2102 if (!confirm_execute || (query_dialog (_(" The Midnight Commander "),
2103 _(" Do you really want to execute? "),
2104 0, 2, _("Yes"), _("No")) == 0))
2105 execute (cmd);
2106 g_free (cmd);
2108 #ifdef USE_VFS
2109 else {
2110 char *tmp;
2112 tmp = concat_dir_and_file (vfs_get_current_dir(), fe->fname);
2113 if (!mc_setctl (tmp, MCCTL_EXTFS_RUN, NULL))
2114 message (1, _(" Warning "), _(" No action taken "));
2115 g_free (tmp);
2117 #endif /* USE_VFS */
2118 set_cursor_normal (cpanel);
2119 return 1;
2122 g_free (full_name);
2123 /* looks like we couldn't open it. Let's ask the user */
2124 retval = gmc_open_with (fe->fname);
2125 set_cursor_normal (cpanel);
2126 return retval;
2128 #else
2130 do_enter_on_file_entry (file_entry *fe)
2132 char *full_name;
2134 if (S_ISDIR (fe->buf.st_mode) || link_isdir (fe)) {
2135 do_cd (fe->fname, cd_exact);
2136 return 1;
2137 } else {
2138 full_name = concat_dir_and_file (cpanel->cwd, fe->fname);
2139 if (is_exe (fe->buf.st_mode) && if_link_is_exe (full_name, fe)) {
2140 g_free (full_name);
2142 #ifdef USE_VFS
2143 if (vfs_current_is_local ())
2144 #endif
2146 char *tmp = name_quote (fe->fname, 0);
2147 char *cmd = g_strconcat (".", PATH_SEP_STR, tmp, NULL);
2148 g_free (tmp);
2149 if (!confirm_execute || (query_dialog (_(" The Midnight Commander "),
2150 _(" Do you really want to execute? "),
2151 0, 2, _("&Yes"), _("&No")) == 0))
2152 execute (cmd);
2153 g_free (cmd);
2155 #ifdef USE_VFS
2156 else {
2157 /* if (vfs_current_is_extfs ()) - I see no reason why
2158 filesystems other than extfs could not implement same
2159 call... -- pavel@ucw.cz*/
2160 char *tmp;
2162 tmp = concat_dir_and_file (vfs_get_current_dir(), fe->fname);
2163 if (!mc_setctl (tmp, MCCTL_EXTFS_RUN, NULL))
2164 message (1, _(" Warning "), _(" No action taken "));
2166 g_free (tmp);
2168 #endif /* USE_VFS */
2169 return 1;
2170 } else {
2171 char *p;
2173 g_free (full_name);
2175 p = regex_command (fe->fname, "Open", NULL, 0);
2176 if (p && (strcmp (p, "Success") == 0))
2177 return 1;
2178 else
2179 return 0;
2183 #endif /* else not HAVE_GNOME */
2185 do_enter (WPanel *panel)
2187 return do_enter_on_file_entry (selection (panel));
2190 static void
2191 chdir_other_panel (WPanel *panel)
2193 char *new_dir;
2195 if (get_other_type () != view_listing)
2196 return;
2198 if (!S_ISDIR (panel->dir.list [panel->selected].buf.st_mode))
2199 new_dir = concat_dir_and_file (panel->cwd, "..");
2200 else
2201 new_dir = concat_dir_and_file (panel->cwd, panel->dir.list [panel->selected].fname);
2203 change_panel ();
2204 do_cd (new_dir, cd_exact);
2205 change_panel ();
2207 move_down (panel);
2209 g_free (new_dir);
2212 static void
2213 chdir_to_readlink (WPanel *panel)
2215 char *new_dir;
2217 if (get_other_type () != view_listing)
2218 return;
2220 if (S_ISLNK (panel->dir.list [panel->selected].buf.st_mode)) {
2221 char buffer [MC_MAXPATHLEN], *p;
2222 int i;
2223 struct stat mybuf;
2225 i = readlink (selection (panel)->fname, buffer, MC_MAXPATHLEN);
2226 if (i < 0)
2227 return;
2228 if (mc_stat (selection (panel)->fname, &mybuf) < 0)
2229 return;
2230 buffer [i] = 0;
2231 if (!S_ISDIR (mybuf.st_mode)) {
2232 p = strrchr (buffer, PATH_SEP);
2233 if (p && !p[1]) {
2234 *p = 0;
2235 p = strrchr (buffer, PATH_SEP);
2237 if (!p)
2238 return;
2239 p[1] = 0;
2241 if (*buffer == PATH_SEP)
2242 new_dir = g_strdup (buffer);
2243 else
2244 new_dir = concat_dir_and_file (panel->cwd, buffer);
2246 change_panel ();
2247 do_cd (new_dir, cd_exact);
2248 change_panel ();
2250 move_down (panel);
2252 g_free (new_dir);
2256 static const key_map panel_keymap [] = {
2257 { KEY_DOWN, move_down },
2258 { KEY_UP, move_up },
2260 /* The action button :-) */
2261 { '\n', (key_callback) do_enter },
2262 { KEY_ENTER, (key_callback) do_enter },
2264 { KEY_IC, mark_file },
2265 { KEY_HOME, move_home },
2266 { KEY_C1, move_end },
2267 { KEY_END, move_end },
2268 { KEY_A1, move_home },
2269 { KEY_NPAGE, next_page_key },
2270 { KEY_PPAGE, prev_page_key },
2272 /* To quickly move in the panel */
2273 { ALT('g'), goto_top_file },
2274 { ALT('r'), goto_middle_file }, /* M-r like emacs */
2275 { ALT('j'), goto_bottom_file },
2277 #ifdef OS2_NT
2278 { ALT(KEY_F(11)), drive_cmd_a },
2279 { ALT(KEY_F(12)), drive_cmd_b },
2280 { ALT('d'), drive_chg },
2281 #endif
2283 /* Emacs-like bindings */
2284 { XCTRL('v'), next_page }, /* C-v like emacs */
2285 { ALT('v'), prev_page }, /* M-v like emacs */
2286 { XCTRL('p'), move_up }, /* C-p like emacs */
2287 { XCTRL('n'), move_down }, /* C-n like emacs */
2288 { XCTRL('s'), start_search }, /* C-s like emacs */
2289 { ALT('s'), start_search }, /* M-s not like emacs */
2290 { XCTRL('t'), mark_file },
2291 { ALT('o'), chdir_other_panel },
2292 { ALT('l'), chdir_to_readlink },
2293 { KEY_F(13), view_simple_cmd },
2294 { KEY_F(14), edit_cmd_new },
2295 { ALT('y'), directory_history_prev },
2296 { ALT('u'), directory_history_next },
2297 { ALT('H'), directory_history_list },
2298 { ALT('+'), select_cmd_panel },
2299 { KEY_KP_ADD, select_cmd_panel },
2300 { ALT('\\'), unselect_cmd_panel },
2301 { ALT('-'), unselect_cmd_panel },
2302 { KEY_KP_SUBTRACT, unselect_cmd_panel },
2303 { ALT('*'), reverse_selection_cmd_panel },
2304 { KEY_KP_MULTIPLY, reverse_selection_cmd_panel },
2307 #ifdef HAVE_GNOME
2308 { '+', select_cmd_panel },
2309 { '\\', unselect_cmd_panel },
2310 { '-', unselect_cmd_panel },
2311 { '*', reverse_selection_cmd_panel },
2312 { XCTRL('r'), reread_cmd },
2313 { KEY_F(3), view_panel_cmd },
2314 { KEY_F(4), edit_panel_cmd },
2315 { KEY_F(5), copy_cmd },
2316 { KEY_F(6), ren_cmd },
2317 { KEY_F(7), mkdir_panel_cmd },
2318 { KEY_F(8), delete_cmd },
2319 { KEY_DC, delete_cmd },
2320 #endif
2322 { 0, 0 }
2325 static inline int
2326 panel_key (WPanel *panel, int key)
2328 int i;
2330 for (i = 0; panel_keymap [i].key_code; i++){
2331 if (key == panel_keymap [i].key_code){
2332 if (panel_keymap [i].fn != start_search)
2333 panel->searching = 0;
2334 (*panel_keymap [i].fn)(panel);
2335 return 1;
2338 if (torben_fj_mode && key == ALT('h')) {
2339 goto_middle_file (panel);
2340 return 1;
2343 /* We do not want to take a key press if nothing can be done with it */
2344 /* The command line widget may do something more usefull */
2345 if (key == KEY_LEFT)
2346 return move_left (panel, key);
2348 if (key == KEY_RIGHT)
2349 return move_right (panel, key);
2351 if (is_abort_char (key)) {
2352 panel->searching = 0;
2353 display_mini_info (panel);
2354 return 1;
2357 /* Do not eat characters not meant for the panel below ' ' (e.g. C-l). */
2358 if ((key >= ' '&& key <= 255) || key == 8 || key == KEY_BACKSPACE) {
2359 if (panel->searching){
2360 do_search (panel, key);
2361 return 1;
2364 if (!command_prompt) {
2365 start_search (panel);
2366 do_search (panel, key);
2367 return 1;
2371 return 0;
2374 void user_file_menu_cmd (void) { user_menu_cmd (NULL); }
2376 static int
2377 panel_callback (Dlg_head *h, WPanel *panel, int msg, int par)
2379 switch (msg){
2380 case WIDGET_INIT:
2381 #ifdef HAVE_X
2382 define_label (h, (Widget *)panel, 1, _("Help"), help_cmd);
2383 define_label (h, (Widget *)panel, 2, _("Menu"), user_file_menu_cmd);
2384 define_label (h, (Widget *)panel, 3, _("View"), view_panel_cmd);
2385 define_label (h, (Widget *)panel, 4, _("Edit"), edit_panel_cmd);
2386 define_label (h, (Widget *)panel, 5, _("Copy"), copy_cmd);
2387 define_label (h, (Widget *)panel, 6, _("RenMov"), ren_cmd);
2388 define_label (h, (Widget *)panel, 7, _("Mkdir"), mkdir_panel_cmd);
2389 define_label (h, (Widget *)panel, 8, _("Delete"), delete_cmd);
2390 x_create_panel (h, h->wdata, panel);
2391 #endif
2392 return 1;
2394 case WIDGET_DRAW:
2395 paint_panel (panel);
2396 break;
2398 case WIDGET_FOCUS:
2399 #ifndef HAVE_GNOME
2400 current_panel = panel;
2401 #endif
2402 panel->active = 1;
2403 if (mc_chdir (panel->cwd) != 0){
2404 message (1, MSG_ERROR, _(" Can't chdir to \"%s\" \n %s "),
2405 panel->cwd, unix_error_string (errno));
2406 } else
2407 subshell_chdir (panel->cwd);
2409 show_dir (panel);
2410 focus_select_item (panel);
2411 #ifndef HAVE_X
2412 define_label (h, (Widget *)panel, 1, _("Help"), help_cmd);
2413 define_label (h, (Widget *)panel, 2, _("Menu"), user_file_menu_cmd);
2414 define_label (h, (Widget *)panel, 3, _("View"), view_panel_cmd);
2415 define_label (h, (Widget *)panel, 4, _("Edit"), edit_panel_cmd);
2416 define_label (h, (Widget *)panel, 5, _("Copy"), copy_cmd);
2417 define_label (h, (Widget *)panel, 6, _("RenMov"), ren_cmd);
2418 define_label (h, (Widget *)panel, 7, _("Mkdir"), mkdir_panel_cmd);
2419 define_label (h, (Widget *)panel, 8, _("Delete"), delete_cmd);
2420 redraw_labels (h, (Widget *)panel);
2421 #endif
2422 /* Chain behaviour */
2423 default_proc (h, WIDGET_FOCUS, par);
2424 return 1;
2426 case WIDGET_UNFOCUS:
2427 /* Janne: look at this for the multiple panel options */
2428 if (panel->searching){
2429 panel->searching = 0;
2430 display_mini_info (panel);
2432 #ifdef HAVE_X
2433 show_dir (panel);
2434 unfocus_unselect_item (panel);
2435 panel->active = 0;
2436 #else
2437 panel->active = 0;
2438 show_dir (panel);
2439 unselect_item (panel);
2440 #endif
2441 return 1;
2443 case WIDGET_KEY:
2444 return panel_key (panel, par);
2445 break;
2447 return default_proc (h, msg, par);
2450 /* */
2451 /* Panel mouse events support routines */
2452 /* */
2453 static int mouse_marking = 0;
2455 static void
2456 mouse_toggle_mark (WPanel *panel)
2458 do_mark_file (panel, 0);
2459 mouse_marking = selection (panel)->f.marked;
2462 static void
2463 mouse_set_mark (WPanel *panel)
2465 if (mouse_marking && !(selection (panel)->f.marked))
2466 do_mark_file (panel, 0);
2467 else if (!mouse_marking && (selection (panel)->f.marked))
2468 do_mark_file (panel, 0);
2471 static inline int
2472 mark_if_marking (WPanel *panel, Gpm_Event *event)
2474 if (event->buttons & GPM_B_RIGHT){
2475 if (event->type & GPM_DOWN)
2476 mouse_toggle_mark (panel);
2477 else
2478 mouse_set_mark (panel);
2479 return 1;
2481 return 0;
2484 void
2485 file_mark (WPanel *panel, int index, int val)
2487 panel->dir.list [index].f.marked = val;
2488 x_panel_select_item (panel, index, val);
2491 #ifdef PORT_WANTS_GET_SORT_FN
2492 sortfn *
2493 get_sort_fn (char *name)
2495 int i;
2497 /* First, try the long name options, from dir.c */
2498 for (i = 0; i < SORT_TYPES_TOTAL; i++)
2499 if (strcmp (name, sort_orders [i].sort_name) == 0)
2500 return (sortfn *)sort_orders [i].sort_fn;
2502 /* Then try the short name options, from our local table */
2503 for (i = 0; i < ELEMENTS (formats); i++){
2504 if (strcmp (name, formats [i].id) == 0 && formats [i].sort_routine)
2505 return formats [i].sort_routine;
2507 return NULL;
2510 static int
2511 panel_event (Gpm_Event *event, WPanel *panel)
2513 const int lines = panel->count;
2515 int my_index;
2517 event->y -= 2;
2518 if ((event->type & (GPM_DOWN|GPM_DRAG))){
2520 if (panel != (WPanel *) current_dlg->current->widget)
2521 change_panel ();
2523 if (event->y <= 0){
2524 mark_if_marking (panel, event);
2525 return MOU_REPEAT;
2528 if (!((panel->top_file + event->y <= panel->count) &&
2529 event->y <= lines)){
2530 mark_if_marking (panel, event);
2531 return MOU_REPEAT;
2533 my_index = panel->top_file + event->y - 1;
2534 if (panel->split){
2535 if (event->x > ((panel->widget.cols-2)/2))
2536 my_index += llines (panel);
2539 if (my_index >= panel->count)
2540 my_index = panel->count - 1;
2542 if (my_index != panel->selected){
2543 unselect_item (panel);
2544 panel->selected = my_index;
2545 select_item (panel);
2548 /* This one is new */
2549 mark_if_marking (panel, event);
2551 } else if ((event->type & (GPM_UP|GPM_DOUBLE)) == (GPM_UP|GPM_DOUBLE)){
2552 if (event->y > 0 && event->y <= lines)
2553 do_enter (panel);
2555 return MOU_NORMAL;
2558 #else
2560 static int
2561 panel_event (Gpm_Event *event, WPanel *panel)
2563 const int lines = llines (panel);
2565 int my_index;
2567 if (event->type & GPM_DOWN && event->x == 1 + 1 && event->y == 0 + 1) {
2568 directory_history_prev (panel);
2569 return MOU_NORMAL;
2572 if (event->type & GPM_DOWN && event->x == panel->widget.cols - 2 + 1 && event->y == 0 + 1) {
2573 directory_history_next (panel);
2574 return MOU_NORMAL;
2577 if (event->type & GPM_DOWN && event->x == panel->widget.cols - 3 + 1 && event->y == 0 + 1) {
2578 directory_history_list (panel);
2579 return MOU_NORMAL;
2582 event->y -= 2;
2583 if ((event->type & (GPM_DOWN|GPM_DRAG))){
2585 if (panel != (WPanel *) current_dlg->current->widget)
2586 change_panel ();
2588 if (event->y <= 0){
2589 mark_if_marking (panel, event);
2590 if (mouse_move_pages)
2591 prev_page (panel);
2592 else
2593 move_up (panel);
2594 return MOU_REPEAT;
2597 if (!((panel->top_file + event->y <= panel->count) &&
2598 event->y <= lines)){
2599 mark_if_marking (panel, event);
2600 if (mouse_move_pages)
2601 next_page (panel);
2602 else
2603 move_down (panel);
2604 return MOU_REPEAT;
2606 my_index = panel->top_file + event->y - 1;
2607 if (panel->split){
2608 if (event->x > ((panel->widget.cols-2)/2))
2609 my_index += llines (panel);
2612 if (my_index >= panel->count)
2613 my_index = panel->count - 1;
2615 if (my_index != panel->selected){
2616 unselect_item (panel);
2617 panel->selected = my_index;
2618 select_item (panel);
2621 /* This one is new */
2622 mark_if_marking (panel, event);
2624 } else if ((event->type & (GPM_UP|GPM_DOUBLE)) == (GPM_UP|GPM_DOUBLE)){
2625 if (event->y > 0 && event->y <= lines)
2626 do_enter (panel);
2628 return MOU_NORMAL;
2630 #endif
2632 void
2633 panel_update_marks (WPanel *panel)
2635 #ifdef PORT_HAS_UPDATE_MARKS
2636 x_panel_update_marks (panel);
2637 #endif
2640 void
2641 panel_re_sort (WPanel *panel)
2643 char *filename;
2644 int i;
2646 if (panel == NULL)
2647 return;
2649 filename = g_strdup (selection (panel)->fname);
2650 unselect_item (panel);
2651 do_sort (&panel->dir, panel->sort_type, panel->count-1, panel->reverse, panel->case_sensitive);
2652 panel->selected = -1;
2653 for (i = panel->count; i; i--){
2654 if (!strcmp (panel->dir.list [i-1].fname, filename)){
2655 panel->selected = i-1;
2656 break;
2659 g_free (filename);
2660 panel->top_file = panel->selected - ITEMS (panel)/2;
2661 if (panel->top_file < 0)
2662 panel->top_file = 0;
2663 select_item (panel);
2664 panel_update_contents (panel);
2667 void
2668 panel_set_sort_order (WPanel *panel, sortfn *sort_order)
2670 if (sort_order == 0)
2671 return;
2673 panel->sort_type = sort_order;
2675 /* The directory is already sorted, we have to load the unsorted stuff */
2676 if (sort_order == (sortfn *) unsorted){
2677 char *current_file;
2679 current_file = g_strdup (panel->dir.list [panel->selected].fname);
2680 panel_reload (panel);
2681 try_to_select (panel, current_file);
2682 g_free (current_file);
2684 panel_re_sort (panel);