rework svg plugin, fast flash flush, init resize pixmaps, test edl version
[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 "bcdisplayinfo.h"
23 #include "clip.h"
24 #include "svgwin.h"
25 #include "filexml.h"
26 #include "language.h"
27 #include <string.h>
28 #include <unistd.h>
29 #include <fcntl.h>
30 #include <sys/types.h>
31 #include <fcntl.h>
32 #include <sys/stat.h>
33 #include <errno.h>
34
35 #include "empty_svg.h"
36
37 struct fifo_struct {
38         int pid;
39 // 1 = update from client, 2 = client closes, 3 = quit
40         int action;
41 };
42
43 SvgWin::SvgWin(SvgMain *client)
44  : PluginClientWindow(client, 300, 180, 300, 180, 1)
45
46         this->client = client; 
47         this->editing = 0;
48 }
49
50 SvgWin::~SvgWin()
51 {
52 }
53
54 void SvgWin::create_objects()
55 {
56         BC_Title *title;
57         int x = 10, y = 10;
58         add_tool(title = new BC_Title(x, y, _("Out X:")));
59         int x1 = x + title->get_w() + 10;
60         out_x = new SvgCoord(this, client, x1, y, &client->config.out_x);
61         out_x->create_objects();
62         y += out_x->get_h() + 5;
63         add_tool(new BC_Title(x, y, _("Out Y:")));
64         out_y = new SvgCoord(this, client, x1, y, &client->config.out_y);
65         out_y->create_objects();
66         y += out_y->get_h() + 20;
67
68         add_tool(new_svg_button = new NewSvgButton(client, this, x, y));
69         add_tool(edit_svg_button = new EditSvgButton(client, this, x+190, y));
70
71         add_tool(svg_file_title = new BC_Title(x, y+=42, client->config.svg_file));
72         add_tool(svg_file_mstime = new BC_Title(x, y+=26, ""));
73
74         show_window();
75         flush();
76 }
77
78 int SvgWin::close_event()
79 {
80         edit_svg_button->stop();
81         set_done(1);
82         return 1;
83 }
84
85
86 void SvgWin::update_gui(SvgConfig &config)
87 {
88         lock_window("SvgWin::update_gui");
89         out_x->update(config.out_x);
90         out_y->update(config.out_y);
91         svg_file_title->update(config.svg_file);
92         char mtime[BCSTRLEN];  mtime[0] = 0;
93         if( config.ms_time > 0 ) {
94                 time_t tm = config.ms_time/1000;
95                 ctime_r(&tm ,mtime);
96         }
97         svg_file_mstime->update(mtime);
98         unlock_window();
99 }
100
101 static void flicker(BC_GenericButton *btn, int n, int clr)
102 {
103         int color = btn->get_color();
104         while( --n >= 0 ) {
105                 btn->text_color(clr);   btn->draw_face(1);
106                 btn->sync_display();    usleep(100000);
107                 btn->text_color(color); btn->draw_face(1);
108                 btn->sync_display();    usleep(100000);
109         }
110 }
111
112 SvgCoord::SvgCoord(SvgWin *win, SvgMain *client, int x, int y, float *value)
113  : BC_TumbleTextBox(win, *value, (float)0, (float)3000, x, y, 100)
114 {
115 //printf("SvgWidth::SvgWidth %f\n", client->config.w);
116         this->client = client;
117         this->win = win;
118         this->value = value;
119 }
120
121 SvgCoord::~SvgCoord()
122 {
123 }
124
125 int SvgCoord::handle_event()
126 {
127         *value = atof(get_text());
128         client->send_configure_change();
129         return 1;
130 }
131
132 NewSvgButton::NewSvgButton(SvgMain *client, SvgWin *window, int x, int y)
133  : BC_GenericButton(x, y, _("New/Open SVG..."))
134 {
135         this->client = client;
136         this->window = window;
137 }
138
139 int NewSvgButton::handle_event()
140 {
141         window->editing_lock.lock();
142         if( !window->editing ) {
143                 window->editing = 1;
144                 window->editing_lock.unlock();
145                 start();
146         }
147         else {
148                 flicker(this, 5, RED);
149                 window->editing_lock.unlock();
150         }
151
152         return 1;
153 }
154
155 void NewSvgButton::run()
156 {
157 // ======================================= get path from user
158         int result;
159 //printf("NewSvgButton::run 1\n");
160         result = 1;
161         char filename[1024];
162         strncpy(filename, client->config.svg_file, sizeof(filename));
163 // Loop until file is chosen
164         do {
165                 char directory[1024];
166                 strncpy(directory, client->config.svg_file, sizeof(directory));
167                 char *cp = strrchr(directory, '/');
168                 if( cp ) *cp = 0;
169                 if( !directory[0] ) {
170                         char *cp = getenv("HOME");
171                         if( cp ) strncpy(directory, cp, sizeof(directory));
172                 }
173                 NewSvgWindow *new_window = new NewSvgWindow(client, window, directory);
174                 new_window->create_objects();
175                 new_window->update_filter("*.svg");
176                 result = new_window->run_window();
177                 const char *filepath = new_window->get_path(0);
178                 strcpy(filename, filepath);
179                 delete new_window;
180                 if( result || !filepath || !*filepath ) {
181                         window->editing_lock.lock();
182                         window->editing = 0;
183                         window->editing_lock.unlock();
184                         return;              // cancel or no filename given
185                 }
186
187 // Extend the filename with .svg
188                 if(strlen(filename) < 4 || 
189                         strcasecmp(&filename[strlen(filename) - 4], ".svg")) {
190                         strcat(filename, ".svg");
191                 }
192
193                 if( !access(filename, R_OK) )
194                         result = 0;
195                 else {
196                         FILE *out = fopen(filename,"w");
197                         if( out ) {
198                                 unsigned long size = sizeof(empty_svg) - 4;
199                                 fwrite(empty_svg+4, size,  1, out);
200                                 fclose(out);
201                                 result = 0;
202                         }
203                 }
204         } while(result);        // file doesn't exist so repeat
205         
206         strcpy(client->config.svg_file, filename);
207         struct stat st;
208         client->config.ms_time = stat(filename, &st) ? 0 :
209                 st.st_mtim.tv_sec*1000 + st.st_mtim.tv_nsec/1000000;
210         window->update_gui(client->config);
211         client->send_configure_change();
212
213         window->editing_lock.lock();
214         window->editing = 0;
215         window->editing_lock.unlock();
216
217         return;
218 }
219
220 EditSvgButton::EditSvgButton(SvgMain *client, SvgWin *window, int x, int y)
221  : BC_GenericButton(x, y, _("Edit")), Thread(1)
222 {
223         this->client = client;
224         this->window = window;
225         fh_fifo = -1;
226 }
227
228 EditSvgButton::~EditSvgButton()
229 {
230         stop();
231 }
232
233 void EditSvgButton::stop()
234 {
235         if( running() ) {
236                 if( fh_fifo >= 0 ) {
237                         struct fifo_struct fifo_buf;
238                         fifo_buf.pid = getpid();
239                         fifo_buf.action = 3;
240                         write(fh_fifo, &fifo_buf, sizeof(fifo_buf));
241                 }
242                 join();
243         }
244 }
245
246 int EditSvgButton::handle_event()
247 {
248         
249         window->editing_lock.lock();
250         if (!window->editing && client->config.svg_file[0] != 0) 
251         {
252                 window->editing = 1;
253                 window->editing_lock.unlock();
254                 start();
255         }
256         else {
257                 flicker(this, 5, RED);
258                 window->editing_lock.unlock();
259         }
260         return 1;
261 }
262
263 void EditSvgButton::run()
264 {
265 // ======================================= get path from user
266         char filename_png[1024];
267         char filename_fifo[1024];
268         strcpy(filename_png, client->config.svg_file);
269         strcat(filename_png, ".png");
270         remove(filename_png);
271         strcpy(filename_fifo, filename_png);
272         strcat(filename_fifo, ".fifo"); 
273         remove(filename_fifo);
274         if( !mkfifo(filename_fifo, S_IRWXU) &&
275             (fh_fifo = ::open(filename_fifo, O_RDWR+O_NONBLOCK)) >= 0 ) {
276                 SvgInkscapeThread inkscape_thread(this);
277                 inkscape_thread.start();
278                 int done = 0;
279                 while( inkscape_thread.running() && !done ) {
280                         struct stat st;
281                         int64_t ms_time = stat(client->config.svg_file, &st) ? 0 :
282                                 st.st_mtim.tv_sec*1000 + st.st_mtim.tv_nsec/1000000;
283                         if( client->config.ms_time != ms_time ) {
284                                 client->config.ms_time = ms_time;
285                                 client->send_configure_change();
286                         }
287                         // select(fh_fifo+1,rds,0,ers,tmo) does not work here
288                         Timer::delay(200);
289                         struct fifo_struct fifo_buf; fifo_buf.action = 1;
290                         int ret = read(fh_fifo, &fifo_buf, sizeof(fifo_buf));
291                         if( ret < 0 ) {
292                                 if( errno == EAGAIN ) continue;
293                                 perror("fifo");
294                                 break;
295                         }
296                         if( ret != sizeof(fifo_buf) ) continue;
297                         switch( fifo_buf.action ) {
298                         case 1: break;
299                         case 2: printf(_("Inkscape has exited\n"));
300                                 break;
301                         case 3: printf(_("Plugin window has closed\n"));
302                                 done = 1;
303                                 break;
304                         }
305                 }
306         }
307         else
308                 perror(_("Error opening fifo file"));
309         remove(filename_fifo); // fifo destroyed on last close
310         ::close(fh_fifo);
311         window->editing_lock.lock();
312         window->editing = 0;
313         window->editing_lock.unlock();
314         struct stat st;
315         client->config.ms_time = stat(client->config.svg_file, &st) ? 0 :
316                 st.st_mtim.tv_sec*1000 + st.st_mtim.tv_nsec/1000000;
317         client->send_configure_change();
318 }
319
320 SvgInkscapeThread::SvgInkscapeThread(EditSvgButton *edit)
321  : Thread(1)
322 {
323         this->edit = edit;;
324 }
325
326 SvgInkscapeThread::~SvgInkscapeThread()
327 {
328         cancel();
329         join();
330 }
331
332 void SvgInkscapeThread::run()
333 {
334 // Runs the inkscape
335         char command[1024];
336         sprintf(command, "inkscape --with-gui %s", edit->client->config.svg_file);
337         printf(_("Running external SVG editor: %s\n"), command);
338
339         enable_cancel();
340         system(command);
341         printf(_("External SVG editor finished\n"));
342         struct fifo_struct fifo_buf;
343         fifo_buf.pid = getpid();
344         fifo_buf.action = 2;
345         write(edit->fh_fifo, &fifo_buf, sizeof(fifo_buf));
346         disable_cancel();
347
348         return;
349 }
350
351
352
353 NewSvgWindow::NewSvgWindow(SvgMain *client, SvgWin *window, char *init_directory)
354  : BC_FileBox(0,
355         BC_WindowBase::get_resources()->filebox_h / 2,
356         init_directory, 
357         _("SVG Plugin: Pick SVG file"), 
358         _("Open an existing SVG file or create a new one"))
359
360         this->window = window; 
361 }
362
363 NewSvgWindow::~NewSvgWindow() {}
364
365
366
367
368
369
370