Merge pull request #230 from dxx-rebirth/allow_window_subclasses_2

Allow window subclasses
This commit is contained in:
kreatordxx 2016-10-03 10:36:26 +08:00 committed by GitHub
commit b87fcad332
19 changed files with 156 additions and 100 deletions

View file

@ -22,32 +22,21 @@
namespace dcx {
struct window
{
grs_canvas w_canv; // the window's canvas to draw to
window_event_result (*w_callback)(window *wind,const d_event &event, void *data); // the event handler
int w_visible; // whether it's visible
int w_modal; // modal = accept all user input exclusively
void *data; // whatever the user wants (eg menu data for 'newmenu' menus)
struct window *prev; // the previous window in the doubly linked list
struct window *next; // the next window in the doubly linked list
};
static window *FrontWindow = NULL;
static window *FirstWindow = NULL;
window *window_create(grs_canvas *src, int x, int y, int w, int h, window_subfunction<void> event_callback, void *data, const void *createdata)
window::window(grs_canvas *src, int x, int y, int w, int h, window_subfunction<void> event_callback, void *data, const void *createdata)
{
window *prev = window_get_front();
window *prev_front = window_get_front();
d_create_event event;
window *wind = new window;
window *wind = this;
Assert(src != NULL);
Assert(event_callback != NULL);
gr_init_sub_canvas(wind->w_canv, *src, x, y, w, h);
wind->w_callback = event_callback;
wind->w_visible = 1; // default to visible
wind->w_modal = 1; // default to modal
wind->data = data;
wind->w_data = data;
if (FirstWindow == NULL)
FirstWindow = wind;
@ -56,14 +45,24 @@ window *window_create(grs_canvas *src, int x, int y, int w, int h, window_subfun
FrontWindow->next = wind;
wind->next = NULL;
FrontWindow = wind;
if (prev)
WINDOW_SEND_EVENT(prev, EVENT_WINDOW_DEACTIVATED);
if (prev_front)
WINDOW_SEND_EVENT(prev_front, EVENT_WINDOW_DEACTIVATED);
event.createdata = createdata;
WINDOW_SEND_EVENT(wind, EVENT_WINDOW_CREATED);
WINDOW_SEND_EVENT(wind, EVENT_WINDOW_ACTIVATED);
}
return wind;
window::~window()
{
if (this == FrontWindow)
FrontWindow = this->prev;
if (this == FirstWindow)
FirstWindow = this->next;
if (this->next)
this->next->prev = this->prev;
if (this->prev)
this->prev->next = this->next;
}
int window_close(window *wind)
@ -85,21 +84,12 @@ int window_close(window *wind)
return 0;
}
if (wind == FrontWindow)
FrontWindow = wind->prev;
if (wind == FirstWindow)
FirstWindow = wind->next;
if (wind->next)
wind->next->prev = wind->prev;
if (wind->prev)
wind->prev->next = wind->next;
if ((prev = window_get_front()))
WINDOW_SEND_EVENT(prev, EVENT_WINDOW_ACTIVATED);
event.type = EVENT_WINDOW_CLOSED;
w_callback(wind, event, NULL); // callback needs to recognise this is a NULL pointer!
delete wind;
w_callback(nullptr, event, nullptr); // callback needs to recognise nullptr is being passed!
return 1;
}
@ -127,16 +117,6 @@ window *window_get_first(void)
return FirstWindow;
}
window *window_get_next(window &wind)
{
return wind.next;
}
window *window_get_prev(window &wind)
{
return wind.prev;
}
// Make wind the front window
void window_select(window &wind)
{
@ -156,7 +136,7 @@ void window_select(window &wind)
wind.next = nullptr;
FrontWindow = &wind;
if (window_is_visible(wind))
if (wind.is_visible())
{
if (prev)
WINDOW_SEND_EVENT(prev, EVENT_WINDOW_DEACTIVATED);
@ -181,16 +161,6 @@ window *window_set_visible(window &w, int visible)
return wind;
}
int window_is_visible(window &wind)
{
return wind.w_visible;
}
grs_canvas &window_get_canvas(window &wind)
{
return wind.w_canv;
}
#if !DXX_USE_OGL
void window_update_canvases()
{
@ -206,22 +176,4 @@ void window_update_canvases()
}
#endif
window_event_result window_send_event(window &wind, const d_event &event)
{
auto r = wind.w_callback(&wind, event, wind.data);
if (r == window_event_result::close)
window_close(&wind);
return r;
}
void window_set_modal(window &wind, int modal)
{
wind.w_modal = modal;
}
int window_is_modal(window &wind)
{
return wind.w_modal;
}
}

View file

@ -24,14 +24,15 @@ enum class window_event_result : uint8_t;
template <typename T>
using window_subfunction = window_event_result (*)(window *menu,const d_event &event, T *userdata);
template <typename T>
using window_subclass_subfunction = window_event_result (*)(T *menu,const d_event &event, void*);
class unused_window_userdata_t;
/* No declaration for embed_window_pointer_t or ignore_window_pointer_t
* since every user needs the full definition.
*/
window *window_create(grs_canvas *src, int x, int y, int w, int h, window_subfunction<void> event_callback, void *userdata, const void *createdata);
int window_close(window *wind);
int window_exists(window *wind);
window *window_get_front();
@ -40,13 +41,11 @@ window *window_get_next(window &wind);
window *window_get_prev(window &wind);
void window_select(window &wind);
window *window_set_visible(window &wind, int visible);
int window_is_visible(window &wind);
grs_canvas &window_get_canvas(window &wind);
#if !DXX_USE_OGL
void window_update_canvases();
#endif
window_event_result window_send_event(window &wind,const d_event &event);
void window_set_modal(window &wind, int modal);
int window_is_modal(window &wind);
#define WINDOW_SEND_EVENT(w, e) (event.type = e, (WINDOW_SEND_EVENT)(*w, event, __FILE__, __LINE__, #e))

View file

@ -50,10 +50,101 @@ static inline void set_embedded_window_pointer(embed_window_pointer_t *wp, windo
static inline void set_embedded_window_pointer(ignore_window_pointer_t *, window *) {}
struct window
{
private:
grs_canvas w_canv; // the window's canvas to draw to
window_subfunction<void> w_callback; // the event handler
int w_visible; // whether it's visible
int w_modal; // modal = accept all user input exclusively
void *w_data; // whatever the user wants (eg menu data for 'newmenu' menus)
struct window *prev; // the previous window in the doubly linked list
struct window *next; // the next window in the doubly linked list
public:
// For creating the window, there are two ways - using the (older) window_create function
// or using the constructor, passing an event handler that takes a subclass of window.
explicit window(grs_canvas *src, int x, int y, int w, int h, window_subfunction<void> event_callback, void *data, const void *createdata);
template <typename T>
window(grs_canvas *src, int x, int y, int w, int h, window_subclass_subfunction<T> event_callback) :
window(src, x, y, w, h, reinterpret_cast<window_subclass_subfunction<window>>(event_callback), nullptr, nullptr) {}
~window();
// Declaring as friends to keep function syntax, for historical reasons (for now at least)
// Intended to transition to the class method form
friend window *window_create(grs_canvas *src, int x, int y, int w, int h, window_subfunction<void> event_callback, void *userdata, const void *createdata);
friend int window_close(window *wind);
friend int window_exists(window *wind);
friend window *window_get_front();
friend window *window_get_first();
friend void window_select(window &wind);
friend window *window_set_visible(window &wind, int visible);
#if !DXX_USE_OGL
friend void window_update_canvases();
#endif
friend grs_canvas &window_get_canvas(window &wind)
{
return wind.w_canv;
}
friend window *window_set_visible(window *wind, int visible)
{
return window_set_visible(*wind, visible);
}
int is_visible()
{
return w_visible;
}
friend int window_is_visible(window *wind)
{
return wind->is_visible();
}
void set_modal(int modal)
{
w_modal = modal;
}
friend void window_set_modal(window *wind, int modal)
{
wind->set_modal(modal);
}
friend int window_is_modal(window &wind)
{
return wind.w_modal;
}
friend window_event_result window_send_event(window &wind, const d_event &event)
{
auto r = wind.w_callback(&wind, event, wind.w_data);
if (r == window_event_result::close)
window_close(&wind);
return r;
}
friend window *window_get_next(window &wind)
{
return wind.next;
}
friend window *window_get_prev(window &wind)
{
return wind.prev;
}
};
template <typename T1, typename T2 = const void>
static inline window *window_create(grs_canvas *src, int x, int y, int w, int h, window_subfunction<T1> event_callback, T1 *data, T2 *createdata = nullptr)
{
auto win = window_create(src, x, y, w, h, reinterpret_cast<window_subfunction<void>>(event_callback), static_cast<void *>(data), static_cast<const void *>(createdata));
auto win = new window(src, x, y, w, h, reinterpret_cast<window_subfunction<void>>(event_callback), static_cast<void *>(data), static_cast<const void *>(createdata));
set_embedded_window_pointer(data, win);
return win;
}
@ -61,20 +152,7 @@ static inline window *window_create(grs_canvas *src, int x, int y, int w, int h,
template <typename T1, typename T2 = const void>
static inline window *window_create(grs_canvas *src, int x, int y, int w, int h, window_subfunction<const T1> event_callback, const T1 *userdata, T2 *createdata = nullptr)
{
return window_create(src, x, y, w, h, reinterpret_cast<window_subfunction<void>>(event_callback), static_cast<void *>(const_cast<T1 *>(userdata)), static_cast<const void *>(createdata));
}
static inline window *window_set_visible(window *wind, int visible)
{
return window_set_visible(*wind, visible);
}
static inline int window_is_visible(window *wind)
{
return window_is_visible(*wind);
}
static inline void window_set_modal(window *wind, int modal)
{
window_set_modal(*wind, modal);
return new window(src, x, y, w, h, reinterpret_cast<window_subfunction<void>>(event_callback), static_cast<void *>(const_cast<T1 *>(userdata)), static_cast<const void *>(createdata));
}
static inline window_event_result (WINDOW_SEND_EVENT)(window &w, const d_event &event, const char *file, unsigned line, const char *e)

View file

@ -137,6 +137,7 @@ static window_event_result ui_dialog_handler(window *wind,const d_event &event,
ui_gadget_delete_all(dlg);
selected_gadget = NULL;
delete dlg;
delete wind;
return window_event_result::ignored;
default:
return window_event_result::ignored;

View file

@ -510,7 +510,7 @@ static window_event_result do_state_2(const d_event &event)
static window_event_result menu_handler(window *, const d_event &event, MENU *menu)
static window_event_result menu_handler(window *wind, const d_event &event, MENU *menu)
{
int i;
int keypress = 0;
@ -524,7 +524,8 @@ static window_event_result menu_handler(window *, const d_event &event, MENU *me
{
state = 0;
menu_hide_all();
menu->wind = NULL;
delete wind;
menu->wind = nullptr;
return window_event_result::ignored;
}
window_event_result rval = window_event_result::ignored;
@ -664,7 +665,7 @@ static window_event_result menu_handler(window *, const d_event &event, MENU *me
return rval;
}
static window_event_result menubar_handler(window *, const d_event &event, MENU *)
static window_event_result menubar_handler(window *wind, const d_event &event, MENU *)
{
if (event.type == EVENT_WINDOW_DRAW)
{
@ -684,7 +685,8 @@ static window_event_result menubar_handler(window *, const d_event &event, MENU
}
}
Menu[0].wind = NULL;
delete wind;
Menu[0].wind = nullptr;
}
switch (state)

View file

@ -1690,6 +1690,7 @@ static window_event_result escort_menu_handler(window *wind,const d_event &event
case EVENT_WINDOW_CLOSE:
d_free(menu);
delete wind;
return window_event_result::ignored; // continue closing
default:
return window_event_result::ignored;

View file

@ -274,7 +274,7 @@ struct movie : ignore_window_pointer_t
}
static window_event_result show_pause_message(window *, const d_event &event, const unused_window_userdata_t *)
static window_event_result show_pause_message(window *wind, const d_event &event, const unused_window_userdata_t *)
{
switch (event.type)
{
@ -309,13 +309,17 @@ static window_event_result show_pause_message(window *, const d_event &event, co
break;
}
case EVENT_WINDOW_CLOSE:
delete wind;
break;
default:
break;
}
return window_event_result::ignored;
}
static window_event_result MovieHandler(window *, const d_event &event, movie *m)
static window_event_result MovieHandler(window *wind, const d_event &event, movie *m)
{
int key;
@ -369,6 +373,7 @@ static window_event_result MovieHandler(window *, const d_event &event, movie *m
case EVENT_WINDOW_CLOSE:
if (Quitting)
m->result = m->aborted = 1;
delete wind;
break;
default:

View file

@ -334,6 +334,7 @@ static window_event_result info_display_all(window *wind,const d_event &event, c
return window_event_result::handled;
case EVENT_WINDOW_CLOSE:
Pad_info = NULL;
delete wind;
break;
default:

View file

@ -952,6 +952,7 @@ static window_event_result automap_handler(window *wind,const d_event &event, au
window_set_visible(Game_wind, 1);
Automap_active = 0;
multi_send_msgsend_state(msgsend_none);
delete wind;
return window_event_result::ignored; // continue closing
break;

View file

@ -287,6 +287,7 @@ static window_event_result con_handler(window *wind,const d_event &event, const
}
break;
case EVENT_WINDOW_CLOSE:
delete wind;
break;
default:
break;

View file

@ -94,7 +94,7 @@ struct credits : ignore_window_pointer_t
}
namespace dsx {
static window_event_result credits_handler(window *, const d_event &event, credits *cr)
static window_event_result credits_handler(window *wind, const d_event &event, credits *cr)
{
int l, y;
switch (event.type)
@ -217,6 +217,8 @@ static window_event_result credits_handler(window *, const d_event &event, credi
songs_set_volume(GameCfg.MusicVolume);
songs_play_song( SONG_TITLE, 1 );
std::default_delete<credits>()(cr);
if (wind)
delete wind;
break;
default:
break;

View file

@ -1305,6 +1305,7 @@ window_event_result game_handler(window *,const d_event &event, const unused_win
if (!EditorWindow) // have to do it this way because of the necessary longjmp. Yuck.
#endif
show_menus();
delete Game_wind;
Game_wind = NULL;
event_toggle_focus(0);
key_toggle_repeat(1);

View file

@ -339,7 +339,7 @@ struct pause_window : ignore_window_pointer_t
};
//Process selected keys until game unpaused
static window_event_result pause_handler(window *, const d_event &event, pause_window *p)
static window_event_result pause_handler(window *wind, const d_event &event, pause_window *p)
{
int key;
@ -379,6 +379,7 @@ static window_event_result pause_handler(window *, const d_event &event, pause_w
case EVENT_WINDOW_CLOSE:
songs_resume();
delete p;
delete wind;
break;
default:

View file

@ -1286,6 +1286,7 @@ static window_event_result kconfig_handler(window *wind,const d_event &event, kc
case EVENT_WINDOW_CLOSE:
delete menu;
delete wind;
// Update save values...

View file

@ -279,7 +279,7 @@ static void kmatrix_redraw_coop()
}
namespace dsx {
static window_event_result kmatrix_handler(window *, const d_event &event, kmatrix_screen *km)
static window_event_result kmatrix_handler(window *wind, const d_event &event, kmatrix_screen *km)
{
int k = 0, choice = 0;
@ -377,6 +377,7 @@ static window_event_result kmatrix_handler(window *, const d_event &event, kmatr
case EVENT_WINDOW_CLOSE:
game_flush_inputs();
newmenu_free_background();
delete wind;
break;
default:

View file

@ -2285,7 +2285,7 @@ void do_options_menu()
#ifndef RELEASE
namespace dsx {
static window_event_result polygon_models_viewer_handler(window *, const d_event &event, const unused_window_userdata_t *)
static window_event_result polygon_models_viewer_handler(window *wind, const d_event &event, const unused_window_userdata_t *)
{
static unsigned view_idx;
int key = 0;
@ -2354,6 +2354,8 @@ static window_event_result polygon_models_viewer_handler(window *, const d_event
case EVENT_WINDOW_CLOSE:
load_palette(MENU_PALETTE,0,1);
key_toggle_repeat(0);
if (wind)
delete wind;
break;
default:
break;
@ -2377,7 +2379,7 @@ static void polygon_models_viewer()
}
namespace dsx {
static window_event_result gamebitmaps_viewer_handler(window *, const d_event &event, const unused_window_userdata_t *)
static window_event_result gamebitmaps_viewer_handler(window *wind, const d_event &event, const unused_window_userdata_t *)
{
static int view_idx = 0;
int key = 0;
@ -2433,6 +2435,8 @@ static window_event_result gamebitmaps_viewer_handler(window *, const d_event &e
case EVENT_WINDOW_CLOSE:
load_palette(MENU_PALETTE,0,1);
key_toggle_repeat(0);
if (wind)
delete wind;
break;
default:
break;

View file

@ -1567,6 +1567,7 @@ static window_event_result newmenu_handler(window *wind,const d_event &event, ne
return newmenu_draw(wind, menu);
case EVENT_WINDOW_CLOSE:
delete menu;
delete wind;
break;
default:
@ -2074,6 +2075,7 @@ static window_event_result listbox_handler(window *wind,const d_event &event, li
return listbox_draw(wind, lb);
case EVENT_WINDOW_CLOSE:
std::default_delete<listbox>()(lb);
delete wind;
break;
default:
break;

View file

@ -446,6 +446,7 @@ static window_event_result scores_handler(window *wind,const d_event &event, sco
case EVENT_WINDOW_CLOSE:
d_free(menu);
delete wind;
break;
default:

View file

@ -109,7 +109,7 @@ struct title_screen : ignore_window_pointer_t
}
static window_event_result title_handler(window *, const d_event &event, title_screen *ts)
static window_event_result title_handler(window *wind, const d_event &event, title_screen *ts)
{
switch (event.type)
{
@ -146,6 +146,7 @@ static window_event_result title_handler(window *, const d_event &event, title_s
case EVENT_WINDOW_CLOSE:
gr_free_bitmap_data(ts->title_bm);
delete wind;
break;
default:
@ -1443,7 +1444,7 @@ static int new_briefing_screen(briefing *br, int first)
//-----------------------------------------------------------------------------
namespace dsx {
static window_event_result briefing_handler(window *, const d_event &event, briefing *br)
static window_event_result briefing_handler(window *wind, const d_event &event, briefing *br)
{
switch (event.type)
{
@ -1553,6 +1554,7 @@ static window_event_result briefing_handler(window *, const d_event &event, brie
#if defined(DXX_BUILD_DESCENT_II)
br->hum_channel.reset();
#endif
delete wind;
break;
default: