Select Git revision
-
Christophe Geuzaine authoredChristophe Geuzaine authored
fieldWindow.cpp 13.80 KiB
// Gmsh - Copyright (C) 1997-2019 C. Geuzaine, J.-F. Remacle
//
// See the LICENSE.txt file for license information. Please report all
// issues on https://gitlab.onelab.info/gmsh/gmsh/issues.
//
// Contributor(s):
// Jonathan Lambrechts
//
#include <sstream>
#include <FL/Fl_Input.H>
#include <FL/Fl_Tabs.H>
#include <FL/Fl_Return_Button.H>
#include <FL/Fl_Check_Button.H>
#include <FL/Fl_Round_Button.H>
#include <FL/Fl_Value_Input.H>
#include <FL/fl_draw.H>
#include "FlGui.h"
#include "drawContext.h"
#include "fieldWindow.h"
#include "paletteWindow.h"
#include "fileDialogs.h"
#include "GmshDefines.h"
#include "GModel.h"
#include "PView.h"
#include "GmshMessage.h"
#include "Field.h"
#include "GeoStringInterface.h"
#include "StringUtils.h"
#include "Options.h"
#include "Context.h"
void field_cb(Fl_Widget *w, void *data)
{
FlGui::instance()->fields->win->show();
FlGui::instance()->fields->editField(NULL);
}
static void field_delete_cb(Fl_Widget *w, void *data)
{
Field *f = (Field *)FlGui::instance()->fields->editor_group->user_data();
delete_field(f->id, GModel::current()->getFileName());
FlGui::instance()->fields->editField(NULL);
}
static void field_new_cb(Fl_Widget *w, void *data)
{
Fl_Menu_Button *mb = ((Fl_Menu_Button *)w);
FieldManager *fields = GModel::current()->getFields();
int id = fields->newId();
add_field(id, mb->text(), GModel::current()->getFileName());
if((*fields)[id]) FlGui::instance()->fields->editField((*fields)[id]);
}
static void field_apply_cb(Fl_Widget *w, void *data)
{
FlGui::instance()->fields->saveFieldOptions();
}
static void field_browser_cb(Fl_Widget *w, void *data)
{
int selected = FlGui::instance()->fields->browser->value();
if(!selected) {
FlGui::instance()->fields->editField(NULL);
}
Field *f = (Field *)FlGui::instance()->fields->browser->data(selected);
FlGui::instance()->fields->editField(f);
}
static void field_put_on_view_cb(Fl_Widget *w, void *data)
{
Fl_Menu_Button *mb = ((Fl_Menu_Button *)w);
Field *field = (Field *)FlGui::instance()->fields->editor_group->user_data();
if(mb->value() == 0)
field->putOnNewView();
else if(mb->value() - 1 < (int)PView::list.size())
field->putOnView(PView::list[mb->value() - 1]);
FlGui::instance()->updateViews(mb->value() == 0, true);
drawContext::global()->draw();
}
static void field_callback_cb(Fl_Widget *w, void *data)
{
FieldCallback *cb = (FieldCallback *)data;
cb->run();
}
static void field_select_file_cb(Fl_Widget *w, void *data)
{
Fl_Input *input = (Fl_Input *)data;
int ret = fileChooser(FILE_CHOOSER_SINGLE, "Choose", "", input->value());
if(ret) {
input->value(fileChooserGetName(0).c_str());
input->set_changed();
}
}
fieldWindow::fieldWindow(int deltaFontSize) : _deltaFontSize(deltaFontSize)
{
FL_NORMAL_SIZE -= deltaFontSize;
int width0 = 34 * FL_NORMAL_SIZE + WB;
int height0 = 12 * BH + 4 * WB;
int width = (CTX::instance()->fieldSize[0] < width0) ?
width0 :
CTX::instance()->fieldSize[0];
int height = (CTX::instance()->fieldSize[1] < height0) ?
height0 :
CTX::instance()->fieldSize[1];
win = new paletteWindow(width, height,
CTX::instance()->nonModalWindows ? true : false,
"Size fields");
win->box(GMSH_WINDOW_BOX);
int x = WB, y = WB, w = (int)(1.5 * BB), h = height - 2 * WB - 3 * BH;
Fl_Menu_Button *new_btn = new Fl_Menu_Button(x, y, w, BH, "New");
FieldManager &fields = *GModel::current()->getFields();
std::map<std::string, FieldFactory *>::iterator it;
for(it = fields.map_type_name.begin(); it != fields.map_type_name.end(); it++)
new_btn->add(it->first.c_str());
new_btn->callback(field_new_cb);
y += BH;
browser = new Fl_Hold_Browser(x, y + WB, w, h - 2 * WB);
browser->callback(field_browser_cb);
y += h;
delete_btn = new Fl_Button(x, y, w, BH, "Delete");
delete_btn->callback(field_delete_cb, this);
y += BH;
put_on_view_btn = new Fl_Menu_Button(x, y, w, BH, "Visualize");
put_on_view_btn->callback(field_put_on_view_cb, this);
x += w + WB;
y = WB;
w = width - x - WB;
h = height - y - WB;
empty_message = new Fl_Box(x, y, w, h,
"Create a new field\n\n"
"- or -\n\nSelect a field in the browser");
empty_message->align(FL_ALIGN_CENTER);
editor_group = new Fl_Group(x, y, w, h);
title = new Fl_Box(x, y, w, BH, "field_name");
title->labelfont(FL_BOLD);
title->labelsize(FL_NORMAL_SIZE + 3);
y += BH + WB;
h -= BH + WB;
Fl_Tabs *tabs = new Fl_Tabs(x, y, w, h);
y += BH;
h -= BH;
x += WB;
w -= 2 * WB;
Fl_Group *options_tab = new Fl_Group(x, y, w, h, "Options");
options_scroll = new Fl_Scroll(x, y + WB, w, h - BH - 3 * WB);
options_scroll->end();
Fl_Button *apply_btn =
new Fl_Return_Button(x + w - BB, y + h - BH - WB, BB, BH, "Apply");
apply_btn->callback(field_apply_cb, this);
background_btn = new Fl_Round_Button(x, y + h - BH - WB, w - BB - WB, BH,
"Set as background field");
background_btn->tooltip(
"Only a single field can be set as background field.\n"
"To combine multiple fields use the Min or Max fields.");
options_tab->end();
Fl_Group *help_tab = new Fl_Group(x, y, w, h, "Help");
help_display = new Fl_Help_View(x, y + WB, w, h - 2 * WB);
help_display->textfont(FL_HELVETICA);
help_display->textsize(FL_NORMAL_SIZE);
help_tab->end();
tabs->end();
editor_group->end();
win->resizable(new Fl_Box((int)(1.5 * BB) + 2 * WB, BH + 2 * WB,
width - 3 * WB - (int)(1.5 * BB),
height - 3 * BH - 5 * WB));
editor_group->resizable(tabs);
tabs->resizable(options_tab);
options_tab->resizable(new Fl_Box(3 * BB + 4 * WB, BH + 2 * WB,
width - 9 * WB - 5 * BB,
height - 3 * BH - 5 * WB));
win->size_range(width0, height0);
win->position(CTX::instance()->fieldPosition[0],
CTX::instance()->fieldPosition[1]);
win->end();
FL_NORMAL_SIZE += deltaFontSize;
loadFieldViewList();
editField(NULL);
}
void fieldWindow::loadFieldViewList()
{
put_on_view_btn->clear();
put_on_view_btn->add("Create new view");
put_on_view_btn->activate();
for(unsigned int i = 0; i < PView::list.size(); i++) {
std::ostringstream s;
s << "Put on View [" << i << "]";
put_on_view_btn->add(s.str().c_str());
}
}
void fieldWindow::loadFieldList()
{
FieldManager &fields = *GModel::current()->getFields();
Field *selected_field = (Field *)editor_group->user_data();
browser->clear();
int i_entry = 0;
for(FieldManager::iterator it = fields.begin(); it != fields.end(); it++) {
i_entry++;
Field *field = it->second;
std::ostringstream sstream;
if(it->first == fields.getBackgroundField()) sstream << "@b";
sstream << it->first << " " << field->getName();
browser->add(sstream.str().c_str(), field);
if(it->second == selected_field) browser->select(i_entry);
}
}
void fieldWindow::saveFieldOptions()
{
std::list<Fl_Widget *>::iterator input = options_widget.begin();
Field *f = (Field *)editor_group->user_data();
std::ostringstream sstream;
int i;
char a;
double d;
sstream.precision(16);
for(std::map<std::string, FieldOption *>::iterator it = f->options.begin();
it != f->options.end(); it++) {
FieldOption *option = it->second;
sstream.str("");
switch(option->getType()) {
case FIELD_OPTION_STRING:
case FIELD_OPTION_PATH:
sstream << "\"" << ((Fl_Input *)*input)->value() << "\"";
break;
case FIELD_OPTION_INT:
sstream << (int)((Fl_Value_Input *)*input)->value();
break;
case FIELD_OPTION_DOUBLE:
sstream << ((Fl_Value_Input *)*input)->value();
break;
case FIELD_OPTION_BOOL:
sstream << (bool)((Fl_Check_Button *)*input)->value();
break;
case FIELD_OPTION_LIST: {
sstream << "{";
std::istringstream istream(((Fl_Input *)*input)->value());
while(istream >> i) {
sstream << i;
if(istream >> a) {
if(a != ',')
Msg::Error("Unexpected character \'%c\' while parsing option "
"'%s' of field \'%d\'",
a, it->first.c_str(), f->id);
sstream << ", ";
}
}
sstream << "}";
} break;
case FIELD_OPTION_LIST_DOUBLE: {
sstream << "{";
std::istringstream istream(((Fl_Input *)*input)->value());
while(istream >> d) {
sstream << d;
if(istream >> a) {
if(a != ',')
Msg::Error("Unexpected character \'%c\' while parsing option "
"'%s' of field \'%d\'",
a, it->first.c_str(), f->id);
sstream << ", ";
}
}
sstream << "}";
} break;
}
if((*input)->changed()) {
add_field_option(f->id, it->first, sstream.str(),
GModel::current()->getFileName());
(*input)->clear_changed();
}
input++;
}
int is_bg_field = background_btn->value();
FieldManager &fields = *GModel::current()->getFields();
if(is_bg_field && fields.getBackgroundField() != f->id) {
set_background_field(f->id, GModel::current()->getFileName());
loadFieldList();
}
if(!is_bg_field && fields.getBackgroundField() == f->id) {
set_background_field(-1, GModel::current()->getFileName());
loadFieldList();
}
}
void fieldWindow::loadFieldOptions()
{
Field *f = (Field *)editor_group->user_data();
std::list<Fl_Widget *>::iterator input = options_widget.begin();
for(std::map<std::string, FieldOption *>::iterator it = f->options.begin();
it != f->options.end(); it++) {
FieldOption *option = it->second;
std::ostringstream vstr;
std::list<int>::const_iterator list_it;
std::list<double>::const_iterator listdouble_it;
switch(option->getType()) {
case FIELD_OPTION_STRING:
case FIELD_OPTION_PATH:
((Fl_Input *)(*input))->value(option->string().c_str());
break;
case FIELD_OPTION_INT:
case FIELD_OPTION_DOUBLE:
((Fl_Value_Input *)(*input))->value(option->numericalValue());
break;
case FIELD_OPTION_BOOL:
((Fl_Check_Button *)(*input))->value((int)option->numericalValue());
break;
case FIELD_OPTION_LIST:
vstr.str("");
for(list_it = option->list().begin(); list_it != option->list().end();
list_it++) {
if(list_it != option->list().begin()) vstr << ", ";
vstr << *list_it;
}
((Fl_Input *)(*input))->value(vstr.str().c_str());
break;
case FIELD_OPTION_LIST_DOUBLE:
vstr.str("");
vstr.precision(16);
for(listdouble_it = option->listdouble().begin();
listdouble_it != option->listdouble().end(); listdouble_it++) {
if(listdouble_it != option->listdouble().begin()) vstr << ", ";
vstr << *listdouble_it;
}
((Fl_Input *)(*input))->value(vstr.str().c_str());
break;
}
(*input)->clear_changed();
input++;
}
background_btn->value(GModel::current()->getFields()->getBackgroundField() ==
f->id);
}
void fieldWindow::editField(Field *f)
{
editor_group->user_data(f);
put_on_view_btn->deactivate();
delete_btn->deactivate();
if(f == NULL) {
selected_id = -1;
editor_group->hide();
empty_message->show();
loadFieldList();
return;
}
FL_NORMAL_SIZE -= _deltaFontSize;
selected_id = f->id;
empty_message->hide();
editor_group->show();
editor_group->user_data(f);
title->label(f->getName());
options_scroll->clear();
options_widget.clear();
options_scroll->begin();
int xx = options_scroll->x();
int yy = options_scroll->y();
std::string help = f->getDescription();
ConvertToHTML(help);
if(!f->options.empty())
help += std::string("<p><center><b>Options</b></center>");
for(std::map<std::string, FieldOption *>::iterator it = f->options.begin();
it != f->options.end(); it++) {
Fl_Widget *input;
help += std::string("<p><b>") + it->first + "</b>";
help += " (<em>" + it->second->getTypeName() + "</em>): ";
help += it->second->getDescription();
switch(it->second->getType()) {
case FIELD_OPTION_INT:
case FIELD_OPTION_DOUBLE:
input = new Fl_Value_Input(xx, yy, IW, BH, it->first.c_str());
input->align(FL_ALIGN_RIGHT);
break;
case FIELD_OPTION_BOOL:
input = new Fl_Check_Button(xx, yy, 2 * BB, BH, it->first.c_str());
input->type(FL_TOGGLE_BUTTON);
break;
case FIELD_OPTION_PATH: {
input = new Fl_Input(xx, yy, IW, BH, it->first.c_str());
input->align(FL_ALIGN_RIGHT);
int tw = (int)fl_width(it->first.c_str());
Fl_Button *b = new Fl_Button(xx + IW + tw + 2 * WB, yy, BB, BH, "Choose");
b->callback(field_select_file_cb, input);
} break;
case FIELD_OPTION_STRING:
input = new Fl_Input(xx, yy, IW, BH, it->first.c_str());
input->align(FL_ALIGN_RIGHT);
break;
case FIELD_OPTION_LIST:
case FIELD_OPTION_LIST_DOUBLE:
default:
input = new Fl_Input(xx, yy, IW, BH, it->first.c_str());
input->align(FL_ALIGN_RIGHT);
break;
}
options_widget.push_back(input);
yy += BH;
}
if(!f->callbacks.empty())
help += std::string("<p><center><b>Actions</b></center>");
for(std::map<std::string, FieldCallback *>::iterator it =
f->callbacks.begin();
it != f->callbacks.end(); it++) {
Fl_Widget *btn;
help += std::string("<p><b>") + it->first + "</b>: ";
help += it->second->getDescription();
btn = new Fl_Button(xx, yy, IW, BH, it->first.c_str());
btn->callback(field_callback_cb, it->second);
yy += BH;
}
help_display->value(help.c_str());
options_scroll->end();
FL_NORMAL_SIZE += _deltaFontSize;
loadFieldOptions();
options_scroll->damage(1);
put_on_view_btn->activate();
delete_btn->activate();
loadFieldList();
}