2 Panel layout module for the Midnight Commander
4 Copyright (C) 1995-2020
5 Free Software Foundation, Inc.
10 Andrew Borodin <aborodin@vmail.ru>, 2011, 2012, 2013
11 Slava Zanko <slavazanko@gmail.com>, 2013
12 Avi Kelman <patcherton.fixesthings@gmail.com>, 2013
14 This file is part of the Midnight Commander.
16 The Midnight Commander is free software: you can redistribute it
17 and/or modify it under the terms of the GNU General Public License as
18 published by the Free Software Foundation, either version 3 of the License,
19 or (at your option) any later version.
21 The Midnight Commander is distributed in the hope that it will be useful,
22 but WITHOUT ANY WARRANTY; without even the implied warranty of
23 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 GNU General Public License for more details.
26 You should have received a copy of the GNU General Public License
27 along with this program. If not, see <http://www.gnu.org/licenses/>.
31 * \brief Source: panel layout module
36 #include <pwd.h> /* for username in xterm title */
40 #include <sys/types.h>
43 #include "lib/global.h"
44 #include "lib/tty/tty.h"
46 #include "lib/tty/key.h"
47 #include "lib/tty/mouse.h"
48 #include "lib/mcconfig.h"
49 #include "lib/vfs/vfs.h" /* For _vfs_get_cwd () */
50 #include "lib/strutil.h"
51 #include "lib/widget.h"
52 #include "lib/event.h"
53 #include "lib/util.h" /* mc_time_elapsed() */
55 #include "src/consaver/cons.saver.h"
56 #include "src/viewer/mcviewer.h" /* The view widget */
57 #include "src/setup.h"
58 #ifdef ENABLE_SUBSHELL
59 #include "src/subshell/subshell.h"
65 /* Needed for the extern declarations of integer parameters */
68 #include "info.h" /* The Info widget */
70 /*** global variables ****************************************************************************/
72 panels_layout_t panels_layout
= {
73 /* Set if the panels are split horizontally */
74 .horizontal_split
= FALSE
,
77 .vertical_equal
= TRUE
,
80 /* horizontal split */
81 .horizontal_equal
= TRUE
,
85 /* Controls the display of the rotating dash on the verbose mode */
86 gboolean nice_rotating_dash
= TRUE
;
88 /* The number of output lines shown (if available) */
91 /* Set if the command prompt is to be displayed */
92 gboolean command_prompt
= TRUE
;
94 /* Set if the main menu is visible */
95 gboolean menubar_visible
= TRUE
;
97 /* Set to show current working dir in xterm window title */
98 gboolean xterm_title
= TRUE
;
100 /* Set to show free space on device assigned to current directory */
101 gboolean free_space
= TRUE
;
103 /* The starting line for the output of the subprogram */
104 int output_start_y
= 0;
106 int ok_to_refresh
= 1;
108 /*** file scope macro definitions ****************************************************************/
110 /* The maximum number of views managed by the create_panel routine */
111 /* Must be at least two (for current and other). Please note that until */
112 /* Janne gets around this, we will only manage two of them :-) */
115 /* Width 12 for a wee Quick (Hex) View */
119 #define B_2LEFT B_USER
120 #define B_2RIGHT (B_USER + 1)
121 #define B_PLUS (B_USER + 2)
122 #define B_MINUS (B_USER + 3)
124 #define LAYOUT_OPTIONS_COUNT G_N_ELEMENTS (check_options)
126 /*** file scope type declarations ****************************************************************/
130 gboolean menubar_visible
;
131 gboolean command_prompt
;
132 gboolean keybar_visible
;
133 gboolean message_visible
;
134 gboolean xterm_title
;
139 /*** file scope variables ************************************************************************/
143 panel_view_mode_t type
;
145 char *last_saved_dir
; /* last view_list working directory */
146 } panels
[MAX_VIEWS
] =
149 /* init MAX_VIEWS items */
150 { view_listing
, NULL
, NULL
},
151 { view_listing
, NULL
, NULL
}
155 static layout_t old_layout
;
156 static panels_layout_t old_panels_layout
;
158 static gboolean equal_split
;
159 static int _output_lines
;
163 static WRadio
*radio_widget
;
173 { N_("&Equal split"), &equal_split
, NULL
},
174 { N_("&Menubar visible"), &menubar_visible
, NULL
},
175 { N_("Command &prompt"), &command_prompt
, NULL
},
176 { N_("&Keybar visible"), &mc_global
.keybar_visible
, NULL
},
177 { N_("H&intbar visible"), &mc_global
.message_visible
, NULL
},
178 { N_("&XTerm window title"), &xterm_title
, NULL
},
179 { N_("&Show free space"), &free_space
, NULL
}
183 static const char *output_lines_label
= NULL
;
184 static int output_lines_label_len
;
186 static WButton
*bleft_widget
, *bright_widget
;
188 /*** file scope functions ************************************************************************/
189 /* --------------------------------------------------------------------------------------------- */
191 /* don't use max() macro to avoid double call of str_term_width1() in widget width calculation */
197 return a
> b
? a
: b
;
200 /* --------------------------------------------------------------------------------------------- */
203 check_split (panels_layout_t
* layout
)
205 if (layout
->horizontal_split
)
207 if (layout
->horizontal_equal
)
208 layout
->top_panel_size
= height
/ 2;
209 else if (layout
->top_panel_size
< MINHEIGHT
)
210 layout
->top_panel_size
= MINHEIGHT
;
211 else if (layout
->top_panel_size
> height
- MINHEIGHT
)
212 layout
->top_panel_size
= height
- MINHEIGHT
;
216 int md_cols
= CONST_WIDGET (midnight_dlg
)->cols
;
218 if (layout
->vertical_equal
)
219 layout
->left_panel_size
= md_cols
/ 2;
220 else if (layout
->left_panel_size
< MINWIDTH
)
221 layout
->left_panel_size
= MINWIDTH
;
222 else if (layout
->left_panel_size
> md_cols
- MINWIDTH
)
223 layout
->left_panel_size
= md_cols
- MINWIDTH
;
227 /* --------------------------------------------------------------------------------------------- */
230 update_split (const WDialog
* h
)
232 /* Check split has to be done before testing if it changed, since
233 it can change due to calling check_split() as well */
234 check_split (&panels_layout
);
236 if (panels_layout
.horizontal_split
)
237 check_options
[0].widget
->state
= panels_layout
.horizontal_equal
;
239 check_options
[0].widget
->state
= panels_layout
.vertical_equal
;
240 widget_draw (WIDGET (check_options
[0].widget
));
242 tty_setcolor (check_options
[0].widget
->state
? DISABLED_COLOR
: COLOR_NORMAL
);
244 widget_gotoyx (h
, 6, 5);
245 if (panels_layout
.horizontal_split
)
246 tty_printf ("%03d", panels_layout
.top_panel_size
);
248 tty_printf ("%03d", panels_layout
.left_panel_size
);
250 widget_gotoyx (h
, 6, 17);
251 if (panels_layout
.horizontal_split
)
252 tty_printf ("%03d", height
- panels_layout
.top_panel_size
);
254 tty_printf ("%03d", CONST_WIDGET (midnight_dlg
)->cols
- panels_layout
.left_panel_size
);
256 widget_gotoyx (h
, 6, 12);
257 tty_print_char ('=');
260 /* --------------------------------------------------------------------------------------------- */
263 b_left_right_cback (WButton
* button
, int action
)
267 if (button
== bright_widget
)
269 if (panels_layout
.horizontal_split
)
270 panels_layout
.top_panel_size
++;
272 panels_layout
.left_panel_size
++;
276 if (panels_layout
.horizontal_split
)
277 panels_layout
.top_panel_size
--;
279 panels_layout
.left_panel_size
--;
282 update_split (DIALOG (WIDGET (button
)->owner
));
288 /* --------------------------------------------------------------------------------------------- */
291 bplus_cback (WButton
* button
, int action
)
296 if (_output_lines
< 99)
301 /* --------------------------------------------------------------------------------------------- */
304 bminus_cback (WButton
* button
, int action
)
309 if (_output_lines
> 0)
314 /* --------------------------------------------------------------------------------------------- */
317 layout_callback (Widget
* w
, Widget
* sender
, widget_msg_t msg
, int parm
, void *data
)
319 WDialog
*h
= DIALOG (w
);
324 /* When repainting the whole dialog (e.g. with C-l) we have to
326 dlg_default_repaint (h
);
328 old_layout
.output_lines
= -1;
332 if (old_layout
.output_lines
!= _output_lines
)
334 old_layout
.output_lines
= _output_lines
;
335 tty_setcolor (mc_global
.tty
.console_flag
!= '\0' ? COLOR_NORMAL
: DISABLED_COLOR
);
336 widget_gotoyx (h
, 9, 5);
337 tty_print_string (output_lines_label
);
338 widget_gotoyx (h
, 9, 5 + 3 + output_lines_label_len
);
339 tty_printf ("%02d", _output_lines
);
345 const Widget
*mw
= CONST_WIDGET (midnight_dlg
);
346 gboolean _menubar_visible
, _command_prompt
, _keybar_visible
, _message_visible
;
348 _menubar_visible
= check_options
[1].widget
->state
;
349 _command_prompt
= check_options
[2].widget
->state
;
350 _keybar_visible
= check_options
[3].widget
->state
;
351 _message_visible
= check_options
[4].widget
->state
;
353 if (mc_global
.tty
.console_flag
== '\0')
355 mw
->lines
- (_keybar_visible
? 1 : 0) - (_command_prompt
? 1 : 0) -
356 (_menubar_visible
? 1 : 0) - _output_lines
- (_message_visible
? 1 : 0);
361 if (_output_lines
< 0)
364 mw
->lines
- (_keybar_visible
? 1 : 0) - (_command_prompt
? 1 : 0) -
365 (_menubar_visible
? 1 : 0) - _output_lines
- (_message_visible
? 1 : 0);
366 minimum
= MINHEIGHT
* (1 + (panels_layout
.horizontal_split
? 1 : 0));
367 if (height
< minimum
)
369 _output_lines
-= minimum
- height
;
374 if (old_layout
.output_lines
!= _output_lines
)
376 old_layout
.output_lines
= _output_lines
;
377 tty_setcolor (mc_global
.tty
.console_flag
!= '\0' ? COLOR_NORMAL
: DISABLED_COLOR
);
378 widget_gotoyx (h
, 9, 5 + 3 + output_lines_label_len
);
379 tty_printf ("%02d", _output_lines
);
385 if (sender
== WIDGET (radio_widget
))
387 if ((panels_layout
.horizontal_split
? 1 : 0) == radio_widget
->sel
)
393 panels_layout
.horizontal_split
= radio_widget
->sel
!= 0;
395 if (panels_layout
.horizontal_split
)
397 eq
= panels_layout
.horizontal_equal
;
399 panels_layout
.top_panel_size
= height
/ 2;
403 eq
= panels_layout
.vertical_equal
;
405 panels_layout
.left_panel_size
= CONST_WIDGET (midnight_dlg
)->cols
/ 2;
408 widget_disable (WIDGET (bleft_widget
), eq
);
409 widget_disable (WIDGET (bright_widget
), eq
);
419 if (sender
== WIDGET (check_options
[0].widget
))
423 if (panels_layout
.horizontal_split
)
425 panels_layout
.horizontal_equal
= check_options
[0].widget
->state
;
426 eq
= panels_layout
.horizontal_equal
;
430 panels_layout
.vertical_equal
= check_options
[0].widget
->state
;
431 eq
= panels_layout
.vertical_equal
;
434 widget_disable (WIDGET (bleft_widget
), eq
);
435 widget_disable (WIDGET (bright_widget
), eq
);
447 if (sender
== WIDGET (check_options
[1].widget
))
448 menubar_visible
= check_options
[1].widget
->state
;
449 else if (sender
== WIDGET (check_options
[2].widget
))
450 command_prompt
= check_options
[2].widget
->state
;
451 else if (sender
== WIDGET (check_options
[3].widget
))
452 mc_global
.keybar_visible
= check_options
[3].widget
->state
;
453 else if (sender
== WIDGET (check_options
[4].widget
))
454 mc_global
.message_visible
= check_options
[4].widget
->state
;
455 else if (sender
== WIDGET (check_options
[5].widget
))
456 xterm_title
= check_options
[5].widget
->state
;
457 else if (sender
== WIDGET (check_options
[6].widget
))
458 free_space
= check_options
[6].widget
->state
;
471 return MSG_NOT_HANDLED
;
474 return dlg_default_callback (w
, sender
, msg
, parm
, data
);
478 /* --------------------------------------------------------------------------------------------- */
481 layout_dlg_create (void)
489 const char *title1
= N_("Panel split");
490 const char *title2
= N_("Console output");
491 const char *title3
= N_("Other options");
493 const char *s_split_direction
[2] = {
498 const char *ok_button
= N_("&OK");
499 const char *cancel_button
= N_("&Cancel");
501 output_lines_label
= _("Output lines:");
505 static gboolean i18n
= FALSE
;
511 i
= G_N_ELEMENTS (s_split_direction
);
513 s_split_direction
[i
] = _(s_split_direction
[i
]);
517 for (i
= 0; i
< (size_t) LAYOUT_OPTIONS_COUNT
; i
++)
518 check_options
[i
].text
= _(check_options
[i
].text
);
522 ok_button
= _(ok_button
);
523 cancel_button
= _(cancel_button
);
528 i
= G_N_ELEMENTS (s_split_direction
);
530 l1
= max (l1
, str_term_width1 (s_split_direction
[i
]) + 7);
532 for (i
= 0; i
< (size_t) LAYOUT_OPTIONS_COUNT
; i
++)
533 l1
= max (l1
, str_term_width1 (check_options
[i
].text
) + 7);
535 l1
= max (l1
, str_term_width1 (title1
) + 4);
536 l1
= max (l1
, str_term_width1 (title2
) + 4);
537 l1
= max (l1
, str_term_width1 (title3
) + 4);
538 /* label + "+"/"-" buttons */
539 output_lines_label_len
= str_term_width1 (output_lines_label
);
540 l1
= max (l1
, output_lines_label_len
+ 12);
542 b1
= str_term_width1 (ok_button
) + 5; /* default button */
543 b2
= str_term_width1 (cancel_button
) + 3;
546 width
= max (l1
* 2 + 7, b
);
549 dlg_create (TRUE
, 0, 0, 15, width
, WPOS_CENTER
, FALSE
, dialog_colors
, layout_callback
, NULL
,
550 "[Layout]", _("Layout"));
551 g
= GROUP (layout_dlg
);
553 #define XTRACT(i) (*check_options[i].variable != 0), check_options[i].text
555 /* "Panel split" groupbox */
556 group_add_widget (g
, groupbox_new (2, 3, 6, l1
, title1
));
558 radio_widget
= radio_new (3, 5, 2, s_split_direction
);
559 radio_widget
->sel
= panels_layout
.horizontal_split
? 1 : 0;
560 group_add_widget (g
, radio_widget
);
562 check_options
[0].widget
= check_new (5, 5, XTRACT (0));
563 group_add_widget (g
, check_options
[0].widget
);
565 equal_split
= panels_layout
.horizontal_split
?
566 panels_layout
.horizontal_equal
: panels_layout
.vertical_equal
;
568 bleft_widget
= button_new (6, 8, B_2LEFT
, NARROW_BUTTON
, "&<", b_left_right_cback
);
569 widget_disable (WIDGET (bleft_widget
), equal_split
);
570 group_add_widget (g
, bleft_widget
);
572 bright_widget
= button_new (6, 14, B_2RIGHT
, NARROW_BUTTON
, "&>", b_left_right_cback
);
573 widget_disable (WIDGET (bright_widget
), equal_split
);
574 group_add_widget (g
, bright_widget
);
576 /* "Console output" groupbox */
578 widget_state_t disabled
;
581 disabled
= mc_global
.tty
.console_flag
!= '\0' ? 0 : WST_DISABLED
;
583 w
= WIDGET (groupbox_new (8, 3, 3, l1
, title2
));
584 w
->state
|= disabled
;
585 group_add_widget (g
, w
);
587 w
= WIDGET (button_new (9, output_lines_label_len
+ 5, B_PLUS
,
588 NARROW_BUTTON
, "&+", bplus_cback
));
589 w
->state
|= disabled
;
590 group_add_widget (g
, w
);
592 w
= WIDGET (button_new (9, output_lines_label_len
+ 5 + 5, B_MINUS
,
593 NARROW_BUTTON
, "&-", bminus_cback
));
594 w
->state
|= disabled
;
595 group_add_widget (g
, w
);
598 /* "Other options" groupbox */
599 group_add_widget (g
, groupbox_new (2, 4 + l1
, 9, l1
, title3
));
601 for (i
= 1; i
< (size_t) LAYOUT_OPTIONS_COUNT
; i
++)
603 check_options
[i
].widget
= check_new (i
+ 2, 6 + l1
, XTRACT (i
));
604 group_add_widget (g
, check_options
[i
].widget
);
609 group_add_widget (g
, hline_new (11, -1, -1));
611 group_add_widget (g
, button_new (12, (width
- b
) / 2, B_ENTER
, DEFPUSH_BUTTON
, ok_button
, 0));
613 button_new (12, (width
- b
) / 2 + b1
+ 1, B_CANCEL
, NORMAL_BUTTON
,
616 widget_select (WIDGET (radio_widget
));
621 /* --------------------------------------------------------------------------------------------- */
624 panel_do_cols (int idx
)
626 if (get_panel_type (idx
) == view_listing
)
627 set_panel_formats (PANEL (panels
[idx
].widget
));
629 panel_update_cols (panels
[idx
].widget
, frame_half
);
632 /* --------------------------------------------------------------------------------------------- */
633 /** Save current list_view widget directory into panel */
636 restore_into_right_dir_panel (int idx
, gboolean last_was_panel
, int y
, int x
, int lines
, int cols
)
641 p_name
= get_nth_panel_name (idx
);
645 vfs_path_t
*saved_dir_vpath
;
647 saved_dir_vpath
= vfs_path_from_str (panels
[idx
].last_saved_dir
);
648 new_widget
= panel_sized_with_dir_new (p_name
, y
, x
, lines
, cols
, saved_dir_vpath
);
649 vfs_path_free (saved_dir_vpath
);
652 new_widget
= panel_sized_new (p_name
, y
, x
, lines
, cols
);
654 return WIDGET (new_widget
);
657 /* --------------------------------------------------------------------------------------------- */
662 old_layout
.menubar_visible
= menubar_visible
;
663 old_layout
.command_prompt
= command_prompt
;
664 old_layout
.keybar_visible
= mc_global
.keybar_visible
;
665 old_layout
.message_visible
= mc_global
.message_visible
;
666 old_layout
.xterm_title
= xterm_title
;
667 old_layout
.free_space
= free_space
;
668 old_layout
.output_lines
= -1;
670 _output_lines
= output_lines
;
672 old_panels_layout
= panels_layout
;
675 /* --------------------------------------------------------------------------------------------- */
678 layout_restore (void)
680 menubar_visible
= old_layout
.menubar_visible
;
681 command_prompt
= old_layout
.command_prompt
;
682 mc_global
.keybar_visible
= old_layout
.keybar_visible
;
683 mc_global
.message_visible
= old_layout
.message_visible
;
684 xterm_title
= old_layout
.xterm_title
;
685 free_space
= old_layout
.free_space
;
686 output_lines
= old_layout
.output_lines
;
688 panels_layout
= old_panels_layout
;
691 /* --------------------------------------------------------------------------------------------- */
692 /*** public functions ****************************************************************************/
693 /* --------------------------------------------------------------------------------------------- */
699 /* update the main menu, because perhaps there was a change in the way
700 how the panel are split (horizontal/vertical),
701 and a change of menu visibility. */
706 /* --------------------------------------------------------------------------------------------- */
715 layout_dlg
= layout_dlg_create ();
717 if (dlg_run (layout_dlg
) == B_ENTER
)
721 for (i
= 0; i
< (size_t) LAYOUT_OPTIONS_COUNT
; i
++)
722 if (check_options
[i
].widget
!= NULL
)
723 *check_options
[i
].variable
= check_options
[i
].widget
->state
;
725 output_lines
= _output_lines
;
730 dlg_destroy (layout_dlg
);
735 /* --------------------------------------------------------------------------------------------- */
738 panel_update_cols (Widget
* widget
, panel_display_t frame_size
)
740 const Widget
*mw
= CONST_WIDGET (midnight_dlg
);
743 /* don't touch panel if it is not in dialog yet */
744 /* if panel is not in dialog it is not in widgets list
745 and cannot be compared with get_panel_widget() result */
746 if (widget
->owner
== NULL
)
749 if (panels_layout
.horizontal_split
)
751 widget
->cols
= mw
->cols
;
755 if (frame_size
== frame_full
)
760 else if (widget
== get_panel_widget (0))
762 cols
= panels_layout
.left_panel_size
;
767 cols
= mw
->cols
- panels_layout
.left_panel_size
;
768 x
= mw
->x
+ panels_layout
.left_panel_size
;
775 /* --------------------------------------------------------------------------------------------- */
780 /* File manager screen layout:
782 * +---------------------------------------------------------------+
784 * +-------------------------------+-------------------------------+
789 * | Left panel | Right panel |
794 * +-------------------------------+-------------------------------+
795 * | Hint (message) bar |
796 * +---------------------------------------------------------------+
798 * | Console content |
800 * +--------+------------------------------------------------------+
801 * | Prompt | Command line |
802 * | Key (button) bar |
803 * +--------+------------------------------------------------------+
806 const Widget
*mw
= CONST_WIDGET (midnight_dlg
);
809 /* iniitial height of panels */
811 mw
->lines
- (menubar_visible
? 1 : 0) - (mc_global
.message_visible
? 1 : 0) -
812 (command_prompt
? 1 : 0) - (mc_global
.keybar_visible
? 1 : 0);
814 if (mc_global
.tty
.console_flag
!= '\0')
818 if (output_lines
< 0)
821 height
-= output_lines
;
822 minimum
= MINHEIGHT
* (1 + (panels_layout
.horizontal_split
? 1 : 0));
823 if (height
< minimum
)
825 output_lines
-= minimum
- height
;
830 widget_set_size (WIDGET (the_menubar
), mw
->y
, mw
->x
, 1, mw
->cols
);
831 menubar_set_visible (the_menubar
, menubar_visible
);
833 check_split (&panels_layout
);
834 start_y
= mw
->y
+ (menubar_visible
? 1 : 0);
836 /* update columns first... */
840 /* ...then rows and origin */
841 if (panels_layout
.horizontal_split
)
843 widget_set_size (panels
[0].widget
, start_y
, mw
->x
, panels_layout
.top_panel_size
,
844 panels
[0].widget
->cols
);
845 widget_set_size (panels
[1].widget
, start_y
+ panels_layout
.top_panel_size
, mw
->x
,
846 height
- panels_layout
.top_panel_size
, panels
[1].widget
->cols
);
850 widget_set_size (panels
[0].widget
, start_y
, mw
->x
, height
, panels
[0].widget
->cols
);
851 widget_set_size (panels
[1].widget
, start_y
, panels
[1].widget
->x
, height
,
852 panels
[1].widget
->cols
);
855 if (mc_global
.message_visible
)
856 widget_set_size (WIDGET (the_hint
), height
+ start_y
, mw
->x
, 1, mw
->cols
);
859 widget_set_size (WIDGET (the_hint
), 0, 0, 0, 0);
862 if (mc_global
.tty
.console_flag
!= '\0' && output_lines
!= 0)
864 unsigned char end_line
;
866 end_line
= mw
->lines
- (mc_global
.keybar_visible
? 1 : 0) - 1;
867 output_start_y
= end_line
- (command_prompt
? 1 : 0) - output_lines
+ 1;
868 show_console_contents (output_start_y
, end_line
- output_lines
, end_line
);
873 #ifdef ENABLE_SUBSHELL
874 if (!mc_global
.tty
.use_subshell
|| !do_load_prompt ())
881 widget_set_size (WIDGET (cmdline
), 0, 0, 0, 0);
882 widget_set_size (WIDGET (the_prompt
), mw
->lines
, mw
->cols
, 0, 0);
885 widget_set_size (WIDGET (the_bar
), mw
->lines
- 1, mw
->x
, mc_global
.keybar_visible
? 1 : 0,
887 buttonbar_set_visible (the_bar
, mc_global
.keybar_visible
);
889 update_xterm_title_path ();
892 /* --------------------------------------------------------------------------------------------- */
895 panels_split_equal (void)
897 if (panels_layout
.horizontal_split
)
898 panels_layout
.horizontal_equal
= TRUE
;
900 panels_layout
.vertical_equal
= TRUE
;
906 /* --------------------------------------------------------------------------------------------- */
909 panels_split_more (void)
911 if (panels_layout
.horizontal_split
)
913 panels_layout
.horizontal_equal
= FALSE
;
914 panels_layout
.top_panel_size
++;
918 panels_layout
.vertical_equal
= FALSE
;
919 panels_layout
.left_panel_size
++;
925 /* --------------------------------------------------------------------------------------------- */
928 panels_split_less (void)
930 if (panels_layout
.horizontal_split
)
932 panels_layout
.horizontal_equal
= FALSE
;
933 panels_layout
.top_panel_size
--;
937 panels_layout
.vertical_equal
= FALSE
;
938 panels_layout
.left_panel_size
--;
944 /* --------------------------------------------------------------------------------------------- */
950 const Widget
*mw
= CONST_WIDGET (midnight_dlg
);
953 char *tmp_prompt
= (char *) mc_prompt
;
955 #ifdef ENABLE_SUBSHELL
956 if (mc_global
.tty
.use_subshell
)
958 tmp_prompt
= g_string_free (subshell_prompt
, FALSE
);
959 (void) strip_ctrl_codes (tmp_prompt
);
963 prompt_width
= str_term_width1 (tmp_prompt
);
965 /* Check for prompts too big */
966 if (mw
->cols
> 8 && prompt_width
> mw
->cols
- 8)
970 prompt_width
= mw
->cols
- 8;
971 prompt_len
= str_offset_to_pos (tmp_prompt
, prompt_width
);
972 tmp_prompt
[prompt_len
] = '\0';
975 #ifdef ENABLE_SUBSHELL
976 if (mc_global
.tty
.use_subshell
)
978 subshell_prompt
= g_string_new (tmp_prompt
);
980 mc_prompt
= subshell_prompt
->str
;
984 y
= mw
->lines
- 1 - (mc_global
.keybar_visible
? 1 : 0);
986 widget_set_size (WIDGET (the_prompt
), y
, mw
->x
, 1, prompt_width
);
987 label_set_text (the_prompt
, mc_prompt
);
988 widget_set_size (WIDGET (cmdline
), y
, mw
->x
+ prompt_width
, 1, mw
->cols
- prompt_width
);
991 /* --------------------------------------------------------------------------------------------- */
994 use_dash (gboolean flag
)
1002 /* --------------------------------------------------------------------------------------------- */
1005 set_hintbar (const char *str
)
1007 label_set_text (the_hint
, str
);
1008 if (ok_to_refresh
> 0)
1012 /* --------------------------------------------------------------------------------------------- */
1015 rotate_dash (gboolean show
)
1017 static guint64 timestamp
= 0;
1018 /* update with 10 FPS rate */
1019 static const guint64 delay
= G_USEC_PER_SEC
/ 10;
1021 const Widget
*w
= CONST_WIDGET (midnight_dlg
);
1023 if (!nice_rotating_dash
|| (ok_to_refresh
<= 0))
1026 if (show
&& !mc_time_elapsed (×tamp
, delay
))
1029 widget_gotoyx (w
, menubar_visible
!= 0 ? 1 : 0, w
->cols
- 1);
1030 tty_setcolor (NORMAL_COLOR
);
1033 tty_print_alt_char (ACS_URCORNER
, FALSE
);
1036 static const char rotating_dash
[4] = "|/-\\";
1037 static size_t pos
= 0;
1039 tty_print_char (rotating_dash
[pos
]);
1040 pos
= (pos
+ 1) % sizeof (rotating_dash
);
1046 /* --------------------------------------------------------------------------------------------- */
1049 get_nth_panel_name (int num
)
1052 return "New Left Panel";
1055 return "New Right Panel";
1058 static char buffer
[BUF_SMALL
];
1060 g_snprintf (buffer
, sizeof (buffer
), "%ith Panel", num
);
1065 /* --------------------------------------------------------------------------------------------- */
1066 /* I wonder if I should start to use the folding mode than Dugan uses */
1068 /* This is the centralized managing of the panel display types */
1069 /* This routine takes care of destroying and creating new widgets */
1070 /* Please note that it could manage MAX_VIEWS, not just left and right */
1071 /* Currently nothing in the code takes advantage of this and has hard- */
1072 /* coded values for two panels only */
1074 /* Set the num-th panel to the view type: type */
1075 /* This routine also keeps at least one WPanel object in the screen */
1076 /* since a lot of routines depend on the current_panel variable */
1079 create_panel (int num
, panel_view_mode_t type
)
1081 int x
= 0, y
= 0, cols
= 0, lines
= 0;
1082 unsigned int the_other
= 0; /* Index to the other panel */
1083 const char *file_name
= NULL
; /* For Quick view */
1084 Widget
*new_widget
= NULL
, *old_widget
= NULL
;
1085 panel_view_mode_t old_type
= view_listing
;
1086 WPanel
*the_other_panel
= NULL
;
1088 if (num
>= MAX_VIEWS
)
1090 fprintf (stderr
, "Cannot allocate more that %d views\n", MAX_VIEWS
);
1093 /* Check that we will have a WPanel * at least */
1094 if (type
!= view_listing
)
1096 the_other
= num
== 0 ? 1 : 0;
1098 if (panels
[the_other
].type
!= view_listing
)
1103 if (panels
[num
].widget
!= NULL
)
1105 Widget
*w
= panels
[num
].widget
;
1106 WPanel
*panel
= PANEL (w
);
1113 old_type
= panels
[num
].type
;
1115 if (old_type
== view_listing
&& panel
->frame_size
== frame_full
&& type
!= view_listing
)
1117 int md_cols
= CONST_WIDGET (midnight_dlg
)->cols
;
1119 if (panels_layout
.horizontal_split
)
1126 cols
= md_cols
- panels_layout
.left_panel_size
;
1128 x
= panels_layout
.left_panel_size
;
1133 /* Restoring saved path from panels.ini for nonlist panel */
1134 /* when it's first creation (for example view_info) */
1135 if (old_widget
== NULL
&& type
!= view_listing
)
1136 panels
[num
].last_saved_dir
= _vfs_get_cwd ();
1143 gboolean last_was_panel
;
1145 last_was_panel
= old_widget
!= NULL
&& get_panel_type (num
) != view_listing
;
1146 new_widget
= restore_into_right_dir_panel (num
, last_was_panel
, y
, x
, lines
, cols
);
1151 new_widget
= WIDGET (info_new (y
, x
, lines
, cols
));
1155 new_widget
= WIDGET (tree_new (y
, x
, lines
, cols
, TRUE
));
1159 new_widget
= WIDGET (mcview_new (y
, x
, lines
, cols
, TRUE
));
1160 the_other_panel
= PANEL (panels
[the_other
].widget
);
1161 if (the_other_panel
!= NULL
)
1162 file_name
= the_other_panel
->dir
.list
[the_other_panel
->selected
].fname
;
1166 mcview_load ((WView
*) new_widget
, 0, file_name
, 0, 0, 0);
1173 if (type
!= view_listing
)
1174 /* Must save dir, for restoring after change type to */
1176 save_panel_dir (num
);
1178 panels
[num
].type
= type
;
1179 panels
[num
].widget
= new_widget
;
1181 /* We use replace to keep the circular list of the dialog in the */
1182 /* same state. Maybe we could just kill it and then replace it */
1183 if ((midnight_dlg
!= NULL
) && (old_widget
!= NULL
))
1185 if (old_type
== view_listing
)
1187 /* save and write directory history of panel
1188 * ... and other histories of midnight_dlg */
1189 dlg_save_history (midnight_dlg
);
1192 widget_replace (old_widget
, new_widget
);
1195 if (type
== view_listing
)
1197 WPanel
*panel
= PANEL (new_widget
);
1199 /* if existing panel changed type to view_listing, then load history */
1200 if (old_widget
!= NULL
)
1202 ev_history_load_save_t event_data
= { NULL
, new_widget
};
1204 mc_event_raise (midnight_dlg
->event_group
, MCEVENT_HISTORY_LOAD
, &event_data
);
1210 right_panel
= panel
;
1212 /* forced update format after set new sizes */
1213 set_panel_formats (panel
);
1216 if (type
== view_tree
)
1217 the_tree
= (WTree
*) new_widget
;
1219 /* Prevent current_panel's value from becoming invalid.
1220 * It's just a quick hack to prevent segfaults. Comment out and
1222 * - select left panel
1223 * - invoke menue left/tree
1224 * - as long as you stay in the left panel almost everything that uses
1225 * current_panel causes segfault, e.g. C-Enter, C-x c, ...
1227 if ((type
!= view_listing
) && (current_panel
== PANEL (old_widget
)))
1228 current_panel
= num
== 0 ? right_panel
: left_panel
;
1230 g_free (old_widget
);
1233 /* --------------------------------------------------------------------------------------------- */
1234 /** This routine is deeply sticked to the two panels idea.
1235 What should it do in more panels. ANSWER - don't use it
1236 in any multiple panels environment. */
1241 WPanel
*panel1
, *panel2
;
1244 panel1
= PANEL (panels
[0].widget
);
1245 panel2
= PANEL (panels
[1].widget
);
1247 if (panels
[0].type
== view_listing
&& panels
[1].type
== view_listing
&&
1248 !mc_config_get_bool (mc_global
.main_config
, CONFIG_PANELS_SECTION
, "simple_swap", FALSE
))
1252 #define panelswap(x) panel.x = panel1->x; panel1->x = panel2->x; panel2->x = panel.x;
1253 /* Change content and related stuff */
1256 panelswap (cwd_vpath
);
1257 panelswap (lwd_vpath
);
1259 panelswap (dirs_marked
);
1261 panelswap (top_file
);
1262 panelswap (selected
);
1263 panelswap (is_panelized
);
1264 panelswap (dir_stat
);
1267 panel1
->searching
= FALSE
;
1268 panel2
->searching
= FALSE
;
1270 if (current_panel
== panel1
)
1271 current_panel
= panel2
;
1273 current_panel
= panel1
;
1275 /* if sort options are different -> resort panels */
1276 if (memcmp (&panel1
->sort_info
, &panel2
->sort_info
, sizeof (dir_sort_options_t
)) != 0)
1278 panel_re_sort (other_panel
);
1279 panel_re_sort (current_panel
);
1282 if (widget_is_active (panels
[0].widget
))
1283 widget_select (panels
[1].widget
);
1284 else if (widget_is_active (panels
[1].widget
))
1285 widget_select (panels
[0].widget
);
1290 int x
, y
, cols
, lines
;
1293 tmp_panel
= right_panel
;
1294 right_panel
= left_panel
;
1295 left_panel
= tmp_panel
;
1297 if (panels
[0].type
== view_listing
)
1299 if (strcmp (panel1
->panel_name
, get_nth_panel_name (0)) == 0)
1301 g_free (panel1
->panel_name
);
1302 panel1
->panel_name
= g_strdup (get_nth_panel_name (1));
1305 if (panels
[1].type
== view_listing
)
1307 if (strcmp (panel2
->panel_name
, get_nth_panel_name (1)) == 0)
1309 g_free (panel2
->panel_name
);
1310 panel2
->panel_name
= g_strdup (get_nth_panel_name (0));
1314 x
= panels
[0].widget
->x
;
1315 y
= panels
[0].widget
->y
;
1316 cols
= panels
[0].widget
->cols
;
1317 lines
= panels
[0].widget
->lines
;
1319 panels
[0].widget
->x
= panels
[1].widget
->x
;
1320 panels
[0].widget
->y
= panels
[1].widget
->y
;
1321 panels
[0].widget
->cols
= panels
[1].widget
->cols
;
1322 panels
[0].widget
->lines
= panels
[1].widget
->lines
;
1324 panels
[1].widget
->x
= x
;
1325 panels
[1].widget
->y
= y
;
1326 panels
[1].widget
->cols
= cols
;
1327 panels
[1].widget
->lines
= lines
;
1329 tmp_widget
= panels
[0].widget
;
1330 panels
[0].widget
= panels
[1].widget
;
1331 panels
[1].widget
= tmp_widget
;
1332 tmp_type
= panels
[0].type
;
1333 panels
[0].type
= panels
[1].type
;
1334 panels
[1].type
= tmp_type
;
1336 /* force update formats because of possible changed sizes */
1337 if (panels
[0].type
== view_listing
)
1338 set_panel_formats (PANEL (panels
[0].widget
));
1339 if (panels
[1].type
== view_listing
)
1340 set_panel_formats (PANEL (panels
[1].widget
));
1344 /* --------------------------------------------------------------------------------------------- */
1347 get_panel_type (int idx
)
1349 return panels
[idx
].type
;
1352 /* --------------------------------------------------------------------------------------------- */
1355 get_panel_widget (int idx
)
1357 return panels
[idx
].widget
;
1360 /* --------------------------------------------------------------------------------------------- */
1363 get_current_index (void)
1365 return (panels
[0].widget
== WIDGET (current_panel
) ? 0 : 1);
1368 /* --------------------------------------------------------------------------------------------- */
1371 get_other_index (void)
1373 return (get_current_index () == 0 ? 1 : 0);
1376 /* --------------------------------------------------------------------------------------------- */
1379 get_other_panel (void)
1381 return PANEL (get_panel_widget (get_other_index ()));
1384 /* --------------------------------------------------------------------------------------------- */
1385 /** Returns the view type for the current panel/view */
1388 get_current_type (void)
1390 return (panels
[0].widget
== WIDGET (current_panel
) ? panels
[0].type
: panels
[1].type
);
1393 /* --------------------------------------------------------------------------------------------- */
1394 /** Returns the view type of the unselected panel */
1397 get_other_type (void)
1399 return (panels
[0].widget
== WIDGET (current_panel
) ? panels
[1].type
: panels
[0].type
);
1402 /* --------------------------------------------------------------------------------------------- */
1403 /** Save current list_view widget directory into panel */
1406 save_panel_dir (int idx
)
1408 panel_view_mode_t type
;
1410 type
= get_panel_type (idx
);
1411 if (type
== view_listing
)
1415 p
= PANEL (get_panel_widget (idx
));
1418 g_free (panels
[idx
].last_saved_dir
); /* last path no needed */
1419 /* Because path can be nonlocal */
1420 panels
[idx
].last_saved_dir
= g_strdup (vfs_path_as_str (p
->cwd_vpath
));
1425 /* --------------------------------------------------------------------------------------------- */
1426 /** Return working dir, if it's view_listing - cwd,
1427 but for other types - last_saved_dir */
1430 get_panel_dir_for (const WPanel
* widget
)
1434 for (i
= 0; i
< MAX_VIEWS
; i
++)
1435 if (PANEL (get_panel_widget (i
)) == widget
)
1439 return g_strdup (".");
1441 if (get_panel_type (i
) == view_listing
)
1443 vfs_path_t
*cwd_vpath
;
1445 cwd_vpath
= PANEL (get_panel_widget (i
))->cwd_vpath
;
1446 return g_strdup (vfs_path_as_str (cwd_vpath
));
1449 return g_strdup (panels
[i
].last_saved_dir
);
1452 /* --------------------------------------------------------------------------------------------- */
1454 #ifdef ENABLE_SUBSHELL
1456 do_load_prompt (void)
1458 gboolean ret
= FALSE
;
1460 if (!read_subshell_prompt ())
1463 /* Don't actually change the prompt if it's invisible */
1464 if (top_dlg
!= NULL
&& DIALOG (top_dlg
->data
) == midnight_dlg
&& command_prompt
)
1468 /* since the prompt has changed, and we are called from one of the
1469 * tty_get_event channels, the prompt updating does not take place
1470 * automatically: force a cursor update and a screen refresh
1472 update_cursor (midnight_dlg
);
1476 update_subshell_prompt
= TRUE
;
1480 /* --------------------------------------------------------------------------------------------- */
1483 load_prompt (int fd
, void *unused
)
1491 #endif /* ENABLE_SUBSHELL */
1493 /* --------------------------------------------------------------------------------------------- */
1496 title_path_prepare (char **path
, char **login
)
1498 char host
[BUF_TINY
];
1499 struct passwd
*pw
= NULL
;
1503 vfs_path_to_str_flags (current_panel
->cwd_vpath
, 0, VPF_STRIP_HOME
| VPF_STRIP_PASSWORD
);
1505 res
= gethostname (host
, sizeof (host
));
1509 host
[sizeof (host
) - 1] = '\0';
1511 pw
= getpwuid (getuid ());
1513 *login
= g_strdup_printf ("%s@%s", pw
->pw_name
, host
);
1515 *login
= g_strdup (host
);
1518 /* --------------------------------------------------------------------------------------------- */
1520 /** Show current directory in the xterm title */
1522 update_xterm_title_path (void)
1524 if (mc_global
.tty
.xterm_flag
&& xterm_title
)
1530 title_path_prepare (&path
, &login
);
1532 p
= g_strdup_printf ("mc [%s]:%s", login
, path
);
1536 fprintf (stdout
, "\33]0;%s\7", str_term_form (p
));
1539 if (!mc_global
.tty
.alternate_plus_minus
)
1540 numeric_keypad_mode ();
1541 (void) fflush (stdout
);
1545 /* --------------------------------------------------------------------------------------------- */