text: /* dialog management for wineconsole
   * USER32 backend
   * Copyright (c) 2001, 2002 Eric Pouech
   *
   * This library is free software; you can redistribute it and/or
   * modify it under the terms of the GNU Lesser General Public
   * License as published by the Free Software Foundation; either
   * version 2.1 of the License, or (at your option) any later version.
   *
   * This library is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   * Lesser General Public License for more details.
   *
   * You should have received a copy of the GNU Lesser General Public
   * License along with this library; if not, write to the Free Software
   * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
   */
  
  #include <stdio.h>
  #include <stdlib.h>
  #include <stdarg.h>
  
  #define NONAMELESSUNION
  #define NONAMELESSSTRUCT
  #include "windef.h"
  #include "winbase.h"
  #include "wingdi.h"
  #include "winuser.h"
  #include "winnls.h"
  #include "commctrl.h"
  #include "prsht.h"
  #include "winecon_user.h"
  
  #include "wine/debug.h"
  
  WINE_DEFAULT_DEBUG_CHANNEL(wineconsole);
  
  struct dialog_info
  {
      struct config_data  config;         /* configuration used for dialog box */
      struct inner_data*	data;	        /* pointer to current winecon info */
      HWND		hDlg;		/* handle to active propsheet */
      int			nFont;		/* number of font size in size LB */
      struct font_info
      {
          UINT                    height;
          UINT                    weight;
          WCHAR                   faceName[LF_FACESIZE];
      } 			*font;		/* array of nFont. index sync'ed with SIZE LB */
  };
  
  /******************************************************************
   *		WCUSER_OptionDlgProc
   *
   * Dialog prop for the option property sheet
   */
  static INT_PTR WINAPI WCUSER_OptionDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
  {
      struct dialog_info*		di;
      unsigned 			idc;
  
      switch (msg)
      {
      case WM_INITDIALOG:
  	di = (struct dialog_info*)((PROPSHEETPAGEA*)lParam)->lParam;
  	di->hDlg = hDlg;
  	SetWindowLongPtr(hDlg, DWLP_USER, (LONG_PTR)di);
  
  	SendMessage(GetDlgItem(hDlg,IDC_OPT_HIST_SIZE_UD), UDM_SETRANGE, 0, MAKELPARAM (500, 0));
  
  	if (di->config.cursor_size <= 25)	idc = IDC_OPT_CURSOR_SMALL;
  	else if (di->config.cursor_size <= 50)	idc = IDC_OPT_CURSOR_MEDIUM;
  	else				        idc = IDC_OPT_CURSOR_LARGE;
  	SendDlgItemMessage(hDlg, idc, BM_SETCHECK, BST_CHECKED, 0L);
  	SetDlgItemInt(hDlg, IDC_OPT_HIST_SIZE, di->config.history_size,  FALSE);
          SendDlgItemMessage(hDlg, IDC_OPT_HIST_NODOUBLE, BM_SETCHECK,
                             (di->config.history_nodup) ? BST_CHECKED : BST_UNCHECKED, 0L);
          SendDlgItemMessage(hDlg, IDC_OPT_CONF_CTRL, BM_SETCHECK,
                             (di->config.menu_mask & MK_CONTROL) ? BST_CHECKED : BST_UNCHECKED, 0L);
          SendDlgItemMessage(hDlg, IDC_OPT_CONF_SHIFT, BM_SETCHECK,
                             (di->config.menu_mask & MK_SHIFT) ? BST_CHECKED : BST_UNCHECKED, 0L);
          SendDlgItemMessage(hDlg, IDC_OPT_QUICK_EDIT, BM_SETCHECK,
                             (di->config.quick_edit) ? BST_CHECKED : BST_UNCHECKED, 0L);
  	return FALSE; /* because we set the focus */
      case WM_COMMAND:
  	break;
      case WM_NOTIFY:
      {
  	NMHDR*	nmhdr = (NMHDR*)lParam;
          DWORD   val;
          BOOL	done;
  
  	di = (struct dialog_info*)GetWindowLongPtr(hDlg, DWLP_USER);
  
  	switch (nmhdr->code)
  	{
  	case PSN_SETACTIVE:
  	    /* needed in propsheet to keep properly the selected radio button
  	     * otherwise, the focus would be set to the first tab stop in the
  	     * propsheet, which would always activate the first radio button
  	     */
  	    if (IsDlgButtonChecked(hDlg, IDC_OPT_CURSOR_SMALL) == BST_CHECKED)
  		idc = IDC_OPT_CURSOR_SMALL;
  	    else if (IsDlgButtonChecked(hDlg, IDC_OPT_CURSOR_MEDIUM) == BST_CHECKED)
  		idc = IDC_OPT_CURSOR_MEDIUM;
  	    else
  		idc = IDC_OPT_CURSOR_LARGE;
  	    PostMessage(hDlg, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hDlg, idc), TRUE);
              di->hDlg = hDlg;
  	    break;
  	case PSN_APPLY:
  	    if (IsDlgButtonChecked(hDlg, IDC_OPT_CURSOR_SMALL) == BST_CHECKED) val = 25;
  	    else if (IsDlgButtonChecked(hDlg, IDC_OPT_CURSOR_MEDIUM) == BST_CHECKED) val = 50;
  	    else val = 100;
              di->config.cursor_size = val;
  
   	    val = GetDlgItemInt(hDlg, IDC_OPT_HIST_SIZE, &done, FALSE);
  	    if (done) di->config.history_size = val;
  
              val = (IsDlgButtonChecked(hDlg, IDC_OPT_HIST_NODOUBLE) & BST_CHECKED) ? TRUE : FALSE;
              di->config.history_nodup = val;
  
              val = 0;
              if (IsDlgButtonChecked(hDlg, IDC_OPT_CONF_CTRL) & BST_CHECKED)  val |= MK_CONTROL;
              if (IsDlgButtonChecked(hDlg, IDC_OPT_CONF_SHIFT) & BST_CHECKED) val |= MK_SHIFT;
              di->config.menu_mask = val;
  
              val = (IsDlgButtonChecked(hDlg, IDC_OPT_QUICK_EDIT) & BST_CHECKED) ? TRUE : FALSE;
              di->config.quick_edit = val;
  
              SetWindowLongPtr(hDlg, DWLP_MSGRESULT, PSNRET_NOERROR);
  	    return TRUE;
  	default:
  	    return FALSE;
  	}
  	break;
      }
      default:
  	return FALSE;
      }
      return TRUE;
  }
  
  /******************************************************************
   *		WCUSER_FontPreviewProc
   *
   * Window proc for font previewer in font property sheet
   */
  static LRESULT WINAPI WCUSER_FontPreviewProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
  {
      switch (msg)
      {
      case WM_CREATE:
          SetWindowLongPtr(hWnd, 0, 0);
          break;
      case WM_GETFONT:
          return GetWindowLongPtr(hWnd, 0);
      case WM_SETFONT:
          SetWindowLongPtr(hWnd, 0, wParam);
          if (LOWORD(lParam))
          {
              InvalidateRect(hWnd, NULL, TRUE);
              UpdateWindow(hWnd);
          }
          break;
      case WM_DESTROY:
          {
              HFONT hFont = (HFONT)GetWindowLongPtr(hWnd, 0L);
              if (hFont) DeleteObject(hFont);
          }
          break;
      case WM_PAINT:
          {
              PAINTSTRUCT	        ps;
              int		        font_idx;
              int		        size_idx;
              struct dialog_info*	di;
              HFONT	        hFont, hOldFont;
  
              di = (struct dialog_info*)GetWindowLongPtr(GetParent(hWnd), DWLP_USER);
              BeginPaint(hWnd, &ps);
  
              font_idx = SendDlgItemMessage(di->hDlg, IDC_FNT_LIST_FONT, LB_GETCURSEL, 0L, 0L);
              size_idx = SendDlgItemMessage(di->hDlg, IDC_FNT_LIST_SIZE, LB_GETCURSEL, 0L, 0L);
  
              hFont = (HFONT)GetWindowLongPtr(hWnd, 0L);
              if (hFont)
              {
                  WCHAR	buf1[256];
                  WCHAR	buf2[256];
                  int	len1, len2;
  
                  len1 = LoadString(GetModuleHandle(NULL), IDS_FNT_PREVIEW_1,
                                    buf1, sizeof(buf1) / sizeof(WCHAR));
                  len2 = LoadString(GetModuleHandle(NULL), IDS_FNT_PREVIEW_2,
                                    buf2, sizeof(buf2) / sizeof(WCHAR));
                  buf1[len1] = buf2[len2] = 0;
                  if (len1)
                  {
                      hOldFont = SelectObject(ps.hdc, hFont);
                      SetBkColor(ps.hdc, WCUSER_ColorMap[GetWindowLong(GetDlgItem(di->hDlg, IDC_FNT_COLOR_BK), 0)]);
                      SetTextColor(ps.hdc, WCUSER_ColorMap[GetWindowLong(GetDlgItem(di->hDlg, IDC_FNT_COLOR_FG), 0)]);
                      TextOut(ps.hdc, 0, 0, buf1, len1);
                      if (len2)
                          TextOut(ps.hdc, 0, di->font[size_idx].height, buf2, len2);
                      SelectObject(ps.hdc, hOldFont);
                  }
              }
              EndPaint(hWnd, &ps);
          }
          break;
      default:
  	return DefWindowProc(hWnd, msg, wParam, lParam);
      }
      return 0L;
  }
  
  /******************************************************************
   *		WCUSER_ColorPreviewProc
   *
   * Window proc for color previewer in font property sheet
   */
  static LRESULT WINAPI WCUSER_ColorPreviewProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
  {
      switch (msg)
      {
      case WM_PAINT:
          {
              PAINTSTRUCT     ps;
              int             i, step;
              RECT            client, r;
              HBRUSH          hbr;
  
              BeginPaint(hWnd, &ps);
              GetClientRect(hWnd, &client);
              step = client.right / 8;
  
              for (i = 0; i < 16; i++)
              {
                  r.top = (i / 8) * (client.bottom / 2);
                  r.bottom = r.top + client.bottom / 2;
                  r.left = (i & 7) * step;
                  r.right = r.left + step;
                  hbr = CreateSolidBrush(WCUSER_ColorMap[i]);
                  FillRect(ps.hdc, &r, hbr);
                  DeleteObject(hbr);
                  if (GetWindowLong(hWnd, 0) == i)
                  {
                      HPEN        hOldPen;
                      int         i = 2;
  
                      hOldPen = SelectObject(ps.hdc, GetStockObject(WHITE_PEN));
                      r.right--; r.bottom--;
                      for (;;)
                      {
                          MoveToEx(ps.hdc, r.left, r.bottom, NULL);
                          LineTo(ps.hdc, r.left, r.top);
                          LineTo(ps.hdc, r.right, r.top);
                          SelectObject(ps.hdc, GetStockObject(BLACK_PEN));
                          LineTo(ps.hdc, r.right, r.bottom);
                          LineTo(ps.hdc, r.left, r.bottom);
  
                          if (--i == 0) break;
                          r.left++; r.top++; r.right--; r.bottom--;
                          SelectObject(ps.hdc, GetStockObject(WHITE_PEN));
                      }
                      SelectObject(ps.hdc, hOldPen);
                  }
              }
              EndPaint(hWnd, &ps);
              break;
          }
      case WM_LBUTTONDOWN:
          {
              int             i, step;
              RECT            client;
  
              GetClientRect(hWnd, &client);
              step = client.right / 8;
              i = (HIWORD(lParam) >= client.bottom / 2) ? 8 : 0;
              i += LOWORD(lParam) / step;
              SetWindowLong(hWnd, 0, i);
              InvalidateRect(GetDlgItem(GetParent(hWnd), IDC_FNT_PREVIEW), NULL, FALSE);
              InvalidateRect(hWnd, NULL, FALSE);
          }
          break;
      default:
  	return DefWindowProc(hWnd, msg, wParam, lParam);
      }
      return 0L;
  }
  
  /******************************************************************
   *		font_enum
   *
   * enumerates all the font names with at least one valid font
   */
  static int CALLBACK font_enum_size2(const LOGFONT* lf, const TEXTMETRIC* tm,
  				    DWORD FontType, LPARAM lParam)
  {
      struct dialog_info*	di = (struct dialog_info*)lParam;
  
      WCUSER_DumpTextMetric(tm, FontType);
      if (WCUSER_ValidateFontMetric(di->data, tm, FontType))
      {
  	di->nFont++;
      }
  
      return 1;
  }
  
  static int CALLBACK font_enum(const LOGFONT* lf, const TEXTMETRIC* tm,
  			      DWORD FontType, LPARAM lParam)
  {
      struct dialog_info*	di = (struct dialog_info*)lParam;
  
      WCUSER_DumpLogFont("DlgFamily: ", lf, FontType);
      if (WCUSER_ValidateFont(di->data, lf))
      {
          if (FontType & RASTER_FONTTYPE)
          {
              di->nFont = 0;
              EnumFontFamilies(PRIVATE(di->data)->hMemDC, lf->lfFaceName, font_enum_size2, (LPARAM)di);
          }
          else
              di->nFont = 1;
  
          if (di->nFont)
  	{
   	    SendDlgItemMessage(di->hDlg, IDC_FNT_LIST_FONT, LB_ADDSTRING,
                                 0, (LPARAM)lf->lfFaceName);
          }
      }
  
      return 1;
  }
  
  /******************************************************************
   *		font_enum_size
   *
   *
   */
  static int CALLBACK font_enum_size(const LOGFONT* lf, const TEXTMETRIC* tm,
  				   DWORD FontType, LPARAM lParam)
  {
      struct dialog_info*	di = (struct dialog_info*)lParam;
      WCHAR	        buf[32];
      static const WCHAR  fmt[] = {'%','l','d',0};
  
      WCUSER_DumpTextMetric(tm, FontType);
      if (di->nFont == 0 && !(FontType & RASTER_FONTTYPE))
      {
          static const int sizes[] = {8,9,10,11,12,14,16,18,20,22,24,26,28,36,48,72};
          int i;
  
          di->nFont = sizeof(sizes) / sizeof(sizes[0]);
          di->font = HeapAlloc(GetProcessHeap(), 0, di->nFont * sizeof(di->font[0]));
          for (i = 0; i < di->nFont; i++)
          {
              /* drop sizes where window size wouldn't fit on screen */
              if (sizes[i] * di->data->curcfg.win_height > GetSystemMetrics(SM_CYSCREEN))
              {
                  di->nFont = i;
                  break;
              }
              di->font[i].height = sizes[i];
              di->font[i].weight = 400;
              lstrcpy(di->font[i].faceName, lf->lfFaceName);
              wsprintf(buf, fmt, sizes[i]);
              SendDlgItemMessage(di->hDlg, IDC_FNT_LIST_SIZE, LB_INSERTSTRING, i, (LPARAM)buf);
          }
          /* don't need to enumerate other */
          return 0;
      }
  
      if (WCUSER_ValidateFontMetric(di->data, tm, FontType))
      {
  	int	idx;
  
  	/* we want the string to be sorted with a numeric order, not a lexicographic...
  	 * do the job by hand... get where to insert the new string
  	 */
  	for (idx = 0; idx < di->nFont && tm->tmHeight > di->font[idx].height; idx++);
          while (idx < di->nFont &&
                 tm->tmHeight == di->font[idx].height &&
                 tm->tmWeight > di->font[idx].weight)
              idx++;
          if (idx == di->nFont ||
              tm->tmHeight != di->font[idx].height ||
              tm->tmWeight < di->font[idx].weight)
          {
              /* here we need to add the new entry */
              wsprintf(buf, fmt, tm->tmHeight);
              SendDlgItemMessage(di->hDlg, IDC_FNT_LIST_SIZE, LB_INSERTSTRING, idx, (LPARAM)buf);
  
              /* now grow our arrays and insert the values at the same index than in the list box */
              if (di->nFont)
              {
                  di->font = HeapReAlloc(GetProcessHeap(), 0, di->font, sizeof(*di->font) * (di->nFont + 1));
                  if (idx != di->nFont)
                      memmove(&di->font[idx + 1], &di->font[idx], (di->nFont - idx) * sizeof(*di->font));
              }
              else
                  di->font = HeapAlloc(GetProcessHeap(), 0, sizeof(*di->font));
              di->font[idx].height = tm->tmHeight;
              di->font[idx].weight = tm->tmWeight;
              lstrcpy(di->font[idx].faceName, lf->lfFaceName);
              di->nFont++;
          }
      }
      return 1;
  }
  
  /******************************************************************
   *		select_font
   *
   *
   */
  static BOOL  select_font(struct dialog_info* di)
  {
      int		font_idx, size_idx;
      WCHAR	buf[256];
      WCHAR	fmt[128];
      LOGFONT     lf;
      HFONT       hFont, hOldFont;
      struct config_data config;
  
      font_idx = SendDlgItemMessage(di->hDlg, IDC_FNT_LIST_FONT, LB_GETCURSEL, 0L, 0L);
      size_idx = SendDlgItemMessage(di->hDlg, IDC_FNT_LIST_SIZE, LB_GETCURSEL, 0L, 0L);
  
      if (font_idx < 0 || size_idx < 0 || size_idx >= di->nFont)
  	return FALSE;
  
      WCUSER_FillLogFont(&lf, di->font[size_idx].faceName,
                         di->font[size_idx].height, di->font[size_idx].weight);
      hFont = WCUSER_CopyFont(&config, di->data->hWnd, &lf, NULL);
      if (!hFont) return FALSE;
  
      if (config.cell_height != di->font[size_idx].height)
          WINE_TRACE("mismatched heights (%u<>%u)\n",
                     config.cell_height, di->font[size_idx].height);
      hOldFont = (HFONT)SendDlgItemMessage(di->hDlg, IDC_FNT_PREVIEW, WM_GETFONT, 0L, 0L);
  
      SendDlgItemMessage(di->hDlg, IDC_FNT_PREVIEW, WM_SETFONT, (WPARAM)hFont, TRUE);
      if (hOldFont) DeleteObject(hOldFont);
  
      LoadString(GetModuleHandle(NULL), IDS_FNT_DISPLAY, fmt, sizeof(fmt) / sizeof(WCHAR));
      wsprintf(buf, fmt, config.cell_width, config.cell_height);
  
      SendDlgItemMessage(di->hDlg, IDC_FNT_FONT_INFO, WM_SETTEXT, 0, (LPARAM)buf);
  
      return TRUE;
  }
  
  /******************************************************************
   *		fill_list_size
   *
   * fills the size list box according to selected family in font LB
   */
  static BOOL  fill_list_size(struct dialog_info* di, BOOL doInit)
  {
      int		idx;
      WCHAR	lfFaceName[LF_FACESIZE];
  
      idx = SendDlgItemMessage(di->hDlg, IDC_FNT_LIST_FONT, LB_GETCURSEL, 0L, 0L);
      if (idx < 0) return FALSE;
  
      SendDlgItemMessage(di->hDlg, IDC_FNT_LIST_FONT, LB_GETTEXT, idx, (LPARAM)lfFaceName);
      SendDlgItemMessage(di->hDlg, IDC_FNT_LIST_SIZE, LB_RESETCONTENT, 0L, 0L);
      HeapFree(GetProcessHeap(), 0, di->font);
      di->nFont = 0;
      di->font = NULL;
  
      EnumFontFamilies(PRIVATE(di->data)->hMemDC, lfFaceName, font_enum_size, (LPARAM)di);
  
      if (doInit)
      {
          int     ref = -1;
  
  	for (idx = 0; idx < di->nFont; idx++)
  	{
              if (!lstrcmp(di->font[idx].faceName, di->config.face_name) &&
                  di->font[idx].height == di->config.cell_height &&
                  di->font[idx].weight == di->config.font_weight)
              {
                  if (ref == -1) ref = idx;
                  else WINE_TRACE("Several matches found: ref=%d idx=%d\n", ref, idx);
              }
  	}
  	idx = (ref == -1) ? 0 : ref;
      }
      else
  	idx = 0;
      SendDlgItemMessage(di->hDlg, IDC_FNT_LIST_SIZE, LB_SETCURSEL, idx, 0L);
      select_font(di);
      return TRUE;
  }
  
  /******************************************************************
   *		fill_list_font
   *
   * Fills the font LB
   */
  static BOOL fill_list_font(struct dialog_info* di)
  {
      SendDlgItemMessage(di->hDlg, IDC_FNT_LIST_FONT, LB_RESETCONTENT, 0L, 0L);
      EnumFontFamilies(PRIVATE(di->data)->hMemDC, NULL, font_enum, (LPARAM)di);
      if (SendDlgItemMessage(di->hDlg, IDC_FNT_LIST_FONT, LB_SELECTSTRING,
  			   (WPARAM)-1, (LPARAM)di->config.face_name) == LB_ERR)
  	SendDlgItemMessage(di->hDlg, IDC_FNT_LIST_FONT, LB_SETCURSEL, 0L, 0L);
      fill_list_size(di, TRUE);
      return TRUE;
  }
  
  /******************************************************************
   *		WCUSER_FontDlgProc
   *
   * Dialog proc for the Font property sheet
   */
  static INT_PTR WINAPI WCUSER_FontDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
  {
      struct dialog_info*		di;
  
      switch (msg)
      {
      case WM_INITDIALOG:
  	di = (struct dialog_info*)((PROPSHEETPAGEA*)lParam)->lParam;
  	di->hDlg = hDlg;
  	SetWindowLongPtr(hDlg, DWLP_USER, (DWORD_PTR)di);
          /* remove dialog from this control, font will be reset when listboxes are filled */
          SendDlgItemMessage(hDlg, IDC_FNT_PREVIEW, WM_SETFONT, 0L, 0L);
  	fill_list_font(di);
          SetWindowLong(GetDlgItem(hDlg, IDC_FNT_COLOR_BK), 0, (di->config.def_attr >> 4) & 0x0F);
          SetWindowLong(GetDlgItem(hDlg, IDC_FNT_COLOR_FG), 0, di->config.def_attr & 0x0F);
  	break;
      case WM_COMMAND:
  	di = (struct dialog_info*)GetWindowLongPtr(hDlg, DWLP_USER);
  	switch (LOWORD(wParam))
  	{
  	case IDC_FNT_LIST_FONT:
  	    if (HIWORD(wParam) == LBN_SELCHANGE)
  	    {
  		fill_list_size(di, FALSE);
  	    }
  	    break;
  	case IDC_FNT_LIST_SIZE:
  	    if (HIWORD(wParam) == LBN_SELCHANGE)
  	    {
  		select_font(di);
  	    }
  	    break;
  	}
  	break;
      case WM_NOTIFY:
      {
  	NMHDR*	nmhdr = (NMHDR*)lParam;
          DWORD   val;
  
  	di = (struct dialog_info*)GetWindowLongPtr(hDlg, DWLP_USER);
  	switch (nmhdr->code)
  	{
          case PSN_SETACTIVE:
              di->hDlg = hDlg;
              break;
  	case PSN_APPLY:
   	    val = SendDlgItemMessage(hDlg, IDC_FNT_LIST_SIZE, LB_GETCURSEL, 0L, 0L);
  
  	    if (val < di->nFont)
              {
                  LOGFONT lf;
  
                  WCUSER_FillLogFont(&lf, di->font[val].faceName,
                                     di->font[val].height, di->font[val].weight);
                  DeleteObject(WCUSER_CopyFont(&di->config,
                                               di->data->hWnd, &lf, NULL));
              }
  
              val = (GetWindowLong(GetDlgItem(hDlg, IDC_FNT_COLOR_BK), 0) << 4) |
                  GetWindowLong(GetDlgItem(hDlg, IDC_FNT_COLOR_FG), 0);
              di->config.def_attr = val;
  
              SetWindowLongPtr(hDlg, DWLP_MSGRESULT, PSNRET_NOERROR);
  	    return TRUE;
  	default:
  	    return FALSE;
  	}
  	break;
      }
      default:
  	return FALSE;
      }
      return TRUE;
  }
  
  /******************************************************************
   *		WCUSER_ConfigDlgProc
   *
   * Dialog proc for the config property sheet
   */
  static INT_PTR WINAPI WCUSER_ConfigDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
  {
      struct dialog_info*		di;
      int                     nMaxUD = 2000;
  
      switch (msg)
      {
      case WM_INITDIALOG:
          di = (struct dialog_info*)((PROPSHEETPAGEA*)lParam)->lParam;
          di->hDlg = hDlg;
  
          SetWindowLongPtr(hDlg, DWLP_USER, (DWORD_PTR)di);
          SetDlgItemInt(hDlg, IDC_CNF_SB_WIDTH,   di->config.sb_width,   FALSE);
          SetDlgItemInt(hDlg, IDC_CNF_SB_HEIGHT,  di->config.sb_height,  FALSE);
          SetDlgItemInt(hDlg, IDC_CNF_WIN_WIDTH,  di->config.win_width,  FALSE);
          SetDlgItemInt(hDlg, IDC_CNF_WIN_HEIGHT, di->config.win_height, FALSE);
  
          SendMessage(GetDlgItem(hDlg,IDC_CNF_WIN_HEIGHT_UD), UDM_SETRANGE, 0, MAKELPARAM (nMaxUD, 0));
          SendMessage(GetDlgItem(hDlg,IDC_CNF_WIN_WIDTH_UD), UDM_SETRANGE, 0, MAKELPARAM (nMaxUD, 0));
          SendMessage(GetDlgItem(hDlg,IDC_CNF_SB_HEIGHT_UD), UDM_SETRANGE, 0, MAKELPARAM (nMaxUD, 0));
          SendMessage(GetDlgItem(hDlg,IDC_CNF_SB_WIDTH_UD), UDM_SETRANGE, 0, MAKELPARAM (nMaxUD, 0));
  
          SendDlgItemMessage(hDlg, IDC_CNF_CLOSE_EXIT, BM_SETCHECK,
                             (di->config.exit_on_die) ? BST_CHECKED : BST_UNCHECKED, 0L);
          {
              static const WCHAR s1[] = {'W','i','n','3','2',0};
              static const WCHAR s2[] = {'E','m','a','c','s',0};
  
              SendDlgItemMessage(hDlg, IDC_CNF_EDITION_MODE, CB_ADDSTRING,
                                 0, (LPARAM)s1);
              SendDlgItemMessage(hDlg, IDC_CNF_EDITION_MODE, CB_ADDSTRING,
                                 0, (LPARAM)s2);
              SendDlgItemMessage(hDlg, IDC_CNF_EDITION_MODE, CB_SETCURSEL,
                                 di->config.edition_mode, 0);
      	}
  
  	break;
      case WM_COMMAND:
  	di = (struct dialog_info*)GetWindowLongPtr(hDlg, DWLP_USER);
  	switch (LOWORD(wParam))
  	{
  	}
  	break;
      case WM_NOTIFY:
      {
  	NMHDR*	        nmhdr = (NMHDR*)lParam;
          int             win_w, win_h, sb_w, sb_h;
          BOOL            st1, st2;
  
  	di = (struct dialog_info*)GetWindowLongPtr(hDlg, DWLP_USER);
  	switch (nmhdr->code)
  	{
          case PSN_SETACTIVE:
              di->hDlg = hDlg;
              break;
  	case PSN_APPLY:
              sb_w = GetDlgItemInt(hDlg, IDC_CNF_SB_WIDTH,  &st1, FALSE);
              sb_h = GetDlgItemInt(hDlg, IDC_CNF_SB_HEIGHT, &st2, FALSE);
              if (!st1 || ! st2)
              {
                  SetWindowLongPtr(hDlg, DWLP_MSGRESULT, PSNRET_INVALID);        
                  return TRUE;
              }
              win_w = GetDlgItemInt(hDlg, IDC_CNF_WIN_WIDTH,  &st1, FALSE);
              win_h = GetDlgItemInt(hDlg, IDC_CNF_WIN_HEIGHT, &st2, FALSE);
              if (!st1 || !st2)
              {
                  SetWindowLongPtr(hDlg, DWLP_MSGRESULT, PSNRET_INVALID); 
                  return TRUE;
              }
              if (win_w > sb_w || win_h > sb_h)
              {
                  WCHAR   cap[256];
                  WCHAR   txt[256];
  
                  LoadString(GetModuleHandle(NULL), IDS_DLG_TIT_ERROR, 
                             cap, sizeof(cap) / sizeof(WCHAR));
                  LoadString(GetModuleHandle(NULL), IDS_DLG_ERR_SBWINSIZE, 
                             txt, sizeof(txt) / sizeof(WCHAR));
                  
                  MessageBox(hDlg, txt, cap, MB_OK);
                  SetWindowLongPtr(hDlg, DWLP_MSGRESULT, PSNRET_INVALID); 
                  return TRUE;
              }
              di->config.win_width  = win_w;
              di->config.win_height = win_h;
              di->config.sb_width  = sb_w;
              di->config.sb_height = sb_h;
  
              di->config.exit_on_die = IsDlgButtonChecked(hDlg, IDC_CNF_CLOSE_EXIT) ? 1 : 0;
              di->config.edition_mode = SendDlgItemMessage(hDlg, IDC_CNF_EDITION_MODE, CB_GETCURSEL,
                                                           0, 0);
              SetWindowLongPtr(hDlg, DWLP_MSGRESULT, PSNRET_NOERROR);
  	    return TRUE;
  	default:
  	    return FALSE;
  	}
  	break;
      }
      default:
  	return FALSE;
      }
      return TRUE;
  }
  
  /******************************************************************
   *		WCUSER_SaveDlgProc
   *
   *      Dialog Procedure for choosing how to handle modification to the
   * console settings.
   */
  static INT_PTR WINAPI WCUSER_SaveDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
  {
      switch (msg)
      {
      case WM_INITDIALOG:
          SendDlgItemMessage(hDlg, IDC_SAV_SESSION, BM_SETCHECK, BST_CHECKED, 0);
  	break;
      case WM_COMMAND:
  	switch (LOWORD(wParam))
  	{
          case IDOK:
              EndDialog(hDlg,
                        (IsDlgButtonChecked(hDlg, IDC_SAV_SAVE) == BST_CHECKED) ?
                        IDC_SAV_SAVE : IDC_SAV_SESSION);
              break;
          case IDCANCEL:
              EndDialog(hDlg, IDCANCEL); break;
  	}
          break;
      default:
          return FALSE;
      }
      return TRUE;
  }
  
  /******************************************************************
   *		WCUSER_GetProperties
   *
   * Runs the dialog box to set up the wineconsole options
   */
  BOOL WCUSER_GetProperties(struct inner_data* data, BOOL current)
  {
      HPROPSHEETPAGE	psPage[3];
      PROPSHEETPAGE	psp;
      PROPSHEETHEADER	psHead;
      WCHAR		buff[256];
      WNDCLASS		wndclass;
      static const WCHAR szFntPreview[] = {'W','i','n','e','C','o','n','F','o','n','t','P','r','e','v','i','e','w',0};
      static const WCHAR szColorPreview[] = {'W','i','n','e','C','o','n','C','o','l','o','r','P','r','e','v','i','e','w',0};
      struct dialog_info	di;
      struct config_data  defcfg;
      struct config_data* refcfg;
      BOOL                save, modify_session;
  
      InitCommonControls();
  
      di.data = data;
      if (current)
      {
          refcfg = &data->curcfg;
          save = FALSE;
      }
      else
      {
          WINECON_RegLoad(NULL, refcfg = &defcfg);
          save = TRUE;
      }
      di.config = *refcfg;
      di.nFont = 0;
      di.font = NULL;
  
      modify_session = FALSE;
  
      wndclass.style         = 0;
      wndclass.lpfnWndProc   = WCUSER_FontPreviewProc;
      wndclass.cbClsExtra    = 0;
      wndclass.cbWndExtra    = sizeof (DWORD_PTR); /* for hFont */
      wndclass.hInstance     = GetModuleHandle(NULL);
      wndclass.hIcon         = 0;
      wndclass.hCursor       = LoadCursor(0, IDC_ARROW);
      wndclass.hbrBackground = GetStockObject(BLACK_BRUSH);
      wndclass.lpszMenuName  = NULL;
      wndclass.lpszClassName = szFntPreview;
      RegisterClass(&wndclass);
  
      wndclass.style         = 0;
      wndclass.lpfnWndProc   = WCUSER_ColorPreviewProc;
      wndclass.cbClsExtra    = 0;
      wndclass.cbWndExtra    = sizeof(DWORD);
      wndclass.hInstance     = GetModuleHandle(NULL);
      wndclass.hIcon         = 0;
      wndclass.hCursor       = LoadCursor(0, IDC_ARROW);
      wndclass.hbrBackground = GetStockObject(BLACK_BRUSH);
      wndclass.lpszMenuName  = NULL;
      wndclass.lpszClassName = szColorPreview;
      RegisterClass(&wndclass);
  
      memset(&psp, 0, sizeof(psp));
      psp.dwSize = sizeof(psp);
      psp.dwFlags = 0;
      psp.hInstance = wndclass.hInstance;
      psp.lParam = (LPARAM)&di;
  
      psp.u.pszTemplate = MAKEINTRESOURCE(IDD_OPTION);
      psp.pfnDlgProc = WCUSER_OptionDlgProc;
      psPage[0] = CreatePropertySheetPage(&psp);
  
      psp.u.pszTemplate = MAKEINTRESOURCE(IDD_FONT);
      psp.pfnDlgProc = WCUSER_FontDlgProc;
      psPage[1] = CreatePropertySheetPage(&psp);
  
      psp.u.pszTemplate = MAKEINTRESOURCE(IDD_CONFIG);
      psp.pfnDlgProc = WCUSER_ConfigDlgProc;
      psPage[2] = CreatePropertySheetPage(&psp);
  
      memset(&psHead, 0, sizeof(psHead));
      psHead.dwSize = sizeof(psHead);
  
      if (!LoadString(GetModuleHandle(NULL),
                      (current) ? IDS_DLG_TIT_CURRENT : IDS_DLG_TIT_DEFAULT,
                      buff, sizeof(buff) / sizeof(buff[0])))
      {
          buff[0] = 'S';
          buff[1] = 'e';
          buff[2] = 't';
          buff[3] = 'u';
          buff[4] = 'p';
          buff[5] = '\0';
      }
  
      psHead.pszCaption = buff;
      psHead.nPages = 3;
      psHead.hwndParent = data->hWnd;
      psHead.u3.phpage = psPage;
      psHead.dwFlags = PSH_NOAPPLYNOW;
  
      WINECON_DumpConfig("init", refcfg);
  
      PropertySheet(&psHead);
  
      if (memcmp(refcfg, &di.config, sizeof(*refcfg)) == 0)
          return TRUE;
  
      WINECON_DumpConfig("ref", refcfg);
      WINECON_DumpConfig("cur", &di.config);
      if (refcfg == &data->curcfg)
      {
          switch (DialogBox(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_SAVE_SETTINGS),
                            data->hWnd, WCUSER_SaveDlgProc))
          {
          case IDC_SAV_SAVE:      save = TRUE; modify_session = TRUE; break;
          case IDC_SAV_SESSION:   modify_session = TRUE; break;
          case IDCANCEL:          break;
          default: WINE_ERR("ooch\n");
          }
      }
  
      if (modify_session) WINECON_SetConfig(data, &di.config);
      if (save)           WINECON_RegSave(&di.config);
  
      return TRUE;
  }
  