mirror of https://github.com/MidnightCommander/mc
566 lines
13 KiB
C
566 lines
13 KiB
C
/* Tk panel stuff.
|
|
Copyright (C) 1995, 1997 Miguel de Icaza
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
|
|
|
#include <config.h>
|
|
#include <string.h>
|
|
#include <stdlib.h> /* atoi */
|
|
#include "fs.h"
|
|
#include "dir.h"
|
|
#include "tkmain.h"
|
|
#include "panel.h"
|
|
#include "command.h"
|
|
#include "panel.h" /* current_panel */
|
|
#include "command.h" /* cmdline */
|
|
#include "main.h"
|
|
#include "mouse.h"
|
|
#include "layout.h" /* get_panel_widget */
|
|
#include "ext.h" /* regex_command */
|
|
#include "cmd.h" /* copy_cmd, ren_cmd, delete_cmd, ... */
|
|
#include "tkscreen.h"
|
|
|
|
/* These two variables keep track of the dimensions of a character in the
|
|
* panel listing.
|
|
*/
|
|
static int panel_font_width;
|
|
static int panel_font_height;
|
|
|
|
static char *attrib;
|
|
|
|
void
|
|
repaint_file (WPanel *panel, int file_index, int move, int attr, int isstatus)
|
|
{
|
|
}
|
|
|
|
void
|
|
show_dir (WPanel *panel)
|
|
{
|
|
char *tkw = wtk_win (panel->widget);
|
|
char *filter = panel->filter ? panel->filter : "*";
|
|
|
|
if (!panel->widget.wdata)
|
|
return;
|
|
|
|
tk_evalf ("%s.cwd configure -text {%s [%s]}", tkw, panel->cwd, filter);
|
|
}
|
|
|
|
void
|
|
x_fill_panel (WPanel *panel)
|
|
{
|
|
const int top = panel->count;
|
|
const int panel_width = panel->widget.cols - 2;
|
|
char *panel_name, *tag;
|
|
char buffer [255];
|
|
int i;
|
|
int selected;
|
|
if (!panel->widget.wcontainer)
|
|
return;
|
|
|
|
selected = panel->selected;
|
|
|
|
panel_name = copy_strings (wtk_win (panel->widget), ".m.p.panel", 0);
|
|
|
|
tk_evalf ("%s delete 0.0 end", panel_name);
|
|
for (i = 0; i < top; i++){
|
|
file_entry *fe = &panel->dir.list [i];
|
|
int marked = fe->f.marked;
|
|
|
|
format_file (buffer, panel, i, panel_width, NORMAL, 0);
|
|
|
|
if (i)
|
|
tk_evalf ("%s insert end \\n", panel_name);
|
|
|
|
|
|
/* Set the mark tag name -- this probably should go into generic code */
|
|
if (marked)
|
|
tag = "marked";
|
|
else {
|
|
tag = "regular";
|
|
if (S_ISLNK (fe->buf.st_mode)){
|
|
if (fe->f.link_to_dir)
|
|
tag = "directory";
|
|
} else if (S_ISDIR (fe->buf.st_mode))
|
|
tag = "directory";
|
|
else if (is_exe (fe->buf.st_mode))
|
|
tag = "executable";
|
|
}
|
|
tk_evalf ("%s insert end {%s} %s", panel_name, buffer, tag);
|
|
}
|
|
if (panel->active)
|
|
x_select_item (panel);
|
|
#if 0
|
|
/* The first time, the panel does not yet have a command */
|
|
if (panel->widget.wdata)
|
|
x_select_item (panel);
|
|
free (panel_name);
|
|
#endif
|
|
}
|
|
|
|
/* Adjusts a panel size */
|
|
static void
|
|
tk_panel_set_size (int index, int boot)
|
|
{
|
|
Widget *w;
|
|
WPanel *p;
|
|
char *pn;
|
|
int cols, lines;
|
|
|
|
w = (Widget *) get_panel_widget (index);
|
|
|
|
tk_evalf ("panel_info cols");
|
|
cols = atoi (interp->result);
|
|
|
|
tk_evalf ("panel_info lines");
|
|
lines = atoi (interp->result);
|
|
|
|
if ((lines < 10) || (cols < 3))
|
|
return;
|
|
|
|
w = get_panel_widget (index);
|
|
p = (WPanel *) w;
|
|
|
|
w->cols = cols;
|
|
w->lines = lines;
|
|
|
|
set_panel_formats (p);
|
|
paint_panel (p);
|
|
/* FIXME: paint_panel() includes calls to paint_frame() & x_fill_panel(). */
|
|
/* Why does we call them 2 times ? Timur */
|
|
if (!boot)
|
|
paint_frame (p);
|
|
x_fill_panel (p);
|
|
}
|
|
|
|
/* Called by panel bootstrap routine */
|
|
void
|
|
x_panel_set_size (int index)
|
|
{
|
|
tk_panel_set_size (index, 1);
|
|
}
|
|
|
|
/* Called at runtime when the size of the window changes */
|
|
static void
|
|
x_change_size (char *panel, int boot)
|
|
{
|
|
if (strncmp (panel, ".left", 5) == 0)
|
|
tk_panel_set_size (0, 0);
|
|
else
|
|
tk_panel_set_size (1, 0);
|
|
}
|
|
|
|
#if TCL_MAJOR_VERSION > 7
|
|
/* Tcl 8.xx support */
|
|
static void
|
|
compute_font_size (char *font, char *win, char *dest)
|
|
{
|
|
Tk_Window window_id;
|
|
Tk_Font tkfont;
|
|
Tk_FontMetrics fmPtr;
|
|
int width, height;
|
|
|
|
window_id = Tk_NameToWindow (interp, win, Tk_MainWindow (interp));
|
|
if (window_id == NULL) {
|
|
fprintf (stderr, "Error: %s\n\r", interp->result);
|
|
exit (1);
|
|
}
|
|
tkfont = Tk_GetFont (interp, window_id, font);
|
|
if (tkfont == NULL) {
|
|
fprintf (stderr,
|
|
"This should not happend: %s\n", interp->result);
|
|
exit (1);
|
|
}
|
|
Tk_GetFontMetrics (tkfont, &fmPtr);
|
|
|
|
width = Tk_TextWidth (tkfont, "O", 1);
|
|
height = fmPtr.linespace;
|
|
Tk_FreeFont (tkfont);
|
|
|
|
sprintf (dest, "%d %d", height, width);
|
|
}
|
|
|
|
#else
|
|
|
|
#ifdef HAVE_TKFONT
|
|
/* PreTcl 8.xx support */
|
|
#define GetFontMetrics(tkfont) \
|
|
((CONST TkFontMetrics *) &((TkFont *) (tkfont))->fm)
|
|
|
|
static void
|
|
compute_font_size (char *font, char *win, char *dest)
|
|
{
|
|
Tk_Window window_id;
|
|
Tk_Font tkfont;
|
|
const TkFontMetrics *fmPtr;
|
|
int width, height;
|
|
|
|
window_id = Tk_NameToWindow (interp, win, Tk_MainWindow (interp));
|
|
if (window_id == NULL) {
|
|
fprintf (stderr, "Error: %s\n\r", interp->result);
|
|
exit (1);
|
|
}
|
|
tkfont = Tk_GetFont (interp, window_id, font);
|
|
if (tkfont == NULL) {
|
|
fprintf (stderr,
|
|
"This should not happend: %s\n", interp->result);
|
|
exit (1);
|
|
}
|
|
fmPtr = GetFontMetrics (tkfont);
|
|
|
|
width = fmPtr->maxWidth;
|
|
height = fmPtr->ascent + fmPtr->descent;
|
|
Tk_FreeFont (tkfont);
|
|
|
|
sprintf (dest, "%d %d", height, width);
|
|
}
|
|
|
|
#else
|
|
static char
|
|
compute_font_size (char *font, char *win, char *dest)
|
|
{
|
|
Tk_Uid font_uid;
|
|
Tk_Window window_id;
|
|
XFontStruct *f;
|
|
int width, height;
|
|
|
|
font_uid = Tk_GetUid (font);
|
|
window_id = Tk_NameToWindow (interp, win, Tk_MainWindow (interp));
|
|
if (window_id == NULL){
|
|
fprintf (stderr, "Error: %s\n\r", interp->result);
|
|
exit (1);
|
|
}
|
|
f = Tk_GetFontStruct (interp, window_id, font_uid);
|
|
|
|
if (f == NULL){
|
|
fprintf (stderr, "This should not happend: %s\n", interp->result);
|
|
exit (1);
|
|
}
|
|
|
|
width = f->max_bounds.width;
|
|
height = f->ascent + f->descent;
|
|
|
|
/* Ok, we will use this dummy until monday, the correct thing
|
|
* to do is extract the Tk font information from Tk's hash
|
|
* table (tkFont.c).
|
|
*
|
|
* TkFont->widths ['0'] holds the width
|
|
*/
|
|
sprintf (dest, "%d %d", height, width);
|
|
Tk_FreeFontStruct (f);
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
/*
|
|
* This routine is called when the user has chosen an action from the popup
|
|
* menu. Handles the Copy, Move and Delete commands internally, anything
|
|
* else ends in the regex_command routine.
|
|
*/
|
|
static void
|
|
tk_invoke (WPanel *panel, int idx, char *operation)
|
|
{
|
|
char *filename = panel->dir.list [idx].fname;
|
|
int movedir;
|
|
|
|
if (STREQ (operation, "Copy"))
|
|
copy_cmd ();
|
|
else if (STREQ (operation, "Move"))
|
|
ren_cmd ();
|
|
else if (STREQ (operation, "Delete"))
|
|
delete_cmd ();
|
|
else {
|
|
regex_command (filename, operation, NULL, &movedir);
|
|
}
|
|
}
|
|
|
|
static void
|
|
tk_add_popup_entry (char *option, char *cmd, int idx)
|
|
{
|
|
tk_evalf (".m add command -label {%s} -command {%s invoke %d {%s}}", option, cmd, idx, option);
|
|
}
|
|
|
|
/* This routine assumes the Tcl code has already created the .m menu */
|
|
static void
|
|
tk_load_popup (WPanel *panel, char *cmd, int idx)
|
|
{
|
|
char *filename = panel->dir.list [idx].fname;
|
|
char *p, *q;
|
|
int c;
|
|
|
|
tk_evalf ("popup_add_action {%s} %s %d", filename, cmd, idx);
|
|
|
|
p = regex_command (filename, NULL, NULL, NULL);
|
|
if (!p)
|
|
return;
|
|
tk_evalf (".m add separator");
|
|
for (;;){
|
|
while (*p == ' ' || *p == '\t')
|
|
p++;
|
|
if (!*p)
|
|
break;
|
|
q = p;
|
|
while (*q && *q != '=' && *q != '\t')
|
|
q++;
|
|
c = *q;
|
|
*q = 0;
|
|
tk_add_popup_entry (p, cmd, idx);
|
|
if (!c)
|
|
break;
|
|
p = q + 1;
|
|
}
|
|
}
|
|
|
|
void
|
|
tk_set_sort (WPanel *panel, char *name)
|
|
{
|
|
sortfn *f;
|
|
|
|
if (!name || (f = get_sort_fn (name)) == NULL)
|
|
return;
|
|
|
|
if (!name)
|
|
return;
|
|
set_sort_to (panel, f);
|
|
}
|
|
|
|
void
|
|
tk_return_drag_text (WPanel *panel)
|
|
{
|
|
if (panel->marked){
|
|
sprintf (interp->result, "%d file%s", panel->marked,
|
|
panel->marked== 1 ? "" : "s");
|
|
} else
|
|
strcpy (interp->result, "1 file");
|
|
}
|
|
|
|
int
|
|
tk_panel_callback (ClientData cd, Tcl_Interp *interp, int ac, char *av[])
|
|
{
|
|
Gpm_Event e;
|
|
WPanel *panel = (WPanel *) cd;
|
|
char b [20];
|
|
char *p;
|
|
int mouse_etype = 0;
|
|
|
|
p = av [1];
|
|
|
|
if (STREQ (p, "mdown"))
|
|
mouse_etype = GPM_DOWN;
|
|
else if (STREQ (p, "mup"))
|
|
mouse_etype = GPM_UP;
|
|
else if (STREQ (p, "double"))
|
|
mouse_etype = GPM_DOUBLE|GPM_UP;
|
|
else if (STREQ (p, "motion"))
|
|
mouse_etype = GPM_MOVE|GPM_DRAG;
|
|
else if (STREQ (p, "resize")){
|
|
x_change_size (av [2], 0);
|
|
return TCL_OK;
|
|
} else if (STREQ (p, "fontdim")){
|
|
compute_font_size (av [2], av [3], interp->result);
|
|
return TCL_OK;
|
|
} else if (STREQ (p, "load")){
|
|
tk_load_popup (panel, av [0], atoi (av [2])-1);
|
|
tk_evalf ("tk_popup .m %s %s", av [3], av [4]);
|
|
return TCL_OK;
|
|
} else if (STREQ (p, "invoke")){
|
|
tk_invoke (panel, atoi (av [2]), av [3]);
|
|
return TCL_OK;
|
|
} else if (STREQ (p, "refresh")){
|
|
reread_cmd ();
|
|
return TCL_OK;
|
|
} else if (STREQ (p, "setmask")){
|
|
filter_cmd ();
|
|
return TCL_OK;
|
|
} else if (STREQ (p, "nomask")){
|
|
if (panel->filter){
|
|
free (panel->filter);
|
|
panel->filter = 0;
|
|
}
|
|
reread_cmd ();
|
|
return TCL_OK;
|
|
} else if (STREQ (p, "sort")) {
|
|
tk_set_sort (panel, av [2]);
|
|
return TCL_OK;
|
|
} else if (STREQ (p, "reverse")){
|
|
panel->reverse = !panel->reverse;
|
|
do_re_sort (panel);
|
|
return TCL_OK;
|
|
} else if (STREQ (p, "dragtext")){
|
|
tk_return_drag_text (panel);
|
|
return TCL_OK;
|
|
}
|
|
|
|
if (STREQ (p, "top")){
|
|
int old_sel = panel->selected;
|
|
int new = old_sel;
|
|
|
|
panel->top_file = atoi (av [2]) - 1;
|
|
if (old_sel < panel->top_file)
|
|
new = panel->top_file;
|
|
if (old_sel > (panel->top_file + ITEMS (panel)))
|
|
new = panel->top_file + ITEMS (panel) - 1;
|
|
|
|
if (new != old_sel){
|
|
unselect_item (panel);
|
|
panel->selected = new;
|
|
select_item (panel);
|
|
}
|
|
return TCL_OK;
|
|
}
|
|
|
|
if (mouse_etype){
|
|
for (p = av [3]; *p && *p != '.'; p++)
|
|
;
|
|
*p++ = 0;
|
|
e.buttons = atoi (av [2]);
|
|
e.y = atoi (av [3]) + 2 - panel->top_file;
|
|
e.x = atoi (p);
|
|
e.type = mouse_etype;
|
|
panel_event (&e, panel);
|
|
} else {
|
|
/* We are currently dealing with those */
|
|
fprintf (stderr, "Unknown command: %s\n", p);
|
|
return TCL_ERROR;
|
|
}
|
|
return TCL_OK;
|
|
}
|
|
|
|
void
|
|
x_create_panel (Dlg_head *h, widget_data parent, WPanel *panel)
|
|
{
|
|
char *cmd;
|
|
widget_data container = panel->widget.wcontainer;
|
|
|
|
cmd = tk_new_command (container, panel, tk_panel_callback, 'p');
|
|
tk_evalf ("panel_setup %s %s", wtk_win (panel->widget), cmd);
|
|
tk_evalf ("panel_bind %s %s", wtk_win (panel->widget), cmd);
|
|
paint_frame (panel);
|
|
x_fill_panel (panel);
|
|
}
|
|
|
|
/* Called when f.marked has changed on a file */
|
|
void
|
|
x_panel_select_item (WPanel *panel, int index, int value)
|
|
{
|
|
char *s;
|
|
|
|
s = value ? "add" : "remove";
|
|
tk_evalf ("panel_mark_entry %s %s %d", wtk_win(panel->widget), s, index+1);
|
|
}
|
|
|
|
void
|
|
x_unselect_item (WPanel *panel)
|
|
{
|
|
const int selected = panel->selected + 1;
|
|
|
|
if (panel->active)
|
|
tk_evalf ("panel_unmark_entry %s %d\n", wtk_win (panel->widget), selected);
|
|
}
|
|
|
|
void
|
|
x_select_item (WPanel *panel)
|
|
{
|
|
const int selected = panel->selected + 1;
|
|
char *cmd = wtcl_cmd (panel->widget);
|
|
|
|
if (!(cmd && *cmd))
|
|
return;
|
|
|
|
if (panel->active)
|
|
tk_evalf ("panel_select %s %d %s", wtk_win (panel->widget),
|
|
selected, cmd);
|
|
}
|
|
|
|
void
|
|
x_adjust_top_file (WPanel *panel)
|
|
{
|
|
tk_evalf ("%s.m.p.panel yview %d.0", wtk_win (panel->widget),
|
|
panel->top_file+1);
|
|
}
|
|
|
|
void
|
|
x_filter_changed (WPanel *panel)
|
|
{
|
|
show_dir (panel);
|
|
}
|
|
|
|
/* The following two routines may be called at the very beginning of the
|
|
* program, so we have to check if the widget has already been constructed
|
|
*/
|
|
static sort_label_last_pos;
|
|
|
|
void
|
|
x_add_sort_label (WPanel *panel, int index, char *text, char *tag, void *sr)
|
|
{
|
|
int pos;
|
|
|
|
if (!panel->format_modified)
|
|
return;
|
|
|
|
if (!panel->widget.wdata)
|
|
return;
|
|
|
|
/* We may still not have this information */
|
|
if (!panel_font_width){
|
|
tk_evalf ("panel_info heightc");
|
|
panel_font_height = atoi (interp->result);
|
|
|
|
tk_evalf ("panel_info widthc");
|
|
panel_font_width = atoi (interp->result);
|
|
}
|
|
|
|
pos = sort_label_last_pos;
|
|
sort_label_last_pos += (strlen (text) * panel_font_width) + (4);
|
|
|
|
/* The addition down there is to account for the canvas border width */
|
|
tk_evalf ("panel_add_sort %s %d {%s} %d %d {%s}", wtk_win(panel->widget),
|
|
strlen (text), text, pos , sort_label_last_pos, *tag ? tag : "Type");
|
|
}
|
|
|
|
void
|
|
x_sort_label_start (WPanel *panel)
|
|
{
|
|
if (!panel->widget.wdata)
|
|
return;
|
|
sort_label_last_pos = 0;
|
|
tk_evalf ("panel_sort_label_start %s", wtk_win (panel->widget));
|
|
}
|
|
|
|
void
|
|
x_reset_sort_labels (WPanel *panel)
|
|
{
|
|
if (!panel->widget.wdata)
|
|
return;
|
|
sort_label_last_pos = 0;
|
|
tk_evalf ("panel_reset_sort_labels %s", wtk_win (panel->widget));
|
|
}
|
|
|
|
void
|
|
panel_update_cols (Widget *widget, int frame_size)
|
|
{
|
|
/* nothing */
|
|
}
|
|
|
|
void
|
|
display_mini_info (WPanel *panel)
|
|
{
|
|
/* FIXME: implement */
|
|
}
|
|
|
|
void
|
|
x_panel_destroy (WPanel *panel)
|
|
{
|
|
}
|