1141 lines
39 KiB
C
1141 lines
39 KiB
C
#include <ctype.h>
|
|
#include <fcntl.h>
|
|
#include <pwd.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/types.h>
|
|
#include <sys/utsname.h>
|
|
#include <unistd.h>
|
|
|
|
#include <SDL2/SDL.h>
|
|
#include <SDL2/SDL2_gfxPrimitives.h> /* stringRGBA(); */
|
|
|
|
#include "romio.h" /* opt_gx */
|
|
#include "config.h"
|
|
#include "ui.h"
|
|
#include "ui_inner.h"
|
|
|
|
#define KEYBOARD_HEIGHT ( BUTTONS[ LAST_HPKEY ].y + BUTTONS[ LAST_HPKEY ].h )
|
|
#define KEYBOARD_WIDTH ( BUTTONS[ LAST_HPKEY ].x + BUTTONS[ LAST_HPKEY ].w )
|
|
|
|
#define TOP_SKIP 65
|
|
#define SIDE_SKIP 20
|
|
#define BOTTOM_SKIP 25
|
|
#define DISP_KBD_SKIP 65
|
|
#define KBD_UPLINE 25
|
|
|
|
#define DISPLAY_WIDTH ( 264 + 8 )
|
|
#define DISPLAY_HEIGHT ( 128 + 16 + 8 )
|
|
#define DISPLAY_OFFSET_X ( SIDE_SKIP + ( 286 - DISPLAY_WIDTH ) / 2 )
|
|
#define DISPLAY_OFFSET_Y TOP_SKIP
|
|
|
|
#define DISP_FRAME 8
|
|
|
|
#define KEYBOARD_OFFSET_X SIDE_SKIP
|
|
#define KEYBOARD_OFFSET_Y ( TOP_SKIP + DISPLAY_HEIGHT + DISP_KBD_SKIP )
|
|
|
|
/***********/
|
|
/* typedef */
|
|
/***********/
|
|
typedef struct on_off_sdl_textures_struct_t {
|
|
SDL_Texture* up;
|
|
SDL_Texture* down;
|
|
} on_off_sdl_textures_struct_t;
|
|
|
|
/*************/
|
|
/* variables */
|
|
/*************/
|
|
static int display_offset_x, display_offset_y;
|
|
|
|
color_t colors[ NB_COLORS ];
|
|
static on_off_sdl_textures_struct_t buttons_textures[ NB_KEYS ];
|
|
static on_off_sdl_textures_struct_t annunciators_textures[ NB_ANNUNCIATORS ];
|
|
|
|
static SDL_Window* window;
|
|
static SDL_Renderer* renderer;
|
|
static SDL_Texture* main_texture;
|
|
|
|
/****************************/
|
|
/* functions implementation */
|
|
/****************************/
|
|
static inline unsigned color2bgra( int color )
|
|
{
|
|
return 0xff000000 | ( colors[ color ].r << 16 ) | ( colors[ color ].g << 8 ) | colors[ color ].b;
|
|
}
|
|
|
|
/*
|
|
Create a SDL_Texture from binary bitmap data
|
|
*/
|
|
static SDL_Texture* bitmap_to_texture( unsigned int w, unsigned int h, unsigned char* data, int color_fg, int color_bg )
|
|
{
|
|
SDL_Surface* surf = SDL_CreateRGBSurface( SDL_SWSURFACE, w, h, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000 );
|
|
|
|
SDL_LockSurface( surf );
|
|
|
|
unsigned char* pixels = ( unsigned char* )surf->pixels;
|
|
unsigned int pitch = surf->pitch;
|
|
unsigned byteperline = w / 8;
|
|
if ( byteperline * 8 != w )
|
|
byteperline++;
|
|
|
|
for ( unsigned int y = 0; y < h; y++ ) {
|
|
unsigned int* lineptr = ( unsigned int* )( pixels + y * pitch );
|
|
for ( unsigned int x = 0; x < w; x++ ) {
|
|
// Address the correct byte
|
|
char c = data[ y * byteperline + ( x >> 3 ) ];
|
|
// Look for the bit in that byte
|
|
char b = c & ( 1 << ( x & 7 ) );
|
|
|
|
lineptr[ x ] = color2bgra( b ? color_fg : color_bg );
|
|
}
|
|
}
|
|
|
|
SDL_UnlockSurface( surf );
|
|
|
|
SDL_Texture* tex = SDL_CreateTextureFromSurface( renderer, surf );
|
|
SDL_FreeSurface( surf );
|
|
|
|
return tex;
|
|
}
|
|
|
|
static void __draw_pixel( int x, int y, int color )
|
|
{
|
|
SDL_SetRenderDrawColor( renderer, colors[ color ].r, colors[ color ].g, colors[ color ].b, colors[ color ].a );
|
|
SDL_RenderDrawPoint( renderer, x, y );
|
|
}
|
|
|
|
static void __draw_line( int x1, int y1, int x2, int y2, int color )
|
|
{
|
|
SDL_SetRenderDrawColor( renderer, colors[ color ].r, colors[ color ].g, colors[ color ].b, colors[ color ].a );
|
|
SDL_RenderDrawLine( renderer, x1, y1, x2, y2 );
|
|
}
|
|
|
|
static void __draw_rect( int x, int y, int w, int h, int color )
|
|
{
|
|
SDL_Rect rect;
|
|
rect.x = x;
|
|
rect.y = y;
|
|
rect.w = w;
|
|
rect.h = h;
|
|
|
|
SDL_SetRenderDrawColor( renderer, colors[ color ].r, colors[ color ].g, colors[ color ].b, colors[ color ].a );
|
|
SDL_RenderFillRect( renderer, &rect );
|
|
}
|
|
|
|
static void __draw_texture( int x, int y, unsigned int w, unsigned int h, SDL_Texture* texture )
|
|
{
|
|
SDL_Rect drect;
|
|
drect.x = x;
|
|
drect.y = y;
|
|
drect.w = w;
|
|
drect.h = h;
|
|
|
|
SDL_RenderCopy( renderer, texture, NULL, &drect );
|
|
}
|
|
|
|
static void __draw_bitmap( int x, int y, unsigned int w, unsigned int h, unsigned char* data, int color_fg, int color_bg )
|
|
{
|
|
__draw_texture( x, y, w, h, bitmap_to_texture( w, h, data, color_fg, color_bg ) );
|
|
}
|
|
|
|
static void write_with_small_font( int x, int y, const char* string, int color_fg, int color_bg )
|
|
{
|
|
for ( unsigned int i = 0; i < strlen( string ); i++ ) {
|
|
if ( small_font[ ( int )string[ i ] ].h != 0 )
|
|
__draw_bitmap( x, ( int )( y - small_font[ ( int )string[ i ] ].h ), small_font[ ( int )string[ i ] ].w,
|
|
small_font[ ( int )string[ i ] ].h, small_font[ ( int )string[ i ] ].bits, color_fg, color_bg );
|
|
|
|
x += SmallTextWidth( &string[ i ], 1 );
|
|
}
|
|
}
|
|
|
|
static void colors_setup( void )
|
|
{
|
|
// Adjust the LCD color according to the contrast
|
|
int contrast = display.contrast;
|
|
if ( contrast < 0x3 )
|
|
contrast = 0x3;
|
|
if ( contrast > 0x13 )
|
|
contrast = 0x13;
|
|
|
|
for ( unsigned i = FIRST_COLOR; i < LAST_COLOR; i++ ) {
|
|
colors[ i ] = COLORS[ i ];
|
|
if ( config.mono ) {
|
|
colors[ i ].r = colors[ i ].mono_rgb;
|
|
colors[ i ].g = colors[ i ].mono_rgb;
|
|
colors[ i ].b = colors[ i ].mono_rgb;
|
|
} else if ( config.gray ) {
|
|
colors[ i ].r = colors[ i ].gray_rgb;
|
|
colors[ i ].g = colors[ i ].gray_rgb;
|
|
colors[ i ].b = colors[ i ].gray_rgb;
|
|
}
|
|
|
|
if ( !config.mono && i == PIXEL ) {
|
|
colors[ i ].r = ( 0x13 - contrast ) * ( colors[ LCD ].r / 0x10 );
|
|
colors[ i ].g = ( 0x13 - contrast ) * ( colors[ LCD ].g / 0x10 );
|
|
colors[ i ].b = 128 - ( ( 0x13 - contrast ) * ( ( 128 - colors[ LCD ].b ) / 0x10 ) );
|
|
}
|
|
}
|
|
}
|
|
|
|
// This should be called once to setup the surfaces. Calling it multiple
|
|
// times is fine, it won't do anything on subsequent calls.
|
|
static void create_annunciators_textures( void )
|
|
{
|
|
for ( int i = 0; i < NB_ANNUNCIATORS; i++ ) {
|
|
annunciators_textures[ i ].up = bitmap_to_texture( ann_tbl[ i ].width, ann_tbl[ i ].height, ann_tbl[ i ].bits, PIXEL, LCD );
|
|
annunciators_textures[ i ].down = bitmap_to_texture( ann_tbl[ i ].width, ann_tbl[ i ].height, ann_tbl[ i ].bits, LCD, LCD );
|
|
}
|
|
}
|
|
|
|
// Find which key is pressed, if any.
|
|
// Returns -1 is no key is pressed
|
|
static int mouse_click_to_hpkey( unsigned int x, unsigned int y )
|
|
{
|
|
/* return immediatly if the click isn't even in the keyboard area */
|
|
if ( y < KEYBOARD_OFFSET_Y )
|
|
return -1;
|
|
|
|
int row = ( y - KEYBOARD_OFFSET_Y ) / ( KEYBOARD_HEIGHT / 9 );
|
|
int column;
|
|
switch ( row ) {
|
|
case 0:
|
|
case 1:
|
|
case 2:
|
|
case 3:
|
|
column = ( x - KEYBOARD_OFFSET_X ) / ( KEYBOARD_WIDTH / 6 );
|
|
return ( row * 6 ) + column;
|
|
case 4: /* with [ENTER] key */
|
|
column = ( ( x - KEYBOARD_OFFSET_X ) / ( KEYBOARD_WIDTH / 5 ) ) - 1;
|
|
if ( column < 0 )
|
|
column = 0;
|
|
return ( 4 * 6 ) + column;
|
|
case 5:
|
|
case 6:
|
|
case 7:
|
|
case 8:
|
|
column = ( x - KEYBOARD_OFFSET_X ) / ( KEYBOARD_WIDTH / 5 );
|
|
return ( 4 * 6 ) + 5 + ( ( row - 5 ) * 5 ) + column;
|
|
|
|
default:
|
|
return -1;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
// Map the keyboard keys to the HP keys
|
|
// Returns -1 if there is no mapping
|
|
static int sdlkey_to_hpkey( SDL_Keycode k )
|
|
{
|
|
switch ( k ) {
|
|
case SDLK_0:
|
|
return HPKEY_0;
|
|
case SDLK_1:
|
|
return HPKEY_1;
|
|
case SDLK_2:
|
|
return HPKEY_2;
|
|
case SDLK_3:
|
|
return HPKEY_3;
|
|
case SDLK_4:
|
|
return HPKEY_4;
|
|
case SDLK_5:
|
|
return HPKEY_5;
|
|
case SDLK_6:
|
|
return HPKEY_6;
|
|
case SDLK_7:
|
|
return HPKEY_7;
|
|
case SDLK_8:
|
|
return HPKEY_8;
|
|
case SDLK_9:
|
|
return HPKEY_9;
|
|
case SDLK_KP_0:
|
|
return HPKEY_0;
|
|
case SDLK_KP_1:
|
|
return HPKEY_1;
|
|
case SDLK_KP_2:
|
|
return HPKEY_2;
|
|
case SDLK_KP_3:
|
|
return HPKEY_3;
|
|
case SDLK_KP_4:
|
|
return HPKEY_4;
|
|
case SDLK_KP_5:
|
|
return HPKEY_5;
|
|
case SDLK_KP_6:
|
|
return HPKEY_6;
|
|
case SDLK_KP_7:
|
|
return HPKEY_7;
|
|
case SDLK_KP_8:
|
|
return HPKEY_8;
|
|
case SDLK_KP_9:
|
|
return HPKEY_9;
|
|
case SDLK_a:
|
|
return HPKEY_A;
|
|
case SDLK_b:
|
|
return HPKEY_B;
|
|
case SDLK_c:
|
|
return HPKEY_C;
|
|
case SDLK_d:
|
|
return HPKEY_D;
|
|
case SDLK_e:
|
|
return HPKEY_E;
|
|
case SDLK_f:
|
|
return HPKEY_F;
|
|
case SDLK_g:
|
|
return HPKEY_MTH;
|
|
case SDLK_h:
|
|
return HPKEY_PRG;
|
|
case SDLK_i:
|
|
return HPKEY_CST;
|
|
case SDLK_j:
|
|
return HPKEY_VAR;
|
|
case SDLK_k:
|
|
return HPKEY_UP;
|
|
case SDLK_UP:
|
|
return HPKEY_UP;
|
|
case SDLK_l:
|
|
return HPKEY_NXT;
|
|
case SDLK_m:
|
|
return HPKEY_COLON;
|
|
case SDLK_n:
|
|
return HPKEY_STO;
|
|
case SDLK_o:
|
|
return HPKEY_EVAL;
|
|
case SDLK_p:
|
|
return HPKEY_LEFT;
|
|
case SDLK_LEFT:
|
|
return HPKEY_LEFT;
|
|
case SDLK_q:
|
|
return HPKEY_DOWN;
|
|
case SDLK_DOWN:
|
|
return HPKEY_DOWN;
|
|
case SDLK_r:
|
|
return HPKEY_RIGHT;
|
|
case SDLK_RIGHT:
|
|
return HPKEY_RIGHT;
|
|
case SDLK_s:
|
|
return HPKEY_SIN;
|
|
case SDLK_t:
|
|
return HPKEY_COS;
|
|
case SDLK_u:
|
|
return HPKEY_TAN;
|
|
case SDLK_v:
|
|
return HPKEY_SQRT;
|
|
case SDLK_w:
|
|
return HPKEY_POWER;
|
|
case SDLK_x:
|
|
return HPKEY_INV;
|
|
case SDLK_y:
|
|
return HPKEY_NEG;
|
|
case SDLK_z:
|
|
return HPKEY_EEX;
|
|
case SDLK_SPACE:
|
|
return HPKEY_SPC;
|
|
case SDLK_F1:
|
|
case SDLK_RETURN:
|
|
case SDLK_KP_ENTER:
|
|
return HPKEY_ENTER;
|
|
case SDLK_BACKSPACE:
|
|
return HPKEY_BS;
|
|
case SDLK_DELETE:
|
|
return HPKEY_DEL;
|
|
case SDLK_PERIOD:
|
|
return HPKEY_PERIOD;
|
|
case SDLK_KP_PERIOD:
|
|
return HPKEY_PERIOD;
|
|
case SDLK_PLUS:
|
|
return HPKEY_PLUS;
|
|
case SDLK_KP_PLUS:
|
|
return HPKEY_PLUS;
|
|
case SDLK_MINUS:
|
|
return HPKEY_MINUS;
|
|
case SDLK_KP_MINUS:
|
|
return HPKEY_MINUS;
|
|
case SDLK_ASTERISK:
|
|
return HPKEY_MUL;
|
|
case SDLK_KP_MULTIPLY:
|
|
return HPKEY_MUL;
|
|
case SDLK_SLASH:
|
|
return HPKEY_DIV;
|
|
case SDLK_KP_DIVIDE:
|
|
return HPKEY_DIV;
|
|
case SDLK_F5:
|
|
case SDLK_ESCAPE:
|
|
return HPKEY_ON;
|
|
case SDLK_LSHIFT:
|
|
if ( !config.leave_shift_keys )
|
|
return HPKEY_SHL;
|
|
break;
|
|
case SDLK_RSHIFT:
|
|
if ( !config.leave_shift_keys )
|
|
return HPKEY_SHR;
|
|
break;
|
|
case SDLK_F2:
|
|
case SDLK_RCTRL:
|
|
return HPKEY_SHL;
|
|
case SDLK_F3:
|
|
case SDLK_LCTRL:
|
|
return HPKEY_SHR;
|
|
case SDLK_F4:
|
|
case SDLK_LALT:
|
|
case SDLK_RALT:
|
|
return HPKEY_ALPHA;
|
|
case SDLK_F7:
|
|
case SDLK_F10:
|
|
// please_exit = true;
|
|
close_and_exit();
|
|
return -1;
|
|
default:
|
|
return -1;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
static void _draw_bezel( unsigned int cut, unsigned int offset_y, int keypad_width, int keypad_height )
|
|
{
|
|
// bottom lines
|
|
__draw_line( 1, keypad_height - 1, keypad_width - 1, keypad_height - 1, PAD_TOP );
|
|
__draw_line( 2, keypad_height - 2, keypad_width - 2, keypad_height - 2, PAD_TOP );
|
|
|
|
// right lines
|
|
__draw_line( keypad_width - 1, keypad_height - 1, keypad_width - 1, cut, PAD_TOP );
|
|
__draw_line( keypad_width - 2, keypad_height - 2, keypad_width - 2, cut, PAD_TOP );
|
|
|
|
// right lines
|
|
__draw_line( keypad_width - 1, cut - 1, keypad_width - 1, 1, DISP_PAD_TOP );
|
|
__draw_line( keypad_width - 2, cut - 1, keypad_width - 2, 2, DISP_PAD_TOP );
|
|
|
|
// top lines
|
|
__draw_line( 0, 0, keypad_width - 2, 0, DISP_PAD_BOT );
|
|
__draw_line( 1, 1, keypad_width - 3, 1, DISP_PAD_BOT );
|
|
|
|
// left lines
|
|
__draw_line( 0, cut - 1, 0, 0, DISP_PAD_BOT );
|
|
__draw_line( 1, cut - 1, 1, 1, DISP_PAD_BOT );
|
|
|
|
// left lines
|
|
__draw_line( 0, keypad_height - 2, 0, cut, PAD_BOT );
|
|
__draw_line( 1, keypad_height - 3, 1, cut, PAD_BOT );
|
|
|
|
// lower the menu BUTTONS
|
|
|
|
// bottom lines
|
|
__draw_line( 3, keypad_height - 3, keypad_width - 3, keypad_height - 3, PAD_TOP );
|
|
__draw_line( 4, keypad_height - 4, keypad_width - 4, keypad_height - 4, PAD_TOP );
|
|
|
|
// right lines
|
|
__draw_line( keypad_width - 3, keypad_height - 3, keypad_width - 3, cut, PAD_TOP );
|
|
__draw_line( keypad_width - 4, keypad_height - 4, keypad_width - 4, cut, PAD_TOP );
|
|
|
|
// right lines
|
|
__draw_line( keypad_width - 3, cut - 1, keypad_width - 3, offset_y - ( KBD_UPLINE - 1 ), DISP_PAD_TOP );
|
|
__draw_line( keypad_width - 4, cut - 1, keypad_width - 4, offset_y - ( KBD_UPLINE - 2 ), DISP_PAD_TOP );
|
|
|
|
// top lines
|
|
__draw_line( 2, offset_y - ( KBD_UPLINE - 0 ), keypad_width - 4, offset_y - ( KBD_UPLINE - 0 ), DISP_PAD_BOT );
|
|
__draw_line( 3, offset_y - ( KBD_UPLINE - 1 ), keypad_width - 5, offset_y - ( KBD_UPLINE - 1 ), DISP_PAD_BOT );
|
|
|
|
// left lines
|
|
__draw_line( 2, cut - 1, 2, offset_y - ( KBD_UPLINE - 1 ), DISP_PAD_BOT );
|
|
__draw_line( 3, cut - 1, 3, offset_y - ( KBD_UPLINE - 2 ), DISP_PAD_BOT );
|
|
|
|
// left lines
|
|
__draw_line( 2, keypad_height - 4, 2, cut, PAD_BOT );
|
|
__draw_line( 3, keypad_height - 5, 3, cut, PAD_BOT );
|
|
|
|
// lower the keyboard
|
|
|
|
// bottom lines
|
|
__draw_line( 5, keypad_height - 5, keypad_width - 3, keypad_height - 5, PAD_TOP );
|
|
__draw_line( 6, keypad_height - 6, keypad_width - 4, keypad_height - 6, PAD_TOP );
|
|
|
|
// right lines
|
|
__draw_line( keypad_width - 5, keypad_height - 5, keypad_width - 5, cut + 1, PAD_TOP );
|
|
__draw_line( keypad_width - 6, keypad_height - 6, keypad_width - 6, cut + 2, PAD_TOP );
|
|
|
|
// top lines
|
|
__draw_line( 4, cut, keypad_width - 6, cut, DISP_PAD_BOT );
|
|
__draw_line( 5, cut + 1, keypad_width - 7, cut + 1, DISP_PAD_BOT );
|
|
|
|
// left lines
|
|
__draw_line( 4, keypad_height - 6, 4, cut + 1, PAD_BOT );
|
|
__draw_line( 5, keypad_height - 7, 5, cut + 2, PAD_BOT );
|
|
|
|
// round off the bottom edge
|
|
__draw_line( keypad_width - 7, keypad_height - 7, keypad_width - 7, keypad_height - 14, PAD_TOP );
|
|
__draw_line( keypad_width - 8, keypad_height - 8, keypad_width - 8, keypad_height - 11, PAD_TOP );
|
|
__draw_line( keypad_width - 7, keypad_height - 7, keypad_width - 14, keypad_height - 7, PAD_TOP );
|
|
__draw_line( keypad_width - 7, keypad_height - 8, keypad_width - 11, keypad_height - 8, PAD_TOP );
|
|
__draw_pixel( keypad_width - 9, keypad_height - 9, PAD_TOP );
|
|
|
|
__draw_line( 7, keypad_height - 7, 13, keypad_height - 7, PAD_TOP );
|
|
__draw_line( 8, keypad_height - 8, 10, keypad_height - 8, PAD_TOP );
|
|
|
|
__draw_line( 6, keypad_height - 8, 6, keypad_height - 14, PAD_BOT );
|
|
__draw_line( 7, keypad_height - 9, 7, keypad_height - 11, PAD_BOT );
|
|
}
|
|
|
|
static void _draw_header( void )
|
|
{
|
|
int x = display_offset_x;
|
|
int y;
|
|
|
|
// insert the HP Logo
|
|
if ( opt_gx )
|
|
x -= 6;
|
|
|
|
__draw_bitmap( x, 10, hp_width, hp_height, hp_bitmap, LOGO, LOGO_BACK );
|
|
|
|
if ( !opt_gx ) {
|
|
__draw_line( display_offset_x, 9, display_offset_x + hp_width - 1, 9, FRAME );
|
|
__draw_line( display_offset_x - 1, 10, display_offset_x - 1, 10 + hp_height - 1, FRAME );
|
|
__draw_line( display_offset_x, 10 + hp_height, display_offset_x + hp_width - 1, 10 + hp_height, FRAME );
|
|
__draw_line( display_offset_x + hp_width, 10, display_offset_x + hp_width, 10 + hp_height - 1, FRAME );
|
|
}
|
|
|
|
// write the name of it
|
|
if ( opt_gx ) {
|
|
x = display_offset_x + DISPLAY_WIDTH - gx_128K_ram_width + gx_128K_ram_x_hot + 2;
|
|
y = 10 + gx_128K_ram_y_hot;
|
|
__draw_bitmap( x, y, gx_128K_ram_width, gx_128K_ram_height, gx_128K_ram_bitmap, LABEL, DISP_PAD );
|
|
|
|
x = display_offset_x + hp_width;
|
|
y = hp_height + 8 - hp48gx_height;
|
|
__draw_bitmap( x, y, hp48gx_width, hp48gx_height, hp48gx_bitmap, LOGO, DISP_PAD );
|
|
|
|
x = display_offset_x + DISPLAY_WIDTH - gx_128K_ram_width + gx_silver_x_hot + 2;
|
|
y = 10 + gx_silver_y_hot;
|
|
__draw_bitmap( x, y, gx_silver_width, gx_silver_height, gx_silver_bitmap, LOGO,
|
|
0 ); // Background transparent: draw only silver line
|
|
|
|
x = display_offset_x + DISPLAY_WIDTH - gx_128K_ram_width + gx_green_x_hot + 2;
|
|
y = 10 + gx_green_y_hot;
|
|
__draw_bitmap( x, y, gx_green_width, gx_green_height, gx_green_bitmap, RIGHT,
|
|
0 ); // Background transparent: draw only green menu
|
|
} else {
|
|
x = display_offset_x;
|
|
y = TOP_SKIP - DISP_FRAME - hp48sx_height - 3;
|
|
__draw_bitmap( x, y, hp48sx_width, hp48sx_height, hp48sx_bitmap, RIGHT,
|
|
0 ); // Background transparent: draw only green menu
|
|
|
|
x = display_offset_x + DISPLAY_WIDTH - 1 - science_width;
|
|
y = TOP_SKIP - DISP_FRAME - science_height - 4;
|
|
__draw_bitmap( x, y, science_width, science_height, science_bitmap, RIGHT,
|
|
0 ); // Background transparent: draw only green menu
|
|
}
|
|
}
|
|
|
|
static SDL_Texture* create_button_texture( int hpkey, bool is_up )
|
|
{
|
|
int x, y;
|
|
SDL_Texture* texture =
|
|
SDL_CreateTexture( renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, BUTTONS[ hpkey ].w, BUTTONS[ hpkey ].h );
|
|
SDL_SetRenderTarget( renderer, texture );
|
|
|
|
// Fill the button and outline
|
|
__draw_rect( 0, 0, BUTTONS[ hpkey ].w, BUTTONS[ hpkey ].h, BUTTON );
|
|
|
|
// draw edge of button
|
|
// left
|
|
__draw_line( 1, BUTTONS[ hpkey ].h - 2, 1, 1, BUT_TOP );
|
|
__draw_line( 2, BUTTONS[ hpkey ].h - 3, 2, 2, BUT_TOP );
|
|
__draw_line( 3, BUTTONS[ hpkey ].h - 4, 3, 3, BUT_TOP );
|
|
// top
|
|
__draw_line( 1, 1, BUTTONS[ hpkey ].w - 2, 1, BUT_TOP );
|
|
__draw_line( 2, 2, BUTTONS[ hpkey ].w - 3, 2, BUT_TOP );
|
|
__draw_line( 3, 3, BUTTONS[ hpkey ].w - 4, 3, BUT_TOP );
|
|
__draw_line( 4, 4, BUTTONS[ hpkey ].w - 5, 4, BUT_TOP );
|
|
// top-left
|
|
__draw_pixel( 4, 5, BUT_TOP );
|
|
// bottom
|
|
__draw_line( 3, BUTTONS[ hpkey ].h - 2, BUTTONS[ hpkey ].w - 2, BUTTONS[ hpkey ].h - 2, BUT_BOT );
|
|
__draw_line( 4, BUTTONS[ hpkey ].h - 3, BUTTONS[ hpkey ].w - 3, BUTTONS[ hpkey ].h - 3, BUT_BOT );
|
|
// right
|
|
__draw_line( BUTTONS[ hpkey ].w - 2, BUTTONS[ hpkey ].h - 2, BUTTONS[ hpkey ].w - 2, 3, BUT_BOT );
|
|
__draw_line( BUTTONS[ hpkey ].w - 3, BUTTONS[ hpkey ].h - 3, BUTTONS[ hpkey ].w - 3, 4, BUT_BOT );
|
|
__draw_line( BUTTONS[ hpkey ].w - 4, BUTTONS[ hpkey ].h - 4, BUTTONS[ hpkey ].w - 4, 5, BUT_BOT );
|
|
__draw_pixel( BUTTONS[ hpkey ].w - 5, BUTTONS[ hpkey ].h - 4, BUT_BOT );
|
|
|
|
// draw frame around button
|
|
// left
|
|
__draw_line( 0, BUTTONS[ hpkey ].h - 3, 0, 2, FRAME );
|
|
if ( !is_up )
|
|
__draw_line( 1, BUTTONS[ hpkey ].h - 3, 1, 2, FRAME ); /* down */
|
|
// top
|
|
__draw_line( 2, 0, BUTTONS[ hpkey ].w - 3, 0, FRAME );
|
|
if ( !is_up )
|
|
__draw_line( 2, 1, BUTTONS[ hpkey ].w - 3, 1, FRAME ); /* down */
|
|
// bottom
|
|
__draw_line( 2, BUTTONS[ hpkey ].h - 1, BUTTONS[ hpkey ].w - 3, BUTTONS[ hpkey ].h - 1, FRAME );
|
|
if ( !is_up )
|
|
__draw_line( 2, BUTTONS[ hpkey ].h - 2, BUTTONS[ hpkey ].w - 3, BUTTONS[ hpkey ].h - 2, FRAME ); /* down */
|
|
// right
|
|
__draw_line( BUTTONS[ hpkey ].w - 1, BUTTONS[ hpkey ].h - 3, BUTTONS[ hpkey ].w - 1, 2, FRAME );
|
|
if ( !is_up )
|
|
__draw_line( BUTTONS[ hpkey ].w - 2, BUTTONS[ hpkey ].h - 3, BUTTONS[ hpkey ].w - 2, 2, FRAME ); /* down */
|
|
if ( hpkey == HPKEY_ON ) {
|
|
if ( is_up ) {
|
|
// top
|
|
__draw_line( 1, 1, BUTTONS[ hpkey ].w - 2, 1, FRAME );
|
|
// top-left
|
|
__draw_pixel( 1, 2, FRAME );
|
|
// top-right
|
|
__draw_pixel( BUTTONS[ hpkey ].w - 2, 2, FRAME );
|
|
} else {
|
|
// top
|
|
__draw_line( 1, 2, BUTTONS[ hpkey ].w - 2, 2, FRAME ); /* down change */
|
|
// top-left
|
|
__draw_pixel( 1, 3, FRAME ); /* down change */
|
|
// top-right
|
|
__draw_pixel( BUTTONS[ hpkey ].w - 2, 3, FRAME ); /* down change */
|
|
}
|
|
} else {
|
|
if ( is_up ) {
|
|
// top-left
|
|
__draw_pixel( 1, 1, FRAME );
|
|
// top-right
|
|
__draw_pixel( BUTTONS[ hpkey ].w - 2, 1, FRAME );
|
|
} else {
|
|
// top-left
|
|
__draw_pixel( 1, 2, FRAME ); /* down change */
|
|
// top-right
|
|
__draw_pixel( BUTTONS[ hpkey ].w - 2, 2, FRAME ); /* down change */
|
|
}
|
|
}
|
|
// bottom-left
|
|
__draw_pixel( 1, BUTTONS[ hpkey ].h - 2, FRAME );
|
|
// bottom-right
|
|
__draw_pixel( BUTTONS[ hpkey ].w - 2, BUTTONS[ hpkey ].h - 2, FRAME );
|
|
|
|
if ( BUTTONS[ hpkey ].label != ( char* )0 ) {
|
|
/* Button has a text label */
|
|
x = ( BUTTONS[ hpkey ].w - strlen( BUTTONS[ hpkey ].label ) * 8 ) / 2;
|
|
if ( is_up )
|
|
y = ( BUTTONS[ hpkey ].h + 1 ) / 2 - 4;
|
|
else
|
|
y = ( BUTTONS[ hpkey ].h + 1 ) / 2 - 5; /* down change */
|
|
|
|
stringRGBA( renderer, x, y, BUTTONS[ hpkey ].label, 255, 255, 255, 255 );
|
|
} else if ( BUTTONS[ hpkey ].lw != 0 ) {
|
|
/* Button has a texture */
|
|
x = ( 1 + BUTTONS[ hpkey ].w - BUTTONS[ hpkey ].lw ) / 2;
|
|
if ( is_up )
|
|
y = ( 1 + BUTTONS[ hpkey ].h - BUTTONS[ hpkey ].lh ) / 2 + 1;
|
|
else
|
|
y = ( 1 + BUTTONS[ hpkey ].h - BUTTONS[ hpkey ].lh ) / 2;
|
|
|
|
__draw_bitmap( x, y, BUTTONS[ hpkey ].lw, BUTTONS[ hpkey ].lh, BUTTONS[ hpkey ].lb, BUTTONS[ hpkey ].lc, BUTTON );
|
|
}
|
|
|
|
return texture;
|
|
}
|
|
|
|
static void create_buttons_textures( void )
|
|
{
|
|
for ( int i = FIRST_HPKEY; i <= LAST_HPKEY; i++ ) {
|
|
buttons_textures[ i ].up = create_button_texture( i, true );
|
|
buttons_textures[ i ].down = create_button_texture( i, false );
|
|
}
|
|
|
|
// Give back to renderer as it was
|
|
SDL_SetRenderTarget( renderer, main_texture );
|
|
}
|
|
|
|
static void _draw_key( int hpkey )
|
|
{
|
|
__draw_texture( KEYBOARD_OFFSET_X + BUTTONS[ hpkey ].x, KEYBOARD_OFFSET_Y + BUTTONS[ hpkey ].y, BUTTONS[ hpkey ].w, BUTTONS[ hpkey ].h,
|
|
keyboard[ hpkey ].pressed ? buttons_textures[ hpkey ].down : buttons_textures[ hpkey ].up );
|
|
}
|
|
|
|
static void _draw_keypad( void )
|
|
{
|
|
int x, y;
|
|
int pw = opt_gx ? 58 : 44;
|
|
int ph = opt_gx ? 48 : 9;
|
|
int left_label_width, right_label_width;
|
|
int space_char_width = SmallTextWidth( " ", 1 );
|
|
int total_top_labels_width;
|
|
|
|
for ( int i = FIRST_HPKEY; i <= LAST_HPKEY; i++ ) {
|
|
// Background
|
|
if ( BUTTONS[ i ].is_menu ) {
|
|
x = KEYBOARD_OFFSET_X + BUTTONS[ i ].x;
|
|
y = KEYBOARD_OFFSET_Y + BUTTONS[ i ].y - small_ascent - small_descent;
|
|
|
|
if ( opt_gx ) {
|
|
x -= 6;
|
|
y -= 6;
|
|
} else
|
|
x += ( BUTTONS[ i ].w - pw ) / 2;
|
|
|
|
__draw_rect( x, y, pw, ph, UNDERLAY );
|
|
}
|
|
|
|
// Letter (small character bottom right of key)
|
|
if ( BUTTONS[ i ].letter != ( char* )0 ) {
|
|
x = KEYBOARD_OFFSET_X + BUTTONS[ i ].x + BUTTONS[ i ].w;
|
|
y = KEYBOARD_OFFSET_Y + BUTTONS[ i ].y + BUTTONS[ i ].h;
|
|
|
|
if ( opt_gx ) {
|
|
x += 3;
|
|
y += 1;
|
|
} else {
|
|
x -= SmallTextWidth( BUTTONS[ i ].letter, 1 ) / 2 + 5;
|
|
y -= 2;
|
|
}
|
|
|
|
write_with_small_font( x, y, BUTTONS[ i ].letter, WHITE, ( i < HPKEY_MTH ) ? DISP_PAD : PAD );
|
|
}
|
|
|
|
// Bottom label: the only one is the cancel button
|
|
if ( BUTTONS[ i ].sub != ( char* )0 ) {
|
|
x = KEYBOARD_OFFSET_X + BUTTONS[ i ].x +
|
|
( 1 + BUTTONS[ i ].w - SmallTextWidth( BUTTONS[ i ].sub, strlen( BUTTONS[ i ].sub ) ) ) / 2;
|
|
y = KEYBOARD_OFFSET_Y + BUTTONS[ i ].y + BUTTONS[ i ].h + small_ascent + 2;
|
|
write_with_small_font( x, y, BUTTONS[ i ].sub, WHITE, PAD );
|
|
}
|
|
|
|
total_top_labels_width = 0;
|
|
// Draw the left labels
|
|
if ( BUTTONS[ i ].left != ( char* )0 ) {
|
|
x = KEYBOARD_OFFSET_X + BUTTONS[ i ].x;
|
|
y = KEYBOARD_OFFSET_Y + BUTTONS[ i ].y - small_descent;
|
|
|
|
left_label_width = SmallTextWidth( BUTTONS[ i ].left, strlen( BUTTONS[ i ].left ) );
|
|
total_top_labels_width = left_label_width;
|
|
|
|
if ( BUTTONS[ i ].right != ( char* )0 ) {
|
|
// label to the left
|
|
right_label_width = SmallTextWidth( BUTTONS[ i ].right, strlen( BUTTONS[ i ].right ) );
|
|
total_top_labels_width += space_char_width + right_label_width;
|
|
}
|
|
|
|
x += ( 1 + BUTTONS[ i ].w - total_top_labels_width ) / 2;
|
|
|
|
write_with_small_font( x, y, BUTTONS[ i ].left, LEFT, BUTTONS[ i ].is_menu ? UNDERLAY : PAD );
|
|
}
|
|
|
|
// draw the right labels ( .is_menu never have one )
|
|
if ( BUTTONS[ i ].right != ( char* )0 ) {
|
|
x = KEYBOARD_OFFSET_X + BUTTONS[ i ].x;
|
|
y = KEYBOARD_OFFSET_Y + BUTTONS[ i ].y - small_descent;
|
|
|
|
if ( BUTTONS[ i ].left == ( char* )0 ) {
|
|
right_label_width = SmallTextWidth( BUTTONS[ i ].right, strlen( BUTTONS[ i ].right ) );
|
|
total_top_labels_width = right_label_width;
|
|
} else
|
|
x += space_char_width + left_label_width;
|
|
|
|
x += ( 1 + BUTTONS[ i ].w - total_top_labels_width ) / 2;
|
|
|
|
write_with_small_font( x, y, BUTTONS[ i ].right, RIGHT, PAD );
|
|
}
|
|
}
|
|
|
|
for ( int i = FIRST_HPKEY; i <= LAST_HPKEY; i++ )
|
|
_draw_key( i );
|
|
}
|
|
|
|
static void _draw_bezel_LCD( void )
|
|
{
|
|
for ( int i = 0; i < DISP_FRAME; i++ ) {
|
|
__draw_line( display_offset_x - i, display_offset_y + DISPLAY_HEIGHT + 2 * i, display_offset_x + DISPLAY_WIDTH + i,
|
|
display_offset_y + DISPLAY_HEIGHT + 2 * i, DISP_PAD_TOP );
|
|
__draw_line( display_offset_x - i, display_offset_y + DISPLAY_HEIGHT + 2 * i + 1, display_offset_x + DISPLAY_WIDTH + i,
|
|
display_offset_y + DISPLAY_HEIGHT + 2 * i + 1, DISP_PAD_TOP );
|
|
__draw_line( display_offset_x + DISPLAY_WIDTH + i, display_offset_y - i, display_offset_x + DISPLAY_WIDTH + i,
|
|
display_offset_y + DISPLAY_HEIGHT + 2 * i, DISP_PAD_TOP );
|
|
|
|
__draw_line( display_offset_x - i - 1, display_offset_y - i - 1, display_offset_x + DISPLAY_WIDTH + i - 1, display_offset_y - i - 1,
|
|
DISP_PAD_BOT );
|
|
__draw_line( display_offset_x - i - 1, display_offset_y - i - 1, display_offset_x - i - 1,
|
|
display_offset_y + DISPLAY_HEIGHT + 2 * i - 1, DISP_PAD_BOT );
|
|
}
|
|
|
|
// round off corners
|
|
__draw_line( display_offset_x - DISP_FRAME, display_offset_y - DISP_FRAME, display_offset_x - DISP_FRAME + 3,
|
|
display_offset_y - DISP_FRAME, DISP_PAD );
|
|
__draw_line( display_offset_x - DISP_FRAME, display_offset_y - DISP_FRAME, display_offset_x - DISP_FRAME,
|
|
display_offset_y - DISP_FRAME + 3, DISP_PAD );
|
|
__draw_pixel( display_offset_x - DISP_FRAME + 1, display_offset_y - DISP_FRAME + 1, DISP_PAD );
|
|
|
|
__draw_line( display_offset_x + DISPLAY_WIDTH + DISP_FRAME - 4, display_offset_y - DISP_FRAME,
|
|
display_offset_x + DISPLAY_WIDTH + DISP_FRAME - 1, display_offset_y - DISP_FRAME, DISP_PAD );
|
|
__draw_line( display_offset_x + DISPLAY_WIDTH + DISP_FRAME - 1, display_offset_y - DISP_FRAME,
|
|
display_offset_x + DISPLAY_WIDTH + DISP_FRAME - 1, display_offset_y - DISP_FRAME + 3, DISP_PAD );
|
|
__draw_pixel( display_offset_x + DISPLAY_WIDTH + DISP_FRAME - 2, display_offset_y - DISP_FRAME + 1, DISP_PAD );
|
|
|
|
__draw_line( display_offset_x - DISP_FRAME, display_offset_y + DISPLAY_HEIGHT + 2 * DISP_FRAME - 4, display_offset_x - DISP_FRAME,
|
|
display_offset_y + DISPLAY_HEIGHT + 2 * DISP_FRAME - 1, DISP_PAD );
|
|
__draw_line( display_offset_x - DISP_FRAME, display_offset_y + DISPLAY_HEIGHT + 2 * DISP_FRAME - 1, display_offset_x - DISP_FRAME + 3,
|
|
display_offset_y + DISPLAY_HEIGHT + 2 * DISP_FRAME - 1, DISP_PAD );
|
|
__draw_pixel( display_offset_x - DISP_FRAME + 1, display_offset_y + DISPLAY_HEIGHT + 2 * DISP_FRAME - 2, DISP_PAD );
|
|
|
|
__draw_line( display_offset_x + DISPLAY_WIDTH + DISP_FRAME - 1, display_offset_y + DISPLAY_HEIGHT + 2 * DISP_FRAME - 4,
|
|
display_offset_x + DISPLAY_WIDTH + DISP_FRAME - 1, display_offset_y + DISPLAY_HEIGHT + 2 * DISP_FRAME - 1, DISP_PAD );
|
|
__draw_line( display_offset_x + DISPLAY_WIDTH + DISP_FRAME - 4, display_offset_y + DISPLAY_HEIGHT + 2 * DISP_FRAME - 1,
|
|
display_offset_x + DISPLAY_WIDTH + DISP_FRAME - 1, display_offset_y + DISPLAY_HEIGHT + 2 * DISP_FRAME - 1, DISP_PAD );
|
|
__draw_pixel( display_offset_x + DISPLAY_WIDTH + DISP_FRAME - 2, display_offset_y + DISPLAY_HEIGHT + 2 * DISP_FRAME - 2, DISP_PAD );
|
|
|
|
// simulate rounded lcd corners
|
|
__draw_line( display_offset_x - 1, display_offset_y + 1, display_offset_x - 1, display_offset_y + DISPLAY_HEIGHT - 2, LCD );
|
|
__draw_line( display_offset_x + 1, display_offset_y - 1, display_offset_x + DISPLAY_WIDTH - 2, display_offset_y - 1, LCD );
|
|
__draw_line( display_offset_x + 1, display_offset_y + DISPLAY_HEIGHT, display_offset_x + DISPLAY_WIDTH - 2,
|
|
display_offset_y + DISPLAY_HEIGHT, LCD );
|
|
__draw_line( display_offset_x + DISPLAY_WIDTH, display_offset_y + 1, display_offset_x + DISPLAY_WIDTH,
|
|
display_offset_y + DISPLAY_HEIGHT - 2, LCD );
|
|
}
|
|
|
|
static void _draw_background( int width, int height, int w_top, int h_top )
|
|
{
|
|
__draw_rect( 0, 0, w_top, h_top, PAD );
|
|
__draw_rect( 0, 0, width, height, DISP_PAD );
|
|
}
|
|
|
|
static void _draw_background_LCD( void ) { __draw_rect( display_offset_x, display_offset_y, DISPLAY_WIDTH, DISPLAY_HEIGHT, LCD ); }
|
|
|
|
// Show the hp key which is being pressed
|
|
static void _show_key( int hpkey )
|
|
{
|
|
if ( config.hide_chrome || hpkey < 0 )
|
|
return;
|
|
|
|
SDL_SetRenderTarget( renderer, main_texture );
|
|
|
|
_draw_key( hpkey );
|
|
|
|
SDL_SetRenderTarget( renderer, NULL );
|
|
SDL_RenderCopy( renderer, main_texture, NULL, NULL );
|
|
SDL_RenderPresent( renderer );
|
|
|
|
return;
|
|
}
|
|
|
|
static void _draw_serial_devices_path( void )
|
|
{
|
|
char text[ 1024 ] = "";
|
|
|
|
if ( config.verbose ) {
|
|
fprintf( stderr, "wire_name: %s\n", wire_name );
|
|
fprintf( stderr, "ir_name: %s\n", ir_name );
|
|
}
|
|
|
|
if ( wire_name ) {
|
|
strcat( text, "wire: " );
|
|
strcat( text, wire_name );
|
|
}
|
|
if ( ir_name ) {
|
|
if ( strlen( text ) > 0 )
|
|
strcat( text, " | " );
|
|
|
|
strcat( text, "ir: " );
|
|
strcat( text, ir_name );
|
|
}
|
|
|
|
if ( strlen( text ) > 0 )
|
|
stringRGBA( renderer, 10, 240, text, 255, 255, 255, 255 );
|
|
}
|
|
|
|
static void sdl_draw_nibble( int nx, int ny, int val )
|
|
{
|
|
SDL_SetRenderTarget( renderer, main_texture );
|
|
|
|
for ( int x = 0; x < 4; x++ ) {
|
|
if ( nx + x >= 131 ) // Clip at 131 pixels
|
|
break;
|
|
|
|
char pixel = val & ( 1 << ( x & 3 ) );
|
|
|
|
__draw_rect( display_offset_x + 5 + ( 2 * ( nx + x ) ), display_offset_y + 20 + ( 2 * ny ), 2, 2, pixel ? PIXEL : LCD );
|
|
}
|
|
|
|
SDL_SetRenderTarget( renderer, NULL );
|
|
SDL_RenderCopy( renderer, main_texture, NULL, NULL );
|
|
SDL_RenderPresent( renderer );
|
|
}
|
|
|
|
static inline void draw_nibble( int col, int row, int val )
|
|
{
|
|
val &= 0x0f;
|
|
if ( val == lcd_nibbles_buffer[ row ][ col ] )
|
|
return;
|
|
|
|
lcd_nibbles_buffer[ row ][ col ] = val;
|
|
|
|
int x = col * 4;
|
|
if ( row <= display.lines )
|
|
x -= ( 2 * display.offset );
|
|
|
|
sdl_draw_nibble( x, row, val );
|
|
}
|
|
|
|
/* Identical in all ui_*.c */
|
|
static inline void draw_row( long addr, int row )
|
|
{
|
|
int line_length = NIBBLES_PER_ROW;
|
|
|
|
if ( ( display.offset > 3 ) && ( row <= display.lines ) )
|
|
line_length += 2;
|
|
|
|
for ( int i = 0; i < line_length; i++ )
|
|
draw_nibble( i, row, read_nibble( addr + i ) );
|
|
}
|
|
|
|
static int sdl_press_key( int hpkey )
|
|
{
|
|
if ( hpkey == -1 || keyboard[ hpkey ].pressed )
|
|
return -1;
|
|
|
|
press_key( hpkey );
|
|
_show_key( hpkey );
|
|
|
|
return hpkey;
|
|
}
|
|
|
|
static int sdl_release_key( int hpkey )
|
|
{
|
|
if ( hpkey == -1 || !keyboard[ hpkey ].pressed )
|
|
return -1;
|
|
|
|
release_key( hpkey );
|
|
_show_key( hpkey );
|
|
|
|
return hpkey;
|
|
}
|
|
|
|
/**********/
|
|
/* public */
|
|
/**********/
|
|
void sdl_get_event( void )
|
|
{
|
|
SDL_Event event;
|
|
int hpkey = -1;
|
|
static int lasthpkey = -1; // last key that was pressed or -1 for none
|
|
static int lastticks = -1; // time at which a key was pressed or -1 if timer expired
|
|
|
|
// Iterate as long as there are events
|
|
while ( SDL_PollEvent( &event ) ) {
|
|
switch ( event.type ) {
|
|
case SDL_QUIT:
|
|
// please_exit = true;
|
|
close_and_exit();
|
|
break;
|
|
|
|
case SDL_MOUSEBUTTONDOWN:
|
|
hpkey = mouse_click_to_hpkey( event.button.x, event.button.y );
|
|
if ( sdl_press_key( hpkey ) != -1 ) {
|
|
if ( lasthpkey == -1 ) {
|
|
lasthpkey = hpkey;
|
|
// Start timer
|
|
lastticks = SDL_GetTicks();
|
|
} else
|
|
lasthpkey = lastticks = -1;
|
|
}
|
|
|
|
break;
|
|
case SDL_MOUSEBUTTONUP:
|
|
hpkey = mouse_click_to_hpkey( event.button.x, event.button.y );
|
|
if ( lasthpkey != hpkey || lastticks == -1 || ( SDL_GetTicks() - lastticks < 750 ) )
|
|
sdl_release_key( hpkey );
|
|
|
|
lasthpkey = lastticks = -1;
|
|
break;
|
|
|
|
case SDL_KEYDOWN:
|
|
sdl_press_key( sdlkey_to_hpkey( event.key.keysym.sym ) );
|
|
break;
|
|
case SDL_KEYUP:
|
|
sdl_release_key( sdlkey_to_hpkey( event.key.keysym.sym ) );
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void sdl_update_LCD( void )
|
|
{
|
|
if ( display.on ) {
|
|
int i;
|
|
long addr = display.disp_start;
|
|
static int old_offset = -1;
|
|
static int old_lines = -1;
|
|
|
|
if ( display.offset != old_offset ) {
|
|
memset( lcd_nibbles_buffer, 0xf0, ( size_t )( ( display.lines + 1 ) * NIBS_PER_BUFFER_ROW ) );
|
|
old_offset = display.offset;
|
|
}
|
|
if ( display.lines != old_lines ) {
|
|
memset( &lcd_nibbles_buffer[ 56 ][ 0 ], 0xf0, ( size_t )( 8 * NIBS_PER_BUFFER_ROW ) );
|
|
old_lines = display.lines;
|
|
}
|
|
for ( i = 0; i <= display.lines; i++ ) {
|
|
draw_row( addr, i );
|
|
addr += display.nibs_per_line;
|
|
}
|
|
if ( i < DISP_ROWS ) {
|
|
addr = display.menu_start;
|
|
for ( ; i < DISP_ROWS; i++ ) {
|
|
draw_row( addr, i );
|
|
addr += NIBBLES_PER_ROW;
|
|
}
|
|
}
|
|
} else
|
|
ui_init_LCD();
|
|
}
|
|
|
|
void sdl_refresh_LCD( void ) {}
|
|
|
|
void sdl_disp_draw_nibble( word_20 addr, word_4 val )
|
|
{
|
|
long offset = ( addr - display.disp_start );
|
|
int x = offset % display.nibs_per_line;
|
|
|
|
if ( x < 0 || x > 35 )
|
|
return;
|
|
|
|
if ( display.nibs_per_line != 0 ) {
|
|
int y = offset / display.nibs_per_line;
|
|
if ( y < 0 || y > 63 )
|
|
return;
|
|
|
|
draw_nibble( x, y, val );
|
|
} else
|
|
for ( int y = 0; y < display.lines; y++ )
|
|
draw_nibble( x, y, val );
|
|
}
|
|
|
|
void sdl_menu_draw_nibble( word_20 addr, word_4 val )
|
|
{
|
|
long offset = ( addr - display.menu_start );
|
|
int x = offset % NIBBLES_PER_ROW;
|
|
int y = display.lines + ( offset / NIBBLES_PER_ROW ) + 1;
|
|
|
|
draw_nibble( x, y, val );
|
|
}
|
|
|
|
void sdl_draw_annunc( void )
|
|
{
|
|
if ( saturn.annunc == last_annunc_state )
|
|
return;
|
|
|
|
bool annunc_state;
|
|
last_annunc_state = saturn.annunc;
|
|
|
|
SDL_SetRenderTarget( renderer, main_texture );
|
|
|
|
for ( int i = 0; i < NB_ANNUNCIATORS; i++ ) {
|
|
annunc_state = ( ( annunciators_bits[ i ] & saturn.annunc ) == annunciators_bits[ i ] );
|
|
|
|
__draw_texture( display_offset_x + ann_tbl[ i ].x, display_offset_y + ann_tbl[ i ].y, ann_tbl[ i ].width, ann_tbl[ i ].height,
|
|
( annunc_state ) ? annunciators_textures[ i ].up : annunciators_textures[ i ].down );
|
|
}
|
|
|
|
// Always immediately update annunciators
|
|
SDL_SetRenderTarget( renderer, NULL );
|
|
SDL_RenderCopy( renderer, main_texture, NULL, NULL );
|
|
SDL_RenderPresent( renderer );
|
|
}
|
|
|
|
void sdl_adjust_contrast( void )
|
|
{
|
|
colors_setup();
|
|
|
|
// redraw LCD
|
|
ui_init_LCD();
|
|
sdl_update_LCD();
|
|
|
|
// redraw annunc
|
|
last_annunc_state = -1;
|
|
|
|
sdl_draw_annunc();
|
|
}
|
|
|
|
void sdl2_ui_stop( void )
|
|
{
|
|
SDL_DestroyTexture( main_texture );
|
|
SDL_DestroyRenderer( renderer );
|
|
SDL_DestroyWindow( window );
|
|
}
|
|
|
|
void init_sdl2_ui( int argc, char** argv )
|
|
{
|
|
if ( config.verbose )
|
|
fprintf( stderr, "UI is sdl2\n" );
|
|
|
|
/* Set public API to this UI's functions */
|
|
ui_disp_draw_nibble = sdl_disp_draw_nibble;
|
|
ui_menu_draw_nibble = sdl_menu_draw_nibble;
|
|
ui_get_event = sdl_get_event;
|
|
ui_update_LCD = sdl_update_LCD;
|
|
ui_refresh_LCD = sdl_refresh_LCD;
|
|
ui_adjust_contrast = sdl_adjust_contrast;
|
|
ui_draw_annunc = sdl_draw_annunc;
|
|
|
|
// Initialize SDL
|
|
if ( SDL_Init( SDL_INIT_VIDEO ) < 0 ) {
|
|
printf( "Couldn't initialize SDL: %s\n", SDL_GetError() );
|
|
exit( 1 );
|
|
}
|
|
|
|
// On exit: clean SDL
|
|
atexit( SDL_Quit );
|
|
|
|
unsigned int width, height;
|
|
display_offset_x = DISPLAY_OFFSET_X;
|
|
display_offset_y = DISPLAY_OFFSET_Y;
|
|
width = ( BUTTONS[ LAST_HPKEY ].x + BUTTONS[ LAST_HPKEY ].w ) + 2 * SIDE_SKIP;
|
|
height = display_offset_y + DISPLAY_HEIGHT + DISP_KBD_SKIP + BUTTONS[ LAST_HPKEY ].y + BUTTONS[ LAST_HPKEY ].h + BOTTOM_SKIP;
|
|
|
|
if ( config.hide_chrome ) {
|
|
display_offset_x = 0;
|
|
display_offset_y = 0;
|
|
width = DISPLAY_WIDTH;
|
|
height = DISPLAY_HEIGHT;
|
|
}
|
|
|
|
uint32_t window_flags = SDL_WINDOW_ALLOW_HIGHDPI;
|
|
if ( config.show_ui_fullscreen )
|
|
window_flags |= SDL_WINDOW_FULLSCREEN_DESKTOP;
|
|
else
|
|
window_flags |= SDL_WINDOW_RESIZABLE;
|
|
|
|
window = SDL_CreateWindow( config.progname, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, width, height, window_flags );
|
|
if ( window == NULL ) {
|
|
printf( "Couldn't create window: %s\n", SDL_GetError() );
|
|
exit( 1 );
|
|
}
|
|
|
|
renderer = SDL_CreateRenderer( window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE );
|
|
if ( renderer == NULL )
|
|
exit( 2 );
|
|
|
|
main_texture = SDL_CreateTexture( renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, width, height );
|
|
|
|
SDL_SetRenderTarget( renderer, main_texture );
|
|
|
|
colors_setup();
|
|
|
|
create_annunciators_textures();
|
|
|
|
if ( !config.hide_chrome ) {
|
|
int cut = BUTTONS[ HPKEY_MTH ].y + KEYBOARD_OFFSET_Y - 19;
|
|
|
|
create_buttons_textures();
|
|
|
|
_draw_background( width, cut, width, height );
|
|
_draw_bezel( cut, KEYBOARD_OFFSET_Y, width, height );
|
|
_draw_header();
|
|
_draw_bezel_LCD();
|
|
_draw_keypad();
|
|
|
|
_draw_serial_devices_path();
|
|
}
|
|
|
|
_draw_background_LCD();
|
|
|
|
SDL_SetRenderTarget( renderer, NULL );
|
|
SDL_RenderCopy( renderer, main_texture, NULL, NULL );
|
|
SDL_RenderPresent( renderer );
|
|
}
|