cd5ebd84d6
C/C++ extension built directly against the vendored Cockos reaper-sdk headers (no Rust/reaper-rs wrapper layer). Loads, registers a test action, and confirms via REAPER's console — confirmed working in REAPER 2026-07-15. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
257 lines
9.7 KiB
C++
257 lines
9.7 KiB
C++
/* Cockos SWELL (Simple/Small Win32 Emulation Layer for Linux/OSX)
|
|
Copyright (C) 2006 and later, Cockos, Inc.
|
|
|
|
This software is provided 'as-is', without any express or implied
|
|
warranty. In no event will the authors be held liable for any damages
|
|
arising from the use of this software.
|
|
|
|
Permission is granted to anyone to use this software for any purpose,
|
|
including commercial applications, and to alter it and redistribute it
|
|
freely, subject to the following restrictions:
|
|
|
|
1. The origin of this software must not be misrepresented; you must not
|
|
claim that you wrote the original software. If you use this software
|
|
in a product, an acknowledgment in the product documentation would be
|
|
appreciated but is not required.
|
|
2. Altered source versions must be plainly marked as such, and must not be
|
|
misrepresented as being the original software.
|
|
3. This notice may not be removed or altered from any source distribution.
|
|
|
|
This file provides functions to dynamically create controls in a view from a win32 resource script.
|
|
|
|
Use swell_resgen.pl or swell_resgen.php on the .rc file, which will produce .rc_mac_dlg, include that.
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#ifndef _SWELL_DLGGEN_H_
|
|
#define _SWELL_DLGGEN_H_
|
|
|
|
#ifdef BEGIN
|
|
#undef BEGIN
|
|
#endif
|
|
|
|
#ifdef END
|
|
#undef END
|
|
#endif
|
|
|
|
|
|
struct SWELL_DlgResourceEntry
|
|
{
|
|
const char *str1;
|
|
int flag1;
|
|
const char *str2;
|
|
|
|
int p1; // often used for ID
|
|
|
|
// todo: see at runtime if some of these can be short instead of int (p2-p6 probably can, but not completely sure) -- i.e. do we use any
|
|
// big values in flags. note: it can't be unsigned short, because we want negative values.
|
|
int p2, p3, p4, p5, p6; // meaning is dependent on class
|
|
};
|
|
|
|
|
|
#define BEGIN {NULL,
|
|
#define END },
|
|
|
|
#define PUSHBUTTON }, { "__SWELL_BUTTON", 0,
|
|
#define DEFPUSHBUTTON }, { "__SWELL_BUTTON", 1,
|
|
#define EDITTEXT }, { "__SWELL_EDIT", 0, "",
|
|
#define CTEXT }, { "__SWELL_LABEL", 0,
|
|
#define LTEXT }, { "__SWELL_LABEL", -1,
|
|
#define RTEXT }, { "__SWELL_LABEL", 1,
|
|
#define CONTROL }, {
|
|
#define COMBOBOX }, { "__SWELL_COMBO", 0, "",
|
|
#define GROUPBOX }, { "__SWELL_GROUP", 0,
|
|
#define CHECKBOX }, { "__SWELL_CHECKBOX", 0,
|
|
#define LISTBOX }, { "__SWELL_LISTBOX", 0, "",
|
|
#define ICON }, { "__SWELL_ICON", 0, (const char*)(INT_PTR)
|
|
|
|
#define NOT
|
|
|
|
// flags we ignore
|
|
#define LVS_SHOWSELALWAYS 0
|
|
#define LVS_SHAREIMAGELISTS 0
|
|
#define ES_AUTOVSCROLL 0
|
|
#define GROUP 0
|
|
#define PBS_SMOOTH 0
|
|
#define CBS_AUTOHSCROLL 0
|
|
#define TBS_NOTICKS 0
|
|
#define TBS_TOP 0
|
|
#define TBS_BOTH 0
|
|
#define LBS_NOINTEGRALHEIGHT 0
|
|
#define TVS_HASLINES 0
|
|
#define TVS_LINESATROOT 0
|
|
#define TVS_SHOWSELALWAYS 0
|
|
#define TVS_HASBUTTONS 0
|
|
#define TVS_TRACKSELECT 0
|
|
#define TVS_NONEVENHEIGHT 0
|
|
#define TVS_NOTOOLTIPS 0
|
|
#define BS_FLAT 0
|
|
#define SS_SUNKEN 0
|
|
#define BS_RIGHT 0
|
|
#define WS_EX_STATICEDGE 0
|
|
#define WS_EX_RIGHT 0
|
|
#define SS_CENTERIMAGE 0
|
|
#define WS_CLIPCHILDREN 0
|
|
|
|
// more ignore flags for vc11+
|
|
#define LVS_ALIGNLEFT 0 /* 0x0800 */
|
|
|
|
#ifndef IDC_STATIC
|
|
#define IDC_STATIC 0
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#define SWELL_DLG_WS_CHILD 1
|
|
#define SWELL_DLG_WS_RESIZABLE 2
|
|
#define SWELL_DLG_WS_FLIPPED 4
|
|
#define SWELL_DLG_WS_NOAUTOSIZE 8
|
|
#define SWELL_DLG_WS_OPAQUE 16
|
|
#define SWELL_DLG_WS_DROPTARGET 32
|
|
#ifdef SWELL_TARGET_OSX
|
|
#define SWELL_DLG_WS_DEFAULT_SCALING 128
|
|
#endif
|
|
|
|
typedef struct SWELL_DialogResourceIndex
|
|
{
|
|
const char *resid;
|
|
const char *title;
|
|
int windowTypeFlags;
|
|
void (*createFunc)(HWND, int);
|
|
int width,height;
|
|
struct SWELL_DialogResourceIndex *_next;
|
|
} SWELL_DialogResourceIndex;
|
|
|
|
typedef struct SWELL_CursorResourceIndex
|
|
{
|
|
const char *resid;
|
|
const char *resname;
|
|
POINT hotspot;
|
|
HCURSOR cachedCursor;
|
|
struct SWELL_CursorResourceIndex *_next;
|
|
} SWELL_CursorResourceIndex;
|
|
|
|
|
|
class SWELL_DialogRegHelper {
|
|
public:
|
|
SWELL_DialogResourceIndex m_rec;
|
|
SWELL_DialogRegHelper(SWELL_DialogResourceIndex **h, void (*cf)(HWND,int), int recid, int flags,
|
|
const char *titlestr, int wid, int hei, double xscale, double yscale)
|
|
{
|
|
if (recid)
|
|
{
|
|
m_rec.resid=MAKEINTRESOURCE(recid);
|
|
m_rec.title=titlestr;
|
|
m_rec.windowTypeFlags=flags;
|
|
m_rec.createFunc=cf;
|
|
m_rec.width=(int)(wid*xscale);
|
|
m_rec.height=(int)(hei*yscale);
|
|
m_rec._next=*h;
|
|
*h = &m_rec;
|
|
}
|
|
}
|
|
};
|
|
|
|
#ifdef _DEBUG
|
|
#include "../assocarray.h"
|
|
class SWELL_DialogRegValidator
|
|
{
|
|
public:
|
|
SWELL_DialogRegValidator(const SWELL_DlgResourceEntry *recs, size_t recs_sz, int dlg_w, int dlg_h, int recid)
|
|
{
|
|
if (recs_sz>1)
|
|
{
|
|
// check for duplicate IDs
|
|
// also check for multiple DEFPUSHBUTTON
|
|
WDL_IntKeyedArray<bool> tmp;
|
|
int defpushcnt = 0;
|
|
for (size_t x = 0; x < recs_sz; x ++)
|
|
{
|
|
const SWELL_DlgResourceEntry *list = recs + x;
|
|
const int idx = strncmp(list->str1,"__SWELL_",8) ? list->flag1 : list->p1;
|
|
int parms[6] = { list->p1, list->p2, list->p3, list->p4, list->p5, list->p6 };
|
|
const int coord_offs = 1; // all, I guess?
|
|
const int xpos = parms[coord_offs], ypos = parms[coord_offs+1];
|
|
WDL_ASSERT(xpos >= -1);
|
|
WDL_ASSERT(ypos >= -1);
|
|
if (list->flag1 && !strcmp(list->str1,"__SWELL_BUTTON"))
|
|
{
|
|
if (defpushcnt) wdl_log("resource %d has duplicate DEFPUSHBUTTON\n",recid);
|
|
WDL_ASSERT(!defpushcnt);
|
|
defpushcnt++;
|
|
}
|
|
|
|
// far-bounds check; for old style pre-scaled coordinates this didn't work right (dlg_w/h were scaled)
|
|
// and there are instances where out of bounds controls do make sense.
|
|
|
|
// const int w = parms[coord_offs+2];
|
|
// const int h = strcmp(list->str1,"__SWELL_COMBO") ? parms[coord_offs+3] : 0;
|
|
// WDL_ASSERT(xpos + w <= dlg_w);
|
|
// WDL_ASSERT(ypos + h <= dlg_h);
|
|
|
|
if (idx != 0 && idx != -1)
|
|
{
|
|
if (tmp.Get(idx)) wdl_log("resource %d has duplicate item ID %d\n",recid, idx);
|
|
WDL_ASSERT(!tmp.Get(idx));
|
|
tmp.Insert(idx,true);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
#define SWELL_VALIDATE_DIALOG_RESOURCE(v,r,w,h,recid) static SWELL_DialogRegValidator v(r+1, sizeof(r)/sizeof(r[0])-1,w,h,recid);
|
|
#else
|
|
#define SWELL_VALIDATE_DIALOG_RESOURCE(v,r,w,h,recid)
|
|
#endif
|
|
|
|
|
|
// per-resource scaling (deprecated), these have a bit more overhead (an extra float) and can't do
|
|
// dynamic scaling on macOS
|
|
#define SWELL_DEFINE_DIALOG_RESOURCE_BEGIN(recid, flags, titlestr, wid, hei, scale) \
|
|
static void SWELL__dlg_cf__##recid(HWND view, int wflags); \
|
|
const float __swell_dlg_scale__##recid = (float) (scale); \
|
|
static SWELL_DialogRegHelper __swell_dlg_helper_##recid(&SWELL_curmodule_dialogresource_head, SWELL__dlg_cf__##recid, recid,(flags) & ~SWELL_DLG_WS_DEFAULT_SCALING,titlestr,wid,hei,scale,(scale)*(SWELL_DLG_SCALE_AUTOGEN_YADJ)); \
|
|
static const SWELL_DlgResourceEntry __swell_dlg_list__##recid[]={
|
|
|
|
|
|
#define SWELL_DEFINE_DIALOG_RESOURCE_END(recid ) }; \
|
|
SWELL_VALIDATE_DIALOG_RESOURCE( __swell_dlg_validator__##recid, __swell_dlg_list__##recid, __swell_dlg_helper_##recid.m_rec.width, __swell_dlg_helper_##recid.m_rec.height, recid) \
|
|
static void SWELL__dlg_cf__##recid(HWND view, int wflags) { \
|
|
SWELL_MakeSetCurParms(__swell_dlg_scale__##recid,__swell_dlg_scale__##recid * (SWELL_DLG_SCALE_AUTOGEN_YADJ),0,0,view,false,!(wflags&SWELL_DLG_WS_NOAUTOSIZE)); \
|
|
SWELL_GenerateDialogFromList(__swell_dlg_list__##recid+1,sizeof(__swell_dlg_list__##recid)/sizeof(__swell_dlg_list__##recid[0])-1); \
|
|
}
|
|
|
|
#ifdef SWELL_TARGET_OSX
|
|
// macOS uses dynamic dialog scaling if not overriden
|
|
#define SWELL_DEF_DLGSCALE2 1.0
|
|
#define SWELL_DEF_DLGFLAG2 SWELL_DLG_WS_DEFAULT_SCALING
|
|
#else
|
|
// -generic uses a fixed dialog scaling if not overridden
|
|
#define SWELL_DEF_DLGSCALE2 1.9
|
|
#define SWELL_DEF_DLGFLAG2 0
|
|
#endif
|
|
|
|
// newer declaration, does not include scale (globally defined default is used)
|
|
#define SWELL_DEFINE_DIALOG_RESOURCE_BEGIN2(recid, flags, titlestr, wid, hei) \
|
|
static void SWELL__dlg_cf__##recid(HWND view, int wflags); \
|
|
static SWELL_DialogRegHelper __swell_dlg_helper_##recid(&SWELL_curmodule_dialogresource_head, SWELL__dlg_cf__##recid, recid,(flags)|SWELL_DEF_DLGFLAG2,titlestr,wid,hei,SWELL_DEF_DLGSCALE2,SWELL_DEF_DLGSCALE2); \
|
|
static const SWELL_DlgResourceEntry __swell_dlg_list__##recid[]={
|
|
|
|
#define SWELL_DEFINE_DIALOG_RESOURCE_END2(recid) }; \
|
|
SWELL_VALIDATE_DIALOG_RESOURCE( __swell_dlg_validator__##recid, __swell_dlg_list__##recid, __swell_dlg_helper_##recid.m_rec.width, __swell_dlg_helper_##recid.m_rec.height, recid) \
|
|
static void SWELL__dlg_cf__##recid(HWND view, int wflags) { \
|
|
SWELL_MakeSetCurParms(0.0 /* use default */,0.0 /* use default */, \
|
|
0,0,view,false,!(wflags&SWELL_DLG_WS_NOAUTOSIZE)); \
|
|
SWELL_GenerateDialogFromList(__swell_dlg_list__##recid+1,sizeof(__swell_dlg_list__##recid)/sizeof(__swell_dlg_list__##recid[0])-1); \
|
|
}
|
|
|
|
#ifndef SWELL_DLG_SCALE_AUTOGEN_YADJ
|
|
#define SWELL_DLG_SCALE_AUTOGEN_YADJ 1.0
|
|
#endif
|
|
|
|
#endif
|