diff --git a/data b/data index d5ff8d51..3195fa5d 160000 --- a/data +++ b/data @@ -1 +1 @@ -Subproject commit d5ff8d51a37ba4d66a99778914f4d3751c23006b +Subproject commit 3195fa5d55daa308404529f06030e3d643945291 diff --git a/po/colobot.pot b/po/colobot.pot index 3992e702..60365092 100644 --- a/po/colobot.pot +++ b/po/colobot.pot @@ -180,6 +180,12 @@ msgstr "" msgid "Program finished" msgstr "" +msgid "Program cloned" +msgstr "" + +msgid "This program is read-only, clone it to edit" +msgstr "" + msgid "\\b;List of objects\n" msgstr "" @@ -857,6 +863,9 @@ msgstr "" msgid "Remove selected program" msgstr "" +msgid "Clone selected program" +msgstr "" + msgid "Move selected program up" msgstr "" @@ -1016,6 +1025,9 @@ msgstr "" msgid "Cancel\\Cancel all changes" msgstr "" +msgid "Clone program" +msgstr "" + msgid "Open (Ctrl+o)" msgstr "" diff --git a/po/de.po b/po/de.po index 533ddd6c..7f9cd723 100644 --- a/po/de.po +++ b/po/de.po @@ -395,6 +395,13 @@ msgstr "Checkpoint erreicht" msgid "Climb\\Increases the power of the jet" msgstr "Steigen\\Leistung des Triebwerks steigern" +msgid "Clone program" +msgstr "" + +#, fuzzy +msgid "Clone selected program" +msgstr "Gewähltes Programm bearbeiten" + msgid "Close" msgstr "Schließen" @@ -1129,6 +1136,10 @@ msgstr "Geschütztes Element (private)" msgid "Private\\Private folder" msgstr "Privat\\Privater Ordner" +#, fuzzy +msgid "Program cloned" +msgstr "Programm beendet" + msgid "Program editor" msgstr "Programmeditor" @@ -1487,6 +1498,9 @@ msgstr "Dieses Label existiert nicht" msgid "This object is not a member of a class" msgstr "Das Objekt ist nicht eine Instanz einer Klasse" +msgid "This program is read-only, clone it to edit" +msgstr "" + msgid "Thump (\\key action;)" msgstr "Stampfen (\\key action;)" diff --git a/po/fr.po b/po/fr.po index 2a38eca3..c2bf87fc 100644 --- a/po/fr.po +++ b/po/fr.po @@ -390,6 +390,13 @@ msgstr "Indicateur atteint" msgid "Climb\\Increases the power of the jet" msgstr "Monter\\Augmenter la puissance du réacteur" +msgid "Clone program" +msgstr "" + +#, fuzzy +msgid "Clone selected program" +msgstr "Édite le programme sélectionné" + msgid "Close" msgstr "Fermer" @@ -1125,6 +1132,10 @@ msgstr "Elément protégé" msgid "Private\\Private folder" msgstr "Privé\\Dossier privé" +#, fuzzy +msgid "Program cloned" +msgstr "Programme terminé" + msgid "Program editor" msgstr "Edition du programme" @@ -1482,6 +1493,9 @@ msgstr "Cette étiquette n'existe pas" msgid "This object is not a member of a class" msgstr "L'objet n'est pas une instance d'une classe" +msgid "This program is read-only, clone it to edit" +msgstr "" + msgid "Thump (\\key action;)" msgstr "Secoue (\\key action;)" diff --git a/po/pl.po b/po/pl.po index 0bb00846..7676f72a 100644 --- a/po/pl.po +++ b/po/pl.po @@ -400,6 +400,12 @@ msgstr "Przekroczono punkt kontrolny" msgid "Climb\\Increases the power of the jet" msgstr "W górę\\Zwiększa moc silnika" +msgid "Clone program" +msgstr "Skopiuj program" + +msgid "Clone selected program" +msgstr "Skopiuj zaznaczony program" + msgid "Close" msgstr "Zamknij" @@ -1048,7 +1054,7 @@ msgid "Pause/continue" msgstr "Pauza/Kontynuuj" msgid "Pause\\Pause the game without opening menu" -msgstr "" +msgstr "Pauza\\Zatrzymaj grę bez otwierania menu" msgid "Phazer shooter" msgstr "Działo fazowe" @@ -1132,6 +1138,9 @@ msgstr "Element prywatny" msgid "Private\\Private folder" msgstr "Prywatny\\Folder prywatny" +msgid "Program cloned" +msgstr "Program skopiowany" + msgid "Program editor" msgstr "Edytor programu" @@ -1487,6 +1496,9 @@ msgstr "Taka etykieta nie istnieje" msgid "This object is not a member of a class" msgstr "Ten obiekt nie jest członkiem klasy" +msgid "This program is read-only, clone it to edit" +msgstr "Ten program jest tylko do odczytu, skopiuj go, aby edytować" + msgid "Thump (\\key action;)" msgstr "Uderz (\\key action;)" diff --git a/po/ru.po b/po/ru.po index 6be55cbc..b0396022 100644 --- a/po/ru.po +++ b/po/ru.po @@ -390,6 +390,13 @@ msgstr "Вы прошли контрольную точку" msgid "Climb\\Increases the power of the jet" msgstr "Взлет и подъем\\Увеличивает мощность реактивного двигателя" +msgid "Clone program" +msgstr "" + +#, fuzzy +msgid "Clone selected program" +msgstr "Изменить выбранную программу" + msgid "Close" msgstr "Закрыть" @@ -1124,6 +1131,10 @@ msgstr "Частный элемент" msgid "Private\\Private folder" msgstr "Личное\\Личная папка" +#, fuzzy +msgid "Program cloned" +msgstr "Программа выполнена" + msgid "Program editor" msgstr "Редактор программ" @@ -1483,6 +1494,9 @@ msgstr "Эта метка не существует" msgid "This object is not a member of a class" msgstr "Этот объект не член класса" +msgid "This program is read-only, clone it to edit" +msgstr "" + msgid "Thump (\\key action;)" msgstr "Удар (\\key action;)" diff --git a/src/common/event.cpp b/src/common/event.cpp index a77ef153..415a9008 100644 --- a/src/common/event.cpp +++ b/src/common/event.cpp @@ -428,6 +428,7 @@ void InitializeEventTypeTexts() EVENT_TYPE_TEXT[EVENT_OBJECT_PROGSTART] = "EVENT_OBJECT_PROGSTART"; EVENT_TYPE_TEXT[EVENT_OBJECT_PROGSTOP] = "EVENT_OBJECT_PROGSTOP"; EVENT_TYPE_TEXT[EVENT_OBJECT_PROGADD] = "EVENT_OBJECT_PROGADD"; + EVENT_TYPE_TEXT[EVENT_OBJECT_PROGCLONE] = "EVENT_OBJECT_PROGCLONE"; EVENT_TYPE_TEXT[EVENT_OBJECT_PROGREMOVE] = "EVENT_OBJECT_PROGREMOVE"; EVENT_TYPE_TEXT[EVENT_OBJECT_PROGMOVEUP] = "EVENT_OBJECT_PROGMOVEUP"; EVENT_TYPE_TEXT[EVENT_OBJECT_PROGMOVEDOWN] = "EVENT_OBJECT_PROGMOVEDOWN"; @@ -497,6 +498,7 @@ void InitializeEventTypeTexts() EVENT_TYPE_TEXT[EVENT_STUDIO_CANCEL] = "EVENT_STUDIO_CANCEL"; EVENT_TYPE_TEXT[EVENT_STUDIO_EDIT] = "EVENT_STUDIO_EDIT"; EVENT_TYPE_TEXT[EVENT_STUDIO_LIST] = "EVENT_STUDIO_LIST"; + EVENT_TYPE_TEXT[EVENT_STUDIO_CLONE] = "EVENT_STUDIO_CLONE"; EVENT_TYPE_TEXT[EVENT_STUDIO_NEW] = "EVENT_STUDIO_NEW"; EVENT_TYPE_TEXT[EVENT_STUDIO_OPEN] = "EVENT_STUDIO_OPEN"; EVENT_TYPE_TEXT[EVENT_STUDIO_SAVE] = "EVENT_STUDIO_SAVE"; diff --git a/src/common/event.h b/src/common/event.h index 02ba74b9..7566ec96 100644 --- a/src/common/event.h +++ b/src/common/event.h @@ -460,8 +460,9 @@ enum EventType EVENT_OBJECT_PROGSTOP = 1314, EVENT_OBJECT_PROGADD = 1315, EVENT_OBJECT_PROGREMOVE = 1316, - EVENT_OBJECT_PROGMOVEUP = 1317, - EVENT_OBJECT_PROGMOVEDOWN = 1318, + EVENT_OBJECT_PROGCLONE = 1317, + EVENT_OBJECT_PROGMOVEUP = 1318, + EVENT_OBJECT_PROGMOVEDOWN = 1319, EVENT_OBJECT_INFOOK = 1340, EVENT_OBJECT_DELETE = 1350, EVENT_OBJECT_GENERGY = 1360, @@ -528,6 +529,7 @@ enum EventType EVENT_STUDIO_CANCEL = 2001, EVENT_STUDIO_EDIT = 2002, EVENT_STUDIO_LIST = 2003, + EVENT_STUDIO_CLONE = 2004, EVENT_STUDIO_NEW = 2010, EVENT_STUDIO_OPEN = 2011, EVENT_STUDIO_SAVE = 2012, diff --git a/src/common/restext.cpp b/src/common/restext.cpp index 20be7363..f117fd33 100644 --- a/src/common/restext.cpp +++ b/src/common/restext.cpp @@ -119,6 +119,9 @@ void InitializeRestext() stringsText[RT_STUDIO_LISTTT] = TR("Keyword help(\\key cbot;)"); stringsText[RT_STUDIO_COMPOK] = TR("Compilation ok (0 errors)"); stringsText[RT_STUDIO_PROGSTOP] = TR("Program finished"); + stringsText[RT_STUDIO_CLONED] = TR("Program cloned"); + + stringsText[RT_PROGRAM_READONLY] = TR("This program is read-only, clone it to edit"); stringsText[RT_SATCOM_LIST] = TR("\\b;List of objects\n"); stringsText[RT_SATCOM_BOT] = TR("\\b;Robots\n"); @@ -374,6 +377,7 @@ void InitializeRestext() stringsEvent[EVENT_OBJECT_PROGEDIT] = TR("Edit the selected program"); stringsEvent[EVENT_OBJECT_PROGADD] = TR("Add new program"); stringsEvent[EVENT_OBJECT_PROGREMOVE] = TR("Remove selected program"); + stringsEvent[EVENT_OBJECT_PROGCLONE] = TR("Clone selected program"); stringsEvent[EVENT_OBJECT_PROGMOVEUP] = TR("Move selected program up"); stringsEvent[EVENT_OBJECT_PROGMOVEDOWN] = TR("Move selected program down"); stringsEvent[EVENT_OBJECT_INFOOK] = TR("\\SatCom on standby"); @@ -433,6 +437,7 @@ void InitializeRestext() stringsEvent[EVENT_STUDIO_OK] = TR("OK\\Close program editor and return to game"); stringsEvent[EVENT_STUDIO_CANCEL] = TR("Cancel\\Cancel all changes"); + stringsEvent[EVENT_STUDIO_CLONE] = TR("Clone program"); stringsEvent[EVENT_STUDIO_NEW] = TR("New"); stringsEvent[EVENT_STUDIO_OPEN] = TR("Open (Ctrl+o)"); stringsEvent[EVENT_STUDIO_SAVE] = TR("Save (Ctrl+s)"); diff --git a/src/common/restext.h b/src/common/restext.h index 46906058..6fb9a015 100644 --- a/src/common/restext.h +++ b/src/common/restext.h @@ -115,6 +115,9 @@ enum ResTextType RT_STUDIO_LISTTT = 120, RT_STUDIO_COMPOK = 121, RT_STUDIO_PROGSTOP = 122, + RT_STUDIO_CLONED = 123, + + RT_PROGRAM_READONLY = 130, RT_SATCOM_LIST = 140, RT_SATCOM_BOT = 141, diff --git a/src/object/brain.cpp b/src/object/brain.cpp index 94a41784..d505e8d6 100644 --- a/src/object/brain.cpp +++ b/src/object/brain.cpp @@ -346,6 +346,27 @@ bool CBrain::EventProcess(const Event &event) StopEditScript(true); m_main->SaveOneScript(m_object); } + if( action == EVENT_STUDIO_CLONE ) + { + StopEditScript(false); + Program* newProgram = CloneProgram(m_program[m_selScript]); + m_selScript = m_program.size()-1; + m_main->SaveOneScript(m_object); + + UpdateInterface(); + Ui::CWindow* pw = static_cast< Ui::CWindow* >(m_interface->SearchControl(EVENT_WINDOW0)); + if ( pw != 0 ) + { + UpdateScript(pw); + } + SetSelScript(m_selScript); + + StartEditScript(newProgram, ""); + + std::string res; + GetResource(RES_TEXT, RT_STUDIO_CLONED, res); + m_studio->SetInfoText(res, false); + } return true; } @@ -462,6 +483,25 @@ bool CBrain::EventProcess(const Event &event) } } + if( action == EVENT_OBJECT_PROGCLONE ) + { + if(m_selScript < m_program.size()) + { + CloneProgram(m_program[m_selScript]); + m_selScript = m_program.size()-1; + m_main->SaveOneScript(m_object); + + UpdateInterface(); + Ui::CWindow* pw = static_cast< Ui::CWindow* >(m_interface->SearchControl(EVENT_WINDOW0)); + if ( pw != 0 ) + { + UpdateScript(pw); + } + SetSelScript(m_selScript); + } + } + + if( action == EVENT_OBJECT_PROGMOVEUP ) { std::iter_swap(m_program.begin() + m_selScript, m_program.begin() + m_selScript - 1); @@ -1399,17 +1439,17 @@ bool CBrain::CreateInterface(bool bSelect) ddim.y = dim.y*0.5f; pos.y = oy+sy*0.0f; - ddim.x = dim.x*2.0f; + ddim.x = dim.x*1.1f; pos.x = ox+sx*0.0f; pw->CreateButton(pos, ddim, 24, EVENT_OBJECT_PROGADD); ddim.x = dim.x*1.0f; - pos.x = ox+sx*2.0f; + pos.x = ox+sx*1.1f; pw->CreateButton(pos, ddim, 25, EVENT_OBJECT_PROGREMOVE); - ddim.x = dim.x*1.05f; - pos.x = ox+sx*3.0f; + pos.x = ox+sx*2.1f; + pw->CreateButton(pos, ddim, 61, EVENT_OBJECT_PROGCLONE); + pos.x = ox+sx*3.1f; pw->CreateButton(pos, ddim, 49, EVENT_OBJECT_PROGMOVEUP); - ddim.x = dim.x*1.05f; - pos.x = ox+sx*4.05f; + pos.x = ox+sx*4.1f; pw->CreateButton(pos, ddim, 50, EVENT_OBJECT_PROGMOVEDOWN); pos.x = ox+sx*5.2f; @@ -2270,7 +2310,8 @@ void CBrain::UpdateInterface() EnableInterface(pw, EVENT_OBJECT_PROGEDIT, (m_primaryTask == 0 && !m_bTraceRecord) && m_selScript < m_program.size()); EnableInterface(pw, EVENT_OBJECT_PROGLIST, bEnable && !m_bTraceRecord); EnableInterface(pw, EVENT_OBJECT_PROGADD, m_currentProgram == nullptr); - EnableInterface(pw, EVENT_OBJECT_PROGREMOVE, m_currentProgram == nullptr); + EnableInterface(pw, EVENT_OBJECT_PROGREMOVE, m_currentProgram == nullptr && m_selScript < m_program.size() && !m_program[m_selScript]->readOnly); + EnableInterface(pw, EVENT_OBJECT_PROGCLONE, m_currentProgram == nullptr); EnableInterface(pw, EVENT_OBJECT_PROGMOVEUP, m_currentProgram == nullptr && m_program.size() >= 2 && m_selScript > 0); EnableInterface(pw, EVENT_OBJECT_PROGMOVEDOWN,m_currentProgram == nullptr && m_program.size() >= 2 && m_selScript < m_program.size()-1); EnableInterface(pw, EVENT_OBJECT_LEFT, bEnable); @@ -3073,6 +3114,7 @@ Program* CBrain::AddProgram() { Program* program = new Program(); program->script = new CScript(m_object, &m_secondaryTask); + program->readOnly = false; AddProgram(program); return program; } @@ -3112,6 +3154,20 @@ void CBrain::RemoveProgram(Program* program) } } +Program* CBrain::CloneProgram(Program* program) +{ + Program* newprog = AddProgram(); + + // TODO: Is there any reason CScript doesn't have a function to get the program code directly? + Ui::CEdit* edit = new Ui::CEdit(); + edit->SetMaxChar(Ui::EDITSTUDIOMAX); + program->script->PutScript(edit, ""); + newprog->script->GetScript(edit); + delete edit; + + return newprog; +} + int CBrain::GetProgramIndex(Program* program) { for(unsigned int i = 0; i < m_program.size(); i++) diff --git a/src/object/brain.h b/src/object/brain.h index ce21d6ce..de3c007d 100644 --- a/src/object/brain.h +++ b/src/object/brain.h @@ -78,6 +78,7 @@ struct Program { CScript* script; std::string filename; + bool readOnly = false; }; @@ -148,6 +149,7 @@ public: Program* AddProgram(); bool AddProgram(Program* program); void RemoveProgram(Program* program); + Program* CloneProgram(Program* program); Program* GetProgram(int index); Program* GetOrAddProgram(int index); diff --git a/src/object/robotmain.cpp b/src/object/robotmain.cpp index 4b5304f7..d5cc377f 100644 --- a/src/object/robotmain.cpp +++ b/src/object/robotmain.cpp @@ -3470,6 +3470,7 @@ void CRobotMain::CreateScene(bool soluce, bool fixScene, bool resetObject) { Program* program = brain->AddProgram(); program->filename = "../"+line->GetParam("script")->AsPath("ai"); + program->readOnly = true; brain->SetScriptRun(program); } continue; @@ -3629,9 +3630,11 @@ void CRobotMain::CreateScene(bool soluce, bool fixScene, bool resetObject) for (int i = 0; i < 10; i++) { std::string op = "script"+boost::lexical_cast(i+1); // script1..script10 + std::string opReadOnly = "scriptReadOnly"+boost::lexical_cast(i+1); // scriptReadOnly1..scriptReadOnly10 if(line->GetParam(op)->IsDefined()) { Program* program = brain->AddProgram(); program->filename = "../"+line->GetParam(op)->AsPath("ai"); + program->readOnly = line->GetParam(opReadOnly)->AsBool(true); loadedPrograms[i] = program; } diff --git a/src/ui/studio.cpp b/src/ui/studio.cpp index 170d830b..ab69ed61 100644 --- a/src/ui/studio.cpp +++ b/src/ui/studio.cpp @@ -552,8 +552,8 @@ void CStudio::StartEditScript(CScript *script, std::string name, Program* progra CSlider* slider; CList* list; - m_script = script; - m_program = program; + m_script = script; + m_program = program; m_main->SetEditLock(true, true); m_main->SetEditFull(false); @@ -636,6 +636,8 @@ void CStudio::StartEditScript(CScript *script, std::string name, Program* progra button = pw->CreateButton(pos, dim, -1, EVENT_STUDIO_OK); button->SetState(STATE_SHADOW); + button = pw->CreateButton(pos, dim, 61, EVENT_STUDIO_CLONE); + button->SetState(STATE_SHADOW); button = pw->CreateButton(pos, dim, -1, EVENT_STUDIO_CANCEL); button->SetState(STATE_SHADOW); button = pw->CreateButton(pos, dim, 64+23, EVENT_STUDIO_COMPILE); @@ -647,6 +649,12 @@ void CStudio::StartEditScript(CScript *script, std::string name, Program* progra button = pw->CreateButton(pos, dim, 64+29, EVENT_STUDIO_STEP); button->SetState(STATE_SHADOW); + if(m_program->readOnly) + { + GetResource(RES_TEXT, RT_PROGRAM_READONLY, res); + SetInfoText(res, false); + } + UpdateFlux(); UpdateButtons(); AdjustEditScript(); @@ -799,7 +807,18 @@ void CStudio::AdjustEditScript() button->SetPos(pos); button->SetDim(dim); } - pos.x = wpos.x+0.14f; + dim.x = 25.0f/480.0f; + dim.y = 25.0f/480.0f; + pos.x = wpos.x+0.01f+0.125f+0.005f; + button = static_cast< CButton* >(pw->SearchControl(EVENT_STUDIO_CLONE)); + if ( button != nullptr ) + { + button->SetPos(pos); + button->SetDim(dim); + } + dim.x = 80.0f/640.0f - 25.0f/480.0f; + dim.y = 25.0f/480.0f; + pos.x = wpos.x+0.01f+0.125f+0.005f+(25.0f/480.0f)+0.005f; button = static_cast< CButton* >(pw->SearchControl(EVENT_STUDIO_CANCEL)); if ( button != nullptr ) { @@ -979,8 +998,8 @@ void CStudio::UpdateButtons() } else { - edit->SetIcon(0); // standard background - edit->SetEditCap(true); + edit->SetIcon(m_program->readOnly ? 1 : 0); // standard background + edit->SetEditCap(!m_program->readOnly); edit->SetHighlightCap(true); } @@ -1000,6 +1019,27 @@ void CStudio::UpdateButtons() button = static_cast< CButton* >(pw->SearchControl(EVENT_STUDIO_STEP)); if ( button == 0 ) return; button->SetState(STATE_ENABLE, (m_bRunning && !m_bRealTime && !m_script->IsContinue())); + + + button = static_cast< CButton* >(pw->SearchControl(EVENT_STUDIO_NEW)); + if ( button == 0 ) return; + button->SetState(STATE_ENABLE, !m_program->readOnly); + + button = static_cast< CButton* >(pw->SearchControl(EVENT_STUDIO_OPEN)); + if ( button == 0 ) return; + button->SetState(STATE_ENABLE, !m_program->readOnly); + + button = static_cast< CButton* >(pw->SearchControl(EVENT_STUDIO_UNDO)); + if ( button == 0 ) return; + button->SetState(STATE_ENABLE, !m_program->readOnly); + + button = static_cast< CButton* >(pw->SearchControl(EVENT_STUDIO_CUT)); + if ( button == 0 ) return; + button->SetState(STATE_ENABLE, !m_program->readOnly); + + button = static_cast< CButton* >(pw->SearchControl(EVENT_STUDIO_PASTE)); + if ( button == 0 ) return; + button->SetState(STATE_ENABLE, !m_program->readOnly); } diff --git a/src/ui/studio.h b/src/ui/studio.h index 15833ee0..5118375d 100644 --- a/src/ui/studio.h +++ b/src/ui/studio.h @@ -70,13 +70,14 @@ public: void StartEditScript(CScript *script, std::string name, Program* program); bool StopEditScript(bool bCancel); + + void SetInfoText(std::string text, bool bClickable); protected: bool EventFrame(const Event &event); void SearchToken(CEdit* edit); void ColorizeScript(CEdit* edit); void AdjustEditScript(); - void SetInfoText(std::string text, bool bClickable); void ViewEditScript(); void UpdateFlux(); void UpdateButtons();