mupen64plus-oldsvn/blight_input/configdialog_sdl.c

1158 lines
41 KiB
C

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus - configdialog_sdl.c *
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
* Copyright (C) 2002 Blight *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifdef GUI_SDL
#include "configdialog_sdl.h"
#include <stdarg.h>
#include <string.h>
#include "SDL.h"
#include "SDL_thread.h"
#include "SDL_ttf.h"
#include "pad.h" // pad image
#include "arial.ttf.h" // arial font
#define FONT_SIZEPT 15
#define SCREEN_W 640
#define SCREEN_H 480
// callback structure
typedef struct
{
void (*callback)(int _arg);
int arg;
int x;
int y;
int w;
int h;
} SCallback;
// extern functions
extern void read_configuration( void ); // from plugin.c
extern int write_configuration( void ); // from plugin.c
// colors
static Uint32 u32black, u32gray, u32dark_gray, u32gray_border, u32white;
static SDL_Color black = { 0x44, 0x44, 0x44, 0 };
static SDL_Color gray = { 0xEE, 0xEE, 0xEE, 0 };
static SDL_Color dark_gray = { 0xDF, 0xDF, 0xDF, 0 };
static SDL_Color gray_border = { 0x84, 0x84, 0x84, 0 };
static SDL_Color white = { 0xFF, 0xFF, 0xFF, 0 };
// button names
static const char *button_names[] = {
"DPad R", // R_DPAD
"DPad L", // L_DPAD
"DPad D", // D_DPAD
"DPad U", // U_DPAD
"Start", // START_BUTTON
"Z Trig", // Z_TRIG
"B Button", // B_BUTTON
"A Button", // A_BUTTON
"C Button R", // R_CBUTTON
"C Button L", // L_CBUTTON
"C Button D", // D_CBUTTON
"C Button U", // U_CBUTTON
"R Trig", // R_TRIG
"L Trig", // L_TRIG
"Mempak switch",
"Rumblepak switch",
"Y Axis", // Y_AXIS
"X Axis" // X_AXIS
};
// SDL axis names
static char axis_names[] = {
'X', 'Y', 'Z', 'U', 'V', 'W'
};
// globals
static int keep_looping; // set this to 0 to hide the config dialog
static SDL_Surface *screen = NULL;
static SDL_Thread *thread = NULL;
static TTF_Font *font = NULL;
static SDL_Surface *pad = NULL;
static SDL_Joystick *joys[8] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
static int num_joys = 0;
static int okHeld;
static int cancelHeld;
static int cont = 0; // selected controller to configure
static SController config[4]; // configuration (copy)
static SController *orig_cont; // original controllers from plugin.c (to save configuration)
// callback functions
static void controller_tab_clicked( int _arg );
static void button_clicked( int _arg );
static void checkbutton_clicked( int _arg );
static void device_clicked( int _arg );
static void pad_button_clicked( int _arg );
// callbacks
static SCallback callback[] = {
{ controller_tab_clicked, 0, 10, 10, 155, 20 },
{ controller_tab_clicked, 1, 165, 10, 155, 20 },
{ controller_tab_clicked, 2, 320, 10, 155, 20 },
{ controller_tab_clicked, 3, 475, 10, 155, 20 },
{ button_clicked, 0, 150, 445, 90, 25 }, // ok
{ button_clicked, 1, 380, 445, 90, 25 }, // cancel
{ checkbutton_clicked, 0, 20, 45, 90, 25 }, // plugged
{ checkbutton_clicked, 1, 120, 45, 100, 25 }, // plugin
{ device_clicked, 0, 360, 45, 260, 25 }, // device
{ pad_button_clicked, R_DPAD, 110, 245, 50, 20 },
{ pad_button_clicked, L_DPAD, 110, 195, 50, 20 },
{ pad_button_clicked, D_DPAD, 110, 220, 50, 20 },
{ pad_button_clicked, U_DPAD, 110, 170, 50, 20 },
{ pad_button_clicked, START_BUTTON, 300, 65, 40, 20 },
{ pad_button_clicked, Z_TRIG, 120, 290, 50, 20 },
{ pad_button_clicked, B_BUTTON, 475, 230, 70, 20 },
{ pad_button_clicked, A_BUTTON, 475, 325, 70, 20 },
{ pad_button_clicked, L_CBUTTON, 475, 130, 80, 20 },
{ pad_button_clicked, U_CBUTTON, 475, 155, 80, 20 },
{ pad_button_clicked, R_CBUTTON, 475, 180, 80, 20 },
{ pad_button_clicked, D_CBUTTON, 475, 205, 80, 20 },
{ pad_button_clicked, R_TRIG, 395, 105, 50, 20 },
{ pad_button_clicked, L_TRIG, 155, 105, 50, 20 },
{ pad_button_clicked, MEMPAK, 110, 350, 150, 20 },
{ pad_button_clicked, RUMBLEPAK, 110, 375, 150, 20 },
{ pad_button_clicked, Y_AXIS, 220, 398, 50, 20 },
{ pad_button_clicked, X_AXIS, 280, 398, 50, 20 },
{ checkbutton_clicked, 2, 340, 398, 110, 25 }, // enable mouse
{ NULL, 0, 0, 0, 0, 0 }
};
// render text
static inline SDL_Surface *
render_text( SDL_Color fg, SDL_Color bg, const char *fmt, ... )
{
va_list ap;
char buf[2049];
va_start( ap, fmt );
vsnprintf( buf, 2048, fmt, ap );
va_end( ap );
if( *buf == '\0' )
return NULL;
return( TTF_RenderText_Shaded( font, buf, fg, bg ) );
}
// write text
static inline void
write_text( SDL_Surface *dst, int x, int y, SDL_Color fg, SDL_Color bg, const char *fmt, ... )
{
SDL_Surface *text;
SDL_Rect dstrect;
memset(&dstrect,0,sizeof(SDL_Rect));
va_list ap;
char buf[2049];
va_start( ap, fmt );
vsnprintf( buf, 2048, fmt, ap );
va_end( ap );
if( *buf == '\0' )
return;
text = render_text( fg, bg, buf );
if( text == NULL )
{
fprintf( stderr, "["PLUGIN_NAME"]: Couldn't render text: %s\n", SDL_GetError() );
return;
}
dstrect.x = x;
dstrect.y = y;
dstrect.w = text->w;
dstrect.h = text->h;
SDL_BlitSurface( text, NULL, dst, &dstrect );
SDL_FreeSurface( text );
}
// controller tab clicked
static void
controller_tab_clicked( int _arg )
{
#ifdef _DEBUG
printf( "controller_tab_clicked(): controller = %d\n", _arg );
#endif
cont = _arg;
}
// button clicked (ok/cancel)
static void
button_clicked( int _arg )
{
if( _arg == 0 )
{
#ifdef _DEBUG
printf( "OK clicked!\n" );
#endif
okHeld = 1;
}
else if( _arg == 1 )
{
#ifdef _DEBUG
printf( "Cancel clicked!\n" );
#endif
cancelHeld = 1;
}
// close dialog
//keep_looping = 0;
}
static void
button_released()
{
int i;
if(okHeld)
{
okHeld = 0;
// save configuration
for( i = 0; i < 4; i++ )
{
orig_cont[i].device = config[i].device;
orig_cont[i].mouse = config[i].mouse;
memcpy( orig_cont[i].axis, config[i].axis, sizeof( SAxisMap ) * 2 );
memcpy( orig_cont[i].button, config[i].button, sizeof( SButtonMap ) * 16 );
memcpy( &orig_cont[i].control, &config[i].control, sizeof( CONTROL ) );
}
write_configuration();
keep_looping = 0;
}
else
{
if(cancelHeld)
{
cancelHeld = 0;
keep_looping = 0;
}
}
}
// plugged/mempak checkbutton clicked
static void
checkbutton_clicked( int _arg )
{
if( _arg == 0 )
{
config[cont].control.Present ^= 1;
}
else if( _arg == 1 )
{
if( config[cont].control.Plugin == PLUGIN_RAW )
config[cont].control.Plugin = PLUGIN_NONE;
else if( config[cont].control.Plugin == PLUGIN_NONE )
config[cont].control.Plugin = PLUGIN_MEMPAK;
else
config[cont].control.Plugin = PLUGIN_RAW;
}
else if( _arg == 2 )
{
if (config[cont].mouse == 0)
{
if (config[0].mouse || config[1].mouse || config[2].mouse || config[3].mouse)
{
// error
}
}
config[cont].mouse ^= 1;
}
}
// device box clicked
static void
device_clicked( int _arg )
{
config[cont].device++;
if( config[cont].device >= num_joys )
config[cont].device = DEVICE_NONE;
}
// open/close joysticks
static void
close_joysticks( void )
{
int i;
for (i = 0; i < 8; i++)
{
if (joys[i] != NULL)
{
SDL_JoystickClose(joys[i]);
joys[i] = NULL;
}
}
num_joys = 0;
}
static void
open_joysticks( void )
{
int i;
if (num_joys > 0)
close_joysticks();
num_joys = SDL_NumJoysticks();
if (num_joys > 8)
num_joys = 8;
for (i = 0; i < num_joys; i++)
{
joys[i] = SDL_JoystickOpen(i);
if (joys[i] == NULL)
{
fprintf( stderr, "["PLUGIN_NAME"]: Couldn't open joystick #%d (%s): %s\n",
i + 1, SDL_JoystickName(i), SDL_GetError() );
}
}
}
// display a small dialog
static void
display_dialog( const char *caption, const char *line1, const char *line2 )
{
SDL_Rect dstrect, dstrect2;
memset(&dstrect,0,sizeof(SDL_Rect));
memset(&dstrect2,0,sizeof(SDL_Rect));
// draw the dialog
dstrect.w = 300; dstrect.h = 100;
dstrect.x = (screen->w - dstrect.w) / 2;
dstrect.y = (screen->h - dstrect.h) / 2;
SDL_FillRect( screen, &dstrect, u32black );
dstrect2.x = dstrect.x + 2; dstrect2.y = dstrect.y + 2;
dstrect2.w = dstrect.w - 4;
dstrect2.h = 25;
SDL_FillRect( screen, &dstrect2, u32gray );
write_text( screen, dstrect2.x + 100, dstrect2.y, black, gray, caption );
dstrect2.y += 26;
dstrect2.h = dstrect.h - 30;
SDL_FillRect( screen, &dstrect2, u32gray );
write_text( screen, dstrect2.x + 10, dstrect2.y, black, gray, line1 );
write_text( screen, dstrect2.x + 10, dstrect2.y + 20, black, gray, line2 );
SDL_Flip( screen );
}
// pad button clicked (read assignment)
static void
pad_button_clicked( int _arg )
{
SDL_Event event;
int waitevent, axis;
char text[2000];
SDLKey key_a = 0;
int button_a = 0;
int hat_pos_a = 0;
int usesaxisforconf = 0;
int axisused = 0;
if( _arg == Y_AXIS || _arg == X_AXIS )
{
// read key/button a
sprintf( text, "a key/button for '%s'",
(_arg == X_AXIS) ? "left" : "up" );
axis = _arg - Y_AXIS;
display_dialog( button_names[_arg], "Move any axis or press", text );
waitevent = 1;
while( waitevent )
{
if( SDL_WaitEvent( &event ) == 0 )
{
fprintf( stderr, "["PLUGIN_NAME"]: SDL_WaitEvent(): %s\n", SDL_GetError() );
return;
}
switch( event.type )
{
case SDL_KEYDOWN:
if( event.key.keysym.sym == SDLK_ESCAPE )
{
return;
}
key_a = event.key.keysym.sym;
waitevent = 0;
break;
case SDL_JOYAXISMOTION:
if( event.jaxis.which == config[cont].device )
{
if( event.jaxis.value >= 15000 )
{
config[cont].axis[axis].axis_a = event.jaxis.axis;
config[cont].axis[axis].axis_dir_a = 1;
usesaxisforconf = 1;
axisused = event.jaxis.axis;
waitevent = 0;
}
else if( event.jaxis.value <= -15000 )
{
config[cont].axis[axis].axis_a = event.jaxis.axis;
config[cont].axis[axis].axis_dir_a = -1;
usesaxisforconf = 1;
axisused = event.jaxis.axis;
waitevent = 0;
}
}
break;
case SDL_JOYBUTTONDOWN:
if( event.jbutton.which == config[cont].device )
{
button_a = event.jbutton.button;
waitevent = 0;
}
break;
case SDL_JOYHATMOTION:
if( event.jhat.which == config[cont].device &&
(event.jhat.value == SDL_HAT_UP || event.jhat.value == SDL_HAT_DOWN ||
event.jhat.value == SDL_HAT_LEFT || event.jhat.value == SDL_HAT_RIGHT))
{
hat_pos_a = event.jhat.value;
waitevent = 0;
}
break;
}
}
if(usesaxisforconf)
{
sprintf(text, "Axis %i selected.", axisused);
display_dialog( button_names[_arg], text, "Please center joystick");
waitevent = 1;
while(waitevent)
{
if( SDL_WaitEvent( &event ) == 0 )
{
fprintf( stderr, "["PLUGIN_NAME"]: SDL_WaitEvent(): %s\n", SDL_GetError() );
return;
}
if (event.type == SDL_JOYAXISMOTION && event.jaxis.which == config[cont].device)
{
if (event.jaxis.axis == axisused && event.jaxis.value >= -10000 && event.jaxis.value <= 10000)
waitevent = 0;
}
}
}
// read key/button b
sprintf( text, "a key/button for '%s'",
(_arg == X_AXIS) ? "right" : "down" );
display_dialog( button_names[_arg], "Move any axis or press", text );
waitevent = 1;
while( waitevent )
{
if( SDL_WaitEvent( &event ) == 0 )
{
fprintf( stderr, "["PLUGIN_NAME"]: SDL_WaitEvent(): %s\n", SDL_GetError() );
return;
}
switch( event.type )
{
case SDL_KEYDOWN:
if( event.key.keysym.sym == SDLK_ESCAPE )
{
return;
}
config[cont].axis[axis].key_a = key_a;
config[cont].axis[axis].key_b = event.key.keysym.sym;
waitevent = 0;
break;
case SDL_JOYBUTTONDOWN:
if( event.jbutton.which == config[cont].device )
{
config[cont].axis[axis].button_a = button_a;
config[cont].axis[axis].button_b = event.jbutton.button;
waitevent = 0;
}
break;
case SDL_JOYAXISMOTION:
if( event.jaxis.which == config[cont].device )
{
if (event.jaxis.value >= 15000)
{
if (config[cont].axis[axis].axis_a == event.jaxis.axis && config[cont].axis[axis].axis_dir_a == 1)
break;
config[cont].axis[axis].axis_b = event.jaxis.axis;
config[cont].axis[axis].axis_dir_b = 1;
waitevent = 0;
}
else if (event.jaxis.value <= -15000)
{
if (config[cont].axis[axis].axis_a == event.jaxis.axis && config[cont].axis[axis].axis_dir_a == -1)
break;
config[cont].axis[axis].axis_b = event.jaxis.axis;
config[cont].axis[axis].axis_dir_b = -1;
waitevent = 0;
}
}
break;
case SDL_JOYHATMOTION:
if( event.jhat.which == config[cont].device &&
(event.jhat.value == SDL_HAT_UP || event.jhat.value == SDL_HAT_DOWN ||
event.jhat.value == SDL_HAT_LEFT || event.jhat.value == SDL_HAT_RIGHT))
{
config[cont].axis[_arg].hat = event.jhat.hat;
config[cont].axis[_arg].hat_pos_a = hat_pos_a;
config[cont].axis[_arg].hat_pos_b = event.jhat.value;
waitevent = 0;
}
break;
}
}
}
else
{
display_dialog( button_names[_arg], "Press a key/button or", "move any axis..." );
waitevent = 1;
while( waitevent )
{
if( SDL_WaitEvent( &event ) == 0 )
{
fprintf( stderr, "["PLUGIN_NAME"]: SDL_WaitEvent(): %s\n", SDL_GetError() );
return;
}
switch( event.type )
{
case SDL_KEYDOWN:
if( event.key.keysym.sym == SDLK_ESCAPE )
{
return;
}
config[cont].button[_arg].key = event.key.keysym.sym;
waitevent = 0;
break;
case SDL_JOYBUTTONDOWN:
if( event.jbutton.which == config[cont].device )
{
config[cont].button[_arg].button = event.jbutton.button;
waitevent = 0;
}
break;
case SDL_JOYAXISMOTION:
if( event.jaxis.which == config[cont].device )
{
if( event.jaxis.value >= 15000 )
{
config[cont].button[_arg].axis = event.jaxis.axis;
config[cont].button[_arg].axis_dir = 1;
waitevent = 0;
}
else if( event.jaxis.value <= -15000 )
{
config[cont].button[_arg].axis = event.jaxis.axis;
config[cont].button[_arg].axis_dir = -1;
waitevent = 0;
}
}
break;
case SDL_JOYHATMOTION:
if( event.jhat.which == config[cont].device )
{
if( event.jhat.value == SDL_HAT_UP || event.jhat.value == SDL_HAT_DOWN ||
event.jhat.value == SDL_HAT_LEFT || event.jhat.value == SDL_HAT_RIGHT )
{
config[cont].button[_arg].hat = event.jhat.hat;
config[cont].button[_arg].hat_pos = event.jhat.value;
waitevent = 0;
}
}
break;
case SDL_MOUSEBUTTONDOWN:
if( config[cont].mouse )
{
config[cont].button[_arg].mouse = event.button.button;
waitevent = 0;
}
break;
}
}
}
}
// display button mapping in a tool-tip
#define HAT_POS_NAME( hat ) \
((hat == SDL_HAT_UP) ? "Up" : \
((hat == SDL_HAT_DOWN) ? "Down" : \
((hat == SDL_HAT_LEFT) ? "Left" : \
((hat == SDL_HAT_RIGHT) ? "Right" : \
"None"))))
static void
display_button_map( int button, int x, int y )
{
SDL_Rect dstrect, dstrect2;
memset(&dstrect,0,sizeof(SDL_Rect));
memset(&dstrect2,0,sizeof(SDL_Rect));
const char *key_a, *key_b;
char button_a[200], button_b[200], axis[200], axis_a[200], axis_b[200], hat[200], hat_pos_a[200], hat_pos_b[200], mbutton[200];
int a;
// draw the dialog
dstrect.w = 300; dstrect.h = 140;
if( screen->w - x >= dstrect.w )
dstrect.x = x;
else
dstrect.x = x - 10 - dstrect.w;
if( screen->h - y >= dstrect.h )
dstrect.y = y;
else
dstrect.y = y - 10 - dstrect.h;
SDL_FillRect( screen, &dstrect, u32black );
dstrect2.x = dstrect.x + 2; dstrect2.y = dstrect.y + 2;
dstrect2.w = dstrect.w - 4;
dstrect2.h = 25;
SDL_FillRect( screen, &dstrect2, u32gray );
write_text( screen, dstrect2.x + 100, dstrect2.y, black, gray, button_names[button] );
dstrect2.y += 26;
dstrect2.h = dstrect.h - 30;
SDL_FillRect( screen, &dstrect2, u32gray );
// write mapping
if( button == Y_AXIS || button == X_AXIS )
{
a = button - Y_AXIS;
key_a = (config[cont].axis[a].key_a == SDLK_UNKNOWN) ? "None" : SDL_GetKeyName( config[cont].axis[a].key_a );
key_b = (config[cont].axis[a].key_b == SDLK_UNKNOWN) ? "None" : SDL_GetKeyName( config[cont].axis[a].key_b );
if( config[cont].axis[a].button_a >= 0 )
sprintf( button_a, "%d", config[cont].axis[a].button_a );
else
strcpy( button_a, "None" );
if( config[cont].axis[a].button_b >= 0 )
sprintf( button_b, "%d", config[cont].axis[a].button_b );
else
strcpy( button_b, "None" );
if( config[cont].axis[a].axis_a >= 0 )
sprintf( axis_a, "%c Axis %c", axis_names[config[cont].axis[a].axis_a],
(config[cont].axis[a].axis_dir_a > 0) ? '+' : '-' );
else
strcpy( axis_a, "None" );
if( config[cont].axis[a].axis_b >= 0 )
sprintf( axis_b, "%c Axis %c", axis_names[config[cont].axis[a].axis_b],
(config[cont].axis[a].axis_dir_b > 0) ? '+' : '-' );
else
strcpy( axis_b, "None" );
if( config[cont].axis[a].hat >= 0 )
{
sprintf( hat, "#%d", config[cont].axis[a].hat );
strcpy( hat_pos_a, HAT_POS_NAME(config[cont].axis[a].hat_pos_a) );
strcpy( hat_pos_b, HAT_POS_NAME(config[cont].axis[a].hat_pos_b) );
}
else
{
strcpy( hat, "None" );
strcpy( hat_pos_a, "None" );
strcpy( hat_pos_b, "None" );
}
if( button == Y_AXIS )
{
write_text( screen, dstrect2.x + 10, dstrect2.y, black, gray, "Keys: Up = %s, Down = %s", key_a, key_b );
write_text( screen, dstrect2.x + 10, dstrect2.y + 20, black, gray, "Buttons: Up = %s, Down = %s", button_a, button_b );
write_text( screen, dstrect2.x + 10, dstrect2.y + 40, black, gray, "Hat: %s; Up = %s, Down = %s", hat, hat_pos_a, hat_pos_b );
write_text( screen, dstrect2.x + 10, dstrect2.y + 60, black, gray, "Axis: Up = %s, Down = %s", axis_a, axis_b );
}
else
{
write_text( screen, dstrect2.x + 10, dstrect2.y, black, gray, "Keys: Left = %s, Right = %s", key_a, key_b );
write_text( screen, dstrect2.x + 10, dstrect2.y + 20, black, gray, "Buttons: Left = %s, Right = %s", button_a, button_b );
write_text( screen, dstrect2.x + 10, dstrect2.y + 40, black, gray, "Hat: %s; Left = %s, Right = %s", hat, hat_pos_a, hat_pos_b );
write_text( screen, dstrect2.x + 10, dstrect2.y + 60, black, gray, "Axis: Left = %s, Right = %s", axis_a, axis_b );
}
}
else
{
key_a = (config[cont].button[button].key == SDLK_UNKNOWN) ? "None" : SDL_GetKeyName( config[cont].button[button].key );
if( config[cont].button[button].button >= 0 )
sprintf( button_a, "%d", config[cont].button[button].button );
else
strcpy( button_a, "None" );
if( config[cont].button[button].axis >= 0 )
sprintf( axis, "%c Axis %c", axis_names[config[cont].button[button].axis],
(config[cont].button[button].axis_dir > 0) ? '+' : '-' );
else
strcpy( axis, "None" );
if( config[cont].button[button].hat >= 0 )
{
sprintf( hat, "#%d", config[cont].button[button].hat );
strcpy( hat_pos_a, " " );
strcat( hat_pos_a, HAT_POS_NAME(config[cont].button[button].hat_pos) );
}
else
{
strcpy( hat, "None" );
strcpy( hat_pos_a, "" );
}
if( config[cont].button[button].mouse > 0 )
sprintf( mbutton, "#%d", config[cont].button[button].mouse );
else
strcpy( mbutton, "None" );
write_text( screen, dstrect2.x + 10, dstrect2.y, black, gray, "Key: %s", key_a );
write_text( screen, dstrect2.x + 10, dstrect2.y + 20, black, gray, "Button: %s", button_a );
write_text( screen, dstrect2.x + 10, dstrect2.y + 40, black, gray, "Hat: %s%s", hat, hat_pos_a );
write_text( screen, dstrect2.x + 10, dstrect2.y + 60, black, gray, "Axis: %s", axis );
write_text( screen, dstrect2.x + 10, dstrect2.y + 80, black, gray, "Mouse Btn: %s", mbutton );
}
SDL_Flip( screen );
}
// thread
static int
configure_thread( void *_arg )
{
int i, x, y, button;
SDL_Rect dstrect, dstrect2;
memset(&dstrect,0,sizeof(SDL_Rect));
memset(&dstrect2,0,sizeof(SDL_Rect));
SDL_Event event;
SDL_Surface *surface;
keep_looping = 1;
while( keep_looping )
{
// read mouse state
SDL_PumpEvents();
SDL_GetMouseState( &x, &y );
// draw screen
SDL_FillRect( screen, NULL, u32dark_gray );
// draw the controller tab
dstrect.x = 10;
dstrect.y = 10;
dstrect.w = (SCREEN_W - 20) / 4;
dstrect.h = 25;
for( i = 0; i < 4; i++ )
{
if( i == cont )
{
dstrect2.x = dstrect.x + 1; dstrect2.y = dstrect.y + 1;
dstrect2.w = dstrect.w - 2; dstrect2.h = dstrect.h - 1;
SDL_FillRect( screen, &dstrect, u32black );
SDL_FillRect( screen, &dstrect2, u32gray );
}
else
{
SDL_FillRect( screen, &dstrect, u32dark_gray );
}
write_text( screen, dstrect.x + 32, dstrect.y + 2, black, (i == cont) ? gray : dark_gray, "Controller %d", i + 1 );
dstrect.x += dstrect.w;
}
dstrect.x = 10;
dstrect.y = 35;
dstrect.w = SCREEN_W - 20;
dstrect.h = SCREEN_H - 80;
SDL_FillRect( screen, &dstrect, u32black );
dstrect.x++; dstrect.y++; dstrect.w -= 2; dstrect.h -= 2;
SDL_FillRect( screen, &dstrect, u32gray );
// draw the pad
dstrect.x = (SCREEN_W - pad->w) / 2;
dstrect.y = (SCREEN_H - pad->h) / 2;
dstrect.w = pad->w;
dstrect.h = pad->h;
SDL_BlitSurface( pad, NULL, screen, &dstrect );
// draw the button names
write_text( screen, 110, 245, black, gray, button_names[R_DPAD] );
write_text( screen, 110, 195, black, gray, button_names[L_DPAD] );
write_text( screen, 110, 220, black, gray, button_names[D_DPAD] );
write_text( screen, 110, 170, black, gray, button_names[U_DPAD] );
write_text( screen, 300, 65, black, gray, button_names[START_BUTTON] );
write_text( screen, 120, 290, black, gray, button_names[Z_TRIG] );
write_text( screen, 475, 230, black, gray, button_names[B_BUTTON] );
write_text( screen, 475, 325, black, gray, button_names[A_BUTTON] );
write_text( screen, 475, 130, black, gray, button_names[L_CBUTTON] );
write_text( screen, 475, 155, black, gray, button_names[U_CBUTTON] );
write_text( screen, 475, 180, black, gray, button_names[R_CBUTTON] );
write_text( screen, 475, 205, black, gray, button_names[D_CBUTTON] );
write_text( screen, 395, 105, black, gray, button_names[R_TRIG] );
write_text( screen, 155, 105, black, gray, button_names[L_TRIG] );
write_text( screen, 110, 350, black, gray, button_names[MEMPAK] );
write_text( screen, 110, 375, black, gray, button_names[RUMBLEPAK] );
write_text( screen, 220, 398, black, gray, button_names[Y_AXIS] );
write_text( screen, 280, 398, black, gray, button_names[X_AXIS] );
// draw plugged checkbutton
dstrect.x = 20; dstrect.y = 45; dstrect.w = 90; dstrect.h = 25;
SDL_FillRect( screen, &dstrect, u32black );
dstrect.x++; dstrect.y++; dstrect.w -= 2; dstrect.h -= 2;
SDL_FillRect( screen, &dstrect, (config[cont].control.Present) ? u32gray_border : u32white );
dstrect.x++; dstrect.y++; dstrect.w--; dstrect.h--;
SDL_FillRect( screen, &dstrect, (config[cont].control.Present) ? u32gray : u32dark_gray );
write_text( screen, dstrect.x + 13, dstrect.y+1, black, (config[cont].control.Present) ? gray : dark_gray, "Plugged" );
// draw mempak checkbutton
dstrect.x = 120; dstrect.y = 45; dstrect.w = 100; dstrect.h = 25;
SDL_FillRect( screen, &dstrect, u32black );
dstrect.x++; dstrect.y++; dstrect.w -= 2; dstrect.h -= 2;
SDL_FillRect( screen, &dstrect, (config[cont].control.Plugin == PLUGIN_MEMPAK) ? u32gray_border : u32white );
dstrect.x++; dstrect.y++; dstrect.w--; dstrect.h--;
SDL_FillRect( screen, &dstrect, (config[cont].control.Plugin != PLUGIN_NONE) ? u32gray : u32dark_gray );
if (config[cont].control.Plugin == PLUGIN_NONE)
write_text( screen, dstrect.x + 12, dstrect.y, black, dark_gray, "None" );
if (config[cont].control.Plugin == PLUGIN_MEMPAK)
write_text( screen, dstrect.x + 12, dstrect.y, black, gray, "Mem Pak" );
if (config[cont].control.Plugin == PLUGIN_RAW)
write_text( screen, dstrect.x + 12, dstrect.y, black, gray, "Rumble Pak" );
// draw mouse checkbutton
dstrect.x = 340; dstrect.y = 398; dstrect.w = 110; dstrect.h = 25;
SDL_FillRect( screen, &dstrect, u32black );
dstrect.x++; dstrect.y++; dstrect.w -= 2; dstrect.h -= 2;
SDL_FillRect( screen, &dstrect, (config[cont].mouse) ? u32gray_border : u32white );
dstrect.x++; dstrect.y++; dstrect.w--; dstrect.h--;
SDL_FillRect( screen, &dstrect, (config[cont].mouse) ? u32gray : u32dark_gray );
write_text( screen, dstrect.x + 8, dstrect.y+1, black, (config[cont].mouse) ? gray : dark_gray, "Enable Mouse" );
// draw device box
write_text( screen, 300, 45, black, gray, "Device:" );
dstrect.x = 360; dstrect.y = 45; dstrect.w = 260; dstrect.h = 25;
SDL_FillRect( screen, &dstrect, u32black );
dstrect.x++; dstrect.y++; dstrect.w -= 2; dstrect.h -= 2;
SDL_FillRect( screen, &dstrect, u32dark_gray );
if( config[cont].device == DEVICE_NONE )
surface = render_text( black, dark_gray, "None" );
else if( config[cont].device == DEVICE_KEYBOARD )
surface = render_text( black, dark_gray, "Keyboard" );
else
{
char chJoyName[64];
int iJoyNum = config[cont].device;
const char *pchSDLName = SDL_JoystickName(iJoyNum);
if (pchSDLName == NULL)
sprintf(chJoyName, "NULL (#%i)", iJoyNum + 1);
else
sprintf(chJoyName, "%.55s (#%i)", pchSDLName, iJoyNum + 1);
surface = render_text( black, dark_gray, chJoyName );
}
if(surface)
{
dstrect.x += dstrect.w - surface->w - 5;
dstrect.w = surface->w;
dstrect.h = surface->h;
SDL_BlitSurface( surface, NULL, screen, &dstrect );
SDL_FreeSurface( surface );
}
// draw some help
dstrect.x = 20; dstrect.y = 80; dstrect.w = 55; dstrect.h = 25;
SDL_FillRect( screen, &dstrect, u32black );
dstrect2.x = dstrect.x + 1; dstrect2.y = dstrect.y + 1;
dstrect2.w = dstrect.w - 2; dstrect2.h = dstrect.h - 2;
SDL_FillRect( screen, &dstrect2, u32gray );
write_text( screen, dstrect.x + 10, dstrect.y + 2, black, gray, "Help" );
if( x >= dstrect.x && y >= dstrect.y &&
x <= dstrect.x + dstrect.w &&
y <= dstrect.y + dstrect.h )
{
dstrect.x = x + 5; dstrect.y = y + 5;
dstrect.w = 310; dstrect.h = 190;
SDL_FillRect( screen, &dstrect, u32black );
dstrect.x++; dstrect.y++; dstrect.w -= 2; dstrect.h -= 2;
SDL_FillRect( screen, &dstrect, u32gray );
write_text( screen, dstrect.x + 10, dstrect.y + 0, black, gray, "Move the mouse cursor over a button" );
write_text( screen, dstrect.x + 10, dstrect.y + 20, black, gray, "name to see the mappings. Click it" );
write_text( screen, dstrect.x + 10, dstrect.y + 40, black, gray, "to assign a new mapping. Press DEL" );
write_text( screen, dstrect.x + 10, dstrect.y + 60, black, gray, "to clear the mappings and ESC to" );
write_text( screen, dstrect.x + 10, dstrect.y + 80, black, gray, "cancel an assignment." );
write_text( screen, dstrect.x + 10, dstrect.y + 100, black, gray, "The plugged and mempak checkbuttons" );
write_text( screen, dstrect.x + 10, dstrect.y + 120, black, gray, "can be toggled by clicking them." );
write_text( screen, dstrect.x + 10, dstrect.y + 140, black, gray, "You can cycle through the devices by" );
write_text( screen, dstrect.x + 10, dstrect.y + 160, black, gray, "clicking the device entry." );
}
// draw ok button
dstrect.x = 150; dstrect.y = 445; dstrect.w = 90; dstrect.h = 25;
SDL_FillRect( screen, &dstrect, u32black );
dstrect.x++; dstrect.y++; dstrect.w -= 2; dstrect.h -= 2;
SDL_FillRect( screen, &dstrect, (okHeld) ? u32gray_border : u32white );
dstrect.x++; dstrect.y++; dstrect.w--; dstrect.h--;
SDL_FillRect( screen, &dstrect, (okHeld) ? u32gray : u32dark_gray );
write_text( screen, dstrect.x + 35 + okHeld, dstrect.y + 1 + okHeld, black, (okHeld) ? gray : dark_gray, "Ok" );
// draw cancel button
dstrect.x = 380; dstrect.y = 445; dstrect.w = 90; dstrect.h = 25;
SDL_FillRect( screen, &dstrect, u32black );
dstrect.x++; dstrect.y++; dstrect.w -= 2; dstrect.h -= 2;
SDL_FillRect( screen, &dstrect, (cancelHeld) ? u32gray_border : u32white );
dstrect.x++; dstrect.y++; dstrect.w--; dstrect.h--;
SDL_FillRect( screen, &dstrect, (cancelHeld) ? u32gray : u32dark_gray );
write_text( screen, dstrect.x + 20 + cancelHeld, dstrect.y + 1 + cancelHeld, black, (cancelHeld) ? gray : dark_gray, "Cancel" );
// draw mapping tool-tips
// search button
button = -1;
for( i = 0; callback[i].callback; i++ )
{
if( callback[i].callback == pad_button_clicked )
{
if( x >= callback[i].x && y >= callback[i].y &&
x <= callback[i].x + callback[i].w &&
y <= callback[i].y + callback[i].h )
{
display_button_map( callback[i].arg, x + 5, y + 5 );
button = callback[i].arg;
}
}
}
// update screen
SDL_Flip( screen );
// process input queue
while( SDL_PollEvent( &event ) )
{
switch( event.type )
{
case SDL_MOUSEBUTTONDOWN:
// search callback
for( i = 0; callback[i].callback; i++ )
{
if( event.button.x >= callback[i].x && event.button.y >= callback[i].y &&
event.button.x <= callback[i].x + callback[i].w &&
event.button.y <= callback[i].y + callback[i].h )
{
callback[i].callback( callback[i].arg );
break;
}
}
break;
case SDL_MOUSEBUTTONUP:
button_released();
case SDL_KEYDOWN:
if( event.key.keysym.sym == SDLK_DELETE )
{
if( button >= 0 )
{
// clear mappings
if( button == Y_AXIS || button == X_AXIS )
{
int axis = button - Y_AXIS;
config[cont].axis[axis].axis_a = -1;
config[cont].axis[axis].axis_dir_a = 0;
config[cont].axis[axis].axis_b = -1;
config[cont].axis[axis].axis_dir_b = 0;
config[cont].axis[axis].button_a = -1;
config[cont].axis[axis].button_b = -1;
config[cont].axis[axis].key_a = SDLK_UNKNOWN;
config[cont].axis[axis].key_b = SDLK_UNKNOWN;
config[cont].axis[axis].hat = -1;
config[cont].axis[axis].hat_pos_a = -1;
config[cont].axis[axis].hat_pos_b = -1;
}
else
{
config[cont].button[button].axis = -1;
config[cont].button[button].axis_dir = 0;
config[cont].button[button].button = -1;
config[cont].button[button].key = SDLK_UNKNOWN;
config[cont].button[button].hat = -1;
config[cont].button[button].hat_pos = -1;
config[cont].button[button].mouse = -1;
}
}
}
break;
case SDL_QUIT:
keep_looping = 0;
break;
}
}
// don't use 100% CPU
SDL_Delay(100);
}
return 0;
}
static SController *g_psController = NULL;
static int
init_and_run( void *_arg )
{
SDL_RWops *rw;
int i, rval;
// init sdl
if( !SDL_WasInit( SDL_INIT_VIDEO | SDL_INIT_JOYSTICK ) )
if( SDL_InitSubSystem( SDL_INIT_VIDEO | SDL_INIT_JOYSTICK ) < 0 )
{
fprintf( stderr, "["PLUGIN_NAME"]: Couldn't init SDL video and joystick subsystem: %s\n", SDL_GetError() );
return 1;
}
SDL_JoystickEventState( SDL_ENABLE );
// load the pad image
pad = SDL_CreateRGBSurfaceFrom( (char *)pad_image.pixel_data, pad_image.width, pad_image.height, pad_image.bytes_per_pixel * 8,
pad_image.width * pad_image.bytes_per_pixel, 0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000 );
if( !pad )
{
fprintf( stderr, "["PLUGIN_NAME"]: Couldn't load the pad image from memory: %s\n", SDL_GetError() );
SDL_JoystickEventState( SDL_DISABLE );
SDL_QuitSubSystem( SDL_INIT_VIDEO | SDL_INIT_JOYSTICK );
return 2;
}
// init sdl_ttf2
if( !TTF_WasInit() )
if( TTF_Init() < 0 )
{
fprintf( stderr, "["PLUGIN_NAME"]: Couldn't init TTF library: %s\n", SDL_GetError() );
SDL_JoystickEventState( SDL_DISABLE );
SDL_QuitSubSystem( SDL_INIT_VIDEO | SDL_INIT_JOYSTICK );
return 3;
}
// open font
rw = SDL_RWFromMem( (char *)arial.data, arial.size );
font = TTF_OpenFontRW( rw, 0, FONT_SIZEPT );
if( font == NULL )
{
fprintf( stderr, "["PLUGIN_NAME"]: Couldn't load %d pt font: %s\n", FONT_SIZEPT, SDL_GetError() );
TTF_Quit();
SDL_JoystickEventState( SDL_DISABLE );
SDL_QuitSubSystem( SDL_INIT_VIDEO | SDL_INIT_JOYSTICK );
return 4;
}
TTF_SetFontStyle( font, TTF_STYLE_NORMAL );
// display dialog (set video mode)
screen = SDL_SetVideoMode( 640, 480, 0, SDL_SWSURFACE );
if( !screen )
{
fprintf( stderr, "["PLUGIN_NAME"]: Couldn't set video mode 640x480: %s\n", SDL_GetError() );
TTF_Quit();
SDL_JoystickEventState( SDL_DISABLE );
SDL_QuitSubSystem( SDL_INIT_VIDEO | SDL_INIT_JOYSTICK );
return 5;
}
SDL_WM_SetCaption( PLUGIN_NAME" "PLUGIN_VERSION, NULL );
// create colors
u32black = SDL_MapRGBA( screen->format, black.r, black.g, black.b, 0 );
u32gray = SDL_MapRGBA( screen->format, gray.r, gray.g, gray.b, 0 );
u32dark_gray = SDL_MapRGBA( screen->format, dark_gray.r, dark_gray.g, dark_gray.b, 0 );
u32gray_border = SDL_MapRGBA( screen->format, gray_border.r, gray_border.g, gray_border.b, 0 );
u32white = SDL_MapRGBA( screen->format, white.r, white.g, white.b, 0 );
/* Open all joysticks */
open_joysticks();
// load configuration
orig_cont = g_psController;
for( i = 0; i < 4; i++ )
{
if (orig_cont[i].device < num_joys)
config[i].device = orig_cont[i].device;
else
config[i].device = DEVICE_NONE;
config[i].mouse = orig_cont[i].mouse;
memcpy( config[i].axis, orig_cont[i].axis, sizeof( SAxisMap ) * 2 );
memcpy( config[i].button, orig_cont[i].button, sizeof( SButtonMap ) * 16 );
memcpy( &config[i].control, &orig_cont[i].control, sizeof( CONTROL ) );
}
// run the dialog
rval = configure_thread(_arg);
// close sdl
close_joysticks();
SDL_FreeSurface( pad );
TTF_Quit();
SDL_JoystickEventState( SDL_DISABLE );
SDL_QuitSubSystem( SDL_INIT_VIDEO | SDL_INIT_JOYSTICK );
/* all done */
return rval;
}
// config function
void
configure_sdl( SController *controller )
{
// we must initialize SDL from within the new thread in order to call SDL_PumpEvents
g_psController = controller;
// run thread
#if defined(__APPLE__)
init_and_run(NULL);
#else
thread = SDL_CreateThread( init_and_run, NULL );
if( !thread )
{
fprintf( stderr, "["PLUGIN_NAME"]: Couldn't create thread: %s\n", SDL_GetError() );
return;
}
#endif
// everything ok
}
#endif // GUI_SDL