📄 widget.c
字号:
if (label->auto_adjust_cols) {
newcols = strlen (text);
if (newcols > label->widget.cols)
label->widget.cols = newcols;
}
} else
label->text = 0;
if (label->widget.parent)
#ifdef HAVE_X
x_label_set_text (label, text);
#else
label_callback (label->widget.parent, label, WIDGET_DRAW, 0);
#endif
if (newcols < label->widget.cols)
label->widget.cols = newcols;
}
static void
label_destroy (WLabel *l)
{
x_destroy_cmd (l);
if (l->text)
free (l->text);
}
WLabel *
label_new (int y, int x, char *text, char *tkname)
{
WLabel *l = xmalloc (sizeof (WLabel), "label_new");
init_widget (&l->widget, y, x, 1, 1,
(callback_fn) label_callback,
(destroy_fn) label_destroy, NULL, tkname);
l->text = text ? strdup (text) : 0;
l->auto_adjust_cols = 1;
l->transparent = 0;
widget_want_cursor (l->widget, 0);
return l;
}
/* Gauge widget (progress indicator) */
/* Currently width is hardcoded here for text mode */
#define gauge_len 47
static int
gauge_callback (Dlg_head *h, WGauge *g, int Msg, int Par)
{
if (Msg == WIDGET_INIT)
return x_create_gauge (h, h->wdata, g);
/* We don't want to get the focus */
if (Msg == WIDGET_FOCUS)
return 0;
#ifndef HAVE_X
if (Msg == WIDGET_DRAW){
widget_move (&g->widget, 0, 0);
attrset (NORMALC);
if (!g->shown)
printw ("%*s", gauge_len, "");
else {
long percentage, columns;
long total = g->max, done = g->current;
if (total <= 0 || done < 0) {
done = 0;
total = 100;
}
if (done > total)
done = total;
while (total > 65535) {
total /= 256;
done /= 256;
}
percentage = (200 * done / total + 1) / 2;
columns = (2 * (gauge_len - 7) * done / total + 1) / 2;
addch ('[');
attrset (GAUGE_COLOR);
printw ("%*s", columns, "");
attrset (NORMALC);
printw ("%*s] %3d%%", gauge_len - 7 - columns, "", percentage);
}
return 1;
}
#endif
return default_proc (h, Msg, Par);
}
void
gauge_set_value (WGauge *g, int max, int current)
{
if (g->current == current && g->max == max)
return; /* Do not flicker */
if (max == 0)
max = 1; /* I do not like division by zero :) */
#ifdef HAVE_X
/* NOTE: x_gauge_set_value has to be called before we change actual
* max and current values in g, since it assumes g->max and
* g->current as the previous values and max and current
* as the new ones :) */
x_gauge_set_value (g, max, current);
#endif
g->current = current;
g->max = max;
#ifndef HAVE_X
gauge_callback (g->widget.parent, g, WIDGET_DRAW, 0);
#endif
}
void
gauge_show (WGauge *g, int shown)
{
if (g->shown == shown)
return;
g->shown = shown;
#ifdef HAVE_X
x_gauge_show (g);
#else
gauge_callback (g->widget.parent, g, WIDGET_DRAW, 0);
#endif
}
static void
gauge_destroy (WGauge *g)
{
/* nothing */
}
WGauge *
gauge_new (int y, int x, int shown, int max, int current, char *tkname)
{
WGauge *g = xmalloc (sizeof (WGauge), "gauge_new");
init_widget (&g->widget, y, x, 1, gauge_len,
(callback_fn) gauge_callback,
(destroy_fn) gauge_destroy, NULL, tkname);
g->shown = shown;
if (max == 0)
max = 1; /* I do not like division by zero :) */
g->max = max;
g->current = current;
g->pixels = 0;
widget_want_cursor (g->widget, 0);
return g;
}
/* Input widget */
/* {{{ history button */
#define LARGE_HISTORY_BUTTON 1
#ifdef LARGE_HISTORY_BUTTON
# define HISTORY_BUTTON_WIDTH 3
#else
# define HISTORY_BUTTON_WIDTH 1
#endif
#define should_show_history_button(in) \
(in->history && in->field_len > HISTORY_BUTTON_WIDTH * 2 + 1 && in->widget.parent)
static void draw_history_button (WInput * in)
{
char c;
c = in->history->next ? (in->history->prev ? '|' : 'v') : '^';
widget_move (&in->widget, 0, in->field_len - HISTORY_BUTTON_WIDTH);
#ifdef LARGE_HISTORY_BUTTON
{
Dlg_head *h;
h = in->widget.parent;
#if 0
attrset (NORMALC); /* button has the same colour as other buttons */
addstr ("[ ]");
attrset (HOT_NORMALC);
#else
attrset (NORMAL_COLOR);
addstr ("[ ]");
/* Too distracting: attrset (MARKED_COLOR); */
#endif
widget_move (&in->widget, 0, in->field_len - HISTORY_BUTTON_WIDTH + 1);
addch (c);
}
#else
attrset (MARKED_COLOR);
addch (c);
#endif
}
/* }}} history button */
/* Input widgets now have a global kill ring */
/* Pointer to killed data */
static char *kill_buffer = 0;
void
update_input (WInput *in, int clear_first)
{
#ifndef HAVE_XVIEW
int has_history = 0;
int i, j;
char c;
int buf_len = strlen (in->buffer);
if (should_show_history_button (in))
has_history = HISTORY_BUTTON_WIDTH;
if (in->disable_update)
return;
/* Make the point visible */
if ((in->point < in->first_shown) ||
(in->point >= in->first_shown+in->field_len - has_history)){
in->first_shown = in->point - (in->field_len / 3);
if (in->first_shown < 0)
in->first_shown = 0;
}
/* Adjust the mark */
if (in->mark > buf_len)
in->mark = buf_len;
#ifdef HAVE_X
if (clear_first && in->first)
in->first = -1;
x_update_input (in);
#else
if (has_history)
draw_history_button (in);
attrset (in->color);
widget_move (&in->widget, 0, 0);
for (i = 0; i < in->field_len - has_history; i++)
addch (' ');
widget_move (&in->widget, 0, 0);
for (i = 0, j = in->first_shown; i < in->field_len - has_history && in->buffer [j]; i++){
c = in->buffer [j++];
c = is_printable (c) ? c : '.';
if (in->is_password)
c = '*';
addch (c);
}
widget_move (&in->widget, 0, in->point - in->first_shown);
if (clear_first)
in->first = 0;
#endif
#endif
}
void
winput_set_origin (WInput *in, int x, int field_len)
{
in->widget.x = x;
in->field_len = in->widget.cols = field_len;
update_input (in, 0);
}
/* {{{ history saving and loading */
/*
This loads and saves the history of an input line to and from the
widget. It is called with the widgets tk name on creation of the
widget, and returns the Hist list. It stores histories in the file
~/.mc/history in using the profile code.
If def_text is passed as INPUT_LAST_TEXT (to the input_new()
function) then input_new assigns the default text to be the last text
entered, or "" if not found.
*/
int num_history_items_recorded = 60;
Hist *history_get (char *input_name)
{
int i;
Hist *old = 0, *new = 0;
char *profile;
if (!num_history_items_recorded) /* this is how to disable */
return 0;
if (!input_name)
return 0;
if (!*input_name)
return 0;
profile = concat_dir_and_file (home_dir, HISTORY_FILE_NAME);
for (i = 0;; i++) {
char key_name[32];
char this_entry[1024];
sprintf (key_name, "%d", i);
GetPrivateProfileString (input_name, key_name, "", this_entry, sizeof (this_entry), profile);
if (!*this_entry)
break;
new = xmalloc (sizeof (Hist), "history_get");
memset (new, 0, sizeof (Hist));
new->text = strdup (this_entry);
new->prev = old; /* set up list pointers */
if (old)
old->next = new;
old = new;
}
free (profile);
return new; /* return pointer to last entry in list */
}
#ifdef PORT_WIDGET_WANTS_HISTORY
void history_put (char *input_name, Hist *h)
{
int i;
char *profile;
if (!input_name)
return;
if (!*input_name)
return;
if (!h)
return;
if (!num_history_items_recorded) /* this is how to disable */
return;
profile = concat_dir_and_file (home_dir, HISTORY_FILE_NAME);
while (h->next) /* go to end of list */
h = h->next;
/* go back 60 places */
for (i = 0; i < num_history_items_recorded - 1 && h->prev; i++)
h = h->prev;
i = 0;
if (input_name)
profile_clean_section (input_name, profile);
/* dump histories into profile */
while (h){
if (h->text){
/* probably aren't any null entries, but lets be sure */
if (*(h->text)){
char key_name[32];
sprintf (key_name, "%d", i++);
WritePrivateProfileString (input_name, key_name, h->text, profile);
}
}
h = h->next;
}
free (profile);
}
#else
void history_put (char *input_name, Hist *h)
{
}
#endif
/* }}} history saving and loading */
/* {{{ history display */
static const char history_title[] = " History ";
int history_callback (Dlg_head * h, int Par, int Msg)
{
#ifndef HAVE_X
switch (Msg) {
case DLG_DRAW:
attrset (COLOR_NORMAL);
dlg_erase (h);
draw_box (h, 0, 0, h->lines, h->cols);
attrset (COLOR_HOT_NORMAL);
dlg_move (h, 0, (h->cols - strlen (history_title)) / 2);
printw ((char *) history_title);
break;
}
#endif
return 0;
}
static inline int listbox_fwd (WListbox *l);
char *show_hist (Hist *history, int widget_x, int widget_y)
{
Hist *hi, *z;
int maxlen = strlen(history_title), i, count = 0;
int x, y, w, h;
char *q, *r = 0;
Dlg_head *query_dlg;
WListbox *query_list;
z = history;
if (!z)
return 0;
while (z->prev) /* goto first */
z = z->prev;
hi = z;
while (hi) {
if ((i = strlen (hi->text)) > maxlen)
maxlen = i;
count++;
hi = hi->next;
}
y = widget_y;
h = count + 2;
if (h <= y || y > LINES - 6)
{
h = min(h, y - 1);
y -= h;
}
else
{
y++;
h = min(h, LINES - y);
}
x = widget_x - 2;
if ((w = maxlen + 4) + x > COLS)
{
w = min(w,COLS);
x = COLS - w;
}
query_dlg = create_dlg (y, x, h, w, dialog_colors, history_callback,
"[History-query]", "history", DLG_NONE);
query_list = listbox_new (1, 1, w - 2, h - 2, listbox_finish, 0, NULL);
add_widget (query_dlg, query_list);
hi = z;
if (y < widget_y) {
while (hi) { /* traverse */
listbox_add_item (query_list, 0, 0, hi->text, NULL);
hi = hi->next;
}
while (listbox_fwd (query_list));
} else {
while (hi->next)
hi = hi->next;
while (hi) { /* traverse backwards */
listbox_add_item (query_list, 0, 0, hi->text, NULL);
hi = hi->prev;
}
}
run_dlg (query_dlg);
q = NULL;
if (query_dlg->ret_value != B_CANCEL) {
listbox_get_current (query_list, &q, NULL);
if (q)
r = strdup (q);
}
destroy_dlg (query_dlg);
return r;
}
static void do_show_hist (WInput * in)
{
char *r;
r = show_hist (in->history, in->widget.x, in->widget.y);
if (r) {
assign_text (in, r);
free (r);
}
}
/* }}} history display */
static void
input_destroy (WInput *in)
{
if (!in){
fprintf (stderr, "Internal error: null Input *\n");
exit (1);
}
new_input (in);
if (in->history){
Hist *current, *old;
if (!in->is_password && PORT_WIDGET_WANTS_HISTORY) /* don't save passwords ;-) */
history_put (in->history_name, in->history);
current = in->history;
while (current->next)
current = current->next;
while (current){
old = current;
current = current->prev;
free (old->text);
free (old);
}
}
x_destroy_cmd (in);
free (in->buffer);
free_completions (in);
if (in->history_name)
free (in->history_name);
}
static char disable_update = 0;
void
input_disable_update (WInput *in)
{
in->disable_update++;
}
void
input_enable_update (WInput *in)
{
in->disable_update--;
update_input (in, 0);
}
int
push_history (WInput *in, char *text)
{
Hist *new;
char *p;
for (p = text; *p == ' ' || *p == '\t'; p++);
if (!*p)
return 0;
if (in->history){
while (in->history->next)
in->history = in->history->next;
if (!strcmp (in->history->text, text))
return 1;
new = xmalloc (sizeof (Hist), "push_history");
in->history->next = new;
} else
new = xmalloc (sizeof (Hist), "push_history");
in->need_push = 0;
new->next = 0;
new->prev = in->history;
new->text = strdup (text);
in->history = new;
return 2;
}
/* Cleans the input line and adds the current text to the history */
void
new_input (WInput *in)
{
if (in->buffer)
push_history (in, in->buffer);
in->need_push = 1;
in->buffer [0] = 0;
in->point = 0;
in->mark = 0;
free_completions (in);
update_input (in, 0);
}
static int
insert_char (WInput *in, int c_code)
{
int i;
if (c_code == -1)
return 0;
in->need_push = 1;
if (strlen (in->buffer)+1 == in->current_max_len){
/* Expand the buffer */
char *narea = xmalloc(in->current_max_len + in->field_len, "string expansion");
if (narea){
char *p = in->buffer;
strcpy (narea, in->buffer);
in->buffer = narea;
in->current_max_len += in->field_len;
free (p);
}
}
if (strlen (in->buffer)+1 < in->current_max_len){
int l = strlen (&in->buffer [in->point]);
for (i = l+1; i > 0; i--)
in->buffer [in->point+i] = in->buffer [in->point+i-1];
in->buffer [in->point] = c_code;
in->point++;
}
return 1;
}
static void
beginning_of_line (WInput *in)
{
in->point = 0;
}
static void
end_of_line (WInput *in)
{
in->point = strlen (in->buffer);
}
static void
backward_char (WInput *in)
{
if (in->point)
in->point--;
}
static void
forward_char (WInput *in)
{
if (in->buffer [in->point])
in->point++;
}
static void
forward_word (WInput *in)
{
char *p = in->buffer+in->point;
while ((*p && isspace (*p)) || ispunct (*p))
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -