Mercurial > hg
view mcabber/src/screen.c @ 147:7571de4aed73
[/trunk] Changeset 159 by mikael
* Fix a bug in buddylist_build()
* We now lock the current buddy even not when being in chat mode.
For example, if we're writing to s.o. and he leaves just before
we press enter, we won't write to the wrong buddy...
If the current_buddy is a group, we lock it too.
* Remove MCABBER_TESTUNIT ifdef in roster.h (test program isn't
up-to-date anymore...)
author | mikael |
---|---|
date | Fri, 29 Apr 2005 19:56:28 +0000 |
parents | 300bb88f631f |
children | c3624b2a7059 |
line wrap: on
line source
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <ncurses.h> #include <panel.h> #include <time.h> #include <ctype.h> #include <locale.h> #include "screen.h" #include "hbuf.h" #include "commands.h" #include "compl.h" #include "roster.h" #include "parsecfg.h" #include "utils.h" #include "list.h" #define window_entry(n) list_entry(n, window_entry_t, list) LIST_HEAD(window_list); typedef struct _window_entry_t { WINDOW *win; PANEL *panel; char *name; GList *hbuf; GList *top; // If top is not specified (NULL), we'll display the last lines char cleared; // For ex, user has issued a /clear command... struct list_head list; } window_entry_t; static WINDOW *rosterWnd, *chatWnd, *inputWnd; static WINDOW *logWnd, *logWnd_border; static PANEL *rosterPanel, *chatPanel, *inputPanel; static PANEL *logPanel, *logPanel_border; static int maxY, maxX; static window_entry_t *currentWindow; static int chatmode; int update_roster; static char inputLine[INPUTLINE_LENGTH+1]; static char *ptr_inputline; static short int inputline_offset; static int completion_started; /* Functions */ int scr_WindowWidth(WINDOW * win) { int x, y; getmaxyx(win, y, x); return x; } void scr_clear_box(WINDOW *win, int y, int x, int height, int width, int Color) { int i, j; wattrset(win, COLOR_PAIR(Color)); for (i = 0; i < height; i++) { wmove(win, y + i, x); for (j = 0; j < width; j++) wprintw(win, " "); } } void scr_draw_box(WINDOW * win, int y, int x, int height, int width, int Color, chtype box, chtype border) { int i, j; wattrset(win, COLOR_PAIR(Color)); for (i = 0; i < height; i++) { wmove(win, y + i, x); for (j = 0; j < width; j++) if (!i && !j) waddch(win, border | ACS_ULCORNER); else if (i == height - 1 && !j) waddch(win, border | ACS_LLCORNER); else if (!i && j == width - 1) waddch(win, box | ACS_URCORNER); else if (i == height - 1 && j == width - 1) waddch(win, box | ACS_LRCORNER); else if (!i) waddch(win, border | ACS_HLINE); else if (i == height - 1) waddch(win, box | ACS_HLINE); else if (!j) waddch(win, border | ACS_VLINE); else if (j == width - 1) waddch(win, box | ACS_VLINE); else waddch(win, box | ' '); } } int FindColor(char *name) { if (!strcmp(name, "default")) return -1; if (!strcmp(name, "black")) return COLOR_BLACK; if (!strcmp(name, "red")) return COLOR_RED; if (!strcmp(name, "green")) return COLOR_GREEN; if (!strcmp(name, "yellow")) return COLOR_YELLOW; if (!strcmp(name, "blue")) return COLOR_BLUE; if (!strcmp(name, "magenta")) return COLOR_MAGENTA; if (!strcmp(name, "cyan")) return COLOR_CYAN; if (!strcmp(name, "white")) return COLOR_WHITE; return -1; } void ParseColors(void) { char *colors[11] = { "", "", "borderlines", "jidonline", "newmsg", "jidofflineselected", "jidoffline", "text", NULL }; char *tmp = malloc(1024); char *color1; char *background = cfg_read("color_background"); char *backselected = cfg_read("color_backselected"); int i = 0; while (colors[i]) { sprintf(tmp, "color_%s", colors[i]); color1 = cfg_read(tmp); switch (i + 1) { case 1: init_pair(1, COLOR_BLACK, COLOR_WHITE); break; case 2: init_pair(2, COLOR_WHITE, COLOR_BLACK); break; case 3: init_pair(3, FindColor(color1), FindColor(background)); break; case 4: init_pair(4, FindColor(color1), FindColor(backselected)); break; case 5: init_pair(5, FindColor(color1), FindColor(background)); break; case 6: init_pair(6, FindColor(color1), FindColor(backselected)); break; case 7: init_pair(7, FindColor(color1), FindColor(background)); break; case 8: init_pair(8, FindColor(color1), FindColor(background)); break; } i++; } } window_entry_t *scr_CreatePanel(const char *title, int x, int y, int lines, int cols, int dont_show) { window_entry_t *tmp = calloc(1, sizeof(window_entry_t)); tmp->win = newwin(lines, cols, y, x); tmp->panel = new_panel(tmp->win); tmp->name = (char *) calloc(1, 1024); strncpy(tmp->name, title, 1024); scr_clear_box(tmp->win, 0, 0, lines, cols, COLOR_GENERAL); if (!dont_show) { currentWindow = tmp; } else { if (currentWindow) top_panel(currentWindow->panel); else top_panel(chatPanel); } update_panels(); list_add_tail(&tmp->list, &window_list); return tmp; } window_entry_t *scr_SearchWindow(const char *winId) { struct list_head *pos, *n; window_entry_t *search_entry = NULL; list_for_each_safe(pos, n, &window_list) { search_entry = window_entry(pos); if (search_entry->name) { if (!strcasecmp(search_entry->name, winId)) { return search_entry; } } } return NULL; } // scr_UpdateWindow() // (Re-)Display the given chat window. void scr_UpdateWindow(window_entry_t *win_entry) { int n; int width; char **lines; GList *hbuf_head; width = scr_WindowWidth(win_entry->win); // Should the window be empty? if (win_entry->cleared) { scr_clear_box(win_entry->win, 0, 0, CHAT_WIN_HEIGHT, width, COLOR_GENERAL); return; } // win_entry->top is the top message of the screen. If it set to NULL, we // are displaying the last messages. // We will show the last CHAT_WIN_HEIGHT lines. // Let's find out where it begins. if (!win_entry->top || (g_list_position(g_list_first(win_entry->hbuf), win_entry->top) == -1)) { // Move up CHAT_WIN_HEIGHT lines win_entry->hbuf = g_list_last(win_entry->hbuf); hbuf_head = win_entry->hbuf; win_entry->top = NULL; // (Just to make sure) n = 0; while (hbuf_head && (n < CHAT_WIN_HEIGHT-1) && g_list_previous(hbuf_head)) { hbuf_head = g_list_previous(hbuf_head); n++; } } else hbuf_head = win_entry->top; // Get the last CHAT_WIN_HEIGHT lines. lines = hbuf_get_lines(hbuf_head, CHAT_WIN_HEIGHT); // Display these lines wmove(win_entry->win, 0, 0); for (n = 0; n < CHAT_WIN_HEIGHT; n++) { int r = width; if (*(lines+2*n)) { if (**(lines+2*n)) wprintw(win_entry->win, "%s", *(lines+2*n)); // prefix else { wprintw(win_entry->win, " "); r -= 12; } wprintw(win_entry->win, "%s", *(lines+2*n+1)); // line // Calculate the number of blank characters to empty the line r -= strlen(*(lines+2*n)) + strlen(*(lines+2*n+1)); } for ( ; r>0 ; r--) { wprintw(win_entry->win, " "); } //// wclrtoeol(win_entry->win); does not work :( } g_free(lines); } // scr_ShowWindow() // Display the chat window with the given identifier. void scr_ShowWindow(const char *winId) { window_entry_t *win_entry = scr_SearchWindow(winId); if (win_entry != NULL) { top_panel(win_entry->panel); currentWindow = win_entry; chatmode = TRUE; roster_setflags(winId, ROSTER_FLAG_MSG, FALSE); roster_setflags(winId, ROSTER_FLAG_LOCK, TRUE); update_roster = TRUE; // Refresh the window scr_UpdateWindow(win_entry); // Finished :) update_panels(); doupdate(); } else { top_panel(chatPanel); currentWindow = win_entry; // == NULL (current window empty) } top_panel(inputPanel); } // scr_ShowBuddyWindow() // Display the chat window buffer for the current buddy. void scr_ShowBuddyWindow(void) { const gchar *jid; if (!current_buddy) jid = NULL; else jid = CURRENT_JID; if (!jid) { top_panel(chatPanel); top_panel(inputPanel); currentWindow = NULL; return; } scr_ShowWindow(jid); } // scr_WriteInWindow() // Write some text in the winId window (this usually is a jid). // Lines are splitted when they are too long to fit in the chat window. // If this window doesn't exist, it is created. void scr_WriteInWindow(const char *winId, const char *text, int TimeStamp, const char *prefix, int force_show) { char *fullprefix = NULL; window_entry_t *win_entry; int dont_show = FALSE; // Prepare the prefix if (prefix || TimeStamp) { if (!prefix) prefix = ""; fullprefix = calloc(1, strlen(prefix)+16); if (TimeStamp) { time_t now = time(NULL); strftime(fullprefix, 12, "[%H:%M] ", localtime(&now)); } else { strcpy(fullprefix, " "); } strcat(fullprefix, prefix); } // Look for the window entry. win_entry = scr_SearchWindow(winId); // Do we have to really show the window? if (!chatmode) dont_show = TRUE; else if ((!force_show) && ((!currentWindow || (currentWindow != win_entry)))) dont_show = TRUE; // If the window entry doesn't exist yet, let's create it. if (win_entry == NULL) { win_entry = scr_CreatePanel(winId, ROSTER_WIDTH, 0, CHAT_WIN_HEIGHT, maxX - ROSTER_WIDTH, dont_show); } hbuf_add_line(&win_entry->hbuf, text, fullprefix, maxX - scr_WindowWidth(rosterWnd) - 14); free(fullprefix); if (win_entry->cleared) { win_entry->cleared = 0; // The message must be displayed win_entry->top = g_list_last(win_entry->hbuf); } if (!dont_show) { // Show and refresh the window top_panel(win_entry->panel); scr_UpdateWindow(win_entry); top_panel(inputPanel); update_panels(); doupdate(); } else { roster_setflags(winId, ROSTER_FLAG_MSG, TRUE); update_roster = TRUE; } } void scr_InitCurses(void) { initscr(); noecho(); raw(); halfdelay(5); start_color(); use_default_colors(); ParseColors(); getmaxyx(stdscr, maxY, maxX); inputLine[0] = 0; ptr_inputline = inputLine; setlocale(LC_CTYPE, ""); return; } void scr_TerminateCurses(void) { clear(); refresh(); endwin(); return; } void scr_DrawMainWindow(void) { int l; /* Draw main panels */ rosterWnd = newwin(CHAT_WIN_HEIGHT, ROSTER_WIDTH, 0, 0); rosterPanel = new_panel(rosterWnd); scr_clear_box(rosterWnd, 0, 0, CHAT_WIN_HEIGHT, ROSTER_WIDTH, COLOR_GENERAL); for (l=0 ; l < CHAT_WIN_HEIGHT ; l++) mvwaddch(rosterWnd, l, ROSTER_WIDTH-1, ACS_VLINE); chatWnd = newwin(CHAT_WIN_HEIGHT, maxX - ROSTER_WIDTH, 0, ROSTER_WIDTH); chatPanel = new_panel(chatWnd); scr_clear_box(chatWnd, 0, 0, CHAT_WIN_HEIGHT, maxX - ROSTER_WIDTH, COLOR_GENERAL); scrollok(chatWnd, TRUE); mvwprintw(chatWnd, 0, 0, "This is the status window"); logWnd_border = newwin(LOG_WIN_HEIGHT, maxX, CHAT_WIN_HEIGHT, 0); logPanel_border = new_panel(logWnd_border); scr_draw_box(logWnd_border, 0, 0, LOG_WIN_HEIGHT, maxX, COLOR_GENERAL, 0, 0); logWnd = derwin(logWnd_border, LOG_WIN_HEIGHT-2, maxX-2, 1, 1); logPanel = new_panel(logWnd); wbkgd(logWnd, COLOR_PAIR(COLOR_GENERAL)); scrollok(logWnd, TRUE); inputWnd = newwin(1, maxX, maxY-1, 0); inputPanel = new_panel(inputWnd); scr_DrawRoster(); return; } // scr_DrawRoster() // Actually, display the buddylist on the screen. void scr_DrawRoster(void) { static guint offset = 0; char name[ROSTER_WIDTH]; int maxx, maxy; GList *buddy; int i, n; int rOffset; // We can reset update_roster update_roster = FALSE; getmaxyx(rosterWnd, maxy, maxx); maxx --; // last char is for vertical border name[ROSTER_WIDTH-7] = 0; // cleanup of roster window wattrset(rosterWnd, COLOR_PAIR(COLOR_GENERAL)); for (i = 0; i < maxy; i++) { mvwprintw(rosterWnd, i, 0, ""); for (n = 0; n < maxx; n++) waddch(rosterWnd, ' '); } // Leave now if buddylist is empty if (!buddylist) { offset = 0; update_panels(); doupdate(); return; } // Update offset if necessary i = g_list_position(buddylist, current_buddy); if (i == -1) { // This is bad scr_LogPrint("Doh! Can't find current selected buddy!!"); update_panels(); doupdate(); return; } else if (i < offset) { offset = i; } else if (i+1 > offset + maxy) { offset = i + 1 - maxy; } buddy = buddylist; rOffset = offset; for (i=0; i<maxy && buddy; buddy = g_list_next(buddy)) { char status = '?'; char pending = ' '; enum imstatus budstate; if (rOffset > 0) { rOffset--; continue; } if (buddy_getflags(BUDDATA(buddy)) & ROSTER_FLAG_MSG) { pending = '#'; } budstate = buddy_getstatus(BUDDATA(buddy)); if (budstate >= 0 && budstate < imstatus_size) status = imstatus2char[budstate]; if (buddy == current_buddy) { wattrset(rosterWnd, COLOR_PAIR(COLOR_BD_DESSEL)); // The 3 following lines aim to color the whole line wmove(rosterWnd, i, 0); for (n = 0; n < maxx; n++) waddch(rosterWnd, ' '); } else { if (buddy_getflags(BUDDATA(buddy)) & ROSTER_FLAG_MSG) wattrset(rosterWnd, COLOR_PAIR(COLOR_NMSG)); else wattrset(rosterWnd, COLOR_PAIR(COLOR_BD_DES)); } strncpy(name, buddy_getname(BUDDATA(buddy)), ROSTER_WIDTH-7); if (buddy_gettype(BUDDATA(buddy)) & ROSTER_TYPE_GROUP) { char *sep; if (buddy_getflags(BUDDATA(buddy)) & ROSTER_FLAG_HIDE) sep = "+++"; else sep = "---"; mvwprintw(rosterWnd, i, 0, " %c%s %s", pending, sep, name); } else mvwprintw(rosterWnd, i, 0, " %c[%c] %s", pending, status, name); i++; } top_panel(inputPanel); update_panels(); doupdate(); } void scr_WriteMessage(const char *jid, const char *text, char *prefix) { scr_WriteInWindow(jid, text, TRUE, prefix, FALSE); } void scr_WriteIncomingMessage(const char *jidfrom, const char *text) { // FIXME expand tabs / filter out special chars... scr_WriteMessage(jidfrom, text, "<== "); update_panels(); doupdate(); } void scr_WriteOutgoingMessage(const char *jidto, const char *text) { scr_WriteMessage(jidto, text, "--> "); scr_ShowWindow(jidto); } int scr_Getch(void) { int ch; ch = wgetch(inputWnd); return ch; } WINDOW *scr_GetRosterWindow(void) { return rosterWnd; } WINDOW *scr_GetStatusWindow(void) { return chatWnd; } WINDOW *scr_GetInputWindow(void) { return inputWnd; } // scr_RosterTop() // Go to the first buddy in the buddylist void scr_RosterTop(void) { enum imstatus prev_st = imstatus_size; // undef if (current_buddy) { prev_st = buddy_getstatus(BUDDATA(current_buddy)); if (chatmode) buddy_setflags(BUDDATA(current_buddy), ROSTER_FLAG_LOCK, FALSE); } current_buddy = buddylist; if (chatmode && current_buddy) buddy_setflags(BUDDATA(current_buddy), ROSTER_FLAG_LOCK, TRUE); // We should rebuild the buddylist but not everytime // Here we check if we were locking a buddy who is actually offline, // and hide_offline_buddies is TRUE. In which case we need to rebuild. if (current_buddy && prev_st == offline && buddylist_get_hide_offline_buddies()) buddylist_build(); if (chatmode) scr_ShowBuddyWindow(); update_roster = TRUE; } // scr_RosterBottom() // Go to the last buddy in the buddylist void scr_RosterBottom(void) { enum imstatus prev_st = imstatus_size; // undef if (current_buddy) { prev_st = buddy_getstatus(BUDDATA(current_buddy)); if (chatmode) buddy_setflags(BUDDATA(current_buddy), ROSTER_FLAG_LOCK, FALSE); } current_buddy = g_list_last(buddylist); // Lock the buddy in the buddylist if we're in chat mode if (chatmode && current_buddy) buddy_setflags(BUDDATA(current_buddy), ROSTER_FLAG_LOCK, TRUE); // We should rebuild the buddylist but not everytime // Here we check if we were locking a buddy who is actually offline, // and hide_offline_buddies is TRUE. In which case we need to rebuild. if (current_buddy && prev_st == offline && buddylist_get_hide_offline_buddies()) buddylist_build(); if (chatmode) scr_ShowBuddyWindow(); update_roster = TRUE; } // scr_RosterUp() // Go to the previous buddy in the buddylist void scr_RosterUp(void) { enum imstatus prev_st = imstatus_size; // undef if (current_buddy) { if (g_list_previous(current_buddy)) { prev_st = buddy_getstatus(BUDDATA(current_buddy)); buddy_setflags(BUDDATA(current_buddy), ROSTER_FLAG_LOCK, FALSE); current_buddy = g_list_previous(current_buddy); // Lock the buddy in the buddylist if we're in chat mode if (chatmode) buddy_setflags(BUDDATA(current_buddy), ROSTER_FLAG_LOCK, TRUE); // We should rebuild the buddylist but not everytime // Here we check if we were locking a buddy who is actually offline, // and hide_offline_buddies is TRUE. In which case we need to rebuild. if (prev_st == offline && buddylist_get_hide_offline_buddies()) buddylist_build(); update_roster = TRUE; } } if (chatmode) scr_ShowBuddyWindow(); } // scr_RosterDown() // Go to the next buddy in the buddylist void scr_RosterDown(void) { enum imstatus prev_st = imstatus_size; // undef if (current_buddy) { if (g_list_next(current_buddy)) { prev_st = buddy_getstatus(BUDDATA(current_buddy)); buddy_setflags(BUDDATA(current_buddy), ROSTER_FLAG_LOCK, FALSE); current_buddy = g_list_next(current_buddy); if (chatmode) buddy_setflags(BUDDATA(current_buddy), ROSTER_FLAG_LOCK, TRUE); // We should rebuild the buddylist but not everytime // Here we check if we were locking a buddy who is actually offline, // and hide_offline_buddies is TRUE. In which case we need to rebuild. if (prev_st == offline && buddylist_get_hide_offline_buddies()) buddylist_build(); update_roster = TRUE; } } if (chatmode) scr_ShowBuddyWindow(); } // scr_ScrollUp() // Scroll up the current buddy window, half a screen. void scr_ScrollUp(void) { const gchar *jid; window_entry_t *win_entry; int n, nblines; GList *hbuf_top; // Get win_entry if (!current_buddy) return; jid = CURRENT_JID; if (!jid) return; win_entry = scr_SearchWindow(jid); if (!win_entry) return; // Scroll up half a screen (or less) nblines = CHAT_WIN_HEIGHT/2-1; hbuf_top = win_entry->top; if (!hbuf_top) { hbuf_top = g_list_last(win_entry->hbuf); if (!win_entry->cleared) nblines *= 3; else win_entry->cleared = FALSE; } n = 0; while (hbuf_top && n < nblines && g_list_previous(hbuf_top)) { hbuf_top = g_list_previous(hbuf_top); n++; } win_entry->top = hbuf_top; // Refresh the window scr_UpdateWindow(win_entry); // Finished :) update_panels(); doupdate(); } // scr_ScrollDown() // Scroll down the current buddy window, half a screen. void scr_ScrollDown(void) { const gchar *jid; window_entry_t *win_entry; int n, nblines; GList *hbuf_top; // Get win_entry if (!current_buddy) return; jid = CURRENT_JID; if (!jid) return; win_entry = scr_SearchWindow(jid); if (!win_entry) return; // Scroll down half a screen (or less) nblines = CHAT_WIN_HEIGHT/2-1; hbuf_top = win_entry->top; for (n=0 ; hbuf_top && n < nblines ; n++) hbuf_top = g_list_next(hbuf_top); win_entry->top = hbuf_top; // Check if we are at the bottom for (n=0 ; hbuf_top && n < CHAT_WIN_HEIGHT-1 ; n++) hbuf_top = g_list_next(hbuf_top); if (!hbuf_top) win_entry->top = NULL; // End reached // Refresh the window scr_UpdateWindow(win_entry); // Finished :) update_panels(); doupdate(); } // scr_Clear() // Clear the current buddy window (used for the /clear command) void scr_Clear(void) { const gchar *jid; window_entry_t *win_entry; // Get win_entry if (!current_buddy) return; jid = CURRENT_JID; if (!jid) return; win_entry = scr_SearchWindow(jid); if (!win_entry) return; win_entry->cleared = TRUE; win_entry->top = NULL; // Refresh the window scr_UpdateWindow(win_entry); // Finished :) update_panels(); doupdate(); } // scr_LogPrint(...) // Display a message in the log window. void scr_LogPrint(const char *fmt, ...) { time_t timestamp; char *buffer; va_list ap; buffer = (char *) calloc(1, 4096); timestamp = time(NULL); strftime(buffer, 64, "[%H:%M:%S] ", localtime(×tamp)); wprintw(logWnd, "\n%s", buffer); va_start(ap, fmt); vsnprintf(buffer, 4096, fmt, ap); va_end(ap); wprintw(logWnd, "%s", buffer); free(buffer); update_panels(); doupdate(); } // scr_set_chatmode() // Public fonction to (un)set chatmode... inline void scr_set_chatmode(int enable) { chatmode = enable; } // which_row() // Tells which row our cursor is in, in the command line. // -1 -> normal text // 0 -> command // 1 -> parameter 1 (etc.) // If > 0, then *p_row is set to the beginning of the row int which_row(char **p_row) { int row = -1; char *p; int quote = FALSE; // Not a command? if ((ptr_inputline == inputLine) || (inputLine[0] != '/')) return -1; // This is a command row = 0; for (p = inputLine ; p < ptr_inputline ; p++) { if (quote) { if (*p == '"' && *(p-1) != '\\') quote = FALSE; continue; } if (*p == '"' && *(p-1) != '\\') { quote = TRUE; } else if (*p == ' ') { if (*(p-1) != ' ') row++; *p_row = p+1; } } return row; } // scr_insert_text() // Insert the given text at the current cursor position. // The cursor is moved. We don't check if the cursor still is in the screen // after, the caller should do that. void scr_insert_text(const char *text) { char tmpLine[INPUTLINE_LENGTH+1]; int len = strlen(text); // Check the line isn't too long if (strlen(inputLine) + len >= INPUTLINE_LENGTH) { scr_LogPrint("Cannot insert text, line too long."); return; } strcpy(tmpLine, ptr_inputline); strcpy(ptr_inputline, text); ptr_inputline += len; strcpy(ptr_inputline, tmpLine); } // scr_handle_tab() // Function called when tab is pressed. // Initiate or continue a completion... void scr_handle_tab(void) { int nrow; char *row; const char *cchar; guint compl_categ; nrow = which_row(&row); // a) No completion if no leading slash ('cause not a command) // b) We can't have more than 2 parameters (we use 2 flags) if (nrow < 0 || nrow > 2) return; if (nrow == 0) { // Command completion row = &inputLine[1]; compl_categ = COMPL_CMD; } else { // Other completion, depending on the command cmd *com = cmd_get(inputLine); if (!com || !row) { scr_LogPrint("I cannot complete that..."); return; } compl_categ = com->completion_flags[nrow-1]; } if (!completion_started) { GSList *list = compl_get_category_list(compl_categ); if (list) { char *prefix = g_strndup(row, ptr_inputline-row); // Init completion new_completion(prefix, list); g_free(prefix); // Now complete cchar = complete(); if (cchar) scr_insert_text(cchar); completion_started = TRUE; } } else { // Completion already initialized char *c; guint back = cancel_completion(); // Remove $back chars ptr_inputline -= back; c = ptr_inputline; for ( ; *c ; c++) *c = *(c+back); // Now complete again cchar = complete(); if (cchar) scr_insert_text(cchar); } } void scr_cancel_current_completion(void) { char *c; guint back = cancel_completion(); // Remove $back chars ptr_inputline -= back; c = ptr_inputline; for ( ; *c ; c++) *c = *(c+back); } void scr_end_current_completion(void) { done_completion(); completion_started = FALSE; } // check_offset(int direction) // Check inputline_offset value, and make sure the cursor is inside the // screen. inline void check_offset(int direction) { // Left side if (inputline_offset && direction <= 0) { while (ptr_inputline <= (char*)&inputLine + inputline_offset) { if (inputline_offset) { inputline_offset -= 5; if (inputline_offset < 0) inputline_offset = 0; } } } // Right side if (direction >= 0) { while (ptr_inputline >= inputline_offset + (char*)&inputLine + maxX) inputline_offset += 5; } } // process_key(key) // Handle the pressed key, in the command line (bottom). int process_key(int key) { if (isprint(key)) { char tmpLine[INPUTLINE_LENGTH+1]; // Check the line isn't too long if (strlen(inputLine) >= INPUTLINE_LENGTH) return 0; // Insert char strcpy(tmpLine, ptr_inputline); *ptr_inputline++ = key; strcpy(ptr_inputline, tmpLine); check_offset(1); } else { switch(key) { case KEY_BACKSPACE: if (ptr_inputline != (char*)&inputLine) { char *c = --ptr_inputline; for ( ; *c ; c++) *c = *(c+1); check_offset(-1); } break; case KEY_DC: if (*ptr_inputline) strcpy(ptr_inputline, ptr_inputline+1); break; case KEY_LEFT: if (ptr_inputline != (char*)&inputLine) { ptr_inputline--; check_offset(-1); } break; case KEY_RIGHT: if (*ptr_inputline) ptr_inputline++; check_offset(1); break; case 7: // Ctrl-g scr_cancel_current_completion(); scr_end_current_completion(); check_offset(-1); break; case 9: // Tab scr_handle_tab(); check_offset(0); break; case '\n': // Enter if (process_line(inputLine)) return 255; ptr_inputline = inputLine; *ptr_inputline = 0; inputline_offset = 0; break; case KEY_UP: scr_RosterUp(); break; case KEY_DOWN: scr_RosterDown(); break; case KEY_PPAGE: scr_ScrollUp(); break; case KEY_NPAGE: scr_ScrollDown(); break; case KEY_HOME: case 1: ptr_inputline = inputLine; inputline_offset = 0; break; case KEY_END: case 5: for (; *ptr_inputline; ptr_inputline++) ; check_offset(1); break; case 21: // Ctrl-u strcpy(inputLine, ptr_inputline); ptr_inputline = inputLine; inputline_offset = 0; break; case KEY_EOL: case 11: // Ctrl-k *ptr_inputline = 0; break; case 16: // Ctrl-p scr_LogPrint("Ctrl-p not yet implemented"); break; case 14: // Ctrl-n scr_LogPrint("Ctrl-n not yet implemented"); break; case 27: // ESC currentWindow = NULL; chatmode = FALSE; if (current_buddy) buddy_setflags(BUDDATA(current_buddy), ROSTER_FLAG_LOCK, FALSE); top_panel(chatPanel); top_panel(inputPanel); break; default: scr_LogPrint("Unkown key=%d", key); } } if (completion_started && key != 9) scr_end_current_completion(); mvwprintw(inputWnd, 0,0, "%s", inputLine + inputline_offset); wclrtoeol(inputWnd); if (*ptr_inputline) { wmove(inputWnd, 0, ptr_inputline - (char*)&inputLine - inputline_offset); } update_panels(); doupdate(); return 0; }