/* 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)
      {
        if (recs_sz>1)
        {
          // check for duplicate IDs
          WDL_IntKeyedArray<bool> tmp;
          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);

            // 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)
            {
              WDL_ASSERT(!tmp.Get(idx));
              tmp.Insert(idx,true);
            }
          }
        }
      }
  };
  #define SWELL_VALIDATE_DIALOG_RESOURCE(v,r,w,h) static SWELL_DialogRegValidator v(r+1, sizeof(r)/sizeof(r[0])-1,w,h);
#else
  #define SWELL_VALIDATE_DIALOG_RESOURCE(v,r,w,h)
#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) \
                              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) \
                              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
