New netplay UI.
git-svn-id: svn://svn.code.sf.net/p/sc2/code/trunk@2500 8092fc87-c524-0410-9efc-e669fe64eaf9
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
Changes towards version 0.6:
|
||||
- Netplay configuration dialog - Michael
|
||||
- Better error message for 'Kernel failed to load' (#917) - Michael
|
||||
- Pushbutton for connecting to netplay, in anticipation of a full
|
||||
configuration dialog later - Michael
|
||||
|
||||
@@ -1,42 +1,23 @@
|
||||
To use Netplay you need to pass some parameters to uqm. In future versions
|
||||
you should be able to set everything you need to set from within the
|
||||
game itself.
|
||||
|
||||
--netport1 specifies the port the bottom player will connect to or accept
|
||||
incoming connections on. If this parameter is not specified, 21837 will
|
||||
be used.
|
||||
Your firewall needs to be set up to allow TCP connections from/to
|
||||
the used port.
|
||||
--nethost1 specifies the name or ip number of the host to connect to for
|
||||
the bottom player. If this parameter is not specified, UQM will
|
||||
instead accept incoming connections.
|
||||
--netport2
|
||||
As --netport1, but for the top player
|
||||
--nethost2
|
||||
As --nethost1, but for the top player
|
||||
--netdelay
|
||||
The desired input delay (in frames). A keypress or keyrelease
|
||||
will only take effect after this many frames. The result is that while
|
||||
higher values make your ship to seem to respond more sluggishly,
|
||||
they give the keypress information more time to reach the remote party.
|
||||
If the game stutters, this is because it is waiting for this
|
||||
keypress information to arrive, which is an indication that the
|
||||
input delay is too low.
|
||||
As SuperMelee runs at 24 frames per second, each frame delayed will
|
||||
delay the input by about 42ms.
|
||||
The delay used is the maximum of the desired value for both parties.
|
||||
The default is 0. Values lower than 4 will be hardly noticable
|
||||
in terms of responsiveness.
|
||||
Future versions may automatically decide on the best value to use.
|
||||
|
||||
In SuperMelee, there is now an extra button, "NET". When you push it,
|
||||
UQM will start paying attention to incoming connections or try to
|
||||
establish an outgoing connection, depending on the specified
|
||||
parameters. Pressing SPACE at the connection screen will cancel
|
||||
connection attempts. Once a connection has been established, the
|
||||
input will be listed as "NETWORK CONTROL". To abort an already
|
||||
established connection, change the control scheme away from NETWORK
|
||||
CONTROL. The game won't start until both parties have confirmed the
|
||||
current setup. If one player moves away from the 'Battle!' button,
|
||||
both parties need to reconfirm.
|
||||
In SuperMelee, there is now an extra button for each side, marked
|
||||
"NET". When you push it, you will get the net configuration dialog.
|
||||
To have someone else connect to you, choose the first option.
|
||||
Otherwise, edit the host name and choose "connect". Pressing SPACE on
|
||||
the resulting connection screen will cancel connection attempts. Once
|
||||
a connection has been established, the input will be listed as
|
||||
"NETWORK CONTROL". To abort an already established connection, change
|
||||
the control scheme away from NETWORK CONTROL. The game won't start
|
||||
until both parties have confirmed the current setup. If one player
|
||||
moves away from the 'Battle!' button, both parties need to reconfirm.
|
||||
|
||||
In addition to setting the hostname, you can also configure the port
|
||||
and the input delay in frames. A keypress or keyrelease will only take
|
||||
effect after this many frames. The result is that while higher values
|
||||
make your ship to seem to respond more sluggishly, they give the
|
||||
keypress information more time to reach the remote party. If the game
|
||||
stutters, this is because it is waiting for this keypress information
|
||||
to arrive, which is an indication that the input delay is too low. As
|
||||
SuperMelee runs at 24 frames per second, each frame delayed will delay
|
||||
the input by about 42ms. The delay used is the maximum of the desired
|
||||
value for both parties. The default is 0. Values lower than 4 will be
|
||||
hardly noticable in terms of responsiveness. Future versions may
|
||||
automatically decide on the best value to use.
|
||||
|
||||
+552
-4
@@ -20,32 +20,575 @@
|
||||
|
||||
#include "cnctdlg.h"
|
||||
#include "controls.h"
|
||||
#include "colors.h"
|
||||
#include "setup.h"
|
||||
#include "libs/graphics/widgets.h"
|
||||
#include "netplay/netoptions.h"
|
||||
|
||||
#define MCD_WIDTH 260
|
||||
#define MCD_HEIGHT 100
|
||||
|
||||
#define MENU_FRAME_RATE (ONE_SECOND / 20)
|
||||
|
||||
typedef struct connect_dialog_state
|
||||
{
|
||||
BOOLEAN (*InputFunc) (struct connect_dialog_state *pInputState);
|
||||
COUNT MenuRepeatDelay;
|
||||
|
||||
DWORD NextTime;
|
||||
BOOLEAN Initialized;
|
||||
int which_side;
|
||||
|
||||
int option;
|
||||
int confirmed;
|
||||
} CONNECT_DIALOG_STATE;
|
||||
|
||||
static void DrawConnectDialog (void);
|
||||
|
||||
typedef CONNECT_DIALOG_STATE *PCONNECT_DIALOG_STATE;
|
||||
|
||||
static WIDGET_MENU_SCREEN menu;
|
||||
static WIDGET_BUTTON buttons[3];
|
||||
static WIDGET_SLIDER slider;
|
||||
static WIDGET_TEXTENTRY texts[2];
|
||||
|
||||
static WIDGET *menu_widgets[] = {
|
||||
(WIDGET *)&buttons[1],
|
||||
(WIDGET *)&texts[0],
|
||||
(WIDGET *)&buttons[0],
|
||||
(WIDGET *)&slider,
|
||||
(WIDGET *)&texts[1],
|
||||
(WIDGET *)&buttons[2] };
|
||||
|
||||
static BOOLEAN done;
|
||||
|
||||
/* This kind of sucks, but the Button callbacks need access to the
|
||||
* CONNECT_DIALOG_STATE, so we need a pointer to it */
|
||||
|
||||
static PCONNECT_DIALOG_STATE current_state;
|
||||
|
||||
static int do_connect (WIDGET *self, int event);
|
||||
static int do_listen (WIDGET *self, int event);
|
||||
static int do_cancel (WIDGET *self, int event);
|
||||
|
||||
static void
|
||||
MCD_DrawMenuScreen (WIDGET *_self, int x, int y)
|
||||
{
|
||||
int widget_index, widget_y;
|
||||
|
||||
WIDGET_MENU_SCREEN *self = (WIDGET_MENU_SCREEN *)_self;
|
||||
|
||||
widget_y = y + 8;
|
||||
for (widget_index = 0; widget_index < self->num_children; widget_index++)
|
||||
{
|
||||
WIDGET *c = self->child[widget_index];
|
||||
(*c->draw)(c, x, widget_y);
|
||||
widget_y += (*c->height)(c) + 8;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
MCD_DrawButton (WIDGET *_self, int x, int y)
|
||||
{
|
||||
WIDGET_BUTTON *self = (WIDGET_BUTTON *)_self;
|
||||
COLOR oldtext;
|
||||
COLOR inactive, selected;
|
||||
FONT oldfont = SetContextFont (StarConFont);
|
||||
FRAME oldFontEffect = SetContextFontEffect (NULL);
|
||||
TEXT t;
|
||||
|
||||
selected = MENU_HIGHLIGHT_COLOR;
|
||||
inactive = MENU_TEXT_COLOR;
|
||||
|
||||
t.baseline.x = 160;
|
||||
t.baseline.y = y;
|
||||
t.align = ALIGN_CENTER;
|
||||
t.CharCount = ~0;
|
||||
t.pStr = self->name;
|
||||
if (widget_focus == _self)
|
||||
{
|
||||
oldtext = SetContextForeGroundColor (selected);
|
||||
}
|
||||
else
|
||||
{
|
||||
oldtext = SetContextForeGroundColor (inactive);
|
||||
}
|
||||
font_DrawText (&t);
|
||||
SetContextFontEffect (oldFontEffect);
|
||||
SetContextFont (oldfont);
|
||||
SetContextForeGroundColor (oldtext);
|
||||
(void) x;
|
||||
}
|
||||
|
||||
static void
|
||||
MCD_DrawSlider (WIDGET *_self, int x, int y)
|
||||
{
|
||||
WIDGET_SLIDER *self = (WIDGET_SLIDER *)_self;
|
||||
COLOR oldtext;
|
||||
COLOR default_color, selected;
|
||||
FONT oldfont = SetContextFont (StarConFont);
|
||||
FRAME oldFontEffect = SetContextFontEffect (NULL);
|
||||
TEXT t;
|
||||
RECT r;
|
||||
int tick = (MCD_WIDTH) / 8;
|
||||
|
||||
default_color = MENU_TEXT_COLOR;
|
||||
selected = MENU_HIGHLIGHT_COLOR;
|
||||
|
||||
t.baseline.x = x;
|
||||
t.baseline.y = y;
|
||||
t.align = ALIGN_LEFT;
|
||||
t.CharCount = ~0;
|
||||
t.pStr = self->category;
|
||||
if (widget_focus == _self)
|
||||
{
|
||||
oldtext = SetContextForeGroundColor (selected);
|
||||
}
|
||||
else
|
||||
{
|
||||
oldtext = SetContextForeGroundColor (default_color);
|
||||
}
|
||||
font_DrawText (&t);
|
||||
|
||||
r.corner.x = t.baseline.x + 3 * tick;
|
||||
r.corner.y = t.baseline.y - 4;
|
||||
r.extent.height = 2;
|
||||
r.extent.width = 3 * tick;
|
||||
DrawFilledRectangle (&r);
|
||||
|
||||
r.extent.width = 3;
|
||||
r.extent.height = 8;
|
||||
r.corner.y = t.baseline.y - 7;
|
||||
r.corner.x = t.baseline.x + 3 * tick + (3 * tick * (self->value - self->min) /
|
||||
(self->max - self->min)) - 1;
|
||||
DrawFilledRectangle (&r);
|
||||
|
||||
(*self->draw_value)(self, t.baseline.x + 7 * tick, t.baseline.y);
|
||||
|
||||
SetContextFontEffect (oldFontEffect);
|
||||
SetContextFont (oldfont);
|
||||
SetContextForeGroundColor (oldtext);
|
||||
}
|
||||
|
||||
void
|
||||
MCD_DrawTextEntry (WIDGET *_self, int x, int y)
|
||||
{
|
||||
WIDGET_TEXTENTRY *self = (WIDGET_TEXTENTRY *)_self;
|
||||
COLOR oldtext;
|
||||
COLOR inactive, default_color, selected;
|
||||
FONT oldfont = SetContextFont (StarConFont);
|
||||
FRAME oldFontEffect = SetContextFontEffect (NULL);
|
||||
TEXT t;
|
||||
|
||||
default_color = MENU_TEXT_COLOR;
|
||||
selected = MENU_HIGHLIGHT_COLOR;
|
||||
inactive = MENU_TEXT_COLOR;
|
||||
|
||||
BatchGraphics ();
|
||||
|
||||
t.baseline.x = x;
|
||||
t.baseline.y = y;
|
||||
t.align = ALIGN_LEFT;
|
||||
t.CharCount = ~0;
|
||||
t.pStr = self->category;
|
||||
if (widget_focus == _self)
|
||||
{
|
||||
oldtext = SetContextForeGroundColor (selected);
|
||||
}
|
||||
else
|
||||
{
|
||||
oldtext = SetContextForeGroundColor (default_color);
|
||||
}
|
||||
font_DrawText (&t);
|
||||
|
||||
/* Force string termination */
|
||||
self->value[WIDGET_TEXTENTRY_WIDTH-1] = 0;
|
||||
|
||||
t.baseline.y = y;
|
||||
t.CharCount = utf8StringCount (self->value);
|
||||
t.pStr = self->value;
|
||||
|
||||
if (!(self->state & WTE_EDITING))
|
||||
{ // normal or selected state
|
||||
t.baseline.x = 160;
|
||||
t.align = ALIGN_CENTER;
|
||||
|
||||
if (widget_focus == _self)
|
||||
{
|
||||
oldtext = SetContextForeGroundColor (selected);
|
||||
}
|
||||
else
|
||||
{
|
||||
oldtext = SetContextForeGroundColor (inactive);
|
||||
}
|
||||
font_DrawText (&t);
|
||||
}
|
||||
else
|
||||
{ // editing state
|
||||
COUNT i;
|
||||
RECT text_r;
|
||||
BYTE char_deltas[WIDGET_TEXTENTRY_WIDTH];
|
||||
PBYTE pchar_deltas;
|
||||
RECT r;
|
||||
SIZE leading;
|
||||
|
||||
t.baseline.x = x + 90;
|
||||
t.align = ALIGN_LEFT;
|
||||
|
||||
// calc background box dimensions
|
||||
// XXX: this may need some tuning, especially if a
|
||||
// different font is used. The font 'leading' values
|
||||
// are not what they should be.
|
||||
#define BOX_VERT_OFFSET 2
|
||||
GetContextFontLeading (&leading);
|
||||
r.corner.x = t.baseline.x - 1;
|
||||
r.corner.y = t.baseline.y - leading + BOX_VERT_OFFSET;
|
||||
r.extent.width = MCD_WIDTH - r.corner.x - 10;
|
||||
r.extent.height = leading + 2;
|
||||
|
||||
TextRect (&t, &text_r, char_deltas);
|
||||
#if 0
|
||||
// XXX: this should potentially be used in ChangeCallback
|
||||
if ((text_r.extent.width + 2) >= r.extent.width)
|
||||
{ // the text does not fit the input box size and so
|
||||
// will not fit when displayed later
|
||||
UnbatchGraphics ();
|
||||
// disallow the change
|
||||
return (FALSE);
|
||||
}
|
||||
#endif
|
||||
|
||||
oldtext = SetContextForeGroundColor (selected);
|
||||
DrawFilledRectangle (&r);
|
||||
|
||||
// calculate the cursor position and draw it
|
||||
pchar_deltas = char_deltas;
|
||||
for (i = self->cursor_pos; i > 0; --i)
|
||||
r.corner.x += (SIZE)*pchar_deltas++;
|
||||
if (self->cursor_pos < t.CharCount) /* cursor mid-line */
|
||||
--r.corner.x;
|
||||
if (self->state & WTE_BLOCKCUR)
|
||||
{ // Use block cursor for keyboardless systems
|
||||
if (self->cursor_pos == t.CharCount)
|
||||
{ // cursor at end-line -- use insertion point
|
||||
r.extent.width = 1;
|
||||
}
|
||||
else if (self->cursor_pos + 1 == t.CharCount)
|
||||
{ // extra pixel for last char margin
|
||||
r.extent.width = (SIZE)*pchar_deltas + 2;
|
||||
}
|
||||
else
|
||||
{ // normal mid-line char
|
||||
r.extent.width = (SIZE)*pchar_deltas + 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{ // Insertion point cursor
|
||||
r.extent.width = 1;
|
||||
}
|
||||
// position cursor within input field rect
|
||||
++r.corner.x;
|
||||
++r.corner.y;
|
||||
r.extent.height -= 2;
|
||||
SetContextForeGroundColor (MENU_TEXT_COLOR);
|
||||
DrawFilledRectangle (&r);
|
||||
|
||||
SetContextForeGroundColor (inactive);
|
||||
font_DrawText (&t);
|
||||
}
|
||||
|
||||
UnbatchGraphics ();
|
||||
SetContextFontEffect (oldFontEffect);
|
||||
SetContextFont (oldfont);
|
||||
SetContextForeGroundColor (oldtext);
|
||||
}
|
||||
|
||||
/* Text entry stuff, mostly C&Ped from setupmenu.c. Could use some
|
||||
* refactoring, as redraw_menu () is the only real change. */
|
||||
|
||||
static BOOLEAN
|
||||
OnTextEntryChange (PTEXTENTRY_STATE pTES)
|
||||
{
|
||||
WIDGET_TEXTENTRY *widget = (WIDGET_TEXTENTRY *) pTES->CbParam;
|
||||
|
||||
widget->cursor_pos = pTES->CursorPos;
|
||||
if (pTES->JoystickMode)
|
||||
widget->state |= WTE_BLOCKCUR;
|
||||
else
|
||||
widget->state &= ~WTE_BLOCKCUR;
|
||||
|
||||
// XXX TODO: Here, we can examine the text entered so far
|
||||
// to make sure it fits on the screen, for example,
|
||||
// and return FALSE to disallow the last change
|
||||
|
||||
return TRUE; // allow change
|
||||
}
|
||||
|
||||
static BOOLEAN
|
||||
OnTextEntryFrame (PTEXTENTRY_STATE pTES)
|
||||
{
|
||||
WIDGET_TEXTENTRY *widget = (WIDGET_TEXTENTRY *) pTES->CbParam;
|
||||
|
||||
DrawConnectDialog ();
|
||||
|
||||
SleepThreadUntil (pTES->NextTime);
|
||||
pTES->NextTime = GetTimeCounter () + MENU_FRAME_RATE;
|
||||
|
||||
return TRUE; // continue
|
||||
}
|
||||
|
||||
static int
|
||||
OnTextEntryEvent (WIDGET_TEXTENTRY *widget)
|
||||
{ // Going to edit the text
|
||||
TEXTENTRY_STATE tes;
|
||||
UNICODE revert_buf[256];
|
||||
|
||||
// position cursor at the end of text
|
||||
widget->cursor_pos = utf8StringCount (widget->value);
|
||||
widget->state = WTE_EDITING;
|
||||
DrawConnectDialog ();
|
||||
|
||||
// make a backup copy for revert on cancel
|
||||
utf8StringCopy (revert_buf, sizeof (revert_buf), widget->value);
|
||||
|
||||
// text entry setup
|
||||
tes.Initialized = FALSE;
|
||||
tes.MenuRepeatDelay = 0;
|
||||
tes.NextTime = GetTimeCounter () + MENU_FRAME_RATE;
|
||||
tes.BaseStr = widget->value;
|
||||
tes.MaxSize = widget->maxlen;
|
||||
tes.CursorPos = widget->cursor_pos;
|
||||
tes.CbParam = widget;
|
||||
tes.ChangeCallback = OnTextEntryChange;
|
||||
tes.FrameCallback = OnTextEntryFrame;
|
||||
|
||||
// SetMenuSounds (0, MENU_SOUND_SELECT);
|
||||
if (!DoTextEntry (&tes))
|
||||
{ // editing failed (canceled) -- revert the changes
|
||||
utf8StringCopy (widget->value, widget->maxlen, revert_buf);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (widget->onChange)
|
||||
{
|
||||
(*(widget->onChange))(widget);
|
||||
}
|
||||
}
|
||||
|
||||
widget->state = WTE_NORMAL;
|
||||
DrawConnectDialog ();
|
||||
|
||||
return TRUE; // event handled
|
||||
}
|
||||
|
||||
/* Button response routines */
|
||||
|
||||
static int
|
||||
do_connect (WIDGET *self, int event)
|
||||
{
|
||||
if (event == WIDGET_EVENT_SELECT)
|
||||
{
|
||||
/* These assignments are safe exactly because texts[] is file-scope) */
|
||||
netplayOptions.peer[current_state->which_side].host = texts[0].value;
|
||||
netplayOptions.peer[current_state->which_side].port = texts[1].value;
|
||||
netplayOptions.peer[current_state->which_side].isServer = FALSE;
|
||||
current_state->confirmed = TRUE;
|
||||
netplayOptions.inputDelay = slider.value;
|
||||
|
||||
done = TRUE;
|
||||
}
|
||||
(void)self;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static int
|
||||
do_listen (WIDGET *self, int event)
|
||||
{
|
||||
if (event == WIDGET_EVENT_SELECT)
|
||||
{
|
||||
/* These assignments are safe exactly because texts[] is file-scope) */
|
||||
netplayOptions.peer[current_state->which_side].port = texts[1].value;
|
||||
netplayOptions.peer[current_state->which_side].isServer = TRUE;
|
||||
netplayOptions.inputDelay = slider.value;
|
||||
current_state->confirmed = TRUE;
|
||||
done = TRUE;
|
||||
}
|
||||
(void)self;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static int
|
||||
do_cancel (WIDGET *self, int event)
|
||||
{
|
||||
if (event == WIDGET_EVENT_SELECT)
|
||||
{
|
||||
current_state->confirmed = FALSE;
|
||||
done = TRUE;
|
||||
}
|
||||
(void)self;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
CreateWidgets (void)
|
||||
{
|
||||
int i;
|
||||
|
||||
done = false;
|
||||
|
||||
for (i = 0; i < 3; i++)
|
||||
{
|
||||
buttons[i].tag = WIDGET_TYPE_BUTTON;
|
||||
buttons[i].parent = NULL;
|
||||
buttons[i].receiveFocus = Widget_ReceiveFocusSimple;
|
||||
buttons[i].draw = MCD_DrawButton;
|
||||
buttons[i].height = Widget_HeightOneLine;
|
||||
buttons[i].width = Widget_WidthFullScreen;
|
||||
}
|
||||
buttons[0].name = "Connect to remote host";
|
||||
buttons[1].name = "Wait for incoming connection";
|
||||
buttons[2].name = "Cancel";
|
||||
|
||||
buttons[0].handleEvent = do_connect;
|
||||
buttons[1].handleEvent = do_listen;
|
||||
buttons[2].handleEvent = do_cancel;
|
||||
|
||||
menu.tag = WIDGET_TYPE_MENU_SCREEN;
|
||||
menu.parent = NULL;
|
||||
menu.receiveFocus = Widget_ReceiveFocusMenuScreen;
|
||||
menu.draw = MCD_DrawMenuScreen;
|
||||
menu.height = Widget_HeightFullScreen;
|
||||
menu.width = Widget_WidthFullScreen;
|
||||
menu.num_children = 6;
|
||||
menu.child = menu_widgets;
|
||||
menu.handleEvent = Widget_HandleEventMenuScreen;
|
||||
|
||||
slider.tag = WIDGET_TYPE_SLIDER;
|
||||
slider.parent = NULL;
|
||||
slider.handleEvent = Widget_HandleEventSlider;
|
||||
slider.receiveFocus = Widget_ReceiveFocusSimple;
|
||||
slider.draw = MCD_DrawSlider;
|
||||
slider.height = Widget_HeightOneLine;
|
||||
slider.width = Widget_WidthFullScreen;
|
||||
slider.draw_value = Widget_Slider_DrawValue;
|
||||
slider.min = 0;
|
||||
slider.max = 9;
|
||||
slider.step = 1;
|
||||
slider.value = netplayOptions.inputDelay;
|
||||
slider.category = "Net Delay";
|
||||
|
||||
for (i = 0; i < 2; i++)
|
||||
{
|
||||
texts[i].tag = WIDGET_TYPE_TEXTENTRY;
|
||||
texts[i].parent = NULL;
|
||||
texts[i].handleEvent = Widget_HandleEventTextEntry;
|
||||
texts[i].receiveFocus = Widget_ReceiveFocusSimple;
|
||||
texts[i].draw = MCD_DrawTextEntry;
|
||||
texts[i].height = Widget_HeightOneLine;
|
||||
texts[i].width = Widget_WidthFullScreen;
|
||||
texts[i].handleEventSelect = OnTextEntryEvent;
|
||||
texts[i].maxlen = WIDGET_TEXTENTRY_WIDTH-1;
|
||||
texts[i].state = WTE_NORMAL;
|
||||
texts[i].cursor_pos = 0;
|
||||
}
|
||||
|
||||
texts[0].category = "Host";
|
||||
texts[1].category = "Port";
|
||||
|
||||
/* We sometimes assign to these internals; cannot strncpy over self! */
|
||||
if (texts[0].value != netplayOptions.peer[current_state->which_side].host)
|
||||
{
|
||||
strncpy (texts[0].value, netplayOptions.peer[current_state->which_side].host, texts[0].maxlen);
|
||||
}
|
||||
if (texts[1].value != netplayOptions.peer[current_state->which_side].port)
|
||||
{
|
||||
strncpy (texts[1].value, netplayOptions.peer[current_state->which_side].port, texts[1].maxlen);
|
||||
}
|
||||
texts[0].value[texts[0].maxlen]=0;
|
||||
texts[1].value[texts[1].maxlen]=0;
|
||||
|
||||
menu.receiveFocus ((WIDGET *)&menu, WIDGET_EVENT_DOWN);
|
||||
}
|
||||
|
||||
static void
|
||||
DrawConnectDialog (void)
|
||||
{
|
||||
RECT r;
|
||||
|
||||
r.extent.width = MCD_WIDTH;
|
||||
r.extent.height = MCD_HEIGHT;
|
||||
r.corner.x = (SCREEN_WIDTH - r.extent.width) >> 1;
|
||||
r.corner.y = (SCREEN_HEIGHT - r.extent.height) >> 1;
|
||||
|
||||
LockMutex (GraphicsLock);
|
||||
|
||||
DrawShadowedBox (&r, SHADOWBOX_BACKGROUND_COLOR,
|
||||
SHADOWBOX_DARK_COLOR, SHADOWBOX_MEDIUM_COLOR);
|
||||
|
||||
menu.draw ((WIDGET *)&menu, r.corner.x + 10, r.corner.y + 10);
|
||||
|
||||
UnlockMutex (GraphicsLock);
|
||||
}
|
||||
|
||||
static BOOLEAN
|
||||
DoMeleeConnectDialog (PCONNECT_DIALOG_STATE state)
|
||||
{
|
||||
BOOLEAN changed;
|
||||
|
||||
if (!state->Initialized)
|
||||
{
|
||||
state->Initialized = TRUE;
|
||||
SetDefaultMenuRepeatDelay ();
|
||||
state->NextTime = GetTimeCounter ();
|
||||
/* Prepare widgets, draw stuff, etc. */
|
||||
CreateWidgets ();
|
||||
DrawConnectDialog ();
|
||||
}
|
||||
|
||||
/* But this is skeletal, so just end immediately */
|
||||
return FALSE;
|
||||
changed = TRUE;
|
||||
|
||||
if (PulsedInputState.menu[KEY_MENU_UP])
|
||||
{
|
||||
Widget_Event (WIDGET_EVENT_UP);
|
||||
}
|
||||
else if (PulsedInputState.menu[KEY_MENU_DOWN])
|
||||
{
|
||||
Widget_Event (WIDGET_EVENT_DOWN);
|
||||
}
|
||||
else if (PulsedInputState.menu[KEY_MENU_LEFT])
|
||||
{
|
||||
Widget_Event (WIDGET_EVENT_LEFT);
|
||||
}
|
||||
else if (PulsedInputState.menu[KEY_MENU_RIGHT])
|
||||
{
|
||||
Widget_Event (WIDGET_EVENT_RIGHT);
|
||||
}
|
||||
else if (PulsedInputState.menu[KEY_MENU_SELECT])
|
||||
{
|
||||
Widget_Event (WIDGET_EVENT_SELECT);
|
||||
}
|
||||
else if (PulsedInputState.menu[KEY_MENU_CANCEL])
|
||||
{
|
||||
Widget_Event (WIDGET_EVENT_CANCEL);
|
||||
}
|
||||
else if (PulsedInputState.menu[KEY_MENU_DELETE])
|
||||
{
|
||||
Widget_Event (WIDGET_EVENT_DELETE);
|
||||
}
|
||||
else
|
||||
{
|
||||
changed = FALSE;
|
||||
}
|
||||
|
||||
if (changed)
|
||||
{
|
||||
DrawConnectDialog ();
|
||||
}
|
||||
|
||||
SleepThreadUntil (state->NextTime + MENU_FRAME_RATE);
|
||||
state->NextTime = GetTimeCounter ();
|
||||
return !((GLOBAL (CurrentActivity) & CHECK_ABORT) ||
|
||||
done);
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
@@ -56,10 +599,15 @@ MeleeConnectDialog (int side)
|
||||
state.Initialized = FALSE;
|
||||
state.which_side = side;
|
||||
state.InputFunc = DoMeleeConnectDialog;
|
||||
state.confirmed = TRUE;
|
||||
|
||||
current_state = &state;
|
||||
|
||||
DoInput ((PVOID)&state, TRUE);
|
||||
|
||||
return TRUE;
|
||||
current_state = NULL;
|
||||
|
||||
return state.confirmed;
|
||||
}
|
||||
|
||||
#endif /* NETPLAY */
|
||||
|
||||
@@ -43,7 +43,7 @@ typedef enum {
|
||||
NUM_WIDGET_TYPES
|
||||
} WIDGET_TYPE;
|
||||
|
||||
#define WIDGET_TEXTENTRY_WIDTH 30
|
||||
#define WIDGET_TEXTENTRY_WIDTH 50
|
||||
#define WIDGET_CONTROLENTRY_WIDTH 16
|
||||
|
||||
typedef struct _widget {
|
||||
@@ -213,4 +213,7 @@ void Widget_DrawControlEntry (WIDGET *_self, int x, int y);
|
||||
|
||||
void Widget_Slider_DrawValue (WIDGET_SLIDER *self, int x, int y);
|
||||
|
||||
/* Other implementations will need these values */
|
||||
extern WIDGET *widget_focus;
|
||||
|
||||
#endif /* _WIDGETS_H */
|
||||
|
||||
Reference in New Issue
Block a user