igor ru.po
[goodguy/history.git] / cinelerra-5.1 / plugins / svg / svgwin.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  */
21
22 #include "svgwin.h"
23 #include "filexml.h"
24 #include "language.h"
25
26 #include <string.h>
27 #include <unistd.h>
28 #include <fcntl.h>
29 #include <sys/types.h>
30 #include <fcntl.h>
31 #include <sys/stat.h>
32 #include <errno.h>
33
34 #include "empty_svg.h"
35
36 struct fifo_struct {
37         int pid;
38 // 1 = update from client, 2 = client closes, 3 = quit
39         int action;
40 };
41
42 SvgWin::SvgWin(SvgMain *client)
43  : PluginClientWindow(client, 420, 210, 420, 210, 1)
44 {
45         this->client = client;
46         this->editing = 0;
47 }
48
49 SvgWin::~SvgWin()
50 {
51 }
52
53 void SvgWin::create_objects()
54 {
55         BC_Title *title;
56         int x0 = 10, y = 10;
57
58         add_tool(title = new BC_Title(x0, y, _("Out X:")));
59         int x1 = x0 + title->get_w() + 10;
60         out_x = new SvgCoord(this, client, x1, y, &client->config.out_x);
61         out_x->create_objects();
62         int x2 = x1 + out_x->get_w() + 15;
63         add_tool(title = new BC_Title(x2, y, _("Out W:")));
64         int x3 = x2 + title->get_w() + 10;
65         out_w = new SvgCoord(this, client, x3, y, &client->config.out_w);
66         out_w->create_objects();
67         y += out_x->get_h() + 5;
68
69         add_tool(new BC_Title(x0, y, _("Out Y:")));
70         out_y = new SvgCoord(this, client, x1, y, &client->config.out_y);
71         out_y->create_objects();
72         add_tool(title = new BC_Title(x2, y, _("Out H:")));
73         out_h = new SvgCoord(this, client, x3, y, &client->config.out_h);
74         out_h->create_objects();
75         y += out_y->get_h() + 20;
76
77         add_tool(title = new BC_Title(x0, y, _("DPI:")));
78         dpi = new DpiValue(this, client, x1, y, &client->config.dpi);
79         dpi->create_objects();
80         add_tool(dpi_button = new DpiButton(this, client, x2, y));
81         dpi_button->create_objects();
82         y += dpi->get_h() + 20;
83
84         add_tool(svg_file_title = new BC_Title(x0, y, client->config.svg_file));
85         y += svg_file_title->get_h() + 5;
86         struct stat st;
87         int64_t ms_time = stat(client->config.svg_file, &st) ? 0 :
88                 st.st_mtim.tv_sec*1000 + st.st_mtim.tv_nsec/1000000;
89         char mtime[BCSTRLEN];  mtime[0] = 0;
90         if( ms_time > 0 ) {
91                 time_t tm = ms_time/1000;
92                 ctime_r(&tm ,mtime);
93         }
94         add_tool(svg_file_mstime = new BC_Title(x0, y, mtime));
95         y += svg_file_mstime->get_h() + 15;
96
97         y = get_h() - NewSvgButton::calculate_h() - 5;
98         add_tool(new_svg_button = new NewSvgButton(client, this, x0, y));
99         y = get_h() - EditSvgButton::calculate_h() - 5;
100         add_tool(edit_svg_button = new EditSvgButton(client, this, x0+300, y));
101
102         show_window();
103         flush();
104 }
105
106 int SvgWin::close_event()
107 {
108         edit_svg_button->stop();
109         set_done(1);
110         return 1;
111 }
112
113 int SvgWin::hide_window(int flush)
114 {
115         edit_svg_button->stop();
116         return BC_WindowBase::hide_window(flush);
117 }
118
119
120 void SvgWin::update_gui(SvgConfig &config)
121 {
122         lock_window("SvgWin::update_gui");
123         out_x->update(config.out_x);
124         out_y->update(config.out_y);
125         out_w->update(config.out_w);
126         out_h->update(config.out_h);
127         dpi->update(config.dpi);
128         svg_file_title->update(config.svg_file);
129         char mtime[BCSTRLEN];  mtime[0] = 0;
130         if( config.ms_time > 0 ) {
131                 time_t tm = config.ms_time/1000;
132                 ctime_r(&tm ,mtime);
133         }
134         svg_file_mstime->update(mtime);
135         unlock_window();
136 }
137
138 SvgCoord::SvgCoord(SvgWin *win, SvgMain *client, int x, int y, float *value)
139  : BC_TumbleTextBox(win, *value, (float)0, (float)3000, x, y, 100)
140 {
141 //printf("SvgWidth::SvgWidth %f\n", client->config.w);
142         this->client = client;
143         this->win = win;
144         this->value = value;
145 }
146
147 SvgCoord::~SvgCoord()
148 {
149 }
150
151 int SvgCoord::handle_event()
152 {
153         *value = atof(get_text());
154         client->send_configure_change();
155         return 1;
156 }
157
158 NewSvgButton::NewSvgButton(SvgMain *client, SvgWin *window, int x, int y)
159  : BC_GenericButton(x, y, _("New/Open SVG..."))
160 {
161         this->client = client;
162         this->window = window;
163 }
164
165 int NewSvgButton::handle_event()
166 {
167         window->editing_lock.lock();
168         if( !window->editing ) {
169                 window->editing = 1;
170                 window->editing_lock.unlock();
171                 start();
172         }
173         else {
174                 flicker();
175                 window->editing_lock.unlock();
176         }
177
178         return 1;
179 }
180
181 void NewSvgButton::run()
182 {
183 // ======================================= get path from user
184         int result;
185 //printf("NewSvgButton::run 1\n");
186         result = 1;
187         char filename[1024];
188         strncpy(filename, client->config.svg_file, sizeof(filename));
189 // Loop until file is chosen
190         do {
191                 char directory[1024];
192                 strncpy(directory, client->config.svg_file, sizeof(directory));
193                 char *cp = strrchr(directory, '/');
194                 if( cp ) *cp = 0;
195                 if( !directory[0] ) {
196                         char *cp = getenv("HOME");
197                         if( cp ) strncpy(directory, cp, sizeof(directory));
198                 }
199                 NewSvgWindow *new_window = new NewSvgWindow(client, window, directory);
200                 new_window->create_objects();
201                 new_window->update_filter("*.svg");
202                 result = new_window->run_window();
203                 const char *filepath = new_window->get_path(0);
204                 strcpy(filename, filepath);
205                 delete new_window;
206                 if( result || !filepath || !*filepath ) {
207                         window->editing_lock.lock();
208                         window->editing = 0;
209                         window->editing_lock.unlock();
210                         return;              // cancel or no filename given
211                 }
212
213 // Extend the filename with .svg
214                 if( strlen(filename) < 4 ||
215                         strcasecmp(&filename[strlen(filename) - 4], ".svg") ) {
216                         strcat(filename, ".svg");
217                 }
218
219                 if( !access(filename, R_OK) )
220                         result = 0;
221                 else {
222                         FILE *out = fopen(filename,"w");
223                         if( out ) {
224                                 unsigned long size = sizeof(empty_svg) - 4;
225                                 fwrite(empty_svg+4, size,  1, out);
226                                 fclose(out);
227                                 result = 0;
228                         }
229                 }
230         } while(result);        // file doesn't exist so repeat
231
232         strcpy(client->config.svg_file, filename);
233         struct stat st;
234         client->config.ms_time = stat(filename, &st) ? 0 :
235                 st.st_mtim.tv_sec*1000 + st.st_mtim.tv_nsec/1000000;
236         window->update_gui(client->config);
237         client->send_configure_change();
238
239         window->editing_lock.lock();
240         window->editing = 0;
241         window->editing_lock.unlock();
242
243         return;
244 }
245
246 EditSvgButton::EditSvgButton(SvgMain *client, SvgWin *window, int x, int y)
247  : BC_GenericButton(x, y, _("Edit")), Thread(1)
248 {
249         this->client = client;
250         this->window = window;
251         fh_fifo = -1;
252 }
253
254 EditSvgButton::~EditSvgButton()
255 {
256         stop();
257 }
258
259 void EditSvgButton::stop()
260 {
261         if( running() ) {
262                 if( fh_fifo >= 0 ) {
263                         struct fifo_struct fifo_buf;
264                         fifo_buf.pid = getpid();
265                         fifo_buf.action = 3;
266                         write(fh_fifo, &fifo_buf, sizeof(fifo_buf));
267                 }
268         }
269         join();
270 }
271
272 int EditSvgButton::handle_event()
273 {
274
275         window->editing_lock.lock();
276         if( !window->editing && client->config.svg_file[0] != 0 ) {
277                 window->editing = 1;
278                 window->editing_lock.unlock();
279                 start();
280         }
281         else {
282                 flicker();
283                 window->editing_lock.unlock();
284         }
285         return 1;
286 }
287
288 void EditSvgButton::run()
289 {
290 // ======================================= get path from user
291         char filename_png[1024];
292         char filename_fifo[1024];
293         strcpy(filename_png, client->config.svg_file);
294         strcat(filename_png, ".png");
295         remove(filename_png);
296         strcpy(filename_fifo, filename_png);
297         strcat(filename_fifo, ".fifo");
298         remove(filename_fifo);
299         if( !mkfifo(filename_fifo, S_IRWXU) &&
300             (fh_fifo = ::open(filename_fifo, O_RDWR+O_NONBLOCK)) >= 0 ) {
301                 SvgInkscapeThread inkscape_thread(this);
302                 inkscape_thread.start();
303                 int done = 0;
304                 while( inkscape_thread.running() && !done ) {
305                         struct stat st;
306                         int64_t ms_time = stat(client->config.svg_file, &st) ? 0 :
307                                 st.st_mtim.tv_sec*1000 + st.st_mtim.tv_nsec/1000000;
308                         if( client->config.ms_time != ms_time ) {
309                                 client->config.ms_time = ms_time;
310                                 client->send_configure_change();
311                         }
312                         // select(fh_fifo+1,rds,0,ers,tmo) does not work here
313                         Timer::delay(200);
314                         struct fifo_struct fifo_buf; fifo_buf.action = 1;
315                         int ret = read(fh_fifo, &fifo_buf, sizeof(fifo_buf));
316                         if( ret < 0 ) {
317                                 if( errno == EAGAIN ) continue;
318                                 perror("fifo");
319                                 break;
320                         }
321                         if( ret != sizeof(fifo_buf) ) continue;
322                         switch( fifo_buf.action ) {
323                         case 1: break;
324                         case 2: printf(_("Inkscape has exited\n"));
325                                 break;
326                         case 3: printf(_("Plugin window has closed\n"));
327                                 done = 1;
328                                 break;
329                         }
330                 }
331         }
332         else
333                 perror(_("Error opening fifo file"));
334         remove(filename_fifo); // fifo destroyed on last close
335         ::close(fh_fifo);
336         window->editing_lock.lock();
337         window->editing = 0;
338         window->editing_lock.unlock();
339         struct stat st;
340         client->config.ms_time = stat(client->config.svg_file, &st) ? 0 :
341                 st.st_mtim.tv_sec*1000 + st.st_mtim.tv_nsec/1000000;
342         client->send_configure_change();
343 }
344
345 SvgInkscapeThread::SvgInkscapeThread(EditSvgButton *edit)
346  : Thread(1)
347 {
348         this->edit = edit;;
349 }
350
351 SvgInkscapeThread::~SvgInkscapeThread()
352 {
353         cancel();
354         join();
355 }
356
357 void SvgInkscapeThread::run()
358 {
359 // Runs the inkscape
360         char command[1024];
361         sprintf(command, "inkscape --with-gui %s", edit->client->config.svg_file);
362         printf(_("Running external SVG editor: %s\n"), command);
363
364         enable_cancel();
365         system(command);
366         printf(_("External SVG editor finished\n"));
367         struct fifo_struct fifo_buf;
368         fifo_buf.pid = getpid();
369         fifo_buf.action = 2;
370         write(edit->fh_fifo, &fifo_buf, sizeof(fifo_buf));
371         disable_cancel();
372
373         return;
374 }
375
376
377
378 NewSvgWindow::NewSvgWindow(SvgMain *client, SvgWin *window, char *init_directory)
379  : BC_FileBox(0,
380         BC_WindowBase::get_resources()->filebox_h / 2,
381         init_directory,
382         _("SVG Plugin: Pick SVG file"),
383         _("Open an existing SVG file or create a new one"))
384 {
385         this->window = window;
386 }
387
388 NewSvgWindow::~NewSvgWindow() {}
389
390
391 DpiValue::DpiValue(SvgWin *win, SvgMain *client, int x, int y, float *value)
392  : BC_TumbleTextBox(win, *value, (float)10, (float)1000, x, y, 100)
393 {
394 //printf("SvgWidth::SvgWidth %f\n", client->config.w);
395         this->client = client;
396         this->win = win;
397         this->value = value;
398 }
399
400 DpiValue::~DpiValue()
401 {
402 }
403
404 int DpiValue::handle_event()
405 {
406         *value = atof(get_text());
407         return 1;
408 }
409
410
411 DpiButton::DpiButton( SvgWin *window, SvgMain *client, int x, int y)
412  : BC_GenericButton(x, y, _("update dpi"))
413 {
414         this->client = client;
415         this->window = window;
416 }
417
418 DpiButton::~DpiButton()
419 {
420 }
421
422 int DpiButton::handle_event()
423 {
424         client->send_configure_change();
425         return 1;
426 };
427