~ubuntu-branches/ubuntu/vivid/fotoxx/vivid

« back to all changes in this revision

Viewing changes to fotoxx_area.cc

  • Committer: Package Import Robot
  • Author(s): Santiago Torres Batan
  • Date: 2011-11-07 16:37:55 UTC
  • mfrom: (1.1.10)
  • Revision ID: package-import@ubuntu.com-20111107163755-2fdevt5hu7tcguhx
Tags: 11.11.1-1
* New upstream release
  
* debian/watch
  -Fix lintian warning: debian_watch_contains_dh_make_template

* debian/rules
  -Remove -XTRANLATIONS -XCHANGES params in dh_compress.
  -Fix lintian warning: debian_rules_missing_recommends_targets
  -Add symlink to avoid duplicate documentation at intalldocs rule.
  -Remove unnecessary files.
 
* debian/control
 -Bump Standars-Version to 3.9.2
 -Remov libfreeimage-dev, libimage-exiftool-perf from
   Build-Depends
 -Add xgd-utils and libimage-exiftool-perf to Recommends
 -Add brasero to Suggests

* debian/copyright
  -Update copyright to 2010, 2011
 
* debian/patches/ 
  -Fix lintian warning format-3.0-but-debian-changes-patch and
   (closes: #643119) by creating:
  -docs_dir.patch: changes upstream sources for the program to
   know where documentation is installed
  -makefile_changes.patch: edit makefile for installation
   Removes the depencies check by dependencies.sh. (closes: #622315)
   Fix FTBFS with binutils-gold. (closes: #610545)
   fotoxxfotoxx.desktop was created by mistake. (closes: #610544)
   Thanks to Mahyuddin Susanto.

* debian/doc-base
  -Register fotoxx user guide documentation.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/**************************************************************************
 
2
 
 
3
   Fotoxx      edit photos and manage collections
 
4
 
 
5
   Copyright 2007 2008 2009 2010 2011  Michael Cornelison
 
6
   Source URL: http://kornelix.squarespace.com/fotoxx
 
7
   Contact: kornelix2@googlemail.com
 
8
   
 
9
   This program is free software: you can redistribute it and/or modify
 
10
   it under the terms of the GNU General Public License as published by
 
11
   the Free Software Foundation, either version 3 of the License, or
 
12
   (at your option) any later version.
 
13
 
 
14
   This program is distributed in the hope that it will be useful,
 
15
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
16
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
17
   GNU General Public License for more details.
 
18
 
 
19
   You should have received a copy of the GNU General Public License
 
20
   along with this program. If not, see http://www.gnu.org/licenses/.
 
21
 
 
22
***************************************************************************/
 
23
 
 
24
#define EX extern          //  enable extern declarations
 
25
#include "fotoxx.h"
 
26
 
 
27
/**************************************************************************
 
28
 
 
29
   Fotoxx image editor - select area functions
 
30
 
 
31
   Select an area within the current image.
 
32
   Subsequent edit functions are carried out within the area.
 
33
   Otherwise, edit functions apply to the entire image.
 
34
   
 
35
   sa_stat  0/1/2/3 = none/edit/pause/complete
 
36
   sa_mode is current area selection method:
 
37
      1  select rectangle by drag or clicks
 
38
      2  select ellipse by drag
 
39
      3  freehand draw by drag
 
40
      4  follow edge indicated by clicks
 
41
      5  select adjacent pixels matching color
 
42
      6  select pixels within mouse radius
 
43
      7  select whole image
 
44
 
 
45
***************************************************************************/
 
46
 
 
47
//  user select area dialog
 
48
//  line drawing and selection by color range are combined                 //  v.9.7
 
49
 
 
50
void m_select(GtkWidget *, cchar *)                                        //  menu function
 
51
{
 
52
   int   select_dialog_event(zdialog *, cchar *event);                     //  dialog event and completion funcs
 
53
 
 
54
   cchar    *title = ZTX("Select Area for Edits");
 
55
   cchar    *helptext = ZTX("Press F1 for help");
 
56
 
 
57
   zfuncs::F1_help_topic = "select_area";
 
58
 
 
59
   if (! curr_file) return;                                                //  no image
 
60
   if (zdsela) return;                                                     //  already active
 
61
   
 
62
   if (CEF && CEF->Farea != 2) {                                           //  active edit function
 
63
      zmessageACK(mWin,ZTX("Select Area not supported \n"                  //  v.11.08
 
64
                           "by this edit function")); 
 
65
      return;
 
66
   }
 
67
   
 
68
   if (Fpreview) edit_fullsize();                                          //  use full-size image
 
69
   
 
70
   if (! Fpxm16) {                                                         //  create Fpxm16 if not already
 
71
      mutex_lock(&Fpixmap_lock);
 
72
      Fpxm16 = f_load(curr_file,16);
 
73
      mutex_unlock(&Fpixmap_lock);
 
74
      if (! Fpxm16) return;
 
75
   }
 
76
 
 
77
/***  v.11.02
 
78
    _________________________________________________________
 
79
   |                Press F1 for help                        |
 
80
   | (o) select rectangle                                    |
 
81
   | (o) select ellipse                                      |
 
82
   | (o) draw: freehand                                      |
 
83
   | (o) draw: follow edge                                   |
 
84
   | (o) select by mouse     radius [__]                     |
 
85
   | (o) select by color     match [__]                      |
 
86
   | [x] my mouse   [x] firewall   Blend Width [__]          |
 
87
   |                                                         |
 
88
   | [Show] [Hide] [Color] [Finish] [Unfinish]               |
 
89
   | [Enable] [Disable] [Invert] [Unselect] [Done]           |
 
90
   |_________________________________________________________|
 
91
   
 
92
***/
 
93
 
 
94
   zdsela = zdialog_new(title,mWin,null);
 
95
   zdialog_add_widget(zdsela,"label","labhelp","dialog",helptext);
 
96
   zdialog_add_widget(zdsela,"hbox","hb1","dialog");
 
97
   zdialog_add_widget(zdsela,"vbox","vb1","hb1",0,"homog");
 
98
   zdialog_add_widget(zdsela,"vbox","vb2","hb1",0,"homog");
 
99
   zdialog_add_widget(zdsela,"radio","rbrect","vb1",ZTX("rectangle"));
 
100
   zdialog_add_widget(zdsela,"radio","rbelips","vb1",ZTX("ellipse"));
 
101
   zdialog_add_widget(zdsela,"radio","rbdraw","vb1",ZTX("draw: freehand"));
 
102
   zdialog_add_widget(zdsela,"radio","rbfollow","vb1",ZTX("draw: follow edge"));
 
103
   zdialog_add_widget(zdsela,"radio","rbmouse","vb1",ZTX("select by mouse"));
 
104
   zdialog_add_widget(zdsela,"radio","rbcolor","vb1",ZTX("select by color"));
 
105
 
 
106
   zdialog_add_widget(zdsela,"label","space1","vb2");
 
107
   zdialog_add_widget(zdsela,"label","space2","vb2");
 
108
   zdialog_add_widget(zdsela,"label","space3","vb2");
 
109
   zdialog_add_widget(zdsela,"label","space4","vb2");
 
110
 
 
111
   zdialog_add_widget(zdsela,"hbox","hbmouserad","vb2");
 
112
   zdialog_add_widget(zdsela,"label","labmouserad","hbmouserad",ZTX("radius"),"space=5");
 
113
   zdialog_add_widget(zdsela,"spin","mouseradius","hbmouserad","1|300|1|20");
 
114
 
 
115
   zdialog_add_widget(zdsela,"hbox","hbcolor","vb2");
 
116
   zdialog_add_widget(zdsela,"label","labmatch","hbcolor",ZTX("match"),"space=5");
 
117
   zdialog_add_widget(zdsela,"spin","colormatch","hbcolor","0|100|1|90");
 
118
 
 
119
   zdialog_add_widget(zdsela,"hbox","hbb1","dialog",0,"space=5");
 
120
   zdialog_add_widget(zdsela,"check","mymouse","hbb1",BmyMouse,"space=5");
 
121
   zdialog_add_widget(zdsela,"check","firewall","hbb1",ZTX("firewall"),"space=5");
 
122
   zdialog_add_widget(zdsela,"label","labblend","hbb1",Bblendwidth,"space=5");
 
123
   zdialog_add_widget(zdsela,"spin","blendwidth","hbb1","0|500|1|0");
 
124
 
 
125
   zdialog_add_widget(zdsela,"hbox","hbb2","dialog",0,"space=5");
 
126
   zdialog_add_widget(zdsela,"button","show","hbb2",Bshow);
 
127
   zdialog_add_widget(zdsela,"button","hide","hbb2",Bhide);
 
128
   zdialog_add_widget(zdsela,"button","color","hbb2",Bcolor);
 
129
   zdialog_add_widget(zdsela,"button","finish","hbb2",Bfinish);
 
130
   zdialog_add_widget(zdsela,"button","unfinish","hbb2",Bunfinish);
 
131
 
 
132
   zdialog_add_widget(zdsela,"hbox","hbb3","dialog",0,"space=3");
 
133
   zdialog_add_widget(zdsela,"button","enable","hbb3",Benable);
 
134
   zdialog_add_widget(zdsela,"button","disable","hbb3",Bdisable);
 
135
   zdialog_add_widget(zdsela,"button","invert","hbb3",Binvert);
 
136
   zdialog_add_widget(zdsela,"button","unselect","hbb3",Bunselect);
 
137
   zdialog_add_widget(zdsela,"button","done","hbb3",Bdone);
 
138
 
 
139
   zdialog_help(zdsela,"select_area");                                     //  v.11.08
 
140
   zdialog_run(zdsela,select_dialog_event,"save");                         //  run dialog - parallel     v.11.07
 
141
 
 
142
   sa_mouseradius = 20;                                                    //  initial values matching dialog
 
143
   sa_colormatch = 90;
 
144
   sa_blend = 0;
 
145
   sa_firewall = 0;
 
146
   sa_mode = 3;                                                            //  default mode = freehand draw
 
147
   zdialog_stuff(zdsela,"rbdraw",1);
 
148
   sa_show(1);                                                             //  show existing area, if any
 
149
 
 
150
   return;
 
151
}
 
152
 
 
153
 
 
154
//  dialog event and completion callback function
 
155
 
 
156
int select_dialog_event(zdialog *zd, cchar *event)
 
157
{
 
158
   int         ii, cc, mymouse;
 
159
   
 
160
   if (strEqu(event,"done") || zd->zstat)                                  //  done or cancel
 
161
   {
 
162
      freeMouse();                                                         //  disconnect mouse function    v.10.12
 
163
      zdialog_free(zdsela);                                                //  kill dialog
 
164
      return 0;
 
165
   }
 
166
   
 
167
   if (CEF && CEF->Farea != 2) {                                           //  select area not supported    v.11.08
 
168
      printf("select area ignored \n");
 
169
      return 0;
 
170
   }
 
171
   
 
172
   if (sa_fww != Fww || sa_fhh != Fhh)                                     //  delete area not valid for image
 
173
      sa_unselect();                                                       //  bugfix     v.11.08
 
174
   
 
175
   if (! sa_stat) {                                                        //  no area, create one          v.11.07
 
176
      cc = Fww * Fhh * sizeof(uint16);                                     //  allocate sa_pixmap[] for new area
 
177
      sa_pixmap = (uint16 *) zmalloc(cc,"sa_select");                      //  maps pixels in area
 
178
      memset(sa_pixmap,0,cc);
 
179
      sa_currseq = sa_Ncurrseq = 0;                                        //  reset selection sequence
 
180
      sa_Npixel = sa_blend = sa_calced = Factivearea = 0;
 
181
      sa_fww = Fww;                                                        //  valid image size for area    v.11.08
 
182
      sa_fhh = Fhh;
 
183
      sa_stat = 1;                                                         //  status = edit
 
184
   }
 
185
 
 
186
   ii = strcmpv(event,"rbrect","rbelips","rbdraw","rbfollow","rbcolor","rbmouse",null);
 
187
   if (ii) {
 
188
      sa_mode = ii;                                                        //  radio button 1-6
 
189
      sa_stat = 1;                                                         //  resume edit
 
190
      sa_Npixel = sa_blend = sa_calced = Factivearea = 0;
 
191
      zdialog_stuff(zd,"blendwidth",0);                                    //  reset blend width      v.11.01
 
192
      sa_show(1);                                                          //  show area              v.11.04
 
193
   }
 
194
 
 
195
   if (strEqu(event,"mouseradius"))                                        //  mouse selection radius
 
196
      zdialog_fetch(zd,"mouseradius",sa_mouseradius);
 
197
 
 
198
   if (strEqu(event,"colormatch"))                                         //  color match range, 0 to 99.9
 
199
      zdialog_fetch(zdsela,"colormatch",sa_colormatch);
 
200
   
 
201
   if (strEqu(event,"firewall"))                                           //  color select firewall on/off   v.10.11
 
202
      zdialog_fetch(zdsela,"firewall",sa_firewall);
 
203
 
 
204
   if (strEqu(event,"mymouse")) {                                          //  toggle mouse capture      v.10.12
 
205
      zdialog_fetch(zd,"mymouse",mymouse);
 
206
      if (mymouse) {
 
207
         sa_stat = 1;                                                      //  resume edit
 
208
         sa_Npixel = sa_blend = sa_calced = Factivearea = 0;
 
209
         zdialog_stuff(zd,"blendwidth",0);                                 //  reset blend width    v.11.01
 
210
         sa_show(1);
 
211
      }
 
212
      else sa_stat = 2;                                                    //  pause edit
 
213
   }
 
214
 
 
215
   if (strEqu(event,"show")) sa_show(1);                                   //  show area
 
216
 
 
217
   if (strEqu(event,"hide")) sa_show(0);                                   //  hide area
 
218
 
 
219
   if (strEqu(event,"color")) {                                            //  switch colors
 
220
      if (sa_pixRGB == &red) sa_pixRGB = &green;
 
221
      else if (sa_pixRGB == &green) sa_pixRGB = &black;
 
222
      else sa_pixRGB = &red;
 
223
      sa_show(1);
 
224
   }
 
225
 
 
226
   if (strstr("finish unselect able invert blend",event)) {                //  dialog buttons
 
227
      freeMouse();                                                         //  disconnect mouse             v.11.04
 
228
      gdk_window_set_cursor(drWin->window,null);                           //  normal cursor                v.11.03
 
229
   }
 
230
 
 
231
   if (strEqu(event,"finish")) sa_finish();                                //  finish (finalize) area
 
232
   if (strEqu(event,"unfinish")) sa_unfinish();                            //  unfinish area                v.11.07
 
233
   if (strEqu(event,"unselect")) sa_unselect();                            //  unselect area
 
234
   if (strEqu(event,"enable")) sa_enable();                                //  enable area
 
235
   if (strEqu(event,"disable")) sa_disable();                              //  disable area
 
236
   if (strEqu(event,"invert")) sa_invert();                                //  invert area
 
237
   
 
238
   if (strEqu(event,"blendwidth") && Factivearea) {                        //  blend width changed
 
239
      sa_edgecalc();                                                       //  do edge calc. if not already
 
240
      if (sa_calced && CEF && CEF->zd) {                                   //  edit is active
 
241
         zdialog_fetch(zd,"blendwidth",sa_blend);                          //  update sa_blend
 
242
         zdialog_send_event(CEF->zd,event);                                //  notify edit dialog
 
243
      }
 
244
   }                                                                       //  "ignore once" logic removed  v.11.01
 
245
 
 
246
   if (sa_stat == 1)                                                       //  active edit mode
 
247
   {
 
248
      if (sa_mode == 1) takeMouse(zd,sa_geom_mousefunc,dragcursor);        //  rectangle                    v.11.03
 
249
      if (sa_mode == 2) takeMouse(zd,sa_geom_mousefunc,dragcursor);        //  ellipse
 
250
      if (sa_mode == 3) takeMouse(zd,sa_draw_mousefunc,drawcursor);        //  freehand draw
 
251
      if (sa_mode == 4) takeMouse(zd,sa_draw_mousefunc,drawcursor);        //  follow edge
 
252
      if (sa_mode == 5) takeMouse(zd,sa_color_mousefunc,0);                //  color match
 
253
      if (sa_mode == 6) takeMouse(zd,sa_radius_mousefunc,0);               //  mouse radius
 
254
      if (sa_mode < 3) sa_geom1 = sa_geom2 = 0;                            //  new rectangle or ellipse
 
255
      if (sa_mode < 5) paint_toparc(2);                                    //  erase radius circle
 
256
   }
 
257
   else                                                                    //  edit paused
 
258
      freeMouse();                                                         //  disconnect mouse             v.10.12
 
259
 
 
260
   return 0;
 
261
}
 
262
 
 
263
 
 
264
//  select area mouse function - select a rectangle or ellipse
 
265
 
 
266
void sa_geom_mousefunc()                                                   //  new v.11.03
 
267
{
 
268
   static int  mx1, my1, mx2, my2;
 
269
   static int  mdx0, mdy0;
 
270
   
 
271
   if (sa_stat != 1) return;                                               //  area gone?    v.11.07
 
272
 
 
273
   if (sa_currseq > sa_maxseq-2) {
 
274
      zmessageACK(mWin,ZTX("exceed %d edits"),sa_maxseq);                  //  cannot continue
 
275
      return;
 
276
   }
 
277
 
 
278
   if (RMclick)                                                            //  right mouse click
 
279
   {
 
280
      RMclick = 0;
 
281
      sa_unselect_pixels();                                                //  remove latest selection
 
282
      sa_geom1 = sa_geom2 = 0;
 
283
      mwpaint2();
 
284
      return;
 
285
   }
 
286
   
 
287
   if (! Mxdrag && ! Mydrag) return;                                       //  v.11.04
 
288
   
 
289
   if (Mxdown != mdx0 || Mydown != mdy0) {                                 //  new drag initiated
 
290
      mdx0 = Mxdown;
 
291
      mdy0 = Mydown;
 
292
      mx1 = mdx0;                                                          //  drag start, one corner
 
293
      my1 = mdy0;
 
294
      sa_geom1 = 1;
 
295
      sa_geom2 = 0;
 
296
      return;
 
297
   }
 
298
 
 
299
   if (sa_geom2) sa_unselect_pixels();                                     //  remove prior selection
 
300
   mx2 = Mxdrag;                                                           //  drag continues, 2nd corner
 
301
   my2 = Mydrag;
 
302
   sa_geom2 = 1;
 
303
   
 
304
   sa_nextseq();                                                           //  next sequence number
 
305
   
 
306
   if (sa_mode == 1)                                                       //  draw rectangle
 
307
   {
 
308
      sa_draw_line(mx1,my1,mx2,my1);
 
309
      sa_draw_line(mx2,my1,mx2,my2);
 
310
      sa_draw_line(mx2,my2,mx1,my2);
 
311
      sa_draw_line(mx1,my2,mx1,my1);
 
312
   }
 
313
   
 
314
   if (sa_mode == 2)                                                       //  draw ellipse
 
315
   {
 
316
      double   a, b, a2, b2;
 
317
      double   x, y, x2, y2, cx, cy;   
 
318
      int      px, py;
 
319
 
 
320
      a = abs(mx2 - mx1);                                                  //  ellipse constants from    v.11.04
 
321
      b = abs(my2 - my1);                                                  //    enclosing rectangle
 
322
      a2 = a * a;
 
323
      b2 = b * b;
 
324
      cx = mx1;                                                            //  center at drag origin     v.11.04
 
325
      cy = my1;
 
326
      
 
327
      for (y = -b; y < b; y++)                                             //  step through y values
 
328
      {
 
329
         y2 = y * y;
 
330
         x2 = a2 * (1 - y2 / b2);
 
331
         x = sqrt(x2);                                                     //  corresp. x values, + and -
 
332
         py = y + cy;
 
333
         px = cx - x + 0.5;
 
334
         sa_draw1pix(px,py);                                               //  draw 2 points on ellipse
 
335
         px = cx + x + 0.5;
 
336
         sa_draw1pix(px,py);
 
337
      }
 
338
 
 
339
      for (x = -a; x < a; x++)                                             //  step through x values
 
340
      {
 
341
         x2 = x * x;
 
342
         y2 = b2 * (1 - x2 / a2);
 
343
         y = sqrt(y2);                                                     //  corresp. y values, + and -
 
344
         px = cx + x;
 
345
         py = cy - y + 0.5;
 
346
         sa_draw1pix(px,py);                                               //  draw 2 points on ellipse
 
347
         py = cy + y + 0.5;
 
348
         sa_draw1pix(px,py);
 
349
      }
 
350
   }
 
351
   
 
352
   mwpaint2();
 
353
   return;
 
354
}
 
355
 
 
356
 
 
357
//  select area mouse function - freehand draw and follow edge
 
358
 
 
359
void sa_draw_mousefunc()
 
360
{
 
361
   void sa_follow_edge(int mx1, int my1, int mx2, int my2);
 
362
 
 
363
   int         mx1, my1, mx2, my2;
 
364
   int         npdist, npx, npy;
 
365
   int         ii, click, newseq, thresh;
 
366
   static int  drag = 0, mdx0, mdy0, mdx1, mdy1;
 
367
   
 
368
   if (sa_stat != 1) return;                                               //  area gone?    v.11.07
 
369
 
 
370
   sa_thresh = 4.0 / Mscale + 1;                                           //  mouse pixel distance threshold
 
371
   click = newseq = 0;
 
372
   
 
373
   if (LMclick || Mxdrag || Mydrag)                                        //  left mouse click or mouse drag
 
374
   {
 
375
      if (LMclick)                                                         //  left mouse click
 
376
      {
 
377
         LMclick = 0;
 
378
         mx1 = mx2 = Mxclick;                                              //  click position
 
379
         my1 = my2 = Myclick;
 
380
         newseq++;
 
381
         click++;
 
382
         drag = 0;
 
383
      }
 
384
      else                                                                 //  drag motion
 
385
      {
 
386
         if (Mxdown != mdx0 || Mydown != mdy0) {                           //  new drag initiated
 
387
            mdx0 = mdx1 = Mxdown;
 
388
            mdy0 = mdy1 = Mydown;
 
389
            newseq++;
 
390
         }
 
391
         mx1 = mdx1;                                                       //  drag start
 
392
         my1 = mdy1;
 
393
         mx2 = Mxdrag;                                                     //  drag position
 
394
         my2 = Mydrag;
 
395
         mdx1 = mx2;                                                       //  next drag start
 
396
         mdy1 = my2;
 
397
         drag++;
 
398
         click = 0;
 
399
      }
 
400
      
 
401
      if (Mbutton == 3)                                                    //  right mouse >> erase
 
402
      {
 
403
         while (true) {
 
404
            thresh = sa_thresh;
 
405
            npdist = sa_nearpix(mx2,my2,thresh,npx,npy);
 
406
            if (! npdist) break;
 
407
            ii = npy * Fww + npx;
 
408
            sa_pixmap[ii] = 0;
 
409
         }
 
410
         mwpaint2();
 
411
         return;
 
412
      }
 
413
 
 
414
      if (sa_currseq > sa_maxseq-2) {
 
415
         zmessageACK(mWin,ZTX("exceed %d edits"),sa_maxseq);               //  cannot continue
 
416
         return;
 
417
      }
 
418
      
 
419
      if (sa_currseq == 0 && newseq)                                       //  1st pixel(s) of 1st sequence
 
420
      {
 
421
         sa_nextseq();                                                     //  set next (1st) sequence no.  v.10.8
 
422
         sa_draw_line(mx1,my1,mx2,my2);                                    //  draw initial pixel or line
 
423
         sa_endpx[sa_currseq] = mx2;
 
424
         sa_endpy[sa_currseq] = my2;
 
425
         return;
 
426
      }
 
427
      
 
428
      if (click) {
 
429
         mx1 = sa_endpx[sa_currseq];                                       //  prior sequence end pixel
 
430
         my1 = sa_endpy[sa_currseq];                                       //  (before this click)
 
431
      }
 
432
      
 
433
      if (drag) {
 
434
         if (newseq) thresh = 2 * sa_thresh;                               //  new drag threshold
 
435
         else thresh = 5 * sa_thresh;                                      //  continuation drag threshold
 
436
         npx = sa_endpx[sa_currseq];                                       //  distance from prior end pixel
 
437
         npy = sa_endpy[sa_currseq];                                       //    (before this drag)
 
438
         if (abs(mx1-npx) < thresh && abs(my1-npy) < thresh) {
 
439
            mx1 = sa_endpx[sa_currseq];                                    //  if < threshold, connect this
 
440
            my1 = sa_endpy[sa_currseq];                                    //    drag to prior drag or click
 
441
         }
 
442
      }
 
443
 
 
444
      if (newseq || drag > 50) {
 
445
         sa_nextseq();                                                     //  set next sequence no.     v.10.8
 
446
         drag = 1;                                                         //  drag length within sequence
 
447
      }
 
448
      
 
449
      if (sa_mode == 4) sa_follow_edge(mx1,my1,mx2,my2);                   //  follow edge or draw line
 
450
      else sa_draw_line(mx1,my1,mx2,my2);                                  //    from end pixel to mouse
 
451
      
 
452
      sa_endpx[sa_currseq] = mx2;                                          //  set end pixel for this sequence
 
453
      sa_endpy[sa_currseq] = my2;
 
454
   }
 
455
 
 
456
   else if (RMclick)                                                       //  right mouse click
 
457
   {
 
458
      RMclick = 0;
 
459
      sa_unselect_pixels();                                                //  remove latest selection   v.10.8
 
460
      mwpaint2();
 
461
   }
 
462
   
 
463
   return;
 
464
}
 
465
 
 
466
 
 
467
//  Find the nearest drawn pixel within a radius of a given pixel.
 
468
//  Returns distance to pixel, or zero if nothing found.
 
469
//  Returns 1 for adjacent or diagonally adjacent pixel.
 
470
 
 
471
int sa_nearpix(int mx, int my, int rad2, int &npx, int &npy)
 
472
{
 
473
   int      ii, rad, qx, qy, dx, dy;
 
474
   int      mindist, dist;
 
475
 
 
476
   npx = npy = 0;
 
477
   mindist = (rad2+1) * (rad2+1);
 
478
 
 
479
   for (rad = 1; rad <= rad2; rad++)                                       //  seek neighbors within range
 
480
   {
 
481
      if (rad * rad > mindist) break;                                      //  can stop searching now
 
482
 
 
483
      for (qx = mx-rad; qx <= mx+rad; qx++)                                //  search within rad
 
484
      for (qy = my-rad; qy <= my+rad; qy++)
 
485
      {
 
486
         if (qx != mx-rad && qx != mx+rad &&                               //  exclude within rad-1
 
487
             qy != my-rad && qy != my+rad) continue;                       //  (already searched)
 
488
         if (qx < 0 || qx > Fww-1) continue;
 
489
         if (qy < 0 || qy > Fhh-1) continue;
 
490
         ii = qy * Fww + qx;
 
491
         if (! sa_pixmap[ii]) continue;
 
492
         dx = (mx - qx) * (mx - qx);                                       //  found pixel
 
493
         dy = (my - qy) * (my - qy);
 
494
         dist = dx + dy;                                                   //  distance**2
 
495
         if (dist < mindist) {
 
496
            mindist = dist;
 
497
            npx = qx;                                                      //  save nearest pixel found
 
498
            npy = qy;
 
499
         }
 
500
      }
 
501
   }
 
502
   
 
503
   if (npx + npy) return sqrt(mindist) + 0.5;
 
504
   return 0;
 
505
}
 
506
 
 
507
 
 
508
//  draw a line between two given pixels
 
509
//  add all in-line pixels to sa_pixmap[]
 
510
  
 
511
void sa_draw_line(int px1, int py1, int px2, int py2)
 
512
{
 
513
   void  sa_draw1pix(int px, int py);
 
514
 
 
515
   int      pxm, pym;
 
516
   double   slope;
 
517
   
 
518
   if (sa_stat != 1) return;                                               //  area gone?          v.11.07
 
519
 
 
520
   if (px1 == px2 && py1 == py2) {                                         //  only one pixel
 
521
      sa_draw1pix(px1,py1);
 
522
      return;
 
523
   }
 
524
   
 
525
   if (abs(py2 - py1) > abs(px2 - px1)) {
 
526
      slope = 1.0 * (px2 - px1) / (py2 - py1);
 
527
      if (py2 > py1) {
 
528
         for (pym = py1; pym <= py2; pym++) {
 
529
            pxm = round(px1 + slope * (pym - py1));
 
530
            sa_draw1pix(pxm,pym);
 
531
         }
 
532
      }
 
533
      else {
 
534
         for (pym = py1; pym >= py2; pym--) {
 
535
            pxm = round(px1 + slope * (pym - py1));
 
536
            sa_draw1pix(pxm,pym);
 
537
         }
 
538
      }
 
539
   }
 
540
   else {
 
541
      slope = 1.0 * (py2 - py1) / (px2 - px1);
 
542
      if (px2 > px1) {
 
543
         for (pxm = px1; pxm <= px2; pxm++) {
 
544
            pym = round(py1 + slope * (pxm - px1));
 
545
            sa_draw1pix(pxm,pym);
 
546
         }
 
547
      }
 
548
      else {
 
549
         for (pxm = px1; pxm >= px2; pxm--) {
 
550
            pym = round(py1 + slope * (pxm - px1));
 
551
            sa_draw1pix(pxm,pym);
 
552
         }
 
553
      }
 
554
   }
 
555
 
 
556
   return;
 
557
}
 
558
 
 
559
 
 
560
//  draw one pixel only if not already drawn
 
561
 
 
562
void sa_draw1pix(int px, int py)
 
563
{
 
564
   if (px < 0 || px > Fww-1) return;                                       //  bugfix              v.11.03.1
 
565
   if (py < 0 || py > Fhh-1) return;
 
566
   int ii = Fww * py + px;
 
567
   if (sa_pixmap[ii]) return;                                              //  map to curr. selection sequence
 
568
   sa_pixmap[ii] = sa_currseq;
 
569
   sa_Ncurrseq++;                                                          //  v.10.8
 
570
   draw_fat_pixel(px,py,sa_pixRGB);                                        //  v.11.04
 
571
   return;
 
572
}
 
573
 
 
574
 
 
575
//  Find series of edge pixels from px1/py1 to px2/py2 and connect them together.
 
576
 
 
577
void sa_follow_edge(int px1, int py1, int px2, int py2)                    //  v.10.8
 
578
{
 
579
   double   sa_get_contrast(int px, int py);
 
580
   
 
581
   double   px3, py3, px4, py4, px5, py5, px6, py6;
 
582
   double   dx, dy, dist, contrast, maxcontrast;
 
583
   
 
584
   if (sa_stat != 1) return;                                               //  area gone?       v.11.07
 
585
   
 
586
   px3 = px1;                                                              //  p3 progresses from p1 to p2
 
587
   py3 = py1;
 
588
   
 
589
   while (true)
 
590
   {
 
591
      dx = px2 - px3;
 
592
      dy = py2 - py3;
 
593
      
 
594
      dist = sqrt(dx * dx + dy * dy);                                      //  last segment
 
595
      if (dist < 3) break;
 
596
      
 
597
      px4 = px3 + dx / dist;                                               //  p4 = p3 moved toward p2
 
598
      py4 = py3 + dy / dist;
 
599
      
 
600
      maxcontrast = 0;
 
601
      px6 = px4;
 
602
      py6 = py4;
 
603
 
 
604
      for (int ii = -2; ii <= +2; ii++)                                    //  p5 points are in a line through p4
 
605
      {                                                                    //    and perpendicular to p4 - p2
 
606
         px5 = px4 + ii * dy / dist;
 
607
         py5 = py4 - ii * dx / dist;
 
608
         contrast = sa_get_contrast(px5,py5);
 
609
         contrast *= (7 - abs(ii));                                        //  favor points closer together   v.10.9
 
610
         if (contrast > maxcontrast) {
 
611
            px6 = px5;                                                     //  p6 = highest contrast point in p5
 
612
            py6 = py5;
 
613
            maxcontrast = contrast;
 
614
         }
 
615
      }
 
616
      
 
617
      sa_draw_line(px3,py3,px6,py6);                                       //  draw p3 to p6
 
618
 
 
619
      px3 = px6;                                                           //  next p3
 
620
      py3 = py6;
 
621
   }
 
622
   
 
623
   sa_draw_line(px3,py3,px2,py2);
 
624
   return;
 
625
}
 
626
 
 
627
 
 
628
//  Find max. contrast between neighbors on opposite sides of given pixel
 
629
 
 
630
double sa_get_contrast(int px, int py)                                     //  v.10.8
 
631
{
 
632
   int         map[4][2] = { {1, 0}, {1, 1}, {0, 1}, {-1, 1} };
 
633
   int         ii, qx, qy;
 
634
   uint16      *pix1, *pix2;
 
635
   double      red, green, blue;
 
636
   double      contrast, maxcontrast = 0;
 
637
   double      f65k = 1.0 / 65535.0;
 
638
   
 
639
   if (px < 1 || px > Fww-2) return 0;                                     //  avoid edge pixels
 
640
   if (py < 1 || py > Fhh-2) return 0;
 
641
   
 
642
   for (ii = 0; ii < 4; ii++)                                              //  compare pixels around target
 
643
   {                                                                       //  e.g. (px-1,py) to (px+1,py)
 
644
      qx = map[ii][0];
 
645
      qy = map[ii][1];
 
646
      pix1 = PXMpix(Fpxm16,px+qx,py+qy);
 
647
      pix2 = PXMpix(Fpxm16,px-qx,py-qy);
 
648
      red = f65k * abs(pix1[0] - pix2[0]);
 
649
      green = f65k * abs(pix1[1] - pix2[1]);
 
650
      blue = f65k * abs(pix1[2] - pix2[2]);
 
651
      contrast = (1.0 - red) * (1.0 - green) * (1.0 - blue);               //  no contrast = 1.0
 
652
      contrast = 1.0 - contrast;                                           //  max. contrast = 1.0
 
653
      if (contrast > maxcontrast) maxcontrast = contrast;
 
654
   }
 
655
   
 
656
   return maxcontrast;
 
657
}
 
658
 
 
659
 
 
660
//  select area by color range - mouse function
 
661
 
 
662
void sa_color_mousefunc()
 
663
{
 
664
   void sa_find_color_pixels();
 
665
 
 
666
   int         cc;
 
667
   static int  mxdown, mydown, drag = 0;
 
668
   
 
669
   if (sa_stat != 1) return;                                               //  area gone?          v.11.07
 
670
 
 
671
   sa_radius = sa_mouseradius;                                             //  use mouse radius
 
672
   sa_radius2 = sa_radius * sa_radius;
 
673
 
 
674
   toparcx = Mxposn - sa_radius;                                           //  draw radius outline circle
 
675
   toparcy = Myposn - sa_radius;
 
676
   toparcw = toparch = 2 * sa_radius;
 
677
   Ftoparc = 1;
 
678
   paint_toparc(3);
 
679
 
 
680
   if (sa_stackdirec) zfree(sa_stackdirec);                                //  allocate pixel search stack
 
681
   if (sa_stackii) zfree(sa_stackii);
 
682
   cc = Fww * Fhh;   
 
683
   sa_stackdirec = zmalloc(cc,"sa_color");
 
684
   sa_stackii = (int *) zmalloc(4*cc,"sa_color");
 
685
   sa_maxstack = cc;
 
686
   sa_Nstack = 0;
 
687
 
 
688
   sa_mousex = sa_mousey = 0;
 
689
 
 
690
   if (LMclick) {                                                          //  get mouse position at click
 
691
      sa_mousex = Mxclick;
 
692
      sa_mousey = Myclick;
 
693
      LMclick = 0;
 
694
      sa_nextseq();                                                        //  set next sequence no.     v.10.8
 
695
      drag = 1;
 
696
   }
 
697
 
 
698
   if ((Mxdrag || Mydrag) && Mbutton == 3) {                               //  right drag, unselect within radius
 
699
      sa_radius_mousefunc();
 
700
      mwpaint2();
 
701
   }
 
702
 
 
703
   if ((Mxdrag || Mydrag) && Mbutton == 1) {                               //  left drag, select matching colors
 
704
      sa_mousex = Mxdrag;
 
705
      sa_mousey = Mydrag;
 
706
      Mxdrag = Mydrag = 0;
 
707
 
 
708
      if (Mxdown != mxdown || Mydown != mydown) {                          //  detect if new drag started
 
709
         mxdown = Mxdown;
 
710
         mydown = Mydown;
 
711
         sa_nextseq();                                                     //  set next sequence no.     v.10.8
 
712
         drag = 1;
 
713
      }
 
714
      else if (++drag > 30) {                                              //  limit work per sequence no.
 
715
         sa_nextseq();                                                     //  set next sequence no.     v.10.8
 
716
         drag = 1;
 
717
      }
 
718
   }
 
719
 
 
720
   if (sa_mousex || sa_mousey) {
 
721
      sa_find_color_pixels();                                              //  accumulate pixels
 
722
      mwpaint2();
 
723
   }
 
724
 
 
725
   if (RMclick) {
 
726
      RMclick = 0;
 
727
      sa_unselect_pixels();                                                //  remove latest selection   v.10.8
 
728
      mwpaint2();
 
729
   }
 
730
 
 
731
   return;
 
732
}
 
733
 
 
734
 
 
735
//  find all contiguous pixels within the specified range of colors to match
 
736
 
 
737
void sa_find_color_pixels()                                                //  overhauled       v.11.02
 
738
{
 
739
   int         ii, kk, cc, px, py, rx, ry, rad2;
 
740
   int         ppx, ppy, npx, npy;
 
741
   uint16      *matchpix;
 
742
   double      match1, match2, ff = 1.0 / 65536.0;
 
743
   double      dred, dgreen, dblue;
 
744
   char        direc;
 
745
   
 
746
   match1 = 0.01 * sa_colormatch;                                          //  color match level, 0.01 to 1.0
 
747
 
 
748
   px = sa_mousex;
 
749
   py = sa_mousey;
 
750
   if (px < 0 || px > Fww-1) return;                                       //  mouse outside image
 
751
   if (py < 0 || py > Fhh-1) return;
 
752
 
 
753
   cc = Fww * Fhh;                                                         //  allocate selection map
 
754
   sa_pixselc = zmalloc(cc,"sa_color");
 
755
   memset(sa_pixselc,0,cc);
 
756
 
 
757
   sa_Nmatch = 0;                                                          //  match color count
 
758
 
 
759
   for (rx = -sa_radius; rx <= sa_radius; rx++)                            //  loop every pixel in radius of mouse
 
760
   for (ry = -sa_radius; ry <= sa_radius; ry++)
 
761
   {
 
762
      rad2 = rx * rx + ry * ry;
 
763
      if (rad2 > sa_radius2) continue;                                     //  outside radius
 
764
      px = sa_mousex + rx;
 
765
      py = sa_mousey + ry;
 
766
      if (px < 0 || px > Fww-1) continue;                                  //  off the image edge
 
767
      if (py < 0 || py > Fhh-1) continue;
 
768
 
 
769
      matchpix = PXMpix(Fpxm16,px,py);                                     //  get color at mouse position
 
770
      
 
771
      for (ii = 0; ii < sa_Nmatch; ii++)                                   //  see if color is already included
 
772
      {
 
773
         dred =   ff * abs(sa_matchRGB[ii][0] - matchpix[0]);              //  0 = perfect match
 
774
         dgreen = ff * abs(sa_matchRGB[ii][1] - matchpix[1]);
 
775
         dblue =  ff * abs(sa_matchRGB[ii][2] - matchpix[2]);
 
776
         match2 = (1.0 - dred) * (1.0 - dgreen) * (1.0 - dblue);           //  1 = perfect match
 
777
         if (match2 >= match1) break;                                      //  matches close enough
 
778
      }
 
779
      
 
780
      if (ii == sa_Nmatch) {                                               //  no close match 
 
781
         sa_matchRGB[ii][0] = matchpix[0];                                 //  add new match color to list
 
782
         sa_matchRGB[ii][1] = matchpix[1];
 
783
         sa_matchRGB[ii][2] = matchpix[2];
 
784
         sa_Nmatch++;
 
785
         if (sa_Nmatch == 1000) goto startsearch;                          //  capacity limit
 
786
      }
 
787
   }
 
788
 
 
789
startsearch:
 
790
 
 
791
   sa_Ncurrseq = 0;                                                        //  count newly selected pixels
 
792
 
 
793
   px = sa_mousex;                                                         //  pixel at mouse
 
794
   py = sa_mousey;
 
795
   ii = Fww * py + px;
 
796
   sa_pixselc[ii] = 1;                                                     //  pixel is in current selection
 
797
 
 
798
   if (! sa_pixmap[ii]) {                                                  //  if selected for the first time,  v.10.12
 
799
      sa_pixmap[ii] = sa_currseq;                                          //    map pixel to current sequence
 
800
      sa_Ncurrseq++;                                                       //  current sequence pixel count
 
801
   }
 
802
 
 
803
   sa_stackii[0] = ii;                                                     //  put 1st pixel into stack
 
804
   sa_stackdirec[0] = 'a';                                                 //  direction = ahead               v.11.04
 
805
   sa_Nstack = 1;                                                          //  stack count
 
806
 
 
807
   while (sa_Nstack)
 
808
   {
 
809
      kk = sa_Nstack - 1;                                                  //  get last pixel in stack
 
810
      ii = sa_stackii[kk];
 
811
      direc = sa_stackdirec[kk];
 
812
      
 
813
      py = ii / Fww;                                                       //  reconstruct px, py
 
814
      px = ii - Fww * py;
 
815
 
 
816
      if (direc == 'x') {                                                  //  no neighbors left to check
 
817
         sa_Nstack--;
 
818
         continue;
 
819
      }
 
820
      
 
821
      if (sa_Nstack > 1) {
 
822
         ii = sa_Nstack - 2;                                               //  get prior pixel in stack
 
823
         ii = sa_stackii[ii];
 
824
         ppy = ii / Fww;
 
825
         ppx = ii - ppy * Fww;
 
826
      }
 
827
      else {
 
828
         ppx = px - 1;                                                     //  if only one, assume prior = left
 
829
         ppy = py;
 
830
      }
 
831
 
 
832
      if (direc == 'a') {                                                  //  next ahead pixel             v.11.04
 
833
         npx = px + px - ppx;
 
834
         npy = py + py - ppy;
 
835
         sa_stackdirec[kk] = 'r';                                          //  next search direction
 
836
      }
 
837
 
 
838
      else if (direc == 'r') {                                             //  next right pixel             v.11.04
 
839
         npx = px + py - ppy;
 
840
         npy = py + px - ppx;
 
841
         sa_stackdirec[kk] = 'l';
 
842
      }
 
843
 
 
844
      else { /*  direc = 'l'  */                                           //  next left pixel              v.11.04
 
845
         npx = px + ppy - py;
 
846
         npy = py + ppx - px;
 
847
         sa_stackdirec[kk] = 'x';
 
848
      }
 
849
 
 
850
      if (npx < 0 || npx > Fww-1) continue;                                //  pixel off the edge           v.11.04
 
851
      if (npy < 0 || npy > Fhh-1) continue;
 
852
      
 
853
      rx = npx - Mxposn;                                                   //  limit search to 3 * mouse radius
 
854
      ry = npy - Myposn;                                                   //  v.11.04
 
855
      rad2 = rx * rx + ry * ry;
 
856
      if (rad2 > 9 * sa_radius2) continue;
 
857
      
 
858
      ii = npy * Fww + npx;
 
859
      if (sa_pixselc[ii]) continue;                                        //  already in current selection   v.10.8
 
860
 
 
861
      if (sa_firewall && sa_pixmap[ii])                                    //  aleady selected, firewall mode  v.10.12
 
862
         if (rad2 > sa_radius2) continue;                                  //  and pixel outside mouse radius
 
863
 
 
864
      matchpix = PXMpix(Fpxm16,npx,npy);
 
865
      for (kk = 0; kk < sa_Nmatch; kk++) {                                 //  compare pixel RGB to match colors
 
866
         dred =   ff * abs(sa_matchRGB[kk][0] - matchpix[0]);              //  v.10.8
 
867
         dgreen = ff * abs(sa_matchRGB[kk][1] - matchpix[1]);
 
868
         dblue =  ff * abs(sa_matchRGB[kk][2] - matchpix[2]);
 
869
         match2 = (1.0 - dred) * (1.0 - dgreen) * (1.0 - dblue);           //  1 = perfect match
 
870
         if (match2 >= match1) break;                                      //  within range
 
871
      }
 
872
      if (kk == sa_Nmatch) continue;                                       //  not within range of any color
 
873
 
 
874
      sa_pixselc[ii] = 1;                                                  //  map pixel to current selection   v.10.8
 
875
 
 
876
      if (! sa_pixmap[ii]) {                                               //  if selected for the first time,  v.10.12
 
877
         sa_pixmap[ii] = sa_currseq;                                       //    map pixel to current sequence
 
878
         sa_Ncurrseq++;                                                    //  current sequence pixel count
 
879
      }
 
880
 
 
881
      if (sa_Nstack == sa_maxstack) continue;                              //  stack is full
 
882
      kk = sa_Nstack++;                                                    //  push pixel into stack
 
883
      sa_stackii[kk] = ii;
 
884
      sa_stackdirec[kk] = 'a';                                             //  direction = ahead            v.11.04
 
885
   }
 
886
 
 
887
   zfree(sa_pixselc);                                                      //  free memory
 
888
   return;
 
889
}
 
890
 
 
891
 
 
892
//  select or un-select all pixels within radius - mouse function
 
893
 
 
894
void sa_radius_mousefunc()
 
895
{
 
896
   int      ii, px, py, rx, ry;
 
897
   
 
898
   if (sa_stat != 1) return;                                               //  area gone?                v.11.07
 
899
   
 
900
   sa_radius = sa_mouseradius;                                             //  pixel selection radius
 
901
   sa_radius2 = sa_radius * sa_radius;
 
902
 
 
903
   toparcx = Mxposn - sa_radius;                                           //  draw radius outline circle
 
904
   toparcy = Myposn - sa_radius;
 
905
   toparcw = toparch = 2 * sa_radius;
 
906
   Ftoparc = 1;
 
907
   paint_toparc(3);
 
908
 
 
909
   if (LMclick || RMclick) {                                               //  mouse click
 
910
      sa_nextseq();                                                        //  set next sequence no.     v.10.8
 
911
      LMclick = RMclick = 0;
 
912
   }
 
913
 
 
914
   if (Mbutton != 1 && Mbutton != 3) {                                     //  button released
 
915
      sa_nextseq();                                                        //  set next sequence no.     v.10.8
 
916
      return;                                                              //  (if some pixels mapped)
 
917
   }
 
918
   
 
919
   for (rx = -sa_radius; rx <= sa_radius; rx++)                            //  loop every pixel in radius
 
920
   for (ry = -sa_radius; ry <= sa_radius; ry++)
 
921
   {
 
922
      if (rx * rx + ry * ry > sa_radius2) continue;                        //  outside radius
 
923
      px = Mxposn + rx;
 
924
      py = Myposn + ry;
 
925
      if (px < 0 || px > Fww-1) continue;                                  //  off the image edge
 
926
      if (py < 0 || py > Fhh-1) continue;
 
927
 
 
928
      ii = Fww * py + px;
 
929
      
 
930
      if (Mbutton == 3)                                                    //  right mouse button
 
931
         sa_pixmap[ii] = 0;                                                //  remove pixel from select area
 
932
 
 
933
      if (Mbutton == 1)                                                    //  left mouse button
 
934
      {
 
935
         if (sa_pixmap[ii]) continue;                                      //  pixel already selected
 
936
 
 
937
         if (sa_Ncurrseq > 1000)                                           //  start new sequence no.
 
938
            sa_nextseq();                                                  //    after 1000 pixels
 
939
 
 
940
         sa_pixmap[ii] = sa_currseq;                                       //  map pixel to current sequence
 
941
         sa_Ncurrseq++;
 
942
      }
 
943
   }
 
944
 
 
945
   mwpaint2();
 
946
}
 
947
 
 
948
 
 
949
//  set next sequence number for pixels about to be selected
 
950
 
 
951
void sa_nextseq()                                                          //  v.10.8
 
952
{
 
953
   if (sa_Ncurrseq > 0) sa_currseq++;                                      //  increase only if some pixels mapped
 
954
   if (sa_currseq < sa_initseq) sa_currseq = sa_initseq;                   //  start at initial value
 
955
   sa_Ncurrseq = 0;
 
956
   return;
 
957
}
 
958
 
 
959
 
 
960
//  un-select all pixels mapped to current sequence number
 
961
//  reduce sequence number and set pixel count = 1
 
962
 
 
963
void sa_unselect_pixels()
 
964
{
 
965
   if (sa_stat != 1) return;                                               //  area gone?             v.11.07
 
966
   if (! sa_currseq) return;                                               //  no pixels mapped
 
967
 
 
968
   for (int ii = 0; ii < Fww * Fhh; ii++)
 
969
      if (sa_pixmap[ii] == sa_currseq) sa_pixmap[ii] = 0;                  //  unmap current selection
 
970
   
 
971
   if (sa_currseq > sa_initseq) {                                          //  reduce sequence no.    v.10.8
 
972
      sa_currseq--;
 
973
      sa_Ncurrseq = 1;                                                     //  unknown but > 0
 
974
   }
 
975
   else  sa_Ncurrseq = 0;                                                  //  initial sequence no. reached
 
976
   
 
977
   return;
 
978
}
 
979
 
 
980
 
 
981
//  Finish select area - map pixels enclosed by edge pixels 
 
982
//  into sa_pixmap[ii]: 0/1/2 = outside/edge/inside (ii=py*Fww+px)
 
983
//  total count = sa_Npixel
 
984
 
 
985
zdialog  *safinzd = 0;
 
986
 
 
987
void sa_finish()                                                           //  overhauled    v.11.02
 
988
{
 
989
   void sa_finish_mousefunc();
 
990
   int  sa_finish_dialog_event(zdialog *, cchar *event);
 
991
 
 
992
   cchar  *fmess = ZTX("Click one time inside each enclosed area \n"
 
993
                       "(possible gaps in the outline will be found). \n"
 
994
                       "Press F1 for help.");
 
995
 
 
996
   GtkWidget   *pwin = zdialog_widget(zdsela,"dialog");
 
997
   int         ii, cc, px, py;
 
998
 
 
999
   if (! sa_stat) return;                                                  //  no area?                  v.11.07
 
1000
   if (sa_fww != Fww || sa_fhh != Fhh) return;                             //  area not valid for image  v.11.08
 
1001
   if (sa_mode == 7) return;                                               //  a whole image area
 
1002
 
 
1003
   sa_Npixel = Factivearea = 0;                                            //  area disabled, unfinished
 
1004
   sa_hole = 0;                                                            //  no hole detected yet
 
1005
   sa_show(1);                                                             //  show outline
 
1006
 
 
1007
   sa_minx = Fww;
 
1008
   sa_maxx = 0;
 
1009
   sa_miny = Fhh;
 
1010
   sa_maxy = 0;
 
1011
 
 
1012
   for (ii = 0; ii < Fww * Fhh; ii++)                                      //  get enclosing rectangle
 
1013
   {                                                                       //    for selected area
 
1014
      if (! sa_pixmap[ii]) continue;
 
1015
      py = ii / Fww;
 
1016
      px = ii - Fww * py;
 
1017
      if (px >= sa_maxx) sa_maxx = px+1;                                   //  like Fww, sa_maxx = last + 1
 
1018
      if (px < sa_minx) sa_minx = px;
 
1019
      if (py >= sa_maxy) sa_maxy = py+1;
 
1020
      if (py < sa_miny) sa_miny = py;
 
1021
   }
 
1022
 
 
1023
   sa_minx -= 10;                                                          //  add margins where possible
 
1024
   if (sa_minx < 0) sa_minx = 0;
 
1025
   sa_maxx += 10;
 
1026
   if (sa_maxx > Fww) sa_maxx = Fww;
 
1027
   sa_miny -= 10;
 
1028
   if (sa_miny < 0) sa_miny = 0;
 
1029
   sa_maxy += 10;
 
1030
   if (sa_maxy > Fhh) sa_maxy = Fhh;
 
1031
   
 
1032
   sa_map_pixels();                                                        //  map edge and interior pixels
 
1033
   if (sa_Npixel < 10) return;                                             //  ridiculous
 
1034
 
 
1035
   for (py = sa_miny; py < sa_maxy; py++)                                  //  loop pixels in rectangle   v.10.12
 
1036
   for (px = sa_minx; px < sa_maxx; px++)
 
1037
   {
 
1038
      ii = Fww * py + px;
 
1039
      if (sa_pixmap[ii] == 2) sa_pixmap[ii] = 0;                           //  eliminate interior pixels
 
1040
   }
 
1041
 
 
1042
   cc = (sa_maxx-sa_minx) * (sa_maxy-sa_miny);                             //  allocate stack memory
 
1043
   if (sa_stackdirec) zfree(sa_stackdirec);
 
1044
   sa_stackdirec = zmalloc(cc,"sa_finish");
 
1045
   if (sa_stackii) zfree(sa_stackii);
 
1046
   sa_stackii = (int *) zmalloc(cc * 4,"sa_finish");
 
1047
   sa_maxstack = cc;
 
1048
   
 
1049
   safinzd = zdialog_new(ZTX("finish area"),pwin,Bdone,Bcancel,null);      //  dialog for user to click inside
 
1050
   zdialog_add_widget(safinzd,"label","fmess","dialog",fmess,"space=5");   //    each enclosed area
 
1051
   zdialog_add_widget(safinzd,"hbox","hbstat","dialog");
 
1052
   zdialog_add_widget(safinzd,"label","labstat","hbstat","status:","space=5");
 
1053
   zdialog_add_widget(safinzd,"label","statmess","hbstat",0);
 
1054
   
 
1055
   takeMouse(safinzd,sa_finish_mousefunc,dragcursor);                      //  connect mouse function    v.11.03
 
1056
 
 
1057
   zdialog_run(safinzd,sa_finish_dialog_event,"save");                     //  run dialog, parallel      v.11.07
 
1058
   zdialog_wait(safinzd);
 
1059
   return;
 
1060
}
 
1061
 
 
1062
 
 
1063
//  mouse function - get user clicks and perform pixel searches
 
1064
 
 
1065
void sa_finish_mousefunc()                                                 //  overhauled    v.11.02
 
1066
{
 
1067
   int         px, py, ii, kk;
 
1068
   int         ppx, ppy, npx, npy;
 
1069
   char        direc;
 
1070
 
 
1071
   if (! LMclick) return;
 
1072
   LMclick = 0;
 
1073
   
 
1074
   if (! sa_stat) return;                                                  //  area gone?                   v.11.07
 
1075
 
 
1076
   ii = Fww * Myclick + Mxclick;                                           //  seed pixel from mouse click
 
1077
   if (sa_pixmap[ii] == 1) return;                                         //  ignore if edge pixel         v.11.07
 
1078
   sa_pixmap[ii] = 2;                                                      //  map the pixel, inside area
 
1079
   sa_stackii[0] = ii;                                                     //  put seed pixel into stack
 
1080
   sa_stackdirec[0] = 'a';                                                 //  direction = ahead            v.11.04
 
1081
   sa_Nstack = 1;                                                          //  stack count
 
1082
 
 
1083
   zdialog_stuff(safinzd,"statmess",ZTX("searching"));
 
1084
   zmainloop();
 
1085
   zsleep(0.2);
 
1086
   
 
1087
   Ffuncbusy++;
 
1088
 
 
1089
   while (sa_Nstack)                                                       //  find all pixels outside enclosed area(s)
 
1090
   {
 
1091
      kk = sa_Nstack - 1;                                                  //  get last pixel in stack
 
1092
      ii = sa_stackii[kk];
 
1093
      direc = sa_stackdirec[kk];
 
1094
      
 
1095
      py = ii / Fww;                                                       //  reconstruct px, py
 
1096
      px = ii - Fww * py;
 
1097
 
 
1098
      if (px < sa_minx || px >= sa_maxx || py < sa_miny || py >= sa_maxy)  //  moved v.11.08
 
1099
      {
 
1100
         sa_hole++;                                                        //  ran off the edge, seed pixel was
 
1101
         break;                                                            //    not inside area or area has a hole
 
1102
      }
 
1103
 
 
1104
      if (direc == 'x') {                                                  //  no neighbors left to check
 
1105
         sa_Nstack--;
 
1106
         continue;
 
1107
      }
 
1108
 
 
1109
      if (sa_Nstack > 1) {
 
1110
         ii = sa_Nstack - 2;                                               //  get prior pixel in stack
 
1111
         ii = sa_stackii[ii];
 
1112
         ppy = ii / Fww;
 
1113
         ppx = ii - ppy * Fww;
 
1114
      }
 
1115
      else {
 
1116
         ppx = px - 1;                                                     //  if only one, assume prior = left
 
1117
         ppy = py;
 
1118
      }
 
1119
      
 
1120
      if (direc == 'a') {                                                  //  next ahead pixel             v.11.04
 
1121
         npx = px + px - ppx;
 
1122
         npy = py + py - ppy;
 
1123
         sa_stackdirec[kk] = 'r';                                          //  next search direction
 
1124
      }
 
1125
 
 
1126
      else if (direc == 'r') {                                             //  next right pixel             v.11.04
 
1127
         npx = px + py - ppy;
 
1128
         npy = py + px - ppx;
 
1129
         sa_stackdirec[kk] = 'l';
 
1130
      }
 
1131
 
 
1132
      else { /*  direc = 'l'  */                                           //  next left pixel              v.11.04
 
1133
         npx = px + ppy - py;
 
1134
         npy = py + ppx - px;
 
1135
         sa_stackdirec[kk] = 'x';
 
1136
      }
 
1137
      
 
1138
      if (npx < 0 || npx > Fww-1) continue;                                //  next pixel off the image edge
 
1139
      if (npy < 0 || npy > Fhh-1) continue;                                //  bugfix        v.11.04
 
1140
      
 
1141
      ii = npy * Fww + npx;
 
1142
      if (sa_pixmap[ii]) continue;                                         //  pixel already mapped
 
1143
 
 
1144
      sa_pixmap[ii] = 2;                                                   //  map the pixel, inside area
 
1145
      kk = sa_Nstack++;                                                    //  put pixel into stack
 
1146
      sa_stackii[kk] = ii;
 
1147
      sa_stackdirec[kk] = 'a';                                             //  direction = ahead            v.11.04
 
1148
      draw_pixel(npx,npy,sa_pixRGB);                                       //  color mapped pixels
 
1149
      zmainloop(30);                                                       //  let window  update           v.11.07
 
1150
   }
 
1151
 
 
1152
   Ffuncbusy--;
 
1153
 
 
1154
   if (sa_hole)
 
1155
      zdialog_stuff(safinzd,"statmess",ZTX("outline has a gap"));
 
1156
   else 
 
1157
      zdialog_stuff(safinzd,"statmess",ZTX("success"));                    //  all pixels found and mapped
 
1158
   return;
 
1159
}
 
1160
 
 
1161
 
 
1162
//  dialog event and completion callback function
 
1163
 
 
1164
int sa_finish_dialog_event(zdialog *zd, cchar *event)
 
1165
{
 
1166
   int         zstat;
 
1167
 
 
1168
   freeMouse();                                                            //  disconnect mouse
 
1169
   zstat = zd->zstat;
 
1170
   zdialog_free(safinzd);                                                  //  kill dialog
 
1171
 
 
1172
   if (! sa_stat) return 0;                                                //  area gone?       v.11.07
 
1173
 
 
1174
   if (zstat != 1 || sa_hole)                                              //  user cancel or pixel search failure
 
1175
   {
 
1176
      sa_unfinish();                                                       //  unmap interior pixels, set edit mode
 
1177
      return 0;                                                            //  v.11.07
 
1178
   }
 
1179
 
 
1180
   sa_map_pixels();                                                        //  count pixels, map interior pixels
 
1181
 
 
1182
   sa_stat = 3;                                                            //  area is finished
 
1183
   Factivearea = 1;                                                        //  area is active by default
 
1184
   sa_calced = sa_blend = 0;                                               //  edge calculation is missing
 
1185
   mwpaint2();
 
1186
   return 0;
 
1187
}
 
1188
 
 
1189
 
 
1190
//  Finish select area automatically when the 
 
1191
//  interior selected pixels are already known.
 
1192
 
 
1193
void sa_finish_auto()
 
1194
{
 
1195
   int      ii, px, py;
 
1196
 
 
1197
   if (! sa_stat) return;                                                  //  no area?         v.11.07
 
1198
   if (sa_fww != Fww || sa_fhh != Fhh) return;                             //  area not valid for image  v.11.08
 
1199
 
 
1200
   sa_Npixel = Factivearea = 0;                                            //  area disabled, unfinished
 
1201
   
 
1202
   sa_minx = Fww;
 
1203
   sa_maxx = 0;
 
1204
   sa_miny = Fhh;
 
1205
   sa_maxy = 0;
 
1206
 
 
1207
   for (ii = 0; ii < Fww * Fhh; ii++)                                      //  get enclosing rectangle
 
1208
   {                                                                       //    for selected area
 
1209
      if (! sa_pixmap[ii]) continue;
 
1210
      py = ii / Fww;
 
1211
      px = ii - Fww * py;
 
1212
      if (px >= sa_maxx) sa_maxx = px+1;                                   //  like Fww, sa_maxx = last + 1
 
1213
      if (px < sa_minx) sa_minx = px;
 
1214
      if (py >= sa_maxy) sa_maxy = py+1;
 
1215
      if (py < sa_miny) sa_miny = py;
 
1216
   }
 
1217
 
 
1218
   sa_minx -= 10;                                                          //  add margins where possible
 
1219
   if (sa_minx < 0) sa_minx = 0;
 
1220
   sa_maxx += 10;
 
1221
   if (sa_maxx > Fww) sa_maxx = Fww;
 
1222
   sa_miny -= 10;
 
1223
   if (sa_miny < 0) sa_miny = 0;
 
1224
   sa_maxy += 10;
 
1225
   if (sa_maxy > Fhh) sa_maxy = Fhh;
 
1226
   
 
1227
   sa_map_pixels();                                                        //  count pixels, map interior pixels
 
1228
   
 
1229
   sa_stat = 3;                                                            //  area is finished
 
1230
   Factivearea = 1;                                                        //  area is active by default
 
1231
   sa_calced = sa_blend = 0;                                               //  edge calculation is missing
 
1232
   mwpaint2();
 
1233
   return;
 
1234
}
 
1235
 
 
1236
 
 
1237
//  private function
 
1238
//  map edge and interior pixels (sa_pixmap[*] = 1 or 2)
 
1239
//  set sa_Npixel = total pixel count
 
1240
 
 
1241
void sa_map_pixels()                                                       //  v.11.07
 
1242
{
 
1243
   int      npix, px, py, ii, kk;
 
1244
 
 
1245
   if (! sa_stat) return;                                                  //  no area?
 
1246
 
 
1247
   npix = 0;
 
1248
 
 
1249
   for (py = sa_miny; py < sa_maxy; py++)                                  //  find edge pixels
 
1250
   for (px = sa_minx; px < sa_maxx; px++)
 
1251
   {
 
1252
      ii = py * Fww + px;
 
1253
      if (! sa_pixmap[ii]) continue;
 
1254
      npix++;
 
1255
      
 
1256
      if (px == 0 || px == Fww-1 || py == 0 || py == Fhh-1)                //  edge of image
 
1257
         goto edgepix;
 
1258
 
 
1259
      if (! sa_pixmap[ii-1] || ! sa_pixmap[ii+1]) goto edgepix;            //  check 8 neighbor pixels
 
1260
      kk = ii - Fww;
 
1261
      if (! sa_pixmap[kk] || ! sa_pixmap[kk-1] || ! sa_pixmap[kk+1]) goto edgepix;
 
1262
      kk = ii + Fww;
 
1263
      if (! sa_pixmap[kk] || ! sa_pixmap[kk-1] || ! sa_pixmap[kk+1]) goto edgepix;
 
1264
 
 
1265
      sa_pixmap[ii] = 2;                                                   //  interior pixel
 
1266
      continue;
 
1267
 
 
1268
   edgepix:
 
1269
      sa_pixmap[ii] = 1;                                                   //  edge pixel
 
1270
   }
 
1271
 
 
1272
   sa_Npixel = npix;                                                       //  total pixel count
 
1273
   return;
 
1274
}
 
1275
 
 
1276
 
 
1277
//  unfinish an area - unmap interior pixels and put back in edit mode
 
1278
 
 
1279
void sa_unfinish()                                                         //  v.11.07
 
1280
{
 
1281
   int      px, py, ii;
 
1282
 
 
1283
   if (! sa_stat) return;                                                  //  no area?
 
1284
 
 
1285
   for (py = sa_miny; py < sa_maxy; py++)                                  //  loop pixels in rectangle
 
1286
   for (px = sa_minx; px < sa_maxx; px++)
 
1287
   {
 
1288
      ii = py * Fww + px;                                                  //  clear interior pixels found
 
1289
      if (sa_pixmap[ii] == 2) sa_pixmap[ii] = 0;                           //    by finish search function
 
1290
   }
 
1291
 
 
1292
   sa_stat = 1;                                                            //  resume edit mode
 
1293
   Factivearea = 0;
 
1294
   sa_calced = sa_blend = 0;
 
1295
   mwpaint2();
 
1296
   return;
 
1297
}
 
1298
 
 
1299
 
 
1300
//  menu function for show, hide, enable, disable, invert, unselect
 
1301
//  (also implemented as buttons in select area dialog)
 
1302
 
 
1303
void m_select_show(GtkWidget *, cchar *menu)
 
1304
{
 
1305
   zfuncs::F1_help_topic = "area_show_hide";
 
1306
   sa_show(1);
 
1307
   return;
 
1308
}
 
1309
 
 
1310
 
 
1311
void m_select_hide(GtkWidget *, cchar *menu)
 
1312
{
 
1313
   zfuncs::F1_help_topic = "area_show_hide";
 
1314
   sa_show(0);
 
1315
   return;
 
1316
}
 
1317
 
 
1318
 
 
1319
void m_select_enable(GtkWidget *, cchar *menu)
 
1320
{
 
1321
   zfuncs::F1_help_topic = "area_enable_disable";
 
1322
   sa_enable();
 
1323
   return;
 
1324
}
 
1325
 
 
1326
 
 
1327
void m_select_disable(GtkWidget *, cchar *menu)
 
1328
{
 
1329
   zfuncs::F1_help_topic = "area_enable_disable";
 
1330
   sa_disable();
 
1331
   return;
 
1332
}
 
1333
 
 
1334
 
 
1335
void m_select_invert(GtkWidget *, cchar *menu)
 
1336
{
 
1337
   zfuncs::F1_help_topic = "area_invert";
 
1338
   sa_invert();
 
1339
   return;
 
1340
}
 
1341
 
 
1342
 
 
1343
void m_select_unselect(GtkWidget *, cchar *menu)                           //  delete the area
 
1344
{
 
1345
   zfuncs::F1_help_topic = "area_unselect";
 
1346
   sa_unselect();
 
1347
   return;
 
1348
}
 
1349
 
 
1350
 
 
1351
//  show or hide outline of select area
 
1352
//  also called from mwpaint1() if Fshowarea = 1
 
1353
 
 
1354
void sa_show(int flag)
 
1355
{
 
1356
   int      px, py, ii, kk;
 
1357
   
 
1358
   if (! sa_stat) return;                                                  //  no area
 
1359
   if (sa_fww != Fww || sa_fhh != Fhh) return;                             //  area not valid for image
 
1360
   if (sa_mode == 7) return;                                               //  a whole image area
 
1361
   if (Fpreview) return;                                                   //  preview mode, area ignored
 
1362
 
 
1363
   Fshowarea = flag;                                                       //  flag for mwpaint1()
 
1364
 
 
1365
   if (! flag) {
 
1366
      mwpaint2();                                                          //  erase area outline     v.10.8
 
1367
      return;
 
1368
   }
 
1369
   
 
1370
   for (py = 0; py < Fhh; py++)                                            //  find pixels in area    bugfix  v.10.9
 
1371
   for (px = 0; px < Fww; px++)
 
1372
   {
 
1373
      ii = py * Fww + px;
 
1374
      if (! sa_pixmap[ii]) continue;                                       //  outside of area
 
1375
 
 
1376
      if (px == 0 || px == Fww-1 || py == 0 || py == Fhh-1)                //  edge of image
 
1377
         goto edgepix;
 
1378
 
 
1379
      if (! sa_pixmap[ii-1] || ! sa_pixmap[ii+1]) goto edgepix;            //  check 8 neighbor pixels
 
1380
      kk = ii - Fww;
 
1381
      if (! sa_pixmap[kk] || ! sa_pixmap[kk-1] || ! sa_pixmap[kk+1]) goto edgepix;
 
1382
      kk = ii + Fww;
 
1383
      if (! sa_pixmap[kk] || ! sa_pixmap[kk-1] || ! sa_pixmap[kk+1]) goto edgepix;
 
1384
      continue;
 
1385
 
 
1386
   edgepix:
 
1387
      draw_fat_pixel(px,py,sa_pixRGB);                                     //  draw fat pixels           v.11.04
 
1388
   }
 
1389
 
 
1390
   return;
 
1391
}
 
1392
 
 
1393
 
 
1394
//  enable select area that was disabled
 
1395
 
 
1396
void sa_enable()
 
1397
{
 
1398
   if (sa_fww != Fww || sa_fhh != Fhh) return;                             //  area not valid for image     v.11.08
 
1399
 
 
1400
   if (sa_stat != 3) {
 
1401
      zmessageACK(mWin,ZTX("the area is not finished"));                   //  v.11.08
 
1402
      return;                                                              //  v.11.06.1
 
1403
   }
 
1404
 
 
1405
   Factivearea = 1;
 
1406
   sa_show(1);                                                             //  v.10.11
 
1407
   return;
 
1408
}
 
1409
 
 
1410
 
 
1411
//  disable select area
 
1412
 
 
1413
void sa_disable()
 
1414
{
 
1415
   Factivearea = 0;                                                        //  v.9.7
 
1416
   sa_show(0);                                                             //  v.10.11
 
1417
   return;
 
1418
}
 
1419
 
 
1420
 
 
1421
//  invert a selected area
 
1422
 
 
1423
void sa_invert()
 
1424
{
 
1425
   int      ii, jj, px, py, npix;
 
1426
 
 
1427
   if (sa_fww != Fww || sa_fhh != Fhh) return;                             //  area not valid for image     v.11.08
 
1428
 
 
1429
   if (sa_stat != 3) {                                                     //  v.11.06.1
 
1430
      zmessageACK(mWin,ZTX("the area is not finished"));
 
1431
      return;
 
1432
   }
 
1433
 
 
1434
   if (sa_mode == 7) return;                                               //  a whole image area
 
1435
   
 
1436
   npix = 0;
 
1437
 
 
1438
   for (py = 0; py < Fhh; py++)                                            //  loop all pixels
 
1439
   for (px = 0; px < Fww; px++)
 
1440
   {
 
1441
      ii = py * Fww + px;
 
1442
      jj = sa_pixmap[ii];                                                  //  0/1/2+ = outside/edge/inside
 
1443
 
 
1444
      if (px == 0 || px == Fww-1 || py == 0 || py == Fhh-1)                //  pixel on image edge    v.10.12
 
1445
      {
 
1446
         if (jj == 0) {
 
1447
            sa_pixmap[ii] = 1;                                             //  outside pixel >> edge pixel
 
1448
            npix++;                                                        //  count
 
1449
         }
 
1450
         else sa_pixmap[ii] = 0;                                           //  edge pixel >> outside
 
1451
         continue;
 
1452
      }
 
1453
 
 
1454
      if (jj > 1) sa_pixmap[ii] = 0;                                       //  inside pixel (2+) >> outside (0)
 
1455
      else {
 
1456
         sa_pixmap[ii] = 2 - jj;                                           //  edge/outside (1/0) >> edge/inside (1/2)
 
1457
         npix++;                                                           //  count
 
1458
      }
 
1459
   }
 
1460
 
 
1461
   sa_Npixel = npix;                                                       //  new select area pixel count
 
1462
   sa_calced = sa_blend = 0;                                               //  edge calculation missing
 
1463
   if (zdsela) zdialog_stuff(zdsela,"blendwidth",0);                       //  reset blend width               v.11.01
 
1464
   
 
1465
   sa_minx = Fww;                                                          //  new enclosing rectangle    bugfix v.11.01
 
1466
   sa_maxx = 0;
 
1467
   sa_miny = Fhh;
 
1468
   sa_maxy = 0;
 
1469
 
 
1470
   for (ii = 0; ii < Fww * Fhh; ii++)
 
1471
   {
 
1472
      if (! sa_pixmap[ii]) continue;
 
1473
      py = ii / Fww;
 
1474
      px = ii - Fww * py;
 
1475
      if (px >= sa_maxx) sa_maxx = px + 1;
 
1476
      if (px < sa_minx) sa_minx = px;
 
1477
      if (py >= sa_maxy) sa_maxy = py + 1;
 
1478
      if (py < sa_miny) sa_miny = py;
 
1479
   }
 
1480
 
 
1481
   return;
 
1482
}
 
1483
 
 
1484
 
 
1485
//  unselect current area (delete the area)
 
1486
 
 
1487
void sa_unselect()
 
1488
{
 
1489
   sa_stat = sa_Npixel = sa_blend = sa_calced = Factivearea = 0;
 
1490
   sa_currseq = sa_Ncurrseq = 0;
 
1491
   sa_fww = sa_fhh = 0;                                                    //  v.11.08
 
1492
   if (sa_pixmap) zfree(sa_pixmap);
 
1493
   if (sa_stackii) zfree(sa_stackii);
 
1494
   if (sa_stackdirec) zfree(sa_stackdirec);
 
1495
   sa_pixmap = 0;
 
1496
   sa_stackii = 0;
 
1497
   sa_stackdirec = 0;
 
1498
   if (zdsela) zdialog_stuff(zdsela,"blendwidth",0);                       //  reset blend width    v.11.01
 
1499
   mwpaint2();
 
1500
   return;
 
1501
}
 
1502
 
 
1503
 
 
1504
//  compute distance from all pixels in area to nearest edge
 
1505
//  output: sa_pixmap[*] = 0/1/2+ = outside, edge, inside distance from edge
 
1506
 
 
1507
namespace sa_edgecalc_names
 
1508
{
 
1509
   uint16      *sa_edgepx, *sa_edgepy, *sa_edgedist;
 
1510
   int         sa_Nedge;
 
1511
}
 
1512
 
 
1513
void sa_edgecalc()
 
1514
{
 
1515
   using namespace sa_edgecalc_names;
 
1516
   
 
1517
   int    edgecalc_dialog_event(zdialog*, cchar *event);
 
1518
   void * edgecalc_thread(void *);
 
1519
 
 
1520
   int         ii, nn, cc, px, py;
 
1521
   zdialog     *zd = 0;
 
1522
   cchar       *zectext = ZTX("Edge calculation in progress");
 
1523
 
 
1524
   if (! sa_stat) return;                                                  //  area gone?                   v.11.07
 
1525
   if (sa_mode == 7) return;                                               //  a whole image area
 
1526
 
 
1527
   if (sa_calced) return;                                                  //  done already
 
1528
   if (! Factivearea) sa_finish();                                         //  finish if needed
 
1529
   if (! Factivearea) return;                                              //  no finished area
 
1530
   
 
1531
   zd = zdialog_new(ZTX("Area Edge Calc"),mWin,Bcancel,null);              //  start dialog for user cancel
 
1532
   zdialog_add_widget(zd,"label","lab1","dialog",zectext,"space=10");
 
1533
   zdialog_run(zd,edgecalc_dialog_event);
 
1534
   Fkillfunc = 0;
 
1535
 
 
1536
   cc = Fww * Fhh * sizeof(uint16);                                        //  allocate memory for calculations
 
1537
   sa_edgedist = (uint16 *) zmalloc(cc,"sa_edgecalc");
 
1538
   memset(sa_edgedist,0,cc);
 
1539
   
 
1540
   for (ii = nn = 0; ii < Fww * Fhh; ii++)                                 //  count edge pixels in select area
 
1541
      if (sa_pixmap[ii] == 1) nn++;
 
1542
   
 
1543
   cc = nn * sizeof(uint16);
 
1544
   sa_edgepx = (uint16 *) zmalloc(cc,"sa_edgecalc");                       //  allocate memory
 
1545
   sa_edgepy = (uint16 *) zmalloc(cc,"sa_edgecalc");
 
1546
 
 
1547
   for (ii = nn = 0; ii < Fww * Fhh; ii++)                                 //  build list of edge pixels
 
1548
   {                                                                       //  v.9.6
 
1549
      if (sa_pixmap[ii] != 1) continue;
 
1550
      py = ii / Fww;
 
1551
      px = ii - py * Fww;
 
1552
      if (px < 3 || px > Fww-4) continue;                                  //  omit pixels < 3 from image edge
 
1553
      if (py < 3 || py > Fhh-4) continue;
 
1554
      sa_edgepx[nn] = px;
 
1555
      sa_edgepy[nn] = py;
 
1556
      nn++;
 
1557
   }
 
1558
 
 
1559
   sa_Nedge = nn;
 
1560
 
 
1561
   SB_goal = sa_Npixel;
 
1562
   SB_done = 0;
 
1563
   
 
1564
   for (ii = 0; ii < Nwt; ii++)                                            //  start worker threads to calculate
 
1565
      start_wthread(edgecalc_thread,&wtnx[ii]);                            //    sa_pixmap[] edge distances
 
1566
   wait_wthreads();                                                        //  wait for completion
 
1567
 
 
1568
   SB_goal = 0;
 
1569
   
 
1570
   if (! Fkillfunc) {                                                      //  v.11.07
 
1571
      for (ii = 0; ii < Fww * Fhh; ii++)                                   //  copy data from sa_edgedist[]
 
1572
      {                                                                    //    to sa_pixmap[]
 
1573
         if (sa_pixmap[ii] < 2) continue;                                  //  skip outside and edge pixels
 
1574
         sa_pixmap[ii] = sa_edgedist[ii];                                  //  interior pixel edge distance
 
1575
      }
 
1576
   }
 
1577
 
 
1578
   zdialog_free(zd);                                                       //  kill dialog
 
1579
   zfree(sa_edgedist);                                                     //  free memory
 
1580
   zfree(sa_edgepx);
 
1581
   zfree(sa_edgepy);
 
1582
 
 
1583
   if (Fkillfunc) {
 
1584
      Fkillfunc = 0;
 
1585
      sa_calced = 0;
 
1586
      if (zdsela) zdialog_stuff(zdsela,"blendwidth",0);                    //  reset blend width    v.11.01
 
1587
   }
 
1588
 
 
1589
   sa_calced = 1;                                                          //  edge calculation available
 
1590
 
 
1591
   mwpaint2();
 
1592
   return;
 
1593
}
 
1594
 
 
1595
 
 
1596
//  dialog event and completion callback function
 
1597
 
 
1598
int edgecalc_dialog_event(zdialog *zd, cchar *event)                       //  respond to user cancel
 
1599
{
 
1600
   Fkillfunc = 1;
 
1601
   printf("edge calc killed \n");
 
1602
   return 0;
 
1603
}
 
1604
 
 
1605
 
 
1606
void * edgecalc_thread(void *arg)                                          //  worker thread function
 
1607
{                                                                          //  new algorithm    v.11.05
 
1608
   using namespace sa_edgecalc_names;
 
1609
   
 
1610
   void  edgecalc_f1(int px, int py);
 
1611
 
 
1612
   int      index = *((int *) (arg));
 
1613
   int      midx, midy, radx, rady, rad;
 
1614
   int      ii, px, py;
 
1615
   
 
1616
   midx = (sa_maxx + sa_minx) / 2;
 
1617
   midy = (sa_maxy + sa_miny) / 2;
 
1618
   radx = (sa_maxx - sa_minx) / 2 + 1;
 
1619
   rady = (sa_maxy - sa_miny) / 2 + 1;
 
1620
   px = midx;                                                              //  center of enclosing rectangle
 
1621
   py = midy;   
 
1622
 
 
1623
   ii = py * Fww + px;
 
1624
   if (sa_pixmap[ii]) edgecalc_f1(px,py);                                  //  do center pixel first
 
1625
 
 
1626
   for (rad = 1; rad < radx || rad < rady; rad++)                          //  expanding square from the center
 
1627
   {
 
1628
      for (px = midx-rad; px <= midx+rad; px += 2 * rad)                   //  process edges only, interior already done
 
1629
      for (py = midy-rad+index; py <= midy+rad; py += Nwt)
 
1630
      {
 
1631
         if (px < 0 || px > Fww-1) continue;
 
1632
         if (py < 0 || py > Fhh-1) continue;
 
1633
         ii = py * Fww + px;
 
1634
         if (! sa_pixmap[ii]) continue;
 
1635
         if (sa_edgedist[ii]) continue;
 
1636
         edgecalc_f1(px,py);
 
1637
         if (Fkillfunc) exit_wthread();
 
1638
      }
 
1639
 
 
1640
      for (py = midy-rad; py <= midy+rad; py += 2 * rad)
 
1641
      for (px = midx-rad+index; px <= midx+rad; px += Nwt)
 
1642
      {
 
1643
         if (px < 0 || px > Fww-1) continue;
 
1644
         if (py < 0 || py > Fhh-1) continue;
 
1645
         ii = py * Fww + px;
 
1646
         if (! sa_pixmap[ii]) continue;
 
1647
         if (sa_edgedist[ii]) continue;
 
1648
         edgecalc_f1(px,py);
 
1649
         if (Fkillfunc) exit_wthread();
 
1650
      }
 
1651
   }
 
1652
 
 
1653
   exit_wthread();
 
1654
   return 0;                                                               //  not executed, stop gcc warning
 
1655
}
 
1656
 
 
1657
 
 
1658
//  Find the nearest edge pixel for a given pixel.
 
1659
//  For all pixels in a line from the given pixel to the edge pixel, 
 
1660
//  the same edge pixel is used to compute edge distance.
 
1661
 
 
1662
void edgecalc_f1(int px1, int py1)
 
1663
{
 
1664
   using namespace sa_edgecalc_names;
 
1665
   
 
1666
   int      ii, px2, py2, mindist;
 
1667
   uint     dist2, mindist2;
 
1668
   int      epx, epy, pxm, pym, dx, dy, inc;
 
1669
   double   slope;
 
1670
   
 
1671
   mindist = 9999;
 
1672
   mindist2 = mindist * mindist;
 
1673
   epx = epy = 0;
 
1674
 
 
1675
   for (ii = 0; ii < sa_Nedge; ii++)                                       //  loop all edge pixels
 
1676
   {
 
1677
      px2 = sa_edgepx[ii];
 
1678
      py2 = sa_edgepy[ii];
 
1679
      dx = px2 - px1;
 
1680
      if (dx >= mindist) continue;                                         //  speedup          v.11.05
 
1681
      dy = py2 - py1;
 
1682
      if (dy >= mindist) continue;
 
1683
      dist2 = dx*dx + dy*dy;                                               //  avoid sqrt()
 
1684
      if (dist2 < mindist2) {
 
1685
         mindist2 = dist2;                                                 //  remember minimum
 
1686
         epx = px2;                                                        //  remember nearest edge pixel
 
1687
         mindist = sqrt(dist2);
 
1688
         epy = py2;
 
1689
      }
 
1690
   }
 
1691
   
 
1692
   if (abs(epy - py1) > abs(epx - px1)) {                                  //  find all pixels along a line
 
1693
      slope = 1.0 * (epx - px1) / (epy - py1);                             //    to the edge pixel
 
1694
      if (epy > py1) inc = 1;
 
1695
      else inc = -1;
 
1696
      for (pym = py1; pym != epy; pym += inc) {
 
1697
         pxm = px1 + slope * (pym - py1);
 
1698
         ii = pym * Fww + pxm;
 
1699
         if (sa_edgedist[ii]) break;
 
1700
         dx = epx - pxm;                                                   //  calculate distance to edge
 
1701
         dy = epy - pym;
 
1702
         dist2 = sqrt(dx*dx + dy*dy) + 0.5;
 
1703
         sa_edgedist[ii] = dist2;                                          //  save
 
1704
         SB_done++;                                                        //  track progress            v.11.06
 
1705
      }
 
1706
   }
 
1707
 
 
1708
   else {
 
1709
      slope = 1.0 * (epy - py1) / (epx - px1);
 
1710
      if (epx > px1) inc = 1;
 
1711
      else inc = -1;
 
1712
      for (pxm = px1; pxm != epx; pxm += inc) {
 
1713
         pym = py1 + slope * (pxm - px1);
 
1714
         ii = pym * Fww + pxm;
 
1715
         if (sa_edgedist[ii]) break;
 
1716
         dx = epx - pxm;
 
1717
         dy = epy - pym;
 
1718
         dist2 = sqrt(dx*dx + dy*dy) + 0.5;
 
1719
         sa_edgedist[ii] = dist2;
 
1720
         SB_done++;
 
1721
      }
 
1722
   }
 
1723
 
 
1724
   return;
 
1725
}
 
1726
 
 
1727
 
 
1728
/**************************************************************************
 
1729
   select area copy and paste menu functions
 
1730
***************************************************************************/
 
1731
 
 
1732
PXM      *sacp_image16 = 0;                                                //  select area pixmap image
 
1733
PXM      *sacp_info16 = 0;                                                 //  opacity and edge distance
 
1734
int      sacp_ww, sacp_hh;                                                 //  original dimensions
 
1735
 
 
1736
PXM      *sacpR_image16 = 0;                                               //  resized/rotated image
 
1737
PXM      *sacpR_info16 = 0;                                                //  resized/rotated info
 
1738
int      sacpR_ww, sacpR_hh;                                               //  resized/rotated dimensions
 
1739
 
 
1740
double   sacp_resize;                                                      //  size, 1.0 = original size
 
1741
double   sacp_angle;                                                       //  angle of rotation, -180 to +180
 
1742
int      sacp_orgx, sacp_orgy;                                             //  origin in target image
 
1743
double   sacp_blend;                                                       //  edge blend with target image
 
1744
 
 
1745
 
 
1746
//  copy selected area, save in memory
 
1747
 
 
1748
void m_select_copy(GtkWidget *, cchar *menu)                               //  overhauled    v.11.02
 
1749
{
 
1750
   int      ii, px, py;
 
1751
   int      pxmin, pxmax, pymin, pymax;
 
1752
   uint16   *pix1, *pix2;
 
1753
 
 
1754
   if (menu) zfuncs::F1_help_topic = "area_copy_paste";
 
1755
 
 
1756
   if (sa_mode == 7) return;                                               //  a whole image area         v.11.01
 
1757
   if (! Factivearea) sa_finish();                                         //  finish area if not already
 
1758
   if (! Factivearea) return;
 
1759
   sa_edgecalc();                                                          //  do edge calc if not already
 
1760
   sa_show(0);
 
1761
   
 
1762
   pxmin = Fww;
 
1763
   pxmax = 0;
 
1764
   pymin = Fhh;
 
1765
   pymax = 0;
 
1766
 
 
1767
   for (ii = 0; ii < Fww * Fhh; ii++)                                      //  find pixels in select area
 
1768
   {                                                                       //  v.9.6
 
1769
      if (! sa_pixmap[ii]) continue;
 
1770
      py = ii / Fww;
 
1771
      px = ii - py * Fww;
 
1772
      if (px > pxmax) pxmax = px;                                          //  find enclosing rectangle
 
1773
      if (px < pxmin) pxmin = px;
 
1774
      if (py > pymax) pymax = py;
 
1775
      if (py < pymin) pymin = py;
 
1776
   }
 
1777
   
 
1778
   PXM_free(sacp_image16);                                                 //  free prior if any
 
1779
   PXM_free(sacp_info16);
 
1780
   PXM_free(sacpR_image16);
 
1781
   PXM_free(sacpR_info16);
 
1782
   
 
1783
   sacp_ww = pxmax - pxmin + 1;                                            //  new area image PXM
 
1784
   sacp_hh = pymax - pymin + 1;
 
1785
   sacp_image16 = PXM_make(sacp_ww,sacp_hh,16);
 
1786
   sacp_info16 = PXM_make(sacp_ww,sacp_hh,16);                             //  new info PXM
 
1787
   
 
1788
   for (ii = 0; ii < Fww * Fhh; ii++)                                      //  find pixels in select area
 
1789
   {
 
1790
      if (! sa_pixmap[ii]) continue;                                       //  0/1/2+ = outside/edge/inside edge distance
 
1791
      py = ii / Fww;
 
1792
      px = ii - py * Fww;
 
1793
      pix1 = PXMpix(Fpxm16,px,py);                                         //  copy pixels into image PXM
 
1794
      px = px - pxmin;
 
1795
      py = py - pymin;
 
1796
      pix2 = PXMpix(sacp_image16,px,py);
 
1797
      pix2[0] = pix1[0];
 
1798
      pix2[1] = pix1[1];
 
1799
      pix2[2] = pix1[2];
 
1800
      pix2 = PXMpix(sacp_info16,px,py);                                    //  build info PXM      v.11.02
 
1801
      pix2[0] = 65535;                                                     //  opacity
 
1802
      pix2[1] = sa_pixmap[ii];                                             //  edge distance
 
1803
      pix2[2] = 0;
 
1804
   }
 
1805
 
 
1806
   return;
 
1807
}
 
1808
 
 
1809
 
 
1810
//  paste selected area into current image
 
1811
//  this is an edit function - select area image is copied into main image
 
1812
 
 
1813
int      sacp_porg = 0;                                                    //  pasted area is present
 
1814
int      sacp_porgx, sacp_porgy;                                           //  pasted area origin in image
 
1815
int      sacp_pww, sacp_phh;                                               //  pasted area dimensions
 
1816
 
 
1817
editfunc    EFpaste;
 
1818
 
 
1819
void m_select_paste(GtkWidget *, cchar *menu)                              //  menu function
 
1820
{
 
1821
   int   select_paste_dialog_event(zdialog *, cchar *event);
 
1822
   void  select_paste_mousefunc();
 
1823
 
 
1824
   cchar  *dragmess = ZTX("position with mouse click/drag");
 
1825
 
 
1826
   if (menu) zfuncs::F1_help_topic = "area_copy_paste";
 
1827
 
 
1828
   if (! sacp_image16) return;                                             //  nothing to paste
 
1829
   sa_unselect();                                                          //  unselect area if present
 
1830
   
 
1831
   EFpaste.funcname = "paste";
 
1832
   if (! edit_setup(EFpaste)) return;                                      //  setup edit for paste
 
1833
   
 
1834
   sacp_resize = 1.0;                                                      //  size = 1x
 
1835
   sacp_blend = 1;                                                         //  edge blend = 1
 
1836
   sacp_angle = 0;                                                         //  angle = 0
 
1837
 
 
1838
   PXM_free(sacpR_image16);                                                //  free prior if any
 
1839
   PXM_free(sacpR_info16);
 
1840
 
 
1841
   sacpR_ww = sacp_ww;                                                     //  setup resized paste image
 
1842
   sacpR_hh = sacp_hh;                                                     //  (initially 1x, 0 rotation)
 
1843
   sacpR_image16 = PXM_copy(sacp_image16);
 
1844
   sacpR_info16 = PXM_copy(sacp_info16);
 
1845
   
 
1846
   sacp_porg = 0;                                                          //  no image paste location yet
 
1847
   
 
1848
   CEF->zd = zdialog_new(ZTX("Paste Image"),mWin,Bdone,Bcancel,null);
 
1849
   zdialog_add_widget(CEF->zd,"hbox","hb0","dialog",0,"space=8");
 
1850
   zdialog_add_widget(CEF->zd,"label","lab1","hb0",dragmess,"space=8");
 
1851
   zdialog_add_widget(CEF->zd,"check","mymouse","hb0",BmyMouse);
 
1852
 
 
1853
   zdialog_add_widget(CEF->zd,"hbox","hbres","dialog",0,"space=5");
 
1854
   zdialog_add_widget(CEF->zd,"label","labres","hbres","resize");
 
1855
   zdialog_add_widget(CEF->zd,"button","+.1%","hbres","+.1%");
 
1856
   zdialog_add_widget(CEF->zd,"button","+1%","hbres","+1%");
 
1857
   zdialog_add_widget(CEF->zd,"button","+10%","hbres","+10%");
 
1858
   zdialog_add_widget(CEF->zd,"button","-.1%","hbres","-.1%");
 
1859
   zdialog_add_widget(CEF->zd,"button","-1%","hbres","-1%");
 
1860
   zdialog_add_widget(CEF->zd,"button","-10%","hbres","-10%");
 
1861
 
 
1862
   zdialog_add_widget(CEF->zd,"hbox","hbang","dialog",0,"space=5");        //  rotation  v.11.02
 
1863
   zdialog_add_widget(CEF->zd,"label","labang","hbang",ZTX("angle"));
 
1864
   zdialog_add_widget(CEF->zd,"button","+.1°","hbang","+.1°");
 
1865
   zdialog_add_widget(CEF->zd,"button","+1°","hbang","+1°");
 
1866
   zdialog_add_widget(CEF->zd,"button","+10°","hbang","+10°");
 
1867
   zdialog_add_widget(CEF->zd,"button","-.1°","hbang","-.1°");
 
1868
   zdialog_add_widget(CEF->zd,"button","-1°","hbang","-1°");
 
1869
   zdialog_add_widget(CEF->zd,"button","-10°","hbang","-10°");
 
1870
 
 
1871
   zdialog_add_widget(CEF->zd,"hbox","hbbl","dialog",0,"space=5");
 
1872
   zdialog_add_widget(CEF->zd,"label","lab2","hbbl","edge blend");
 
1873
   zdialog_add_widget(CEF->zd,"hscale","blend","hbbl","0|20|0.3|0","expand");     //  v.11.06
 
1874
 
 
1875
   zdialog_help(CEF->zd,"area_copy_paste");                                //  zdialog help topic        v.11.08
 
1876
   zdialog_run(CEF->zd,select_paste_dialog_event,"80/20");                 //  v.11.07
 
1877
 
 
1878
   takeMouse(CEF->zd,select_paste_mousefunc,0);                            //  connect mouse function
 
1879
   zdialog_stuff(CEF->zd,"mymouse",1);                                     //  v.11.03
 
1880
 
 
1881
   return;
 
1882
}
 
1883
 
 
1884
 
 
1885
//  Dialog event and completion callback function
 
1886
//  Get dialog values and convert image. When done, commit edited image 
 
1887
//  (with pasted area) and set up a new select area for the pasted area,
 
1888
//  allowing further editing of the area.
 
1889
 
 
1890
int select_paste_dialog_event(zdialog *zd, cchar *event)
 
1891
{
 
1892
   void  select_paste_mousefunc();
 
1893
   void  select_paste_pixmap();
 
1894
   void  select_paste_makearea();
 
1895
 
 
1896
   int      mymouse, ww, hh;
 
1897
   PXM      *pxm_temp;
 
1898
   
 
1899
   if (zd->zstat)                                                          //  dialog completed
 
1900
   {
 
1901
      freeMouse();                                                         //  disconnect mouse
 
1902
 
 
1903
      if (zd->zstat != 1 || ! sacp_porg) {                                 //  cancel paste
 
1904
         edit_cancel(EFpaste);                                             //  cancel edit, restore image
 
1905
         sa_unselect();
 
1906
         return 0;
 
1907
      }
 
1908
      
 
1909
      edit_done(EFpaste);                                                  //  commit the edit (pasted image)
 
1910
      select_paste_makearea();                                             //  make equivalent select area
 
1911
      PXM_free(sacpR_image16);                                             //  free memory
 
1912
      PXM_free(sacpR_info16);
 
1913
      return 0;
 
1914
   }
 
1915
 
 
1916
   if (strEqu(event,"mymouse")) {                                          //  toggle mouse capture      v.10.12
 
1917
      zdialog_fetch(zd,"mymouse",mymouse);
 
1918
      if (mymouse) takeMouse(zd,select_paste_mousefunc,0);
 
1919
      else freeMouse();
 
1920
      return 0;
 
1921
   }
 
1922
 
 
1923
   if (strstr(event,"%") || strstr(event,"°"))                             //  new size or angle
 
1924
   {
 
1925
      if (strEqu(event,"+.1%")) sacp_resize *= 1.001;                      
 
1926
      if (strEqu(event,"+1%")) sacp_resize *= 1.01;
 
1927
      if (strEqu(event,"+10%")) sacp_resize *= 1.10;
 
1928
      if (strEqu(event,"-.1%")) sacp_resize *= 0.999001;
 
1929
      if (strEqu(event,"-1%")) sacp_resize *= 0.990099;
 
1930
      if (strEqu(event,"-10%")) sacp_resize *= 0.909091;                   //  -10% is really 1.0/1.10
 
1931
 
 
1932
      if (strEqu(event,"+.1°")) sacp_angle += 0.1;                         //  rotation   v.11.02
 
1933
      if (strEqu(event,"+1°")) sacp_angle += 1.0;
 
1934
      if (strEqu(event,"+10°")) sacp_angle += 10.0;
 
1935
      if (strEqu(event,"-.1°")) sacp_angle -= 0.1;
 
1936
      if (strEqu(event,"-1°")) sacp_angle -= 1.0;
 
1937
      if (strEqu(event,"-10°")) sacp_angle -= 10.0;
 
1938
 
 
1939
      PXM_free(sacpR_image16);                                             //  free prior if any
 
1940
      PXM_free(sacpR_info16);
 
1941
 
 
1942
      ww = sacp_resize * sacp_ww;                                          //  new size
 
1943
      hh = sacp_resize * sacp_hh;
 
1944
 
 
1945
      pxm_temp = PXM_rescale(sacp_image16,ww,hh);                          //  resized area image
 
1946
      sacpR_image16 = PXM_rotate(pxm_temp,sacp_angle);                     //  rotated area image
 
1947
      PXM_free(pxm_temp);
 
1948
 
 
1949
      pxm_temp = PXM_rescale(sacp_info16,ww,hh);                           //  resized area info
 
1950
      sacpR_info16 = PXM_rotate(pxm_temp,sacp_angle);                      //  rotated/resized area info
 
1951
      PXM_free(pxm_temp);
 
1952
 
 
1953
      sacpR_ww = sacpR_image16->ww;                                        //  size after resize/rotate
 
1954
      sacpR_hh = sacpR_image16->hh;
 
1955
 
 
1956
      select_paste_pixmap();                                               //  copy onto target image
 
1957
   }
 
1958
 
 
1959
   if (strEqu(event,"blend") && sacp_porg) {
 
1960
      zdialog_fetch(zd,"blend",sacp_blend);                                //  new edge blend distance
 
1961
      select_paste_pixmap();                                               //  copy onto target image
 
1962
   }
 
1963
 
 
1964
   CEF->Fmod = 1;                                                          //  image is modified
 
1965
   mwpaint2();
 
1966
   return 0;
 
1967
}
 
1968
 
 
1969
 
 
1970
//  convert the pasted image area into an equivalent select area by mouse
 
1971
 
 
1972
void select_paste_makearea()
 
1973
{
 
1974
   int      cc, ii;
 
1975
   int      px1, py1, px2, py2;
 
1976
   uint16   *pix2;
 
1977
   
 
1978
   sa_unselect();                                                          //  unselect old area
 
1979
 
 
1980
   cc = Fww * Fhh * sizeof(uint16);
 
1981
   sa_pixmap = (uint16 *) zmalloc(cc,"sa_paste");                          //  pixel map for new area
 
1982
   memset(sa_pixmap,0,cc);
 
1983
   
 
1984
   for (py1 = 0; py1 < sacpR_hh; py1++)                                    //  map non-transparent pixels
 
1985
   for (px1 = 0; px1 < sacpR_ww; px1++)                                    //    into sa_pixmap[]
 
1986
   {
 
1987
      pix2 = PXMpix(sacpR_info16,px1,py1);                                 //  opacity and edge distance
 
1988
      if (pix2[0] == 0) continue;                                          //  transparent
 
1989
      px2 = px1 + sacp_orgx;
 
1990
      py2 = py1 + sacp_orgy;
 
1991
      if (px2 < 0 || px2 > Fww-1) continue;                                //  parts may be beyond edges
 
1992
      if (py2 < 0 || py2 > Fhh-1) continue;
 
1993
      ii = py2 * Fww + px2;
 
1994
      sa_pixmap[ii] = 1;
 
1995
   }
 
1996
 
 
1997
   sa_stat = 1;
 
1998
   sa_mode = 6;                                                            //  equivalent select-mouse area
 
1999
   sa_fww = Fww;                                                           //  v.11.08
 
2000
   sa_fhh = Fhh;
 
2001
   sa_finish_auto();                                                       //  v.11.04
 
2002
   sa_show(1);
 
2003
   return;
 
2004
}
 
2005
 
 
2006
 
 
2007
//  mouse function - follow mouse drags and move pasted area accordingly
 
2008
 
 
2009
void select_paste_mousefunc()
 
2010
{
 
2011
   void  select_paste_pixmap();
 
2012
 
 
2013
   int            mx1, my1, mx2, my2;
 
2014
   static int     mdx0, mdy0, mdx1, mdy1;
 
2015
   
 
2016
   if (LMclick) {                                                          //  left mouse click
 
2017
      LMclick = 0;
 
2018
      sacp_orgx = Mxclick - sacpR_ww / 2;                                  //  position image at mouse   v.10.11
 
2019
      sacp_orgy = Myclick - sacpR_hh / 2;
 
2020
      select_paste_pixmap();
 
2021
      CEF->Fmod = 1;                                                       //  image is modified
 
2022
   }
 
2023
 
 
2024
   if (! sacp_porg) return;                                                //  no select area paste yet
 
2025
 
 
2026
   if (Mxposn < sacp_orgx || Mxposn > sacp_orgx + sacpR_ww ||              //  mouse outside select area
 
2027
      Myposn < sacp_orgy || Myposn > sacp_orgy + sacpR_hh)
 
2028
      gdk_window_set_cursor(drWin->window,0);                              //  set normal cursor         v.11.03
 
2029
   else 
 
2030
      gdk_window_set_cursor(drWin->window,dragcursor);                     //  set drag cursor           v.11.03
 
2031
 
 
2032
   if (Mxdrag + Mydrag == 0) return;                                       //  no drag underway
 
2033
 
 
2034
   if (Mxdown != mdx0 || Mydown != mdy0) {                                 //  new drag initiated
 
2035
      mdx0 = mdx1 = Mxdown;
 
2036
      mdy0 = mdy1 = Mydown;
 
2037
   }
 
2038
 
 
2039
   mx1 = mdx1;                                                             //  drag start
 
2040
   my1 = mdy1;
 
2041
   mx2 = Mxdrag;                                                           //  drag position
 
2042
   my2 = Mydrag;
 
2043
   mdx1 = mx2;                                                             //  next drag start
 
2044
   mdy1 = my2;
 
2045
   
 
2046
   sacp_orgx += (mx2 - mx1);                                               //  move position of select area
 
2047
   sacp_orgy += (my2 - my1);                                               //    by mouse drag amount
 
2048
   select_paste_pixmap();                                                  //  re-copy area to new position
 
2049
   CEF->Fmod = 1;                                                          //  image is modified
 
2050
 
 
2051
   return;      
 
2052
}
 
2053
 
 
2054
 
 
2055
//  copy select area into edit image, starting at sacp_orgx/y
 
2056
 
 
2057
void select_paste_pixmap()                                                 //  overhauled    v.11.02
 
2058
{
 
2059
   int      px1, py1, px3, py3, opac, dist;
 
2060
   uint16   *pix1, *pix3;
 
2061
   double   f1, f2;
 
2062
   
 
2063
   if (sacp_porg)                                                          //  prior area overlap rectangle
 
2064
   {
 
2065
      for (py1 = 0; py1 < sacp_phh; py1++)                                 //  restore original image pixels   v.10.11
 
2066
      for (px1 = 0; px1 < sacp_pww; px1++)
 
2067
      {
 
2068
         px3 = px1 + sacp_porgx;
 
2069
         py3 = py1 + sacp_porgy;
 
2070
         if (px3 < 0 || px3 >= E3ww) continue;                             //  parts may be beyond edges
 
2071
         if (py3 < 0 || py3 >= E3hh) continue;
 
2072
         pix1 = PXMpix(E1pxm16,px3,py3);
 
2073
         pix3 = PXMpix(E3pxm16,px3,py3);
 
2074
         pix3[0] = pix1[0];
 
2075
         pix3[1] = pix1[1];
 
2076
         pix3[2] = pix1[2];
 
2077
      }
 
2078
   }
 
2079
   
 
2080
   for (py1 = 0; py1 < sacpR_hh; py1++)                                    //  copy paste area pixels to new 
 
2081
   for (px1 = 0; px1 < sacpR_ww; px1++)                                    //    image overlap rectangle
 
2082
   {
 
2083
      pix1 = PXMpix(sacpR_info16,px1,py1);                                 //  opacity and edge distance
 
2084
      opac = pix1[0];
 
2085
      dist = pix1[1];
 
2086
      if (opac == 0) continue;                                             //  skip transparent pixel
 
2087
      px3 = px1 + sacp_orgx;
 
2088
      py3 = py1 + sacp_orgy;
 
2089
      if (px3 < 0 || px3 >= E3ww) continue;                                //  parts may be beyond edges
 
2090
      if (py3 < 0 || py3 >= E3hh) continue;
 
2091
 
 
2092
      pix1 = PXMpix(sacpR_image16,px1,py1);                                //  paste image pixel
 
2093
      pix3 = PXMpix(E3pxm16,px3,py3);                                      //  target image pixel
 
2094
      if (dist > sacp_blend) f1 = 1.0;                                     //  minor bugfix             v.11.06
 
2095
      else f1 = 1.0 * dist / sacp_blend;                                   //  opacity reduction from edge blend
 
2096
      f1 = f1 * opac / 65535.0;                                            //  opacity reduction from resize/rescale
 
2097
      f2 = 1.0 - f1;
 
2098
      pix3[0] = f1 * pix1[0] + f2 * pix3[0];                               //  blend paste and target images
 
2099
      pix3[1] = f1 * pix1[1] + f2 * pix3[1];
 
2100
      pix3[2] = f1 * pix1[2] + f2 * pix3[2];
 
2101
   }
 
2102
 
 
2103
   mwpaint3(sacp_porgx,sacp_porgy,sacp_pww,sacp_phh);                      //  update window for old overlap area
 
2104
   mwpaint3(sacp_orgx,sacp_orgy,sacpR_ww,sacpR_hh);                        //  update window for new overlap area
 
2105
 
 
2106
   sacp_porgx = sacp_orgx;                                                 //  remember location for next call
 
2107
   sacp_porgy = sacp_orgy;
 
2108
   sacp_pww = sacpR_ww;
 
2109
   sacp_phh = sacpR_hh;
 
2110
   sacp_porg = 1;
 
2111
   return;
 
2112
}
 
2113
 
 
2114
 
 
2115
/**************************************************************************
 
2116
   select area load from file and save to file functions           v.9.9
 
2117
***************************************************************************/
 
2118
 
 
2119
//  Load a select area from a disk file and paste into current image.
 
2120
 
 
2121
void m_select_open(GtkWidget *, cchar *)
 
2122
{
 
2123
   char     *pfile1, *pfile2, *pp;
 
2124
 
 
2125
   zfuncs::F1_help_topic = "area_open_save";                               //  v.10.8
 
2126
 
 
2127
   pp = zgetfile1(ZTX("load select area from a file"),"open",saved_areas_dirk);
 
2128
   if (! pp) return;
 
2129
 
 
2130
   pfile1 = strdupz(pp,8,"select_open");
 
2131
   zfree(pp);
 
2132
   pp = strrchr(pfile1,'/');
 
2133
   if (pp) pp = strrchr(pp,'.');
 
2134
   if (pp) strcpy(pp,".tiff");
 
2135
   else strcat(pfile1,".tiff");
 
2136
 
 
2137
   pfile2 = strdupz(pfile1,0,"select_open");
 
2138
   pp = strrchr(pfile2,'.');
 
2139
   strcpy(pp,".info");
 
2140
   
 
2141
   PXM_free(sacp_image16);                                                 //  free prior if any
 
2142
   PXM_free(sacp_info16);
 
2143
 
 
2144
   sacp_image16 = TIFFread(pfile1);                                        //  .tiff file --> image PXM
 
2145
   if (! sacp_image16) goto fail;
 
2146
 
 
2147
   sacp_info16 = TIFFread(pfile2);                                         //  .info file --> info PXM
 
2148
   if (! sacp_info16) goto fail;
 
2149
 
 
2150
   zfree(pfile1);
 
2151
   zfree(pfile2);
 
2152
 
 
2153
   sacp_ww = sacp_image16->ww;                                             //  paste into current image
 
2154
   sacp_hh = sacp_image16->hh;
 
2155
   m_select_paste(0,0);
 
2156
   return;
 
2157
 
 
2158
fail:
 
2159
   zfree(pfile1);
 
2160
   zfree(pfile2);
 
2161
   zmessageACK(mWin,ZTX("cannot open .tiff and .info files"));
 
2162
   return;
 
2163
}
 
2164
 
 
2165
 
 
2166
//  save a select area as a disk file
 
2167
 
 
2168
void m_select_save(GtkWidget *, cchar *)
 
2169
{
 
2170
   char        *pfile1, *pfile2, *pp;
 
2171
 
 
2172
   zfuncs::F1_help_topic = "area_open_save";                               //  v.10.11
 
2173
 
 
2174
   if (sa_mode == 7) return;                                               //  a whole image area         v.11.01
 
2175
   if (! Factivearea) sa_finish();                                         //  finish select area if not already
 
2176
   if (! Factivearea) return;                                              //  v.11.06.1
 
2177
   m_select_copy(0,0);                                                     //  copy select area to memory
 
2178
   if (! sacp_image16) return;
 
2179
   
 
2180
   pp = zgetfile1(ZTX("save select area to a file"),"save",saved_areas_dirk);
 
2181
   if (! pp) return;
 
2182
 
 
2183
   pfile1 = strdupz(pp,8,"select_save");
 
2184
   zfree(pp);
 
2185
   pp = strrchr(pfile1,'/');
 
2186
   if (pp) pp = strrchr(pp,'.');
 
2187
   if (pp) strcpy(pp,".tiff");
 
2188
   else strcat(pfile1,".tiff");
 
2189
 
 
2190
   pfile2 = strdupz(pfile1,0,"select_save");
 
2191
   pp = strrchr(pfile2,'.');
 
2192
   strcpy(pp,".info");
 
2193
 
 
2194
   TIFFwrite(sacp_image16,pfile1);                                         //  image PXM --> .tiff file
 
2195
   TIFFwrite(sacp_info16,pfile2);                                          //  info PXM --> .info file
 
2196
 
 
2197
   return;
 
2198
}
 
2199
 
 
2200
 
 
2201
/**************************************************************************/
 
2202
 
 
2203
//  Select the whole image as an area.
 
2204
//  Set "edge distance" 1 to 255 from pixel or RGB color brightness.
 
2205
//  Set "blend width" to 255
 
2206
//  Edit function coefficient = edge distance / blend width.
 
2207
 
 
2208
spldat   * select_whole_image_curve;
 
2209
 
 
2210
void m_select_whole_image(GtkWidget *, cchar *)                            //  new  v.11.01
 
2211
{
 
2212
   int    select_whole_image_event(zdialog *, cchar *event);               //  dialog event and completion func
 
2213
   void   select_whole_image_curve_update(int spc);                        //  curve update callback function
 
2214
 
 
2215
   cchar    *title = ZTX("Select Whole Image");
 
2216
   cchar    *legend = ZTX("Edit Function Amplifier");
 
2217
 
 
2218
   zfuncs::F1_help_topic = "select_whole_image";
 
2219
 
 
2220
   if (! curr_file) return;                                                //  no image
 
2221
   if (zdsela) return;                                                     //  select dialog already active
 
2222
   if (Fpreview) edit_fullsize();                                          //  use full-size image
 
2223
 
 
2224
/***
 
2225
             Edit Function Amplifier
 
2226
             ------------------------------------------
 
2227
            |                                          |
 
2228
            |                                          |
 
2229
            |           curve drawing area             |
 
2230
            |                                          |
 
2231
            |                                          |
 
2232
             ------------------------------------------
 
2233
             darker areas                 lighter areas
 
2234
 
 
2235
             [+++]  [---]  [+ -]  [- +]  [+-+]  [-+-]
 
2236
             (o) Brightness  (o) Red  (o) Green  (o) Blue
 
2237
             Curve File: [ Open ] [ Save ]
 
2238
                                              [ Done ]
 
2239
***/
 
2240
 
 
2241
   zdsela = zdialog_new(title,mWin,Bdone,null);
 
2242
 
 
2243
   zdialog_add_widget(zdsela,"label","labt","dialog",legend);
 
2244
   zdialog_add_widget(zdsela,"frame","fr1","dialog",0,"expand");
 
2245
   zdialog_add_widget(zdsela,"hbox","hba","dialog");
 
2246
   zdialog_add_widget(zdsela,"label","labda","hba",Bdarker,"space=5");
 
2247
   zdialog_add_widget(zdsela,"label","space","hba",0,"expand");
 
2248
   zdialog_add_widget(zdsela,"label","labba","hba",Blighter,"space=5");
 
2249
   zdialog_add_widget(zdsela,"hbox","hbb","dialog",0,"space=5");
 
2250
   zdialog_add_widget(zdsela,"button","b +++","hbb","+++");
 
2251
   zdialog_add_widget(zdsela,"button","b ---","hbb","‒ ‒ ‒");
 
2252
   zdialog_add_widget(zdsela,"button","b +-", "hbb"," + ‒ ");
 
2253
   zdialog_add_widget(zdsela,"button","b -+", "hbb"," ‒ + ");
 
2254
   zdialog_add_widget(zdsela,"button","b +-+","hbb","+ ‒ +");
 
2255
   zdialog_add_widget(zdsela,"button","b -+-","hbb","‒ + ‒");
 
2256
 
 
2257
   zdialog_add_widget(zdsela,"hbox","hbbr","dialog",0,"space=5");
 
2258
   zdialog_add_widget(zdsela,"radio","bright","hbbr",Bbrightness,"space=5");
 
2259
   zdialog_add_widget(zdsela,"radio","red","hbbr",Bred,"space=5");
 
2260
   zdialog_add_widget(zdsela,"radio","green","hbbr",Bgreen,"space=5");
 
2261
   zdialog_add_widget(zdsela,"radio","blue","hbbr",Bblue,"space=5");
 
2262
 
 
2263
   zdialog_add_widget(zdsela,"hbox","hbcf","dialog",0,"space=5");
 
2264
   zdialog_add_widget(zdsela,"label","labcf","hbcf",Bcurvefile,"space=5");
 
2265
   zdialog_add_widget(zdsela,"button","load","hbcf",Bopen,"space=5");
 
2266
   zdialog_add_widget(zdsela,"button","save","hbcf",Bsave,"space=5");
 
2267
 
 
2268
   GtkWidget *frame = zdialog_widget(zdsela,"fr1");                        //  setup for curve editing
 
2269
   spldat *sd = splcurve_init(frame,select_whole_image_curve_update);      //  v.11.01
 
2270
   select_whole_image_curve = sd;
 
2271
 
 
2272
   sd->Nspc = 1;
 
2273
   sd->vert[0] = 0;
 
2274
   sd->nap[0] = 3;                                                         //  initial curve anchor points
 
2275
   sd->apx[0][0] = 0.01;
 
2276
   sd->apy[0][0] = 0.5;
 
2277
   sd->apx[0][1] = 0.50;
 
2278
   sd->apy[0][1] = 0.5;
 
2279
   sd->apx[0][2] = 0.99;
 
2280
   sd->apy[0][2] = 0.5;
 
2281
   splcurve_generate(sd,0);                                                //  generate curve data
 
2282
 
 
2283
   zdialog_stuff(zdsela,"bright",1);
 
2284
   zdialog_stuff(zdsela,"red",0);
 
2285
   zdialog_stuff(zdsela,"green",0);
 
2286
   zdialog_stuff(zdsela,"blue",0);
 
2287
   zdialog_stuff(zdsela,"check",0);
 
2288
 
 
2289
   sa_unselect();                                                          //  unselect current area if any
 
2290
 
 
2291
   zdialog_resize(zdsela,0,360);
 
2292
   zdialog_help(zdsela,"select_whole_image");                              //  zdialog help topic        v.11.08
 
2293
   zdialog_run(zdsela,select_whole_image_event,"80/20");                   //  run dialog - parallel        v.11.07
 
2294
   select_whole_image_event(zdsela,"init");                                //  initialize default params
 
2295
   return;
 
2296
}
 
2297
 
 
2298
 
 
2299
//  dialog event and completion function
 
2300
 
 
2301
int select_whole_image_event(zdialog *zd, cchar *event)
 
2302
{
 
2303
   int         ii, kk, cc, base, pixbright, pixdist;
 
2304
   double      px, py, xval, yval;
 
2305
   uint8       *pixel;
 
2306
   spldat      *sd = select_whole_image_curve;
 
2307
   
 
2308
   if (zd->zstat) {                                                        //  done, kill dialog
 
2309
      zdialog_free(zdsela);
 
2310
      zfree(sd);                                                           //  free curve edit memory
 
2311
      return 0;
 
2312
   }
 
2313
 
 
2314
   if (! sa_stat)
 
2315
   {
 
2316
      cc = Fww * Fhh * sizeof(uint16);                                     //  allocate sa_pixmap[] for new area
 
2317
      sa_pixmap = (uint16 *) zmalloc(cc,"sa_select_image");
 
2318
 
 
2319
      sa_minx = 0;                                                         //  enclosing rectangle
 
2320
      sa_maxx = Fww;
 
2321
      sa_miny = 0;
 
2322
      sa_maxy = Fhh;
 
2323
 
 
2324
      sa_Npixel = Fww * Fhh;
 
2325
      sa_stat = 3;                                                         //  area status = complete
 
2326
      sa_mode = 7;                                                         //  area mode = whole image
 
2327
      sa_calced = 1;                                                       //  edge calculation complete
 
2328
      sa_blend = 255;                                                      //  "blend width" = 255
 
2329
      sa_fww = Fww;                                                        //  valid image dimensions    v.11.08
 
2330
      sa_fhh = Fhh;
 
2331
      Factivearea = 1;                                                     //  area is active
 
2332
   }
 
2333
   
 
2334
   if (strEqu(event,"load")) {                                             //  load saved curve    v.11.02
 
2335
      splcurve_load(sd);
 
2336
      if (CEF && CEF->zd) zdialog_send_event(CEF->zd,"blendwidth");        //  notify edit dialog
 
2337
      return 0;
 
2338
   }
 
2339
 
 
2340
   if (strEqu(event,"save")) {                                             //  save curve to file  v.11.02
 
2341
      splcurve_save(sd);
 
2342
      return 0;
 
2343
   }
 
2344
 
 
2345
   base = 0;
 
2346
   zdialog_fetch(zd,"bright",ii);                                          //  set brightness or color to be used
 
2347
   if (ii) base = 1;
 
2348
   zdialog_fetch(zd,"red",ii);
 
2349
   if (ii) base = 2;
 
2350
   zdialog_fetch(zd,"green",ii);
 
2351
   if (ii) base = 3;
 
2352
   zdialog_fetch(zd,"blue",ii);
 
2353
   if (ii) base = 4;
 
2354
   if (! base) return 0;
 
2355
 
 
2356
   if (strnEqu(event,"b ",2)) {                                            //  button to move entire curve
 
2357
      for (ii = 0; ii < sd->nap[0]; ii++) {
 
2358
         px = sd->apx[0][ii];
 
2359
         py = sd->apy[0][ii];
 
2360
         if (strEqu(event,"b +++")) py += 0.1;
 
2361
         if (strEqu(event,"b ---")) py -= 0.1;
 
2362
         if (strEqu(event,"b +-"))  py += 0.1 - 0.2 * px;
 
2363
         if (strEqu(event,"b -+"))  py -= 0.1 - 0.2 * px;
 
2364
         if (strEqu(event,"b +-+")) py -= 0.05 - 0.2 * fabs(px-0.5);
 
2365
         if (strEqu(event,"b -+-")) py += 0.05 - 0.2 * fabs(px-0.5);
 
2366
         if (py > 1) py = 1;
 
2367
         if (py < 0) py = 0;
 
2368
         sd->apy[0][ii] = py;
 
2369
      }
 
2370
   }
 
2371
 
 
2372
   splcurve_generate(sd,0);                                                //  regenerate the curve
 
2373
   splcurve_draw(0,0,sd);
 
2374
 
 
2375
   pixel = (uint8 *) Fpxm8->bmp;
 
2376
 
 
2377
   for (ii = 0; ii < Fww * Fhh; ii++)                                      //  loop all pixels
 
2378
   {
 
2379
      pixbright = pixel[0] + pixel[1] + pixel[2] + 1;                      //  brightness of pixel, 1 - 766
 
2380
      if (base == 1) pixbright = pixbright / 3;                            //  brightness, 0 - 255       bugfix v.11.01.2
 
2381
      else if (base == 2) pixbright = 255 * pixel[0] / pixbright;          //  red part: 0 - 255 = 100% red
 
2382
      else if (base == 3) pixbright = 255 * pixel[1] / pixbright;          //  green part
 
2383
      else if (base == 4) pixbright = 255 * pixel[2] / pixbright;          //  blue part
 
2384
      xval = pixbright / 256.0;                                            //  curve x-value, 0 to 0.999
 
2385
      kk = 1000 * xval;                                                    //  speedup    v.11.06
 
2386
      if (kk > 999) kk = 999;
 
2387
      yval = sd->yval[0][kk];
 
2388
      pixdist = 255 * yval;                                                //  pixel "edge distance" 0 to 255
 
2389
      sa_pixmap[ii] = pixdist | 1;                                         //  avoid 0 (pixel outside area)
 
2390
      pixel += 3;
 
2391
   }
 
2392
 
 
2393
   if (CEF && CEF->zd) zdialog_send_event(CEF->zd,"blendwidth");           //  notify edit dialog
 
2394
 
 
2395
   return 0;
 
2396
}
 
2397
 
 
2398
 
 
2399
//  this function is called when curve is edited using mouse
 
2400
 
 
2401
void  select_whole_image_curve_update(int)
 
2402
{
 
2403
   select_whole_image_event(zdsela,"edit");
 
2404
   return;
 
2405
}
 
2406
 
 
2407
 
 
2408
/**************************************************************************/
 
2409
 
 
2410
//  select area and edit in parallel
 
2411
//  current edit function is applied to areas painted with the mouse
 
2412
//  mouse can be weak or strong, and edits are applied incrementally
 
2413
//  method: 
 
2414
//    entire image is a select area with all pixel edge distance = 0 (outside area)
 
2415
//    blendwidth = 10000
 
2416
//    pixels painted with mouse have increasing edge distance to amplify edits
 
2417
 
 
2418
int   select_edit_radius;
 
2419
int   select_edit_cpower;
 
2420
int   select_edit_epower;
 
2421
 
 
2422
void m_select_edit(GtkWidget *, cchar *)                                   //  menu function    v.11.02
 
2423
{
 
2424
   int   select_edit_dialog_event(zdialog *, cchar *event);                //  dialog event function
 
2425
   void  select_edit_mousefunc();                                          //  mouse function
 
2426
 
 
2427
   cchar    *title = ZTX("Select Area for Edits");
 
2428
   cchar    *helptext = ZTX("Press F1 for help");
 
2429
   int      cc;
 
2430
 
 
2431
   zfuncs::F1_help_topic = "select_edit";
 
2432
 
 
2433
   if (! curr_file) return;                                                //  no image
 
2434
   if (zdsela) return;                                                     //  select area already active
 
2435
   if (Fpreview) edit_fullsize();                                          //  use full-size image
 
2436
   
 
2437
   if (! Fpxm16) {                                                         //  create Fpxm16 if not already
 
2438
      mutex_lock(&Fpixmap_lock);
 
2439
      Fpxm16 = f_load(curr_file,16);
 
2440
      mutex_unlock(&Fpixmap_lock);
 
2441
      if (! Fpxm16) return;
 
2442
   }
 
2443
 
 
2444
/***
 
2445
    ____________________________________________
 
2446
   |           Press F1 for help                |
 
2447
   |                                            |
 
2448
   | mouse radius [___|v]                       |
 
2449
   | power:  center [___|v]  edge [___|v]       |
 
2450
   | [x] my mouse    [reset area]               |
 
2451
   |                                  [done]    |
 
2452
   |____________________________________________|
 
2453
   
 
2454
***/
 
2455
 
 
2456
   zdsela = zdialog_new(title,mWin,Bdone,null);
 
2457
   zdialog_add_widget(zdsela,"label","labhelp","dialog",helptext,"space=5");
 
2458
   zdialog_add_widget(zdsela,"hbox","hbr","dialog",0,"space=3");
 
2459
   zdialog_add_widget(zdsela,"label","labr","hbr",ZTX("mouse radius"),"space=5");
 
2460
   zdialog_add_widget(zdsela,"spin","radius","hbr","2|500|1|50");
 
2461
   zdialog_add_widget(zdsela,"hbox","hbt","dialog",0,"space=3");
 
2462
   zdialog_add_widget(zdsela,"label","labtc","hbt",ZTX("power:  center"),"space=5");
 
2463
   zdialog_add_widget(zdsela,"spin","center","hbt","0|100|1|50");
 
2464
   zdialog_add_widget(zdsela,"label","labte","hbt",ZTX("edge"),"space=5");
 
2465
   zdialog_add_widget(zdsela,"spin","edge","hbt","0|100|1|0");
 
2466
   zdialog_add_widget(zdsela,"hbox","hbr","dialog",0,"space=5");
 
2467
   zdialog_add_widget(zdsela,"check","mymouse","hbr",BmyMouse,"space=5");
 
2468
   zdialog_add_widget(zdsela,"button","reset","hbr",ZTX("reset area"),"space=20");
 
2469
   
 
2470
   select_edit_radius = 50;
 
2471
   select_edit_cpower = 50;
 
2472
   select_edit_epower = 0;
 
2473
 
 
2474
   sa_unselect();                                                          //  unselect current area if any
 
2475
   cc = Fww * Fhh * sizeof(uint16);                                        //  allocate sa_pixmap[] for new area
 
2476
   sa_pixmap = (uint16 *) zmalloc(cc,"sa_select_edit");
 
2477
   memset(sa_pixmap,0,cc);                                                 //  edge distance = 0 for all pixels
 
2478
 
 
2479
   sa_minx = 0;                                                            //  enclosing rectangle
 
2480
   sa_maxx = Fww;
 
2481
   sa_miny = 0;
 
2482
   sa_maxy = Fhh;
 
2483
 
 
2484
   sa_Npixel = Fww * Fhh;
 
2485
   sa_stat = 3;                                                            //  area status = complete
 
2486
   sa_mode = 7;                                                            //  area mode = whole image
 
2487
   sa_calced = 1;                                                          //  edge calculation complete
 
2488
   sa_blend = 10000;                                                       //  "blend width"
 
2489
   sa_fww = Fww;                                                           //  valid image dimensions    v.11.08
 
2490
   sa_fhh = Fhh;
 
2491
   Factivearea = 1;                                                        //  area is active
 
2492
 
 
2493
   zdialog_help(zdsela,"select_edit");                                     //  zdialog help topic        v.11.08
 
2494
   zdialog_run(zdsela,select_edit_dialog_event,"80/20");                   //  run dialog - parallel     v.11.07
 
2495
   return;
 
2496
}
 
2497
 
 
2498
 
 
2499
//  tailor whole image area to increase edit power for pixels within the mouse radius
 
2500
//  sa_pixmap[*]  = 0 = never touched by mouse
 
2501
//                = 1 = minimum edit power (barely painted)
 
2502
//                = sa_blend = maximum edit power (edit fully applied)
 
2503
 
 
2504
int select_edit_dialog_event(zdialog *zd, cchar *event)
 
2505
{
 
2506
   void  select_edit_mousefunc();                                          //  mouse function
 
2507
   int      cc, mymouse;
 
2508
   
 
2509
   if (! Factivearea) return 1;                                            //  area gone    v.11.06.1
 
2510
 
 
2511
   if (zd->zstat)                                                          //  done or cancel
 
2512
   {
 
2513
      freeMouse();                                                         //  disconnect mouse function
 
2514
      zdialog_free(zdsela);                                                //  kill dialog
 
2515
      sa_unselect();                                                       //  unselect area
 
2516
      return 0;
 
2517
   }
 
2518
 
 
2519
   if (strEqu(event,"mymouse")) {                                          //  toggle mouse capture
 
2520
      zdialog_fetch(zd,"mymouse",mymouse);
 
2521
      if (mymouse) {
 
2522
         if (! CEF) {
 
2523
            zmessageACK(mWin,ZTX("start edit function first"));            //  no edit function active
 
2524
            zdialog_stuff(zd,"mymouse",0);
 
2525
            return 1;
 
2526
         }
 
2527
         takeMouse(zd,select_edit_mousefunc,0);                            //  connect mouse function
 
2528
      }
 
2529
      else freeMouse();                                                    //  disconnect mouse
 
2530
   }
 
2531
 
 
2532
   if (strEqu(event,"radius"))
 
2533
      zdialog_fetch(zd,"radius",select_edit_radius);                       //  set mouse radius
 
2534
 
 
2535
   if (strEqu(event,"center"))
 
2536
      zdialog_fetch(zd,"center",select_edit_cpower);                       //  set mouse center power
 
2537
 
 
2538
   if (strEqu(event,"edge"))
 
2539
      zdialog_fetch(zd,"edge",select_edit_epower);                         //  set mouse edge power
 
2540
   
 
2541
   if (strEqu(event,"reset")) {
 
2542
      sa_unselect();                                                       //  unselect current area if any
 
2543
      cc = Fww * Fhh * sizeof(uint16);                                     //  allocate sa_pixmap[] for new area
 
2544
      sa_pixmap = (uint16 *) zmalloc(cc,"sa_select_edit");
 
2545
      memset(sa_pixmap,0,cc);                                              //  edge distance = 0 for all pixels
 
2546
 
 
2547
      sa_minx = 0;                                                         //  enclosing rectangle
 
2548
      sa_maxx = Fww;
 
2549
      sa_miny = 0;
 
2550
      sa_maxy = Fhh;
 
2551
 
 
2552
      sa_Npixel = Fww * Fhh;
 
2553
      sa_stat = 3;                                                         //  area status = complete
 
2554
      sa_mode = 7;                                                         //  area mode = whole image
 
2555
      sa_calced = 1;                                                       //  edge calculation complete
 
2556
      sa_blend = 10000;                                                    //  "blend width"
 
2557
      sa_fww = Fww;                                                        //  valid image dimensions    v.11.08
 
2558
      sa_fhh = Fhh;
 
2559
      Factivearea = 1;                                                     //  area is active
 
2560
   }
 
2561
   
 
2562
   return 1;
 
2563
}
 
2564
 
 
2565
 
 
2566
//  mouse function - adjust edit strength for areas within mouse radius
 
2567
//  "edge distance" is increased for more strength, decreased for less
 
2568
 
 
2569
void select_edit_mousefunc()
 
2570
{
 
2571
   int      ii, cc, px, py, rx, ry;
 
2572
   int      radius, radius2, cpower, epower;
 
2573
   double   rad, rad2, power;                                              //  v.11.06
 
2574
   
 
2575
   if (! CEF) {                                                            //  no active edit
 
2576
      freeMouse();
 
2577
      return;
 
2578
   }
 
2579
   
 
2580
   if (! sa_stat)                                                          //  area gone?       v.11.07
 
2581
   {
 
2582
      cc = Fww * Fhh * sizeof(uint16);                                     //  allocate sa_pixmap[] for new area
 
2583
      sa_pixmap = (uint16 *) zmalloc(cc,"sa_select_edit");
 
2584
      memset(sa_pixmap,0,cc);                                              //  clear to zeros
 
2585
 
 
2586
      sa_minx = 0;                                                         //  enclosing rectangle
 
2587
      sa_maxx = Fww;
 
2588
      sa_miny = 0;
 
2589
      sa_maxy = Fhh;
 
2590
 
 
2591
      sa_Npixel = Fww * Fhh;
 
2592
      sa_stat = 3;                                                         //  area status = complete
 
2593
      sa_mode = 7;                                                         //  area mode = whole image
 
2594
      sa_calced = 1;                                                       //  edge calculation complete
 
2595
      sa_blend = 10000;                                                    //  "blend width"
 
2596
      sa_fww = Fww;                                                        //  valid image dimensions    v.11.08
 
2597
      sa_fhh = Fhh;
 
2598
      Factivearea = 1;                                                     //  area is active
 
2599
   }
 
2600
 
 
2601
   radius = select_edit_radius;                                            //  pixel selection radius
 
2602
   radius2 = radius * radius;
 
2603
   cpower = select_edit_cpower;
 
2604
   epower = select_edit_epower;
 
2605
 
 
2606
   toparcx = Mxposn - radius;                                              //  draw mouse outline circle
 
2607
   toparcy = Myposn - radius;
 
2608
   toparcw = toparch = 2 * radius;
 
2609
   Ftoparc = 1;
 
2610
   paint_toparc(3);
 
2611
 
 
2612
   if (LMclick || RMclick)                                                 //  mouse click
 
2613
      LMclick = RMclick = 0;
 
2614
 
 
2615
   if (Mbutton != 1 && Mbutton != 3)                                       //  button released
 
2616
      return;
 
2617
   
 
2618
   for (rx = -radius; rx <= radius; rx++)                                  //  loop every pixel in radius
 
2619
   for (ry = -radius; ry <= radius; ry++)
 
2620
   {
 
2621
      rad2 = rx * rx + ry * ry;
 
2622
      if (rad2 > radius2) continue;                                        //  outside radius
 
2623
      px = Mxposn + rx;
 
2624
      py = Myposn + ry;
 
2625
      if (px < 0 || px > Fww-1) continue;                                  //  off the image edge
 
2626
      if (py < 0 || py > Fhh-1) continue;
 
2627
 
 
2628
      ii = Fww * py + px;
 
2629
      rad = sqrt(rad2);
 
2630
      power = cpower + rad / radius * (epower - cpower);                   //  power at pixel radius     v.11.06
 
2631
      
 
2632
      if (Mbutton == 1)                                                    //  left mouse button
 
2633
      {                                                                    //  increase edit power
 
2634
         sa_pixmap[ii] += power;
 
2635
         if (sa_pixmap[ii] > sa_blend) sa_pixmap[ii] = sa_blend;
 
2636
      }
 
2637
 
 
2638
      if (Mbutton == 3)                                                    //  right mouse button
 
2639
      {                                                                    //  weaken edit power
 
2640
         if (sa_pixmap[ii] <= power) sa_pixmap[ii] = 0;
 
2641
         else sa_pixmap[ii] -= power;
 
2642
      }
 
2643
   }
 
2644
 
 
2645
   sa_minx = Mxposn - radius;                                              //  set temp. smaller area around mouse
 
2646
   if (sa_minx < 0) sa_minx = 0;                                           //    speedup  v.11.06
 
2647
   sa_maxx = Mxposn + radius;
 
2648
   if (sa_maxx > Fww) sa_maxx = Fww;
 
2649
   sa_miny = Myposn - radius;
 
2650
   if (sa_miny < 0) sa_miny = 0;
 
2651
   sa_maxy = Myposn + radius;
 
2652
   if (sa_maxy > Fhh) sa_maxy = Fhh;
 
2653
   sa_Npixel = (sa_maxx - sa_minx) * (sa_maxy - sa_miny);
 
2654
 
 
2655
   paint_toparc(2);                                                        //  remove mouse outline
 
2656
 
 
2657
   zdialog_send_event(CEF->zd,"blendwidth");                               //  notify edit dialog
 
2658
 
 
2659
   Ftoparc = 1;                                                            //  restore mouse outline
 
2660
   paint_toparc(3);
 
2661
 
 
2662
   sa_minx = 0;                                                            //  restore whole image area     v.11.06
 
2663
   sa_maxx = Fww;
 
2664
   sa_miny = 0;
 
2665
   sa_maxy = Fhh;
 
2666
   sa_Npixel = Fww * Fhh;
 
2667
 
 
2668
   return;
 
2669
}
 
2670
 
 
2671
 
 
2672