layout.c 38 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289
  1. /*
  2. Panel layout module for the Midnight Commander
  3. Copyright (C) 1995, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
  4. 2006, 2007, 2009, 2011
  5. The Free Software Foundation, Inc.
  6. Written by:
  7. Janne Kukonlehto, 1995
  8. Miguel de Icaza, 1995
  9. This file is part of the Midnight Commander.
  10. The Midnight Commander is free software: you can redistribute it
  11. and/or modify it under the terms of the GNU General Public License as
  12. published by the Free Software Foundation, either version 3 of the License,
  13. or (at your option) any later version.
  14. The Midnight Commander is distributed in the hope that it will be useful,
  15. but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. GNU General Public License for more details.
  18. You should have received a copy of the GNU General Public License
  19. along with this program. If not, see <http://www.gnu.org/licenses/>.
  20. */
  21. /** \file layout.c
  22. * \brief Source: panel layout module
  23. */
  24. #include <config.h>
  25. #include <stdlib.h>
  26. #include <stdio.h>
  27. #include <string.h>
  28. #include <sys/types.h>
  29. #include <unistd.h>
  30. #include "lib/global.h"
  31. #include "lib/tty/tty.h"
  32. #include "lib/skin.h"
  33. #include "lib/tty/key.h"
  34. #include "lib/tty/mouse.h"
  35. #include "lib/mcconfig.h"
  36. #include "lib/vfs/vfs.h" /* For _vfs_get_cwd () */
  37. #include "lib/strutil.h"
  38. #include "lib/widget.h"
  39. #include "lib/event.h"
  40. #include "src/consaver/cons.saver.h"
  41. #include "src/viewer/mcviewer.h" /* The view widget */
  42. #include "src/setup.h"
  43. #ifdef HAVE_SUBSHELL_SUPPORT
  44. #include "src/main.h" /* do_load_prompt() */
  45. #include "src/subshell.h"
  46. #endif
  47. #include "command.h"
  48. #include "midnight.h"
  49. #include "tree.h"
  50. /* Needed for the extern declarations of integer parameters */
  51. #include "dir.h"
  52. #include "layout.h"
  53. #include "info.h" /* The Info widget */
  54. /*** global variables ****************************************************************************/
  55. panels_layout_t panels_layout = {
  56. /* Set if the panels are split horizontally */
  57. .horizontal_split = 0,
  58. /* vertical split */
  59. .vertical_equal = 1,
  60. .left_panel_size = 0,
  61. /* horizontal split */
  62. .horizontal_equal = 1,
  63. .top_panel_size = 0
  64. };
  65. /* Controls the display of the rotating dash on the verbose mode */
  66. int nice_rotating_dash = 1;
  67. /* The number of output lines shown (if available) */
  68. int output_lines = 0;
  69. /* Set if the command prompt is to be displayed */
  70. gboolean command_prompt = TRUE;
  71. /* Set if the main menu is visible */
  72. int menubar_visible = 1;
  73. /* Set to show current working dir in xterm window title */
  74. gboolean xterm_title = TRUE;
  75. /* Set to show free space on device assigned to current directory */
  76. int free_space = 1;
  77. /* The starting line for the output of the subprogram */
  78. int output_start_y = 0;
  79. int ok_to_refresh = 1;
  80. /*** file scope macro definitions ****************************************************************/
  81. /* The maximum number of views managed by the set_display_type routine */
  82. /* Must be at least two (for current and other). Please note that until */
  83. /* Janne gets around this, we will only manage two of them :-) */
  84. #define MAX_VIEWS 2
  85. /* Width 12 for a wee Quick (Hex) View */
  86. #define MINWIDTH 12
  87. #define MINHEIGHT 5
  88. #define B_2LEFT B_USER
  89. #define B_2RIGHT (B_USER + 1)
  90. #define B_PLUS (B_USER + 2)
  91. #define B_MINUS (B_USER + 3)
  92. #define LAYOUT_OPTIONS_COUNT G_N_ELEMENTS (check_options)
  93. #define OTHER_OPTIONS_COUNT (LAYOUT_OPTIONS_COUNT - 1)
  94. /*** file scope type declarations ****************************************************************/
  95. /*** file scope variables ************************************************************************/
  96. static struct
  97. {
  98. panel_view_mode_t type;
  99. Widget *widget;
  100. char *last_saved_dir; /* last view_list working directory */
  101. } panels[MAX_VIEWS] =
  102. {
  103. /* *INDENT-OFF* */
  104. /* init MAX_VIEWS items */
  105. { view_listing, NULL, NULL},
  106. { view_listing, NULL, NULL}
  107. /* *INDENT-ON* */
  108. };
  109. /* These variables are used to avoid updating the information unless */
  110. /* we need it */
  111. static panels_layout_t old_layout;
  112. static int old_output_lines;
  113. /* Internal variables */
  114. panels_layout_t _panels_layout;
  115. static int equal_split;
  116. static int _menubar_visible;
  117. static int _output_lines;
  118. static gboolean _command_prompt;
  119. static int _keybar_visible;
  120. static int _message_visible;
  121. static gboolean _xterm_title;
  122. static int _free_space;
  123. static int height;
  124. static WRadio *radio_widget;
  125. static struct
  126. {
  127. const char *text;
  128. int *variable;
  129. WCheck *widget;
  130. } check_options[] =
  131. {
  132. /* *INDENT-OFF* */
  133. { N_("Show free sp&ace"), &free_space, NULL},
  134. { N_("&XTerm window title"), &xterm_title, NULL},
  135. { N_("H&intbar visible"), &mc_global.message_visible, NULL},
  136. { N_("&Keybar visible"), &mc_global.keybar_visible, NULL},
  137. { N_("Command &prompt"), &command_prompt, NULL},
  138. { N_("Menu&bar visible"), &menubar_visible, NULL},
  139. { N_("&Equal split"), &equal_split, NULL}
  140. /* *INDENT-ON* */
  141. };
  142. static const char *output_lines_label = NULL;
  143. static int output_lines_label_len;
  144. static WButton *bleft_widget, *bright_widget;
  145. /*** file scope functions ************************************************************************/
  146. /* --------------------------------------------------------------------------------------------- */
  147. /* don't use max() macro to avoid double call of str_term_width1() in widget width calculation */
  148. #undef max
  149. static int
  150. max (int a, int b)
  151. {
  152. return a > b ? a : b;
  153. }
  154. /* --------------------------------------------------------------------------------------------- */
  155. static void
  156. check_split (panels_layout_t * layout)
  157. {
  158. if (layout->horizontal_split)
  159. {
  160. if (layout->horizontal_equal)
  161. layout->top_panel_size = height / 2;
  162. else if (layout->top_panel_size < MINHEIGHT)
  163. layout->top_panel_size = MINHEIGHT;
  164. else if (layout->top_panel_size > height - MINHEIGHT)
  165. layout->top_panel_size = height - MINHEIGHT;
  166. }
  167. else
  168. {
  169. if (layout->vertical_equal)
  170. layout->left_panel_size = COLS / 2;
  171. else if (layout->left_panel_size < MINWIDTH)
  172. layout->left_panel_size = MINWIDTH;
  173. else if (layout->left_panel_size > COLS - MINWIDTH)
  174. layout->left_panel_size = COLS - MINWIDTH;
  175. }
  176. }
  177. /* --------------------------------------------------------------------------------------------- */
  178. static void
  179. update_split (const Dlg_head * h)
  180. {
  181. /* Check split has to be done before testing if it changed, since
  182. it can change due to calling check_split() as well */
  183. check_split (&_panels_layout);
  184. old_layout = _panels_layout;
  185. if (_panels_layout.horizontal_split)
  186. check_options[6].widget->state = _panels_layout.horizontal_equal ? 1 : 0;
  187. else
  188. check_options[6].widget->state = _panels_layout.vertical_equal ? 1 : 0;
  189. send_message ((Widget *) check_options[6].widget, WIDGET_DRAW, 0);
  190. tty_setcolor (check_options[6].widget->state & C_BOOL ? DISABLED_COLOR : COLOR_NORMAL);
  191. dlg_move (h, 6, 5);
  192. if (_panels_layout.horizontal_split)
  193. tty_printf ("%03d", _panels_layout.top_panel_size);
  194. else
  195. tty_printf ("%03d", _panels_layout.left_panel_size);
  196. dlg_move (h, 6, 17);
  197. if (_panels_layout.horizontal_split)
  198. tty_printf ("%03d", height - _panels_layout.top_panel_size);
  199. else
  200. tty_printf ("%03d", COLS - _panels_layout.left_panel_size);
  201. dlg_move (h, 6, 12);
  202. tty_print_char ('=');
  203. }
  204. /* --------------------------------------------------------------------------------------------- */
  205. static int
  206. b_left_right_cback (WButton * button, int action)
  207. {
  208. (void) action;
  209. if (button == bleft_widget)
  210. {
  211. if (_panels_layout.horizontal_split)
  212. _panels_layout.top_panel_size++;
  213. else
  214. _panels_layout.left_panel_size++;
  215. }
  216. else
  217. {
  218. if (_panels_layout.horizontal_split)
  219. _panels_layout.top_panel_size--;
  220. else
  221. _panels_layout.left_panel_size--;
  222. }
  223. update_split (button->widget.owner);
  224. return 0;
  225. }
  226. /* --------------------------------------------------------------------------------------------- */
  227. static int
  228. bplus_cback (WButton * button, int action)
  229. {
  230. (void) button;
  231. (void) action;
  232. if (_output_lines < 99)
  233. _output_lines++;
  234. return 0;
  235. }
  236. /* --------------------------------------------------------------------------------------------- */
  237. static int
  238. bminus_cback (WButton * button, int action)
  239. {
  240. (void) button;
  241. (void) action;
  242. if (_output_lines > 0)
  243. _output_lines--;
  244. return 0;
  245. }
  246. /* --------------------------------------------------------------------------------------------- */
  247. static cb_ret_t
  248. layout_callback (Dlg_head * h, Widget * sender, dlg_msg_t msg, int parm, void *data)
  249. {
  250. switch (msg)
  251. {
  252. case DLG_DRAW:
  253. /* When repainting the whole dialog (e.g. with C-l) we have to
  254. update everything */
  255. common_dialog_repaint (h);
  256. old_layout.horizontal_split = -1;
  257. old_layout.left_panel_size = -1;
  258. old_layout.top_panel_size = -1;
  259. old_output_lines = -1;
  260. update_split (h);
  261. if (old_output_lines != _output_lines)
  262. {
  263. old_output_lines = _output_lines;
  264. tty_setcolor (mc_global.tty.console_flag != '\0' ? COLOR_NORMAL : DISABLED_COLOR);
  265. dlg_move (h, 9, 5);
  266. tty_print_string (output_lines_label);
  267. dlg_move (h, 9, 5 + 3 + output_lines_label_len);
  268. tty_printf ("%02d", _output_lines);
  269. }
  270. return MSG_HANDLED;
  271. case DLG_POST_KEY:
  272. _menubar_visible = check_options[5].widget->state & C_BOOL;
  273. _command_prompt = (check_options[4].widget->state & C_BOOL) != 0;
  274. _keybar_visible = check_options[3].widget->state & C_BOOL;
  275. _message_visible = check_options[2].widget->state & C_BOOL;
  276. _xterm_title = (check_options[1].widget->state & C_BOOL) != 0;
  277. _free_space = check_options[0].widget->state & C_BOOL;
  278. if (mc_global.tty.console_flag != '\0')
  279. {
  280. int minimum;
  281. if (_output_lines < 0)
  282. _output_lines = 0;
  283. height = LINES - _keybar_visible - (_command_prompt ? 1 : 0) -
  284. _menubar_visible - _output_lines - _message_visible;
  285. minimum = MINHEIGHT * (1 + _panels_layout.horizontal_split);
  286. if (height < minimum)
  287. {
  288. _output_lines -= minimum - height;
  289. height = minimum;
  290. }
  291. }
  292. else
  293. height = LINES - _keybar_visible - (_command_prompt ? 1 : 0) -
  294. _menubar_visible - _output_lines - _message_visible;
  295. if (old_output_lines != _output_lines)
  296. {
  297. old_output_lines = _output_lines;
  298. tty_setcolor (mc_global.tty.console_flag != '\0' ? COLOR_NORMAL : DISABLED_COLOR);
  299. dlg_move (h, 9, 5 + 3 + output_lines_label_len);
  300. tty_printf ("%02d", _output_lines);
  301. }
  302. return MSG_HANDLED;
  303. case DLG_ACTION:
  304. if (sender == (Widget *) radio_widget)
  305. {
  306. if (_panels_layout.horizontal_split != radio_widget->sel)
  307. {
  308. _panels_layout.horizontal_split = radio_widget->sel;
  309. if (_panels_layout.horizontal_split)
  310. {
  311. if (_panels_layout.horizontal_equal)
  312. _panels_layout.top_panel_size = height / 2;
  313. }
  314. else
  315. {
  316. if (_panels_layout.vertical_equal)
  317. _panels_layout.left_panel_size = COLS / 2;
  318. }
  319. }
  320. update_split (h);
  321. return MSG_HANDLED;
  322. }
  323. if (sender == (Widget *) check_options[6].widget)
  324. {
  325. int eq;
  326. if (_panels_layout.horizontal_split)
  327. {
  328. _panels_layout.horizontal_equal = check_options[6].widget->state & C_BOOL;
  329. eq = _panels_layout.horizontal_equal;
  330. }
  331. else
  332. {
  333. _panels_layout.vertical_equal = check_options[6].widget->state & C_BOOL;
  334. eq = _panels_layout.vertical_equal;
  335. }
  336. widget_disable (bleft_widget->widget, eq);
  337. send_message ((Widget *) bleft_widget, WIDGET_DRAW, 0);
  338. widget_disable (bright_widget->widget, eq);
  339. send_message ((Widget *) bright_widget, WIDGET_DRAW, 0);
  340. update_split (h);
  341. return MSG_HANDLED;
  342. }
  343. return MSG_NOT_HANDLED;
  344. default:
  345. return default_dlg_callback (h, sender, msg, parm, data);
  346. }
  347. }
  348. /* --------------------------------------------------------------------------------------------- */
  349. static Dlg_head *
  350. init_layout (void)
  351. {
  352. Dlg_head *layout_dlg;
  353. int l1 = 0, width;
  354. int b1, b2, b;
  355. size_t i;
  356. const char *title1 = N_("Panel split");
  357. const char *title2 = N_("Console output");
  358. const char *title3 = N_("Other options");
  359. const char *s_split_direction[2] = {
  360. N_("&Vertical"),
  361. N_("&Horizontal")
  362. };
  363. const char *ok_button = N_("&OK");
  364. const char *cancel_button = N_("&Cancel");
  365. output_lines_label = _("Output lines:");
  366. /* save old params */
  367. _panels_layout = panels_layout;
  368. _menubar_visible = menubar_visible;
  369. _command_prompt = command_prompt;
  370. _keybar_visible = mc_global.keybar_visible;
  371. _message_visible = mc_global.message_visible;
  372. _xterm_title = xterm_title;
  373. _free_space = free_space;
  374. old_layout.horizontal_split = -1;
  375. old_layout.left_panel_size = -1;
  376. old_layout.top_panel_size = -1;
  377. old_output_lines = -1;
  378. _output_lines = output_lines;
  379. #ifdef ENABLE_NLS
  380. {
  381. static gboolean i18n = FALSE;
  382. title1 = _(title1);
  383. title2 = _(title2);
  384. title3 = _(title3);
  385. i = G_N_ELEMENTS (s_split_direction);
  386. while (i-- != 0)
  387. s_split_direction[i] = _(s_split_direction[i]);
  388. if (!i18n)
  389. {
  390. for (i = 0; i < (size_t) LAYOUT_OPTIONS_COUNT; i++)
  391. check_options[i].text = _(check_options[i].text);
  392. i18n = TRUE;
  393. }
  394. ok_button = _(ok_button);
  395. cancel_button = _(cancel_button);
  396. }
  397. #endif
  398. /* radiobuttons */
  399. i = G_N_ELEMENTS (s_split_direction);
  400. while (i-- != 0)
  401. l1 = max (l1, str_term_width1 (s_split_direction[i]) + 7);
  402. /* checkboxes */
  403. for (i = 0; i < (size_t) LAYOUT_OPTIONS_COUNT; i++)
  404. l1 = max (l1, str_term_width1 (check_options[i].text) + 7);
  405. /* groupboxes */
  406. l1 = max (l1, str_term_width1 (title1) + 4);
  407. l1 = max (l1, str_term_width1 (title2) + 4);
  408. l1 = max (l1, str_term_width1 (title3) + 4);
  409. /* label + "+"/"-" buttons */
  410. output_lines_label_len = str_term_width1 (output_lines_label);
  411. l1 = max (l1, output_lines_label_len + 12);
  412. /* buttons */
  413. b1 = str_term_width1 (ok_button) + 5; /* default button */
  414. b2 = str_term_width1 (cancel_button) + 3;
  415. b = b1 + b2 + 1;
  416. /* dialog width */
  417. width = max (l1 * 2 + 7, b);
  418. layout_dlg =
  419. create_dlg (TRUE, 0, 0, 14, width,
  420. dialog_colors, layout_callback, NULL, "[Layout]",
  421. _("Layout"), DLG_CENTER | DLG_REVERSE);
  422. /* buttons */
  423. add_widget (layout_dlg,
  424. button_new (11, (width - b) / 3 * 2 + b1 + 1, B_CANCEL, NORMAL_BUTTON,
  425. cancel_button, 0));
  426. add_widget (layout_dlg,
  427. button_new (11, (width - b) / 3, B_ENTER, DEFPUSH_BUTTON, ok_button, 0));
  428. #define XTRACT(i) *check_options[i].variable, check_options[i].text
  429. /* "Other options" groupbox */
  430. for (i = 0; i < (size_t) OTHER_OPTIONS_COUNT; i++)
  431. {
  432. check_options[i].widget = check_new (OTHER_OPTIONS_COUNT - i + 2, 6 + l1, XTRACT (i));
  433. add_widget (layout_dlg, check_options[i].widget);
  434. }
  435. add_widget (layout_dlg, groupbox_new (2, 4 + l1, 9, l1, title3));
  436. /* "Console output" groupbox */
  437. {
  438. const int disabled = mc_global.tty.console_flag != '\0' ? 0 : W_DISABLED;
  439. Widget *w;
  440. w = (Widget *) button_new (9, output_lines_label_len + 5 + 5, B_MINUS,
  441. NARROW_BUTTON, "&-", bminus_cback);
  442. w->options |= disabled;
  443. add_widget (layout_dlg, w);
  444. w = (Widget *) button_new (9, output_lines_label_len + 5, B_PLUS,
  445. NARROW_BUTTON, "&+", bplus_cback);
  446. w->options |= disabled;
  447. add_widget (layout_dlg, w);
  448. w = (Widget *) groupbox_new (8, 3, 3, l1, title2);
  449. w->options |= disabled;
  450. add_widget (layout_dlg, w);
  451. }
  452. equal_split = panels_layout.horizontal_split ?
  453. panels_layout.horizontal_equal : panels_layout.vertical_equal;
  454. /* "Panel split" groupbox */
  455. bright_widget = button_new (6, 14, B_2RIGHT, NARROW_BUTTON, "&>", b_left_right_cback);
  456. widget_disable (bright_widget->widget, equal_split);
  457. add_widget (layout_dlg, bright_widget);
  458. bleft_widget = button_new (6, 8, B_2LEFT, NARROW_BUTTON, "&<", b_left_right_cback);
  459. widget_disable (bleft_widget->widget, equal_split);
  460. add_widget (layout_dlg, bleft_widget);
  461. check_options[6].widget = check_new (5, 5, XTRACT (6));
  462. add_widget (layout_dlg, check_options[6].widget);
  463. radio_widget = radio_new (3, 5, 2, s_split_direction);
  464. radio_widget->sel = panels_layout.horizontal_split;
  465. add_widget (layout_dlg, radio_widget);
  466. add_widget (layout_dlg, groupbox_new (2, 3, 6, l1, title1));
  467. #undef XTRACT
  468. return layout_dlg;
  469. }
  470. /* --------------------------------------------------------------------------------------------- */
  471. static void
  472. panel_do_cols (int idx)
  473. {
  474. if (get_display_type (idx) == view_listing)
  475. set_panel_formats ((WPanel *) panels[idx].widget);
  476. else
  477. panel_update_cols (panels[idx].widget, frame_half);
  478. }
  479. /* --------------------------------------------------------------------------------------------- */
  480. /** Save current list_view widget directory into panel */
  481. static Widget *
  482. restore_into_right_dir_panel (int idx, Widget * from_widget)
  483. {
  484. Widget *new_widget = NULL;
  485. const char *saved_dir = panels[idx].last_saved_dir;
  486. gboolean last_was_panel = (from_widget && get_display_type (idx) != view_listing);
  487. const char *p_name = get_nth_panel_name (idx);
  488. if (last_was_panel)
  489. new_widget = (Widget *) panel_new_with_dir (p_name, saved_dir);
  490. else
  491. new_widget = (Widget *) panel_new (p_name);
  492. return new_widget;
  493. }
  494. /* --------------------------------------------------------------------------------------------- */
  495. /*** public functions ****************************************************************************/
  496. /* --------------------------------------------------------------------------------------------- */
  497. void
  498. layout_change (void)
  499. {
  500. setup_panels ();
  501. /* update the main menu, because perhaps there was a change in the way
  502. how the panel are split (horizontal/vertical),
  503. and a change of menu visibility. */
  504. update_menu ();
  505. load_hint (1);
  506. }
  507. /* --------------------------------------------------------------------------------------------- */
  508. void
  509. layout_box (void)
  510. {
  511. Dlg_head *layout_dlg;
  512. gboolean layout_do_change = FALSE;
  513. layout_dlg = init_layout ();
  514. if (run_dlg (layout_dlg) == B_ENTER)
  515. {
  516. size_t i;
  517. for (i = 0; i < (size_t) LAYOUT_OPTIONS_COUNT; i++)
  518. if (check_options[i].widget != NULL)
  519. *check_options[i].variable = check_options[i].widget->state & C_BOOL;
  520. panels_layout.horizontal_split = radio_widget->sel;
  521. if (panels_layout.horizontal_split)
  522. {
  523. panels_layout.horizontal_equal = *check_options[6].variable;
  524. panels_layout.top_panel_size = _panels_layout.top_panel_size;
  525. }
  526. else
  527. {
  528. panels_layout.vertical_equal = *check_options[6].variable;
  529. panels_layout.left_panel_size = _panels_layout.left_panel_size;
  530. }
  531. output_lines = _output_lines;
  532. layout_do_change = TRUE;
  533. }
  534. destroy_dlg (layout_dlg);
  535. if (layout_do_change)
  536. layout_change ();
  537. }
  538. /* --------------------------------------------------------------------------------------------- */
  539. void
  540. setup_panels (void)
  541. {
  542. int start_y;
  543. if (mc_global.tty.console_flag != '\0')
  544. {
  545. int minimum;
  546. if (output_lines < 0)
  547. output_lines = 0;
  548. height =
  549. LINES - mc_global.keybar_visible - (command_prompt ? 1 : 0) - menubar_visible -
  550. output_lines - mc_global.message_visible;
  551. minimum = MINHEIGHT * (1 + panels_layout.horizontal_split);
  552. if (height < minimum)
  553. {
  554. output_lines -= minimum - height;
  555. height = minimum;
  556. }
  557. }
  558. else
  559. {
  560. height =
  561. LINES - menubar_visible - (command_prompt ? 1 : 0) - mc_global.keybar_visible -
  562. mc_global.message_visible;
  563. }
  564. check_split (&panels_layout);
  565. start_y = menubar_visible;
  566. /* The column computing is defered until panel_do_cols */
  567. if (panels_layout.horizontal_split)
  568. {
  569. widget_set_size (panels[0].widget, start_y, 0, panels_layout.top_panel_size, 0);
  570. widget_set_size (panels[1].widget, start_y + panels_layout.top_panel_size, 0,
  571. height - panels_layout.top_panel_size, 0);
  572. }
  573. else
  574. {
  575. widget_set_size (panels[0].widget, start_y, 0, height, 0);
  576. widget_set_size (panels[1].widget, start_y, panels_layout.left_panel_size, height, 0);
  577. }
  578. panel_do_cols (0);
  579. panel_do_cols (1);
  580. widget_set_size (&the_menubar->widget, 0, 0, 1, COLS);
  581. if (command_prompt)
  582. {
  583. #ifdef HAVE_SUBSHELL_SUPPORT
  584. if (!mc_global.tty.use_subshell || !do_load_prompt ())
  585. #endif
  586. setup_cmdline ();
  587. }
  588. else
  589. {
  590. widget_set_size (&cmdline->widget, 0, 0, 0, 0);
  591. input_set_origin (cmdline, 0, 0);
  592. widget_set_size (&the_prompt->widget, LINES, COLS, 0, 0);
  593. }
  594. widget_set_size (&the_bar->widget, LINES - 1, 0, mc_global.keybar_visible, COLS);
  595. buttonbar_set_visible (the_bar, mc_global.keybar_visible);
  596. /* Output window */
  597. if (mc_global.tty.console_flag != '\0' && output_lines)
  598. {
  599. output_start_y = LINES - (command_prompt ? 1 : 0) - mc_global.keybar_visible - output_lines;
  600. show_console_contents (output_start_y,
  601. LINES - output_lines - mc_global.keybar_visible - 1,
  602. LINES - mc_global.keybar_visible - 1);
  603. }
  604. if (mc_global.message_visible)
  605. widget_set_size (&the_hint->widget, height + start_y, 0, 1, COLS);
  606. else
  607. widget_set_size (&the_hint->widget, 0, 0, 0, 0);
  608. update_xterm_title_path ();
  609. }
  610. /* --------------------------------------------------------------------------------------------- */
  611. void
  612. panels_split_equal (void)
  613. {
  614. if (panels_layout.horizontal_split)
  615. panels_layout.horizontal_equal = TRUE;
  616. else
  617. panels_layout.vertical_equal = TRUE;
  618. layout_change ();
  619. do_refresh ();
  620. }
  621. /* --------------------------------------------------------------------------------------------- */
  622. void
  623. panels_split_more (void)
  624. {
  625. if (panels_layout.horizontal_split)
  626. {
  627. panels_layout.horizontal_equal = FALSE;
  628. panels_layout.top_panel_size++;
  629. }
  630. else
  631. {
  632. panels_layout.vertical_equal = FALSE;
  633. panels_layout.left_panel_size++;
  634. }
  635. layout_change ();
  636. }
  637. /* --------------------------------------------------------------------------------------------- */
  638. void
  639. panels_split_less (void)
  640. {
  641. if (panels_layout.horizontal_split)
  642. {
  643. panels_layout.horizontal_equal = FALSE;
  644. panels_layout.top_panel_size--;
  645. }
  646. else
  647. {
  648. panels_layout.vertical_equal = FALSE;
  649. panels_layout.left_panel_size--;
  650. }
  651. layout_change ();
  652. }
  653. /* --------------------------------------------------------------------------------------------- */
  654. void
  655. setup_cmdline (void)
  656. {
  657. int prompt_len;
  658. int y;
  659. char *tmp_prompt = NULL;
  660. #ifdef HAVE_SUBSHELL_SUPPORT
  661. if (mc_global.tty.use_subshell)
  662. tmp_prompt = strip_ctrl_codes (subshell_prompt);
  663. if (tmp_prompt == NULL)
  664. #endif
  665. tmp_prompt = (char *) mc_prompt;
  666. prompt_len = str_term_width1 (tmp_prompt);
  667. /* Check for prompts too big */
  668. if (COLS > 8 && prompt_len > COLS - 8)
  669. {
  670. prompt_len = COLS - 8;
  671. tmp_prompt[prompt_len] = '\0';
  672. }
  673. mc_prompt = tmp_prompt;
  674. y = LINES - 1 - mc_global.keybar_visible;
  675. widget_set_size ((Widget *) the_prompt, y, 0, 1, prompt_len);
  676. label_set_text (the_prompt, mc_prompt);
  677. widget_set_size ((Widget *) cmdline, y, prompt_len, 1, COLS - prompt_len);
  678. input_set_origin ((WInput *) cmdline, prompt_len, COLS - prompt_len);
  679. }
  680. /* --------------------------------------------------------------------------------------------- */
  681. void
  682. use_dash (gboolean flag)
  683. {
  684. if (flag)
  685. ok_to_refresh++;
  686. else
  687. ok_to_refresh--;
  688. }
  689. /* --------------------------------------------------------------------------------------------- */
  690. void
  691. set_hintbar (const char *str)
  692. {
  693. label_set_text (the_hint, str);
  694. if (ok_to_refresh > 0)
  695. mc_refresh ();
  696. }
  697. /* --------------------------------------------------------------------------------------------- */
  698. void
  699. rotate_dash (void)
  700. {
  701. static const char rotating_dash[] = "|/-\\";
  702. static size_t pos = 0;
  703. if (!nice_rotating_dash || (ok_to_refresh <= 0))
  704. return;
  705. if (pos >= sizeof (rotating_dash) - 1)
  706. pos = 0;
  707. tty_gotoyx (0, COLS - 1);
  708. tty_setcolor (NORMAL_COLOR);
  709. tty_print_char (rotating_dash[pos]);
  710. mc_refresh ();
  711. pos++;
  712. }
  713. /* --------------------------------------------------------------------------------------------- */
  714. const char *
  715. get_nth_panel_name (int num)
  716. {
  717. static char buffer[BUF_SMALL];
  718. if (!num)
  719. return "New Left Panel";
  720. else if (num == 1)
  721. return "New Right Panel";
  722. else
  723. {
  724. g_snprintf (buffer, sizeof (buffer), "%ith Panel", num);
  725. return buffer;
  726. }
  727. }
  728. /* --------------------------------------------------------------------------------------------- */
  729. /* I wonder if I should start to use the folding mode than Dugan uses */
  730. /* */
  731. /* This is the centralized managing of the panel display types */
  732. /* This routine takes care of destroying and creating new widgets */
  733. /* Please note that it could manage MAX_VIEWS, not just left and right */
  734. /* Currently nothing in the code takes advantage of this and has hard- */
  735. /* coded values for two panels only */
  736. /* Set the num-th panel to the view type: type */
  737. /* This routine also keeps at least one WPanel object in the screen */
  738. /* since a lot of routines depend on the current_panel variable */
  739. void
  740. set_display_type (int num, panel_view_mode_t type)
  741. {
  742. int x = 0, y = 0, cols = 0, lines = 0;
  743. unsigned int the_other = 0; /* Index to the other panel */
  744. const char *file_name = NULL; /* For Quick view */
  745. Widget *new_widget = NULL, *old_widget = NULL;
  746. panel_view_mode_t old_type = view_listing;
  747. WPanel *the_other_panel = NULL;
  748. if (num >= MAX_VIEWS)
  749. {
  750. fprintf (stderr, "Cannot allocate more that %d views\n", MAX_VIEWS);
  751. abort ();
  752. }
  753. /* Check that we will have a WPanel * at least */
  754. if (type != view_listing)
  755. {
  756. the_other = num == 0 ? 1 : 0;
  757. if (panels[the_other].type != view_listing)
  758. return;
  759. }
  760. /* Get rid of it */
  761. if (panels[num].widget != NULL)
  762. {
  763. Widget *w = panels[num].widget;
  764. WPanel *panel = (WPanel *) w;
  765. x = w->x;
  766. y = w->y;
  767. cols = w->cols;
  768. lines = w->lines;
  769. old_widget = w;
  770. old_type = panels[num].type;
  771. if (old_type == view_listing && panel->frame_size == frame_full && type != view_listing)
  772. {
  773. if (panels_layout.horizontal_split)
  774. {
  775. cols = COLS;
  776. x = 0;
  777. }
  778. else
  779. {
  780. cols = COLS - panels_layout.left_panel_size;
  781. if (num == 1)
  782. x = panels_layout.left_panel_size;
  783. }
  784. }
  785. }
  786. /* Restoring saved path from panels.ini for nonlist panel */
  787. /* when it's first creation (for example view_info) */
  788. if (old_widget == NULL && type != view_listing)
  789. {
  790. char *panel_dir;
  791. panel_dir = _vfs_get_cwd ();
  792. panels[num].last_saved_dir = g_strdup (panel_dir);
  793. g_free (panel_dir);
  794. }
  795. switch (type)
  796. {
  797. case view_nothing:
  798. case view_listing:
  799. new_widget = restore_into_right_dir_panel (num, old_widget);
  800. widget_set_size (new_widget, y, x, lines, cols);
  801. break;
  802. case view_info:
  803. new_widget = (Widget *) info_new (y, x, lines, cols);
  804. break;
  805. case view_tree:
  806. new_widget = (Widget *) tree_new (y, x, lines, cols, TRUE);
  807. break;
  808. case view_quick:
  809. new_widget = (Widget *) mcview_new (y, x, lines, cols, TRUE);
  810. the_other_panel = (WPanel *) panels[the_other].widget;
  811. if (the_other_panel != NULL)
  812. file_name = the_other_panel->dir.list[the_other_panel->selected].fname;
  813. else
  814. file_name = "";
  815. mcview_load ((struct mcview_struct *) new_widget, 0, file_name, 0);
  816. break;
  817. }
  818. if (type != view_listing)
  819. /* Must save dir, for restoring after change type to */
  820. /* view_listing */
  821. save_panel_dir (num);
  822. panels[num].type = type;
  823. panels[num].widget = new_widget;
  824. /* We use replace to keep the circular list of the dialog in the */
  825. /* same state. Maybe we could just kill it and then replace it */
  826. if ((midnight_dlg != NULL) && (old_widget != NULL))
  827. {
  828. if (old_type == view_listing)
  829. {
  830. /* save and write directory history of panel
  831. * ... and other histories of midnight_dlg */
  832. dlg_save_history (midnight_dlg);
  833. }
  834. dlg_replace_widget (old_widget, new_widget);
  835. }
  836. if (type == view_listing)
  837. {
  838. WPanel *panel = (WPanel *) new_widget;
  839. /* if existing panel changed type to view_listing, then load history */
  840. if (old_widget != NULL)
  841. {
  842. ev_history_load_save_t event_data = { NULL, new_widget };
  843. mc_event_raise (midnight_dlg->event_group, MCEVENT_HISTORY_LOAD, &event_data);
  844. }
  845. if (num == 0)
  846. left_panel = panel;
  847. else
  848. right_panel = panel;
  849. /* forced update format after set new sizes */
  850. set_panel_formats (panel);
  851. }
  852. if (type == view_tree)
  853. the_tree = (WTree *) new_widget;
  854. /* Prevent current_panel's value from becoming invalid.
  855. * It's just a quick hack to prevent segfaults. Comment out and
  856. * try following:
  857. * - select left panel
  858. * - invoke menue left/tree
  859. * - as long as you stay in the left panel almost everything that uses
  860. * current_panel causes segfault, e.g. C-Enter, C-x c, ...
  861. */
  862. if ((type != view_listing) && (current_panel == (WPanel *) old_widget))
  863. current_panel = num == 0 ? right_panel : left_panel;
  864. g_free (old_widget);
  865. }
  866. /* --------------------------------------------------------------------------------------------- */
  867. /** This routine is deeply sticked to the two panels idea.
  868. What should it do in more panels. ANSWER - don't use it
  869. in any multiple panels environment. */
  870. void
  871. swap_panels (void)
  872. {
  873. WPanel *panel1, *panel2;
  874. Widget *tmp_widget;
  875. panel1 = (WPanel *) panels[0].widget;
  876. panel2 = (WPanel *) panels[1].widget;
  877. if (panels[0].type == view_listing && panels[1].type == view_listing &&
  878. !mc_config_get_bool (mc_main_config, CONFIG_PANELS_SECTION, "simple_swap", FALSE))
  879. {
  880. WPanel panel;
  881. #define panelswap(x) panel.x = panel1->x; panel1->x = panel2->x; panel2->x = panel.x;
  882. #define panelswapstr(e) strcpy (panel.e, panel1->e); \
  883. strcpy (panel1->e, panel2->e); \
  884. strcpy (panel2->e, panel.e);
  885. /* Change content and related stuff */
  886. panelswap (dir);
  887. panelswap (active);
  888. panelswap (cwd_vpath);
  889. panelswap (lwd_vpath);
  890. panelswap (count);
  891. panelswap (marked);
  892. panelswap (dirs_marked);
  893. panelswap (total);
  894. panelswap (top_file);
  895. panelswap (selected);
  896. panelswap (is_panelized);
  897. panelswap (dir_stat);
  898. #undef panelswapstr
  899. #undef panelswap
  900. panel1->searching = FALSE;
  901. panel2->searching = FALSE;
  902. if (current_panel == panel1)
  903. current_panel = panel2;
  904. else
  905. current_panel = panel1;
  906. /* if sort options are different -> resort panels */
  907. if (memcmp (&panel1->sort_info, &panel2->sort_info, sizeof (panel_sort_info_t)) != 0)
  908. {
  909. panel_re_sort (other_panel);
  910. panel_re_sort (current_panel);
  911. }
  912. if (dlg_widget_active (panels[0].widget))
  913. dlg_select_widget (panels[1].widget);
  914. else if (dlg_widget_active (panels[1].widget))
  915. dlg_select_widget (panels[0].widget);
  916. }
  917. else
  918. {
  919. WPanel *tmp_panel;
  920. int x, y, cols, lines;
  921. int tmp_type;
  922. tmp_panel = right_panel;
  923. right_panel = left_panel;
  924. left_panel = tmp_panel;
  925. if (panels[0].type == view_listing)
  926. {
  927. if (strcmp (panel1->panel_name, get_nth_panel_name (0)) == 0)
  928. {
  929. g_free (panel1->panel_name);
  930. panel1->panel_name = g_strdup (get_nth_panel_name (1));
  931. }
  932. }
  933. if (panels[1].type == view_listing)
  934. {
  935. if (strcmp (panel2->panel_name, get_nth_panel_name (1)) == 0)
  936. {
  937. g_free (panel2->panel_name);
  938. panel2->panel_name = g_strdup (get_nth_panel_name (0));
  939. }
  940. }
  941. x = panels[0].widget->x;
  942. y = panels[0].widget->y;
  943. cols = panels[0].widget->cols;
  944. lines = panels[0].widget->lines;
  945. panels[0].widget->x = panels[1].widget->x;
  946. panels[0].widget->y = panels[1].widget->y;
  947. panels[0].widget->cols = panels[1].widget->cols;
  948. panels[0].widget->lines = panels[1].widget->lines;
  949. panels[1].widget->x = x;
  950. panels[1].widget->y = y;
  951. panels[1].widget->cols = cols;
  952. panels[1].widget->lines = lines;
  953. tmp_widget = panels[0].widget;
  954. panels[0].widget = panels[1].widget;
  955. panels[1].widget = tmp_widget;
  956. tmp_type = panels[0].type;
  957. panels[0].type = panels[1].type;
  958. panels[1].type = tmp_type;
  959. /* force update formats because of possible changed sizes */
  960. if (panels[0].type == view_listing)
  961. set_panel_formats ((WPanel *) panels[0].widget);
  962. if (panels[1].type == view_listing)
  963. set_panel_formats ((WPanel *) panels[1].widget);
  964. }
  965. }
  966. /* --------------------------------------------------------------------------------------------- */
  967. panel_view_mode_t
  968. get_display_type (int idx)
  969. {
  970. return panels[idx].type;
  971. }
  972. /* --------------------------------------------------------------------------------------------- */
  973. struct Widget *
  974. get_panel_widget (int idx)
  975. {
  976. return panels[idx].widget;
  977. }
  978. /* --------------------------------------------------------------------------------------------- */
  979. int
  980. get_current_index (void)
  981. {
  982. if (panels[0].widget == ((Widget *) current_panel))
  983. return 0;
  984. else
  985. return 1;
  986. }
  987. /* --------------------------------------------------------------------------------------------- */
  988. int
  989. get_other_index (void)
  990. {
  991. return !get_current_index ();
  992. }
  993. /* --------------------------------------------------------------------------------------------- */
  994. struct WPanel *
  995. get_other_panel (void)
  996. {
  997. return (struct WPanel *) get_panel_widget (get_other_index ());
  998. }
  999. /* --------------------------------------------------------------------------------------------- */
  1000. /** Returns the view type for the current panel/view */
  1001. panel_view_mode_t
  1002. get_current_type (void)
  1003. {
  1004. if (panels[0].widget == (Widget *) current_panel)
  1005. return panels[0].type;
  1006. else
  1007. return panels[1].type;
  1008. }
  1009. /* --------------------------------------------------------------------------------------------- */
  1010. /** Returns the view type of the unselected panel */
  1011. panel_view_mode_t
  1012. get_other_type (void)
  1013. {
  1014. if (panels[0].widget == (Widget *) current_panel)
  1015. return panels[1].type;
  1016. else
  1017. return panels[0].type;
  1018. }
  1019. /* --------------------------------------------------------------------------------------------- */
  1020. /** Save current list_view widget directory into panel */
  1021. void
  1022. save_panel_dir (int idx)
  1023. {
  1024. panel_view_mode_t type = get_display_type (idx);
  1025. Widget *widget = get_panel_widget (idx);
  1026. if ((type == view_listing) && (widget != NULL))
  1027. {
  1028. WPanel *w = (WPanel *) widget;
  1029. g_free (panels[idx].last_saved_dir); /* last path no needed */
  1030. /* Because path can be nonlocal */
  1031. panels[idx].last_saved_dir = vfs_path_to_str (w->cwd_vpath);
  1032. }
  1033. }
  1034. /* --------------------------------------------------------------------------------------------- */
  1035. /** Return working dir, if it's view_listing - cwd,
  1036. but for other types - last_saved_dir */
  1037. char *
  1038. get_panel_dir_for (const WPanel * widget)
  1039. {
  1040. int i;
  1041. for (i = 0; i < MAX_VIEWS; i++)
  1042. if ((WPanel *) get_panel_widget (i) == widget)
  1043. break;
  1044. if (i >= MAX_VIEWS)
  1045. return g_strdup (".");
  1046. if (get_display_type (i) == view_listing)
  1047. return vfs_path_to_str (((WPanel *) get_panel_widget (i))->cwd_vpath);
  1048. return g_strdup (panels[i].last_saved_dir);
  1049. }
  1050. /* --------------------------------------------------------------------------------------------- */