aboutsummaryrefslogtreecommitdiff
path: root/win32
diff options
context:
space:
mode:
Diffstat (limited to 'win32')
-rw-r--r--win32/about.c197
-rw-r--r--win32/about.h14
-rw-r--r--win32/fmplayer.mak1
-rw-r--r--win32/main.c148
-rw-r--r--win32/oscilloview.c14
-rw-r--r--win32/oscilloview.h3
6 files changed, 347 insertions, 30 deletions
diff --git a/win32/about.c b/win32/about.c
new file mode 100644
index 0000000..f18c067
--- /dev/null
+++ b/win32/about.c
@@ -0,0 +1,197 @@
+#include "about.h"
+#include <windowsx.h>
+#include <stdbool.h>
+#include <wchar.h>
+#include <stdlib.h>
+#include "version.h"
+
+enum {
+ ID_OK = 0x10
+};
+
+extern HWND g_currentdlg;
+
+static struct {
+ HINSTANCE hinst;
+ void (*closecb)(void *ptr);
+ void *cbptr;
+ HWND about;
+ ATOM about_class;
+ HFONT font, font_large;
+ HWND static_main, static_icon, static_help, static_info, button_ok;
+ wchar_t *soundapiname;
+ bool adpcm_rom, font_rom;
+} g;
+
+static void on_destroy(HWND hwnd) {
+ DestroyWindow(g.static_main);
+ DestroyWindow(g.static_info);
+ DestroyWindow(g.static_help);
+ DestroyWindow(g.static_icon);
+ DestroyWindow(g.button_ok);
+ if (g.closecb) {
+ g.closecb(g.cbptr);
+ }
+ g.about = 0;
+}
+
+static void update_status(void) {
+ static wchar_t buf[1024];
+ swprintf(buf, sizeof(buf)/sizeof(buf[0]),
+ L"Audio API: %ls\r\n"
+ "ym2608_adpcm_rom.bin: %lsavailable\r\n"
+ "font.rom: %ls\r\n"
+ "SSE2 (for SIMD SSG resampling): %lsavailable\r\n"
+ "SSSE3 (for SIMD FMDSP palette lookup): %lsavailable",
+ g.soundapiname ? g.soundapiname : L"",
+ g.adpcm_rom ? L"" : L"un",
+ g.font_rom ? L"available" : L"unavailable, using MS Gothic",
+ __builtin_cpu_supports("sse2") ? L"" : L"un",
+ __builtin_cpu_supports("ssse3") ? L"" : L"un");
+ SetWindowText(g.static_info, buf);
+}
+
+static bool on_create(HWND hwnd, const CREATESTRUCT *cs) {
+ RECT wr = {
+ .left = 0,
+ .top = 0,
+ .right = 480,
+ .bottom = 300
+ };
+ DWORD style = GetWindowLongPtr(hwnd, GWL_STYLE);
+ DWORD exstyle = GetWindowLongPtr(hwnd, GWL_EXSTYLE);
+ AdjustWindowRectEx(&wr, style, 0, exstyle);
+ SetWindowPos(hwnd, HWND_TOP, 0, 0, wr.right-wr.left, wr.bottom-wr.top,
+ SWP_NOZORDER | SWP_NOMOVE);
+ if (!g.font) {
+ NONCLIENTMETRICS ncm;
+ ncm.cbSize = sizeof(ncm);
+ SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0);
+ LONG height = ncm.lfMessageFont.lfHeight;
+ ncm.lfMessageFont.lfHeight = height * 1.2;
+ ncm.lfMessageFont.lfWidth = 0;
+ g.font = CreateFontIndirect(&ncm.lfMessageFont);
+ ncm.lfMessageFont.lfHeight = height * 1.5;
+ ncm.lfMessageFont.lfWidth = 0;
+ g.font_large = CreateFontIndirect(&ncm.lfMessageFont);
+ }
+ g.static_icon = CreateWindowEx(0, L"static",
+ MAKEINTRESOURCE(1),
+ WS_CHILD | WS_VISIBLE | SS_ICON,
+ 100, 10, 32, 32,
+ hwnd, 0, g.hinst, 0);
+#ifdef _WIN64
+#define ABOUT_ARCH "(amd64)"
+#else
+#define ABOUT_ARCH "(i586)"
+#endif
+ g.static_info = CreateWindowEx(0, L"static",
+ L"",
+ WS_CHILD | WS_VISIBLE,
+ 75, 50, 400, 90,
+ hwnd, 0, g.hinst, 0);
+ SetWindowFont(g.static_info, g.font, TRUE);
+ update_status();
+ g.static_help = CreateWindowEx(0, L"static",
+ L"F11: toggle track display page\r\n"
+ "F12: display FMDSP at 2x\r\n"
+ "Ctrl+F1-F10: FMDSP color palette\r\n\r\n"
+ "1-9,0,-: toggle track mask (Ctrl: PPZ8)\r\n"
+ "Shift+1-9,0,-: track solo\r\n"
+ "=: invert all mask\r\n"
+ "\\: all tracks on",
+ WS_CHILD | WS_VISIBLE,
+ 75, 140, 400, 400,
+ hwnd, 0, g.hinst, 0);
+ SetWindowFont(g.static_help, g.font, TRUE);
+ g.static_main = CreateWindowEx(0, L"static",
+ L"FMPlayer/Win32 " ABOUT_ARCH " v" FMPLAYER_VERSION_STR,
+ WS_CHILD | WS_VISIBLE,
+ 150, 10, 400, 40,
+ hwnd, 0, g.hinst, 0);
+ SetWindowFont(g.static_main, g.font_large, TRUE);
+ g.button_ok = CreateWindowEx(0, L"button",
+ L"&OK",
+ WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_DEFPUSHBUTTON,
+ 200, 270, 80, 25,
+ hwnd, (HMENU)ID_OK, g.hinst, 0);
+ SetWindowFont(g.button_ok, g.font, TRUE);
+ ShowWindow(hwnd, SW_SHOW);
+ return true;
+}
+
+static void on_activate(HWND hwnd, bool activate, HWND targetwnd, WINBOOL state) {
+ if (activate) g_currentdlg = hwnd;
+ else g_currentdlg = 0;
+}
+
+static void on_command(HWND hwnd, int id, HWND hwnd_c, UINT code) {
+ if (code == BN_CLICKED && (id == ID_OK)) {
+ DestroyWindow(hwnd);
+ }
+}
+
+static LRESULT CALLBACK wndproc(
+ HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam
+) {
+ switch (msg) {
+ HANDLE_MSG(hwnd, WM_DESTROY, on_destroy);
+ HANDLE_MSG(hwnd, WM_CREATE, on_create);
+ HANDLE_MSG(hwnd, WM_ACTIVATE, on_activate);
+ HANDLE_MSG(hwnd, WM_COMMAND, on_command);
+ }
+ return DefWindowProc(hwnd, msg, wParam, lParam);
+}
+
+void about_open(HINSTANCE hinst, HWND parent, void (*closecb)(void *ptr), void *cbptr) {
+ g.closecb = closecb;
+ g.cbptr = cbptr;
+ g.hinst = hinst;
+ if (!g.about) {
+ if (!g.about_class) {
+ WNDCLASS wc = {0};
+ wc.lpfnWndProc = wndproc;
+ wc.hInstance = g.hinst;
+ wc.hIcon = LoadIcon(g.hinst, MAKEINTRESOURCE(1));
+ wc.hCursor = LoadCursor(0, IDC_ARROW);
+ wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);
+ wc.lpszClassName = L"myon_fmplayer_ym2608_about";
+ g.about_class = RegisterClass(&wc);
+ }
+ if (!g.about_class) {
+ MessageBox(parent, L"Cannot register class", L"Error", MB_ICONSTOP);
+ return;
+ }
+ g.about = CreateWindowEx(0,
+ MAKEINTATOM(g.about_class),
+ L"About",
+ WS_CAPTION | WS_SYSMENU,
+ CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
+ parent, 0, g.hinst, 0);
+ } else {
+ SetForegroundWindow(g.about);
+ }
+}
+
+void about_setsoundapiname(const wchar_t *apiname) {
+ free(g.soundapiname);
+ g.soundapiname = wcsdup(apiname);
+ if (g.about) update_status();
+}
+
+void about_set_fontrom_loaded(bool loaded) {
+ g.font_rom = loaded;
+ if (g.about) update_status();
+}
+
+void about_set_adpcmrom_loaded(bool loaded) {
+ g.adpcm_rom = loaded;
+ if (g.about) update_status();
+}
+
+void about_close(void) {
+ if (g.about) {
+ g.closecb = 0;
+ DestroyWindow(g.about);
+ }
+}
diff --git a/win32/about.h b/win32/about.h
new file mode 100644
index 0000000..2356e26
--- /dev/null
+++ b/win32/about.h
@@ -0,0 +1,14 @@
+#ifndef MYON_FMPLAYER_WIN32_ABOUT_H_INCLUDED
+#define MYON_FMPLAYER_WIN32_ABOUT_H_INCLUDED
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <stdbool.h>
+
+void about_open(HINSTANCE hinst, HWND parent, void (*closecb)(void *ptr), void *cbptr);
+void about_close(void);
+void about_setsoundapiname(const wchar_t *apiname);
+void about_set_fontrom_loaded(bool loaded);
+void about_set_adpcmrom_loaded(bool loaded);
+
+#endif // MYON_FMPLAYER_WIN32_ABOUT_H_INCLUDED
diff --git a/win32/fmplayer.mak b/win32/fmplayer.mak
index 180de1c..14e3246 100644
--- a/win32/fmplayer.mak
+++ b/win32/fmplayer.mak
@@ -35,6 +35,7 @@ OBJBASE=main \
guid \
fmplayer_file \
fmplayer_file_win \
+ about \
$(FMDRIVER_OBJS) \
$(LIBOPNA_OBJS) \
$(TONEDATA_OBJS) \
diff --git a/win32/main.c b/win32/main.c
index 8dc6bb8..76cd883 100644
--- a/win32/main.c
+++ b/win32/main.c
@@ -19,6 +19,7 @@
#include "toneview.h"
#include "oscillo/oscillo.h"
#include "oscilloview.h"
+#include "about.h"
enum {
ID_OPENFILE = 0x10,
@@ -26,6 +27,7 @@ enum {
ID_2X,
ID_TONEVIEW,
ID_OSCILLOVIEW,
+ ID_ABOUT,
};
#define FMPLAYER_CLASSNAME L"myon_fmplayer_ym2608_win32"
@@ -62,7 +64,8 @@ static struct {
HWND mainwnd;
WNDPROC btn_defproc;
HWND driverinfo;
- HWND button_2x;
+ HWND button_2x, button_toneview, button_oscilloview, button_about;
+ bool toneview_on, oscilloview_on, about_on;
const wchar_t *lastopenpath;
bool fmdsp_2x;
struct oscillodata oscillodata_audiothread[LIBOPNA_OSCILLO_TRACK_COUNT];
@@ -140,6 +143,7 @@ static bool loadfontrom(void) {
CloseHandle(file);
fmdsp_font_from_font_rom(&g.font, g.fontrom);
g.font_loaded = true;
+ about_set_fontrom_loaded(true);
return true;
err_file:
CloseHandle(file);
@@ -178,6 +182,7 @@ static void loadrom(void) {
|| readbytes != OPNA_ROM_SIZE) goto err_buf;
CloseHandle(file);
g.drum_rom = buf;
+ about_set_adpcmrom_loaded(true);
return;
err_buf:
HeapFree(g.heap, 0, buf);
@@ -229,6 +234,7 @@ static void openfile(HWND hwnd, const wchar_t *path) {
g.sound = sound_init(hwnd, SRATE, SECTLEN,
sound_cb, &g.opna_timer);
SetWindowText(g.driverinfo, g.sound->apiname);
+ about_setsoundapiname(g.sound->apiname);
}
fmdsp_vram_init(&g.fmdsp, &g.work, g.vram);
if (!g.sound) goto err;
@@ -327,11 +333,38 @@ static void on_dropfiles(HWND hwnd, HDROP hdrop) {
}
#endif // ENABLE_WM_DROPFILES
-static void mask_set(unsigned mask, bool shift) {
- if (shift) {
- opna_set_mask(&g.opna, ~mask);
+static void mask_set(int p, bool shift, bool control) {
+ if (!control) {
+ if (p >= 11) return;
+ static const unsigned masktbl[11] = {
+ LIBOPNA_CHAN_FM_1,
+ LIBOPNA_CHAN_FM_2,
+ LIBOPNA_CHAN_FM_3,
+ LIBOPNA_CHAN_FM_4,
+ LIBOPNA_CHAN_FM_5,
+ LIBOPNA_CHAN_FM_6,
+ LIBOPNA_CHAN_SSG_1,
+ LIBOPNA_CHAN_SSG_2,
+ LIBOPNA_CHAN_SSG_3,
+ LIBOPNA_CHAN_DRUM_ALL,
+ LIBOPNA_CHAN_ADPCM,
+ };
+ unsigned mask = masktbl[p];
+ if (shift) {
+ opna_set_mask(&g.opna, ~mask);
+ ppz8_set_mask(&g.ppz8, -1);
+ } else {
+ opna_set_mask(&g.opna, opna_get_mask(&g.opna) ^ mask);
+ }
} else {
- opna_set_mask(&g.opna, opna_get_mask(&g.opna) ^ mask);
+ if (p >= 8) return;
+ unsigned mask = 1u<<p;
+ if (shift) {
+ ppz8_set_mask(&g.ppz8, ~mask);
+ opna_set_mask(&g.opna, -1);
+ } else {
+ ppz8_set_mask(&g.ppz8, ppz8_get_mask(&g.ppz8) ^ mask);
+ }
}
}
@@ -382,45 +415,48 @@ static bool proc_key(UINT vk, bool down, int repeat) {
}
} else {
bool shift = GetKeyState(VK_SHIFT) & 0x8000U;
+ bool ctrl = GetKeyState(VK_CONTROL) & 0x8000U;
switch (vk) {
case '1':
- mask_set(LIBOPNA_CHAN_FM_1, shift);
+ mask_set(0, shift, ctrl);
return true;
case '2':
- mask_set(LIBOPNA_CHAN_FM_2, shift);
+ mask_set(1, shift, ctrl);
return true;
case '3':
- mask_set(LIBOPNA_CHAN_FM_3, shift);
+ mask_set(2, shift, ctrl);
return true;
case '4':
- mask_set(LIBOPNA_CHAN_FM_4, shift);
+ mask_set(3, shift, ctrl);
return true;
case '5':
- mask_set(LIBOPNA_CHAN_FM_5, shift);
+ mask_set(4, shift, ctrl);
return true;
case '6':
- mask_set(LIBOPNA_CHAN_FM_6, shift);
+ mask_set(5, shift, ctrl);
return true;
case '7':
- mask_set(LIBOPNA_CHAN_SSG_1, shift);
+ mask_set(6, shift, ctrl);
return true;
case '8':
- mask_set(LIBOPNA_CHAN_SSG_2, shift);
+ mask_set(7, shift, ctrl);
return true;
case '9':
- mask_set(LIBOPNA_CHAN_SSG_3, shift);
+ mask_set(8, shift, ctrl);
return true;
case '0':
- mask_set(LIBOPNA_CHAN_DRUM_ALL, shift);
+ mask_set(9, shift, ctrl);
return true;
case VK_OEM_MINUS:
- mask_set(LIBOPNA_CHAN_ADPCM, shift);
+ mask_set(10, shift, ctrl);
return true;
case VK_OEM_PLUS:
opna_set_mask(&g.opna, ~opna_get_mask(&g.opna));
+ ppz8_set_mask(&g.ppz8, ~ppz8_get_mask(&g.ppz8));
return true;
case VK_OEM_5:
opna_set_mask(&g.opna, 0);
+ ppz8_set_mask(&g.ppz8, 0);
return true;
}
}
@@ -498,30 +534,40 @@ static bool on_create(HWND hwnd, CREATESTRUCT *cs) {
30, 25,
hwnd, (HMENU)ID_2X, g.hinst, 0
);
- HWND button_toneview = CreateWindowEx(
+ g.button_toneview = CreateWindowEx(
0,
L"BUTTON",
L"&Tone viewer",
- WS_TABSTOP | WS_VISIBLE | WS_CHILD,
+ WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_CHECKBOX | BS_PUSHLIKE,
250, 10,
100, 25,
hwnd, (HMENU)ID_TONEVIEW, g.hinst, 0
);
- HWND button_oscilloview = CreateWindowEx(
+ g.button_oscilloview = CreateWindowEx(
0,
L"BUTTON",
L"Oscillo&view",
- WS_TABSTOP | WS_VISIBLE | WS_CHILD,
+ WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_CHECKBOX | BS_PUSHLIKE,
355, 10,
100, 25,
hwnd, (HMENU)ID_OSCILLOVIEW, g.hinst, 0
);
+ g.button_about = CreateWindowEx(
+ 0,
+ L"BUTTON",
+ L"&About",
+ WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_CHECKBOX | BS_PUSHLIKE,
+ 580, 10,
+ 50, 25,
+ hwnd, (HMENU)ID_ABOUT, g.hinst, 0
+ );
g.btn_defproc = (WNDPROC)GetWindowLongPtr(button, GWLP_WNDPROC);
SetWindowLongPtr(button, GWLP_WNDPROC, (intptr_t)btn_wndproc);
SetWindowLongPtr(pbutton, GWLP_WNDPROC, (intptr_t)btn_wndproc);
SetWindowLongPtr(g.button_2x, GWLP_WNDPROC, (intptr_t)btn_wndproc);
- SetWindowLongPtr(button_toneview, GWLP_WNDPROC, (intptr_t)btn_wndproc);
- SetWindowLongPtr(button_oscilloview, GWLP_WNDPROC, (intptr_t)btn_wndproc);
+ SetWindowLongPtr(g.button_toneview, GWLP_WNDPROC, (intptr_t)btn_wndproc);
+ SetWindowLongPtr(g.button_oscilloview, GWLP_WNDPROC, (intptr_t)btn_wndproc);
+ SetWindowLongPtr(g.button_about, GWLP_WNDPROC, (intptr_t)btn_wndproc);
NONCLIENTMETRICS ncm;
ncm.cbSize = sizeof(ncm);
SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0);
@@ -530,8 +576,9 @@ static bool on_create(HWND hwnd, CREATESTRUCT *cs) {
SetWindowFont(pbutton, font, TRUE);
SetWindowFont(g.driverinfo, font, TRUE);
SetWindowFont(g.button_2x, font, TRUE);
- SetWindowFont(button_toneview, font, TRUE);
- SetWindowFont(button_oscilloview, font, TRUE);
+ SetWindowFont(g.button_toneview, font, TRUE);
+ SetWindowFont(g.button_oscilloview, font, TRUE);
+ SetWindowFont(g.button_about, font, TRUE);
loadrom();
loadfont();
fmdsp_init(&g.fmdsp, g.font_loaded ? &g.font : 0);
@@ -544,6 +591,24 @@ static bool on_create(HWND hwnd, CREATESTRUCT *cs) {
return true;
}
+static void toneview_close_cb(void *ptr) {
+ (void)ptr;
+ g.toneview_on = false;
+ Button_SetCheck(g.button_toneview, false);
+}
+
+static void oscilloview_close_cb(void *ptr) {
+ (void)ptr;
+ g.oscilloview_on = false;
+ Button_SetCheck(g.button_oscilloview, false);
+}
+
+static void about_close_cb(void *ptr) {
+ (void)ptr;
+ g.about_on = false;
+ Button_SetCheck(g.button_about, false);
+}
+
static void on_command(HWND hwnd, int id, HWND hwnd_c, UINT code) {
(void)code;
(void)hwnd_c;
@@ -561,10 +626,37 @@ static void on_command(HWND hwnd, int id, HWND hwnd_c, UINT code) {
toggle_2x(hwnd);
break;
case ID_TONEVIEW:
- show_toneview(g.hinst, hwnd);
+ if (!g.toneview_on) {
+ g.toneview_on = true;
+ toneview_open(g.hinst, hwnd, toneview_close_cb, 0);
+ Button_SetCheck(g.button_toneview, true);
+ } else {
+ g.toneview_on = false;
+ toneview_close();
+ Button_SetCheck(g.button_toneview, false);
+ }
break;
case ID_OSCILLOVIEW:
- show_oscilloview(g.hinst, hwnd);
+ if (!g.oscilloview_on) {
+ g.oscilloview_on = true;
+ oscilloview_open(g.hinst, hwnd, oscilloview_close_cb, 0);
+ Button_SetCheck(g.button_oscilloview, true);
+ } else {
+ g.oscilloview_on = false;
+ oscilloview_close();
+ Button_SetCheck(g.button_oscilloview, false);
+ }
+ break;
+ case ID_ABOUT:
+ if (!g.about_on) {
+ g.about_on = true;
+ about_open(g.hinst, hwnd, about_close_cb, 0);
+ Button_SetCheck(g.button_about, true);
+ } else {
+ g.about_on = false;
+ about_close();
+ Button_SetCheck(g.button_about, false);
+ }
break;
}
}
@@ -744,13 +836,13 @@ int CALLBACK wWinMain(HINSTANCE hinst, HINSTANCE hpinst,
wr.bottom = 480;
AdjustWindowRectEx(&wr, style, 0, exStyle);
#ifdef _WIN64
-#define WIN64STR "(amd64)"
+#define WIN64STR "(amd64) "
#else
#define WIN64STR ""
#endif
g.mainwnd = CreateWindowEx(
exStyle,
- (wchar_t*)((uintptr_t)wcatom), L"FMPlayer/Win32 " WIN64STR " v" FMPLAYER_VERSION_STR,
+ (wchar_t*)((uintptr_t)wcatom), L"FMPlayer/Win32 " WIN64STR "v" FMPLAYER_VERSION_STR,
style,
CW_USEDEFAULT, CW_USEDEFAULT,
wr.right-wr.left, wr.bottom-wr.top,
diff --git a/win32/oscilloview.c b/win32/oscilloview.c
index 1478614..12851f4 100644
--- a/win32/oscilloview.c
+++ b/win32/oscilloview.c
@@ -24,12 +24,15 @@ static struct {
struct oscillodata oscillodata[LIBOPNA_OSCILLO_TRACK_COUNT];
UINT mmtimer;
HPEN whitepen;
+ void (*closecb)(void *ptr);
+ void *cbptr;
} g;
static void on_destroy(HWND hwnd) {
g.oscilloview = 0;
timeKillEvent(g.mmtimer);
DeleteObject(g.whitepen);
+ if (g.closecb) g.closecb(g.cbptr);
}
static void CALLBACK mmtimer_cb(UINT timerid, UINT msg,
@@ -111,7 +114,9 @@ static LRESULT CALLBACK wndproc(
return DefWindowProc(hwnd, msg, wParam, lParam);
}
-void show_oscilloview(HINSTANCE hinst, HWND parent) {
+void oscilloview_open(HINSTANCE hinst, HWND parent, void (*closecb)(void *ptr), void *cbptr) {
+ g.closecb = closecb;
+ g.cbptr = cbptr;
g.hinst = hinst;
g.parent = parent;
if (!g.oscilloview) {
@@ -140,3 +145,10 @@ void show_oscilloview(HINSTANCE hinst, HWND parent) {
SetForegroundWindow(g.oscilloview);
}
}
+
+void oscilloview_close(void) {
+ if (g.oscilloview) {
+ g.closecb = 0;
+ DestroyWindow(g.oscilloview);
+ }
+}
diff --git a/win32/oscilloview.h b/win32/oscilloview.h
index 8849830..00d2e60 100644
--- a/win32/oscilloview.h
+++ b/win32/oscilloview.h
@@ -13,7 +13,8 @@ extern struct oscilloview {
struct oscillodata oscillodata[LIBOPNA_OSCILLO_TRACK_COUNT];
} oscilloview_g;
-void show_oscilloview(HINSTANCE hinst, HWND parent);
+void oscilloview_open(HINSTANCE hinst, HWND parent, void (*closecb)(void *ptr), void *cbptr);
+void oscilloview_close(void);
#endif // MYON_FMPLAYER_WIN32_OSCILLOVIEW_H_INCLUDED