Subversion Repositories filter_foundry

Rev

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