X-Git-Url: https://git.ucc.asn.au/?a=blobdiff_plain;f=Usermode%2FApplications%2Firc_src%2Fwindow.c;h=ba12880c1f3f33efd9fb15d4e9985adea070b06f;hb=13078002b01ee4f63eb2001d2ef479a2a006ea32;hp=1314cec3405ed5036567110474189ddedec47414;hpb=4e407e69bd660e9a32644281733192193ee6e8c8;p=tpg%2Facess2.git diff --git a/Usermode/Applications/irc_src/window.c b/Usermode/Applications/irc_src/window.c index 1314cec3..ba12880c 100644 --- a/Usermode/Applications/irc_src/window.c +++ b/Usermode/Applications/irc_src/window.c @@ -7,6 +7,8 @@ #include // TODO: replace with calls into ACurses_* #include #include +#include "server.h" +#include struct sMessage { @@ -14,6 +16,7 @@ struct sMessage time_t Timestamp; enum eMessageClass Class; char *Source; // Pointer to the end of `Data` + size_t PrefixLen; char Data[]; }; @@ -28,12 +31,16 @@ struct sWindow // === PROTOTYPES === void Windows_RepaintCurrent(void); +size_t WordBreak(const char *Line, size_t avail); +size_t Windows_int_PaintMessagePrefix(const tMessage *Message, bool EnablePrint); +size_t Windows_int_PaintMessageLine(const tMessage *Message, size_t Offset, bool EnablePrint); + int Windows_int_GetMessageLines(const tMessage *Message); int Windows_int_PaintMessage(tMessage *Message); // === GLOBALS === tWindow gWindow_Status = { NULL, NULL, NULL, // No next, empty list, no server - 0, {""} // No activity, empty name (rendered as status) + 0, {"(status)"} // No activity, empty name (rendered as status) }; tWindow *gpWindows = &gWindow_Status; tWindow *gpCurrentWindow = &gWindow_Status; @@ -41,59 +48,142 @@ tWindow *gpCurrentWindow = &gWindow_Status; // === CODE === void Windows_RepaintCurrent(void) { - tMessage *msg = gpCurrentWindow->Messages; - // TODO: Title bar? + SetCursorPos(1, 1); + printf("\x1b[37;44m\x1b[2K%s\x1b[0m\n", gpCurrentWindow->Name); + + int avail_rows = giTerminal_Height - 3; // Note: This renders from the bottom up - for( int y = giTerminal_Height - 1; y -- && msg; msg = msg->Next) + tMessage *msg = gpCurrentWindow->Messages; + for( int y = avail_rows; msg && y > 0; ) { - y -= Windows_int_PaintMessage(msg); + int lines = Windows_int_GetMessageLines(msg); + y -= lines; + size_t ofs = 0; + size_t len; + int i = 0; + do { + SetCursorPos(2 + y+i, 1); + len = Windows_int_PaintMessageLine(msg, ofs, (y+i >= 0)); + ofs += len; + i ++; + } while( len > 0 ); + msg = msg->Next; } + // Status line is our department + SetCursorPos(giTerminal_Height-1, 1); + printf("\x1b[37;44m\x1b[2K[%s] [%s/%s]\x1b[0m", Server_GetNick(gpCurrentWindow->Server), + Server_GetName(gpCurrentWindow->Server), gpCurrentWindow->Name); + fflush(stdout); // Bottom line is rendered by the prompt +} + +size_t WordBreak(const char *Line, size_t avail) +{ + // If sufficient space, don't need to break on a word + if( strlen(Line) < avail ) + return strlen(Line); + + // Search backwards from end of space for a non-alpha-numeric character + size_t ret = avail-1; + while( ret > 0 && isalnum(Line[ret]) ) + ret --; + + // if one wasn't found in a sane area, just split + if( ret < avail-20 || ret == 0 ) + return avail; + return ret; } -int Windows_int_PaintMessage(tMessage *Message) +size_t Windows_int_PaintMessagePrefix(const tMessage *Message, bool EnablePrint) { - printf("\33[T"); // Scroll down 1 (free space below) - SetCursorPos(giTerminal_Height-2, 1); + size_t len = 0; + + unsigned long seconds_today = Message->Timestamp/1000 % (24 * 3600); + if(EnablePrint) + printf("%02i:%02i:%02i ", seconds_today/3600, (seconds_today/60)%60, seconds_today%60); + else + len += snprintf(NULL, 0, "%02i:%02i:%02i ", seconds_today/3600, (seconds_today/60)%60, seconds_today%60); - size_t prefixlen = 0; - prefixlen += printf("%02i:%02i:%02i ", (Message->Timestamp/3600)%24, (Message->Timestamp/60)%60, Message->Timestamp%60); + const char *format; switch(Message->Class) { - case MSG_CLASS_BARE: break; + case MSG_CLASS_BARE: + format = ""; + break; case MSG_CLASS_CLIENT: if(Message->Source) - prefixlen += printf("[%s] ", Message->Source); - prefixlen += printf("-!- "); + format = "[%s] -!- "; + else + format = "-!- "; break; case MSG_CLASS_WALL: - prefixlen += printf("[%s] ", Message->Source); + format = "[%s] "; break; case MSG_CLASS_MESSAGE: - prefixlen += printf("<%s> ", Message->Source); + format = "<%s> "; break; case MSG_CLASS_ACTION: - prefixlen += printf("* %s ", Message->Source); + format = "* %s "; break; } - int avail = giTerminal_Width - prefixlen; - int msglen = strlen(Message->Data); - - int nLines = 1; - printf("%.*s", avail, Message); - while( msglen > avail ) { - msglen -= avail; - Message += avail; - printf("\33[T"); - SetCursorPos(giTerminal_Height-2, prefixlen+1); - printf("%.*s", avail, Message); - nLines ++; + + if( EnablePrint ) + len += printf(format, Message->Source); + else + len += snprintf(NULL, 0, format, Message->Source); + + return len; +} + +size_t Windows_int_PaintMessageLine(const tMessage *Message, size_t Offset, bool EnablePrint) +{ + _SysDebug("Windows_int_PaintMessageLine: Message=%p,Offset=%i,EnablePrint=%b", + Message, (int)Offset, EnablePrint); + if( Offset > strlen(Message->Data) ) { + _SysDebug("Windows_int_PaintMessageLine: No message left"); + return 0; } + _SysDebug("Windows_int_PaintMessageLine: Message->Data=\"%.*s\"+\"%s\"", + (int)Offset, Message->Data, Message->Data+Offset); + size_t avail = giTerminal_Width - Message->PrefixLen; + const char *msg_data = Message->Data + Offset; + int used = WordBreak(msg_data, avail); + + if( EnablePrint ) + { + if( Offset == 0 ) + Windows_int_PaintMessagePrefix(Message, true); + else { + for(int i = 0; i < Message->PrefixLen; i ++) + printf(" "); + //printf("\x1b[%iC", Message->PrefixLen); + } + printf("%.*s", used, msg_data); + } + + _SysDebug("used(%i) >= strlen(msg_data)(%i)", used, strlen(msg_data)); + if( used >= strlen(msg_data) ) + return 0; + + return Offset + used; +} + +int Windows_int_GetMessageLines(const tMessage *Message) +{ + assert(Message->PrefixLen); + const size_t avail = giTerminal_Height - Message->PrefixLen; + const size_t msglen = strlen(Message->Data); + size_t offset = 0; + int nLines = 0; + do { + offset += WordBreak(Message->Data+offset, avail); + nLines ++; + } while(offset < msglen); return nLines; } @@ -203,10 +293,18 @@ void Window_AppendMessage(tWindow *Window, enum eMessageClass Class, const char msg->Class = Class; msg->Source = (Source ? msg->Data + len+1 : NULL); + msg->Timestamp = _SysTimestamp(); + va_start(args, Message); vsnprintf(msg->Data, len+1, Message, args); va_end(args); + if( Source ) { + strcpy(msg->Source, Source); + } + + msg->PrefixLen = Windows_int_PaintMessagePrefix(msg, false); + msg->Next = Window->Messages; Window->Messages = msg; @@ -215,8 +313,15 @@ void Window_AppendMessage(tWindow *Window, enum eMessageClass Class, const char // Scroll if needed, and redraw? // - Lazy option of draw at bottom of screen printf("\33[s"); // Save cursor - Windows_int_PaintMessage(msg); - printf("\x1b[u"); // Restore cursor + size_t offset = 0, len; + do { + printf("\33[S"); // Scroll down 1 (free space below) + SetCursorPos(giTerminal_Height-2, 1); + len = Windows_int_PaintMessageLine(msg, offset, true); + offset += len; + } while( len > 0 ); + printf("\33[u"); // Restore cursor + fflush(stdout); } } @@ -240,4 +345,14 @@ void Window_AppendMsg_TopicTime(tWindow *Window, const char *User, const char *T { Window_AppendMessage(Window, MSG_CLASS_CLIENT, NULL, "Topic set by %s at %s", User, Timestamp); } +void Window_AppendMsg_Kick(tWindow *Window, const char *Operator, const char *Nick, const char *Reason) +{ + Window_AppendMessage(Window, MSG_CLASS_CLIENT, NULL, "%s was kicked from %s by %s [%s]", + Nick, Window->Name, Operator, Reason); +} +void Window_AppendMsg_Mode(tWindow *Window, const char *Operator, const char *Flags, const char *Args) +{ + Window_AppendMessage(Window, MSG_CLASS_CLIENT, NULL, "mode/%s [%s %s] by %s", + Window->Name, Flags, Args, Operator); +}