mudgangster

Log | Files | Refs

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:
make.lua | 2+-
src/input.cc | 98+++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------------
src/input.h | 12++++--------
src/main.cc | 3+++
src/platform_network.cc | 4++--
src/platform_network.h | 6+++---
src/platform_ui.h | 10++++++++++
src/script.cc | 2--
src/textbox.cc | 49+++++++++++++++++++++++++++++++++++++++++++++++++
src/textbox.h | 4++++
src/ui.cc | 336+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/ui.h | 13+++++++++++++
src/win32.cc | 306++++++-------------------------------------------------------------------------
src/x11.cc | 409+++++--------------------------------------------------------------------------
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 );