commit 518088c7fb788b170cfbcd7e8d048555f541f27f
parent bd0ff6bd2213fc11e8455d1d6d03a51a99d43570
Author: Michael Savage <mikejsavage@gmail.com>
Date: Fri, 7 Sep 2018 16:27:17 +0300
Split platform independent UI stuff into ui.cc, defer all redrawing
Diffstat:
14 files changed, 542 insertions(+), 712 deletions(-)
diff --git a/make.lua b/make.lua
@@ -12,6 +12,6 @@ if OS == "windows" then
libs = { "lua", "lpeg", "lfs" }
end
-bin( "mudgangster", { platform_objs, "src/script", "src/textbox", "src/input", "src/platform_network" }, libs )
+bin( "mudgangster", { platform_objs, "src/ui", "src/script", "src/textbox", "src/input", "src/platform_network" }, libs )
msvc_bin_ldflags( "mudgangster", "gdi32.lib Ws2_32.lib" )
gcc_bin_ldflags( "mudgangster", "-lm -lX11 -llua" )
diff --git a/src/input.cc b/src/input.cc
@@ -4,10 +4,11 @@
#include "common.h"
#include "input.h"
#include "script.h"
+#include "ui.h"
typedef struct {
char * text;
- int len;
+ size_t len;
} InputHistory;
static InputHistory inputHistory[ MAX_INPUT_HISTORY ];
@@ -18,10 +19,15 @@ static int inputHistoryDelta = 0;
static char * inputBuffer = NULL;
static char * starsBuffer = NULL;
-static int inputBufferSize = 256;
+static size_t inputBufferSize = 256;
-static int inputLen = 0;
-static int inputPos = 0;
+static size_t inputLen = 0;
+static size_t cursor_pos = 0;
+
+static int left, top;
+static int width, height;
+
+static bool dirty = false;
void input_init() {
inputBuffer = ( char * ) malloc( inputBufferSize );
@@ -35,14 +41,6 @@ void input_term() {
free( starsBuffer );
}
-InputBuffer input_get_buffer() {
- InputBuffer buf;
- buf.buf = inputBuffer;
- buf.len = inputLen;
- buf.cursor_pos = inputPos;
- return buf;
-}
-
void input_return() {
if( inputLen > 0 ) {
InputHistory * lastCmd = &inputHistory[ ( inputHistoryHead + inputHistoryCount - 1 ) % MAX_INPUT_HISTORY ];
@@ -71,23 +69,27 @@ void input_return() {
inputHistoryDelta = 0;
inputLen = 0;
- inputPos = 0;
+ cursor_pos = 0;
+
+ dirty = true;
}
void input_backspace() {
- if( inputPos > 0 ) {
- memmove( inputBuffer + inputPos - 1, inputBuffer + inputPos, inputLen - inputPos );
+ if( cursor_pos > 0 ) {
+ memmove( inputBuffer + cursor_pos - 1, inputBuffer + cursor_pos, inputLen - cursor_pos );
inputLen--;
- inputPos--;
+ cursor_pos--;
+ dirty = true;
}
}
void input_delete() {
- if( inputPos < inputLen ) {
- memmove( inputBuffer + inputPos, inputBuffer + inputPos + 1, inputLen - inputPos );
+ if( cursor_pos < inputLen ) {
+ memmove( inputBuffer + cursor_pos, inputBuffer + cursor_pos + 1, inputLen - cursor_pos );
inputLen--;
+ dirty = true;
}
}
@@ -103,7 +105,8 @@ void input_up() {
memcpy( inputBuffer, cmd.text, cmd.len );
inputLen = cmd.len;
- inputPos = cmd.len;
+ cursor_pos = cmd.len;
+ dirty = true;
}
void input_down() {
@@ -120,20 +123,26 @@ void input_down() {
memcpy( inputBuffer, cmd.text, cmd.len );
inputLen = cmd.len;
- inputPos = cmd.len;
+ cursor_pos = cmd.len;
}
else {
inputLen = 0;
- inputPos = 0;
+ cursor_pos = 0;
}
+
+ dirty = true;
}
void input_left() {
- inputPos = max( inputPos - 1, 0 );
+ if( cursor_pos > 0 ) {
+ cursor_pos--;
+ dirty = true;
+ }
}
void input_right() {
- inputPos = min( inputPos + 1, inputLen );
+ cursor_pos = min( cursor_pos + 1, inputLen );
+ dirty = true;
}
void input_add( const char * buffer, int len ) {
@@ -146,12 +155,47 @@ void input_add( const char * buffer, int len ) {
memset( starsBuffer + inputBufferSize / 2, '*', inputBufferSize / 2 );
}
- if( inputPos < inputLen ) {
- memmove( inputBuffer + inputPos + len, inputBuffer + inputPos, inputLen - inputPos );
+ if( cursor_pos < inputLen ) {
+ memmove( inputBuffer + cursor_pos + len, inputBuffer + cursor_pos, inputLen - cursor_pos );
}
- memcpy( inputBuffer + inputPos, buffer, len );
+ memcpy( inputBuffer + cursor_pos, buffer, len );
inputLen += len;
- inputPos += len;
+ cursor_pos += len;
+
+ dirty = true;
+}
+
+void input_set_pos( int x, int y ) {
+ left = x;
+ top = y;
+}
+
+void input_set_size( int w, int h ) {
+ width = w;
+ height = h;
+}
+
+bool input_is_dirty() {
+ return dirty;
+}
+
+void input_draw() {
+ int fw, fh;
+ ui_get_font_size( &fw, &fh );
+
+ ui_fill_rect( left, top, width, height, COLOUR_BG, false );
+
+ for( size_t i = 0; i < inputLen; i++ ) {
+ ui_draw_char( PADDING + i * fw, top - SPACING, inputBuffer[ i ], WHITE, false );
+ }
+
+ ui_fill_rect( PADDING + cursor_pos * fw, top, fw, fh, COLOUR_CURSOR, false );
+
+ if( cursor_pos < inputLen ) {
+ ui_draw_char( PADDING + cursor_pos * fw, top - SPACING, inputBuffer[ cursor_pos ], COLOUR_BG, false );
+ }
+
+ dirty = false;
}
diff --git a/src/input.h b/src/input.h
@@ -2,13 +2,6 @@
#include <stddef.h>
-struct InputBuffer {
- char * buf;
-
- size_t len;
- size_t cursor_pos;
-};
-
void input_init();
void input_term();
@@ -23,4 +16,7 @@ void input_right();
void input_add( const char * buffer, int len );
-InputBuffer input_get_buffer();
+void input_set_pos( int x, int y );
+void input_set_size( int w, int h );
+bool input_is_dirty();
+void input_draw();
diff --git a/src/main.cc b/src/main.cc
@@ -1,17 +1,20 @@
#include "script.h"
#include "input.h"
#include "ui.h"
+#include "platform_ui.h"
#include "platform_network.h"
int main() {
net_init();
ui_init();
input_init();
+ platform_ui_init();
script_init();
event_loop();
script_term();
+ platform_ui_term();
input_term();
ui_term();
net_term();
diff --git a/src/platform_network.cc b/src/platform_network.cc
@@ -7,7 +7,7 @@ struct sockaddr_storage;
static NetAddress sockaddr_to_netaddress( const struct sockaddr_storage & ss );
static struct sockaddr_storage netaddress_to_sockaddr( const NetAddress & addr );
-static void setsockoptone( OSSocket fd, int level, int opt );
+static void setsockoptone( PlatformSocket fd, int level, int opt );
#if PLATFORM_WINDOWS
#include "win32_network.cc"
@@ -70,7 +70,7 @@ static struct sockaddr_storage netaddress_to_sockaddr( const NetAddress & addr )
return ss;
}
-static void setsockoptone( OSSocket fd, int level, int opt ) {
+static void setsockoptone( PlatformSocket fd, int level, int opt ) {
int one = 1;
int ok = setsockopt( fd, level, opt, ( char * ) &one, sizeof( one ) );
if( ok == -1 ) {
diff --git a/src/platform_network.h b/src/platform_network.h
@@ -5,9 +5,9 @@
#if PLATFORM_WINDOWS
#include <winsock2.h>
-typedef SOCKET OSSocket;
+typedef SOCKET PlatformSocket;
#elif PLATFORM_UNIX
-typedef int OSSocket;
+typedef int PlatformSocket;
#else
#error new platform
#endif
@@ -21,7 +21,7 @@ enum TCPRecvResult {
};
struct TCPSocket {
- OSSocket fd;
+ PlatformSocket fd;
};
struct IPv4 { u8 bytes[ 4 ]; };
diff --git a/src/platform_ui.h b/src/platform_ui.h
@@ -0,0 +1,10 @@
+#pragma once
+
+#include "ui.h"
+
+void platform_ui_init();
+void platform_ui_term();
+
+void platform_fill_rect( int left, int top, int width, int height, Colour colour, bool bold );
+void platform_draw_char( int left, int top, char c, Colour colour, bool bold, bool force_bold_font );
+void platform_make_dirty( int left, int top, int width, int height );
diff --git a/src/script.cc b/src/script.cc
@@ -192,8 +192,6 @@ extern "C" int mud_setStatus( lua_State * L ) {
lua_pop( L, 4 );
}
- ui_draw_status();
-
return 0;
}
diff --git a/src/textbox.cc b/src/textbox.cc
@@ -92,6 +92,55 @@ void textbox_page_up( TextBox * tb ) {
textbox_scroll( tb, num_rows( tb->h ) - 1 );
}
+void textbox_mouse_down( TextBox * tb, int window_x, int window_y ) {
+ int x = window_x - tb->x;
+ int y = window_y - tb->y;
+
+ if( x < 0 || y < 0 || x >= tb->w || y >= tb->h )
+ return;
+
+ int fw, fh;
+ ui_get_font_size( &fw, &fh );
+
+ int row = ( tb->h - y ) / ( fh + SPACING );
+ int col = x / fw;
+
+ tb->selecting = true;
+ tb->selection_start_col = col;
+ tb->selection_start_row = row;
+ tb->selection_end_col = col;
+ tb->selection_end_row = row;
+ tb->dirty = true;
+}
+
+void textbox_mouse_move( TextBox * tb, int window_x, int window_y ) {
+ if( !tb->selecting )
+ return;
+
+ int x = window_x - tb->x;
+ int y = window_y - tb->y;
+
+ int fw, fh;
+ ui_get_font_size( &fw, &fh );
+
+ int row = ( tb->h - y ) / ( fh + SPACING );
+ int col = x / fw;
+
+ tb->selection_end_col = col;
+ tb->selection_end_row = row;
+ tb->dirty = true;
+}
+
+void textbox_mouse_up( TextBox * tb, int window_x, int window_y ) {
+ if( !tb->selecting )
+ return;
+
+ // TODO: copy the text
+
+ tb->selecting = false;
+ tb->dirty = true;
+}
+
void textbox_set_pos( TextBox * tb, int x, int y ) {
tb->x = x;
tb->y = y;
diff --git a/src/textbox.h b/src/textbox.h
@@ -41,6 +41,10 @@ void textbox_scroll( TextBox * tb, int offset );
void textbox_page_down( TextBox * tb );
void textbox_page_up( TextBox * tb );
+void textbox_mouse_down( TextBox * tb, int x, int y );
+void textbox_mouse_move( TextBox * tb, int x, int y );
+void textbox_mouse_up( TextBox * tb, int x, int y );
+
void textbox_set_pos( TextBox * tb, int x, int y );
void textbox_set_size( TextBox * tb, int w, int h );
diff --git a/src/ui.cc b/src/ui.cc
@@ -0,0 +1,336 @@
+#include "platform_ui.h"
+#include "input.h"
+#include "textbox.h"
+
+static TextBox main_text;
+static TextBox chat_text;
+
+static int window_width, window_height;
+
+typedef struct {
+ char c;
+
+ Colour fg;
+ bool bold;
+} StatusChar;
+
+static StatusChar * statusContents = NULL;
+static size_t statusCapacity = 256;
+static size_t statusLen = 0;
+static bool status_dirty = false;
+
+void ui_init() {
+ textbox_init( &main_text, SCROLLBACK_SIZE );
+ textbox_init( &chat_text, CHAT_ROWS );
+
+ statusContents = ( StatusChar * ) malloc( statusCapacity * sizeof( StatusChar ) );
+ if( statusContents == NULL )
+ FATAL( "malloc" );
+}
+
+void ui_term() {
+ textbox_destroy( &main_text );
+ textbox_destroy( &chat_text );
+ free( statusContents );
+}
+
+void ui_fill_rect( int left, int top, int width, int height, Colour colour, bool bold ) {
+ platform_fill_rect( left, top, width, height, colour, bold );
+ platform_make_dirty( left, top, width, height );
+}
+
+void ui_draw_char( int left, int top, char c, Colour colour, bool bold, bool force_bold_font ) {
+ int fw, fh;
+ ui_get_font_size( &fw, &fh );
+
+ int left_spacing = fw / 2;
+ int right_spacing = fw - left_spacing;
+ int line_height = fh + SPACING;
+ int top_spacing = line_height / 2;
+ int bot_spacing = line_height - top_spacing;
+
+ // TODO: not the right char...
+ // if( uint8_t( c ) == 155 ) { // fill
+ // ui_fill_rect( left, top, fw, fh, colour, bold );
+ // return;
+ // }
+
+ // TODO: this has a vertical seam. using textbox-space coordinates would help
+ if( uint8_t( c ) == 176 ) { // light shade
+ for( int y = 0; y < fh; y += 3 ) {
+ for( int x = y % 6 == 0 ? 0 : 1; x < fw; x += 2 ) {
+ ui_fill_rect( left + x, top + y, 1, 1, colour, bold );
+ }
+ }
+ return;
+ }
+
+ // TODO: this has a horizontal seam but so does mm2k
+ if( uint8_t( c ) == 177 ) { // medium shade
+ for( int y = 0; y < fh; y += 2 ) {
+ for( int x = y % 4 == 0 ? 1 : 0; x < fw; x += 2 ) {
+ ui_fill_rect( left + x, top + y, 1, 1, colour, bold );
+ }
+ }
+ return;
+ }
+
+ // TODO: this probably has a horizontal seam
+ if( uint8_t( c ) == 178 ) { // heavy shade
+ for( int y = 0; y < fh + SPACING; y++ ) {
+ for( int x = y % 2 == 0 ? 1 : 0; x < fw; x += 2 ) {
+ ui_fill_rect( left + x, top + y, 1, 1, colour, bold );
+ }
+ }
+ return;
+ }
+
+ if( uint8_t( c ) == 179 ) { // vertical
+ ui_fill_rect( left + left_spacing, top, 1, line_height, colour, bold );
+ return;
+ // set_fg( colour, bold );
+ // const char asdf[] = "│";
+ // Xutf8DrawString( UI.display, UI.back_buffer, ( bold ? Style.fontBold : Style.font ).font, UI.gc, left, top + Style.font.ascent + SPACING, asdf, sizeof( asdf ) - 1 );
+ }
+
+ if( uint8_t( c ) == 180 ) { // right stopper
+ ui_fill_rect( left, top + top_spacing, left_spacing, 1, colour, bold );
+ ui_fill_rect( left + left_spacing, top, 1, line_height, colour, bold );
+ return;
+ }
+
+ if( uint8_t( c ) == 186 ) { // double vertical
+ ui_fill_rect( left + left_spacing - 1, top, 1, line_height, colour, bold );
+ ui_fill_rect( left + left_spacing + 1, top, 1, line_height, colour, bold );
+ return;
+ }
+
+ if( uint8_t( c ) == 187 ) { // double top right
+ ui_fill_rect( left, top + top_spacing - 1, right_spacing + 1, 1, colour, bold );
+ ui_fill_rect( left + left_spacing + 1, top + top_spacing - 1, 1, bot_spacing + 1, colour, bold );
+ ui_fill_rect( left, top + top_spacing + 1, right_spacing - 1, 1, colour, bold );
+ ui_fill_rect( left + left_spacing - 1, top + top_spacing + 1, 1, bot_spacing - 1, colour, bold );
+ return;
+ }
+
+ if( uint8_t( c ) == 188 ) { // double bottom right
+ ui_fill_rect( left, top + top_spacing + 1, right_spacing + 1, 1, colour, bold );
+ ui_fill_rect( left + left_spacing + 1, top, 1, top_spacing + 1, colour, bold );
+ ui_fill_rect( left, top + top_spacing - 1, right_spacing - 1, 1, colour, bold );
+ ui_fill_rect( left + left_spacing - 1, top, 1, top_spacing - 1, colour, bold );
+ return;
+ }
+
+ if( uint8_t( c ) == 191 ) { // top right
+ ui_fill_rect( left, top + top_spacing, left_spacing, 1, colour, bold );
+ ui_fill_rect( left + left_spacing, top + top_spacing, 1, bot_spacing, colour, bold );
+ return;
+ }
+
+ if( uint8_t( c ) == 192 ) { // bottom left
+ ui_fill_rect( left + left_spacing, top + top_spacing, right_spacing, 1, colour, bold );
+ ui_fill_rect( left + left_spacing, top, 1, top_spacing, colour, bold );
+ return;
+ }
+
+ if( uint8_t( c ) == 193 ) { // bottom stopper
+ ui_fill_rect( left + left_spacing, top, 1, top_spacing, colour, bold );
+ ui_fill_rect( left, top + top_spacing, fw, 1, colour, bold );
+ return;
+ }
+
+ if( uint8_t( c ) == 194 ) { // top stopper
+ ui_fill_rect( left + left_spacing, top + top_spacing, 1, bot_spacing, colour, bold );
+ ui_fill_rect( left, top + top_spacing, fw, 1, colour, bold );
+ return;
+ }
+
+ if( uint8_t( c ) == 195 ) { // left stopper
+ ui_fill_rect( left + left_spacing, top + top_spacing, right_spacing, 1, colour, bold );
+ ui_fill_rect( left + left_spacing, top, 1, line_height, colour, bold );
+ return;
+ }
+
+ if( uint8_t( c ) == 196 ) { // horizontal
+ ui_fill_rect( left, top + top_spacing, fw, 1, colour, bold );
+ return;
+ }
+
+ if( uint8_t( c ) == 197 ) { // cross
+ ui_fill_rect( left, top + top_spacing, fw, 1, colour, bold );
+ ui_fill_rect( left + left_spacing, top, 1, line_height, colour, bold );
+ return;
+ }
+
+ if( uint8_t( c ) == 200 ) { // double bottom left
+ ui_fill_rect( left + left_spacing - 1, top + top_spacing + 1, right_spacing + 1, 1, colour, bold );
+ ui_fill_rect( left + left_spacing - 1, top, 1, top_spacing + 1, colour, bold );
+ ui_fill_rect( left + left_spacing + 1, top + top_spacing - 1, right_spacing - 1, 1, colour, bold );
+ ui_fill_rect( left + left_spacing + 1, top, 1, top_spacing - 1, colour, bold );
+ return;
+ }
+
+ if( uint8_t( c ) == 201 ) { // double top left
+ ui_fill_rect( left + left_spacing - 1, top + top_spacing - 1, right_spacing + 1, 1, colour, bold );
+ ui_fill_rect( left + left_spacing - 1, top + top_spacing - 1, 1, bot_spacing + 1, colour, bold );
+ ui_fill_rect( left + left_spacing + 1, top + top_spacing + 1, right_spacing - 1, 1, colour, bold );
+ ui_fill_rect( left + left_spacing + 1, top + top_spacing + 1, 1, bot_spacing - 1, colour, bold );
+ return;
+ }
+
+ if( uint8_t( c ) == 205 ) { // double horizontal
+ ui_fill_rect( left, top + top_spacing - 1, fw, 1, colour, bold );
+ ui_fill_rect( left, top + top_spacing + 1, fw, 1, colour, bold );
+ return;
+ }
+
+ if( uint8_t( c ) == 217 ) { // bottom right
+ ui_fill_rect( left, top + top_spacing, right_spacing, 1, colour, bold );
+ ui_fill_rect( left + left_spacing, top, 1, top_spacing, colour, bold );
+ return;
+ }
+
+ if( uint8_t( c ) == 218 ) { // top left
+ ui_fill_rect( left + left_spacing, top + top_spacing, right_spacing, 1, colour, bold );
+ ui_fill_rect( left + left_spacing, top + top_spacing, 1, bot_spacing, colour, bold );
+ return;
+ }
+
+ platform_draw_char( left, top, c, colour, bold, force_bold_font );
+ platform_make_dirty( left, top, fw, line_height );
+}
+
+void ui_clear_status() {
+ statusLen = 0;
+ status_dirty = true;
+}
+
+// TODO: just cap this at like 8k
+void ui_statusAdd( const char c, const Colour fg, const bool bold ) {
+ if( ( statusLen + 1 ) * sizeof( StatusChar ) > statusCapacity ) {
+ size_t newcapacity = statusCapacity * 2;
+ StatusChar * newcontents = ( StatusChar * ) realloc( statusContents, newcapacity );
+ if( !newcontents )
+ FATAL( "REALLOC" );
+
+ statusContents = newcontents;
+ statusCapacity = newcapacity;
+ }
+
+ statusContents[ statusLen ] = ( StatusChar ) { c, fg, bold };
+ statusLen++;
+ status_dirty = true;
+}
+
+void ui_draw_status() {
+ int fw, fh;
+ ui_get_font_size( &fw, &fh );
+
+ ui_fill_rect( 0, window_height - PADDING * 4 - fh * 2, window_width, fh + PADDING * 2, COLOUR_STATUSBG, false );
+
+ for( size_t i = 0; i < statusLen; i++ ) {
+ StatusChar sc = statusContents[ i ];
+
+ int x = PADDING + i * fw;
+ int y = window_height - ( PADDING * 3 ) - fh * 2 - SPACING;
+ ui_draw_char( x, y, sc.c, sc.fg, sc.bold );
+ }
+
+ status_dirty = false;
+}
+
+void ui_redraw_dirty() {
+ if( main_text.dirty )
+ textbox_draw( &main_text );
+ if( chat_text.dirty )
+ textbox_draw( &chat_text );
+ if( input_is_dirty() )
+ input_draw();
+ if( status_dirty )
+ ui_draw_status();
+}
+
+void ui_redraw_everything() {
+ int fw, fh;
+ ui_get_font_size( &fw, &fh );
+
+ ui_fill_rect( 0, 0, window_width, window_height, COLOUR_BG, false );
+
+ input_draw();
+ ui_draw_status();
+
+ textbox_draw( &chat_text );
+ textbox_draw( &main_text );
+
+ int spacerY = ( 2 * PADDING ) + ( fh + SPACING ) * CHAT_ROWS;
+ ui_fill_rect( 0, spacerY, window_width, 1, COLOUR_STATUSBG, false );
+}
+
+void ui_main_newline() {
+ textbox_newline( &main_text );
+}
+
+void ui_main_print( const char * str, size_t len, Colour fg, Colour bg, bool bold ) {
+ textbox_add( &main_text, str, len, fg, bg, bold );
+}
+
+void ui_chat_newline() {
+ textbox_newline( &chat_text );
+}
+
+void ui_chat_print( const char * str, size_t len, Colour fg, Colour bg, bool bold ) {
+ textbox_add( &chat_text, str, len, fg, bg, bold );
+}
+
+void ui_resize( int width, int height ) {
+ int fw, fh;
+ ui_get_font_size( &fw, &fh );
+
+ int old_width = window_width;
+ int old_height = window_height;
+
+ window_width = width;
+ window_height = height;
+
+ if( window_width == old_width && window_height == old_height )
+ return;
+
+ textbox_set_pos( &chat_text, PADDING, PADDING );
+ textbox_set_size( &chat_text, window_width - ( 2 * PADDING ), ( fh + SPACING ) * CHAT_ROWS );
+
+ textbox_set_pos( &main_text, PADDING, ( PADDING * 2 ) + CHAT_ROWS * ( fh + SPACING ) + 1 );
+ textbox_set_size( &main_text, window_width - ( 2 * PADDING ), window_height
+ - ( ( ( fh + SPACING ) * CHAT_ROWS ) + ( PADDING * 2 ) )
+ - ( ( fh * 2 ) + ( PADDING * 5 ) ) - 1
+ );
+
+ input_set_pos( PADDING, window_height - PADDING - fh );
+ input_set_size( window_width - PADDING * 2, fh );
+}
+
+void ui_scroll( int offset ) {
+ textbox_scroll( &main_text, offset );
+}
+
+void ui_page_down() {
+ textbox_page_down( &main_text );
+}
+
+void ui_page_up() {
+ textbox_page_up( &main_text );
+}
+
+void ui_mouse_down( int x, int y ) {
+ textbox_mouse_down( &main_text, x, y );
+ textbox_mouse_down( &chat_text, x, y );
+}
+
+void ui_mouse_up( int x, int y ) {
+ textbox_mouse_up( &main_text, x, y );
+ textbox_mouse_up( &chat_text, x, y );
+}
+
+void ui_mouse_move( int x, int y ) {
+ textbox_mouse_move( &main_text, x, y );
+ textbox_mouse_move( &chat_text, x, y );
+}
diff --git a/src/ui.h b/src/ui.h
@@ -33,6 +33,19 @@ void ui_chat_print( const char * str, size_t len, Colour fg, Colour bg, bool bol
void ui_fill_rect( int left, int top, int width, int height, Colour colour, bool bold );
void ui_draw_char( int left, int top, char c, Colour colour, bool bold, bool force_bold_font = false );
+void ui_redraw_dirty();
+void ui_redraw_everything();
+
+void ui_resize( int width, int height );
+
+void ui_scroll( int offset );
+void ui_page_down();
+void ui_page_up();
+
+void ui_mouse_down( int x, int y );
+void ui_mouse_move( int x, int y );
+void ui_mouse_up( int x, int y );
+
void ui_get_font_size( int * fw, int * fh );
void ui_urgent();
diff --git a/src/win32.cc b/src/win32.cc
@@ -24,8 +24,6 @@ struct {
int width, height;
int max_width, max_height;
-
- bool has_focus;
} UI;
struct Socket {
@@ -156,267 +154,23 @@ static COLORREF get_colour( Colour colour, bool bold ) {
return Style.colours[ bold ][ colour ];
}
-static void make_dirty( int left, int top, int width, int height ) {
- RECT r = { left, top, left + width, top + height };
- InvalidateRect( UI.hwnd, &r, FALSE );
-}
-
-void ui_fill_rect( int left, int top, int width, int height, Colour colour, bool bold ) {
+void platform_fill_rect( int left, int top, int width, int height, Colour colour, bool bold ) {
+ // TODO: preallocate these
HBRUSH brush = CreateSolidBrush( get_colour( colour, bold ) );
RECT r = { left, top, left + width, top + height };
FillRect( UI.back_buffer, &r, brush );
DeleteObject( brush );
- make_dirty( left, top, width, height );
}
-void ui_draw_char( int left, int top, char c, Colour colour, bool bold, bool force_bold_font ) {
- int left_spacing = Style.font.width / 2;
- int right_spacing = Style.font.width - left_spacing;
- int line_height = Style.font.height + SPACING;
- int top_spacing = line_height / 2;
- int bot_spacing = line_height - top_spacing;
-
- // TODO: not the right char...
- // if( uint8_t( c ) == 155 ) { // fill
- // ui_fill_rect( left, top, Style.font.width, Style.font.height, colour, bold );
- // return;
- // }
-
- // TODO: this has a vertical seam. using textbox-space coordinates would help
- if( uint8_t( c ) == 176 ) { // light shade
- for( int y = 0; y < Style.font.height; y += 3 ) {
- for( int x = y % 6 == 0 ? 0 : 1; x < Style.font.width; x += 2 ) {
- ui_fill_rect( left + x, top + y, 1, 1, colour, bold );
- }
- }
- return;
- }
-
- // TODO: this has a horizontal seam but so does mm2k
- if( uint8_t( c ) == 177 ) { // medium shade
- for( int y = 0; y < Style.font.height; y += 2 ) {
- for( int x = y % 4 == 0 ? 1 : 0; x < Style.font.width; x += 2 ) {
- ui_fill_rect( left + x, top + y, 1, 1, colour, bold );
- }
- }
- return;
- }
-
- // TODO: this probably has a horizontal seam
- if( uint8_t( c ) == 178 ) { // heavy shade
- for( int y = 0; y < Style.font.height + SPACING; y++ ) {
- for( int x = y % 2 == 0 ? 1 : 0; x < Style.font.width; x += 2 ) {
- ui_fill_rect( left + x, top + y, 1, 1, colour, bold );
- }
- }
- return;
- }
-
- if( uint8_t( c ) == 179 ) { // vertical
- ui_fill_rect( left + left_spacing, top, 1, line_height, colour, bold );
- return;
- // set_fg( colour, bold );
- // const char asdf[] = "│";
- // Xutf8DrawString( UI.display, UI.back_buffer, ( bold ? Style.fontBold : Style.font ).font, UI.gc, left, top + Style.font.ascent + SPACING, asdf, sizeof( asdf ) - 1 );
- }
-
- if( uint8_t( c ) == 180 ) { // right stopper
- ui_fill_rect( left, top + top_spacing, left_spacing, 1, colour, bold );
- ui_fill_rect( left + left_spacing, top, 1, line_height, colour, bold );
- return;
- }
-
- if( uint8_t( c ) == 186 ) { // double vertical
- ui_fill_rect( left + left_spacing - 1, top, 1, line_height, colour, bold );
- ui_fill_rect( left + left_spacing + 1, top, 1, line_height, colour, bold );
- return;
- }
-
- if( uint8_t( c ) == 187 ) { // double top right
- ui_fill_rect( left, top + top_spacing - 1, right_spacing + 1, 1, colour, bold );
- ui_fill_rect( left + left_spacing + 1, top + top_spacing - 1, 1, bot_spacing + 1, colour, bold );
- ui_fill_rect( left, top + top_spacing + 1, right_spacing - 1, 1, colour, bold );
- ui_fill_rect( left + left_spacing - 1, top + top_spacing + 1, 1, bot_spacing - 1, colour, bold );
- return;
- }
-
- if( uint8_t( c ) == 188 ) { // double bottom right
- ui_fill_rect( left, top + top_spacing + 1, right_spacing + 1, 1, colour, bold );
- ui_fill_rect( left + left_spacing + 1, top, 1, top_spacing + 1, colour, bold );
- ui_fill_rect( left, top + top_spacing - 1, right_spacing - 1, 1, colour, bold );
- ui_fill_rect( left + left_spacing - 1, top, 1, top_spacing - 1, colour, bold );
- return;
- }
-
- if( uint8_t( c ) == 191 ) { // top right
- ui_fill_rect( left, top + top_spacing, left_spacing, 1, colour, bold );
- ui_fill_rect( left + left_spacing, top + top_spacing, 1, bot_spacing, colour, bold );
- return;
- }
-
- if( uint8_t( c ) == 192 ) { // bottom left
- ui_fill_rect( left + left_spacing, top + top_spacing, right_spacing, 1, colour, bold );
- ui_fill_rect( left + left_spacing, top, 1, top_spacing, colour, bold );
- return;
- }
-
- if( uint8_t( c ) == 193 ) { // bottom stopper
- ui_fill_rect( left + left_spacing, top, 1, top_spacing, colour, bold );
- ui_fill_rect( left, top + top_spacing, Style.font.width, 1, colour, bold );
- return;
- }
-
- if( uint8_t( c ) == 194 ) { // top stopper
- ui_fill_rect( left + left_spacing, top + top_spacing, 1, bot_spacing, colour, bold );
- ui_fill_rect( left, top + top_spacing, Style.font.width, 1, colour, bold );
- return;
- }
-
- if( uint8_t( c ) == 195 ) { // left stopper
- ui_fill_rect( left + left_spacing, top + top_spacing, right_spacing, 1, colour, bold );
- ui_fill_rect( left + left_spacing, top, 1, line_height, colour, bold );
- return;
- }
-
- if( uint8_t( c ) == 196 ) { // horizontal
- ui_fill_rect( left, top + top_spacing, Style.font.width, 1, colour, bold );
- return;
- }
-
- if( uint8_t( c ) == 197 ) { // cross
- ui_fill_rect( left, top + top_spacing, Style.font.width, 1, colour, bold );
- ui_fill_rect( left + left_spacing, top, 1, line_height, colour, bold );
- return;
- }
-
- if( uint8_t( c ) == 200 ) { // double bottom left
- ui_fill_rect( left + left_spacing - 1, top + top_spacing + 1, right_spacing + 1, 1, colour, bold );
- ui_fill_rect( left + left_spacing - 1, top, 1, top_spacing + 1, colour, bold );
- ui_fill_rect( left + left_spacing + 1, top + top_spacing - 1, right_spacing - 1, 1, colour, bold );
- ui_fill_rect( left + left_spacing + 1, top, 1, top_spacing - 1, colour, bold );
- return;
- }
-
- if( uint8_t( c ) == 201 ) { // double top left
- ui_fill_rect( left + left_spacing - 1, top + top_spacing - 1, right_spacing + 1, 1, colour, bold );
- ui_fill_rect( left + left_spacing - 1, top + top_spacing - 1, 1, bot_spacing + 1, colour, bold );
- ui_fill_rect( left + left_spacing + 1, top + top_spacing + 1, right_spacing - 1, 1, colour, bold );
- ui_fill_rect( left + left_spacing + 1, top + top_spacing + 1, 1, bot_spacing - 1, colour, bold );
- return;
- }
-
- if( uint8_t( c ) == 205 ) { // double horizontal
- ui_fill_rect( left, top + top_spacing - 1, Style.font.width, 1, colour, bold );
- ui_fill_rect( left, top + top_spacing + 1, Style.font.width, 1, colour, bold );
- return;
- }
-
- if( uint8_t( c ) == 217 ) { // bottom right
- ui_fill_rect( left, top + top_spacing, right_spacing, 1, colour, bold );
- ui_fill_rect( left + left_spacing, top, 1, top_spacing, colour, bold );
- return;
- }
-
- if( uint8_t( c ) == 218 ) { // top left
- ui_fill_rect( left + left_spacing, top + top_spacing, right_spacing, 1, colour, bold );
- ui_fill_rect( left + left_spacing, top + top_spacing, 1, bot_spacing, colour, bold );
- return;
- }
-
+void platform_draw_char( int left, int top, char c, Colour colour, bool bold, bool force_bold_font ) {
SelectObject( UI.back_buffer, ( bold || force_bold_font ? Style.font.bold : Style.font.regular ) );
SetTextColor( UI.back_buffer, get_colour( colour, bold ) );
TextOutA( UI.back_buffer, left, top + SPACING, &c, 1 );
-
- make_dirty( left, top, Style.font.width, Style.font.height + SPACING );
-}
-
-typedef struct {
- char c;
-
- Colour fg;
- bool bold;
-} StatusChar;
-
-static StatusChar * statusContents = NULL;
-static size_t statusCapacity = 256;
-static size_t statusLen = 0;
-
-void ui_clear_status() {
- statusLen = 0;
}
-void ui_statusAdd( const char c, const Colour fg, const bool bold ) {
- if( ( statusLen + 1 ) * sizeof( StatusChar ) > statusCapacity ) {
- size_t newcapacity = statusCapacity * 2;
- StatusChar * newcontents = ( StatusChar * ) realloc( statusContents, newcapacity );
- if( !newcontents )
- FATAL( "realloc" );
-
- statusContents = newcontents;
- statusCapacity = newcapacity;
- }
-
- statusContents[ statusLen ] = { c, fg, bold };
- statusLen++;
-}
-
-void ui_draw_status() {
- ui_fill_rect( 0, UI.height - PADDING * 4 - Style.font.height * 2, UI.width, Style.font.height + PADDING * 2, COLOUR_STATUSBG, false );
-
- for( size_t i = 0; i < statusLen; i++ ) {
- StatusChar sc = statusContents[ i ];
-
- int x = PADDING + i * Style.font.width;
- int y = UI.height - ( PADDING * 3 ) - Style.font.height * 2 - SPACING;
- ui_draw_char( x, y, sc.c, sc.fg, sc.bold );
- }
-}
-
-void draw_input() {
- InputBuffer input = input_get_buffer();
-
- int top = UI.height - PADDING - Style.font.height;
- ui_fill_rect( PADDING, top, UI.width - PADDING * 2, Style.font.height, COLOUR_BG, false );
-
- for( size_t i = 0; i < input.len; i++ )
- ui_draw_char( PADDING + i * Style.font.width, top - SPACING, input.buf[ i ], WHITE, false );
-
- ui_fill_rect( PADDING + input.cursor_pos * Style.font.width, top, Style.font.width, Style.font.height, COLOUR_CURSOR, false );
-
- if( input.cursor_pos < input.len ) {
- ui_draw_char( PADDING + input.cursor_pos * Style.font.width, top - SPACING, input.buf[ input.cursor_pos ], COLOUR_BG, false );
- }
-}
-
-void ui_draw() {
- ui_fill_rect( 0, 0, UI.width, UI.height, COLOUR_BG, false );
-
- draw_input();
- ui_draw_status();
-
- textbox_draw( &UI.chat_text );
- textbox_draw( &UI.main_text );
-
- int spacerY = ( 2 * PADDING ) + ( Style.font.height + SPACING ) * CHAT_ROWS;
- ui_fill_rect( 0, spacerY, UI.width, 1, COLOUR_STATUSBG, false );
-}
-
-void ui_handleXEvents() { }
-
-void ui_main_newline() {
- textbox_newline( &UI.main_text );
-}
-
-void ui_main_print( const char * str, size_t len, Colour fg, Colour bg, bool bold ) {
- textbox_add( &UI.main_text, str, len, fg, bg, bold );
-}
-
-void ui_chat_newline() {
- textbox_newline( &UI.chat_text );
-}
-
-void ui_chat_print( const char * str, size_t len, Colour fg, Colour bg, bool bold ) {
- textbox_add( &UI.chat_text, str, len, fg, bg, bold );
+void platform_make_dirty( int left, int top, int width, int height ) {
+ RECT r = { left, top, left + width, top + height };
+ InvalidateRect( UI.hwnd, &r, FALSE );
}
void ui_get_font_size( int * fw, int * fh ) {
@@ -502,14 +256,8 @@ LRESULT CALLBACK WndProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam ) {
} break;
case WM_SIZE: {
- int old_width = UI.width;
- int old_height = UI.height;
-
- UI.width = LOWORD( lParam );
- UI.height = HIWORD( lParam );
-
- if( UI.width == old_width && UI.height == old_height )
- break;
+ int width = LOWORD( lParam );
+ int height = HIWORD( lParam );
int old_max_width = UI.max_width;
int old_max_height = UI.max_height;
@@ -525,16 +273,8 @@ LRESULT CALLBACK WndProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam ) {
SelectObject( UI.back_buffer, UI.back_buffer_bitmap );
}
- textbox_set_pos( &UI.chat_text, PADDING, PADDING );
- textbox_set_size( &UI.chat_text, UI.width - ( 2 * PADDING ), ( Style.font.height + SPACING ) * CHAT_ROWS );
-
- textbox_set_pos( &UI.main_text, PADDING, ( PADDING * 2 ) + CHAT_ROWS * ( Style.font.height + SPACING ) + 1 );
- textbox_set_size( &UI.main_text, UI.width - ( 2 * PADDING ), UI.height
- - ( ( ( Style.font.height + SPACING ) * CHAT_ROWS ) + ( PADDING * 2 ) )
- - ( ( Style.font.height * 2 ) + ( PADDING * 5 ) ) - 1
- );
-
- ui_draw();
+ ui_resized( width, height );
+ ui_redraw();
} break;
case WM_PAINT: {
@@ -550,28 +290,24 @@ LRESULT CALLBACK WndProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam ) {
return TRUE;
case WM_LBUTTONDOWN: {
- // char szFileName[MAX_PATH];
- // HINSTANCE hInstance = GetModuleHandle(NULL);
- //
- // GetModuleFileName(hInstance, szFileName, MAX_PATH);
- // MessageBox(hwnd, szFileName, "This program is:", MB_OK | MB_ICONINFORMATION);
+ ui_mouse_down( GET_X_LPARAM( lParam ), GET_Y_LPARAM( lParam ) );
} break;
case WM_MOUSEMOVE: {
- // char buf[ 128 ];
- // int x = GET_X_LPARAM( lParam );
- // int y = GET_Y_LPARAM( lParam );
- // int l = snprintf( buf, sizeof( buf ), "what the fuck son %d %d", x, y );
- // TextOutA( dc, 10, 10, buf, l );
+ ui_mouse_move( GET_X_LPARAM( lParam ), GET_Y_LPARAM( lParam ) );
+ break;
+
+ case WM_LBUTTONUP: {
+ ui_mouse_up( GET_X_LPARAM( lParam ), GET_Y_LPARAM( lParam ) );
} break;
- case WM_CLOSE:
+ case WM_CLOSE: {
DestroyWindow( hwnd );
- break;
+ } break;
- case WM_DESTROY:
+ case WM_DESTROY: {
PostQuitMessage( 0 );
- break;
+ } break;
case WM_TIMER: {
script_fire_intervals();
@@ -725,7 +461,7 @@ LRESULT CALLBACK WndProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam ) {
} break;
default:
- return DefWindowProc(hwnd, msg, wParam, lParam);
+ return DefWindowProc( hwnd, msg, wParam, lParam );
}
if( UI.main_text.dirty )
diff --git a/src/x11.cc b/src/x11.cc
@@ -85,10 +85,6 @@ struct {
Window window;
- TextBox main_text;
- TextBox chat_text;
-
- int width, height;
int max_width, max_height;
int depth;
@@ -167,7 +163,7 @@ static void set_fg( Colour colour, bool bold ) {
XSetForeground( UI.display, UI.gc, c );
}
-static void make_dirty( int left, int top, int width, int height ) {
+void platform_make_dirty( int left, int top, int width, int height ) {
int right = left + width;
int bottom = top + height;
@@ -186,332 +182,29 @@ static void make_dirty( int left, int top, int width, int height ) {
}
}
-void ui_fill_rect( int left, int top, int width, int height, Colour colour, bool bold ) {
+void platform_fill_rect( int left, int top, int width, int height, Colour colour, bool bold ) {
set_fg( colour, bold );
XFillRectangle( UI.display, UI.back_buffer, UI.gc, left, top, width, height );
- make_dirty( left, top, width, height );
}
-void ui_draw_char( int left, int top, char c, Colour colour, bool bold, bool force_bold_font ) {
- int left_spacing = Style.font.width / 2;
- int right_spacing = Style.font.width - left_spacing;
- int line_height = Style.font.height + SPACING;
- int top_spacing = line_height / 2;
- int bot_spacing = line_height - top_spacing;
-
- // TODO: not the right char...
- // if( uint8_t( c ) == 155 ) { // fill
- // ui_fill_rect( left, top, Style.font.width, Style.font.height, colour, bold );
- // return;
- // }
-
- // TODO: this has a vertical seam. using textbox-space coordinates would help
- if( uint8_t( c ) == 176 ) { // light shade
- for( int y = 0; y < Style.font.height; y += 3 ) {
- for( int x = y % 6 == 0 ? 0 : 1; x < Style.font.width; x += 2 ) {
- ui_fill_rect( left + x, top + y, 1, 1, colour, bold );
- }
- }
- return;
- }
-
- // TODO: this has a horizontal seam but so does mm2k
- if( uint8_t( c ) == 177 ) { // medium shade
- for( int y = 0; y < Style.font.height; y += 2 ) {
- for( int x = y % 4 == 0 ? 1 : 0; x < Style.font.width; x += 2 ) {
- ui_fill_rect( left + x, top + y, 1, 1, colour, bold );
- }
- }
- return;
- }
-
- // TODO: this probably has a horizontal seam
- if( uint8_t( c ) == 178 ) { // heavy shade
- for( int y = 0; y < Style.font.height + SPACING; y++ ) {
- for( int x = y % 2 == 0 ? 1 : 0; x < Style.font.width; x += 2 ) {
- ui_fill_rect( left + x, top + y, 1, 1, colour, bold );
- }
- }
- return;
- }
-
- if( uint8_t( c ) == 179 ) { // vertical
- ui_fill_rect( left + left_spacing, top, 1, line_height, colour, bold );
- return;
- // set_fg( colour, bold );
- // const char asdf[] = "│";
- // Xutf8DrawString( UI.display, UI.back_buffer, ( bold ? Style.fontBold : Style.font ).font, UI.gc, left, top + Style.font.ascent + SPACING, asdf, sizeof( asdf ) - 1 );
- }
-
- if( uint8_t( c ) == 180 ) { // right stopper
- ui_fill_rect( left, top + top_spacing, left_spacing, 1, colour, bold );
- ui_fill_rect( left + left_spacing, top, 1, line_height, colour, bold );
- return;
- }
-
- if( uint8_t( c ) == 186 ) { // double vertical
- ui_fill_rect( left + left_spacing - 1, top, 1, line_height, colour, bold );
- ui_fill_rect( left + left_spacing + 1, top, 1, line_height, colour, bold );
- return;
- }
-
- if( uint8_t( c ) == 187 ) { // double top right
- ui_fill_rect( left, top + top_spacing - 1, right_spacing + 1, 1, colour, bold );
- ui_fill_rect( left + left_spacing + 1, top + top_spacing - 1, 1, bot_spacing + 1, colour, bold );
- ui_fill_rect( left, top + top_spacing + 1, right_spacing - 1, 1, colour, bold );
- ui_fill_rect( left + left_spacing - 1, top + top_spacing + 1, 1, bot_spacing - 1, colour, bold );
- return;
- }
-
- if( uint8_t( c ) == 188 ) { // double bottom right
- ui_fill_rect( left, top + top_spacing + 1, right_spacing + 1, 1, colour, bold );
- ui_fill_rect( left + left_spacing + 1, top, 1, top_spacing + 1, colour, bold );
- ui_fill_rect( left, top + top_spacing - 1, right_spacing - 1, 1, colour, bold );
- ui_fill_rect( left + left_spacing - 1, top, 1, top_spacing - 1, colour, bold );
- return;
- }
-
- if( uint8_t( c ) == 191 ) { // top right
- ui_fill_rect( left, top + top_spacing, left_spacing, 1, colour, bold );
- ui_fill_rect( left + left_spacing, top + top_spacing, 1, bot_spacing, colour, bold );
- return;
- }
-
- if( uint8_t( c ) == 192 ) { // bottom left
- ui_fill_rect( left + left_spacing, top + top_spacing, right_spacing, 1, colour, bold );
- ui_fill_rect( left + left_spacing, top, 1, top_spacing, colour, bold );
- return;
- }
-
- if( uint8_t( c ) == 193 ) { // bottom stopper
- ui_fill_rect( left + left_spacing, top, 1, top_spacing, colour, bold );
- ui_fill_rect( left, top + top_spacing, Style.font.width, 1, colour, bold );
- return;
- }
-
- if( uint8_t( c ) == 194 ) { // top stopper
- ui_fill_rect( left + left_spacing, top + top_spacing, 1, bot_spacing, colour, bold );
- ui_fill_rect( left, top + top_spacing, Style.font.width, 1, colour, bold );
- return;
- }
-
- if( uint8_t( c ) == 195 ) { // left stopper
- ui_fill_rect( left + left_spacing, top + top_spacing, right_spacing, 1, colour, bold );
- ui_fill_rect( left + left_spacing, top, 1, line_height, colour, bold );
- return;
- }
-
- if( uint8_t( c ) == 196 ) { // horizontal
- ui_fill_rect( left, top + top_spacing, Style.font.width, 1, colour, bold );
- return;
- }
-
- if( uint8_t( c ) == 197 ) { // cross
- ui_fill_rect( left, top + top_spacing, Style.font.width, 1, colour, bold );
- ui_fill_rect( left + left_spacing, top, 1, line_height, colour, bold );
- return;
- }
-
- if( uint8_t( c ) == 200 ) { // double bottom left
- ui_fill_rect( left + left_spacing - 1, top + top_spacing + 1, right_spacing + 1, 1, colour, bold );
- ui_fill_rect( left + left_spacing - 1, top, 1, top_spacing + 1, colour, bold );
- ui_fill_rect( left + left_spacing + 1, top + top_spacing - 1, right_spacing - 1, 1, colour, bold );
- ui_fill_rect( left + left_spacing + 1, top, 1, top_spacing - 1, colour, bold );
- return;
- }
-
- if( uint8_t( c ) == 201 ) { // double top left
- ui_fill_rect( left + left_spacing - 1, top + top_spacing - 1, right_spacing + 1, 1, colour, bold );
- ui_fill_rect( left + left_spacing - 1, top + top_spacing - 1, 1, bot_spacing + 1, colour, bold );
- ui_fill_rect( left + left_spacing + 1, top + top_spacing + 1, right_spacing - 1, 1, colour, bold );
- ui_fill_rect( left + left_spacing + 1, top + top_spacing + 1, 1, bot_spacing - 1, colour, bold );
- return;
- }
-
- if( uint8_t( c ) == 205 ) { // double horizontal
- ui_fill_rect( left, top + top_spacing - 1, Style.font.width, 1, colour, bold );
- ui_fill_rect( left, top + top_spacing + 1, Style.font.width, 1, colour, bold );
- return;
- }
-
- if( uint8_t( c ) == 217 ) { // bottom right
- ui_fill_rect( left, top + top_spacing, right_spacing, 1, colour, bold );
- ui_fill_rect( left + left_spacing, top, 1, top_spacing, colour, bold );
- return;
- }
-
- if( uint8_t( c ) == 218 ) { // top left
- ui_fill_rect( left + left_spacing, top + top_spacing, right_spacing, 1, colour, bold );
- ui_fill_rect( left + left_spacing, top + top_spacing, 1, bot_spacing, colour, bold );
- return;
- }
-
+void platform_draw_char( int left, int top, char c, Colour colour, bool bold, bool force_bold_font ) {
XSetFont( UI.display, UI.gc, ( bold || force_bold_font ? Style.font.bold : Style.font.regular )->fid );
set_fg( colour, bold );
XDrawString( UI.display, UI.back_buffer, UI.gc, left, top + Style.font.ascent + SPACING, &c, 1 );
-
- make_dirty( left, top, Style.font.width, Style.font.height + SPACING );
}
static Atom wmDeleteWindow;
-typedef struct {
- char c;
-
- Colour fg;
- bool bold;
-} StatusChar;
-
-static StatusChar * statusContents = NULL;
-static size_t statusCapacity = 256;
-static size_t statusLen = 0;
-
-void ui_clear_status() {
- statusLen = 0;
-}
-
-void ui_statusAdd( const char c, const Colour fg, const bool bold ) {
- if( ( statusLen + 1 ) * sizeof( StatusChar ) > statusCapacity ) {
- size_t newcapacity = statusCapacity * 2;
- StatusChar * newcontents = ( StatusChar * ) realloc( statusContents, newcapacity );
- if( !newcontents )
- err( 1, "realloc" );
-
- statusContents = newcontents;
- statusCapacity = newcapacity;
- }
-
- statusContents[ statusLen ] = ( StatusChar ) { c, fg, bold };
- statusLen++;
-}
-
-void ui_draw_status() {
- ui_fill_rect( 0, UI.height - PADDING * 4 - Style.font.height * 2, UI.width, Style.font.height + PADDING * 2, COLOUR_STATUSBG, false );
-
- for( size_t i = 0; i < statusLen; i++ ) {
- StatusChar sc = statusContents[ i ];
-
- int x = PADDING + i * Style.font.width;
- int y = UI.height - ( PADDING * 3 ) - Style.font.height * 2 - SPACING;
- ui_draw_char( x, y, sc.c, sc.fg, sc.bold );
- }
-}
-
-void draw_input() {
- InputBuffer input = input_get_buffer();
-
- int top = UI.height - PADDING - Style.font.height;
- ui_fill_rect( PADDING, top, UI.width - PADDING * 2, Style.font.height, COLOUR_BG, false );
-
- for( size_t i = 0; i < input.len; i++ )
- ui_draw_char( PADDING + i * Style.font.width, top - SPACING, input.buf[ i ], WHITE, false );
-
- ui_fill_rect( PADDING + input.cursor_pos * Style.font.width, top, Style.font.width, Style.font.height, COLOUR_CURSOR, false );
-
- if( input.cursor_pos < input.len ) {
- ui_draw_char( PADDING + input.cursor_pos * Style.font.width, top - SPACING, input.buf[ input.cursor_pos ], COLOUR_BG, false );
- }
-}
-
-void ui_draw() {
- ui_fill_rect( 0, 0, UI.width, UI.height, COLOUR_BG, false );
-
- draw_input();
- ui_draw_status();
-
- textbox_draw( &UI.chat_text );
- textbox_draw( &UI.main_text );
-
- int spacerY = ( 2 * PADDING ) + ( Style.font.height + SPACING ) * CHAT_ROWS;
- ui_fill_rect( 0, spacerY, UI.width, 1, COLOUR_STATUSBG, false );
-}
-
static void event_mouse_down( XEvent * xevent ) {
- const XButtonEvent * event = &xevent->xbutton;
-
- if( event->x >= UI.main_text.x && event->x < UI.main_text.x + UI.main_text.w && event->y >= UI.main_text.y && event->y < UI.main_text.y + UI.main_text.h ) {
- int x = event->x - UI.main_text.x;
- int y = event->y - UI.main_text.y;
-
- int my = UI.main_text.h - y;
-
- int row = my / ( Style.font.height + SPACING );
- int col = x / Style.font.width;
-
- UI.main_text.selecting = true;
- UI.main_text.selection_start_col = col;
- UI.main_text.selection_start_row = row;
- UI.main_text.selection_end_col = col;
- UI.main_text.selection_end_row = row;
-
- textbox_draw( &UI.main_text );
- }
-
- if( event->x >= UI.chat_text.x && event->x < UI.chat_text.x + UI.chat_text.w && event->y >= UI.chat_text.y && event->y < UI.chat_text.y + UI.chat_text.h ) {
- int x = event->x - UI.chat_text.x;
- int y = event->y - UI.chat_text.y;
-
- int my = UI.chat_text.h - y;
-
- int row = my / ( Style.font.height + SPACING );
- int col = x / Style.font.width;
-
- UI.chat_text.selecting = true;
- UI.chat_text.selection_start_col = col;
- UI.chat_text.selection_start_row = row;
- UI.chat_text.selection_end_col = col;
- UI.chat_text.selection_end_row = row;
-
- textbox_draw( &UI.chat_text );
- }
-}
-
-static void event_mouse_up( XEvent * xevent ) {
- const XButtonEvent * event = &xevent->xbutton;
-
- if( UI.main_text.selecting ) {
- UI.main_text.selecting = false;
- textbox_draw( &UI.main_text );
- }
-
- if( UI.chat_text.selecting ) {
- UI.chat_text.selecting = false;
- textbox_draw( &UI.chat_text );
- }
+ ui_mouse_down( xevent->xbutton.x, xevent->xbutton.y );
}
static void event_mouse_move( XEvent * xevent ) {
- const XMotionEvent * event = &xevent->xmotion;
-
- if( UI.main_text.selecting ) {
- int x = event->x - UI.main_text.x;
- int y = event->y - UI.main_text.y;
-
- int my = UI.main_text.h - y;
-
- int row = my / ( Style.font.height + SPACING );
- int col = x / Style.font.width;
-
- UI.main_text.selection_end_col = col;
- UI.main_text.selection_end_row = row;
-
- textbox_draw( &UI.main_text );
- }
-
- if( UI.chat_text.selecting ) {
- int x = event->x - UI.chat_text.x;
- int y = event->y - UI.chat_text.y;
-
- int my = UI.chat_text.h - y;
-
- int row = my / ( Style.font.height + SPACING );
- int col = x / Style.font.width;
-
- UI.chat_text.selection_end_col = col;
- UI.chat_text.selection_end_row = row;
+ ui_mouse_move( xevent->xmotion.x, xevent->xmotion.y );
+}
- textbox_draw( &UI.chat_text );
- }
+static void event_mouse_up( XEvent * xevent ) {
+ ui_mouse_up( xevent->xbutton.x, xevent->xbutton.y );
}
static void event_message( XEvent * xevent ) {
@@ -522,40 +215,27 @@ static void event_message( XEvent * xevent ) {
}
static void event_resize( XEvent * xevent ) {
- int old_width = UI.width;
- int old_height = UI.height;
-
- UI.width = xevent->xconfigure.width;
- UI.height = xevent->xconfigure.height;
-
- if( UI.width == old_width && UI.height == old_height )
- return;
+ int width = xevent->xconfigure.width;
+ int height = xevent->xconfigure.height;
int old_max_width = UI.max_width;
int old_max_height = UI.max_height;
- UI.max_width = max( UI.max_width, UI.width );
- UI.max_height = max( UI.max_height, UI.height );
+ UI.max_width = max( UI.max_width, width );
+ UI.max_height = max( UI.max_height, height );
if( UI.max_width != old_max_width || UI.max_height != old_max_height ) {
- if( old_width != -1 ) {
+ if( old_max_width != -1 ) {
XFreePixmap( UI.display, UI.back_buffer );
}
UI.back_buffer = XCreatePixmap( UI.display, UI.window, UI.max_width, UI.max_height, UI.depth );
}
- textbox_set_pos( &UI.chat_text, PADDING, PADDING );
- textbox_set_size( &UI.chat_text, UI.width - ( 2 * PADDING ), ( Style.font.height + SPACING ) * CHAT_ROWS );
-
- textbox_set_pos( &UI.main_text, PADDING, ( PADDING * 2 ) + CHAT_ROWS * ( Style.font.height + SPACING ) + 1 );
- textbox_set_size( &UI.main_text, UI.width - ( 2 * PADDING ), UI.height
- - ( ( ( Style.font.height + SPACING ) * CHAT_ROWS ) + ( PADDING * 2 ) )
- - ( ( Style.font.height * 2 ) + ( PADDING * 5 ) ) - 1
- );
+ ui_resize( width, height );
}
static void event_expose( XEvent * xevent ) {
- ui_draw();
+ ui_redraw_everything();
}
static void event_key_press( XEvent * xevent ) {
@@ -582,53 +262,44 @@ static void event_key_press( XEvent * xevent ) {
switch( key ) {
case XK_Return:
input_return();
- draw_input();
break;
case XK_BackSpace:
input_backspace();
- draw_input();
break;
case XK_Delete:
input_delete();
- draw_input();
break;
case XK_Page_Up:
if( shift )
- textbox_scroll( &UI.main_text, 1 );
+ ui_scroll( 1 );
else
- textbox_page_up( &UI.main_text );
- textbox_draw( &UI.main_text );
+ ui_page_up();
break;
case XK_Page_Down:
if( shift )
- textbox_scroll( &UI.main_text, -1 );
+ ui_scroll( -1 );
else
- textbox_page_down( &UI.main_text );
- textbox_draw( &UI.main_text );
+ ui_page_down();
break;
case XK_Up:
input_up();
- draw_input();
break;
case XK_Down:
input_down();
- draw_input();
break;
case XK_Left:
input_left();
- draw_input();
break;
case XK_Right:
input_right();
- draw_input();
break;
ADD_MACRO( XK_KP_1, "kp1" );
@@ -688,7 +359,6 @@ static void event_key_press( XEvent * xevent ) {
}
else if( len > 0 ) {
input_add( keyBuffer, len );
- draw_input();
}
break;
@@ -713,8 +383,8 @@ static void event_focus( XEvent * xevent ) {
void ui_handleXEvents() {
void ( *event_handlers[ LASTEvent ] )( XEvent * ) = { };
event_handlers[ ButtonPress ] = event_mouse_down;
- event_handlers[ ButtonRelease ] = event_mouse_up;
event_handlers[ MotionNotify ] = event_mouse_move;
+ event_handlers[ ButtonRelease ] = event_mouse_up;
event_handlers[ ClientMessage ] = event_message;
event_handlers[ ConfigureNotify ] = event_resize;
event_handlers[ Expose ] = event_expose;
@@ -744,10 +414,7 @@ void ui_handleXEvents() {
}
}
- if( UI.main_text.dirty )
- textbox_draw( &UI.main_text );
- if( UI.chat_text.dirty )
- textbox_draw( &UI.chat_text );
+ ui_redraw_dirty();
if( UI.dirty ) {
XCopyArea( UI.display, UI.back_buffer, UI.window, UI.gc, UI.dirty_left, UI.dirty_top, UI.dirty_right - UI.dirty_left, UI.dirty_bottom - UI.dirty_top, UI.dirty_left, UI.dirty_top );
@@ -808,7 +475,7 @@ static void initStyle() {
Style.font = load_font( "-windows-dina-medium-r-normal--10-*-*-*-c-0-*-*", "-windows-dina-bold-r-normal--10-*-*-*-c-0-*-*" );
}
-void ui_init() {
+void platform_ui_init() {
for( Socket & s : sockets ) {
s.in_use = false;
}
@@ -818,22 +485,16 @@ void ui_init() {
UI = { };
- textbox_init( &UI.main_text, SCROLLBACK_SIZE );
- textbox_init( &UI.chat_text, CHAT_ROWS );
UI.display = XOpenDisplay( NULL );
UI.screen = XDefaultScreen( UI.display );
- UI.width = -1;
- UI.height = -1;
+ UI.max_width = -1;
+ UI.max_height = -1;
Window root = XRootWindow( UI.display, UI.screen );
UI.depth = XDefaultDepth( UI.display, UI.screen );
Visual * visual = XDefaultVisual( UI.display, UI.screen );
UI.colorMap = XDefaultColormap( UI.display, UI.screen );
- statusContents = ( StatusChar * ) malloc( statusCapacity * sizeof( StatusChar ) );
- if( statusContents == NULL )
- err( 1, "malloc" );
-
initStyle();
XSetWindowAttributes attr = { };
@@ -864,22 +525,6 @@ void ui_init() {
ui_handleXEvents();
}
-void ui_main_newline() {
- textbox_newline( &UI.main_text );
-}
-
-void ui_main_print( const char * str, size_t len, Colour fg, Colour bg, bool bold ) {
- textbox_add( &UI.main_text, str, len, fg, bg, bold );
-}
-
-void ui_chat_newline() {
- textbox_newline( &UI.chat_text );
-}
-
-void ui_chat_print( const char * str, size_t len, Colour fg, Colour bg, bool bold ) {
- textbox_add( &UI.chat_text, str, len, fg, bg, bold );
-}
-
void ui_urgent() {
if( !UI.has_focus ) {
XWMHints * hints = XGetWMHints( UI.display, UI.window );
@@ -903,11 +548,7 @@ bool ui_set_font( const char * name, int size ) {
return false;
}
-void ui_term() {
- textbox_destroy( &UI.main_text );
- textbox_destroy( &UI.chat_text );
- free( statusContents );
-
+void platform_ui_term() {
XFreeFont( UI.display, Style.font.regular );
XFreeFont( UI.display, Style.font.bold );