aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md5
-rwxr-xr-xbuild.sh21
-rw-r--r--chatty.c65
-rw-r--r--ui.h110
4 files changed, 123 insertions, 78 deletions
diff --git a/README.md b/README.md
index 74554de..fa561b6 100644
--- a/README.md
+++ b/README.md
@@ -60,3 +60,8 @@ The idea is the following:
- *unicode and wide characters*: [C for dummies](https://c-for-dummies.com/blog/?p=2578)
- *sockets*: [Nir Lichtman - Making Minimalist Chat Server in C on Linux](https://www.youtube.com/watch?v=gGfTjKwLQxY)
- syscall manpages `man`
+
+- https://www.youtube.com/watch?v=wvtFGa6XJDU
+- https://nullprogram.com/blog/2023/02/11/
+- https://nullprogram.com/blog/2023/02/13/
+- https://nullprogram.com/blog/2023/10/08/
diff --git a/build.sh b/build.sh
index 4548af8..9d69974 100755
--- a/build.sh
+++ b/build.sh
@@ -1,17 +1,6 @@
#!/bin/sh
-build () {
- (
- set -x
- gcc -ggdb -Wall -pedantic -std=c99 -I./external -o ${1%.c} $@
- )
-}
-
-if [ "$1" ]; then
- build "$1"
- exit
-fi
-
-[ -x ./external/keyboard ] || build external/keyboard.c
-build chatty.c
-build server.c
-build send.c
+set -x
+gcc external/keyboard.c
+gcc -DDEBUG -ggdb -Wall -pedantic -std=c99 -o chatty chatty.c
+gcc -DDEBUG -ggdb -Wall -pedantic -std=c99 -o server server.c
+gcc -DDEBUG -ggdb -Wall -pedantic -std=c99 -o send send.c
diff --git a/chatty.c b/chatty.c
index 9dcc2b0..ae7929f 100644
--- a/chatty.c
+++ b/chatty.c
@@ -22,8 +22,6 @@
// Number of spaces inserted when pressing Tab/Ctrl+I
#define TAB_WIDTH 4
-#define DEBUG
-
#include "chatty.h"
#include "protocol.h"
#include "ui.h"
@@ -278,21 +276,49 @@ run_command_get_output(char *Command, char *Argv[], u8 *OutputBuffer, int Len)
// it displays a prompt with the user input of input_len wide characters
// and the received messages from msgsArena
void
-screen_home(Arena* ScratchArena,
+DisplayChat(Arena* ScratchArena,
Arena* MessagesArena, u32 MessagesNum,
Arena* ClientsArena, struct pollfd* fds,
wchar_t Input[], u32 InputLen)
{
- u32 BoxHeight = 3;
+#define MIN_TEXT_WIDTH_FOR_WRAPPING 20
+ u32 BoxHeight = GetInputBoxMinimumHeight();
+ u32 MinBoxWidth = GetInputBoxMinimumWidth();
+
u32 BoxWidth = global.width - 1;
+ u32 InputBoxTextWidth = BoxWidth - MinBoxWidth + 2;
- if (global.height < BoxHeight ||
- global.width < 8)
+ if (InputLen >= InputBoxTextWidth &&
+ InputBoxTextWidth > MIN_TEXT_WIDTH_FOR_WRAPPING)
+ {
+ BoxHeight++;
+ }
+
+ u32 FreeHeight = global.height - BoxHeight;
+
+#undef MIN_TEXT_WIDTH_FOR_WRAPPING
+
+ if (global.height < BoxHeight || global.width < MinBoxWidth)
{
tb_hide_cursor();
return;
}
+ bytebuf_puts(&global.out, global.caps[TB_CAP_SHOW_CURSOR]);
+ InputBox(0, FreeHeight, BoxWidth, BoxHeight,
+ Input, InputLen,
+ True);
+
+ // Print vertical bar
+ s32 VerticalBarOffset = TIMESTAMP_LEN + AUTHOR_LEN + 2;
+ for (u32 Y = 0; Y < FreeHeight; Y++)
+ tb_print(VerticalBarOffset, Y, 0, 0, "│");
+
+ // show error popup if server disconnected
+ if (fds[FDS_UNI].fd == -1 || fds[FDS_BI].fd == -1)
+ {
+ popup(TB_RED, TB_BLACK, (u8*)"Server disconnected.");
+ }
// Print messages in msgsArena, if there are too many to display, start printing from an offset.
// Looks like this:
@@ -301,11 +327,9 @@ screen_home(Arena* ScratchArena,
// 03:24:33 [TlasT] │ I am fine
// 03:24:33 [Fin] │ I am too
{
- s32 VerticalBarOffset = TIMESTAMP_LEN + AUTHOR_LEN + 2;
- u32 FreeHeight = global.height - BoxHeight;
- if (FreeHeight <= 0)
- goto draw_prompt;
+ // If there is not enough space to draw, do not draw
+ if (FreeHeight <= 0) return;
// Used to go to the next message in MessagesArena by incrementing with the messages' size.
u8* MessageAddress = MessagesArena->addr;
@@ -441,22 +465,6 @@ screen_home(Arena* ScratchArena,
}
}
- // Print vertical bar
- for (u32 Y = 0; Y < FreeHeight; Y++)
- tb_print(VerticalBarOffset, Y, 0, 0, "│");
-
- draw_prompt:
- InputBox(0, FreeHeight, BoxWidth, BoxHeight,
- Input, InputLen,
- True);
- bytebuf_puts(&global.out, global.caps[TB_CAP_SHOW_CURSOR]);
-
-
- if (fds[FDS_UNI].fd == -1 || fds[FDS_BI].fd == -1)
- {
- // show error popup
- popup(TB_RED, TB_BLACK, (u8*)"Server disconnected.");
- }
}
}
@@ -567,7 +575,7 @@ main(int argc, char** argv)
tb_init();
tb_get_fds(&fds[FDS_TTY].fd, &fds[FDS_RESIZE].fd);
- screen_home(&ScratchArena,
+ DisplayChat(&ScratchArena,
&MessagesArena, MessagesNum,
&ClientsArena, fds,
Input, InputIndex);
@@ -713,6 +721,7 @@ main(int argc, char** argv)
} break;
case TB_KEY_BACKSPACE2:
if (InputIndex) InputIndex--;
+ Input[InputIndex] = 0;
break;
case TB_KEY_CTRL_D:
case TB_KEY_CTRL_C:
@@ -780,7 +789,7 @@ main(int argc, char** argv)
tb_poll_event(&ev);
}
- screen_home(&ScratchArena, &MessagesArena, MessagesNum, &ClientsArena, fds, Input, InputIndex);
+ DisplayChat(&ScratchArena, &MessagesArena, MessagesNum, &ClientsArena, fds, Input, InputIndex);
tb_present();
}
diff --git a/ui.h b/ui.h
index ff98598..21a4a80 100644
--- a/ui.h
+++ b/ui.h
@@ -295,6 +295,28 @@ preprocess_markdown(Arena* ScratchArena, wchar_t* Text, u32 Len)
return Result;
}
+u32 InputBoxMarginX = 1;
+u32 InputBoxPaddingX = 1;
+#define INPUT_BOX_BORDER_WIDTH 1
+#define INPUT_BOX_MIN_TEXT_WIDTH 1
+#define INPUT_BOX_MIN_TEXT_HEIGHT 1
+
+u32
+GetInputBoxMinimumWidth()
+{
+ return InputBoxPaddingX * 2 +
+ InputBoxMarginX * 2 +
+ INPUT_BOX_BORDER_WIDTH * 2 +
+ INPUT_BOX_MIN_TEXT_WIDTH;
+}
+
+u32
+GetInputBoxMinimumHeight()
+{
+ return INPUT_BOX_BORDER_WIDTH * 2 +
+ INPUT_BOX_MIN_TEXT_HEIGHT;
+}
+
void
InputBox(u32 BoxX, u32 BoxY, u32 BoxWidth, u32 BoxHeight,
wchar_t *Text, u32 TextLen,
@@ -308,17 +330,9 @@ InputBox(u32 BoxX, u32 BoxY, u32 BoxWidth, u32 BoxHeight,
// P -> padding (symmetric)
// M -> margin (symmetric)
- // Configuration options
- u32 MarginX = 1;
- u32 PaddingX = 1;
- u32 MinTextSpace = 3;
- u32 BorderWidth = 1;
-
- // TODO: return early if there is not enough space
- if (BoxHeight < 3)
- return;
- if (BoxWidth < MarginX * 2 + PaddingX * 2 + MinTextSpace)
- return;
+ u32 MarginX = InputBoxMarginX;
+ u32 PaddingX = InputBoxPaddingX;
+ u32 BorderWidth = INPUT_BOX_BORDER_WIDTH;
// Get 0-based coordinate
BoxWidth -= 2* MarginX;
@@ -370,35 +384,63 @@ InputBox(u32 BoxX, u32 BoxY, u32 BoxWidth, u32 BoxHeight,
u32 TextHeight = BoxHeight - BorderWidth * 2 + 1;
u32 TextDisplaySize = TextWidth * TextHeight;
- u32 At = 0;
- // If there is not enough space to fit the text scroll one line by advancing by textwidth.
- if (TextLen >= TextDisplaySize)
- {
- // TextHeight - 1 : scroll by one line
- At = (TextLen / TextWidth - (TextHeight - 1)) * TextWidth;
- }
-
-#ifdef DEBUG
- tb_printf(BoxX + 1, BoxY, 0, 0, "%d/%d %dx%d %d", TextLen, MAX_INPUT_LEN, TextWidth, TextHeight, At);
-#endif
-
- // Keep if needed for cursor position
+ // XOffset and YOffset are needed for setting the cursor position
u32 XOffset = 0, YOffset = 0;
- while (At < TextLen)
+ u32 TextOffset = 0;
+
+ // If there is more than one line, implement vertical wrapping otherwise scroll the text
+ // horizontally.
+ if (TextHeight > 1)
{
- for (YOffset = 0;
- YOffset < TextHeight && At < TextLen;
- YOffset++)
+ // If there is not enough space to fit the text scroll one line by advancing by textwidth.
+ if (TextLen >= TextDisplaySize)
+ {
+ // TextHeight - 1 : scroll by one line
+ TextOffset = (TextLen / TextWidth - (TextHeight - 1)) * TextWidth;
+ }
+
+ // Print the text
+ while (TextOffset < TextLen)
{
- for (XOffset = 0;
- XOffset < TextWidth && At < TextLen;
- XOffset++)
+ for (YOffset = 0;
+ YOffset < TextHeight && TextOffset < TextLen;
+ YOffset++)
{
- tb_printf(TextX + XOffset, TextY + YOffset, 0, 0, "%lc", Text[At]);
- At++;
+ for (XOffset = 0;
+ XOffset < TextWidth && TextOffset < TextLen;
+ XOffset++)
+ {
+ tb_printf(TextX + XOffset, TextY + YOffset, 0, 0, "%lc", Text[TextOffset]);
+ TextOffset++;
+ }
}
}
}
+ else
+ {
+ // Scrooll the text horizontally
+ if (TextLen >= TextDisplaySize)
+ {
+ TextOffset = TextLen - TextWidth;
+ XOffset = TextWidth;
+ }
+ else
+ {
+ XOffset = TextLen;
+ }
+ YOffset = 1;
+ tb_printf(TextX, TextY, 0, 0, "%ls", Text + TextOffset);
+ }
+
+#ifdef DEBUG
+ tb_printf(BoxX + 1, BoxY, 0, 0, "%d/%d [%dx%d] %dx%d %d (%d,%d)+(%d,%d)",
+ TextLen, MAX_INPUT_LEN,
+ BoxWidth, BoxHeight,
+ TextWidth, TextHeight,
+ TextOffset,
+ TextX, TextY,
+ XOffset, YOffset);
+#endif
// Set the cursor
if (Focused)
@@ -409,7 +451,7 @@ InputBox(u32 BoxX, u32 BoxY, u32 BoxWidth, u32 BoxHeight,
global.cursor_x = TextX;
global.cursor_y = TextY;
}
- else if (TextLen % TextWidth == 0)
+ else if (TextLen % TextWidth == 0 && TextHeight > 1)
{
// When at the end of width put the cursor on the next line
global.cursor_x = TextX;