Subversion Repositories filter_foundry

Rev

Rev 454 | Rev 459 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

  1. /*
  2.     This file is part of "Filter Foundry", a filter plugin for Adobe Photoshop
  3.     Copyright (C) 2003-2009 Toby Thain, toby@telegraphics.com.au
  4.     Copyright (C) 2018-2021 Daniel Marschall, ViaThinkSoft
  5.  
  6.     This program is free software; you can redistribute it and/or modify
  7.     it under the terms of the GNU General Public License as published by
  8.     the Free Software Foundation; either version 2 of the License, or
  9.     (at your option) any later version.
  10.  
  11.     This program is distributed in the hope that it will be useful,
  12.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.     GNU General Public License for more details.
  15.  
  16.     You should have received a copy of the GNU General Public License
  17.     along with this program; if not, write to the Free Software
  18.     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  19. */
  20.  
  21. /* Win32 user interface routines */
  22.  
  23. #include "world.h"
  24.  
  25. #include "PIAbout.h"
  26.  
  27. #include <windows.h>
  28. #include <commctrl.h>
  29.  
  30. #include "ff.h"
  31. #include "slider_win.h"
  32. #include "version.h"
  33.  
  34. HWND preview_hwnd;
  35. HCURSOR hCurHandOpen;
  36. HCURSOR hCurHandGrab;
  37.  
  38. HCURSOR hCurHandQuestion;
  39. HICON hIconCautionSign;
  40.  
  41. extern HINSTANCE hDllInstance;
  42.  
  43. void DoAbout(AboutRecordPtr pb){
  44.         char text[1000];
  45.         char title[200];
  46.         PlatformData *p = (PlatformData*)pb->platformData;
  47.  
  48.         if (gdata && gdata->standalone) {
  49.                 sprintf(title, "About %s", gdata->parm.szTitle);
  50.                 sprintf(text,  "%s by %s\n" /* {Title} by {Author} */
  51.                                "%s\n" /* {Copyright} */
  52.                                "\n"
  53.                                "This plugin was built using Filter Foundry " VERSION_STR
  54.                                 #ifdef _WIN64
  55.                                " (64 bit)\n"
  56.                                 #else
  57.                                " (32 bit)\n"
  58.                                 #endif
  59.                                "(C) 2003-2009 Toby Thain, 2018-" RELEASE_YEAR " Daniel Marschall\n"
  60.                                "available from " PROJECT_URL,
  61.                                gdata->parm.szTitle,
  62.                                gdata->parm.szAuthor,
  63.                                gdata->parm.szCopyright);
  64.         } else {
  65.                 sprintf(title, "About Filter Foundry");
  66.                 sprintf(text,  "Filter Foundry " VERSION_STR
  67.                                 #ifdef _WIN64
  68.                                " (64 bit)\n"
  69.                                 #else
  70.                                " (32 bit)\n"
  71.                                 #endif
  72.                                "(C) 2003-2009 Toby Thain, 2018-" RELEASE_YEAR " Daniel Marschall\n"
  73.                                "\n"
  74.                                "Latest version available from\n"
  75.                                PROJECT_URL "\n"
  76.                                "\nPlease contact the author with any bug reports,\n"
  77.                                "suggestions or comments.\n"
  78.                                "If you use this program and like it, please consider\n"
  79.                                "making a donation.");
  80.         }
  81.  
  82.         MessageBoxA((HWND)p->hwnd, text, title, MB_TASKMODAL|MB_ICONINFORMATION|MB_OK);
  83. }
  84.  
  85. Boolean simplealert(TCHAR* s){
  86.         HWND hwnd;
  87.         TCHAR title[256] = { 0 };
  88.         if (gdata && gdata->standalone) {
  89.                 #ifdef UNICODE
  90.                 mbstowcs(&title[0], (const char*)gdata->parm.szTitle, 256);
  91.                 #else
  92.                 strcpy(&title[0], gdata->parm.szTitle);
  93.                 #endif
  94.         }
  95.         else {
  96.                 xstrcpy(&title[0], (TCHAR*)TEXT("Filter Foundry"));
  97.         }
  98.         hwnd = gdata ? gdata->hWndMainDlg : NULL;
  99.         return MessageBox(hwnd, s, title, MB_TASKMODAL|MB_ICONERROR|MB_OK) == IDOK;
  100. }
  101.  
  102. Boolean simplewarning(TCHAR* s) {
  103.         HWND hwnd;
  104.         TCHAR title[256] = { 0 };
  105.         if (gdata && gdata->standalone) {
  106.                 #ifdef UNICODE
  107.                 mbstowcs(&title[0], (const char*)gdata->parm.szTitle, 256);
  108.                 #else
  109.                 strcpy(&title[0], gdata->parm.szTitle);
  110.                 #endif
  111.         } else {
  112.                 xstrcpy(&title[0], (TCHAR*)TEXT("Filter Foundry"));
  113.         }
  114.         hwnd = gdata ? gdata->hWndMainDlg : NULL;
  115.         return MessageBox(hwnd,s,title,MB_TASKMODAL|MB_ICONEXCLAMATION|MB_OK) == IDOK;
  116. }
  117.  
  118. Boolean showmessage(TCHAR *s) {
  119.         HWND hwnd;
  120.         TCHAR title[256] = { 0 };
  121.         if (gdata && gdata->standalone) {
  122.                 #ifdef UNICODE
  123.                 mbstowcs(&title[0], (const char*)gdata->parm.szTitle, 256);
  124.                 #else
  125.                 strcpy(&title[0], gdata->parm.szTitle);
  126.                 #endif
  127.         }
  128.         else {
  129.                 xstrcpy(&title[0], (TCHAR*)TEXT("Filter Foundry"));
  130.         }
  131.         hwnd = gdata ? gdata->hWndMainDlg : NULL;
  132.         return MessageBox(hwnd,s,title,MB_TASKMODAL|MB_ICONINFORMATION|MB_OK) == IDOK;
  133. }
  134.  
  135. INT_PTR CALLBACK maindlgproc(HWND hDlg, UINT wMsg, WPARAM wParam, LPARAM lParam);
  136.  
  137. // Description:
  138. //   Creates a tooltip for an item in a dialog box.
  139. // Parameters:
  140. //   idTool - identifier of an dialog box item.
  141. //   nDlg - window handle of the dialog box.
  142. //   pszText - string to use as the tooltip text.
  143. // Returns:
  144. //   The handle to the tooltip.
  145. //
  146. HWND CreateToolTip(int toolID, HWND hDlg, LPTSTR pszText) {
  147.         // Source: https://docs.microsoft.com/en-us/windows/win32/controls/create-a-tooltip-for-a-control (modified)
  148.  
  149.         HWND hwndTool, hwndTip;
  150.         TOOLINFO toolInfo;
  151.  
  152.         if (!toolID || !hDlg || !pszText) {
  153.                 return FALSE;
  154.         }
  155.         // Get the window of the tool.
  156.         hwndTool = GetDlgItem(hDlg, toolID);
  157.  
  158.         // Create the tooltip. g_hInst is the global instance handle.
  159.         hwndTip = CreateWindowEx(0, TOOLTIPS_CLASS, NULL,
  160.                 WS_POPUP | TTS_ALWAYSTIP /* | TTS_BALLOON*/,
  161.                 CW_USEDEFAULT, CW_USEDEFAULT,
  162.                 CW_USEDEFAULT, CW_USEDEFAULT,
  163.                 hDlg, NULL,
  164.                 hDllInstance, NULL);
  165.  
  166.         if (!hwndTool || !hwndTip) {
  167.                 return (HWND)NULL;
  168.         }
  169.  
  170.         // Associate the tooltip with the tool.
  171.         memset(&toolInfo, 0, sizeof(TOOLINFO)); // toolInfo = { 0 };
  172.         toolInfo.cbSize = sizeof(toolInfo);
  173.         toolInfo.hwnd = hDlg;
  174.         toolInfo.uFlags = TTF_IDISHWND | TTF_SUBCLASS;
  175.         toolInfo.uId = (UINT_PTR)hwndTool;
  176.         toolInfo.lpszText = pszText;
  177.         SendMessage(hwndTip, TTM_ADDTOOL, 0, (LPARAM)&toolInfo);
  178.  
  179.         return hwndTip;
  180. }
  181.  
  182. #define IDT_TIMER_INITPREVIEW_DRAW 1111
  183.  
  184. WNDPROC lpControlEditWndProc[8];
  185.  
  186. LRESULT CALLBACK ControlTextWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
  187.         extern Boolean doupdates;
  188.         int sliderNum;
  189.         for (sliderNum = 0; sliderNum < 8; sliderNum++) {
  190.                 if (hWnd == GetDlgItem(gdata->hWndMainDlg, FIRSTCTLTEXTITEM + sliderNum)) {
  191.                         if ((uMsg == WM_KEYDOWN) && (wParam == VK_UP) && doupdates)
  192.                         {
  193.                                 uint8_t sliderVal = slider[sliderNum] < 255 ? slider[sliderNum] + 1 : slider[sliderNum];
  194.                                 slider[sliderNum] = sliderVal;
  195.  
  196.                                 SETCTLTEXTINT(gdata->hWndMainDlg, FIRSTCTLTEXTITEM + sliderNum, sliderVal, false);
  197.                                 REPAINTCTL(gdata->hWndMainDlg, FIRSTCTLTEXTITEM + sliderNum);
  198.  
  199.                                 recalc_preview(gpb, gdata->hWndMainDlg);
  200.  
  201.                                 return 0;
  202.                         }
  203.                         if ((uMsg == WM_KEYDOWN) && (wParam == VK_DOWN) && doupdates)
  204.                         {
  205.                                 uint8_t sliderVal = slider[sliderNum] > 0 ? slider[sliderNum] - 1 : slider[sliderNum];
  206.                                 slider[sliderNum] = sliderVal;
  207.  
  208.                                 SETCTLTEXTINT(gdata->hWndMainDlg, FIRSTCTLTEXTITEM + sliderNum, sliderVal, false);
  209.                                 REPAINTCTL(gdata->hWndMainDlg, FIRSTCTLTEXTITEM + sliderNum);
  210.  
  211.                                 recalc_preview(gpb, gdata->hWndMainDlg);
  212.  
  213.                                 return 0;
  214.                         }
  215.                         return CallWindowProc(lpControlEditWndProc[sliderNum], hWnd, uMsg, wParam, lParam);
  216.                 }
  217.         }
  218.         return 0; // should not happen
  219. }
  220.  
  221. INT_PTR CALLBACK maindlgproc(HWND hDlg, UINT wMsg, WPARAM wParam, LPARAM lParam){
  222.         static POINT origpos;
  223.         static Point origscroll;
  224.         static Boolean panning = false;
  225.  
  226.         int item,i;
  227.         POINT newpos;
  228.         DRAWITEMSTRUCT *pdi;
  229.         Point newscroll = { 0, 0 };
  230.         HGDIOBJ hfnt;
  231.  
  232.         extern Boolean doupdates;
  233.         extern Handle preview_handle;
  234.  
  235.         if ((gdata->pluginDllSliderMessageId != 0) && (wMsg == gdata->pluginDllSliderMessageId)) {
  236.                 // This is for the PLUGIN.DLL sliders only
  237.                 if (doupdates) {
  238.                         int sliderNum = (int)wParam - FIRSTCTLITEM;
  239.                         int sliderVal = (lParam & 0xFFFF);
  240.                         if (sliderVal < 0) sliderVal = 0;
  241.                         else if (sliderVal > 255) sliderVal = 255;
  242.                         slider[sliderNum] = (uint8_t)sliderVal;
  243.  
  244.                         SETCTLTEXTINT(hDlg, FIRSTCTLTEXTITEM + sliderNum, sliderVal, false);
  245.                         REPAINTCTL(hDlg, FIRSTCTLTEXTITEM + sliderNum);
  246.  
  247.                         recalc_preview(gpb, hDlg);
  248.                 }
  249.                 return true;
  250.         }
  251.  
  252.         switch (wMsg) {
  253.         case WM_TIMER:
  254.                 switch (wParam)
  255.                 {
  256.                 case IDT_TIMER_INITPREVIEW_DRAW:
  257.                         KillTimer(hDlg, IDT_TIMER_INITPREVIEW_DRAW);
  258.                         recalc_preview(gpb, hDlg);
  259.                         return 0;
  260.                 }
  261.                 break;
  262.         case WM_INITDIALOG:
  263.                 gdata->hWndMainDlg = hDlg;
  264.  
  265.                 if(gdata->standalone){
  266.                         SetWindowTextA(hDlg,gdata->parm.szTitle); // window title bar
  267.                 }
  268.                 centre_window(hDlg);
  269.  
  270.                 hfnt = GetStockObject(ANSI_FIXED_FONT);
  271.  
  272.                 hCurHandOpen = LoadCursorA(hDllInstance, "HAND_OPEN");
  273.                 hCurHandGrab = LoadCursorA(hDllInstance, "HAND_GRAB");
  274.                 hCurHandQuestion = LoadCursorA(hDllInstance, "HAND_QUESTION");
  275.  
  276.                 hIconCautionSign = LoadIconA(hDllInstance, "CAUTION_ICO");
  277.  
  278.                 // Note: The whole class "Preview" gets the mouse cursor, not just the single item!
  279.                 preview_hwnd = GetDlgItem(hDlg, PREVIEWITEM);
  280.                 GetClientRect(preview_hwnd, &preview_rect);
  281.                 SetClassLongPtr(preview_hwnd, GCLP_HCURSOR, (LONG_PTR)hCurHandOpen);
  282.  
  283.                 // Note: The whole class "Caution" gets the mouse cursor, not just the single item!
  284.                 SetClassLongPtr(GetDlgItem(hDlg, FIRSTICONITEM), GCLP_HCURSOR, (LONG_PTR)hCurHandQuestion);
  285.  
  286.                 for(i = 0; i < 4; ++i){
  287.                         CreateToolTip(FIRSTICONITEM + i, hDlg, (TCHAR*)TEXT("Error in expression! Click to see details."));
  288.                 }
  289.  
  290.                 CreateToolTip(ZOOMINITEM, hDlg, (TCHAR*)TEXT("Zoom in"));
  291.                 CreateToolTip(ZOOMOUTITEM, hDlg, (TCHAR*)TEXT("Zoom out"));
  292.                 CreateToolTip(ZOOMLEVELITEM, hDlg, (TCHAR*)TEXT("Fully zoom in/out"));
  293.  
  294.                 for(i = 0; i < 8; ++i){
  295.                         if (gdata->pluginDllSliderMessageId == 0) {
  296.                                 // Non PLUGIN.DLL sliders
  297.                                 SetWindowLongPtr(GetDlgItem(hDlg, FIRSTCTLITEM + i), GWL_STYLE, TBS_HORZ | TBS_AUTOTICKS | WS_CHILD | WS_VISIBLE);
  298.                                 SendDlgItemMessage(hDlg, FIRSTCTLITEM + i, TBM_SETRANGE, TRUE, MAKELONG(0, 255));
  299.                                 SendDlgItemMessage(hDlg, FIRSTCTLITEM + i, TBM_SETTICFREQ, SLIDERPAGE, 0);
  300.                                 SendDlgItemMessage(hDlg, FIRSTCTLITEM + i, TBM_SETPAGESIZE, 0, SLIDERPAGE);
  301.                         }
  302.                         else {
  303.                                 // PLUGIN.DLL sliders
  304.                                 SetSliderRange(GetDlgItem(hDlg, FIRSTCTLITEM + i), 0, 255);
  305.                         }
  306.                         SendDlgItemMessage(hDlg,FIRSTCTLTEXTITEM+i,     EM_SETLIMITTEXT,3,0);
  307.                 }
  308.                 for(i = 0; i < 4; ++i){
  309.                         SendDlgItemMessage(hDlg,FIRSTEXPRITEM+i,        EM_SETLIMITTEXT,MAXEXPR-1,0); // we need 1 byte as NUL terminator, so our formula can be max 1023
  310.                         SendDlgItemMessage(hDlg,FIRSTEXPRITEM+i,        WM_SETFONT,(WPARAM)hfnt,false);
  311.                 }
  312.  
  313.                 // Implement "up" and "down" keys for the edit controls
  314.                 // TODO: Better use a spin-edit?
  315.                 for (i = 0; i < 8; ++i) {
  316.                         #ifdef _WIN64
  317.                         lpControlEditWndProc[i] = (WNDPROC)SetWindowLongPtr(GetDlgItem(hDlg, FIRSTCTLTEXTITEM + i), GWLP_WNDPROC, (LONG_PTR)&ControlTextWndProc);
  318.                         #else
  319.                         lpControlEditWndProc[i] = (WNDPROC)SetWindowLongPtr(GetDlgItem(hDlg, FIRSTCTLTEXTITEM + i), GWL_WNDPROC, (LONG_PTR)&ControlTextWndProc);
  320.                         #endif
  321.                 }
  322.  
  323.                 maindlginit(hDlg);
  324.  
  325.                 // Some versions of Windows (NT 3.x) won't show the preview if it is calculated here.
  326.                 // So we need to put it in a timer.
  327.                 // Note that 1 millisecond is enough, even if the window needs longer than 1 millisecond to load.
  328.                 //recalc_preview(gpb, hDlg);
  329.                 SetTimer(hDlg, IDT_TIMER_INITPREVIEW_DRAW, 1, (TIMERPROC)NULL);
  330.  
  331.                 break;
  332.         case WM_DESTROY:
  333.                 gdata->hWndMainDlg = 0;
  334.                 DestroyCursor(hCurHandOpen);
  335.                 DestroyCursor(hCurHandGrab);
  336.                 DestroyCursor(hCurHandQuestion);
  337.                 DestroyIcon(hIconCautionSign);
  338.                 break;
  339.         case WM_DRAWITEM:
  340.                 pdi = (DRAWITEMSTRUCT*)lParam;
  341.                 if(pdi->itemAction == ODA_DRAWENTIRE){
  342.                         switch(pdi->CtlID){
  343.                         case PREVIEWITEM:
  344.                                 drawpreview(hDlg,pdi->hDC,PILOCKHANDLE(preview_handle,false));
  345.                                 PIUNLOCKHANDLE(preview_handle);
  346.                                 break;
  347.                         case FIRSTICONITEM:
  348.                         case FIRSTICONITEM + 1:
  349.                         case FIRSTICONITEM + 2:
  350.                         case FIRSTICONITEM + 3:
  351.                                 DrawIcon(pdi->hDC, 0, 0, hIconCautionSign);
  352.                                 break;
  353.                         default:
  354.                                 return false;
  355.                         }
  356.                 }else
  357.                         return false; // we couldn't handle the message
  358.                 break;
  359.         case WM_COMMAND:
  360.                 item = LOWORD(wParam);
  361.                 switch(HIWORD(wParam)){
  362.                 //case BN_CLICKED:
  363.                 case STN_CLICKED:
  364.                         // BN_CLICKED = Button clicked
  365.                         // STN_CLICKED = Static controls with SS_NOTIFY clicked
  366.                         // Both have the same ordinal number
  367.                         if(item==PREVIEWITEM && GetCursorPos(&origpos)){
  368.                                 panning = true;
  369.                                 origscroll = preview_scroll;
  370.                                 SetCursor(hCurHandGrab);
  371.                                 SetCapture(hDlg);
  372.                                 break;
  373.                         }
  374.                 /* ... falls through ... */
  375.                 case EN_CHANGE:
  376.                         if(doupdates && !maindlgitem(hDlg,item))
  377.                                 EndDialog(hDlg,item);
  378.                 }
  379.                 break;
  380. //      case WM_LBUTTONDOWN: break;
  381.         case WM_MOUSEMOVE:
  382.                 if(panning && GetCursorPos(&newpos)){
  383.                         newscroll.h = (int16)(origscroll.h - zoomfactor*((double)newpos.x - (double)origpos.x));
  384.                         newscroll.v = (int16)(origscroll.v - zoomfactor*((double)newpos.y - (double)origpos.y));
  385.                         if( newscroll.h != preview_scroll.h || newscroll.v != preview_scroll.v ){
  386.                                 preview_scroll = newscroll;
  387.                                 recalc_preview(gpb,hDlg);
  388.                         }
  389.                 }
  390.                 break;
  391.         case WM_LBUTTONUP:
  392.                 ReleaseCapture();
  393.                 panning = false;
  394.                 break;
  395.         case WM_HSCROLL:
  396.                 // Only for non-Plugin.dll-sliders
  397.                 item = GetDlgCtrlID((HWND)lParam);
  398.                 if(doupdates && gdata->pluginDllSliderMessageId == 0 && item>=FIRSTCTLITEM && item<=FIRSTCTLITEM+7)
  399.                         slidermoved(hDlg,item);
  400.                 break;
  401.         default:
  402.                 return false;
  403.         }
  404.  
  405.         return true;
  406. }
  407.  
  408. Boolean maindialog(FilterRecordPtr pb){
  409.         PlatformData *p;
  410.         INT_PTR res;
  411.  
  412.         // First try to use the sliders from PLUGIN.DLL (only Photoshop)
  413.         if (!Slider_Init_PluginDll(TEXT("FoundrySlider"))) {
  414.                 // If we couldn't get the sliders from PLUGIN.DLL (probably not running in Photoshop),
  415.                 // then try the Microsoft Trackbar Control instead
  416.                 if (!Slider_Init_MsTrackbar(TEXT("FoundrySlider"))) {
  417.                         // This will happen if we neither have PLUGIN.DLL, nor the Microsoft Trackbar Control (msctls_trackbar32).
  418.                         // "msctls_trackbar32" is not included in Windows NT 3.1, and since there is no OCX or RegSvr32.
  419.                         // It is included in Windows NT 3.5x.
  420.  
  421.                         //simplealert((TCHAR*)TEXT("This plugin requires Photoshop's PLUGIN.DLL or the Microsoft Trackbar Control (msctls_trackbar32) which was not found on your system."));
  422.                         //return false;
  423.  
  424.                         // We simply hide the sliders and let the user enter the numeric values in the edit-box.
  425.                         simplewarning((TCHAR*)TEXT("Visual sliders are not available because neither PLUGIN.DLL, nor the Microsoft Trackbar Control (msctls_trackbar32) was found on your system."));
  426.                         Slider_Init_None(TEXT("FoundrySlider"));
  427.                 }
  428.         }
  429.  
  430.         // For the preview image and caution symbols, we register subclasses, so that we can assign a mouse cursor to this class.
  431.         MakeSimpleSubclass(TEXT("Preview"), TEXT("STATIC"));
  432.         MakeSimpleSubclass(TEXT("Caution"), TEXT("Button"));
  433.  
  434.         // Now show the dialog
  435.         p = (PlatformData*)pb->platformData;
  436.  
  437.         // Note: "Invalid Cursor Handle" is the error when an unrecognized control class is detected
  438.         res = DialogBoxParam(hDllInstance,MAKEINTRESOURCE(gdata->standalone ? ID_PARAMDLG : ID_MAINDLG),
  439.                              (HWND)p->hwnd,maindlgproc,0);
  440.         if (res == 0) {
  441.                 simplealert((TCHAR*)TEXT("DialogBoxParam in valid parent window handle"));
  442.         }
  443.         if (res == -1) {
  444.                 TCHAR s[0x300];
  445.                 xstrcpy(s, (TCHAR*)TEXT("DialogBoxParam failed: "));
  446.                 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), 0, s + xstrlen(s), 0x300 - (DWORD)xstrlen(s), NULL);
  447.                 dbg(&s[0]);
  448.         }
  449.  
  450.         // Clean up after the dialog has been closed
  451.         UnregisterClass(TEXT("Preview"), hDllInstance);
  452.         UnregisterClass(TEXT("Caution"), hDllInstance);
  453.         UnregisterClass(TEXT("FoundrySlider"), hDllInstance);
  454.         Slider_Uninit_PluginDll();
  455.  
  456.         return res == IDOK;
  457. }
  458.