/* * figinset.C - part of LyX project */ extern int reverse_video; extern long int background_pixels; /* Rework of path-handling (Matthias 04.07.1996 ) * ------------------------------------------------ * figinsets keep an absolute path to the eps-file. * For the user alway a relative path appears * (in lyx-file, latex-file and edit-popup). * To calculate this relative path the path to the * document where the figinset is in is needed. * This is done by a reference to the buffer, called * figinset::cbuffer. To be up to date the cbuffer * is sometimes set to the current buffer * bufferlist.current(), when it can be assumed that * this operation happens in the current buffer. * This is true for InsetFig::Edit(...), * InsetFig::InsetFig(...), InsetFig::Read(...), * InsetFig::Write and InsetFig::Latex(...). * Therefore the bufferlist has to make sure that * during these operations bufferlist.current() * returns the buffer where the figinsets are in. * This made few changes in buffer.C necessary. * * The above is not totally valid anymore. (Lgb) */ #include #include #include #include #include FORMS_H_LOCATION #include #include #include #include "form1.h" #include "figinset.h" #include "lyx.h" #include "lyx_main.h" #include "buffer.h" #include "filedlg.h" #include "filetools.h" #include "LyXView.h" // just because of form_main #include "error.h" #include "lyxdraw.h" #include "LaTeXFeatures.h" #include "lyxrc.h" #include "gettext.h" #include "lyx_gui_misc.h" // CancelCloseBoxCB #include "FileInfo.h" // $Id: figinset.C,v 1.1 1999/09/27 18:44:38 larsbj Exp $ #if !defined(lint) && !defined(WITH_WARNINGS) static char vcid[] = "$Id: figinset.C,v 1.1 1999/09/27 18:44:38 larsbj Exp $"; #endif /* lint */ extern BufferView *current_view; static volatile bool alarmed; extern FL_OBJECT *figinset_canvas; inline void waitalarm(int) { alarmed = true; } extern char **environ; // is this only redundtant on linux systems? Lgb. extern void UpdateInset(Inset* inset, bool mark_dirty = true); // better for asyncron updating: void PutInsetIntoInsetUpdateList(Inset* inset); extern void ProhibitInput(); extern void AllowInput(); #define DEG2PI 57.295779513 #define figallocchunk 32 static int figinsref = 0; /* number of figures */ static int figarrsize = 0; /* current max number of figures */ static int bmpinsref = 0; /* number of bitmaps */ static int bmparrsize = 0; /* current max number of bitmaps */ struct queue { float rx, ry; /* resolution x and y */ int ofsx, ofsy; /* x and y translation */ figdata *data; /* we are doing it for this data */ queue *next; /* next item in queue */ }; struct pidwait { int pid; /* pid to wait for */ pidwait *next; /* next */ }; #define MAXGS 3 /* maximum 3 gs's at a time */ static Figref **figures; /* all the figures */ static figdata **bitmaps; /* all the bitmaps */ static queue *gsqueue = NULL; /* queue for ghostscripting */ static int gsrunning = 0; /* currently so many gs's are running */ static bool bitmap_waiting = false; /* bitmaps are waiting finished */ static char bittable[256]; /* bit reversion table */ static bool gs_color; // do we allocate colors for gs? static bool color_visual; // is the visual color? static bool gs_xcolor = false; // allocated extended colors static unsigned long gs_pixels[128]; // allocated pixels static int gs_num_pixels; // number of pixels allocated static int gs_spc; // shades per color static bool gs_gray; // is grayscale? static int gs_allcolors; // number of all colors static pidwait *pw = NULL; // pid wait list extern FD_form_main *fd_form_main; extern Colormap color_map; void addpidwait(int pid) { // adds pid to pid wait list register pidwait *p = new pidwait; p->pid = pid; p->next = pw; pw = p; if (lyxerr.debugging()) { lyxerr.print(LString("Pids to wait for: ") + int(p->pid)); while (p->next) { p = p->next; lyxerr.print(LString() + int(p->pid)); } } } int GhostscriptMsg(FL_OBJECT *, Window, int, int, XEvent *ev, void *) { int i; char tmp[128]; XClientMessageEvent *e = (XClientMessageEvent*) ev; if(lyxerr.debugging()) { fprintf(stderr, "ClientMessage, win:[xx] gs:[%ld] pm:[%ld]\n", e->data.l[0], e->data.l[1]); } // just kill gs, that way it will work for sure for (i = 0; i < bmpinsref; ++i) if ((long)bitmaps[i]->bitmap == (long)e->data.l[1]) { // found the one figdata *p = bitmaps[i]; p->gsdone = true; // first update p->bitmap, if necessary if (p->bitmap != None && p->flags > (1|8) && gs_color && p->wid) { // query current colormap and re-render // the pixmap with proper colors XColor *cmap; XWindowAttributes wa; register XImage *im; int i, y, wid1, spc1 = gs_spc-1, spc2 = gs_spc*gs_spc, wid = p->wid, forkstat; Display *tmpdisp; GC gc = getGC(gc_copy); XGetWindowAttributes(fl_display, fl_get_canvas_id( figinset_canvas), &wa); XFlush(fl_display); if (lyxerr.debugging()) { fprintf(stderr, "Starting image translation %ld %d %dx%d %d %d\n", p->bitmap, p->flags, p->wid, p->hgh, wa.depth, XYPixmap); } // now fork rendering process forkstat = fork(); if (forkstat == -1) { lyxerr.debug("Cannot fork, using slow " "method for pixmap translation."); tmpdisp = fl_display; } else if (forkstat > 0) { // register child if (lyxerr.debugging()) { lyxerr.print( LString("Spawned child ") + int(forkstat)); } addpidwait(forkstat); break; // in parent process } else { tmpdisp = XOpenDisplay(XDisplayName(NULL)); XFlush(tmpdisp); } im = XGetImage(tmpdisp, p->bitmap, 0, 0, p->wid, p->hgh, (1<wid - 1; // now we process all the image for (y = 0; y < p->hgh; ++y) { register int x; for (x = 0; x < wid; ++x) { register XColor* pc; pc = cmap + XGetPixel(im, x, y); XFlush(tmpdisp); XPutPixel(im, x, y, gs_pixels[((pc->red+6553)* spc1/65535)*spc2+((pc->green+6553)* spc1/65535)*gs_spc+((pc->blue+6553)* spc1/65535)]); XFlush(tmpdisp); } } if (lyxerr.debugging()) { lyxerr.print("Putting image back"); } XPutImage(tmpdisp, p->bitmap, gc, im, 0, 0, 0, 0, p->wid, p->hgh); XDestroyImage(im); if (lyxerr.debugging()) { lyxerr.print("Done translation"); } noim: if (lyxerr.debugging()) { lyxerr.print(LString("Killing gs ") + int(p->gspid)); } kill(p->gspid, SIGHUP); sprintf(tmp, "%s/~lyxgs%d.ps", system_tempdir.c_str(), p->gspid); unlink(tmp); if (forkstat == 0) { XCloseDisplay(tmpdisp); _exit(0); } } else { if (lyxerr.debugging()) { lyxerr.print(LString("Killing gs ") +int(p->gspid)); } kill(p->gspid, SIGHUP); sprintf(tmp, "%s/~lyxgs%d.ps", system_tempdir.c_str(), p->gspid); unlink(tmp); } break; } return 0; } static void AllocColors(int num) // allocate color cube numxnumxnum, if possible { XColor xcol; int i; if (lyxerr.debugging()) { printf("Allocating color cube %dx%dx%d\n", num, num, num); } if (num <= 1) { lyxerr.print("Error allocating color colormap."); gs_color = false; return; } if (num > 5) num = 5; for (i = 0; i < num*num*num; ++i) { xcol.red = 65535*(i/(num*num))/(num-1); xcol.green = 65535*((i/num) % num)/(num-1); xcol.blue = 65535*(i % num)/(num-1); xcol.flags = DoRed | DoGreen | DoBlue; if (!XAllocColor(fl_display, color_map, &xcol)) { if (i) XFreeColors(fl_display, color_map, gs_pixels, i, 0); if(lyxerr.debugging()) { lyxerr.print(LString("Cannot allocate color cube " ) + int(num)); } AllocColors(num-1); return; } gs_pixels[i] = xcol.pixel; } gs_color = true; gs_gray = false; gs_spc = num; gs_num_pixels = num*num*num; } static void AllocGrays(int num) // allocate grayscale ramp { XColor xcol; int i; if (lyxerr.debugging()) { lyxerr.print(LString("Allocating grayscale ramp ") + int(num)); } if (num < 4) { lyxerr.print("Error allocating grayscale colormap."); gs_color = false; return; } if (num > 128) num = 128; for (i = 0; i < num; ++i) { xcol.red = xcol.green = xcol.blue = 65535*i/(num-1); xcol.flags = DoRed | DoGreen | DoBlue; if (!XAllocColor(fl_display, color_map, &xcol)) { if (i) XFreeColors(fl_display, color_map, gs_pixels, i, 0); if (lyxerr.debugging()) { lyxerr.print(LString("Cannot allocate grayscale ") + int(num)); } AllocGrays(num/2); return; } gs_pixels[i] = xcol.pixel; } gs_color = true; gs_gray = false; gs_num_pixels = num; } void InitFigures() { unsigned int i, j, k; Visual *vi; bmparrsize = figarrsize = figallocchunk; figures = (Figref**) malloc(sizeof(Figref*)*figallocchunk); bitmaps = (figdata**) malloc(sizeof(figdata*)*figallocchunk); for (i = 0; i < 256; ++i) { k = 0; for (j = 0; j < 8; ++j) if (i & (1 << (7-j))) k |= 1 << j; bittable[i] = (char) ~k; } fl_add_canvas_handler(figinset_canvas, ClientMessage, GhostscriptMsg, fd_form_main); // now we have to init color_map if (!color_map) color_map = DefaultColormap(fl_display, DefaultScreen(fl_display)); // allocate color cube on pseudo-color display // first get visual gs_color = false; vi = DefaultVisual(fl_display, DefaultScreen(fl_display)); if (lyxerr.debugging()) { printf("Visual ID: %ld, class: %d, bprgb: %d, mapsz: %d\n", vi->visualid, vi->c_class, vi->bits_per_rgb, vi->map_entries); } color_visual = ( (vi->c_class == StaticColor) || (vi->c_class == PseudoColor) || (vi->c_class == TrueColor) || (vi->c_class == DirectColor) ); if ((vi->c_class & 1) == 0) return; // now allocate colors if (vi->c_class == GrayScale) { // allocate grayscale AllocGrays(vi->map_entries/2); } else { // allocate normal color int i = 5; while (i*i*i*2 > vi->map_entries) --i; AllocColors(i); } gs_allcolors = vi->map_entries; } void DoneFigures() { free(figures); free(bitmaps); figarrsize = 0; bmparrsize = 0; lyxerr.debug("Unregistering figures..."); fl_remove_canvas_handler(figinset_canvas, ClientMessage, GhostscriptMsg); if (gs_color) { lyxerr.debug("Freeing up the colors..."); XFreeColors(fl_display, color_map, gs_pixels, gs_num_pixels, 0); /******????????????????? what's planes in this case ??????***/ } } int FindBmpIndex(figdata *tmpdata) { int i = 0; while (i < bmpinsref) { if (bitmaps[i] == tmpdata) return i; ++i; } return i; } static void chpixmap(Pixmap, int, int) { Display* tempdisp = XOpenDisplay(XDisplayName(NULL)); // here read the pixmap and change all colors to those we // have allocated XCloseDisplay(tempdisp); } static void freefigdata(figdata *tmpdata) { int i; tmpdata->ref--; if (tmpdata->ref) return; if (tmpdata->gspid > 0) { int pid = tmpdata->gspid; char buf[128]; // change Pixmap according to our allocated colormap chpixmap(tmpdata->bitmap, tmpdata->wid, tmpdata->hgh); // kill ghostscript and unlink it's files tmpdata->gspid = -1; kill(pid, SIGKILL); sprintf(buf, "%s/~lyxgs%d.ps", system_tempdir.c_str(), pid); unlink(buf); } if (tmpdata->bitmap) XFreePixmap(fl_display, tmpdata->bitmap); delete tmpdata; i = FindBmpIndex(tmpdata); --bmpinsref; while (i < bmpinsref) { bitmaps[i] = bitmaps[i+1]; ++i; } } static void runqueue() { // run queued requests for ghostscript, if any if (!gsrunning && gs_color && !gs_xcolor) { // here alloc all colors, so that gs will use only // those we allocated for it // ***** gs_xcolor = true; } while (gsrunning < MAXGS) { queue *p; int pid; char tbuf[384], tbuf2[80]; Atom *prop; int nprop, i; if (!gsqueue) { if (!gsrunning && gs_xcolor) { // de-allocate rest of colors // ***** gs_xcolor = false; } return; } p = gsqueue; if (!p->data) { delete p; continue; } pid = fork(); if (pid == -1) { if (lyxerr.debugging()) { lyxerr.print("GS start error! Cannot fork."); } p->data->broken = true; p->data->reading = false; return; } if (pid == 0) { // child char **env, rbuf[80], gbuf[40]; int ne = 0; Display* tempdisp = XOpenDisplay(XDisplayName(NULL)); // create translation file sprintf(tbuf, "%s/~lyxgs%d.ps", system_tempdir.c_str(), int(getpid())); FilePtr f(tbuf, FilePtr::write); fprintf(f, "gsave clippath pathbbox grestore\n" "4 dict begin\n" "/ury exch def /urx exch def /lly exch def " "/llx exch def\n" "%g %g translate\n" "%g rotate\n" "%g %g translate\n" "%g %g scale\n" "%d %d translate\nend\n", p->data->wid / 2.0, p->data->hgh / 2.0, p->data->angle, - (p->data->raw_wid / 2.0), -(p->data->raw_hgh / 2.0), p->rx / 72.0, p->ry / 72.0, -p->ofsx, -p->ofsy ); // DON'T EVER remove this!! f.close(); // was this all? (Lgb) // gs process - set ghostview environment first sprintf(tbuf2, "GHOSTVIEW=%ld %ld", fl_get_canvas_id( figinset_canvas), p->data->bitmap); // now set up ghostview property on a window sprintf(tbuf, "0 0 0 0 %d %d 72 72 0 0 0 0", p->data->wid, p->data->hgh); //#warning BUG seems that the only bug here might be the hardcoded dpi.. Bummer! if (lyxerr.debugging()) { lyxerr.print(LString("Will set GHOSTVIEW" " property to [") + tbuf + "]"); } // wait until property is deleted if executing multiple // ghostscripts for (;;) { // grab server to prevent other child interfering // with setting GHOSTVIEW property if (lyxerr.debugging()) { lyxerr.print("Grabbing the server"); } XGrabServer(tempdisp); prop = XListProperties(tempdisp, fl_get_canvas_id( figinset_canvas), &nprop); if (!prop) break; bool err = true; for (i = 0; i < nprop; ++i) { char *p = XGetAtomName(tempdisp, prop[i]); if (strcmp(p, "GHOSTVIEW") == 0) { err = false; break; } XFree(p); } XFree((char *)prop); /* jc: */ if (err) break; // release the server XUngrabServer(tempdisp); XFlush(tempdisp); // ok, property found, we must wait until ghostscript // deletes it if (lyxerr.debugging()) { lyxerr.print("Releasing the server"); lyxerr.print(LString('[') + int(getpid()) + "] GHOSTVIEW property" " found. Waiting."); } #ifdef WITH_WARNINGS #warning What is this doing? (wouldn't a sleep(1); work too?') #endif alarm(1); alarmed = false; signal(SIGALRM, waitalarm); while (!alarmed) pause(); } XChangeProperty(tempdisp, fl_get_canvas_id(figinset_canvas), XInternAtom(tempdisp, "GHOSTVIEW", false), XInternAtom(tempdisp, "STRING", false), 8, PropModeAppend, (unsigned char *) tbuf, strlen(tbuf)); switch (p->data->flags & 3) { case 0: tbuf[0] = 'H'; break; // Hidden case 1: tbuf[0] = 'M'; break; // Mono case 2: tbuf[0] = 'G'; break; // Gray case 3: if (color_visual) tbuf[0] = 'C'; // Color else tbuf[0] = 'G'; // Gray break; } if (reverse_video) { sprintf(tbuf+1, " %ld %ld", WhitePixelOfScreen( DefaultScreenOfDisplay(fl_display)), background_pixels); } else { sprintf(tbuf+1, " %ld %ld", BlackPixelOfScreen( DefaultScreenOfDisplay(fl_display)), background_pixels); } XChangeProperty(tempdisp, fl_get_canvas_id(figinset_canvas), XInternAtom(tempdisp, "GHOSTVIEW_COLORS", false), XInternAtom(tempdisp, "STRING", false), 8, PropModeReplace, (unsigned char *) tbuf, strlen(tbuf)); XUngrabServer(tempdisp); XFlush(tempdisp); if (lyxerr.debugging()) { lyxerr.print("Releasing the server"); } XCloseDisplay(tempdisp); // set up environment while (environ[ne]) ++ne; env = (char **) malloc(sizeof(char*)*(ne+2)); env[0] = tbuf2; memcpy(&env[1], environ, sizeof(char*)*(ne+1)); environ = env; // now make gs command // close(0); // close(1); do NOT close. If GS writes out // errors it would hang. (Matthias 290596) sprintf(rbuf, "-r%gx%g", p->rx, p->ry); sprintf(gbuf, "-g%dx%d", p->data->wid, p->data->hgh); // now chdir into dir with .eps file, to be on the safe // side chdir(OnlyPath(p->data->fname).c_str()); // make temp file name sprintf(tbuf, "%s/~lyxgs%d.ps", system_tempdir.c_str(), int(getpid())); if (lyxerr.debugging()) { printf("starting gs %s %s, pid: %d\n", tbuf, p->data->fname.c_str(), int(getpid())); } int err = execlp(lyxrc->ps_command.c_str(), lyxrc->ps_command.c_str(), "-sDEVICE=x11", "-dNOPAUSE", "-dQUIET", "-dSAFER", rbuf, gbuf, tbuf, p->data->fname.c_str(), "showpage.ps", "quit.ps", "-", NULL); // if we are still there, an error occurred. lyxerr.print(LString("Error executing ghostscript. ") +"Code: "+err); lyxerr.debug("Cmd: " + lyxrc->ps_command +" -sDEVICE=x11 " + tbuf + LString(' ') + p->data->fname); _exit(0); // no gs? } // normal process (parent) if (lyxerr.debugging()) { lyxerr.print(LString("GS [") + int(pid) + "] started"); } gsqueue = gsqueue->next; gsrunning++; p->data->gspid = pid; delete p; } } static void addwait(int psx, int psy, int pswid, int pshgh, figdata *data) { // recompute the stuff and put in the queue queue *p, *p2; p = new queue; p->ofsx = psx; p->ofsy = psy; p->rx = ((float)data->raw_wid*72)/pswid; p->ry = ((float)data->raw_hgh*72)/pshgh; p->data = data; p->next = NULL; // now put into queue p2 = gsqueue; if (!gsqueue) gsqueue = p; else { while (p2->next) p2 = p2->next; p2->next = p; } // if possible, run the queue runqueue(); } static figdata *getfigdata(int wid, int hgh, LString const & fname, int psx, int psy, int pswid, int pshgh, int raw_wid, int raw_hgh, float angle, char flags) { /* first search for an exact match with fname and width/height */ int i = 0; figdata *p; XWindowAttributes wa; if (fname.empty()) return NULL; while (i < bmpinsref) { if (bitmaps[i]->wid == wid && bitmaps[i]->hgh == hgh && bitmaps[i]->flags == flags && bitmaps[i]->fname==fname && bitmaps[i]->angle == angle) { bitmaps[i]->ref++; return bitmaps[i]; } ++i; } /* not found -> create new record or return NULL if no record */ ++bmpinsref; if (bmpinsref > bmparrsize) { // allocate more space bmparrsize += figallocchunk; figdata **tmp = (figdata**) malloc(sizeof(figdata*)*bmparrsize); memcpy(tmp, bitmaps, sizeof(figdata*)*(bmparrsize-figallocchunk)); free(bitmaps); bitmaps = tmp; } p = new figdata; bitmaps[bmpinsref-1] = p; p->wid = wid; p->hgh = hgh; p->raw_wid = raw_wid; p->raw_hgh = raw_hgh; p->angle = angle; p->fname = fname; p->flags = flags; XGetWindowAttributes(fl_display, fl_get_canvas_id( figinset_canvas), &wa); if (lyxerr.debugging()) { printf("Create pixmap disp:%d scr:%d w:%d h:%d depth:%d\n", PTR_AS_INT(fl_display), DefaultScreen(fl_display), wid, hgh, wa.depth); } p->ref = 1; p->reading = false; p->broken = false; p->gspid = -1; if (flags) { p->bitmap = XCreatePixmap(fl_display, fl_get_canvas_id( figinset_canvas), wid, hgh, wa.depth); p->gsdone = false; // initialize reading of .eps file with correct sizes and stuff addwait(psx, psy, pswid, pshgh, p); p->reading = true; } else { p->bitmap = None; p->gsdone = true; } return p; } static void getbitmap(figdata *p) { p->gspid = -1; } static void makeupdatelist(figdata *p) { int i; for (i = 0; i < figinsref; ++i) if (figures[i]->data == p) { if (lyxerr.debugging()) { printf("Updating inset %d\n", PTR_AS_INT(figures[i]->inset)); } //UpdateInset(figures[i]->inset); // add inset figures[i]->inset into to_update list PutInsetIntoInsetUpdateList(figures[i]->inset); } } void sigchldchecker(pid_t pid, int *status) { int i; figdata *p; bool pid_handled = false; lyxerr.debug(LString("Got pid = ") + long (pid)); pid_handled = false; for (i = bmpinsref - 1; i >= 0; --i) { if (bitmaps[i]->reading && pid == bitmaps[i]->gspid) { lyxerr.debug("Found pid in bitmaps"); // now read the file and remove it from disk p = bitmaps[i]; p->reading = false; if (bitmaps[i]->gsdone) *status = 0; if (*status == 0) { lyxerr.debug(LString("GS [") + int(pid) + "] exit OK."); } else { fprintf(stderr, "GS [%ld] error %d E:%d %d S:%d %d\n", long(pid), *status, WIFEXITED(*status), WEXITSTATUS(*status), WIFSIGNALED(*status), WTERMSIG(*status)); } if (*status == 0) { bitmap_waiting = true; p->broken = false; } else { // remove temporary files char tmp[128]; sprintf(tmp, "%s/~lyxgs%d.ps", system_tempdir.c_str(), p->gspid); unlink(tmp); p->gspid = -1; p->broken = true; } makeupdatelist(bitmaps[i]); gsrunning--; runqueue(); pid_handled = true; } } if (!pid_handled) { lyxerr.debug("Checking pid in pidwait"); pidwait *p = pw, *prev = NULL; while (p) { if (pid == p->pid) { lyxerr.debug("Found pid in pidwait"); lyxerr.debug(LString("Caught child pid of recompute routine ") + int(pid)); if (prev) prev->next = p->next; else pw = p->next; free(p); break; } prev = p; p = p->next; } } if (pid == -1) { lyxerr.debug("waitpid error"); switch (errno) { case ECHILD: lyxerr.print( "The process or process group specified by pid " "does not exist or is not a child of the cal-" "ling process or can never be in the states " "specified by options."); break; case EINTR: lyxerr.print( "waitpid() was interrupted due to the receipt " "of a signal sent by the calling process."); break; case EINVAL: lyxerr.print( "An invalid value was specified for options."); break; default: lyxerr.print("Unknown error from waitpid"); break; } } else if (pid == 0) { lyxerr.print("waitpid nohang"); } else { lyxerr.debug("normal exit from childhandler"); } } static void getbitmaps() { int i; bitmap_waiting = false; for (i = 0; i < bmpinsref; ++i) if (bitmaps[i]->gspid > 0 && !bitmaps[i]->reading) getbitmap(bitmaps[i]); } static void RegisterFigure(InsetFig *fi) { Figref *tmpfig; if (figinsref == 0) InitFigures(); fi->form = NULL; ++figinsref; if (figinsref > figarrsize) { // allocate more space figarrsize += figallocchunk; Figref **tmp = (Figref**) malloc(sizeof(Figref*)*figarrsize); memcpy(tmp, figures, sizeof(Figref*)*(figarrsize-figallocchunk)); free(figures); figures = tmp; } tmpfig = new Figref; tmpfig->data = NULL; tmpfig->inset = fi; figures[figinsref-1] = tmpfig; fi->figure = tmpfig; if (lyxerr.debugging()) { lyxerr.print(LString("Register Figure: buffer:[") + long(current_view->currentBuffer()) + "]"); } } int FindFigIndex(Figref *tmpfig) { int i = 0; while (i < figinsref) { if (figures[i] == tmpfig) return i; ++i; } return i; } static void UnregisterFigure(InsetFig *fi) { Figref *tmpfig = fi->figure; int i; if (tmpfig->data) freefigdata(tmpfig->data); if (tmpfig->inset->form) { if (tmpfig->inset->form->Figure->visible) fl_hide_form(tmpfig->inset->form->Figure); fl_free_form(tmpfig->inset->form->Figure); free(tmpfig->inset->form); tmpfig->inset->form = NULL; } i = FindFigIndex(tmpfig); --figinsref; while (i < figinsref) { figures[i] = figures[i+1]; ++i; } delete tmpfig; if (figinsref == 0) DoneFigures(); } static char* NextToken(FILE *myfile) { char* token = NULL; char c; int i = 0; if (!feof(myfile)) { token = new char[256]; do { c = fgetc(myfile); token[i++]=c; } while (!feof(myfile) && !isspace(c)); token[i-1]='\0'; /* just the end of a command */ } return token; } InsetFig::InsetFig(int tmpx, int tmpy, Buffer *o) : owner(o) { wid = tmpx; hgh = tmpy; wtype = DEF; htype = DEF; twtype = DEF; thtype = DEF; pflags = flags = 9; psubfigure = subfigure = false; xwid = xhgh = angle = 0; raw_wid = raw_hgh = 0; changedfname = false; RegisterFigure(this); } InsetFig::~InsetFig() { if (lyxerr.debugging()) { lyxerr.print("Figure destructor called"); } UnregisterFigure(this); } int InsetFig::Ascent(LyXFont const&) const { return hgh + 3; } int InsetFig::Descent(LyXFont const&) const { return 1; } int InsetFig::Width(LyXFont const&) const { return wid + 2; } void InsetFig::Draw(LyXFont font, LyXScreen &scr, int baseline, float &x) { if (bitmap_waiting) getbitmaps(); // I wish that I didn't have to use this // but the figinset code is so complicated so // I don't want to fiddle with it now. unsigned long pm = scr.getForeground(); if (figure && figure->data && figure->data->bitmap && !figure->data->reading && !figure->data->broken) { // draw the bitmap XCopyArea(fl_display, figure->data->bitmap, pm, getGC(gc_copy), 0, 0, wid, hgh, int(x+1), baseline-hgh); XFlush(fl_display); if (flags & 4) XDrawRectangle(fl_display, pm, getGC(gc_copy), int(x), baseline - hgh - 1, wid+1, hgh+1); } else { char * msg = 0; // draw frame XDrawRectangle(fl_display, pm, getGC(gc_copy), (int) x, baseline - hgh - 1, wid+1, hgh+1); if (figure && figure->data) { if (figure->data->broken) msg = _("[render error]"); else if (figure->data->reading) msg = _("[rendering ... ]"); } else if (fname.empty()) msg = _("[no file]"); else if ((flags & 3) == 0) msg = _("[not displayed]"); else if (lyxrc->ps_command.empty()) msg = _("[no ghostscript]"); if (!msg) msg = _("[unknown error]"); font.setFamily (LyXFont::SANS_FAMILY); font.setSize (LyXFont::SIZE_FOOTNOTE); LString justname = OnlyFilename (fname); font.drawString(justname,pm, baseline - font.maxAscent() - 4, (int) x + 8); font.setSize (LyXFont::SIZE_TINY); font.drawText (msg, strlen(msg),pm, baseline - 4, (int) x + 8); } x += Width(font); // ? } void InsetFig::Write(FILE *file) { Regenerate(); fprintf(file, "Figure size %d %d\n", wid, hgh); if (!fname.empty()) { LString buf1 = OnlyPath(owner->getFileName()); LString fname2 = MakeRelPath(fname, buf1); fprintf(file, "file %s\n", fname2.c_str()); } if (!subcaption.empty()) fprintf(file, "subcaption %s\n", subcaption.c_str()); if (wtype) fprintf(file, "width %d %g\n", wtype, xwid); if (htype) fprintf(file, "height %d %g\n", htype, xhgh); if (angle != 0) fprintf(file, "angle %g\n", angle); fprintf(file, "flags %d\n", flags); if (subfigure) fprintf(file, "subfigure\n"); } void InsetFig::Read(LyXLex &lex) { LString buf; bool finished = false; while (lex.IsOK() && !finished) { lex.next(); LString const token = lex.GetString(); lyxerr.debug("Token: " + token); if (token.empty()) continue; else if (token == "\\end_inset") { finished = true; } else if (token == "file") { if (lex.next()) { buf = lex.GetString(); LString buf1 = OnlyPath(owner->getFileName()); fname = MakeAbsPath(buf, buf1); changedfname = true; } } else if (token == "extra") { if (lex.next()); // kept for backwards compability. Delete in 0.13.x } else if (token == "subcaption") { if (lex.EatLine()) subcaption = lex.GetString(); } else if (token == "label") { if (lex.next()); // kept for backwards compability. Delete in 0.13.x } else if (token == "angle") { if (lex.next()) angle = lex.GetFloat(); } else if (token == "size") { if (lex.next()) wid = lex.GetInteger(); if (lex.next()) hgh = lex.GetInteger(); } else if (token == "flags") { if (lex.next()) flags = pflags = lex.GetInteger(); } else if (token == "subfigure") { subfigure = psubfigure = true; } else if (token == "width") { int typ = 0; if (lex.next()) typ = lex.GetInteger(); if (lex.next()) xwid = lex.GetFloat(); switch (typ) { case DEF: wtype = DEF; break; case CM: wtype = CM; break; case IN: wtype = IN; break; case PER_PAGE: wtype = PER_PAGE; break; case PER_COL: wtype = PER_COL; break; default: lyxerr.debug("Unknown type!"); break; } twtype = wtype; } else if (token == "height") { int typ = 0; if (lex.next()) typ = lex.GetInteger(); if (lex.next()) xhgh = lex.GetFloat(); switch (typ) { case DEF: htype = DEF; break; case CM: htype = CM; break; case IN: htype = IN; break; case PER_PAGE: htype = PER_PAGE; break; default: lyxerr.debug("Unknown type!"); break; } thtype = htype; } } Regenerate(); Recompute(); } int InsetFig::Latex(FILE *file, signed char /* fragile*/ ) { Regenerate(); if (!cmd.empty()) fprintf(file, "%s ", cmd.c_str()); return 0; } int InsetFig::Latex(LString &file, signed char /* fragile*/ ) { Regenerate(); file += cmd + ' '; return 0; } int InsetFig::Linuxdoc(LString &/*file*/) { return 0; } int InsetFig::DocBook(LString &file) { LString figurename=fname; if(figurename.suffixIs(".eps")) figurename=figurename.substring(0,fname.length()-5); file += "@"; return 0; } void InsetFig::Validate(LaTeXFeatures &features) const { features.graphics = true; if (subfigure) features.subfigure = true; } unsigned char InsetFig::Editable() const { return 1; } bool InsetFig::Deletable() const { return false; } void InsetFig::Edit(int, int) { lyxerr.debug("Editing InsetFig."); Regenerate(); // We should have RO-versions of the form instead. // The actual prevention of altering a readonly doc // is done in CallbackFig() if(current_view->currentBuffer()->isReadonly()) WarnReadonly(); if (!form) { form = create_form_Figure(); fl_set_form_atclose(form->Figure, CancelCloseBoxCB, NULL); fl_set_object_return(form->Angle,FL_RETURN_ALWAYS); fl_set_object_return(form->Width,FL_RETURN_ALWAYS); fl_set_object_return(form->Height,FL_RETURN_ALWAYS); } RestoreForm(); if (form->Figure->visible) { fl_raise_form(form->Figure); } else { fl_show_form(form->Figure, FL_PLACE_MOUSE | FL_PLACE_SIZE, FL_FULLBORDER, _("Figure")); } } Inset *InsetFig::Clone() { InsetFig *tmp = new InsetFig(100, 100, owner); if (lyxerr.debugging()) { fprintf(stderr, "Clone Figure: buffer:[%d], cbuffer:[xx]\n", PTR_AS_INT(current_view->currentBuffer())); } tmp->wid = wid; tmp->hgh = hgh; tmp->raw_wid = raw_wid; tmp->raw_hgh = raw_hgh; tmp->angle = angle; tmp->xwid = xwid; tmp->xhgh = xhgh; tmp->flags = flags; tmp->pflags = pflags; tmp->subfigure = subfigure; tmp->psubfigure = psubfigure; tmp->wtype = wtype; tmp->htype = htype; tmp->psx = psx; tmp->psy = psy; tmp->pswid = pswid; tmp->pshgh = pshgh; tmp->fname = fname; if (!fname.empty() && (flags & 3) && !lyxrc->ps_command.empty()) { // do not display if there is "do not display" chosen (Matthias 260696) tmp->figure->data = getfigdata(wid, hgh, fname, psx, psy, pswid, pshgh, raw_wid, raw_hgh, angle, flags & (3|8)); } else tmp->figure->data = NULL; tmp->subcaption = subcaption; tmp->changedfname = false; tmp->owner = owner; tmp->Regenerate(); return tmp; } Inset::Code InsetFig::LyxCode() const { return Inset::GRAPHICS_CODE; } void InsetFig::Regenerate() { LString cmdbuf; LString gcmd; LString resizeW, resizeH; LString rotate, recmd; if (fname.empty()) { cmd = "\\fbox{\\rule[-0.5in]{0pt}{1in}"; cmd += _("empty figure path"); cmd += '}'; //if (form) fl_set_object_label(form->cmd, ""); return; } LString buf1 = OnlyPath(owner->getFileName()); LString fname2 = MakeRelPath(fname, buf1); gcmd = "\\includegraphics{" + fname2 + '}'; switch (wtype) { case DEF: break; case CM:{// \resizebox*{h-length}{v-length}{text} char buf[10]; sprintf(buf, "%g", xwid); // should find better resizeW = buf; resizeW += "cm"; break; } case IN: { char buf[10]; sprintf(buf, "%g", xwid); resizeW = buf; resizeW += "in"; break; } case PER_PAGE:{ char buf[10]; sprintf(buf, "%g", xwid/100); resizeW = buf; resizeW += "\\textwidth"; break; } case PER_COL:{ char buf[10]; sprintf(buf, "%g", xwid/100); resizeW = buf; resizeW += "\\columnwidth"; break; } } switch (htype) { case DEF: break; case CM: { char buf[10]; sprintf(buf, "%g", xhgh); resizeH = buf; resizeH += "cm"; break; } case IN:{ char buf[10]; sprintf(buf, "%g", xhgh); resizeH = buf; resizeH += "in"; break; } case PER_PAGE: { char buf[10]; sprintf(buf, "%g", xhgh/100); resizeH = buf; resizeH += "\\textheight"; break; } case PER_COL: { // Doesn't occur; case exists to suppress compiler warnings. break; } } if (!resizeW.empty() || !resizeH.empty()) { recmd = "\\resizebox*{"; if (!resizeW.empty()) recmd += resizeW; else recmd += '!'; recmd += "}{"; if (!resizeH.empty()) recmd += resizeH; else recmd += '!'; recmd += "}{"; } if (angle != 0) { char buf[10]; sprintf(buf, "%g", angle); // \rotatebox{angle}{text} rotate = "\\rotatebox{"; rotate += buf; rotate += "}{"; } cmdbuf = recmd; cmdbuf += rotate; cmdbuf += gcmd; if (!rotate.empty()) cmdbuf += '}'; if (!recmd.empty()) cmdbuf += '}'; if (subfigure) { if (!subcaption.empty()) cmdbuf = "\\subfigure[" + subcaption + "]{" + cmdbuf + "}"; else cmdbuf = "\\subfigure{" + cmdbuf + "}"; } cmd = cmdbuf; //if (form) fl_set_object_label(form->cmd, cmd.c_str()); } void InsetFig::TempRegenerate() { LString gcmd; LString cmdbuf; LString resizeW, resizeH; LString rotate, recmd; LString tsubcap; char const *tfname; // *textra; float tangle, txwid, txhgh; tfname = fl_get_input(form->EpsFile); tsubcap = fl_get_input(form->Subcaption); tangle = atof(fl_get_input(form->Angle)); txwid = atof(fl_get_input(form->Width)); txhgh = atof(fl_get_input(form->Height)); if (!tfname || !*tfname) { //fl_set_object_label(form->cmd, ""); //fl_redraw_object(form->cmd); cmd = "\\fbox{\\rule[-0.5in]{0pt}{1in}"; cmd += _("empty figure path"); cmd += '}'; return; } LString buf1 = OnlyPath(owner->getFileName()); LString fname2 = MakeRelPath(tfname, buf1); // \includegraphics*[][]{file} gcmd = "\\includegraphics{" + fname2 + '}'; switch (twtype) { case DEF: break; case CM: {// \resizebox*{h-length}{v-length}{text} char buf[10]; sprintf(buf, "%g", txwid); // should find better resizeW = buf; resizeW += "cm"; break; } case IN: { char buf[10]; sprintf(buf, "%g", txwid); resizeW = buf; resizeW += "in"; break; } case PER_PAGE: { char buf[10]; sprintf(buf, "%g", txwid/100); resizeW = buf; resizeW += "\\textwidth"; break; } case PER_COL: { char buf[10]; sprintf(buf, "%g", txwid/100); resizeW = buf; resizeW += "\\columnwidth"; break; } } switch (thtype) { case DEF: break; case CM: { char buf[10]; sprintf(buf, "%g", txhgh); resizeH = buf; resizeH += "cm"; break; } case IN: { char buf[10]; sprintf(buf, "%g", txhgh); resizeH = buf; resizeH += "in"; break; } case PER_PAGE: { char buf[10]; sprintf(buf, "%g", txhgh/100); resizeH = buf; resizeH += "\\textheight"; break; } case PER_COL: { // Doesn't occur; case exists to suppress compiler warnings. break; } } // \resizebox*{h-length}{v-length}{text} if (!resizeW.empty() || !resizeH.empty()) { recmd = "\\resizebox*{"; if (!resizeW.empty()) recmd += resizeW; else recmd += '!'; recmd += "}{"; if (!resizeH.empty()) recmd += resizeH; else recmd += '!'; recmd += "}{"; } if (tangle != 0) { char buf[10]; sprintf(buf, "%g", tangle); // \rotatebox{angle}{text} rotate = "\\rotatebox{"; rotate += buf; rotate += "}{"; } cmdbuf = recmd; cmdbuf += rotate; cmdbuf += gcmd; if (!rotate.empty()) cmdbuf += '}'; if (!recmd.empty()) cmdbuf += '}'; if (psubfigure && !tsubcap.empty()) { cmdbuf = LString("\\subfigure{") + tsubcap + LString("}{") + cmdbuf + "}"; } //fl_set_object_label(form->cmd, cmdbuf.c_str()); //fl_redraw_object(form->cmd); } void InsetFig::Recompute() { bool changed = changedfname; int newx, newy, nraw_x, nraw_y, frame_wid, frame_hgh; float sin_a, cos_a; if (changed) GetPSSizes(); sin_a = sin (angle / DEG2PI); /* rotation; H. Zeller 021296 */ cos_a = cos (angle / DEG2PI); frame_wid = (int) ceil (fabs(cos_a * pswid) + fabs(sin_a * pshgh)); frame_hgh= (int) ceil (fabs(cos_a * pshgh) + fabs(sin_a * pswid)); /* now recompute wid and hgh, and if that is changed, set changed */ /* this depends on chosen size of the picture and its bbox */ // This will be redone in 0.13 ... (hen) if (!fname.empty()) { // say, total width is 595 pts, as A4 in TeX, thats in 1/72" */ newx = frame_wid; newy = frame_hgh; switch (wtype) { case DEF: break; case CM: /* cm */ newx = (int) (28.346*xwid); break; case IN: /* in */ newx = (int) (72*xwid); break; case PER_PAGE: /* % of page */ newx = (int) (5.95*xwid); break; case PER_COL: /* % of col */ newx = (int) (2.975*xwid); break; } if (wtype && frame_wid) newy = newx*frame_hgh/frame_wid; switch (htype) { case DEF: //fprintf(stderr, "This should not happen!\n"); break; case CM: /* cm */ newy = (int) (28.346*xhgh); break; case IN: /* in */ newy = (int) (72*xhgh); break; case PER_PAGE: /* % of page */ newy = (int) (8.42*xhgh); break; case PER_COL: // Doesn't occur; case exists to suppress // compiler warnings. break; } if (htype && !wtype && frame_hgh) newx = newy*frame_wid/frame_hgh; } else { newx = wid; newy = hgh; } if (frame_wid == 0) nraw_x = 5; else nraw_x = (int) ((1.0 * pswid * newx)/frame_wid); if (frame_hgh == 0) nraw_y = 5; else nraw_y = (int) ((1.0 * pshgh * newy)/frame_hgh); // cannot be zero, actually, set it to some minimum, so its clickable if (newx < 5) newx = 5; if (newy < 5) newy = 5; if (newx != wid || newy != hgh || nraw_x != raw_wid || nraw_y != raw_hgh || flags != pflags || subfigure != psubfigure) changed = true; raw_wid = nraw_x; raw_hgh = nraw_y; wid = newx; hgh = newy; flags = pflags; subfigure = psubfigure; if (changed) { figdata *pf = figure->data; // get new data if (!fname.empty() && (flags & 3) && !lyxrc->ps_command.empty()) { // do not display if there is "do not display" // chosen (Matthias 260696) figure->data = getfigdata(wid, hgh, fname, psx, psy, pswid, pshgh, raw_wid, raw_hgh, angle, flags & (3|8)); } else figure->data = NULL; // free the old data if (pf) freefigdata(pf); } changedfname = false; } void InsetFig::GetPSSizes() { /* get %%BoundingBox: from postscript file */ int lastchar, c; char *p = NULL; /* defaults to associated size * ..just in case the PS-file is not readable (Henner,24-Aug-97) */ psx = 0; psy = 0; pswid = wid; pshgh = hgh; if (fname.empty()) return; FilePtr f(fname, FilePtr::read); if (!f()) return; // file not found !!!! /* defaults to A4 page */ psx = 0; psy = 0; pswid = 595; pshgh = 842; lastchar = fgetc(f); for (;;) { c = fgetc(f); if (c == EOF) { lyxerr.debug("End of (E)PS file reached and" " no BoundingBox!"); break; } if (c == '%' && lastchar == '%') { p = NextToken(f); if (!p) break; if (strcmp(p, "EndComments") == 0) break; if (strcmp(p, "BoundingBox:") == 0) { float fpsx, fpsy, fpswid, fpshgh; if (fscanf(f, "%f %f %f %f", &fpsx, &fpsy, &fpswid, &fpshgh) == 4) { psx = (int) fpsx; psy = (int) fpsy; pswid = (int) fpswid; pshgh = (int) fpshgh; } if (lyxerr.debugging()) { fprintf(stderr, "%%%%BoundingBox:" " %d %d %d %d\n", psx, psy, pswid, pshgh); break; } } c = 0; delete[] p; p = NULL; } lastchar = c; } if (p) delete[] p; pswid -= psx; pshgh -= psy; } void InsetFig::CallbackFig(long arg) { bool regen = false; char const *p; if (lyxerr.debugging()) { printf("Figure callback, arg %ld\n", arg); } switch (arg) { case 10: case 11: case 12: /* width type */ case 13: case 14: switch (arg - 10) { case DEF: twtype = DEF; // put disable here fl_deactivate_object(form->Width); break; case CM: twtype = CM; // put enable here fl_activate_object(form->Width); break; case IN: twtype = IN; // put enable here fl_activate_object(form->Width); break; case PER_PAGE: twtype = PER_PAGE; // put enable here fl_activate_object(form->Width); break; case PER_COL: twtype = PER_COL; // put enable here fl_activate_object(form->Width); break; default: lyxerr.debug("Unknown type!"); break; } regen = true; break; case 20: case 21: case 22: /* height type */ case 23: switch (arg - 20) { case DEF: thtype = DEF; // put disable here fl_deactivate_object(form->Height); break; case CM: thtype = CM; // put enable here fl_activate_object(form->Height); break; case IN: thtype = IN; // put enable here fl_activate_object(form->Height); break; case PER_PAGE: thtype = PER_PAGE; // put enable here fl_activate_object(form->Height); break; default: lyxerr.debug("Unknown type!"); break; } regen = true; break; case 3: pflags = pflags & ~3; /* wysiwyg0 */ break; case 33: pflags = (pflags & ~3) | 1; /* wysiwyg1 */ break; case 43: pflags = (pflags & ~3) | 2; /* wysiwyg2 */ break; case 63: pflags = (pflags & ~3) | 3; /* wysiwyg3 */ break; case 53: pflags ^= 4; /* frame */ break; case 54: pflags ^= 8; /* do translations */ break; case 70: psubfigure = !psubfigure; /* This is a subfigure */ break; case 2: regen = true; /* regenerate command */ break; case 0: /* browse file */ BrowseFile(); regen = true; break; case 1: /* preview */ p = fl_get_input(form->EpsFile); Preview(p); break; case 7: /* apply */ case 8: /* ok (apply and close) */ if(!current_view->currentBuffer()->isReadonly()) { wtype = twtype; htype = thtype; xwid = atof(fl_get_input(form->Width)); xhgh = atof(fl_get_input(form->Height)); angle = atof(fl_get_input(form->Angle)); p = fl_get_input(form->EpsFile); if (p && *p) { LString buf1 = OnlyPath(owner->getFileName()); fname = MakeAbsPath(p, buf1); changedfname = true; } else { if (!fname.empty()) { changedfname = true; fname.clean(); } } subcaption = fl_get_input(form->Subcaption); Regenerate(); Recompute(); /* now update inset */ if (lyxerr.debugging()) { fprintf(stderr, "Update: [%dx%d]\n", wid, hgh); } UpdateInset(this); if (arg == 8) { fl_hide_form(form->Figure); fl_free_form(form->Figure); free(form); form = NULL; } break; } //if not readonly // The user has already been informed about RO in ::Edit if(arg == 7) // if 'Apply' break; // fall through case 9: /* cancel = restore and close */ fl_hide_form(form->Figure); fl_free_form(form->Figure); free(form); form = NULL; break; } if (regen) TempRegenerate(); } inline void DisableFigurePanel(FD_Figure * const form) { fl_deactivate_object(form->EpsFile); fl_deactivate_object(form->Browse); fl_deactivate_object(form->Width); fl_deactivate_object(form->Height); fl_deactivate_object(form->Frame); fl_deactivate_object(form->Translations); fl_deactivate_object(form->Angle); fl_deactivate_object(form->HeightGrp); fl_deactivate_object(form->page2); fl_deactivate_object(form->Default2); fl_deactivate_object(form->cm2); fl_deactivate_object(form->in2); fl_deactivate_object(form->HeightLabel); fl_deactivate_object(form->WidthLabel); fl_deactivate_object(form->DisplayGrp); fl_deactivate_object(form->Wysiwyg3); fl_deactivate_object(form->Wysiwyg0); fl_deactivate_object(form->Wysiwyg2); fl_deactivate_object(form->Wysiwyg1); fl_deactivate_object(form->WidthGrp); fl_deactivate_object(form->Default1); fl_deactivate_object(form->cm1); fl_deactivate_object(form->in1); fl_deactivate_object(form->page1); fl_deactivate_object(form->column1); fl_deactivate_object(form->Subcaption); fl_deactivate_object(form->Subfigure); fl_deactivate_object (form->OkBtn); fl_deactivate_object (form->ApplyBtn); fl_set_object_lcol (form->OkBtn, FL_INACTIVE); fl_set_object_lcol (form->ApplyBtn, FL_INACTIVE); } inline void EnableFigurePanel(FD_Figure * const form) { fl_activate_object(form->EpsFile); fl_activate_object(form->Browse); fl_activate_object(form->Width); fl_activate_object(form->Height); fl_activate_object(form->Frame); fl_activate_object(form->Translations); fl_activate_object(form->Angle); fl_activate_object(form->HeightGrp); fl_activate_object(form->page2); fl_activate_object(form->Default2); fl_activate_object(form->cm2); fl_activate_object(form->in2); fl_activate_object(form->HeightLabel); fl_activate_object(form->WidthLabel); fl_activate_object(form->DisplayGrp); fl_activate_object(form->Wysiwyg3); fl_activate_object(form->Wysiwyg0); fl_activate_object(form->Wysiwyg2); fl_activate_object(form->Wysiwyg1); fl_activate_object(form->WidthGrp); fl_activate_object(form->Default1); fl_activate_object(form->cm1); fl_activate_object(form->in1); fl_activate_object(form->page1); fl_activate_object(form->column1); fl_activate_object(form->Subcaption); fl_activate_object(form->Subfigure); fl_activate_object (form->OkBtn); fl_activate_object (form->ApplyBtn); fl_set_object_lcol (form->OkBtn, FL_BLACK); fl_set_object_lcol (form->ApplyBtn, FL_BLACK); } void InsetFig::RestoreForm() { char buf[32]; int pflags; EnableFigurePanel(form); twtype = wtype; fl_set_button(form->Default1, (wtype == 0)); fl_set_button(form->cm1, (wtype == 1)); fl_set_button(form->in1, (wtype == 2)); fl_set_button(form->page1, (wtype == 3)); fl_set_button(form->column1, (wtype == 4)); if (wtype == 0) { fl_deactivate_object(form->Width); } else { fl_activate_object(form->Width); } // enable and disable should be put here. thtype = htype; fl_set_button(form->Default2, (htype == 0)); fl_set_button(form->cm2, (htype == 1)); fl_set_button(form->in2, (htype == 2)); fl_set_button(form->page2, (htype == 3)); // enable and disable should be put here. if (htype == 0) { fl_deactivate_object(form->Height); } else { fl_activate_object(form->Height); } pflags = flags & 3; fl_set_button(form->Wysiwyg0, (pflags == 0)); fl_set_button(form->Wysiwyg1, (pflags == 1)); fl_set_button(form->Wysiwyg2, (pflags == 2)); fl_set_button(form->Wysiwyg3, (pflags == 3)); fl_set_button(form->Frame, ((flags & 4) != 0)); fl_set_button(form->Translations, ((flags & 8) != 0)); fl_set_button(form->Subfigure, (subfigure != 0)); pflags = flags; psubfigure = subfigure; sprintf(buf, "%g", xwid); fl_set_input(form->Width, buf); sprintf(buf, "%g", xhgh); fl_set_input(form->Height, buf); sprintf(buf, "%g", angle); fl_set_input(form->Angle, buf); if (!fname.empty()){ LString buf1 = OnlyPath(owner->getFileName()); LString fname2 = MakeRelPath(fname, buf1); fl_set_input(form->EpsFile, fname2.c_str()); } else fl_set_input(form->EpsFile, ""); fl_set_input(form->Subcaption, subcaption.c_str()); if(current_view->currentBuffer()->isReadonly()) DisableFigurePanel(form); TempRegenerate(); } void InsetFig::Preview(char const *p) { int pid; pid = fork(); if (pid == -1) { lyxerr.print("Cannot fork process!"); return; // error } if (pid > 0) { addpidwait(pid); return; // parent process } LString buf1 = OnlyPath(owner->getFileName()); LString buf2 = MakeAbsPath(p, buf1); lyxerr.print(LString("Error during rendering ") + int(execlp(lyxrc->view_pspic_command.c_str(), lyxrc->view_pspic_command.c_str(), buf2.c_str(), NULL))); _exit(0); } void InsetFig::BrowseFile() { LString buf, buf2, bufclip; static LString current_figure_path; static int once = 0; LyXFileDlg fileDlg; if (lyxerr.debugging()) { fprintf(stderr, "Filename: %s\n", owner->getFileName().c_str()); } LString p = fl_get_input(form->EpsFile); buf = MakeAbsPath(owner->getFileName()); buf2 = OnlyPath(buf); if (!p.empty()) { buf = MakeAbsPath(p, buf2); buf = OnlyPath(buf); } else { buf = OnlyPath(owner->getFileName().c_str()); } // Does user clipart directory exist? bufclip = AddName (user_lyxdir, "clipart"); FileInfo fileInfo(bufclip); if (!(fileInfo.isOK() && fileInfo.isDir())) // No - bail out to system clipart directory bufclip = AddName (system_lyxdir, "clipart"); fileDlg.SetButton(0, _("Clipart"), bufclip); fileDlg.SetButton(1, _("Document"), buf); bool error = false; do { ProhibitInput(); if (once) { p =fileDlg.Select(_("EPS Figure"), current_figure_path, "*ps", LString()); } else { p = fileDlg.Select(_("EPS Figure"), buf, "*ps", LString()); } AllowInput(); if (p.empty()) return; buf = MakeRelPath(p, buf2); current_figure_path = OnlyPath(p); once = 1; if (p.contains("#") || p.contains("~") || p.contains("$") || p.contains("%") || p.contains(" ")) { WriteAlert(_("Filename can't contain any of these characters:"), // xgettext:no-c-format _("space, '#', '~', '$' or '%'.")); error = true; } } while (error); if (form) fl_set_input(form->EpsFile, buf.c_str()); } void GraphicsCB(FL_OBJECT *obj, long arg) { /* obj->form contains the form */ if (lyxerr.debugging()) { lyxerr.print(LString("GraphicsCB callback: ") + long(arg)); } /* find inset we were reacting to */ for (int i = 0; i < figinsref; ++i) if (figures[i]->inset->form && figures[i]->inset->form->Figure == obj->form) { if (lyxerr.debugging()) { lyxerr.print(LString("Calling back figure ") +int(i)); } figures[i]->inset->CallbackFig(arg); return; } } void HideFiguresPopups() { for (int i = 0; i < figinsref; ++i) if (figures[i]->inset->form && figures[i]->inset->form->Figure->visible) { if (lyxerr.debugging()) { lyxerr.print(LString("Hiding figure ") +int(i)); } // hide and free the form figures[i]->inset->CallbackFig(9); } }