From 5e112e69e589ee812f87b7496e2f325be513e2f7 Mon Sep 17 00:00:00 2001
From: Frederic Culot <calcurse@culot.org>
Date: Sat, 28 Oct 2006 09:57:07 +0000
Subject: getstring() improved to allow the modification of an existing string
 shwostring(), showcursor(), del_char() and add_char() created

---
 src/utils.c | 173 +++++++++++++++++++++++++++++++++++++++++++++++++-----------
 1 file changed, 142 insertions(+), 31 deletions(-)

(limited to 'src')

diff --git a/src/utils.c b/src/utils.c
index 20d036e..561bbcc 100755
--- a/src/utils.c
+++ b/src/utils.c
@@ -1,4 +1,4 @@
-/*	$calcurse: utils.c,v 1.10 2006/09/17 10:45:06 culot Exp $	*/
+/*	$calcurse: utils.c,v 1.11 2006/10/28 09:57:07 culot Exp $	*/
 
 /*
  * Calcurse - text-based organizer
@@ -116,49 +116,160 @@ print_in_middle(WINDOW * win, int starty, int startx, int width, char *string)
 	custom_remove_attr(win, ATTR_HIGHEST);
 }
 
+/* Delete a character at the given position in string. */
+void del_char(int pos, char *str)
+{
+	str += pos;
+	for (; *str; ++str)
+		*str = *(str + 1);
+	*str = 0;
+}
+
+/* Add a character at the given position in string. */
+char *add_char(int pos, int ch, char *str)
+{
+	int new, buf;
+
+	str += pos;
+	buf = *str; 
+	*str++ = ch; 
+	new = buf;
+	for (; *str; ++str) {
+		buf = *str;
+		*str = new;
+		new = buf;
+	}	
+	*str++ = new;
+	return str;
+}
+
+/* 
+ * Draw the cursor at the correct position in string.
+ * As echoing is not set, we need to know the string we are working on to 
+ * handle display correctly.
+ */
+void showcursor(WINDOW *win, int y, int pos, char *str, int l, int offset)
+{
+	char *nc;
+
+	nc = str + pos;
+	wmove(win, y, pos - offset);
+	(pos >= l) ? waddch(win, SPC|A_REVERSE) : waddch(win, *nc|A_REVERSE);
+}
+
+/* Print the string at the desired position. */
+void showstring(WINDOW *win, int y, int x, char *str, int len, int pos)
+{
+	const int rec = 30, border = 3;
+	const int max_col = col - border, max_len = max_col - rec;
+	int page, max_page, offset, c = 0;
+	char *orig;
+
+	orig = str;
+	max_page = (len - rec) / max_len;
+ 	page = (pos - rec) / max_len;
+	offset = page * max_len;
+	str += offset;
+	mvwaddnstr(win, y, x, str, MIN(len, max_col));
+	wclrtoeol(win);
+	if (page > 0 && page < max_page) {
+		c = '*';
+	} else if (page > 0) {
+		c = '<';
+	} else if (page < max_page) {
+		c = '>';
+	} else
+		c = 0;
+	mvwprintw(win, y, col - 1, "%c", c);
+	showcursor(win, y, pos, orig, len, offset);
+}
+
 /* 
  * Getstring allows to get user input and to print it on a window,
- * even if noecho() is on.
+ * even if noecho() is on. This function is also used to modify an existing
+ * text (the variable string can be non-NULL).
+ * We need to do the echoing manually because of the multi-threading
+ * environment, otherwise the cursor would move from place to place without
+ * control.
  */
-void getstring(win, colr, string, start_x, start_y)
-WINDOW *win;
-int colr;
-char *string;
-int start_x, start_y;
+int getstring(WINDOW *win, int colr, char *string, int x, int y)
 {
-	int ch;
-	int charcount = 0;
+	int ch, newpos, len = 0;
+	char *orig;
 
+	orig = string;
 	custom_apply_attr(win, ATTR_HIGHEST);
-	if (start_x != -1)
-		wmove(win, start_y, start_x);
-
+	for (; *string; ++string, ++len);
+	newpos = x + len;
+	showstring(win, y, x, orig, len, newpos);
+	
 	while ((ch = wgetch(win)) != '\n') {
-	        if ((ch == KEY_BACKSPACE) || 
-				(ch == 330) ||
-				(ch == 263) || 
-				(ch == 127) ||
-				(ch == CTRL('H')) ) {
-			if (charcount > 0) {
-				string--;
-				charcount--;
-				wmove(win, start_y, start_x + charcount);
-				waddch(win, ' ');
-				wmove(win, start_y, start_x + charcount);
+	
+		switch (ch) {
+
+		case KEY_BACKSPACE: 	/* delete one character */
+		case 330:
+		case 127:
+		case CTRL('H'):
+			if (len > 0) { 
+				--newpos; --len;
+				if (newpos >= x + len)
+					--string;
+				else  /* to be deleted inside string */
+					del_char(newpos, orig);
 			}
-		} else if (ch == ESCAPE) {
-			*string = NULL;
-			return;
-		} else {
-			*string++ = ch;
-			charcount++;
-			waddch(win, ch);
+			break;
+
+		case CTRL('D'):		/* delete next character */
+			--len;
+			del_char(newpos, orig);
+			break;
+
+		case CTRL('K'):		/* delete to end-of-line */
+			string = orig + newpos;
+			for (; *string; ++string)
+				*string = 0;
+			len -= (len - newpos);
+			break;
+
+		case CTRL('A'): 	/* go to begginning of string */
+			newpos = x;
+			break;
+
+		case CTRL('E'): 	/* go to end of string */
+			newpos = x + len;
+			break;
+
+		case KEY_LEFT: 		/* move one char backward  */
+		case CTRL('B'):
+			if (newpos > x) newpos--;
+			break;
+	
+		case KEY_RIGHT: 	/* move one char forward */
+		case CTRL('F'):
+			if (newpos < len) newpos++; 
+			break;
+		
+		case ESCAPE: 		/* cancel editing */
+			return 1;	
+			break;
+
+		default: 		/* insert one character */
+			if (len < MAX_LENGTH - 1) {
+				if (newpos >= len)
+					*string++ = ch;
+				else  	// char is to be inserted inside string	
+					string = add_char(newpos, ch, orig);	
+				++len; ++newpos;
+			}
+
 		}
+		showstring(win, y, x, orig, len, newpos);
 		doupdate();
 	}
 	*string = 0;
 	custom_remove_attr(win, ATTR_HIGHEST);
-	return;
+	return 0;
 }
 
 /* checks if a string is only made of digits */
-- 
cgit v1.2.3-70-g09d2