WinUAE/od-win32/win32gui_extra.cpp
Toni Wilen c81a3c40cb 3600b9
2017-12-02 18:47:32 +02:00

745 lines
17 KiB
C++

#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <commctrl.h>
#include "sysconfig.h"
#include "sysdeps.h"
#include "resource.h"
#include "registry.h"
#include "win32.h"
#include "win32gui.h"
#include "xwin.h"
#include "zfile.h"
#define MAX_GUI_FONTS 2
#define DEFAULT_FONTSIZE 8
static double multx, multy;
static int scaleresource_width, scaleresource_height;
static TCHAR fontname_gui[32], fontname_list[32];
static int fontsize_gui = DEFAULT_FONTSIZE;
static int fontsize_list = DEFAULT_FONTSIZE;
static int fontstyle_gui = 0;
static int fontstyle_list = 0;
static int fontweight_gui = FW_REGULAR;
static int fontweight_list = FW_REGULAR;
static int listviewcnt;
static int listviews_id[16];
static int setparamcnt;
static int setparam_id[16];
static HFONT listviewfont;
static TEXTMETRIC listview_tm;
static const TCHAR *fontprefix;
#define BASEMULT 1000
static int baseunitx, baseunity;
static RECT baserect, baseclientrect;
static int baseborderwidth, baseborderheight;
static int basewidth, baseheight;
static int baseclientwidth, baseclientheight;
#include <pshpack2.h>
typedef struct {
WORD dlgVer;
WORD signature;
DWORD helpID;
DWORD exStyle;
DWORD style;
WORD cDlgItems;
short x;
short y;
short cx;
short cy;
/*
sz_Or_Ord menu;
sz_Or_Ord windowClass;
WCHAR title[titleLen];
*/
} DLGTEMPLATEEX;
typedef struct {
WORD pointsize;
WORD weight;
BYTE italic;
BYTE charset;
WCHAR typeface[1];
} DLGTEMPLATEEX_END;
typedef struct {
DWORD helpID;
DWORD exStyle;
DWORD style;
short x;
short y;
short cx;
short cy;
WORD id;
WORD reserved;
WCHAR windowClass[1];
/* variable data after this */
/* sz_Or_Ord title; */
/* WORD extraCount; */
} DLGITEMTEMPLATEEX;
#include <poppack.h>
static int font_vista_ok;
static const wchar_t wfont_vista[] = _T("Segoe UI");
static const wchar_t wfont_xp[] = _T("Tahoma");
static const wchar_t wfont_old[] = _T("MS Sans Serif");
static const TCHAR font_vista[] = _T("Segoe UI");
static const TCHAR font_xp[] = _T("Tahoma");
static int align (double f)
{
int v = (int)(f + 0.5);
return v;
}
static int mmx (int v)
{
return align ((v * multx) / 100.0 + 0.5);
}
static int mmy (int v)
{
return align ((v * multy) / 100.0 + 0.5);
}
static BYTE *skiptextone (BYTE *s)
{
s -= sizeof (WCHAR);
if (s[0] == 0xff && s[1] == 0xff) {
s += 4;
return s;
}
while (s[0] != 0 || s[1] != 0)
s += 2;
s += 2;
return s;
}
static BYTE *skiptext (BYTE *s)
{
if (s[0] == 0xff && s[1] == 0xff) {
s += 4;
return s;
}
while (s[0] != 0 || s[1] != 0)
s += 2;
s += 2;
return s;
}
static BYTE *todword (BYTE *p)
{
while ((LONG_PTR)p & 3)
p++;
return p;
}
static void modifytemplate (DLGTEMPLATEEX *d, DLGTEMPLATEEX_END *d2, int id, int fullscreen)
{
if (fullscreen) {
d->cx = scaleresource_width;
d->cy = scaleresource_height;
} else {
d->cx = mmx (d->cx);
d->cy = mmy (d->cy);
}
}
static void modifytemplatefont (DLGTEMPLATEEX *d, DLGTEMPLATEEX_END *d2)
{
if (!wcscmp (d2->typeface, wfont_old)) {
wcscpy (d2->typeface, fontname_gui);
d2->pointsize = fontsize_gui;
d2->italic = (fontstyle_gui & ITALIC_FONTTYPE) != 0;
d2->weight = fontweight_gui;
}
}
static void modifyitem (DLGTEMPLATEEX *d, DLGTEMPLATEEX_END *d2, DLGITEMTEMPLATEEX *dt, int id)
{
bool noyscale = false;
int wc = 0;
if (dt->windowClass[0] == 0xffff)
wc = dt->windowClass[1];
if (multy >= 89 && multy <= 111) {
if (wc == 0x0080 && dt->cy <= 20) { // button
noyscale = true;
}
if (wc == 0x0085) {// combo box
noyscale = false;
}
if (wc == 0x0081 && dt->cy <= 20) { // edit box
noyscale = true;
}
}
if (!noyscale)
dt->cy = mmy (dt->cy);
dt->cx = mmx (dt->cx);
dt->y = mmy (dt->y);
dt->x = mmx (dt->x);
if (wc == 0x0085) {// combo box
setparam_id[setparamcnt] = dt->id;
setparamcnt++;
}
if (dt->windowClass[0] != 0xffff) {
if (!_tcsicmp (dt->windowClass, WC_LISTVIEWW) || !_tcsicmp (dt->windowClass, WC_TREEVIEWW)) {
listviews_id[listviewcnt] = dt->id;
listviewcnt++;
}
}
}
static INT_PTR CALLBACK DummyProc (HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_DESTROY:
PostQuitMessage (0);
return TRUE;
case WM_CLOSE:
DestroyWindow(hDlg);
return TRUE;
case WM_INITDIALOG:
return TRUE;
}
return FALSE;
}
extern int full_property_sheet;
static struct newresource *scaleresource2 (struct newresource *res, HWND parent, int resize, int fullscreen, DWORD exstyle, bool main)
{
static int main_width, main_height;
DLGTEMPLATEEX *d, *s;
DLGTEMPLATEEX_END *d2, *s2;
DLGITEMTEMPLATEEX *dt;
BYTE *p, *p2, *ps, *ps2;
int i;
struct newresource *ns;
listviewcnt = 0;
setparamcnt = 0;
d = (DLGTEMPLATEEX*)res->resource;
d2 = (DLGTEMPLATEEX_END*)res->resource;
if (d->dlgVer != 1 || d->signature != 0xffff)
return 0;
if (!(d->style & (DS_SETFONT | DS_SHELLFONT)))
return 0;
ns = xcalloc (struct newresource, 1);
ns->inst = res->inst;
ns->size = res->size;
ns->tmpl = res->tmpl;
ns->resource = (LPCDLGTEMPLATEW)xmalloc (uae_u8, ns->size + 32);
memcpy ((void*)ns->resource, res->resource, ns->size);
d = (DLGTEMPLATEEX*)ns->resource;
s = (DLGTEMPLATEEX*)res->resource;
int width = d->cx;
int height = d->cy;
if (resize > 0) {
d->style &= ~DS_MODALFRAME;
d->style |= WS_THICKFRAME;
} else if (resize == 0) {
d->style |= DS_MODALFRAME;
d->style &= ~WS_THICKFRAME;
}
if (fullscreen > 0) {
//d->style |= SW_MAXIMIZE;
d->style |= WS_THICKFRAME;
} else {
d->style |= WS_MINIMIZEBOX;
}
d->exStyle |= exstyle;
d2 = (DLGTEMPLATEEX_END*)ns->resource;
p = (BYTE*)d + sizeof (DLGTEMPLATEEX);
p = skiptext (p);
p = skiptext (p);
p = skiptext (p);
s2 = (DLGTEMPLATEEX_END*)res->resource;
ps = (BYTE*)s2 + sizeof (DLGTEMPLATEEX);
ps = skiptext (ps);
ps = skiptext (ps);
ps = skiptext (ps);
d2 = (DLGTEMPLATEEX_END*)p;
p2 = p;
p2 += sizeof (DLGTEMPLATEEX_END);
p2 = skiptextone (p2);
p2 = todword (p2);
s2 = (DLGTEMPLATEEX_END*)ps;
ps2 = ps;
ps2 += sizeof (DLGTEMPLATEEX_END);
ps2 = skiptextone (ps2);
ps2 = todword (ps2);
modifytemplatefont (d, d2);
p += sizeof (DLGTEMPLATEEX_END);
p = skiptextone (p);
p = todword (p);
memcpy (p, ps2, ns->size - (ps2 - (BYTE*)res->resource));
modifytemplate(d, d2, ns->tmpl, fullscreen);
for (i = 0; i < d->cDlgItems; i++) {
dt = (DLGITEMTEMPLATEEX*)p;
modifyitem (d, d2, dt, ns->tmpl);
p += sizeof (DLGITEMTEMPLATEEX);
p = skiptextone (p);
p = skiptext (p);
p += ((WORD*)p)[0];
p += sizeof (WORD);
p = todword (p);
}
ns->width = width;
ns->height = height;
return ns;
}
struct newresource *scaleresource (struct newresource *res, HWND parent, int resize, int fullscreen, DWORD exstyle, bool main)
{
return scaleresource2(res, parent, resize, fullscreen, exstyle, main);
}
void freescaleresource (struct newresource *ns)
{
xfree ((void*)ns->resource);
xfree (ns);
}
int getscaledfontsize(int size)
{
HDC hdc = GetDC(NULL);
if (size <= 0)
size = fontsize_gui;
size = -MulDiv(size, GetDeviceCaps(hdc, LOGPIXELSY), 72);
ReleaseDC(NULL, hdc);
return size;
}
static void openfont (bool force)
{
HDC hdc;
int size;
if (listviewfont && !force)
return;
if (listviewfont)
DeleteObject (listviewfont);
hdc = GetDC (NULL);
size = -MulDiv (fontsize_list, GetDeviceCaps (hdc, LOGPIXELSY), 72);
listviewfont = CreateFont (size, 0, 0, 0, fontweight_list, (fontstyle_list & ITALIC_FONTTYPE) != 0, 0, 0, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, fontname_list);
HGDIOBJ o = SelectObject(hdc, listviewfont);
memset(&listview_tm, 0, sizeof listview_tm);
listview_tm.tmAveCharWidth = 8;
GetTextMetrics(hdc, &listview_tm);
SelectObject(hdc, o);
ReleaseDC (NULL, hdc);
}
void scalaresource_listview_font_info(int *w)
{
*w = listview_tm.tmAveCharWidth;
}
void scaleresource_setfont (HWND hDlg)
{
if (listviewcnt) {
if (!listviewfont) {
openfont (false);
if (!listviewfont)
return;
}
for (int i = 0; i < listviewcnt; i++) {
SendMessage (GetDlgItem (hDlg, listviews_id[i]), WM_SETFONT, WPARAM(listviewfont), FALSE);
}
}
if (os_vista) {
for (int i = 0; i < setparamcnt; i++) {
int v = SendMessage (GetDlgItem (hDlg, setparam_id[i]), CB_GETITEMHEIGHT , -1, NULL);
if (v > 0 && mmy(v) > v)
SendMessage (GetDlgItem (hDlg, setparam_id[i]), CB_SETITEMHEIGHT , -1, mmy(v));
}
}
}
static void setdeffont (void)
{
_tcscpy (fontname_gui, font_vista_ok ? wfont_vista : wfont_xp);
fontsize_gui = DEFAULT_FONTSIZE;
fontstyle_gui = 0;
fontweight_gui = FW_REGULAR;
_tcscpy (fontname_list, font_vista_ok ? wfont_vista : wfont_xp);
fontsize_list = DEFAULT_FONTSIZE;
fontstyle_list = 0;
fontweight_list = FW_REGULAR;
}
static TCHAR *fontreg[2] = { _T("GUIFont"), _T("GUIListFont") };
static void regsetfont (UAEREG *reg, const TCHAR *prefix, const TCHAR *name, const TCHAR *fontname, int fontsize, int fontstyle, int fontweight)
{
TCHAR tmp[256], tmp2[256];
_stprintf (tmp, _T("%s:%d:%d:%d"), fontname, fontsize, fontstyle, fontweight);
_stprintf (tmp2, _T("%s%s"), name, prefix);
regsetstr (reg, tmp2, tmp);
}
static void regqueryfont (UAEREG *reg, const TCHAR *prefix, const TCHAR *name, TCHAR *fontname, int *pfontsize, int *pfontstyle, int *pfontweight)
{
TCHAR tmp2[256], tmp[256], *p1, *p2, *p3, *p4;
int size;
int fontsize, fontstyle, fontweight;
_tcscpy (tmp2, name);
_tcscat (tmp2, prefix);
size = sizeof tmp / sizeof (TCHAR);
if (!regquerystr (reg, tmp2, tmp, &size))
return;
p1 = _tcschr (tmp, ':');
if (!p1)
return;
*p1++ = 0;
p2 = _tcschr (p1, ':');
if (!p2)
return;
*p2++ = 0;
p3 = _tcschr (p2, ':');
if (!p3)
return;
*p3++ = 0;
p4 = _tcschr (p3, ':');
if (p4)
*p4 = 0;
_tcscpy (fontname, tmp);
fontsize = _tstoi (p1);
fontstyle = _tstoi (p2);
fontweight = _tstoi (p3);
if (fontsize == 0)
fontsize = 8;
if (fontsize < 5)
fontsize = 5;
if (fontsize > 20)
fontsize = 20;
*pfontsize = fontsize;
*pfontstyle = fontstyle;
*pfontweight = fontweight;
}
void scaleresource_setdefaults (void)
{
setdeffont ();
for (int i = 0; i < MAX_GUI_FONTS; i++) {
TCHAR tmp[256];
_stprintf (tmp, _T("%s%s"), fontreg[i], fontprefix);
regdelete (NULL, tmp);
}
openfont (true);
}
static INT_PTR CALLBACK TestProc (HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
if (msg == WM_INITDIALOG) {
RECT r;
// there really is no better way?
r.left = 0;
r.top = 0;
r.bottom = BASEMULT;
r.right = BASEMULT;
MapDialogRect (hDlg, &r);
baseunitx = r.right * 4 / BASEMULT;
baseunity = r.bottom * 8 / BASEMULT;
GetWindowRect (hDlg, &baserect);
GetClientRect (hDlg, &baseclientrect);
}
return 0;
}
// horrible or what?
static void getbaseunits (int fullscreen)
{
multx = multy = 100;
struct newresource *nr, *nr2;
HWND hwnd;
nr = getresource (IDD_PANEL);
if (!nr) {
write_log (_T("getbaseunits fail!\n"));
abort();
}
nr2 = scaleresource2(nr, NULL, -1, 0, 0, false);
hwnd = CreateDialogIndirect (nr2->inst, nr2->resource, NULL, TestProc);
if (hwnd) {
DestroyWindow (hwnd);
} else {
baserect.left = baserect.top = 0;
baserect.right = 800;
baserect.bottom = 600;
baseclientrect.left = baseclientrect.top = 0;
baseclientrect.right = 800;
baseclientrect.bottom = 600;
}
freescaleresource (nr2);
freescaleresource (nr);
basewidth = baserect.right - baserect.left;
baseheight = baserect.bottom - baserect.top;
baseclientwidth = baseclientrect.right - baseclientrect.left;
baseclientheight = baseclientrect.bottom - baseclientrect.top;
baseborderwidth = basewidth - baseclientwidth;
baseborderheight = baseheight - baseclientheight;
write_log (_T("GUIBase %dx%d (%dx%d)\n"), basewidth, baseheight, baseunitx, baseunity);
}
void scaleresource_init (const TCHAR *prefix, int fullscreen)
{
if (os_vista)
font_vista_ok = 1;
fontprefix = prefix;
setdeffont ();
regqueryfont (NULL, fontprefix, fontreg[0], fontname_gui, &fontsize_gui, &fontstyle_gui, &fontweight_gui);
regqueryfont (NULL, fontprefix, fontreg[1], fontname_list, &fontsize_list, &fontstyle_list, &fontweight_list);
//write_log (_T("GUI font %s:%d:%d:%d\n"), fontname_gui, fontsize_gui, fontstyle_gui, fontweight_gui);
//write_log (_T("List font %s:%d:%d:%d\n"), fontname_list, fontsize_list, fontstyle_list, fontweight_list);
getbaseunits (fullscreen);
openfont (true);
}
#if 0
static void sizefont (HWND hDlg, const TCHAR *name, int size, int style, int weight, int *width, int *height)
{
/* ARGH!!! */
HDC hdc = GetDC (hDlg);
size = -MulDiv (size, lpy, 72);
HFONT font = CreateFont (size, 0, 0, 0, weight,
(style & ITALIC_FONTTYPE) != 0, 0, 0, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, name);
if (!font) {
*width = 8;
*height = 8;
} else {
HFONT hFontOld = (HFONT)SelectObject (hdc, font);
TEXTMETRIC tm;
SIZE fsize;
GetTextMetrics (hdc, &tm);
GetTextExtentPoint32 (hdc, _T("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"), 52, &fsize);
*width = (fsize.cx / 26 + 1) / 2;
*height = tm.tmHeight;
SelectObject (hdc, hFontOld);
DeleteObject (font);
}
ReleaseDC (hDlg, hdc);
}
#endif
typedef enum MONITOR_DPI_TYPE {
MDT_EFFECTIVE_DPI = 0,
MDT_ANGULAR_DPI = 1,
MDT_RAW_DPI = 2,
MDT_DEFAULT = MDT_EFFECTIVE_DPI
} MONITOR_DPI_TYPE;
typedef HRESULT(CALLBACK* GETDPIFORMONITOR)(HMONITOR, MONITOR_DPI_TYPE, UINT*, UINT*);
void scaleresource_getdpimult (double *dpixmp, double *dpiymp, int *dpixp, int *dpiyp)
{
GETDPIFORMONITOR pGetDpiForMonitor;
POINT pt = { 32000, 32000 };
HMONITOR mon = MonitorFromPoint(pt, MONITOR_DEFAULTTOPRIMARY);
*dpixmp = 1.0;
*dpiymp = 1.0;
*dpixp = 0;
*dpiyp = 0;
pGetDpiForMonitor = (GETDPIFORMONITOR)GetProcAddress(GetModuleHandle(_T("Shcore.dll")), "GetDpiForMonitor");
if (pGetDpiForMonitor) {
UINT dpix, dpiy;
if (SUCCEEDED(pGetDpiForMonitor(mon, MDT_EFFECTIVE_DPI, &dpix, &dpiy))) {
if (dpix > 96)
*dpixmp = (double)dpix / 96.0;
if (dpiy > 96)
*dpiymp = (double)dpiy / 96.0;
*dpixp = dpix;
*dpiyp = dpiy;
}
}
}
void scaleresource_setmult (HWND hDlg, int w, int h, int fullscreen)
{
if (w < 0) {
multx = -w;
multy = -h;
return;
}
scaleresource_width = w;
scaleresource_height = h;
multx = w * 100.0 / basewidth;
multy = h * 100.0 / baseheight;
if (multx < 50)
multx = 50;
if (multy < 50)
multy = 50;
//write_log (_T("MX=%f MY=%f\n"), multx, multy);
}
void scaleresource_getmult (int *mx, int *my)
{
if (mx)
*mx = (int)(multx + 0.5);
if (my)
*my = (int)(multy + 0.5);
}
int scaleresource_choosefont (HWND hDlg, int fonttype)
{
CHOOSEFONT cf = { 0 };
LOGFONT lf = { 0 };
HDC hdc;
TCHAR *fontname[2];
int *fontsize[2], *fontstyle[2], *fontweight[2];
int lm;
fontname[0] = fontname_gui;
fontname[1] = fontname_list;
fontsize[0] = &fontsize_gui;
fontsize[1] = &fontsize_list;
fontstyle[0] = &fontstyle_gui;
fontstyle[1] = &fontstyle_list;
fontweight[0] = &fontweight_gui;
fontweight[1] = &fontweight_list;
cf.lStructSize = sizeof cf;
cf.hwndOwner = hDlg;
cf.Flags = CF_FORCEFONTEXIST | CF_INITTOLOGFONTSTRUCT | CF_NOSCRIPTSEL | CF_SCREENFONTS;
cf.lpLogFont = &lf;
cf.nFontType = REGULAR_FONTTYPE;
cf.iPointSize = *fontsize[fonttype];
hdc = GetDC (NULL);
lm = GetDeviceCaps (hdc, LOGPIXELSY);
_tcscpy (lf.lfFaceName, fontname[fonttype]);
lf.lfHeight = -MulDiv (*fontsize[fonttype], lm, 72);
lf.lfWeight = *fontweight[fonttype];
lf.lfItalic = (*fontstyle[fonttype] & ITALIC_FONTTYPE) != 0;
if (!ChooseFont (&cf)) {
ReleaseDC (NULL, hdc);
return 0;
}
_tcscpy (fontname[fonttype], lf.lfFaceName);
*fontsize[fonttype] = lf.lfHeight;
*fontsize[fonttype] = -MulDiv (*fontsize[fonttype], 72, GetDeviceCaps (hdc, LOGPIXELSY));
*fontstyle[fonttype] = lf.lfItalic ? ITALIC_FONTTYPE : 0;
*fontweight[fonttype] = lf.lfWeight;
ReleaseDC (NULL, hdc);
regsetfont (NULL, fontprefix, fontreg[fonttype], fontname[fonttype], *fontsize[fonttype], *fontstyle[fonttype], *fontweight[fonttype]);
openfont (true);
return 1;
}
#include <gdiplus.h>
static bool boxart_inited;
static ULONG_PTR gdiplusToken;
static void boxart_init(void)
{
Gdiplus::GdiplusStartupInput gdiplusStartupInput;
Gdiplus::GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
}
static const TCHAR *boxartnames[] = {
_T("Boxart"),
_T("SShot"),
_T("Title"),
NULL
};
bool show_box_art(const TCHAR *path)
{
TCHAR tmp1[MAX_DPATH];
if (!path || !artcache)
return false;
if (!boxart_inited) {
boxart_init();
boxart_inited = true;
}
write_log(_T("Box art path '%s'\n"), path);
for (int i = 0; boxartnames[i]; i++) {
_tcscpy(tmp1, path);
_tcscat(tmp1, _T("___"));
_tcscat(tmp1, boxartnames[i]);
_tcscat(tmp1, _T(".png"));
Gdiplus::Image *image = Gdiplus::Image::FromFile(tmp1);
// above returns out of memory if file does not exist!
if (image->GetLastStatus() != Gdiplus::Ok) {
_tcscpy(tmp1 + _tcslen(tmp1) - 3, _T("jpg"));
image = Gdiplus::Image::FromFile(tmp1);
}
if (image->GetLastStatus() == Gdiplus::Ok) {
int w = image->GetWidth();
int h = image->GetHeight();
write_log(_T("Image '%s' loaded %d*%d\n"), tmp1, w, h);
}
delete image;
}
return true;
}