lyx_mirror/src/insets/figinset.C
Angus Leeming 47b06816be Add LColor::graphicsbg and use it in the graphics and figure insets.
Ensures that a figure with a transparent colour can be viewed
easily if the LyX screen's background colour is dark.

Prevent deletion of the image file if no conversion is required.

This patch works like a charm with the (old) figinset. When testing
the graphics inset, however, I find that colour "None" in an XPM file
is displayed as black. I have no idea why. This appears to be true of
some other graphics viewers also. E.g., KDE 2's pixie displays "None"
as black but the venerable xv works fine.

Maybe it's my version of the xpm library, but v3.4.11 appears to be
right up to date.

Can people test on their machines and/or offer suggestions here?
Angus

p.s. You can test with the XPM files in lib/images. They will no longer
be deleted if you load them into LyX!

A.


git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@2777 a592a061-630c-0410-9148-cb99ea01b6c8
2001-09-20 13:16:17 +00:00

2054 lines
49 KiB
C

/*
* figinset.C - part of LyX project
*/
/* 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 <config.h>
#include <fstream>
#include <queue>
#include <list>
#include <algorithm>
#include <vector>
#include <utility>
#include <unistd.h>
#include <csignal>
#include <sys/wait.h>
#include FORMS_H_LOCATION
#include <cstdlib>
#include <cctype>
#include <cmath>
#include <cerrno>
#include "figinset.h"
#include "lyx_main.h"
#include "buffer.h"
#include "frontends/FileDialog.h"
#include "support/filetools.h"
#include "LyXView.h" // just because of form_main
#include "debug.h"
#include "LaTeXFeatures.h"
#include "lyxrc.h"
#include "gettext.h"
#include "lyx_gui_misc.h" // CancelCloseBoxCB
#include "support/FileInfo.h"
#include "support/lyxlib.h"
#include "support/os.h"
#include "Painter.h"
#include "font.h"
#include "bufferview_funcs.h"
#include "ColorHandler.h"
#include "converter.h"
#include "frontends/Dialogs.h" // redrawGUI
#include "BufferView.h"
using std::ostream;
using std::istream;
using std::ofstream;
using std::ifstream;
using std::queue;
using std::list;
using std::vector;
using std::find;
using std::flush;
using std::endl;
using std::copy;
using std::pair;
using std::make_pair;
#ifndef CXX_GLOBAL_CSTD
using std::memcpy;
using std::sin;
using std::cos;
using std::fabs;
#endif
extern BufferView * current_view;
extern FL_OBJECT * figinset_canvas;
extern char ** environ; // is this only redundtant on linux systems? Lgb.
// xforms doesn't define this (but it should be in <forms.h>).
extern "C"
FL_APPEVENT_CB fl_set_preemptive_callback(Window, FL_APPEVENT_CB, void *);
namespace {
float const DEG2PI = 57.295779513;
struct queue_element {
float rx, ry; // resolution x and y
int ofsx, ofsy; // x and y translation
figdata * data; // we are doing it for this data
};
int const MAXGS = 3; /* maximum 3 gs's at a time */
typedef vector<Figref *> figures_type;
typedef vector<figdata *> bitmaps_type;
figures_type figures; // all figures
bitmaps_type bitmaps; // all bitmaps
queue<queue_element> gsqueue; // queue for ghostscripting
int gsrunning = 0; /* currently so many gs's are running */
bool bitmap_waiting = false; /* bitmaps are waiting finished */
bool gs_color; // do we allocate colors for gs?
bool color_visual; // is the visual color?
bool gs_xcolor = false; // allocated extended colors
unsigned long gs_pixels[128]; // allocated pixels
int gs_spc; // shades per color
int gs_allcolors; // number of all colors
list<int> pidwaitlist; // pid wait list
GC createGC()
{
XGCValues val;
val.foreground = BlackPixel(fl_get_display(),
DefaultScreen(fl_get_display()));
val.function=GXcopy;
val.graphics_exposures = false;
val.line_style = LineSolid;
val.line_width = 0;
return XCreateGC(fl_get_display(), RootWindow(fl_get_display(), 0),
GCForeground | GCFunction | GCGraphicsExposures
| GCLineWidth | GCLineStyle , &val);
}
GC local_gc_copy;
void addpidwait(int pid)
{
// adds pid to pid wait list
pidwaitlist.push_back(pid);
if (lyxerr.debugging()) {
lyxerr << "Pids to wait for: \n";
copy(pidwaitlist.begin(), pidwaitlist.end(),
std::ostream_iterator<int>(lyxerr, "\n"));
lyxerr << flush;
}
}
string make_tmp(int pid)
{
return system_tempdir + "/~lyxgs" + tostr(pid) + ".ps";
}
void kill_gs(int pid, int sig)
{
if (lyxerr.debugging())
lyxerr << "Killing gs " << pid << endl;
lyx::kill(pid, sig);
lyx::unlink(make_tmp(pid));
}
extern "C" {
static
int GhostscriptMsg(XEvent * ev, void *)
{
// bin all events not of interest
if (ev->type != ClientMessage)
return FL_PREEMPT;
XClientMessageEvent * e = reinterpret_cast<XClientMessageEvent*>(ev);
if (lyxerr.debugging()) {
lyxerr << "ClientMessage, win:[xx] gs:[" << e->data.l[0]
<< "] pm:[" << e->data.l[1] << "]" << endl;
}
// just kill gs, that way it will work for sure
// This loop looks like S**T so it probably is...
for (bitmaps_type::iterator it = bitmaps.begin();
it != bitmaps.end(); ++it)
if (static_cast<long>((*it)->bitmap) ==
static_cast<long>(e->data.l[1])) {
// found the one
figdata * p = (*it);
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
XWindowAttributes wa;
register XImage * im;
int i;
int y;
int spc1 = gs_spc - 1;
int spc2 = gs_spc * gs_spc;
int wid = p->wid;
int forkstat;
Display * tmpdisp;
GC gc = local_gc_copy;
XGetWindowAttributes(fl_get_display(),
fl_get_canvas_id(
figinset_canvas),
&wa);
XFlush(fl_get_display());
if (lyxerr.debugging()) {
lyxerr << "Starting image translation "
<< p->bitmap << " "
<< p->flags << " "
<< p->wid << "x" << p->hgh
<< " " << wa.depth
<< " " << XYPixmap << endl;
}
// now fork rendering process
forkstat = fork();
if (forkstat == -1) {
lyxerr[Debug::INFO]
<< "Cannot fork, using slow "
"method for pixmap translation." << endl;
tmpdisp = fl_get_display();
} else if (forkstat > 0) { // parent
// register child
if (lyxerr.debugging()) {
lyxerr << "Spawned child "
<< forkstat << endl;
}
addpidwait(forkstat);
break;
} else { // child
tmpdisp = XOpenDisplay(DisplayString(fl_get_display()));
XFlush(tmpdisp);
}
im = XGetImage(tmpdisp, p->bitmap, 0, 0,
p->wid, p->hgh, (1<<wa.depth)-1, XYPixmap);
XFlush(tmpdisp);
if (lyxerr.debugging()) {
lyxerr << "Got the image" << endl;
}
if (!im) {
if (lyxerr.debugging()) {
lyxerr << "Error getting the image" << endl;
}
goto noim;
}
{
// query current colormap
XColor * cmap = new XColor[gs_allcolors];
for (i = 0; i < gs_allcolors; ++i) cmap[i].pixel = i;
XQueryColors(tmpdisp,
fl_state[fl_get_vclass()]
.colormap, cmap,
gs_allcolors);
XFlush(tmpdisp);
// now we process all the image
for (y = 0; y < p->hgh; ++y) {
for (int x = 0; x < wid; ++x) {
XColor * 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);
}
}
// This must be correct.
delete [] cmap;
if (lyxerr.debugging()) {
lyxerr << "Putting image back"
<< endl;
}
XPutImage(tmpdisp, p->bitmap,
gc, im, 0, 0,
0, 0, p->wid, p->hgh);
XDestroyImage(im);
if (lyxerr.debugging()) {
lyxerr << "Done translation"
<< endl;
}
}
noim:
kill_gs(p->gspid, SIGHUP);
if (forkstat == 0) {
XCloseDisplay(tmpdisp);
_exit(0);
}
} else {
kill_gs(p->gspid, SIGHUP);
}
break;
}
return FL_PREEMPT;
}
}
void AllocColors(int num)
// allocate color cube numxnumxnum, if possible
{
if (lyxerr.debugging()) {
lyxerr << "Allocating color cube " << num
<< 'x' << num << 'x' << num << endl;
}
if (num <= 1) {
lyxerr << "Error allocating color colormap." << endl;
gs_color = false;
return;
}
if (num > 5) num = 5;
XColor xcol;
for (int i = 0; i < num * num * num; ++i) {
xcol.red = short(65535 * (i / (num * num)) / (num - 1));
xcol.green = short(65535 * ((i / num) % num) / (num - 1));
xcol.blue = short(65535 * (i % num) / (num - 1));
xcol.flags = DoRed | DoGreen | DoBlue;
if (!XAllocColor(fl_get_display(),
fl_state[fl_get_vclass()].colormap, &xcol)) {
if (i) XFreeColors(fl_get_display(),
fl_state[fl_get_vclass()].colormap,
gs_pixels, i, 0);
if (lyxerr.debugging()) {
lyxerr << "Cannot allocate color cube "
<< num << endl;;
}
AllocColors(num - 1);
return;
}
gs_pixels[i] = xcol.pixel;
}
gs_color = true;
gs_spc = num;
}
// allocate grayscale ramp
void AllocGrays(int num)
{
if (lyxerr.debugging()) {
lyxerr << "Allocating grayscale colormap "
<< num << endl;
}
if (num < 4) {
lyxerr << "Error allocating grayscale colormap." << endl;
gs_color = false;
return;
}
if (num > 128) num = 128;
XColor xcol;
for (int i = 0; i < num; ++i) {
xcol.red = xcol.green = xcol.blue = short(65535 * i / (num - 1));
xcol.flags = DoRed | DoGreen | DoBlue;
if (!XAllocColor(fl_get_display(),
fl_state[fl_get_vclass()].colormap, &xcol)) {
if (i) XFreeColors(fl_get_display(),
fl_state[fl_get_vclass()].colormap,
gs_pixels, i, 0);
if (lyxerr.debugging()) {
lyxerr << "Cannot allocate grayscale "
<< num << endl;
}
AllocGrays(num / 2);
return;
}
gs_pixels[i] = xcol.pixel;
}
gs_color = true;
}
void InitFigures()
{
// if bitmaps and figures are not empty we will leak mem
figures.clear();
bitmaps.clear();
// allocate color cube on pseudo-color display
// first get visual
gs_color = false;
if (lyxrc.use_gui) {
/* we want to capture every event, in order to work around an
* xforms bug.
*/
fl_set_preemptive_callback(fl_get_canvas_id(figinset_canvas), GhostscriptMsg, 0);
local_gc_copy = createGC();
Visual * vi = DefaultVisual(fl_get_display(),
DefaultScreen(fl_get_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()
{
// if bitmaps and figures are not empty we will leak mem
bitmaps.clear();
figures.clear();
lyxerr[Debug::INFO] << "Unregistering figures..." << endl;
}
void freefigdata(figdata * tmpdata)
{
tmpdata->ref--;
if (tmpdata->ref) return;
if (tmpdata->gspid > 0) {
int pid = tmpdata->gspid;
// kill ghostscript and unlink it's files
tmpdata->gspid = -1;
kill_gs(pid, SIGKILL);
}
if (tmpdata->bitmap) XFreePixmap(fl_get_display(), tmpdata->bitmap);
bitmaps.erase(find(bitmaps.begin(), bitmaps.end(), tmpdata));
delete tmpdata;
}
void runqueue()
{
// This _have_ to be set before the fork!
unsigned long background_pixel =
lyxColorHandler->colorPixel(LColor::graphicsbg);
// 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) {
//char tbuf[384]; //, tbuf2[80];
Atom * prop;
int nprop, i;
if (gsqueue.empty()) {
if (!gsrunning && gs_xcolor) {
// de-allocate rest of colors
// *****
gs_xcolor = false;
}
return;
}
queue_element * p = &gsqueue.front();
if (!p->data) {
gsqueue.pop();
continue;
}
int pid = ::fork();
if (pid == -1) {
if (lyxerr.debugging()) {
lyxerr << "GS start error! Cannot fork."
<< endl;
}
p->data->broken = true;
p->data->reading = false;
return;
}
if (pid == 0) { // child
char ** env;
int ne = 0;
Display * tempdisp = XOpenDisplay(DisplayString(fl_get_display()));
// create translation file
ofstream ofs;
ofs.open(make_tmp(getpid()).c_str());
ofs << "gsave clippath pathbbox grestore\n"
<< "4 dict begin\n"
<< "/ury exch def /urx exch def /lly exch def "
"/llx exch def\n"
<< p->data->wid / 2.0 << " "
<< p->data->hgh / 2.0 << " translate\n"
<< p->data->angle << " rotate\n"
<< -(p->data->raw_wid / 2.0) << " "
<< -(p->data->raw_hgh / 2.0) << " translate\n"
<< p->rx / 72.0 << " " << p->ry / 72.0
<< " scale\n"
<< -p->ofsx << " " << -p->ofsy << " translate\n"
<< "end" << endl;
ofs.close(); // Don't remove this.
// gs process - set ghostview environment first
ostringstream t2;
t2 << "GHOSTVIEW=" << fl_get_canvas_id(figinset_canvas)
<< ' ' << p->data->bitmap;
// now set up ghostview property on a window
// #ifdef WITH_WARNINGS
// #warning BUG seems that the only bug here
// might be the hardcoded dpi.. Bummer!
// #endif
ostringstream t1;
t1 << "0 0 0 0 " << p->data->wid << ' '
<< p->data->hgh << " 72 72 0 0 0 0";
if (lyxerr.debugging()) {
lyxerr << "Will set GHOSTVIEW property to ["
<< t1.str() << "]" << endl;
}
// wait until property is deleted if executing multiple
// ghostscripts
XGrabServer(tempdisp);
for (;;) {
// grab server to prevent other child
// interfering with setting GHOSTVIEW property
// The grabbing goes on for too long, is it
// really needed? (Lgb)
// I moved most of the grabs... (Lgb)
if (lyxerr.debugging()) {
lyxerr << "Grabbing the server"
<< endl;
}
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 (compare(p, "GHOSTVIEW") == 0) {
err = false;
// We free it when we leave so we don't leak.
XFree(p);
break;
}
XFree(p);
}
XFree(reinterpret_cast<char *>(prop)); // jc:
if (err) break;
// ok, property found, we must wait until
// ghostscript deletes it
if (lyxerr.debugging()) {
lyxerr << "Releasing the server\n["
<< getpid()
<< "] GHOSTVIEW property"
" found. Waiting." << endl;
}
XUngrabServer(tempdisp);
XFlush(tempdisp);
::sleep(1);
XGrabServer(tempdisp);
}
XChangeProperty(tempdisp,
fl_get_canvas_id(figinset_canvas),
XInternAtom(tempdisp, "GHOSTVIEW", false),
XInternAtom(tempdisp, "STRING", false),
8, PropModeAppend,
reinterpret_cast<unsigned char*>(const_cast<char*>(t1.str().c_str())),
int(t1.str().size()));
XUngrabServer(tempdisp);
XFlush(tempdisp);
ostringstream t3;
switch (p->data->flags & 3) {
case 0: t3 << 'H'; break; // Hidden
case 1: t3 << 'M'; break; // Mono
case 2: t3 << 'G'; break; // Gray
case 3:
if (color_visual)
t3 << 'C'; // Color
else
t3 << 'G'; // Gray
break;
}
t3 << ' ' << BlackPixelOfScreen(DefaultScreenOfDisplay(tempdisp))
<< ' ' << background_pixel;
XGrabServer(tempdisp);
XChangeProperty(tempdisp,
fl_get_canvas_id(figinset_canvas),
XInternAtom(tempdisp,
"GHOSTVIEW_COLORS", false),
XInternAtom(tempdisp, "STRING", false),
8, PropModeReplace,
reinterpret_cast<unsigned char*>(const_cast<char*>(t3.str().c_str())),
int(t3.str().size()));
XUngrabServer(tempdisp);
XFlush(tempdisp);
if (lyxerr.debugging()) {
lyxerr << "Releasing the server" << endl;
}
XCloseDisplay(tempdisp);
// set up environment
while (environ[ne])
++ne;
typedef char * char_p;
env = new char_p[ne + 2];
string tmp = t2.str().c_str();
env[0] = new char[tmp.size() + 1];
std::copy(tmp.begin(), tmp.end(), env[0]);
env[0][tmp.size()] = '\0';
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)
string rbuf = "-r" + tostr(p->rx) + "x" + tostr(p->ry);
string gbuf = "-g" + tostr(p->data->wid) + "x" + tostr(p->data->hgh);
// now chdir into dir with .eps file, to be on the safe
// side
lyx::chdir(OnlyPath(p->data->fname));
// make temp file name
string tmpf = make_tmp(getpid());
if (lyxerr.debugging()) {
lyxerr << "starting gs " << tmpf << " "
<< p->data->fname
<< ", pid: " << getpid() << endl;
}
int err = ::execlp(lyxrc.ps_command.c_str(),
lyxrc.ps_command.c_str(),
"-sDEVICE=x11",
"-dNOPAUSE", "-dQUIET",
"-dSAFER",
rbuf.c_str(), gbuf.c_str(), tmpf.c_str(),
p->data->fname.c_str(),
"showpage.ps", "quit.ps", "-", 0);
// if we are still there, an error occurred.
lyxerr << "Error executing ghostscript. "
<< "Code: " << err << endl;
lyxerr[Debug::INFO] << "Cmd: "
<< lyxrc.ps_command
<< " -sDEVICE=x11 "
<< tmpf << ' '
<< p->data->fname << endl;
_exit(0); // no gs?
}
// normal process (parent)
if (lyxerr.debugging()) {
lyxerr << "GS [" << pid << "] started" << endl;
}
p->data->gspid = pid;
++gsrunning;
gsqueue.pop();
}
}
void addwait(int psx, int psy, int pswid, int pshgh, figdata * data)
{
// recompute the stuff and put in the queue
queue_element p;
p.ofsx = psx;
p.ofsy = psy;
p.rx = (float(data->raw_wid) * 72.0) / pswid;
p.ry = (float(data->raw_hgh) * 72.0) / pshgh;
p.data = data;
gsqueue.push(p);
// if possible, run the queue
runqueue();
}
figdata * getfigdata(int wid, int hgh, string 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 */
if (fname.empty() || !IsFileReadable(fname))
return 0;
for (bitmaps_type::iterator it = bitmaps.begin();
it != bitmaps.end(); ++it) {
if ((*it)->wid == wid && (*it)->hgh == hgh &&
(*it)->flags == flags && (*it)->fname == fname &&
(*it)->angle == angle) {
(*it)->ref++;
return (*it);
}
}
figdata * p = new figdata;
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;
bitmaps.push_back(p);
XWindowAttributes wa;
XGetWindowAttributes(fl_get_display(), fl_get_canvas_id(
figinset_canvas), &wa);
if (lyxerr.debugging()) {
lyxerr << "Create pixmap disp:" << fl_get_display()
<< " scr:" << DefaultScreen(fl_get_display())
<< " w:" << wid
<< " h:" << hgh
<< " depth:" << wa.depth << endl;
}
p->ref = 1;
p->reading = false;
p->broken = false;
p->gspid = -1;
if (flags) {
p->bitmap = XCreatePixmap(fl_get_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;
}
void getbitmap(figdata * p)
{
p->gspid = -1;
}
void makeupdatelist(figdata * p)
{
for (figures_type::iterator it = figures.begin();
it != figures.end(); ++it)
if ((*it)->data == p) {
if (lyxerr.debugging()) {
lyxerr << "Updating inset "
<< (*it)->inset
<< endl;
}
// add inset figures[i]->inset into to_update list
current_view->pushIntoUpdateList((*it)->inset);
}
}
} // namespace anon
// this func is only "called" in spellchecker.C
void sigchldchecker(pid_t pid, int * status)
{
lyxerr[Debug::INFO] << "Got pid = " << pid << endl;
bool pid_handled = false;
for (bitmaps_type::iterator it = bitmaps.begin();
it != bitmaps.end(); ++it) {
if ((*it)->reading && pid == (*it)->gspid) {
lyxerr[Debug::INFO] << "Found pid in bitmaps" << endl;
// now read the file and remove it from disk
figdata * p = (*it);
p->reading = false;
if ((*it)->gsdone) *status = 0;
if (*status == 0) {
lyxerr[Debug::INFO] << "GS [" << pid
<< "] exit OK." << endl;
} else {
lyxerr << "GS [" << pid << "] error "
<< *status << " E:"
<< WIFEXITED(*status)
<< " " << WEXITSTATUS(*status)
<< " S:" << WIFSIGNALED(*status)
<< " " << WTERMSIG(*status) << endl;
}
if (*status == 0) {
bitmap_waiting = true;
p->broken = false;
} else {
// remove temporary files
lyx::unlink(make_tmp(p->gspid));
p->gspid = -1;
p->broken = true;
}
makeupdatelist((*it));
--gsrunning;
runqueue();
pid_handled = true;
}
}
if (!pid_handled) {
lyxerr[Debug::INFO] << "Checking pid in pidwait" << endl;
list<int>::iterator it = find(pidwaitlist.begin(),
pidwaitlist.end(), pid);
if (it != pidwaitlist.end()) {
lyxerr[Debug::INFO] << "Found pid in pidwait\n"
<< "Caught child pid of recompute "
"routine" << pid << endl;
pidwaitlist.erase(it);
}
}
if (pid == -1) {
lyxerr[Debug::INFO] << "waitpid error" << endl;
switch (errno) {
case ECHILD:
lyxerr << "The process or process group specified by "
"pid does not exist or is not a child of "
"the calling process or can never be in the "
"states specified by options." << endl;
break;
case EINTR:
lyxerr << "waitpid() was interrupted due to the "
"receipt of a signal sent by the calling "
"process." << endl;
break;
case EINVAL:
lyxerr << "An invalid value was specified for "
"options." << endl;
break;
default:
lyxerr << "Unknown error from waitpid" << endl;
break;
}
} else if (pid == 0) {
lyxerr << "waitpid nohang" << endl;;
} else {
lyxerr[Debug::INFO] << "normal exit from childhandler" << endl;
}
}
namespace {
void getbitmaps()
{
bitmap_waiting = false;
for (bitmaps_type::iterator it = bitmaps.begin();
it != bitmaps.end(); ++it)
if ((*it)->gspid > 0 && !(*it)->reading)
getbitmap((*it));
}
void RegisterFigure(InsetFig * fi)
{
if (figures.empty()) InitFigures();
fi->form = 0;
Figref * tmpfig = new Figref;
tmpfig->data = 0;
tmpfig->inset = fi;
figures.push_back(tmpfig);
fi->figure = tmpfig;
if (lyxerr.debugging() && current_view) {
lyxerr << "Register Figure: buffer:["
<< current_view->buffer() << "]" << endl;
}
}
void UnregisterFigure(InsetFig * fi)
{
if (!lyxrc.use_gui)
return;
Figref * tmpfig = fi->figure;
if (tmpfig->data) freefigdata(tmpfig->data);
if (tmpfig->inset->form) {
if (tmpfig->inset->form->Figure->visible) {
fl_set_focus_object(tmpfig->inset->form->Figure,
tmpfig->inset->form->OkBtn);
fl_hide_form(tmpfig->inset->form->Figure);
}
#if FL_REVISION == 89
// CHECK Reactivate this free_form calls
#else
fl_free_form(tmpfig->inset->form->Figure);
free(tmpfig->inset->form); // Why free?
tmpfig->inset->form = 0;
#endif
}
figures.erase(find(figures.begin(), figures.end(), tmpfig));
delete tmpfig;
if (figures.empty()) DoneFigures();
}
} // namespace anon
InsetFig::InsetFig(int tmpx, int tmpy, Buffer const & 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;
pswid = pshgh = 0;
raw_wid = raw_hgh = 0;
changedfname = false;
RegisterFigure(this);
r_ = Dialogs::redrawGUI.connect(SigC::slot(this, &InsetFig::redraw));
}
InsetFig::~InsetFig()
{
if (lyxerr.debugging()) {
lyxerr << "Figure destructor called" << endl;
}
UnregisterFigure(this);
r_.disconnect();
}
void InsetFig::redraw()
{
if (form && form->Figure->visible)
fl_redraw_form(form->Figure);
}
int InsetFig::ascent(BufferView *, LyXFont const &) const
{
return hgh + 3;
}
int InsetFig::descent(BufferView *, LyXFont const &) const
{
return 1;
}
int InsetFig::width(BufferView *, LyXFont const &) const
{
return wid + 2;
}
void InsetFig::draw(BufferView * bv, LyXFont const & f,
int baseline, float & x, bool) const
{
LyXFont font(f);
Painter & pain = bv->painter();
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.
if (figure && figure->data && figure->data->bitmap &&
!figure->data->reading && !figure->data->broken) {
// draw the bitmap
pain.pixmap(int(x + 1), baseline - hgh,
wid, hgh, figure->data->bitmap);
if (flags & 4)
pain.rectangle(int(x), baseline - hgh - 1,
wid + 1, hgh + 1);
} else {
//char const * msg = 0;
string msg;
string lfname = fname;
if (!fname.empty() && GetExtension(fname).empty())
lfname += ".eps";
// draw frame
pain.rectangle(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 (!IsFileReadable(lfname))
msg = _("[bad file name]");
else if ((flags & 3) == 0)
msg = _("[not displayed]");
else if (lyxrc.ps_command.empty())
msg = _("[no ghostscript]");
if (msg.empty()) msg = _("[unknown error]");
font.setFamily(LyXFont::SANS_FAMILY);
font.setSize(LyXFont::SIZE_FOOTNOTE);
string const justname = OnlyFilename (fname);
pain.text(int(x + 8), baseline - lyxfont::maxAscent(font) - 4,
justname, font);
font.setSize(LyXFont::SIZE_TINY);
pain.text(int(x + 8), baseline - 4, msg, font);
}
x += width(bv, font); // ?
}
void InsetFig::write(Buffer const *, ostream & os) const
{
regenerate();
os << "Figure size " << wid << " " << hgh << "\n";
if (!fname.empty()) {
string buf1 = OnlyPath(owner->fileName());
string fname2 = MakeRelPath(fname, buf1);
os << "file " << fname2 << "\n";
}
if (!subcaption.empty())
os << "subcaption " << subcaption << "\n";
if (wtype) os << "width " << static_cast<int>(wtype) << " " << xwid << "\n";
if (htype) os << "height " << static_cast<int>(htype) << " " << xhgh << "\n";
if (angle != 0) os << "angle " << angle << "\n";
os << "flags " << flags << "\n";
if (subfigure) os << "subfigure\n";
}
void InsetFig::read(Buffer const *, LyXLex & lex)
{
string buf;
bool finished = false;
while (lex.isOK() && !finished) {
lex.next();
string const token = lex.getString();
lyxerr[Debug::INFO] << "Token: " << token << endl;
if (token.empty())
continue;
else if (token == "\\end_inset") {
finished = true;
} else if (token == "file") {
if (lex.next()) {
buf = lex.getString();
string const buf1(OnlyPath(owner->fileName()));
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::INFO] << "Unknown type!" << endl;
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::INFO] << "Unknown type!" << endl;
break;
}
thtype = htype;
}
}
regenerate();
recompute();
}
int InsetFig::latex(Buffer const *, ostream & os,
bool /* fragile*/, bool /* fs*/) const
{
regenerate();
if (!cmd.empty()) os << cmd << " ";
return 0;
}
int InsetFig::ascii(Buffer const *, ostream &, int) const
{
return 0;
}
int InsetFig::linuxdoc(Buffer const *, ostream &) const
{
return 0;
}
int InsetFig::docbook(Buffer const *, ostream & os) const
{
string const buf1 = OnlyPath(owner->fileName());
string figurename = MakeRelPath(fname, buf1);
if (suffixIs(figurename, ".eps"))
figurename.erase(figurename.length() - 4);
os << "@<graphic fileref=\"" << figurename << "\"></graphic>";
return 0;
}
void InsetFig::validate(LaTeXFeatures & features) const
{
features.graphics = true;
if (subfigure) features.subfigure = true;
}
Inset::EDITABLE InsetFig::editable() const
{
return IS_EDITABLE;
}
bool InsetFig::deletable() const
{
return false;
}
string const InsetFig::editMessage() const
{
return _("Opened figure");
}
void InsetFig::edit(BufferView * bv, int, int, unsigned int)
{
lyxerr[Debug::INFO] << "Editing InsetFig." << endl;
regenerate();
// We should have RO-versions of the form instead.
// The actual prevention of altering a readonly doc
// is done in CallbackFig()
if (bv->buffer()->isReadonly())
WarnReadonly(bv->buffer()->fileName());
if (!form) {
form = create_form_Figure();
fl_set_form_atclose(form->Figure, CancelCloseBoxCB, 0);
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_FREE_SIZE, FL_TRANSIENT,
_("Figure"));
}
}
void InsetFig::edit(BufferView * bv, bool)
{
edit(bv, 0, 0, 0);
}
Inset * InsetFig::clone(Buffer const & buffer, bool) const
{
InsetFig * tmp = new InsetFig(100, 100, buffer);
if (lyxerr.debugging()) {
lyxerr << "Clone Figure: buffer:["
<< &buffer
<< "], cbuffer:[xx]" << endl;
}
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;
string lfname = fname;
if (!fname.empty() && GetExtension(fname).empty())
lfname += ".eps";
if (!fname.empty() && IsFileReadable(lfname)
&& (flags & 3) && !lyxrc.ps_command.empty()
&& lyxrc.use_gui) {
// do not display if there is
// "do not display" chosen (Matthias 260696)
tmp->figure->data = getfigdata(wid, hgh, lfname, psx, psy,
pswid, pshgh, raw_wid, raw_hgh,
angle, flags & (3|8));
} else tmp->figure->data = 0;
tmp->subcaption = subcaption;
tmp->changedfname = false;
tmp->owner = owner;
tmp->regenerate();
return tmp;
}
Inset::Code InsetFig::lyxCode() const
{
return Inset::GRAPHICS_CODE;
}
namespace {
string const stringify(InsetFig::HWTYPE hw, float f, string suffix)
{
string res;
switch (hw) {
case InsetFig::DEF:
break;
case InsetFig::CM:// \resizebox*{h-length}{v-length}{text}
res = tostr(f) + "cm";
break;
case InsetFig::IN:
res = tostr(f) + "in";
break;
case InsetFig::PER_PAGE:
res = tostr(f/100) + "\\text" + suffix;
break;
case InsetFig::PER_COL:
// Doesn't occur for htype...
res = tostr(f/100) + "\\column" + suffix;
break;
}
return res;
}
} // namespace anon
void InsetFig::regenerate() const
{
string cmdbuf;
string resizeW;
string resizeH;
string rotate;
string recmd;
if (fname.empty()) {
cmd = "\\fbox{\\rule[-0.5in]{0pt}{1in}";
cmd += _("empty figure path");
cmd += '}';
return;
}
string buf1 = OnlyPath(owner->fileName());
string fname2 = MakeRelPath(fname, buf1);
string gcmd = "\\includegraphics{" + fname2 + '}';
resizeW = stringify(wtype, xwid, "width");
resizeH = stringify(htype, xhgh, "height");
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) {
// \rotatebox{angle}{text}
rotate = "\\rotatebox{" + tostr(angle) + "}{";
}
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;
}
void InsetFig::tempRegenerate()
{
string cmdbuf;
string resizeW;
string resizeH;
string rotate;
string recmd;
char const * tfname = fl_get_input(form->EpsFile);
string tsubcap = fl_get_input(form->Subcaption);
float tangle = atof(fl_get_input(form->Angle));
float txwid = atof(fl_get_input(form->Width));
float txhgh = atof(fl_get_input(form->Height));
if (!tfname || !*tfname) {
cmd = "\\fbox{\\rule[-0.5in]{0pt}{1in}";
cmd += _("empty figure path");
cmd += '}';
return;
}
string buf1 = OnlyPath(owner->fileName());
string fname2 = MakeRelPath(tfname, buf1);
// \includegraphics*[<llx,lly>][<urx,ury>]{file}
string gcmd = "\\includegraphics{" + fname2 + '}';
resizeW = stringify(twtype, txwid, "width");
resizeH = stringify(thtype, txhgh, "height");
// \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) {
// \rotatebox{angle}{text}
rotate = "\\rotatebox{" + tostr(tangle) + "}{";
}
cmdbuf = recmd + rotate + gcmd;
if (!rotate.empty()) cmdbuf += '}';
if (!recmd.empty()) cmdbuf += '}';
if (psubfigure && !tsubcap.empty()) {
cmdbuf = string("\\subfigure{") + tsubcap
+ string("}{") + cmdbuf + "}";
}
}
void InsetFig::recompute()
{
if (!lyxrc.use_gui)
return;
bool changed = changedfname;
int newx, newy, nraw_x, nraw_y;
if (changed) getPSSizes();
float sin_a = sin(angle / DEG2PI); /* rotation; H. Zeller 021296 */
float cos_a = cos(angle / DEG2PI);
int frame_wid = int(ceil(fabs(cos_a * pswid) + fabs(sin_a * pshgh)));
int frame_hgh= int(ceil(fabs(cos_a * pshgh) + fabs(sin_a * pswid)));
string lfname = fname;
if (GetExtension(fname).empty())
lfname += ".eps";
/* 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 (!lfname.empty() && IsFileReadable(lfname)) {
// 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:
//lyxerr << "This should not happen!" << endl;
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 (!lfname.empty() && IsFileReadable(lfname) && (flags & 3)
&& !lyxrc.ps_command.empty()) {
// do not display if there is "do not display"
// chosen (Matthias 260696)
figure->data = getfigdata(wid, hgh, lfname,
psx, psy, pswid, pshgh,
raw_wid, raw_hgh,
angle, flags & (3|8));
} else figure->data = 0;
// free the old data
if (pf) freefigdata(pf);
}
changedfname = false;
}
void InsetFig::getPSSizes()
{
/* get %%BoundingBox: from postscript file */
/* 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;
string p;
string lfname = fname;
if (GetExtension(fname).empty())
lfname += ".eps";
ifstream ifs(lfname.c_str());
if (!ifs) return; // file not found !!!!
/* defaults to A4 page */
psx = 0;
psy = 0;
pswid = 595;
pshgh = 842;
char lastchar = 0; ifs.get(lastchar);
for (;;) {
char c = 0; ifs.get(c);
if (ifs.eof()) {
lyxerr[Debug::INFO] << "End of (E)PS file reached and"
" no BoundingBox!" << endl;
break;
}
if (c == '%' && lastchar == '%') {
ifs >> p;
if (p.empty()) break;
lyxerr[Debug::INFO] << "Token: `" << p << "'" << endl;
if (p == "BoundingBox:") {
float fpsx, fpsy, fpswid, fpshgh;
if (ifs >> fpsx >> fpsy >> fpswid >> fpshgh) {
psx = int(fpsx);
psy = int(fpsy);
pswid = int(fpswid);
pshgh = int(fpshgh);
}
if (lyxerr.debugging()) {
lyxerr << "%%%%BoundingBox:"
<< psx << ' '
<< psy << ' '
<< pswid << ' '
<< pshgh << endl;
}
break;
}
c = 0;
}
lastchar = c;
}
pswid -= psx;
pshgh -= psy;
}
void InsetFig::callbackFig(long arg)
{
bool regen = false;
char const * p;
if (lyxerr.debugging()) {
lyxerr << "Figure callback, arg " << arg << endl;
}
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::INFO] << "Unknown type!" << endl;
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::INFO] << "Unknown type!" << endl;
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->buffer()->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) {
string buf1 = OnlyPath(owner->fileName());
fname = MakeAbsPath(p, buf1);
changedfname = true;
} else {
if (!fname.empty()) {
changedfname = true;
fname.erase();
}
}
subcaption = fl_get_input(form->Subcaption);
regenerate();
recompute();
/* now update inset */
if (lyxerr.debugging()) {
lyxerr << "Update: ["
<< wid << 'x' << hgh << ']' << endl;
}
current_view->updateInset(this, true);
if (arg == 8) {
fl_set_focus_object(form->Figure, form->OkBtn);
fl_hide_form(form->Figure);
#if FL_REVISION == 89
// CHECK Reactivate this free_form calls
#else
fl_free_form(form->Figure);
free(form); // Why free?
form = 0;
#endif
}
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_set_focus_object(form->Figure, form->OkBtn);
fl_hide_form(form->Figure);
#if FL_REVISION == 89
// CHECK Reactivate this free_form calls
// Jug, is this still a problem?
#else
fl_free_form(form->Figure);
free(form); // Why free?
form = 0;
#endif
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()
{
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);
}
int piflags = flags & 3;
fl_set_button(form->Wysiwyg0, (piflags == 0));
fl_set_button(form->Wysiwyg1, (piflags == 1));
fl_set_button(form->Wysiwyg2, (piflags == 2));
fl_set_button(form->Wysiwyg3, (piflags == 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;
fl_set_input(form->Width, tostr(xwid).c_str());
fl_set_input(form->Height, tostr(xhgh).c_str());
fl_set_input(form->Angle, tostr(angle).c_str());
if (!fname.empty()){
string buf1 = OnlyPath(owner->fileName());
string 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->buffer()->isReadonly())
DisableFigurePanel(form);
tempRegenerate();
}
void InsetFig::preview(string const & p)
{
string tfname = p;
if (GetExtension(tfname).empty())
tfname += ".eps";
string buf1 = OnlyPath(owner->fileName());
string buf2 = os::external_path(MakeAbsPath(tfname, buf1));
if (!formats.view(owner, buf2, "eps"))
lyxerr << "Can't view " << buf2 << endl;
}
void InsetFig::browseFile()
{
static string current_figure_path;
static int once;
if (lyxerr.debugging()) {
lyxerr << "Filename: "
<< owner->fileName() << endl;
}
string p = fl_get_input(form->EpsFile);
string buf = MakeAbsPath(owner->fileName());
string buf2 = OnlyPath(buf);
if (!p.empty()) {
buf = MakeAbsPath(p, buf2);
buf = OnlyPath(buf);
} else {
buf = OnlyPath(owner->fileName());
}
// Does user clipart directory exist?
string 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");
FileDialog fileDlg(current_view->owner(), _("Select an EPS figure"),
LFUN_SELECT_FILE_SYNC,
make_pair(string(_("Clip art")), string(bufclip)),
make_pair(string(_("Documents")), string(buf)));
bool error = false;
do {
string const path = (once) ? current_figure_path : buf;
FileDialog::Result result = fileDlg.Select(path, _("*ps| PostScript documents"));
string const p = result.second;
if (p.empty())
return;
buf = MakeRelPath(p, buf2);
current_figure_path = OnlyPath(p);
once = 1;
if (contains(p, "#") || contains(p, "~") || contains(p, "$")
|| contains(p, "%") || contains(p, " ")) {
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 << "GraphicsCB callback: " << arg << endl;
}
/* find inset we were reacting to */
for (figures_type::iterator it = figures.begin();
it != figures.end(); ++it)
if ((*it)->inset->form && (*it)->inset->form->Figure
== obj->form) {
if (lyxerr.debugging()) {
lyxerr << "Calling back figure "
<< (*it) << endl;
}
(*it)->inset->callbackFig(arg);
return;
}
}
void HideFiguresPopups()
{
for (figures_type::iterator it = figures.begin();
it != figures.end(); ++it)
if ((*it)->inset->form
&& (*it)->inset->form->Figure->visible) {
if (lyxerr.debugging()) {
lyxerr << "Hiding figure " << (*it) << endl;
}
// hide and free the form
(*it)->inset->callbackFig(9);
}
}