jcs
/wallops
/amendments
/53
chatter: Improve re-drawing
jcs made amendment 53 about 1 year ago
--- chatter.c	Tue Jan 17 23:18:38 2023
+++ chatter.c	Fri Aug 30 16:38:16 2024
@@ -31,6 +31,8 @@ static Pattern tab_bar_pattern;
 
 void chatter_layout(struct chatter *chatter, bool init, Rect *init_bounds);
 void chatter_draw_tab_bar(struct chatter *chatter);
+void chatter_layout_tab(struct chatter *chatter, struct chatter_tab *tab,
+  Rect *win_bounds, bool init);
 void chatter_focus_tab(struct chatter *chatter, struct chatter_tab *tab);
 void chatter_draw_grow_icon(struct chatter *chatter);
 void chatter_autoscroll(struct chatter *chatter, TEHandle te,
@@ -52,7 +54,7 @@ struct chatter_tab * chatter_find_tab_for_conn_and_cha
 struct chatter *
 chatter_init(const char *server, const unsigned short port,
   const char *password, const char *nick, const char *ident,
-  const char *realname, const char *channel)
+  const char *realname, bool hide_motd, const char *channel)
 {
 	struct focusable *focusable;
 	struct chatter *chatter;
@@ -63,14 +65,23 @@ chatter_init(const char *server, const unsigned short 
 
 	GetIndPattern(&tab_bar_pattern, sysPatListID, 23);
 	
-	chatter = xmalloczero(sizeof(struct chatter), "chatter");
+	chatter = xmalloczero(sizeof(struct chatter));
+	if (chatter == NULL)
+		return NULL;
 	SLIST_INIT(&chatter->tabs_list);
 
+	focusable = xmalloczero(sizeof(struct focusable));
+	if (focusable == NULL) {
+		xfree(&chatter);
+		return NULL;
+	}
+	
 	bounds.left = padding;
 	bounds.top = screenBits.bounds.top + padding +
 	  (GetMBarHeight() * 2) - 1;
 	bounds.right = screenBits.bounds.right - padding - 1;
-	bounds.bottom = screenBits.bounds.bottom - padding - 1;
+//	bounds.bottom = screenBits.bounds.bottom - padding - 1;
+	bounds.bottom = (screenBits.bounds.bottom / 2) - padding - 1;
 	
 	snprintf(title, sizeof(title), "%s: Disconnected", PROGRAM_NAME);
 	chatter->win = NewWindow(0L, &bounds, CtoPstr(title), false,
@@ -87,7 +98,6 @@ chatter_init(const char *server, const unsigned short 
 	bounds.top = bounds.left = 0;
 	chatter_layout(chatter, true, &bounds);
 
-	focusable = xmalloczero(sizeof(struct focusable), "focusable");
 	focusable->win = chatter->win;
 	focusable->cookie = chatter;
 	focusable->wait_type = chatter_wait_type;
@@ -111,9 +121,10 @@ chatter_init(const char *server, const unsigned short 
 
 	tab = SLIST_FIRST(&chatter->tabs_list);
 	tab->conn = irc_connect(chatter, server, port, password, nick, ident,
-	  realname, channel);
+	  realname, hide_motd, channel);
 	DrawControls(chatter->win);
 	chatter_update_titlebar(chatter);
+	chatter_draw_tab_bar(chatter);
 	
 	ValidRect(&bounds);
 
@@ -171,7 +182,9 @@ chatter_layout(struct chatter *chatter, bool init, Rec
 	if (init) {
 		chatter_add_tab(chatter, win_bounds, NULL, NULL);
 	} else {
-		/* TODO: move tabs around */
+		SLIST_FOREACH(tab, &chatter->tabs_list, list) {
+			chatter_layout_tab(chatter, tab, win_bounds, false);
+		}
 	}
 }
 
@@ -188,12 +201,31 @@ chatter_add_tab(struct chatter *chatter, Rect *win_bou
 	if (win_bounds == NULL)
 		win_bounds = &chatter->win->portRect;
 
-	tab = xmalloczero(sizeof(struct chatter_tab), "tab");
+	tab = xmalloczero(sizeof(struct chatter_tab));
 	SLIST_APPEND(&chatter->tabs_list, tab, chatter_tab, list);
 	tab->index = chatter->ntabs++;
 	tab->conn = conn;
 	tab->channel = channel;
+
+	chatter_layout_tab(chatter, tab, win_bounds, true);
 	
+	chatter_focus_tab(chatter, tab);
+	
+	return tab;
+}
+
+void
+chatter_layout_tab(struct chatter *chatter, struct chatter_tab *tab,
+  Rect *win_bounds, bool init)
+{
+	Rect bounds, inset_bounds;
+	Rect data_bounds = { 0, 0, 0, 1 }; /* tlbr */
+	Point cell_size = { 0 };
+	Cell cell = { 0, 0 };
+	
+	if (win_bounds == NULL)
+		win_bounds = &chatter->win->portRect;
+
 	bounds.bottom = (*(chatter->input_te))->viewRect.top - 15;
 
 	if (tab->channel) {
@@ -201,12 +233,18 @@ chatter_add_tab(struct chatter *chatter, Rect *win_bou
 		bounds.top = 0;
 		bounds.right = win_bounds->right - SCROLLBAR_WIDTH + 1;
 		bounds.left = bounds.right - NICK_LIST_WIDTH;
-		tab->nick_list = LNew(&bounds, &data_bounds, cell_size, 0,
-		  chatter->win, true, true, false, true);
-		if (!tab->nick_list)
-			panic("Can't create nick list");
-		LAddColumn(1, 0, tab->nick_list);
-		(*(tab->nick_list))->selFlags = lOnlyOne | lNoNilHilite;
+		if (init) {
+			tab->nick_list = LNew(&bounds, &data_bounds, cell_size, 0,
+			  chatter->win, true, true, false, true);
+			if (!tab->nick_list)
+				panic("Can't create nick list");
+			LAddColumn(1, 0, tab->nick_list);
+			(*(tab->nick_list))->selFlags = lOnlyOne | lNoNilHilite;
+		} else {
+			(*(tab->nick_list))->rView = bounds;
+			LSize(bounds.right - bounds.left, bounds.bottom - bounds.top,
+			  tab->nick_list);
+		}
 	}
 	
 	/* messages scrollbar */
@@ -217,9 +255,15 @@ chatter_add_tab(struct chatter *chatter, Rect *win_bou
 		bounds.right = win_bounds->right + 1;
 	bounds.left = bounds.right - SCROLLBAR_WIDTH;
 	bounds.bottom += 1;
-	tab->messages_scroller = NewControl(chatter->win, &bounds, "\p", true,
-	  1, 1, 1, scrollBarProc, 0L);
-
+	if (init)
+		tab->messages_scroller = NewControl(chatter->win, &bounds,
+		  "\p", true, 1, 1, 1, scrollBarProc, 0L);
+	else {
+		MoveControl(tab->messages_scroller, bounds.left, bounds.top);
+		SizeControl(tab->messages_scroller, bounds.right - bounds.left,
+		  bounds.bottom - bounds.top);
+	}
+	
 	/* messages */
 	bounds.right = (*(tab->messages_scroller))->contrlRect.left;
 	bounds.left = 0;
@@ -227,21 +271,24 @@ chatter_add_tab(struct chatter *chatter, Rect *win_bou
 	bounds.bottom -= 1;
 	inset_bounds = bounds;
 	InsetRect(&inset_bounds, 4, 4);
-	tab->messages_te = TEStylNew(&inset_bounds, &bounds);
-	(*(tab->messages_te))->caretHook = NullCaretHook;
-	TEActivate(tab->messages_te);
-	chatter_autoscroll(chatter, tab->messages_te, tab->messages_scroller);
-
-	chatter_focus_tab(chatter, tab);
-	
-	return tab;
+	if (init) {
+		tab->messages_te = TEStylNew(&inset_bounds, &bounds);
+		(*(tab->messages_te))->caretHook = NullCaretHook;
+		TEActivate(tab->messages_te);
+		chatter_autoscroll(chatter, tab->messages_te,
+		  tab->messages_scroller);
+	} else {
+		(*(tab->messages_te))->viewRect = bounds;
+		(*(tab->messages_te))->destRect = inset_bounds;
+		TECalText(tab->messages_te);
+	}
 }
 
 void
 chatter_focus_tab(struct chatter *chatter, struct chatter_tab *tab)
 {
 	RgnHandle clip;
-	Rect zerorect = { 0, 0, 0, 0 }, r;
+	Rect r;
 
 	if (chatter->current_tab) {
 		if (chatter->current_tab == tab)
@@ -254,19 +301,26 @@ chatter_focus_tab(struct chatter *chatter, struct chat
 		GetClip(clip = NewRgn());
 		r.left = 0;
 		r.top = 0;
-		r.right =
-		  (*(chatter->current_tab->messages_scroller))->contrlRect.right;
-		r.bottom =
-		   (*(chatter->current_tab->messages_scroller))->contrlRect.bottom
+		r.bottom = (*(chatter->current_tab->messages_scroller))->contrlRect.bottom
 		   - 1;
+		if (chatter->current_tab->nick_list)
+			r.right = (*(chatter->current_tab->nick_list))->rView.right;
+		else
+			r.right = (*(chatter->current_tab->messages_scroller))->contrlRect.right;
 		ClipRect(&r);
 		
+		FillRect(&r, white);
 		TEDeactivate(chatter->current_tab->messages_te);
 		if (chatter->current_tab->nick_list)
 			LDoDraw(false, chatter->current_tab->nick_list);
+		
+		/* HideControl will flash, clip it out */
+		r.right = 0;
+		ClipRect(&r);
 		HideControl(chatter->current_tab->messages_scroller);
 		
 		SetClip(clip);
+		DisposeRgn(clip);
 	}
 	
 	chatter->current_tab = tab;
@@ -372,13 +426,22 @@ chatter_idle(struct focusable *focusable, EventRecord 
 {
 	struct chatter *chatter = (struct chatter *)(focusable->cookie);
 	struct chatter_tab *tab;
-	short n;
+	short n, was_state;
+	bool redraw = false;
 	
 	TEIdle(chatter->input_te);
 	
 	SLIST_FOREACH(tab, &chatter->tabs_list, list) {
+		was_state = tab->conn->state;
+		
 		irc_process(tab->conn);
+		
+		if (tab->conn->state != was_state)
+			redraw = true;
 	}
+	
+	if (redraw)
+		chatter_draw_tab_bar(chatter);
 }
 
 void
@@ -457,7 +520,7 @@ chatter_draw_tab_bar(struct chatter *chatter)
 		width = chatter->win->portRect.right - chatter->win->portRect.left;
 		chatter->tab_bar.rowBytes = (((width - 1) / 16) + 1) * 2;
 		chatter->tab_bar.baseAddr = xmalloczero(
-		  chatter->tab_bar.rowBytes * TAB_BAR_HEIGHT, "tab_bar");
+		  chatter->tab_bar.rowBytes * TAB_BAR_HEIGHT);
 		SetRect(&chatter->tab_bar.bounds, 0, 0, width, TAB_BAR_HEIGHT);
 	}
 	
@@ -704,12 +767,15 @@ chatter_resize(struct focusable *focusable, EventRecor
 	width = LoWord(newsize);
 	SizeWindow(focusable->win, width, height, true);
 	EraseRect(&chatter->win->portRect);
+	InvalRect(&chatter->win->portRect);
 	
 	/* chatter_draw_tab_bar will recreate this to the new size */
 	if (chatter->tab_bar.baseAddr)
 		xfree(&chatter->tab_bar.baseAddr);
 		
 	chatter_layout(chatter, false, NULL);
+	chatter_update(focusable, NULL);
+	ValidRect(&chatter->win->portRect);
 }
 
 bool
@@ -759,8 +825,9 @@ chatter_key_down(struct focusable *focusable, EventRec
 		te = *(chatter->input_te);
 		HLock(te->hText);
 		(*(te->hText))[te->teLength] = '\0';
-		input = xstrdup(*(te->hText), "input");
+		input = xstrdup(*(te->hText));
 		TESetText(&k, 0, chatter->input_te);
+		TEScroll(0, 0, chatter->input_te);
 		EraseRect(&te->viewRect);
 		ValidRect(&te->viewRect);
 		TEIdle(chatter->input_te);
@@ -988,7 +1055,9 @@ void
 chatter_remove_channel(struct chatter *chatter,
   struct irc_channel *channel)
 {
+	RgnHandle clip;
 	struct chatter_tab *tab = NULL, *ttab = NULL, *next_tab = NULL;
+	Rect r;
   	short n;
 	
 	SLIST_FOREACH(ttab, &chatter->tabs_list, list) {
@@ -1001,10 +1070,26 @@ chatter_remove_channel(struct chatter *chatter,
 	}
 	
 	if (tab != NULL) {
+		GetClip(clip = NewRgn());
+
+		r.left = 0;
+		r.top = 0;
+		r.bottom = (*(tab->messages_scroller))->contrlRect.bottom - 1;
+		if (tab->nick_list)
+			r.right = (*(tab->nick_list))->rView.right;
+		else
+			r.right = (*(tab->messages_scroller))->contrlRect.right;
+
+		ClipRect(&r);
+
+		FillRect(&r, white);
 		LDispose(tab->nick_list);
 		DisposeControl(tab->messages_scroller);
 		TEDispose(tab->messages_te);
 		SLIST_REMOVE(&chatter->tabs_list, tab, chatter_tab, list);
+
+		SetClip(clip);
+		DisposeRgn(clip);
 		
 		if (chatter->current_tab == tab)
 			chatter->current_tab = NULL;
@@ -1102,4 +1187,22 @@ chatter_insert_to_nick_list(struct chatter *chatter,
 	j += strlcpy(tnick.nick + j, nick->nick, sizeof(tnick.nick) - j);
 	LAddRow(1, cell.v, tab->nick_list);
 	LSetCell(&tnick.nick, j, cell, tab->nick_list);
-}
+}
+
+void
+chatter_remove_from_nick_list(struct chatter *chatter,
+  struct irc_channel *channel, struct irc_channel_nick *nick, short pos)
+{
+	struct chatter_tab *tab;
+	
+	tab = chatter_find_tab_for_conn_and_channel(chatter,
+	  channel->connection, channel);
+	if (!tab)
+		return;
+	
+	if (pos == -1) {
+		/* TODO: find nick in list */
+	}
+	
+	LDelRow(1, pos, tab->nick_list);
+}
\ No newline at end of file