jcs
/wallops
/amendments
/53
chatter: Improve re-drawing
jcs made amendment 53 3 months 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