From a2ee75888739b66b3bd20d2a1f1e465947f1fbc4 Mon Sep 17 00:00:00 2001 From: Joursoir Date: Sun, 22 Nov 2020 18:46:56 +0300 Subject: add chat move, fix some bugs --- src/client/clui.cpp | 141 ++++++++++++++++++++++++++++++++++++++-------------- src/client/clui.hpp | 21 +++++++- src/client/user.cpp | 86 ++++++++++++++++---------------- src/client/user.hpp | 13 +++-- 4 files changed, 175 insertions(+), 86 deletions(-) diff --git a/src/client/clui.cpp b/src/client/clui.cpp index 4ae6a5a..e0b528b 100644 --- a/src/client/clui.cpp +++ b/src/client/clui.cpp @@ -1,33 +1,42 @@ #include #include +#include #include "clui.hpp" -#define CHAT_WIDTH 20 -#define CHAT_HEIGHT 59 +#define CHAT_HEIGHT 20 +#define CHAT_WIDTH 59 #define PLAYERS_WIDTH 20 #define PLAYERS_HEIGHT 20 -#define INPUT_WIDTH 4 -#define INPUT_HEIGHT 80 +#define INPUT_HEIGHT 4 +#define INPUT_WIDTH 80 -#define MAXLEN_MSG 158 +const int maxlen_msg_input = (INPUT_WIDTH - 2) * 2; +const int maxlen_msg_chat = (CHAT_WIDTH - 4) * 2; Interface_wc::Interface_wc(int num_y, int num_x, int by, - int bx, char ch) + int bx, char ch) : ny(num_y), nx(num_x), beg_y(by), + beg_x(bx), ch_line(ch) { - w = newwin(num_y, num_x, by, bx); - box(w, ch, ch); + w = newwin(ny, nx, beg_y, beg_x); + box(w, ch_line, ch_line); this->Update(); } void Interface_wc::Hide() { - werase(this->GetWindow()); // clear - + this->Clear(true); this->Update(); this->Delete(); } +void Interface_wc::Clear(bool full) +{ + werase(this->GetWindow()); + if(!full) + box(this->GetWindow(), ch_line, ch_line); +} + //////////////////////////////////////////////////////////////////////// SelectionMenu::SelectionMenu(char const *i_title, const char**i_choises, int choises_num, @@ -71,27 +80,13 @@ int SelectionMenu::Handling() //////////////////////////////////////////////////////////////////////// -ChatRoom::ChatRoom() +ChatRoom::ChatRoom() : first(0) { - chat = new Interface_wc(CHAT_WIDTH, CHAT_HEIGHT, 0, 0, 0); - players = new Interface_wc(PLAYERS_WIDTH, PLAYERS_HEIGHT, 0, 60, 0); - input = new Interface_wc(INPUT_WIDTH, INPUT_HEIGHT, 20, 0, 0); + chat = new Interface_wc(CHAT_HEIGHT, CHAT_WIDTH, 0, 0, 0); + players = new Interface_wc(PLAYERS_HEIGHT, PLAYERS_WIDTH, 0, 60, 0); + input = new Interface_wc(INPUT_HEIGHT, INPUT_WIDTH, 20, 0, 0); i_nx = 1; i_ny = 1; - - /* WINDOW *newwin(int nlines, int ncols, int begin_y, int begin_x) */ - /*WINDOW *chat = newwin(20, 59, 0, 0); - box(chat, 0, 0); - wrefresh(chat); - - WINDOW *players = newwin(20, 20, 0, 60); - box(players, 0, 0); - wrefresh(players); - - WINDOW *input = newwin(4, 80, 20, 0); - box(input, 0, 0); - wmove(input, 1, 1); - wrefresh(input);*/ } ChatRoom::~ChatRoom() @@ -102,27 +97,92 @@ ChatRoom::~ChatRoom() delete players; if(input) delete input; + + // #TODO: + /* if(first) ... delete message */ } -void ChatRoom::PrintMessage(const char *msg) +void ChatRoom::AddMessage(char *msg) { - // если msg <= **, то одна строка - // иначе 2 строки - WINDOW *win = chat->GetWindow(); - wmove(win, 1, 2); - wprintw(win, msg); + message *recent_msg = new message; + + int lines = 1; + if(strlen(msg) > maxlen_msg_chat/2) + lines = 2; + + strcpy(recent_msg->msg, msg); + recent_msg->num_lines = lines; + + recent_msg->prev = first; + first = recent_msg; + + ChatRedraw(); +} + +void ChatRoom::ChatRedraw() +{ + if(!first) + return; + + /*wprintw(chat->GetWindow(), "redraw"); + chat->Update(); + sleep(3);*/ + + chat->Clear(false); + int available_lines = CHAT_HEIGHT - 2; + bool remove = 0; + message *tmp; + + for(tmp = first; tmp; tmp = tmp->prev) { + if(available_lines >= tmp->num_lines) { + PrintMessage(available_lines, tmp); + available_lines -= tmp->num_lines; + } + // #TODO: + /* delete */ + + } chat->Update(); } +void ChatRoom::PrintMessage(int line, message *m) +{ + WINDOW *win = this->GetChatWin(); + if(m->num_lines == 1) { + wmove(win, line, 2); + wprintw(win, m->msg); + } + else { + wmove(win, line-1, 2); + // print a half of message: + int len_fline = maxlen_msg_chat/2; + + + char *temp = new char[len_fline+1]; + // memccpy(void *restrict s1, const void *restrict s2, int c, size_t n); + memcpy(temp, m->msg, sizeof(char) * len_fline); + temp[len_fline] = '\0'; + wprintw(win, temp); + + int last_len_msg = strlen(m->msg) - len_fline; + memcpy(temp, m->msg, sizeof(char) * (last_len_msg+1)); + temp[last_len_msg] = '\0'; + wmove(win, line, 2); + wprintw(win, temp); + + delete[] temp; + } +} + bool ChatRoom::AddCharToSendMsg(char ch) { - if(i_ny == 2 && i_nx == MAXLEN_MSG/2-1) + if(i_ny == 2 && i_nx == maxlen_msg_input/2-1) return 0; mvwaddch(input->GetWindow(), i_ny, i_nx, ch); i_nx++; - if(i_nx >= MAXLEN_MSG/2) { + if(i_nx >= maxlen_msg_input/2-1) { if(i_ny == 1) { i_ny++; i_nx = 1; @@ -144,11 +204,18 @@ bool ChatRoom::RemoveCharFromMsg() i_nx--; if(i_nx < 1) { i_ny--; - i_nx = MAXLEN_MSG/2-1; + i_nx = maxlen_msg_input/2-1; } mvwaddch(input->GetWindow(), i_ny, i_nx, ' '); wmove(input->GetWindow(), i_ny, i_nx); input->Update(); return 1; +} + +void ChatRoom::SetInputCursor(int y, int x) +{ + input->SetCursor(y, x); + i_ny = y; + i_nx = x; } \ No newline at end of file diff --git a/src/client/clui.hpp b/src/client/clui.hpp index ff447ef..3ebefda 100644 --- a/src/client/clui.hpp +++ b/src/client/clui.hpp @@ -9,10 +9,13 @@ class Interface_wc { WINDOW *w; int ny, nx; int beg_y, beg_x; + int ch_line; public: Interface_wc(int num_y, int num_x, int by, int bx, char ch); WINDOW *GetWindow() { return w; } + void SetCursor(int y, int x) { wmove(w, y, x); } + void Clear(bool full); void Update() { wrefresh(w); } void Delete() { delwin(w); } @@ -37,12 +40,19 @@ class ChatRoom { Interface_wc *players; Interface_wc *input; int i_nx, i_ny; + + struct message { + char msg[300]; + int num_lines; // number of lines + message *prev; + }; + message *first; public: ChatRoom(); ~ChatRoom(); // for chat: - void PrintMessage(const char *msg); + void AddMessage(char *msg); // for players: //void AddPlayer() @@ -50,8 +60,15 @@ public: // for input: bool AddCharToSendMsg(char ch); bool RemoveCharFromMsg(); + void InputClear() { input->Clear(false); } + void SetInputCursor(int y, int x); - WINDOW *GetWin() { return input->GetWindow(); } + WINDOW *GetInputWin() { return input->GetWindow(); } + WINDOW *GetChatWin() { return chat->GetWindow(); } +private: + // for chat: + void ChatRedraw(); + void PrintMessage(int line, message *m); }; #endif \ No newline at end of file diff --git a/src/client/user.cpp b/src/client/user.cpp index 1a60891..85b626e 100644 --- a/src/client/user.cpp +++ b/src/client/user.cpp @@ -41,82 +41,82 @@ Client *Client::Start(const char* ip, int port) void Client::Run(ChatRoom *room) { - /*int fd_stdin = STDIN_FILENO; - const int flags = fcntl(fd_stdin, F_GETFL, 0); - fcntl(fd_stdin, F_SETFL, flags | O_NONBLOCK);*/ - - const int flags = fcntl(fd, F_GETFL, 0); + unsigned int usecs = 0125000; + int flags = fcntl(fd, F_GETFL, 0); fcntl(fd, F_SETFL, flags | O_NONBLOCK); - nodelay(room->GetWin(), true); + nodelay(room->GetInputWin(), true); curs_set(true); do { this->HandleButton(room); int recive = read(fd, out_buffer, sizeof(out_buffer)); + if(recive < 0) { - if(errno == EINTR || errno == EAGAIN) continue; - else break; + if(errno != EINTR && errno != EAGAIN) + break; } else if(recive > 0) { - room->PrintMessage(out_buffer); + room->AddMessage(out_buffer); } - unsigned int usecs = 0125000; usleep(usecs); - - /*struct timeval timeout = { 0 }; - timeout.tv_usec = 5000000; - - fd_set rds, wrs; - FD_ZERO(&rds); - FD_ZERO(&wrs); - - FD_SET(fd, &rds); - - int val = read(fd_stdin, buffer, sizeof(buffer)); - if(val > 0) FD_SET(fd_stdin, &wrs); - - res = select(fd+1, &rds, &wrs, 0, &timeout); - if(res < 0) { - if(errno == EINTR) continue; - else break; - } - else if(res > 0) { - if(FD_ISSET(fd_stdin, &wrs)) // if client want to send any message - { - if(buffer[0] == '#') // exit - exit_flag = true; - else write(fd, buffer, strlen(buffer)*sizeof(char)); - } - if(FD_ISSET(fd, &rds)) // if server want to send any message - { - read(fd, buffer, sizeof(buffer)); - //getchar(); - } - }*/ } while (!exit_flag); } void Client::HandleButton(ChatRoom *room) { - int key = wgetch(room->GetWin()); + int key = wgetch(room->GetInputWin()); switch(key) { // ascii table 32...126 case ' '...'~': { + AddCharToBuffer(key); room->AddCharToSendMsg(key); break; } case '\n': { // send message - // some code + SendMessage(); + room->InputClear(); + room->SetInputCursor(1, 1); break; } case key_backspace: { + RemoveCharFromBuffer(); room->RemoveCharFromMsg(); break; } default: break; } +} + +void Client::AddCharToBuffer(char ch) +{ + if(in_buf_used >= max_line_length-2) // we reserve 1 byte for '\0' + return; + + in_buffer[in_buf_used] = ch; + in_buf_used++; +} + +void Client::RemoveCharFromBuffer() +{ + if(in_buf_used <= 0) + return; + + in_buffer[in_buf_used] = '\0'; + in_buf_used--; +} + +void Client::SendMessage() +{ + if(in_buf_used <= 0) + return; + + in_buffer[in_buf_used] = '\n'; + // if(max_line_length-2 < 0) + write(fd, in_buffer, (in_buf_used+1)*sizeof(char)); + memset(in_buffer, 0, sizeof(in_buffer)); + in_buf_used = 0; } \ No newline at end of file diff --git a/src/client/user.hpp b/src/client/user.hpp index a6e6c15..45fb5e3 100644 --- a/src/client/user.hpp +++ b/src/client/user.hpp @@ -8,14 +8,15 @@ const int max_line_length = 156; class Client { int fd; char in_buffer[max_line_length]; // мы готовим к отправке - char in_buf_used; + int in_buf_used; + char out_buffer[max_line_length]; // нам пришло - char out_buf_used; - bool ignoring; + int out_buf_used; + bool exit_flag; Client(int i_fd) - : fd(i_fd), in_buf_used(0), out_buf_used(0), ignoring(false) { } + : fd(i_fd), in_buf_used(0), out_buf_used(0) { } public: ~Client() { close(fd); } @@ -23,6 +24,10 @@ public: void Run(ChatRoom *room); void HandleButton(ChatRoom *room); + void AddCharToBuffer(char ch); + void RemoveCharFromBuffer(); + void SendMessage(); + int getFd() const { return fd; } // not used }; -- cgit v1.2.3-18-g5258