vic20-ian posted on Feb 26 2007 at 08:54 AM said:
I played Frak! last night and I was transported straight back to illicit gaming in the computer room at school (25 years ago) when Mr todd wasn't looking - excellent!
Ahh, but did you play
rude Frak! :lol:
I Love the keyboard and mapping features, can I have a play with the keyboard source for use in Vice? I might have another tinker with the key mapping in that.
Sure, help yourself - consider the following files optionally under either the GNU GPL 2 (or any later version), or the New BSD licence. (But the emulator core remains under the original authors licence).
Files are:
The on-screen virtual keyboard (uses SDL):
virtualkeyboard.cc, virtualkeyboard.h
The keyboard mapper popup keyboard dialog (uses EG):
keyboardmapper.cc, keyboardmapper.h
The keyboard mapping UI page (uses EG):
beebem_pages.cc, beebem_pages.h
Abstraction for GP2x controls (uses SDL):
button.c, button.h
GP2x input (USB keyboard + stick + buttons etc) are controlled by button.c (and button.h). And this code also handles auto repeat.
Basically all it does is except SDL events as input and generate user events which it adds to the SDL event queue as output. So you can write something like this:
Code:
while ( SDL_PollEvent(&event) ) {
if (event.type != SDL_USEREVENT) {
Button_TranslateEvent(&event, mainWin->ScreenIsReversed());
} else {
switch ( (intptr_t) event.user.data1) {
case SDL_USEREVENT_BUTTON_QUIT:
done = 1;
break;
case SDL_USEREVENT_BUTTON_LEFT:
EG_Window_MoveSmartFocusLeft(dialog_window_p);
break;
... etc ...
case SDL_USEREVENT_BUTTON_CLICK_DOWN:
EG_Window_Trigger_Select_Down(dialog_window_p);
break;
case SDL_USEREVENT_BUTTON_CLICK_UP:
EG_Window_Trigger_Select_Up(dialog_window_p);
break;
}
}
/* Send the event to the dialog too:
*/
EG_Window_ProcessEvent(dialog_window_p, &event, 0, 0);
}
As you can see the code simply passes SDL events to button.c and that adds new 'user SDL events' that the rest of the loop then reads in and uses. With this approach any type of smart manipulation of the stick (8 to 4 directions, d-pad conversions, flipped mode etc) can be abstracted away from the code that reads the SDL user events. The EG_ call at the bottom also feeds the raw SDL event to 'EG' too.
Not completely abstracted (as you need to access the SDL user events raw), but can probably be extended.
Mouse support is handled by EG (via the raw SDL events that are passed to EG_Window_ProcessEvent), but this is not yet wired in for BeebEm running on the GP2x - if you compile for a PC then the mouse works fine, but will never work with this damned 'flipped' mode.
EG
EG is 'Economy GUI' and is the GUI API under the pages and widgets in BeebEm (and is housed in the ./gui directory of the source). It's not a fantastic GUI and only supports simple widgets, so no composites etc. Basically you have a window, and that window can have any number of child widgets associated with it. A window manages its child widgets and handles focus control for them (not a fantastic design I'll admit).
Although EG is written in C, the individual widgets are abstracted and interact with their parent window via a consistant callback based interface. For instance, the ToggleButton and RadioButton widgets both depend on the same RadioGroup widget, and EG_Window sees all EG_Widgets as the same thing anyway. There is support for adding new widgets too, and existing ones are easy to mod.
EG was written by me too, and is therefor not limited to the BeebEm license (although it is dual licensed with that). Again consider it GPL2 (or any later version) or New BSD licensed. You'll need it to run the mapper code above, but it's easy to add.
It's not fantasic though, and there are a number of crucial limitations (as you'd imagine for a none OO design), but it's quite convenient to use for popup configuration pages, and compiles to a static library that can easily be linked to - although it can also be included with the source code.
The new file selector I'm working on will become part of EG, also EG supports popup windows style 'message-boxes' (but they do not work on the GP2x yet - will do soon). Also a 'combo-box' widget with associated popup dialog (for the list of options) is in the works to.
EG is however dependent on SDL, but that dependency can probably be faked away etc. Work on EG ended over a year ago now, and I only maintain it for my UNIX BeebEm port (it's used as the other end of an abstraction layer that fakes Window$ MFC calls so the UNIX BeebEm code doesn't need to stray too far away from Windows BeebEm).
EG is sadly really, really crap, if only I was writing it with what I know now...
For all its faults, it is however quite simple to use though. Here is the mandatory "Hello, World!" type example for EG:
Code:
#include <gui/gui.h>
#include <gui/log.h>
#include <SDL.h>
#include <unistd.h>
/* Needed to abstract GP2x buttons to spoon-feed input to EG: */
#include "button.h"
/* Quit callback: */
static void Callback_NotOK(EG_Widget *me_p, void*)
{
EG_Window_Hide( EG_Widget_GetWindowPtr(me_p) );
}
/* Dialog's event loop (an example of this is in beebem_pages.cc, so you don't
* normally have to rewrite it): */
static void EventLoop(EG_Window *window_p)
{
int old_delay;
SDL_Event event;
if ( window_p == NULL ) return;
if ( EG_Window_IsHidden(window_p) ) EG_Window_Show(window_p);
/* Clear GP2x input state and reset it to 25fps (this is not fantastic,
* but...): */
Button_Reset();
old_delay = Button_GetAutoRepeatDelay();
Button_SetAutoRepeatDelay(5);
/* Event loop, loops until the dialog (window_p) is no longer displayed:
*/
do {
while ( SDL_PollEvent(&event) ) {
if (event.type != SDL_USEREVENT) {
Button_TranslateEvent(&event, 0);
} else {
/* [TODO] The event payload should be
* abstracted via button.c */
switch ( (intptr_t) event.user.data1) {
case SDL_USEREVENT_BUTTON_QUIT:
EG_Window_Hide(window_p);
break;
/* Triggers are EG's way of abstracting input
* that isn't managed via the SDL event queue.
*/
case SDL_USEREVENT_BUTTON_CLICK_DOWN:
EG_Window_Trigger_Select_Down(window_p);
break;
case SDL_USEREVENT_BUTTON_CLICK_UP:
EG_Window_Trigger_Select_Up(window_p);
break;
}
}
/* EG needs these SDL events too (but not really for
* the GP2x yet): */
EG_Window_ProcessEvent(window_p, &event, 0, 0);
}
/* Slow things down to 25 fps and handle auto repeats: */
SDL_Delay(40); Button_RaiseAutoRepeatEvents();
/* Make sure EG can house keep every once in awhile: */
EG_Window_ProcessEvent(window_p, NULL, 0, 0);
/* Fudge for now - bloody 'flipped' mode... */
SDL_UpdateRect(EG_Window_GetSurface(window_p), 0,0,0,0);
} while ( ! EG_Window_IsHidden(window_p) );
/* Be nice and leave button.c as we found it: */
Button_Reset();
Button_SetAutoRepeatDelay(old_delay);
}
/* Create the dialog, display it, process events, then free resources. */
void HelloWorld(SDL_Surface *frame_buffer_p)
{
SDL_Color c = (SDL_Color) {159, 0, 0, 0};
SDL_Rect r, r2;
EG_Window *window_p;
EG_Widget *widget_p;
if (frame_buffer_p == NULL) return;
/* Create the dialog: */
r = (SDL_Rect) { 64, 120-32, 320-128, 64 };
window_p = EG_Window_Create( "win_grue", frame_buffer_p, c, r);
/* Add widgets to the dialog (C_1_1 is a macro for easy widget
* placement): */
widget_p = EG_Label_Create( "grue_title", c, EG_LABEL_ALIGN_CENTER
, "Warning:", C_1_1(r, 1, 2) );
(void) EG_Window_AddWidget(window_p, widget_p);
r2 = C_1_1(r, 3, 6);
widget_p = EG_Box_Create( "grue_box", EG_BOX_BORDER_SUNK, c, r2 );
(void) EG_Window_AddWidget(window_p, widget_p);
r2.x+=4; r2.w-=8;
widget_p = EG_Label_Create( "grue_body", c, EG_LABEL_ALIGN_CENTER
, "V.I.S.T.A. sucks! Bad!", C_1_1(r2, 2, 2) );
(void) EG_Window_AddWidget(window_p, widget_p);
widget_p = EG_Button_Create("grue_notok", c, EG_BUTTON_ALIGN_CENTER
, "Not OK!", C_1_1(r2, 7, 2) );
(void) EG_Button_SetMyCallback_OnClick(widget_p, Callback_NotOK, NULL);
(void) EG_Window_AddWidget(window_p, widget_p);
/* Show it and wait for user to click button: */
EventLoop(window_p);
/* Free resources: */
EG_Window_DestroyAllChildWidgets(window_p);
EG_Window_Destroy(window_p);
}
Does this:
Well, OK, it's not
that short a "Hello, World" example, but I've just typed it in and it worked first time! If you feel that you could live with the above mess, then feel free to use it - I'll package something up etc if you're interested in using it.
Thanks for making me load GMenu2x, I had been too lazy to bother before but I love that too.
Nice isn't it! I especially like the way you get the little loading dialog with the apps icon! Neat!
I'll probably be installing your emulator soon too (even though I don't know the C64 etc), as I've just been reading the history section on Jeff Minter's site (
http://www.llamasoft.co.uk/lshistory1.php) and he's published all his old stuff for free download!
The edit = I suck