/* * ScriptDialog.cpp * * Copyright (C) 2003 J. "MUFTI" Scheurich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program (see the file "COPYING" for details); if * not, write to the Free Software Foundation, Inc., 675 Mass Ave, * Cambridge, MA 02139, USA. */ #include "stdafx.h" #include #include "ScriptDialog.h" #include "ScriptEdit.h" #include "resource.h" #include "MyString.h" #include "newline.h" #include "FieldValue.h" #include "NodeScript.h" #include "SFMFTypes.h" #include "Field.h" #include "EventIn.h" #include "EventOut.h" #include "ExposedField.h" #include "Element.h" #include "DuneApp.h" #define X_SPACING 2 #define Y_SPACING 2 static const char *eventOrField[] = { " ", "eventIn", "eventOut", "field" }; static const char *SfOrMf[] = { " ", "SF", "MF" }; static const char *DataType[] = { " ", "Bool", "Color", "Float", "Image", "Int32", "Node", "Rotation", "String", "Time", "Vec2f", "Vec3f" }; static SWND canvas; static SWND scroll; static SWND parent_window; #define XPOS 56 #define YPOS 47 #ifdef WIN32 # define XMAX 388 # define YMAX 160 #else # define XMAX 388 # define YMAX 210 #endif #define SCROLL_SIZE 5 static int ymax; static void ScriptDialogRedraw(void* data) { SDC dc = swCreateDC(canvas); swSetFGColor(dc, 0xffffff); ScriptDialog* dialog = (ScriptDialog*) data; dialog->accountYmax(); swFillRect(dc, 1, 1, XMAX-2, ymax-2); swSetFGColor(dc, 0); swDrawLine(dc, 0, 0, XMAX-1, 0); swDrawLine(dc, 0, ymax-1, XMAX-1, ymax-1); swDrawLine(dc, 0, 0, 0, ymax-1); swDrawLine(dc, XMAX-1, 0, XMAX-1, ymax-1); dialog->drawInterface(); swDestroyDC(dc); } static void ScriptDialogExposeCallback(void *data, int x, int y, int width, int height) { ScriptDialogRedraw(data); } static void ScriptDialogEnterCallback(void *data, int command) { ScriptDialogRedraw(data); } static int fontHeight; static int selectedText; static void ScriptDialogKeyCallback(void *data, int key, int value, int x, int y, int modifiers) { // Left mouse button down if (key == SW_MOUSE1) if (value) { selectedText = (y - Y_SPACING) / (fontHeight + Y_SPACING); ScriptDialogRedraw(data); } } static void ScriptDialogEditorReadyCallback(void *data) { ScriptDialog *dialog = (ScriptDialog *) data; dialog->OnEditorReadyCallback(); } ScriptDialog::ScriptDialog(SWND parent, Node* oldNode) : Dialog(parent, IDD_SCRIPT) { parent_window = parent; assert (oldNode->getType() == NODE_SCRIPT); _scriptNode = (NodeScript *) oldNode; _okFlag = false; LoadData(); _canClick = true; _scriptEdit = NULL; fontHeight = swGetFontHeight(swGetDefaultFont()); selectedText = -1; accountYmax(); } ScriptDialog::~ScriptDialog() { swDestroyWindow(canvas); swDestroyWindow(scroll); } void ScriptDialog::OnCommand(int id) { if (_canClick) { if (id == ID_ADD_EVENT) { addEvent(); #ifdef WIN32 swSetFocus( swGetDialogItem(_dlg, IDC_EVENT_OR_FIELD)); #endif } else if (id == ID_DELETE_EVENT) deleteEvent(); else { if (id == ID_CHANGE_EVENT) { addEvent(true); changeEvent(); } else if (id == ID_FILE_PREVIEW) { addEvent(true); TheApp->OnFilePreview(_scriptNode->getScene()); } else if (id == ID_SCRIPT_EDIT) { addEvent(true); stopClick(); _scriptEdit = new ScriptEdit(_scriptNode,_dlg, ScriptDialogEditorReadyCallback, this); _scriptEdit->ecmaScriptEdit(); } else if (id == IDOK) { addEvent(true); _okFlag = true; if (Validate()) { swEndDialog(IDOK); } } } } } void ScriptDialog::OnEditorReadyCallback(void) { if (_scriptEdit != NULL) delete _scriptEdit; _scriptEdit = NULL; _canClick = true; swInvalidateWindow(canvas); } void ScriptDialog::eraseWidgets(void) { swComboBoxSetSelection(swGetDialogItem(_dlg, IDC_EVENT_OR_FIELD),0); swComboBoxSetSelection(swGetDialogItem(_dlg, IDC_SF_OR_MF),0); swComboBoxSetSelection(swGetDialogItem(_dlg, IDC_DATATYPE),0); swSetText(swGetDialogItem(_dlg, IDC_EVENT_NAME), ""); } void ScriptDialog::setWidgets(char *eventString, int typeEnum, const char *eventName) { int i; char sfOrMf[3] = { '\0' }; const char *type = typeEnumToString(typeEnum); mystrncpy_danger(sfOrMf, type, 2); const char *dataType = (strlen(type) > 2) ? &type[2] : ""; for (i=0;i<(sizeof(eventOrField)/sizeof(const char*));i++) if (strcmp(eventString, eventOrField[i]) == 0) swComboBoxSetSelection(swGetDialogItem(_dlg, IDC_EVENT_OR_FIELD), i); for (i=0;i<(sizeof(SfOrMf)/sizeof(const char*));i++) if (strcmp(sfOrMf, SfOrMf[i]) == 0) swComboBoxSetSelection(swGetDialogItem(_dlg, IDC_SF_OR_MF), i); for (i=0;i<(sizeof(DataType)/sizeof(const char*));i++) if (strcmp(dataType, DataType[i]) == 0) swComboBoxSetSelection(swGetDialogItem(_dlg, IDC_DATATYPE), i); swSetText(swGetDialogItem(_dlg, IDC_EVENT_NAME), eventName); } void ScriptDialog::addEvent(bool onlyTry) { int event = swComboBoxGetSelection(swGetDialogItem(_dlg, IDC_EVENT_OR_FIELD)); int sfmf = swComboBoxGetSelection(swGetDialogItem(_dlg, IDC_SF_OR_MF)); if (sfmf == 0) return; if (event == 0) return; int type = swComboBoxGetSelection(swGetDialogItem(_dlg, IDC_DATATYPE)); if (type == 0) return; char eventName[1025]; swGetText(swGetDialogItem(_dlg, IDC_EVENT_NAME), eventName, 1024); if (eventName[0] == (char)0) return; Proto* proto=_scriptNode->getProto(); if (proto==NULL) return; int i; bool alreadyUsed = false; for (i=0; i < proto->getNumFields(); i++) if (strcmp(eventName, proto->getField(i)->getName()) == 0) alreadyUsed = true; for (i=0; i < proto->getNumEventIns(); i++) if (strcmp(eventName, proto->getEventIn(i)->getName()) == 0) alreadyUsed = true; for (i=0; i < proto->getNumEventOuts(); i++) if (strcmp(eventName, proto->getEventOut(i)->getName()) == 0) alreadyUsed = true; if (alreadyUsed) { if (onlyTry) return; MyString warning = "name \""; warning += eventName; warning += "\" already in use "; swMessageBox(TheApp->mainWnd(), warning, " dune error ", SW_MB_OK, SW_MB_ERROR); return; } bool invalidChars = false; if (isalpha(eventName[0])) { for (i=1; i < strlen(eventName); i++) if (!isalpha(eventName[i]) && (!isdigit(eventName[i])) && (eventName[i] != '_')) invalidChars = true; } else invalidChars = true; if (invalidChars) { MyString warning = "name \""; warning += eventName; warning += "\" contain non allowed characters "; swMessageBox(TheApp->mainWnd(), warning, " dune error ", SW_MB_OK, SW_MB_ERROR); return; } MyString typeString = SfOrMf[sfmf]; typeString += DataType[type]; int typeEnum = typeStringToEnum(typeString); if (typeEnum == -1) { MyString warning = "\""; warning += strdup(typeString); warning += "\" is not a valid VRML97 Datatype"; swMessageBox(TheApp->mainWnd(), warning, " dune error ", SW_MB_OK, SW_MB_ERROR); return; } if (strcmp(eventOrField[event],"field") == 0) { proto->addField(typeEnum, eventName, typeDefaultValue(typeEnum),0,NULL); } else if (strcmp(eventOrField[event],"eventIn") == 0) { proto->addEventIn(typeEnum, eventName); } else if (strcmp(eventOrField[event],"eventOut") == 0) { proto->addEventOut(typeEnum, eventName); } selectedText = -1; _scriptNode->update(); swInvalidateWindow(canvas); eraseWidgets(); } bool ScriptDialog::deleteEvent() { Proto* proto = _scriptNode->getProto(); InterfaceArray *interfaceData = _scriptNode->getInterfaceData(); if (proto==NULL) return false; if (selectedText == -1) return false; for (int i = 0 ; i < interfaceData->size() ; i++) if (i == selectedText) { int ind = interfaceData->get(i)->_elementIndex; switch (interfaceData->get(i)->_elementEnum) { case EL_FIELD_DEF: proto->getField(ind)->setFlags(FF_DELETED); break; case EL_EVENT_IN: if (hasRoute(_scriptNode->getInput(ind))) { swMessageBox(TheApp->mainWnd(), "cut routes first", " white_dune error ", SW_MB_OK, SW_MB_ERROR); return false; } proto->getEventIn(ind)->setFlags(FF_DELETED); break; case EL_EVENT_OUT: proto->getEventOut(ind)->setFlags(FF_DELETED); if (hasRoute(_scriptNode->getOutput(ind))) { swMessageBox(TheApp->mainWnd(), "cut routes first", " white_dune error ", SW_MB_OK, SW_MB_ERROR); return false; } break; } } _scriptNode->update(); swInvalidateWindow(canvas); return true; } void ScriptDialog::changeEvent() { InterfaceArray *interfaceData = _scriptNode->getInterfaceData(); Proto* proto=_scriptNode->getProto(); if (proto==NULL) return; if (selectedText == -1) return; char *eventOrField = ""; int typeEnum; const char *name = ""; bool lineFound = false; for (int i = 0 ; i < interfaceData->size() ; i++) if (i == selectedText) { lineFound = true; int ind = interfaceData->get(i)->_elementIndex; switch (interfaceData->get(i)->_elementEnum) { case EL_FIELD_DEF: eventOrField = "field"; typeEnum = proto->getField(ind)->getType(); name = proto->getField(ind)->getName(); break; case EL_EVENT_IN: eventOrField = "eventIn"; typeEnum = proto->getEventIn(ind)->getType(); name = proto->getEventIn(ind)->getName(); break; case EL_EVENT_OUT: eventOrField = "eventOut"; typeEnum = proto->getEventOut(ind)->getType(); name = proto->getEventOut(ind)->getName(); break; } } if (lineFound) if (deleteEvent()) { setWidgets(eventOrField, typeEnum, name); } else { eraseWidgets(); } } bool ScriptDialog::Validate() { return true; } void ScriptDialog::LoadData() { int i; SWND comboEventOrField = swGetDialogItem(_dlg, IDC_EVENT_OR_FIELD); swComboBoxDeleteAll(comboEventOrField); for (i=0;i<(sizeof(eventOrField)/sizeof(const char*));i++) swComboBoxAppendItem(comboEventOrField, eventOrField[i]); SWND comboSfOrMf = swGetDialogItem(_dlg, IDC_SF_OR_MF); swComboBoxDeleteAll(comboSfOrMf); for (i=0;i<(sizeof(SfOrMf)/sizeof(const char*));i++) swComboBoxAppendItem(comboSfOrMf, SfOrMf[i]); SWND comboDataType = swGetDialogItem(_dlg, IDC_DATATYPE); swComboBoxDeleteAll(comboDataType); for (i=0;i<(sizeof(DataType)/sizeof(const char*));i++) swComboBoxAppendItem(comboDataType, DataType[i]); scroll = swCreateScrolledWindow(XPOS, YPOS, XMAX-XPOS, YMAX-YPOS, _dlg); canvas = swCreateCanvas("scriptdialog", 0, 0, XMAX, YMAX, scroll); swScrolledWindowSetChild(scroll, canvas); swSetScrollSizes(scroll, XMAX-XPOS-SCROLL_SIZE, YMAX-YPOS-SCROLL_SIZE); swSetClientData(canvas, this); swSetEnterCallback(canvas, ScriptDialogEnterCallback); swSetKeyCallback(canvas, ScriptDialogKeyCallback); swSetExposeCallback(canvas, ScriptDialogExposeCallback); swInvalidateWindow(canvas); swShowWindow(canvas); } void ScriptDialog::accountYmax() { InterfaceArray *interfaceData = _scriptNode->getInterfaceData(); ymax = (interfaceData->size() + 1) * (Y_SPACING + fontHeight) + 2 * Y_SPACING; if (ymax > YMAX-YPOS-SCROLL_SIZE) { swSetScrollSizes(scroll, XMAX-XPOS-SCROLL_SIZE, ymax); swSetSize(canvas, XMAX-XPOS-SCROLL_SIZE, ymax); } else { ymax = YMAX-YPOS-SCROLL_SIZE; swSetScrollSizes(scroll, XMAX-XPOS-SCROLL_SIZE, YMAX-YPOS-SCROLL_SIZE); } } // display type and name of array of dynamic field's, eventIn's and eventOut's // of ScriptNode void ScriptDialog::drawInterface() { InterfaceArray *interfaceData = _scriptNode->getInterfaceData(); SDC dc = swCreateDC(canvas); if (!_canClick) { swSetFGColor(dc, SW_RED(0xFFFFFF)); swDrawText(dc, X_SPACING, Y_SPACING + fontHeight, "editor is running"); return; } Proto* proto = _scriptNode->getProto(); if (proto == NULL) return; int y = 0; for (int i = 0 ; i < interfaceData->size() ; i++) { MyString text = ""; int ind = interfaceData->get(i)->_elementIndex; switch (interfaceData->get(i)->_elementEnum) { case EL_FIELD_DEF: text += "field "; text += typeEnumToString(proto->getField(ind)->getType()); text += " "; text += proto->getField(ind)->getName(); break; case EL_EVENT_OUT: text += "eventOut "; text += typeEnumToString(proto->getEventOut(ind)->getType()); text += " "; text += proto->getEventOut(ind)->getName(); break; case EL_EVENT_IN: text += "eventIn "; text += typeEnumToString(proto->getEventIn(ind)->getType()); text += " "; text += proto->getEventIn(ind)->getName(); break; } y += Y_SPACING + fontHeight; if (selectedText == i) swSetFGColor(dc, swGetWindowColor(parent_window, SW_COLOR_HIGHLIGHT)); else swSetFGColor(dc, swGetWindowColor(parent_window, SW_COLOR_TEXT)); swDrawText(dc, X_SPACING, y, (const char*) text); } swDestroyDC(dc); }