Subversion Repositories filter_foundry

Rev

Rev 57 | Rev 83 | 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-7 Toby Thain, toby@telegraphics.com.au
  4.  
  5.     This program is free software; you can redistribute it and/or modify
  6.     it under the terms of the GNU General Public License as published by  
  7.     the Free Software Foundation; either version 2 of the License, or
  8.     (at your option) any later version.
  9.  
  10.     This program is distributed in the hope that it will be useful,
  11.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.     GNU General Public License for more details.
  14.  
  15.     You should have received a copy of the GNU General Public License  
  16.     along with this program; if not, write to the Free Software
  17.     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  18. */
  19.  
  20. /* This is PLATFORM INDEPENDENT user interface code - mainly dialog logic */
  21.  
  22. #include "ff.h"
  23.  
  24. #include "node.h"
  25. #include "funcs.h"
  26. #include "y.tab.h"
  27. #include "choosefile.h"
  28. #include "sprintf_tiny.h"
  29.  
  30. #ifdef MAC_ENV
  31.         #include <files.h>
  32.         #include <plstringfuncs.h>
  33.        
  34.         #define GETSLIDERVALUE GetDlgControlValue
  35.         #define SETSLIDERVALUE SetDlgControlValue
  36.         #define GETCTLTEXT getctltext
  37.         #define SETCTLTEXT setctltext
  38.         #define GETCTLTEXTINT getctltextint
  39.         #define SETCTLTEXTINT setctltextint
  40.         #define SELECTCTLTEXT selectctltext
  41. #else
  42.         #include <commctrl.h>
  43.         #include "compat_string.h"
  44.        
  45.         #define GETSLIDERVALUE(d,i) SendDlgItemMessage(d,i,TBM_GETPOS,0,0)
  46.         #define SETSLIDERVALUE(d,i,v) SendDlgItemMessage(d,i,TBM_SETPOS,TRUE,v)
  47.         #define GETCTLTEXT GetDlgItemText
  48.         #define SETCTLTEXT SetDlgItemText
  49.         #define SELECTCTLTEXT SELECTDLGITEMTEXT
  50.         #define GETCTLTEXTINT GetDlgItemInt
  51.         #define SETCTLTEXTINT SetDlgItemInt
  52. #endif
  53.  
  54. Boolean doupdates = true;
  55. double zoomfactor,fitzoom;
  56.  
  57. void updateglobals(DIALOGREF dp);
  58. struct node *updateexpr(DIALOGREF dp,int i);
  59. void updatedialog(DIALOGREF dp);
  60. void slidertextchanged(DIALOGREF dp,int item);
  61. void updatezoom(DIALOGREF dp);
  62.  
  63. void updatedialog(DIALOGREF dp){
  64.         int i;
  65.  
  66.         doupdates = false;
  67.  
  68.         for(i = 0; i < 8; ++i){
  69.                 SETSLIDERVALUE(dp,FIRSTCTLITEM+i,slider[i]);
  70.                 SETCTLTEXTINT(dp,FIRSTCTLTEXTITEM+i,slider[i],false);
  71.         }
  72.  
  73.         for(i = 0; i < 4; ++i){
  74.                 if(!gdata->standalone)
  75.                         SETCTLTEXT(dp,FIRSTEXPRITEM+i,expr[i] ? expr[i] : "");
  76.                 if(i < nplanes)
  77.                         updateexpr(dp,FIRSTEXPRITEM+i);
  78.         }
  79.  
  80.         if(!gdata->standalone)
  81.                 SELECTCTLTEXT(dp,FIRSTEXPRITEM,0,-1);
  82.  
  83.         doupdates = true;
  84. }
  85.  
  86. /* copy dialog settings to global variables (sliders, expressions) */
  87.  
  88. void updateglobals(DIALOGREF dp){
  89.         int i;
  90.         char s[MAXEXPR+1];
  91.  
  92.         for(i = 0; i < 8; ++i)
  93.                 slider[i] = GETSLIDERVALUE(dp,FIRSTCTLITEM+i);
  94.  
  95.         if(!gdata->standalone)
  96.                 for(i = 0; i < 4; ++i){
  97.                         /* stash expression strings */
  98.                         if(GETCTLTEXT(dp,FIRSTEXPRITEM+i,s,MAXEXPR)){
  99.                                 if(expr[i])
  100.                                         free(expr[i]);
  101.                                 if(!(expr[i] = my_strdup(s)))
  102.                                         dbg("updateglobals: my_strdup returned zero??");
  103.                         }else
  104.                                 dbg("updateglobals: GETCTLTEXT returned zero??");
  105.                 }
  106. }
  107.  
  108. struct node *updateexpr(DIALOGREF dp,int item){
  109.         char s[MAXEXPR+1];
  110.         int i;
  111.  
  112. //dbg("updateexpr");
  113.  
  114.         i = item - FIRSTEXPRITEM;
  115.  
  116.         freetree(tree[i]);
  117.  
  118.         if(!gdata->standalone){
  119.                 GETCTLTEXT(dp,item,s,MAXEXPR);
  120.        
  121.                 if(expr[i])
  122.                         free(expr[i]);
  123.                 expr[i] = my_strdup(s);
  124.         }
  125.  
  126.         tree[i] = parseexpr(expr[i]);
  127.        
  128.         if(!gdata->standalone){
  129.                 if(tree[i])
  130.                         HideDialogItem(dp,FIRSTICONITEM+i);
  131.                 else{
  132.                         err[i] = errstr;
  133.                         errstart[i] = tokstart;
  134.                         errpos[i] = tokpos;
  135.                         ShowDialogItem(dp,FIRSTICONITEM+i);
  136.                 }
  137.         }
  138.         return tree[i];
  139. }
  140.  
  141. void updatezoom(DIALOGREF dp){
  142.         char s[10],*q = int_str(s,(int)(100./zoomfactor),10);
  143.         *q++ = '%';
  144.         *q = 0;
  145.         SETCTLTEXT(dp,ZOOMLEVELITEM,s);
  146.         if(zoomfactor > 1.)
  147.                 ShowDialogItem(dp,ZOOMINITEM);
  148.         else
  149.                 HideDialogItem(dp,ZOOMINITEM);
  150.         if(zoomfactor < fitzoom)
  151.                 ShowDialogItem(dp,ZOOMOUTITEM);
  152.         else
  153.                 HideDialogItem(dp,ZOOMOUTITEM);
  154. }
  155.  
  156. /* traverse expression tree, looking for constant references to sliders */
  157.  
  158. int checksl(struct node*p,int ctlflags[],int mapflags[]);
  159. int checksl(struct node*p,int ctlflags[],int mapflags[]){
  160.         int s;
  161.  
  162.         if(p){
  163.                 if( (p->kind==TOK_FN1 && p->v.sym->fn == (pfunc_type)ff_ctl)
  164.                  || (p->kind==TOK_FN3 && p->v.sym->fn == (pfunc_type)ff_val) ){
  165.                         if(p->child[0]->kind == TOK_NUM){
  166.                                 s = p->child[0]->v.value;
  167.                                 if(s>=0 && s<=7)
  168.                                         ctlflags[s] = 1;
  169.                         }else
  170.                                 return true; /* can't determine which ctl() */
  171.                 }else if(p->kind==TOK_FN2 && p->v.sym->fn == (pfunc_type)ff_map){
  172.                         if(p->child[0]->kind == TOK_NUM){
  173.                                 s = p->child[0]->v.value;
  174.                                 if(s>=0 && s<=3){
  175.                                         mapflags[s] = 1;
  176.                                         ctlflags[s*2] = ctlflags[s*2+1] = 1;
  177.                                 }
  178.                         }else
  179.                                 return true; /* can't determine which map() */
  180.                  }
  181.  
  182.                 return checksl(p->child[0],ctlflags,mapflags)
  183.                         || checksl(p->child[1],ctlflags,mapflags)
  184.                         || checksl(p->child[2],ctlflags,mapflags)
  185.                         || checksl(p->child[3],ctlflags,mapflags)
  186.                         || checksl(p->child[4],ctlflags,mapflags);     
  187.         }else return false;
  188. }
  189.  
  190. Boolean checksliders(int exprs,int ctlflags[],int mapflags[]){
  191.         int i,f = false;
  192.  
  193.         for(i = 4; i--;)
  194.                 mapflags[i] = 0;
  195.         for(i = 8; i--;)
  196.                 ctlflags[i] = 0;
  197.  
  198.         for(i = 0; i < exprs; i++)
  199.                 if(checksl(tree[i],ctlflags,mapflags))
  200.                         f = true;
  201.  
  202.         return f;
  203. }
  204.  
  205. void slidermoved(DIALOGREF dp,int i){
  206.         int v = GETSLIDERVALUE(dp,i);
  207.         i -= FIRSTCTLITEM;
  208.         slider[i] = v;
  209.         SETCTLTEXTINT(dp,i+FIRSTCTLTEXTITEM,v,false);
  210. }
  211.  
  212. void slidertextchanged(DIALOGREF dp,int i){
  213.         int v = GETCTLTEXTINT(dp,i,NULL,false);
  214.         i -= FIRSTCTLTEXTITEM;
  215.         SETSLIDERVALUE(dp,i+FIRSTCTLITEM,v);
  216.         slider[i] = v;
  217. }
  218.  
  219. void maindlgupdate(DIALOGREF dp){
  220.         int i,unknown,ctls[8],maps[4];
  221.  
  222.         unknown = checksliders(nplanes,ctls,maps);
  223.  
  224.         for(i = 0; i < 8; i++)
  225.                 if(unknown || ctls[i]){
  226.                         ENABLEDLGITEM(dp,FIRSTCTLITEM+i);
  227.                         ShowDialogItem(dp,FIRSTCTLTEXTITEM+i); /* FIXME: this changes keyboard focus */
  228.                 }else{
  229.                         DISABLEDLGITEM(dp,FIRSTCTLITEM+i);
  230.                         HideDialogItem(dp,FIRSTCTLTEXTITEM+i); /* FIXME: this changes keyboard focus */
  231.                 }
  232.  
  233.         for(i = 0; i < nplanes; i++)
  234.                 if(!tree[i]){
  235.                         /* uh oh, couldn't parse one of the saved expressions...this is fatal */
  236.                         DISABLEDLGITEM(dp,IDOK);
  237.                         if(gdata->standalone){
  238.                                 alertuser("Can't run this filter (there is a problem with the saved expressions).","");
  239.                         }else{
  240.                                 DISABLEDLGITEM(dp,SAVEITEM);
  241.                                 DISABLEDLGITEM(dp,MAKEITEM);
  242.                         }
  243.                         return;
  244.                 }
  245.  
  246.         /* we have valid expression trees in all slots...proceed! */
  247.         updateglobals(dp);
  248.         if(setup(gpb))
  249.                 recalc_preview(gpb,dp);
  250.  
  251.         ENABLEDLGITEM(dp,IDOK);
  252.         if(!gdata->standalone){
  253.                 ENABLEDLGITEM(dp,SAVEITEM);
  254.                 ENABLEDLGITEM(dp,MAKEITEM);
  255.         }
  256. }
  257.  
  258. /* one-time initialisation of dialog box */
  259.  
  260. void maindlginit(DIALOGREF dp){
  261.         char s[0x100];
  262.         int i;
  263.  
  264.         /* hide unused expression items */
  265.         if(gdata->standalone){
  266.                 myp2cstrcpy(s,gdata->parm.author);
  267.                 SetDlgItemText(dp,PARAMAUTHORITEM,s);
  268.                 myp2cstrcpy(s,gdata->parm.copyright);
  269.                 SetDlgItemText(dp,PARAMCOPYITEM,s);
  270.                
  271.                 // update labels for map() or ctl() sliders
  272.                 for(i = 0; i < 8; ++i){
  273.                         if(gdata->parm.ctl_used[i]){
  274.                                 myp2cstrcpy(s,gdata->parm.ctl[i]);
  275.                                 SetDlgItemText(dp,FIRSTCTLLABELITEM+i,s);
  276.                         }else if(gdata->parm.map_used[i/2]){
  277.                                 if(i&1)
  278.                                         HideDialogItem(dp,FIRSTCTLLABELITEM+i);
  279.                                 else{
  280.                                         myp2cstrcpy(s,gdata->parm.map[i/2]);
  281.                                         SetDlgItemText(dp,FIRSTCTLLABELITEM+i,s);
  282.                                 }
  283.                         }else{
  284.                                 HideDialogItem(dp,FIRSTCTLITEM+i);
  285.                                 HideDialogItem(dp,FIRSTCTLTEXTITEM+i);
  286.                                 HideDialogItem(dp,FIRSTCTLLABELITEM+i);
  287.                         }
  288.                 }
  289.         }else
  290.                 for(i = nplanes; i < 4; ++i){
  291.                         HideDialogItem(dp,FIRSTICONITEM+i);
  292.                         HideDialogItem(dp,FIRSTEXPRITEM+i);
  293.                         HideDialogItem(dp,FIRSTLABELITEM+i);
  294.                 }
  295.  
  296.         if(setup_preview(gpb)){
  297.                 extern int preview_w,preview_h;
  298.                 double zh = (gpb->filterRect.right-gpb->filterRect.left)/(double)preview_w,
  299.                        zv = (gpb->filterRect.bottom-gpb->filterRect.top)/(double)preview_h,
  300.                        k;
  301.                 fitzoom = zh > zv ? zh : zv;
  302.                
  303.                 // On very large images, processing a fully zoomed out preview (the initial default)
  304.                 // can cause out of memory errors, because Photoshop can't page in all data
  305.                 // during advanceState. To prevent this problem, zoom in until we aren't
  306.                 // previewing more than say 10% of Photoshop's indicated maxSpace.
  307.                 // (e.g., on a 1GB WinXP system, PS CS2 reports 520MB maxSpace, so this will let us
  308.                 // preview about 50MB of image data.)
  309.                
  310.                 k = maxSpace/(10.*preview_w*preview_h*nplanes);
  311.                 for(zoomfactor = fitzoom; zoomfactor >= 2. && zoomfactor*zoomfactor > k; )
  312.                         zoomfactor /= 2.;
  313.                
  314.                 updatezoom(dp);
  315.         }else{
  316.                 HideDialogItem(dp,ZOOMINITEM);
  317.                 HideDialogItem(dp,ZOOMOUTITEM);
  318.                 HideDialogItem(dp,ZOOMLEVELITEM);
  319.         }
  320.        
  321. #ifdef WIN_ENV
  322.   // can't build standalone filter on less than NT platform :-(
  323.   // due to absence of resource editing API (UpdateResource etc)
  324.   if(!isWin32NT())
  325.     HideDialogItem(dp,MAKEITEM);
  326. #endif
  327.  
  328.         updatedialog(dp);
  329.         maindlgupdate(dp);
  330. }
  331.  
  332.  
  333. /* process an item hit. return false if the dialog is finished; otherwise return true. */
  334.  
  335. Boolean maindlgitem(DIALOGREF dp,int item){
  336.         extern int previewerr;
  337.        
  338.         StandardFileReply sfr;
  339.         NavReplyRecord reply;
  340.         static OSType types[] = {TEXT_FILETYPE,PS_FILTER_FILETYPE};
  341.         char *reason;
  342.         Str255 fname;
  343.  
  344.         switch(item){
  345.         case IDOK:
  346.         case IDCANCEL:
  347.                 dispose_preview();
  348.                 return false; // end dialog
  349.         case OPENITEM:
  350.                 if(!gdata->standalone && choosefiletypes("\pChoose filter settings",&sfr,&reply,types,2,
  351.                                         "All supported files (.afs, .8bf, .txt)\0*.afs;*.8bf;*.txt\0All files (*.*)\0*.*\0\0")){
  352.                         if(loadfile(&sfr,&reason)){
  353.                                 updatedialog(dp);
  354.                                 maindlgupdate(dp);
  355.                         }else
  356.                                 alertuser("Cannot load settings.",reason);
  357.                 }
  358.                 break;
  359.         case SAVEITEM:
  360.                 if(!gdata->standalone && putfile("\pSave filter settings",(StringPtr)"",
  361.                                                                                  TEXT_FILETYPE,SIG_SIMPLETEXT,&reply,&sfr,
  362.                                                                                  "afs","Settings file (.afs, .txt)\0*.afs;*.txt\0\0",1)){
  363.                         if(savefile(&sfr))
  364.                                 completesave(&reply);
  365.                 }
  366.                 break;
  367.         case MAKEITEM:
  368.                 if( !gdata->standalone && builddialog(gpb) ){
  369.                         PLstrcpy(fname,gdata->parm.title);
  370. #ifdef MACMACHO
  371.                         PLstrcat(fname,(StringPtr)"\p.plugin");
  372. #endif
  373.                         if( putfile("\pMake standalone filter",fname,
  374.                                                 PS_FILTER_FILETYPE,kPhotoshopSignature,&reply,&sfr,
  375.                                                 "8bf","Filter plugin file (.8bf)\0*.8bf\0\0",1) )
  376.                                 make_standalone(&sfr);
  377.                 }
  378.                 break;
  379.         case ZOOMINITEM:
  380.                 zoomfactor = zoomfactor > 2. ? zoomfactor/2. : 1.;
  381.                 updatezoom(dp);
  382.                 previewerr = false;
  383.                 recalc_preview(gpb,dp);
  384.                 break;
  385.         case ZOOMOUTITEM:
  386.                 zoomfactor *= 2.;
  387.                 if(zoomfactor > fitzoom)
  388.                         zoomfactor = fitzoom;
  389.                 updatezoom(dp);
  390.                 previewerr = false;
  391.                 recalc_preview(gpb,dp);
  392.                 break;
  393.         case ZOOMLEVELITEM:
  394.                 zoomfactor = zoomfactor > 1. ? 1. : fitzoom;
  395.                 updatezoom(dp);
  396.                 previewerr = false;
  397.                 recalc_preview(gpb,dp);
  398.                 break;
  399.         case FIRSTCTLITEM:
  400.         case FIRSTCTLITEM+1:
  401.         case FIRSTCTLITEM+2:
  402.         case FIRSTCTLITEM+3:
  403.         case FIRSTCTLITEM+4:
  404.         case FIRSTCTLITEM+5:
  405.         case FIRSTCTLITEM+6:
  406.         case FIRSTCTLITEM+7:
  407.                 slidermoved(dp,item);
  408.                 recalc_preview(gpb,dp);
  409.                 break;
  410.         case FIRSTCTLTEXTITEM:
  411.         case FIRSTCTLTEXTITEM+1:
  412.         case FIRSTCTLTEXTITEM+2:
  413.         case FIRSTCTLTEXTITEM+3:
  414.         case FIRSTCTLTEXTITEM+4:
  415.         case FIRSTCTLTEXTITEM+5:
  416.         case FIRSTCTLTEXTITEM+6:
  417.         case FIRSTCTLTEXTITEM+7:
  418.                 slidertextchanged(dp,item);
  419.                 recalc_preview(gpb,dp);
  420.                 break;
  421.         case FIRSTICONITEM:
  422.         case FIRSTICONITEM+1:
  423.         case FIRSTICONITEM+2:
  424.         case FIRSTICONITEM+3:
  425.                 item -= FIRSTICONITEM;
  426.                 alertuser(err[item],"");
  427.                 SELECTCTLTEXT(dp,FIRSTEXPRITEM+item,errstart[item],errpos[item]);
  428.                 break;
  429.         case FIRSTEXPRITEM:
  430.         case FIRSTEXPRITEM+1:
  431.         case FIRSTEXPRITEM+2:
  432.         case FIRSTEXPRITEM+3:
  433.                 if((item-FIRSTEXPRITEM) < nplanes){
  434.                         updateexpr(dp,item);
  435.                         maindlgupdate(dp);
  436.                 }
  437.                 break;
  438.         }
  439.  
  440.         return true; // keep going
  441. }
  442.  
  443. Boolean alertuser(char *err,char *more){
  444.         char *s = malloc(strlen(err)+strlen(more)+2),*q;
  445.         Boolean res;
  446.        
  447.         q = cat(s,err);
  448.         *q++ = '\n';
  449.         q = cat(q,more);
  450.         *q = 0;
  451.         res = simplealert(s);
  452.         free(s);
  453.         return res;
  454. }
  455.