/* ui_file.c: user interface file menu */ #include #include #include #include #include #include "ui.h" #include "uit.h" #include "defaults.h" #include "canvas.h" #include "render.h" #include "statistics.h" #include "pools.h" #include "error.h" #include "readmgf.h" #include "fix.h" #include "appdata.h" #include "camera.h" #include "writevrml.h" #include "scene.h" #include "radiance.h" #include "fileopts.h" int force_onesided_surfaces, monochrome, nqcdivs, disable_textures; /* Forward declarations */ static void PushRecentFile(char *filename); static void UpdateCurrentFileCamera(void); /* + + + + + + + + + + + file options dialog + + + + + + + + + + + + +*/ static Widget CreateNrQuartCircDivDialog(Widget parent, char *name) { return CreatePromptDialog(parent, name, FET_INTEGER, (XtPointer)&nqcdivs, NULL, 0); } static Widget CreateFileOptionsMenu(Widget parent) { Widget menu = CreateSubMenu(parent, "fileOptionsButton", "fileOptionsMenu"); CreateToggleButton(menu, "forceOneSidednessButton", force_onesided_surfaces, NULL, (XtPointer)&force_onesided_surfaces); CreateToggleButton(menu, "disableTexturesButton", disable_textures, NULL, (XtPointer)&disable_textures); CreateToggleButton(menu, "monochromeButton", monochrome, NULL, (XtPointer)&monochrome); CreateCascadeDialog(menu, "nqcdivsButton", CreateNrQuartCircDivDialog, "nqcdivsDialog", NULL, NULL); return menu; } /* + + + + + + + + + + + + + + + load button + + + + + + + + + + + +*/ static int LoadFile(char *filename, FILE *fp, int ispipe, Widget loadBox) { int succes; if (CanvasGetMode() == CANVASMODE_WORKING) { Warning(NULL, "Interrupt computations first before loading a new scene"); return 0; /* don't unmanage the file selection box */ } if (!fp) { Error(NULL, "Please enter a file name to be loaded"); return 0; } UpdateCurrentFileCamera(); CanvasPushMode(CANVASMODE_WORKING); succes = ReadFile(filename); CanvasPullMode(); if (succes) PushRecentFile(filename); RenderNewDisplayList(); CanvasPostRedraw(); return succes; /* unmanage the file selection box if succes */ } static int LoadBgFile(char *filename, FILE *fp, int ispipe, Widget loadBox) { int succes; if (!fp) { Error(NULL, "Please enter a file name to be loaded"); return 0; } UpdateCurrentFileCamera(); CanvasPushMode(CANVASMODE_WORKING); succes = InitBackground(fp); CanvasPullMode(); RenderNewDisplayList(); CanvasPostRedraw(); return succes; /* unmanage the file selection box if succes */ } /* Creates a dialog box for selecting a file to be loaded. */ static Widget CreateLoadBox(Widget parent, char *name) { return CreateFileSelectionDialog(parent, name, LoadFile, "r"); } /* Creates a dialog box for selecting a file to be loaded. */ static Widget CreateLoadBgBox(Widget parent, char *name) { return CreateFileSelectionDialog(parent, name, LoadBgFile, "r"); } /* + + + + + + + + + + + + + + + Fix button + + + + + + + + + + + +*/ static void FixVertexOrderInViewCallback(Widget w, XtPointer client_data, XtPointer call_data) { FixVertexOrderInView(); } static void CreateFixMenu(Widget fileMenu) { Widget fixMenu; fixMenu = CreateSubMenu(fileMenu, "fixButton", "fixMenu"); CreatePushButton(fixMenu, "fixVertexOrderInViewButton", FixVertexOrderInViewCallback, (XtPointer)NULL); } /* + + + + + + + + + + + + + + + Save button + + + + + + + + + + + +*/ static int SaveImage(char *fname, FILE *fp, int ispipe, Widget saveBox) { if (!fp) return 1; /* no file to save anything to, so don't save */ /* make sure the dialog box has dissappeared before saving */ XtUnmanageChild(saveBox); CheckForEvents(); CanvasRedraw(); CanvasPushMode(CANVASMODE_WORKING); SaveScreen(fname, fp, ispipe); CanvasPullMode(); return 0; /* probably succes, but we have already unmanaged the file * selection box. */ } static Widget CreateSaveImageBox(Widget parent, char *name) { return CreateFileSelectionDialog(parent, name, SaveImage, "w"); } static int SaveModel(char *fname, FILE *fp, int ispipe, Widget saveBox) { clock_t t; if (!fp) return 1; /* no file to save anything to, so don't save */ if (!World) { Warning(NULL, "There is no model loaded"); return 1; } CanvasPushMode(CANVASMODE_WORKING); fprintf(stderr, "Saving VRML model to file '%s' ... ", fname); fflush(stderr); t = clock(); if (Radiance && Radiance->WriteVRML) Radiance->WriteVRML(fp); else WriteVRML(fp); fprintf(stderr, "%g secs.\n", (float)(clock() - t) / (float)CLOCKS_PER_SEC); CanvasPullMode(); return 1; /* assume succes, so the dialog box is unmanaged. */ } static Widget CreateSaveModelBox(Widget parent, char *name) { return CreateFileSelectionDialog(parent, name, SaveModel, "w"); } /* + + + + + + + + + + + + + + + Stats button + + + + + + + + + + + +*/ /* format string to be used for printing statistics about the current scene. * The format string is the text string assigned to the fileStatsMessage * label at startup and is extracted in CreateFileStatsBox() when creating the * interface. */ static char *fileStatsFormatString = (char *)NULL; /* XmLabelClass widgets used to display the statstics about the current scene */ static Widget fileStatsMessage = (Widget)NULL; /* updates the file statstics */ void UpdateFileStats(void) { char buf[MAX_LABEL_STRING_LENGTH]; if (!fileStatsFormatString || !fileStatsMessage) return; sprintf(buf, fileStatsFormatString, nrgeoms, nrcompounds, nrsurfaces, nrvertices, nrpatches, total_area, ColorLuminance(total_emitted_power), ColorLuminance(max_selfemitted_power), M_PI*ColorLuminance(max_selfemitted_radiance), M_PI*ColorLuminance(estimated_average_radiance), ColorGray(average_reflectivity), (int)GetMemoryUsage()/1024, (int)GetMemoryOverhead()/1024); SetLabelString(fileStatsMessage, buf); } /* called when the Update button on a stats dialog box is clicked: pops down the * statistics dialog box. */ static void UpdateFileStatsCallback(Widget statsBox, XtPointer client_data, XtPointer call_data) { UpdateFileStats(); } /* called when the Dismiss button on a stats dialog box is clicked: pops down the * statistics dialog box. */ static void DismissStatsCallback(Widget statsBox, XtPointer client_data, XtPointer call_data) { XtUnmanageChild(statsBox); } /* Creates a dialog box for showing statistics about the current scene */ static Widget CreateFileStatsBox(Widget parent, char *name) { Widget statsBox; /* create a message dialog to show some statistics about the computation */ statsBox = CreateDialog(parent, name); /* create a label widget inside the statsBox */ fileStatsMessage = CreateLabel(statsBox, "fileStatsMessage"); /* at startup, the text defined for the fileStatsMessage label widget is nothing * else than the printf format string to be used for printing the statistics. */ fileStatsFormatString = GetLabelString(fileStatsMessage); /* fill in the statstics for the current scene */ UpdateFileStats(); XtAddCallback(statsBox, XmNokCallback, UpdateFileStatsCallback, (XtPointer)NULL); XtAddCallback(statsBox, XmNcancelCallback, DismissStatsCallback, (XtPointer)NULL); return statsBox; } /* called when the user presses the 'Statistics' button in the file menu */ static void ShowFileStats(Widget statsButton, XtPointer client_data, XtPointer call_data) { Widget statsBox = (Widget)client_data; UpdateFileStats(); XtManageChild(statsBox); } /* + + + + + + + + + + + + + + + Exit button + + + + + + + + + + + +*/ /* when the user clicks the 'Exit' button in the File menu ... */ static void Exit(Widget w, XtPointer client_data, XtPointer call_data) { UpdateCurrentFileCamera(); SaveUserOptions(); exit(0); } /* + + + + + + + + + + + + Recent File management + + + + + + + + + + +*/ char *GetFilePart(char *name) { char *filepart; if(name == NULL) return NULL; filepart = rindex(name, '/'); if(filepart == NULL) { return(name); } return(filepart + 1); /* After the '/' */ } /* SetRecentFileLabels : sets file menu labels correctly */ void SetRecentFileLabels(void) { char *name; int i; for(i=0; i < NUM_RECENT_FILES; i++) { if(appData.recentFile[i].spec == NULL) { name = NULL; } else { name = GetFilePart(appData.recentFile[i].spec); } if(name == NULL || name[0] == '-') { XtUnmanageChild(appData.recentFile[i].widget); } else { XtVaSetValues(appData.recentFile[i].widget, XtVaTypedArg, XmNlabelString, XmRString, name, strlen(name)+1, NULL); XtManageChild(appData.recentFile[i].widget); } } } /* TODO : Get rid of this static */ static int IsFilePushed = 0; static void PushRecentFile(char *filename) { int i; IsFilePushed = 1; /* Check if filename is already present in the list. * Last entry is not important, since that will be discarded * anyway if the filename is not found */ i = 0; while((i < NUM_RECENT_FILES - 1) && ((appData.recentFile[i].spec == NULL) || (strcmp(filename, appData.recentFile[i].spec)))) { i++; } /* i = recent file field that can be overwritten */ /* TODO Free filename that is discarded ?? */ /* Copy other recent files */ while(i > 0) { /* Don't copy the widget !!! */ appData.recentFile[i].spec = appData.recentFile[i-1].spec; appData.recentFile[i].cam = appData.recentFile[i-1].cam; appData.recentFile[i].acam = appData.recentFile[i-1].acam; i--; } appData.recentFile[0].spec = strdup(filename); SetRecentFileLabels(); } static void LoadRecentFile(Widget w, XtPointer client_data, XtPointer call_data) { int fileNr = (int)client_data; char *filename = appData.recentFile[fileNr].spec; CAMERA oldCam, oldACam; CAMERA * newCam = &(appData.recentFile[fileNr].cam); CAMERA * newACam = &(appData.recentFile[fileNr].acam); int camPushed = FALSE; fprintf(stderr, "LoadRecentFile '%s'\n", filename); UpdateCurrentFileCamera(); CanvasPushMode(CANVASMODE_WORKING); /* Store the current camera and alternate camera */ oldCam = Camera; oldACam = AlternateCamera; if (ReadFile(filename)) { /* Set the camera */ if(!CameraCompare(&oldCam, &Camera)) { /* The camera was changed during the file read. ** We save this camera, so that it can be restored ** if needed. (The test is not foolproof, since ** the new cam can be equal to the old cam.) */ CameraPush(&Camera); camPushed = TRUE; } if(!(CameraSet(&Camera, &(newCam->eyep), &(newCam->lookp), &(newCam->updir), newCam->fov, Camera.hres, Camera.vres, &(Camera.background)))) { if(camPushed) { CameraPop(&Camera); } else { Camera = oldCam; } } /* Set the alternate camera */ if(!(CameraSet(&AlternateCamera, &(newACam->eyep), &(newACam->lookp), &(newACam->updir), newACam->fov, Camera.hres, Camera.vres, &(AlternateCamera.background)))) { Warning("LoadRecentFile","cannot set alternate camera"); AlternateCamera = oldACam; } RenderNewDisplayList(); /* Store the current camera */ oldCam = Camera; RenderScene(); PushRecentFile(filename); } CanvasPullMode(); } /* TODO : filename on command line -> recent files */ static void UpdateCurrentFileCamera(void) { /* recentFile[0] is the current file, except when no file is loaded */ if(IsFilePushed) { appData.recentFile[0].cam = Camera; appData.recentFile[0].acam = AlternateCamera; } } /* + + + + + + + + + + + + + + + File menu + + + + + + + + + + + + +*/ /* creates the File menu in the main menu bar */ void CreateFileMenu(Widget menuBar) { int i; Widget fileMenu = CreateSubMenu(menuBar, "fileButton", "fileMenu"); CreateFileOptionsMenu(fileMenu); CreateCascadeDialog(fileMenu, "loadButton", CreateLoadBox, "loadBox", NULL, NULL); CreateSeparator(fileMenu, "fileSeparator"); CreateCascadeDialog(fileMenu, "saveImageButton", CreateSaveImageBox, "saveImageBox", NULL, NULL); CreateCascadeDialog(fileMenu, "saveModelButton", CreateSaveModelBox, "saveModelBox", NULL, NULL); CreateSeparator(fileMenu, "fileSeparator"); CreateCascadeDialog(fileMenu, "loadBgButton", CreateLoadBgBox, "loadBgBox", NULL, NULL); CreateSeparator(fileMenu, "fileSeparator"); CreateCascadeDialog(fileMenu, "statsButton", CreateFileStatsBox, "statsBox", ShowFileStats, NULL); /* --------------------- Recent files ----------------------- */ CreateSeparator(fileMenu, "fileSeparator"); CreateSeparator(fileMenu, "fileSeparator"); /* NUM_RECENT_FILES Last used files */ for(i = 0; i < NUM_RECENT_FILES; i++) { char tmpStr[20]; sprintf(tmpStr, "lastFile%iButton", i); appData.recentFile[i].widget = CreatePushButton(fileMenu, tmpStr, LoadRecentFile, (XtPointer)i); } SetRecentFileLabels(); /* ------------------- Exit button ------------------- */ CreateSeparator(fileMenu, "fileSeparator"); CreateSeparator(fileMenu, "fileSeparator"); CreatePushButton(fileMenu, "exitButton", Exit, (XtPointer)NULL); }