dxx-rebirth/common/ui/menubar.cpp

895 lines
19 KiB
C++
Raw Normal View History

2006-03-20 17:12:09 +00:00
/*
2014-06-01 17:55:23 +00:00
* Portions of this file are copyright Rebirth contributors and licensed as
* described in COPYING.txt.
* Portions of this file are copyright Parallax Software and licensed
* according to the Parallax license below.
* See COPYING.txt for license details.
2006-03-20 17:12:09 +00:00
THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO
END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS
AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED.
*/
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "physfsx.h"
2006-03-20 17:12:09 +00:00
#include "u_mem.h"
2012-07-01 02:54:33 +00:00
#include "maths.h"
2006-03-20 17:12:09 +00:00
#include "pstypes.h"
#include "gr.h"
2013-12-26 04:18:28 +00:00
#include "strutil.h"
#include "event.h"
#include "window.h"
2006-03-20 17:12:09 +00:00
#include "ui.h"
#include "mouse.h"
2006-03-20 17:12:09 +00:00
#include "key.h"
#include "func.h"
#include "dxxerror.h"
2006-03-20 17:12:09 +00:00
2015-01-17 18:31:39 +00:00
#include "compiler-exchange.h"
#include "compiler-range_for.h"
#include "partial_range.h"
2006-03-20 17:12:09 +00:00
2015-12-13 18:00:49 +00:00
namespace dcx {
2015-12-05 22:57:24 +00:00
2006-03-20 17:12:09 +00:00
#define MAXMENUS 30
#define MAXITEMS 32
namespace {
struct ITEM {
2006-03-20 17:12:09 +00:00
short x, y, w, h;
2015-01-23 03:55:04 +00:00
RAIIdmem<char[]> Text;
RAIIdmem<char[]> InactiveText;
2006-03-20 17:12:09 +00:00
short Hotkey;
int (*user_function)(void);
};
2006-03-20 17:12:09 +00:00
2014-09-07 18:06:59 +00:00
struct MENU : embed_window_pointer_t {
2006-03-20 17:12:09 +00:00
short x, y, w, h;
short ShowBar;
short CurrentItem;
2015-01-17 18:31:39 +00:00
uint16_t NumItems;
2006-03-20 17:12:09 +00:00
short Displayed;
short Active;
2015-01-23 03:55:04 +00:00
array<ITEM, MAXITEMS> Item;
};
2006-03-20 17:12:09 +00:00
}
2015-01-23 03:55:04 +00:00
static array<MENU, MAXMENUS> Menu;
2006-03-20 17:12:09 +00:00
2015-01-17 18:31:39 +00:00
static unsigned num_menus;
2006-03-20 17:12:09 +00:00
static int state;
#define CMENU (Menu[0].CurrentItem+1)
2014-10-04 21:47:13 +00:00
static window_event_result menubar_handler(window *wind,const d_event &event, MENU *menu);
static window_event_result menu_handler(window *wind,const d_event &event, MENU *menu);
2006-03-20 17:12:09 +00:00
//------------------------- Show a menu item -------------------
2013-10-27 22:00:14 +00:00
static void item_show( MENU * menu, int n )
2006-03-20 17:12:09 +00:00
{
ITEM * item = &menu->Item[n];
gr_set_current_canvas(NULL);
// If this is a seperator, then draw it.
if ( item->Text[0] == '-' )
{
2016-02-12 04:02:28 +00:00
const uint8_t color = CBLACK;
gr_urect( item->x, item->y+item->h/2, item->x+item->w-1, item->y+item->h/2, color);
2006-03-20 17:12:09 +00:00
return;
}
if ( menu->CurrentItem==n && menu->ShowBar )
{
if ( menu != &Menu[0] )
{
2016-02-12 04:02:28 +00:00
const uint8_t color = CBLACK;
gr_urect( item->x+1, item->y+1, item->x+menu->w-2, item->y+item->h-2, color);
2006-03-20 17:12:09 +00:00
}
gr_set_fontcolor( CWHITE, CBLACK );
}else {
if ( menu != &Menu[0] )
{
2016-02-12 04:02:28 +00:00
const uint8_t color = CGREY;
gr_urect( item->x+1, item->y+1, item->x+menu->w-2, item->y+item->h-2, color);
2006-03-20 17:12:09 +00:00
}
gr_set_fontcolor( CBLACK, CGREY );
}
if ( menu != &Menu[0] )
{
if ( menu->Active)
gr_ustring(item->x+1, item->y+1, item->Text.get());
2006-03-20 17:12:09 +00:00
else
gr_ustring(item->x+1, item->y+1, item->InactiveText.get());
2006-03-20 17:12:09 +00:00
} else {
if ( menu->Active)
gr_ustring(item->x, item->y, item->Text.get());
2006-03-20 17:12:09 +00:00
else
gr_ustring(item->x, item->y, item->InactiveText.get());
2006-03-20 17:12:09 +00:00
}
}
2013-10-27 22:00:14 +00:00
static void menu_draw(MENU *menu)
{
int i;
gr_set_current_canvas(NULL);
// Draw the menu background
2016-02-12 04:02:28 +00:00
gr_urect( menu->x, menu->y, menu->x + menu->w - 1, menu->y + menu->h - 1, CGREY);
if ( menu != &Menu[0] )
{
2016-02-12 04:02:28 +00:00
gr_ubox(menu->x, menu->y, menu->x + menu->w - 1, menu->y + menu->h - 1, CBLACK);
}
// Draw the items
for (i=0; i< menu->NumItems; i++ )
item_show( menu, i );
}
2006-03-20 17:12:09 +00:00
//---------------------------- Show a menu ---------------------
2013-10-27 22:00:14 +00:00
static void menu_show( MENU * menu )
2006-03-20 17:12:09 +00:00
{
if (!menu->wind)
{
menu->wind = window_create(&grd_curscreen->sc_canvas, menu->x, menu->y, menu->w, menu->h,
2013-12-01 05:21:47 +00:00
((menu == &Menu[0]) ? menubar_handler : menu_handler), menu);
if (!menu->wind)
return;
if (menu == &Menu[0])
window_set_modal(Menu[0].wind, 0); // allow windows behind the menubar to accept events (e.g. the keypad dialogs)
}
window_set_visible(menu->wind, 1);
2006-03-20 17:12:09 +00:00
// Mark as displayed.
menu->Displayed = 1;
}
//-------------------------- Hide a menu -----------------------
2013-10-27 22:00:14 +00:00
static void menu_hide( MENU * menu )
2006-03-20 17:12:09 +00:00
{
// Can't hide if it's not already drawn
if (!menu->Displayed) return;
if ((menu != &Menu[0]) && menu->wind)
window_set_visible(menu->wind, 0); // don't draw or receive events
2006-03-20 17:12:09 +00:00
menu->Active = 0;
if (Menu[0].wind && menu == &Menu[0])
window_set_modal(Menu[0].wind, 0);
2006-03-20 17:12:09 +00:00
// Mark as hidden.
menu->Displayed = 0;
}
//------------------------- Move the menu bar ------------------
2013-10-27 22:00:14 +00:00
static void menu_move_bar_to( MENU * menu, int number )
2006-03-20 17:12:09 +00:00
{
int old_item;
old_item = menu->CurrentItem;
menu->CurrentItem = number;
if (menu->Displayed && (number != old_item))
{
item_show( menu, old_item );
item_show( menu, number );
}
}
//------------------------ Match keypress to item ------------------
2013-10-27 22:00:14 +00:00
static int menu_match_keypress( MENU * menu, int keypress )
2006-03-20 17:12:09 +00:00
{
int i;
char c;
if ((keypress & KEY_CTRLED) || (keypress & KEY_SHIFTED))
return -1;
keypress &= 0xFF;
c = key_ascii();
2006-03-20 17:12:09 +00:00
for (i=0; i< menu->NumItems; i++ )
{
auto letter = strrchr(menu->Item[i].Text.get(), CC_UNDERLINE);
2006-03-20 17:12:09 +00:00
if (letter)
{
letter++;
if (c==tolower(*letter))
return i;
}
}
return -1;
}
2013-10-27 22:00:14 +00:00
static int menu_is_mouse_on( ITEM * item )
2006-03-20 17:12:09 +00:00
{
int x, y, z;
mouse_get_pos(&x, &y, &z);
if ((x >= item->x) &&
(x < item->x + item->w ) &&
(y >= item->y) &&
(y <= item->y + item->h ) )
2006-03-20 17:12:09 +00:00
return 1;
else
return 0;
}
2013-10-27 22:00:14 +00:00
static int menu_check_mouse_item( MENU * menu )
2006-03-20 17:12:09 +00:00
{
int i;
for (i=0; i<menu->NumItems; i++ )
{
if (menu_is_mouse_on( &menu->Item[i] ))
{
if (menu->Item[i].Text[0] == '-')
return -1;
else
return i;
}
}
return -1;
}
2013-10-27 22:00:14 +00:00
static void menu_hide_all()
2006-03-20 17:12:09 +00:00
{
2015-01-17 18:31:39 +00:00
range_for (auto &i, partial_range(Menu, 1u, num_menus))
menu_hide(&i);
2006-03-20 17:12:09 +00:00
Menu[0].ShowBar = 0;
Menu[0].Active = 0;
if (Menu[0].wind)
window_set_modal(Menu[0].wind, 0);
2006-03-20 17:12:09 +00:00
menu_show( &Menu[0] );
}
static int state2_alt_down;
2014-10-04 21:47:13 +00:00
static window_event_result do_state_0(const d_event &event)
2006-03-20 17:12:09 +00:00
{
int keypress = 0;
2014-10-04 21:47:13 +00:00
if (event.type == EVENT_KEY_COMMAND)
keypress = event_key_get(event);
2006-03-20 17:12:09 +00:00
Menu[0].Active = 0;
if (Menu[0].wind)
window_set_modal(Menu[0].wind, 0);
2006-03-20 17:12:09 +00:00
Menu[0].ShowBar = 0;
if ( keypress & KEY_ALTED ) {
2015-11-26 02:56:54 +00:00
const auto i = menu_match_keypress( &Menu[0], keypress );
2006-03-20 17:12:09 +00:00
if (i > -1 )
{
Menu[0].CurrentItem = i;
Menu[0].Active = 0;
if (Menu[0].wind)
window_set_modal(Menu[0].wind, 0);
2006-03-20 17:12:09 +00:00
state = 3;
Menu[ CMENU ].ShowBar = 1;
Menu[ CMENU ].Active = 1;
Menu[0].ShowBar = 1;
menu_show( &Menu[ CMENU ] );
menu_show( &Menu[0] );
2014-08-06 02:10:49 +00:00
return window_event_result::handled;
2006-03-20 17:12:09 +00:00
}
}
2016-02-12 04:02:28 +00:00
range_for (auto &i, partial_const_range(Menu, num_menus))
range_for (auto &j, partial_const_range(i.Item, i.NumItems))
2006-03-20 17:12:09 +00:00
{
2015-01-17 18:31:39 +00:00
if ( j.Hotkey == keypress )
2006-03-20 17:12:09 +00:00
{
2015-01-17 18:31:39 +00:00
if (j.user_function)
j.user_function();
2014-08-06 02:10:49 +00:00
return window_event_result::handled;
2006-03-20 17:12:09 +00:00
}
}
if (keypress & KEY_ALTED)
2006-03-20 17:12:09 +00:00
//if ( (keypress & 0xFF) == KEY_LALT )
{
// Make sure the menubar receives events exclusively
2006-03-20 17:12:09 +00:00
state = 1;
Menu[0].Active = 1;
// Put the menubar in front - hope this doesn't mess anything up by leaving it there
// If it does, will need to remember the previous front window and restore it.
// (Personally, I just use either the mouse or 'hotkeys' for menus)
2015-01-17 18:31:41 +00:00
window_select(*Menu[0].wind);
window_set_modal(Menu[0].wind, 1);
2006-03-20 17:12:09 +00:00
menu_show( &Menu[0] );
2014-08-06 02:10:49 +00:00
return window_event_result::handled;
2006-03-20 17:12:09 +00:00
}
2015-11-26 02:56:54 +00:00
const auto i = menu_check_mouse_item( &Menu[0] );
2006-03-20 17:12:09 +00:00
if ( B1_JUST_PRESSED && (i > -1))
2006-03-20 17:12:09 +00:00
{
Menu[0].CurrentItem = i;
state = 3;
Menu[ CMENU ].ShowBar = 1;
Menu[0].ShowBar = 1;
Menu[ CMENU ].Active = 1;
Menu[0].Active = 0;
window_set_modal(Menu[0].wind, 0);
2006-03-20 17:12:09 +00:00
menu_show( &Menu[ CMENU ] );
menu_show( &Menu[0] );
2014-08-06 02:10:49 +00:00
return window_event_result::handled;
2006-03-20 17:12:09 +00:00
}
2014-08-06 02:10:49 +00:00
return window_event_result::ignored;
2006-03-20 17:12:09 +00:00
}
2014-10-04 21:47:13 +00:00
static window_event_result do_state_1(const d_event &event)
2006-03-20 17:12:09 +00:00
{
int i;
int keypress = 0;
2014-08-06 02:10:49 +00:00
window_event_result rval = window_event_result::ignored;
2014-10-04 21:47:13 +00:00
if (event.type == EVENT_KEY_COMMAND)
keypress = event_key_get(event);
2014-10-04 21:47:13 +00:00
if ((event.type == EVENT_KEY_RELEASE) && !(event_key_get(event) & KEY_ALTED))
2006-03-20 17:12:09 +00:00
{
state = 2;
state2_alt_down = 0;
Menu[0].ShowBar = 1;
Menu[0].Active = 1;
menu_show( &Menu[0] );
2014-08-06 02:10:49 +00:00
rval = window_event_result::handled;
2006-03-20 17:12:09 +00:00
}
i = menu_match_keypress( &Menu[0], keypress );
if (i > -1 )
{
Menu[0].CurrentItem = i;
Menu[0].Active = 0;
window_set_modal(Menu[0].wind, 0);
2006-03-20 17:12:09 +00:00
state = 3;
Menu[ CMENU ].ShowBar = 1;
Menu[ CMENU ].Active = 1;
Menu[0].ShowBar = 1;
menu_show( &Menu[ CMENU ] );
menu_show( &Menu[0] );
2014-08-06 02:10:49 +00:00
rval = window_event_result::handled;
2006-03-20 17:12:09 +00:00
}
i = menu_check_mouse_item( &Menu[0] );
if ( (i == -1) && B1_JUST_RELEASED )
{
state = 0;
menu_hide_all();
2014-08-06 02:10:49 +00:00
return window_event_result::handled;
2006-03-20 17:12:09 +00:00
}
if ( B1_JUST_PRESSED && (i > -1))
2006-03-20 17:12:09 +00:00
{
Menu[0].CurrentItem = i;
state = 3;
Menu[ CMENU ].ShowBar = 1;
Menu[ CMENU ].Active = 1;
Menu[0].ShowBar = 1;
Menu[0].Active = 0;
window_set_modal(Menu[0].wind, 0);
2006-03-20 17:12:09 +00:00
menu_show( &Menu[ CMENU ] );
menu_show( &Menu[0] );
2014-08-06 02:10:49 +00:00
return window_event_result::handled;
2006-03-20 17:12:09 +00:00
}
return rval;
2006-03-20 17:12:09 +00:00
}
2014-10-04 21:47:13 +00:00
static window_event_result do_state_2(const d_event &event)
2006-03-20 17:12:09 +00:00
{
int i;
int keypress = 0;
2014-08-06 02:10:49 +00:00
window_event_result rval = window_event_result::ignored;
2014-10-04 21:47:13 +00:00
if (event.type == EVENT_KEY_COMMAND)
keypress = event_key_get(event);
if (keypress & KEY_ALTED)
{
2006-03-20 17:12:09 +00:00
state2_alt_down = 1;
2014-08-06 02:10:49 +00:00
rval = window_event_result::handled;
}
2006-03-20 17:12:09 +00:00
2014-10-04 21:47:13 +00:00
if ((event.type == EVENT_KEY_RELEASE) && !(event_key_get(event) & KEY_ALTED) && state2_alt_down)
2006-03-20 17:12:09 +00:00
{
state = 0;
menu_hide_all();
2014-08-06 02:10:49 +00:00
rval = window_event_result::handled;
2006-03-20 17:12:09 +00:00
}
switch( keypress )
{
case KEY_ESC:
state = 0;
menu_hide_all();
2014-08-06 02:10:49 +00:00
return window_event_result::handled;
2006-03-20 17:12:09 +00:00
case KEY_LEFT:
case KEY_PAD4:
i = Menu[0].CurrentItem-1;
if (i < 0 ) i = Menu[0].NumItems-1;
menu_move_bar_to( &Menu[0], i );
2014-08-06 02:10:49 +00:00
return window_event_result::handled;
2006-03-20 17:12:09 +00:00
case KEY_RIGHT:
case KEY_PAD6:
i = Menu[0].CurrentItem+1;
if (i >= Menu[0].NumItems ) i = 0;
menu_move_bar_to( &Menu[0], i );
2014-08-06 02:10:49 +00:00
return window_event_result::handled;
2006-03-20 17:12:09 +00:00
case KEY_ENTER:
case KEY_PADENTER:
case KEY_DOWN:
case KEY_PAD2:
state = 3;
Menu[ CMENU ].ShowBar = 1;
Menu[ CMENU ].Active = 1;
Menu[0].Active = 0;
window_set_modal(Menu[0].wind, 0);
2006-03-20 17:12:09 +00:00
menu_show( &Menu[ 0 ] );
menu_show( &Menu[ CMENU ] );
2014-08-06 02:10:49 +00:00
return window_event_result::handled;
2006-03-20 17:12:09 +00:00
default:
i = menu_match_keypress( &Menu[0], keypress );
if (i > -1 )
{
Menu[0].CurrentItem = i;
Menu[0].Active = 0;
window_set_modal(Menu[0].wind, 0);
2006-03-20 17:12:09 +00:00
state = 3;
Menu[ CMENU ].ShowBar = 1;
Menu[ CMENU ].Active = 1;
Menu[0].ShowBar = 1;
menu_show( &Menu[ CMENU ] );
menu_show( &Menu[0] );
2014-08-06 02:10:49 +00:00
return window_event_result::handled;
2006-03-20 17:12:09 +00:00
}
i = menu_check_mouse_item( &Menu[0] );
if ( (i == -1) && B1_JUST_RELEASED )
{
state = 0;
menu_hide_all();
2014-08-06 02:10:49 +00:00
return window_event_result::handled;
2006-03-20 17:12:09 +00:00
}
if (i > -1)
2006-03-20 17:12:09 +00:00
{
Menu[0].CurrentItem = i;
Menu[0].Active = 0;
window_set_modal(Menu[0].wind, 0);
2006-03-20 17:12:09 +00:00
state = 3;
Menu[ CMENU ].ShowBar = 1;
Menu[ CMENU ].Active = 1;
Menu[0].ShowBar = 1;
menu_show( &Menu[ CMENU ] );
menu_show( &Menu[0] );
2014-08-06 02:10:49 +00:00
return window_event_result::handled;
2006-03-20 17:12:09 +00:00
}
}
return rval;
2006-03-20 17:12:09 +00:00
}
2015-01-18 01:58:33 +00:00
static window_event_result menu_handler(window *, const d_event &event, MENU *menu)
2006-03-20 17:12:09 +00:00
{
int i;
int keypress = 0;
if (state != 3)
2014-08-06 02:10:49 +00:00
return window_event_result::ignored;
2014-10-04 21:47:13 +00:00
if (event.type == EVENT_KEY_COMMAND)
keypress = event_key_get(event);
2014-10-04 21:47:13 +00:00
else if (event.type == EVENT_WINDOW_CLOSE) // quitting
{
state = 0;
menu_hide_all();
menu->wind = NULL;
2014-08-06 02:10:49 +00:00
return window_event_result::ignored;
}
2014-08-06 02:10:49 +00:00
window_event_result rval = window_event_result::ignored;
2006-03-20 17:12:09 +00:00
switch( keypress )
{
case 0:
break;
case KEY_ESC:
state = 0;
menu_hide_all();
2014-08-06 02:10:49 +00:00
rval = window_event_result::handled;
break;
case KEY_DOWN:
case KEY_PAD2:
i = Menu[ CMENU ].CurrentItem;
do {
i++;
if ( i >= Menu[ CMENU ].NumItems )
i = 0;
} while( Menu[CMENU].Item[i].Text[0] == '-');
menu_move_bar_to( &Menu[ CMENU ], i );
2014-08-06 02:10:49 +00:00
rval = window_event_result::handled;
break;
case KEY_UP:
case KEY_PAD8:
i = Menu[ CMENU ].CurrentItem;
do
{
i--;
if ( i < 0 )
i = Menu[ CMENU ].NumItems-1;
} while( Menu[CMENU].Item[i].Text[0] == '-');
2006-03-20 17:12:09 +00:00
menu_move_bar_to( &Menu[ CMENU ], i );
2014-08-06 02:10:49 +00:00
rval = window_event_result::handled;
break;
case KEY_RIGHT:
case KEY_PAD6:
menu_hide( &Menu[ CMENU ] );
i = Menu[0].CurrentItem+1;
if (i >= Menu[0].NumItems ) i = 0;
menu_move_bar_to( &Menu[0], i );
Menu[CMENU].ShowBar = 1;
Menu[CMENU].Active = 1;
menu_show( &Menu[CMENU] );
2014-08-06 02:10:49 +00:00
rval = window_event_result::handled;
break;
case KEY_LEFT:
case KEY_PAD4:
menu_hide( &Menu[ CMENU ] );
i = Menu[0].CurrentItem-1;
if (i < 0 ) i = Menu[0].NumItems-1;
menu_move_bar_to( &Menu[0], i );
Menu[ CMENU ].ShowBar = 1;
Menu[CMENU].Active = 1;
menu_show( &Menu[ CMENU ] );
2014-08-06 02:10:49 +00:00
rval = window_event_result::handled;
break;
case KEY_ENTER:
case KEY_PADENTER:
2006-03-20 17:12:09 +00:00
state = 0;
menu_hide_all();
2006-03-20 17:12:09 +00:00
if (Menu[CMENU].Item[ Menu[CMENU].CurrentItem ].user_function)
Menu[CMENU].Item[ Menu[CMENU].CurrentItem ].user_function();
2014-08-06 02:10:49 +00:00
rval = window_event_result::handled;
2006-03-20 17:12:09 +00:00
break;
default:
i = menu_match_keypress( &Menu[ CMENU ], keypress );
if (i > -1 )
{
menu_move_bar_to( &Menu[ CMENU ], i );
state = 0;
menu_hide_all();
if (Menu[CMENU].Item[ Menu[CMENU].CurrentItem ].user_function)
Menu[CMENU].Item[ Menu[CMENU].CurrentItem ].user_function();
2014-08-06 02:10:49 +00:00
rval = window_event_result::handled;
break;
}
}
2014-10-04 21:47:13 +00:00
if (event.type == EVENT_MOUSE_MOVED || B1_JUST_RELEASED)
{
2006-03-20 17:12:09 +00:00
i = menu_check_mouse_item( &Menu[CMENU] );
if (i > -1 )
{
if ( B1_JUST_RELEASED )
2006-03-20 17:12:09 +00:00
{
menu_move_bar_to( &Menu[ CMENU ], i );
state = 0;
menu_hide_all();
if (Menu[CMENU].Item[ Menu[CMENU].CurrentItem ].user_function)
Menu[CMENU].Item[ Menu[CMENU].CurrentItem ].user_function();
2014-08-06 02:10:49 +00:00
rval = window_event_result::handled;
2006-03-20 17:12:09 +00:00
}
else
{
menu_move_bar_to( &Menu[ CMENU ], i );
2014-08-06 02:10:49 +00:00
rval = window_event_result::handled;
}
2006-03-20 17:12:09 +00:00
} else {
i = menu_check_mouse_item( &Menu[0] );
if (i > -1)
2006-03-20 17:12:09 +00:00
{
if ( Menu[0].CurrentItem != i) {
menu_hide( &Menu[ CMENU ] );
menu_move_bar_to( &Menu[0], i );
Menu[ CMENU ].ShowBar = 1;
Menu[CMENU].Active = 1;
menu_show( &Menu[ CMENU ] );
}
2014-08-06 02:10:49 +00:00
rval = window_event_result::handled;
2006-03-20 17:12:09 +00:00
}
if ( B1_JUST_RELEASED )
{
state = 0;
menu_hide_all();
2014-08-06 02:10:49 +00:00
rval = window_event_result::handled;
2006-03-20 17:12:09 +00:00
}
}
}
2014-10-04 21:47:13 +00:00
if (event.type == EVENT_WINDOW_DRAW)
{
menu_draw(&Menu[CMENU]);
2014-08-06 02:10:49 +00:00
return window_event_result::handled;
}
return rval;
}
2015-01-18 01:58:33 +00:00
static window_event_result menubar_handler(window *, const d_event &event, MENU *)
2006-03-20 17:12:09 +00:00
{
2014-10-04 21:47:13 +00:00
if (event.type == EVENT_WINDOW_DRAW)
{
menu_draw(&Menu[0]);
2014-08-06 02:10:49 +00:00
return window_event_result::handled;
}
2014-10-04 21:47:13 +00:00
else if (event.type == EVENT_WINDOW_CLOSE)
{
//menu_hide_all();
//menu_hide( &Menu[0] );
2015-01-17 18:31:39 +00:00
range_for (auto &i, partial_range(Menu, 1u, num_menus))
{
2015-01-17 18:31:39 +00:00
if (i.wind)
{
2015-01-17 18:31:39 +00:00
window_close(exchange(i.wind, nullptr));
}
}
Menu[0].wind = NULL;
}
switch (state)
2006-03-20 17:12:09 +00:00
{
case 0:
2014-08-06 02:10:49 +00:00
return do_state_0(event);
2006-03-20 17:12:09 +00:00
case 1:
2014-08-06 02:10:49 +00:00
return do_state_1(event);
2006-03-20 17:12:09 +00:00
case 2:
2014-08-06 02:10:49 +00:00
return do_state_2(event);
2006-03-20 17:12:09 +00:00
case 3:
break;
default:
state = 0;
menu_hide_all();
2006-03-20 17:12:09 +00:00
}
2014-08-06 02:10:49 +00:00
return window_event_result::ignored;
2006-03-20 17:12:09 +00:00
}
static void CommaParse(uint_fast32_t n, char * dest, const PHYSFSX_gets_line_t<200>::line_t &source)
2006-03-20 17:12:09 +00:00
{
int i = 0, j=0, cn = 0;
// Go to the n'th comma
while (cn < n )
if (source[i++] == ',' )
cn++;
// Read all the whitespace
while ( source[i]==' ' || source[i]=='\t' || source[i]==13 || source[i]==10 )
i++;
// Read up until the next comma
while ( source[i] != ',' )
{
dest[j] = source[i++];
j++;
}
// Null-terminate
dest[j++] = 0;
}
//translate '&' characters to the underline character
2013-10-27 22:00:14 +00:00
static void ul_xlate(char *s)
2006-03-20 17:12:09 +00:00
{
while ((s=strchr(s,'&'))!=NULL)
*s = CC_UNDERLINE;
}
void menubar_init( const char * file )
2006-03-20 17:12:09 +00:00
{
2015-11-26 02:56:54 +00:00
int np;
2006-03-20 17:12:09 +00:00
char buf1[200];
char buf2[200];
num_menus = state = 0;
// This method should be faster than explicitly setting all the variables (I think)
2015-01-23 03:55:04 +00:00
Menu = {};
2015-01-23 03:55:04 +00:00
range_for (auto &i, Menu)
range_for (auto &j, i.Item)
j.Hotkey = -1;
auto infile = PHYSFSX_openReadBuffered(file);
2006-03-20 17:12:09 +00:00
if (!infile) return;
2014-09-07 19:48:10 +00:00
PHYSFSX_gets_line_t<200> buffer;
while ( PHYSFSX_fgets( buffer, infile) != NULL )
2006-03-20 17:12:09 +00:00
{
if ( buffer[0] == ';' ) continue;
CommaParse( 0, buf1, buffer );
char *p;
const auto mi = strtoul(buf1, &p, 10);
if (mi >= MAXMENUS)
{
con_printf(CON_URGENT, "%s:%u: too many menus defined: max=%u, requested=%lu in \"%s\"", __FILE__, __LINE__, MAXMENUS, mi, file);
break;
}
2006-03-20 17:12:09 +00:00
CommaParse( 1, buf1, buffer );
const auto ii = strtoul(buf1, &p, 10);
if (ii >= MAXITEMS)
{
con_printf(CON_URGENT, "%s:%u: too many items defined: max=%u, requested=%lu in \"%s\"", __FILE__, __LINE__, MAXITEMS, ii, file);
break;
}
auto &menu = Menu[mi];
auto &item = menu.Item[ii];
2006-03-20 17:12:09 +00:00
CommaParse( 2, buf1, buffer );
ul_xlate(buf1);
item.Text.reset(d_strdup(buf1[0] == '-' ? buf1 : (snprintf(buf2, sizeof(buf2), " %s ", buf1), buf2)));
2006-03-20 17:12:09 +00:00
item.InactiveText.reset(d_strdup(item.Text.get()));
2006-03-20 17:12:09 +00:00
2015-11-26 02:56:54 +00:00
for (int i = 0, j = 0;; i++ )
2006-03-20 17:12:09 +00:00
{
np = item.Text[i];
2006-03-20 17:12:09 +00:00
if (np != CC_UNDERLINE)
item.InactiveText[j++] = np;
2013-07-14 22:34:37 +00:00
if (!np)
break;
2006-03-20 17:12:09 +00:00
}
CommaParse( 3, buf1, buffer );
if (buf1[0]=='{' && buf1[1] =='}')
item.Hotkey = -1;
2006-03-20 17:12:09 +00:00
else {
2015-11-26 02:56:54 +00:00
const auto i = DecodeKeyText(buf1);
2006-03-20 17:12:09 +00:00
if (i<1) {
UserError("Unknown key, %s, in %s\n", buf1, file );
2006-03-20 17:12:09 +00:00
} else {
item.Hotkey = i;
2006-03-20 17:12:09 +00:00
}
}
CommaParse( 4, buf1, buffer );
2013-12-03 23:21:36 +00:00
if (buf1[0])
2006-03-20 17:12:09 +00:00
{
item.user_function = func_get(buf1, &np);
2006-03-20 17:12:09 +00:00
if (!item.user_function)
2006-03-20 17:12:09 +00:00
{
con_printf(CON_URGENT, "%s:%u: unknown function \"%s\" in \"%s\"", __FILE__, __LINE__, buf1, file);
break;
2006-03-20 17:12:09 +00:00
}
}
item.x = menu.x;
item.y = menu.y;
2006-03-20 17:12:09 +00:00
2015-09-29 02:41:22 +00:00
int w, h;
if (item.Text[0] == '-')
2006-03-20 17:12:09 +00:00
{
w = 1; h = 3;
} else {
gr_get_string_size(item.Text.get(), &w, &h, nullptr);
2006-03-20 17:12:09 +00:00
w += 2;
h += 2;
}
if (mi == 0)
{
menu.h = h;
2006-03-20 17:12:09 +00:00
item.x = menu.x + menu.w;
2006-03-20 17:12:09 +00:00
item.y = menu.y;
2006-03-20 17:12:09 +00:00
Menu[ii+1].x = menu.x + menu.w;
Menu[ii+1].y = menu.h - 2;
2006-03-20 17:12:09 +00:00
item.w = w;
item.h = h;
2006-03-20 17:12:09 +00:00
menu.w += w;
2006-03-20 17:12:09 +00:00
}else {
if (w > menu.w)
2006-03-20 17:12:09 +00:00
{
menu.w = w;
range_for (auto &i, partial_range(menu.Item, menu.NumItems))
i.w = w;
2006-03-20 17:12:09 +00:00
}
item.w = menu.w;
item.x = menu.x;
item.y = menu.y+menu.h;
item.h = h;
menu.h += h;
2006-03-20 17:12:09 +00:00
}
if (ii >= menu.NumItems)
2006-03-20 17:12:09 +00:00
{
menu.NumItems = ii + 1;
2006-03-20 17:12:09 +00:00
}
if (mi >= num_menus)
num_menus = mi + 1;
2006-03-20 17:12:09 +00:00
}
Menu[0].w = 700;
}
void menubar_hide()
{
state = 0;
menu_hide_all();
menu_hide( &Menu[0] );
}
void menubar_show()
{
menu_show( &Menu[0] );
}
void menubar_close()
{
if (!Menu[0].wind)
return;
window_close(exchange(Menu[0].wind, nullptr));
2006-03-20 17:12:09 +00:00
}
2015-12-05 22:57:24 +00:00
}