colobot/colobot-base/ui/studio.cpp

1228 lines
34 KiB
C++

/*
* This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2023, Daniel Roux, EPSITEC SA & TerranovaTeam
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
*
* 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 3 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. If not, see http://gnu.org/licenses
*/
#include "ui/studio.h"
#include "app/app.h"
#include "app/pausemanager.h"
#include "common/event.h"
#include "common/logger.h"
#include "common/settings.h"
#include "common/resources/resourcemanager.h"
#include "graphics/engine/camera.h"
#include "graphics/engine/engine.h"
#include "level/player_profile.h"
#include "level/robotmain.h"
#include "object/object.h"
#include "object/interface/program_storage_object.h"
#include "object/interface/programmable_object.h"
#include "script/cbottoken.h"
#include "script/script.h"
#include "sound/sound.h"
#include "ui/filedialog.h"
#include "ui/controls/check.h"
#include "ui/controls/color.h"
#include "ui/controls/control.h"
#include "ui/controls/edit.h"
#include "ui/controls/group.h"
#include "ui/controls/image.h"
#include "ui/controls/interface.h"
#include "ui/controls/key.h"
#include "ui/controls/label.h"
#include "ui/controls/list.h"
#include "ui/controls/map.h"
#include "ui/controls/shortcut.h"
#include "ui/controls/slider.h"
#include "ui/controls/target.h"
#include "ui/controls/window.h"
#include <stdio.h>
#include <ctime>
namespace Ui
{
// Object's constructor.
CStudio::CStudio()
{
m_app = CApplication::GetInstancePointer();
m_sound = m_app->GetSound();
m_event = m_app->GetEventQueue();
m_engine = Gfx::CEngine::GetInstancePointer();
m_main = CRobotMain::GetInstancePointer();
m_interface = m_main->GetInterface();
m_camera = m_main->GetCamera();
m_pause = m_main->GetPauseManager();
m_settings = CSettings::GetInstancePointer();
m_program = nullptr;
m_script = nullptr;
m_bEditMaximized = false;
m_bEditMinimized = false;
m_time = 0.0f;
m_bRealTime = true;
m_bRunning = false;
m_fixInfoTextTime = 0.0f;
m_fileDialog = nullptr;
m_editCamera = Gfx::CAM_TYPE_NULL;
}
// Object's destructor.
CStudio::~CStudio()
{
}
// Management of an event.
bool CStudio::EventProcess(const Event &event)
{
CWindow* pw;
CEdit* edit;
CSlider* slider;
if (m_fileDialog != nullptr) // dialogue exists?
{
return EventDialog(event);
}
if ( event.type == EVENT_FRAME )
{
EventFrame(event);
}
pw = static_cast< CWindow* >(m_interface->SearchControl(EVENT_WINDOW3));
if ( pw == nullptr ) return false;
edit = static_cast<CEdit*>(pw->SearchControl(EVENT_STUDIO_EDIT));
if ( edit == nullptr ) return false;
if ( event.type == pw->GetEventTypeClose() )
{
m_event->AddEvent(Event(EVENT_STUDIO_OK));
}
if ( event.type == EVENT_STUDIO_EDIT ) // text modified?
{
ColorizeScript(edit);
}
if ( event.type == EVENT_STUDIO_LIST ) // list clicked?
{
m_main->StartDisplayInfo(m_helpFilename, -1);
}
if ( event.type == EVENT_STUDIO_NEW ) // new?
{
m_script->New(edit, "");
}
if ( event.type == EVENT_STUDIO_OPEN ) // open?
{
StartDialog(event);
return true;
}
if ( event.type == EVENT_STUDIO_SAVE ) // save?
{
StartDialog(event);
return true;
}
if ( event.type == EVENT_STUDIO_UNDO ) // undo?
{
edit->Undo();
}
if ( event.type == EVENT_STUDIO_CUT ) // cut?
{
edit->Cut();
}
if ( event.type == EVENT_STUDIO_COPY ) // copy?
{
edit->Copy();
}
if ( event.type == EVENT_STUDIO_PASTE ) // paste?
{
edit->Paste();
}
if ( event.type == EVENT_STUDIO_SIZE ) // size?
{
slider = static_cast< CSlider* >(pw->SearchControl(EVENT_STUDIO_SIZE));
if ( slider == nullptr ) return false;
m_settings->SetFontSize(9.0f+slider->GetVisibleValue()*15.0f);
ViewEditScript();
}
if ( event.type == EVENT_STUDIO_TOOL ) // instructions?
{
m_main->StartDisplayInfo(SATCOM_HUSTON, false);
}
if ( event.type == EVENT_STUDIO_HELP ) // help?
{
m_main->StartDisplayInfo(SATCOM_PROG, false);
}
if ( event.type == EVENT_STUDIO_COMPILE ) // compile?
{
if ( m_script->GetScript(edit) ) // compile
{
std::string res;
GetResource(RES_TEXT, RT_STUDIO_COMPOK, res);
SetInfoText(res, false);
}
else
{
std::string error;
m_script->GetError(error);
SetInfoText(error, false);
}
}
if ( event.type == EVENT_STUDIO_RUN ) // run/stop?
{
if ( m_script->IsRunning() )
{
m_event->AddEvent(Event(EVENT_OBJECT_PROGSTOP));
}
else
{
if ( m_script->GetScript(edit) ) // compile
{
SetInfoText("", false);
m_event->AddEvent(Event(EVENT_OBJECT_PROGSTART));
}
else
{
std::string error;
m_script->GetError(error);
SetInfoText(error, false);
}
}
}
if ( event.type == EVENT_STUDIO_REALTIME ) // real time?
{
m_bRealTime = !m_bRealTime;
m_script->SetStepMode(!m_bRealTime);
UpdateFlux();
UpdateButtons();
}
if ( event.type == EVENT_STUDIO_STEP ) // step?
{
m_script->Step();
}
if ( event.type == EVENT_WINDOW3 ) // window is moved?
{
m_editActualPos = m_editFinalPos = pw->GetPos();
m_editActualDim = m_editFinalDim = pw->GetDim();
m_windowPos = m_editActualPos;
m_windowDim = m_editActualDim;
AdjustEditScript();
}
if ( event.type == pw->GetEventTypeReduce() )
{
if ( m_bEditMinimized )
{
m_editFinalPos = m_windowPos;
m_editFinalDim = m_windowDim;
m_bEditMinimized = false;
m_bEditMaximized = false;
}
else
{
m_editFinalPos.x = 0.00f;
m_editFinalPos.y = -0.44f;
m_editFinalDim.x = 1.00f;
m_editFinalDim.y = 0.50f;
m_bEditMinimized = true;
m_bEditMaximized = false;
}
m_main->SetEditFull(m_bEditMaximized);
pw = static_cast< CWindow* >(m_interface->SearchControl(EVENT_WINDOW3));
if ( pw != nullptr )
{
pw->SetMaximized(m_bEditMaximized);
pw->SetMinimized(m_bEditMinimized);
}
}
if ( event.type == pw->GetEventTypeFull() )
{
if ( m_bEditMaximized )
{
m_editFinalPos = m_windowPos;
m_editFinalDim = m_windowDim;
m_bEditMinimized = false;
m_bEditMaximized = false;
}
else
{
m_editFinalPos.x = 0.00f;
m_editFinalPos.y = 0.00f;
m_editFinalDim.x = 1.00f;
m_editFinalDim.y = 1.00f;
m_bEditMinimized = false;
m_bEditMaximized = true;
}
m_main->SetEditFull(m_bEditMaximized);
pw = static_cast< CWindow* >(m_interface->SearchControl(EVENT_WINDOW3));
if ( pw != nullptr )
{
pw->SetMaximized(m_bEditMaximized);
pw->SetMinimized(m_bEditMinimized);
}
}
return true;
}
// Evolves value with time elapsed.
static float Evolution(float final, float actual, float time)
{
float value;
value = actual + (final-actual)*time;
if ( final > actual )
{
if ( value > final ) value = final; // does not exceed
}
else
{
if ( value < final ) value = final; // does not exceed
}
return value;
}
// Makes the studio evolve as time elapsed.
bool CStudio::EventFrame(const Event &event)
{
CWindow* pw;
CEdit* edit;
CList* list;
float time;
int cursor1, cursor2, iCursor1, iCursor2;
m_time += event.rTime;
m_fixInfoTextTime -= event.rTime;
pw = static_cast< CWindow* >(m_interface->SearchControl(EVENT_WINDOW3));
if ( pw == nullptr ) return false;
edit = static_cast< CEdit* >(pw->SearchControl(EVENT_STUDIO_EDIT));
if ( edit == nullptr ) return false;
list = static_cast< CList* >(pw->SearchControl(EVENT_STUDIO_LIST));
if ( list == nullptr ) return false;
if (m_script->IsRunning() && (!m_script->GetStepMode() || m_script->IsContinue()))
{
if (m_runningPause != nullptr)
{
m_pause->DeactivatePause(m_runningPause);
m_runningPause = nullptr;
}
}
else
{
if (m_runningPause == nullptr)
{
m_runningPause = m_pause->ActivatePause(PAUSE_ENGINE|PAUSE_MUTE_SOUND);
}
}
if ( !m_script->IsRunning() && m_bRunning ) // stop?
{
m_bRunning = false;
UpdateFlux(); // stop
AdjustEditScript();
std::string res;
GetResource(RES_TEXT, RT_STUDIO_PROGSTOP, res);
SetInfoText(res, false);
m_event->AddEvent(Event(EVENT_OBJECT_PROGSTOP));
}
if ( m_script->IsRunning() && !m_bRunning ) // starting?
{
m_bRunning = true;
UpdateFlux(); // run
AdjustEditScript();
}
UpdateButtons();
if ( m_bRunning )
{
m_script->GetCursor(cursor1, cursor2);
edit->GetCursor(iCursor1, iCursor2);
if ( cursor1 != iCursor1 ||
cursor2 != iCursor2 ) // cursors change?
{
edit->SetCursor(cursor1, cursor2); // shows it on the execution
edit->ShowSelect();
}
m_script->UpdateList(list); // updates the list of variables
}
else
{
SearchToken(edit);
}
if ( m_editFinalPos.x != m_editActualPos.x ||
m_editFinalPos.y != m_editActualPos.y ||
m_editFinalDim.x != m_editActualDim.x ||
m_editFinalDim.y != m_editActualDim.y )
{
time = event.rTime*20.0f;
m_editActualPos.x = Evolution(m_editFinalPos.x, m_editActualPos.x, time);
m_editActualPos.y = Evolution(m_editFinalPos.y, m_editActualPos.y, time);
m_editActualDim.x = Evolution(m_editFinalDim.x, m_editActualDim.x, time);
m_editActualDim.y = Evolution(m_editFinalDim.y, m_editActualDim.y, time);
AdjustEditScript();
}
return true;
}
// Indicates whether a character is part of a word.
static bool IsToken(char c)
{
return ( isalnum(c) || c == '_' );
}
// Seeks if the cursor is on a keyword.
void CStudio::SearchToken(CEdit* edit)
{
ObjectType type;
int len, cursor1, cursor2, i, character, level;
std::string text;
std::string token( 100, '\0');
text = edit->GetText();
len = edit->GetTextLength();
edit->GetCursor(cursor1, cursor2);
i = cursor1;
if ( i > 0 )
{
character = static_cast< unsigned char > (text[i-1]);
if ( !IsToken(character) )
{
level = 1;
while ( i > 0 )
{
character = static_cast< unsigned char > (text[i-1]);
if ( character == ')' )
{
level ++;
}
else if ( character == '(' )
{
level --;
if ( level == 0 ) break;
}
i --;
}
if ( level > 0 )
{
m_helpFilename = "";
SetInfoText("", true);
return;
}
while ( i > 0 )
{
character = static_cast< unsigned char > (text[i-1]);
if ( IsToken(character) ) break;
i --;
}
}
}
while ( i > 0 )
{
character = static_cast< unsigned char > (text[i-1]);
if ( !IsToken(character) ) break;
i --;
}
cursor2 = i;
while ( i < len )
{
character = static_cast< unsigned char > (text[i]);
if ( !IsToken(character) ) break;
i ++;
}
cursor1 = i;
len = cursor1-cursor2;
if ( len > 100-1 ) len = 100-1;
for ( i=0 ; i<len ; i++ )
{
token[i] = text[cursor2+i];
}
token[i] = 0;
m_helpFilename = GetHelpFilename(token.c_str());
if ( m_helpFilename.length() == 0 )
{
for ( i=0 ; i<OBJECT_MAX ; i++ )
{
type = static_cast< ObjectType >(i);
text = const_cast<char *>(GetObjectName(type));
if ( text[0] != 0 )
{
if ( token == text )
{
m_helpFilename = GetHelpFilename(type);
SetInfoText(token, true);
return;
}
}
text = const_cast<char *>(GetObjectAlias(type));
if ( text[0] != 0 )
{
if ( token == text )
{
m_helpFilename = GetHelpFilename(type);
SetInfoText(token, true);
return;
}
}
}
}
text = const_cast<char *>(GetHelpText(token.c_str()));
if ( text[0] == 0 && m_helpFilename.length() > 0 )
{
SetInfoText(token, true);
}
else
{
SetInfoText(text, true);
}
}
// Colors the text according to syntax.
void CStudio::ColorizeScript(CEdit* edit)
{
m_script->ColorizeScript(edit);
}
// Starts editing a program.
void CStudio::StartEditScript(CScript *script, std::string name, Program* program)
{
glm::vec2 pos, dim;
CWindow* pw;
CEdit* edit;
CButton* button;
CSlider* slider;
CList* list;
m_script = script;
m_program = program;
m_main->SetEditLock(true, true);
m_main->SetEditFull(false);
m_main->SetSpeed(1.0f);
m_editCamera = m_camera->GetType();
m_camera->SetType(Gfx::CAM_TYPE_EDIT);
m_editorPause = m_pause->ActivatePause(PAUSE_HIDE_SHORTCUTS, PAUSE_MUSIC_EDITOR);
m_bRunning = m_script->IsRunning();
m_bRealTime = m_bRunning;
m_script->SetStepMode(!m_bRealTime);
pw = static_cast<CWindow*>(m_interface->SearchControl(EVENT_WINDOW6));
if (pw != nullptr) pw->ClearState(STATE_VISIBLE | STATE_ENABLE);
m_dialogPos = m_settings->GetIOPos();
m_dialogDim = m_settings->GetIODim();
m_windowPos = m_settings->GetWindowPos();
m_windowDim = m_settings->GetWindowDim();
m_bEditMaximized = m_settings->GetWindowMax();
if ( m_bEditMaximized )
{
m_editFinalPos.x = 0.00f;
m_editFinalPos.y = 0.00f;
m_editFinalDim.x = 1.00f;
m_editFinalDim.y = 1.00f;
}
else
{
m_editFinalPos = m_windowPos;
m_editFinalDim = m_windowDim;
}
pos = m_editActualPos = m_editFinalPos;
dim = m_editActualDim = m_editFinalDim;
pw = m_interface->CreateWindows(pos, dim, 8, EVENT_WINDOW3);
if (pw == nullptr)
return;
pw->SetState(STATE_SHADOW);
pw->SetRedim(true); // before SetName!
pw->SetMovable(true);
pw->SetClosable(true);
std::string res;
GetResource(RES_TEXT, RT_STUDIO_TITLE, res);
pw->SetName(res);
pw->SetMinDim({ 0.49f, 0.50f });
pw->SetMaximized(m_bEditMaximized);
pw->SetMinimized(m_bEditMinimized);
// stop camera control if maximized
m_main->SetEditFull(m_bEditMaximized);
edit = pw->CreateEdit(pos, dim, 0, EVENT_STUDIO_EDIT);
if (edit == nullptr)
return;
edit->SetState(STATE_SHADOW);
edit->SetInsideScroll(false);
//? if ( m_bRunning ) edit->SetEdit(false);
edit->SetFontType(Gfx::FONT_STUDIO);
edit->SetFontStretch(1.0f);
edit->SetDisplaySpec(true);
edit->SetAutoIndent(m_engine->GetEditIndentMode());
m_script->PutScript(edit, name.c_str());
ColorizeScript(edit);
ViewEditScript();
list = pw->CreateList(pos, dim, 1, EVENT_STUDIO_LIST, 1.2f);
list->SetState(STATE_SHADOW);
list->SetFontType(Gfx::FONT_STUDIO);
list->SetSelectCap(false);
list->SetFontSize(Gfx::FONT_SIZE_SMALL*0.85f);
//? list->SetFontStretch(1.0f);
button = pw->CreateButton(pos, dim, 56, EVENT_STUDIO_NEW);
button->SetState(STATE_SHADOW);
button = pw->CreateButton(pos, dim, 57, EVENT_STUDIO_OPEN);
button->SetState(STATE_SHADOW);
button = pw->CreateButton(pos, dim, 58, EVENT_STUDIO_SAVE);
button->SetState(STATE_SHADOW);
button = pw->CreateButton(pos, dim, 59, EVENT_STUDIO_UNDO);
button->SetState(STATE_SHADOW);
button = pw->CreateButton(pos, dim, 60, EVENT_STUDIO_CUT);
button->SetState(STATE_SHADOW);
button = pw->CreateButton(pos, dim, 61, EVENT_STUDIO_COPY);
button->SetState(STATE_SHADOW);
button = pw->CreateButton(pos, dim, 62, EVENT_STUDIO_PASTE);
button->SetState(STATE_SHADOW);
slider = pw->CreateSlider(pos, dim, 0, EVENT_STUDIO_SIZE);
slider->SetState(STATE_SHADOW);
slider->SetVisibleValue((m_settings->GetFontSize()-9.0f)/15.0f);
pw->CreateGroup(pos, dim, 19, EVENT_LABEL1); // SatCom logo
button = pw->CreateButton(pos, dim, 128+57, EVENT_STUDIO_TOOL);
button->SetState(STATE_SHADOW);
button = pw->CreateButton(pos, dim, 128+60, EVENT_STUDIO_HELP);
button->SetState(STATE_SHADOW);
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);
button->SetState(STATE_SHADOW);
button = pw->CreateButton(pos, dim, 21, EVENT_STUDIO_RUN);
button->SetState(STATE_SHADOW);
button = pw->CreateButton(pos, dim, 64+22, EVENT_STUDIO_REALTIME);
button->SetState(STATE_SHADOW);
button = pw->CreateButton(pos, dim, 64+29, EVENT_STUDIO_STEP);
button->SetState(STATE_SHADOW);
if (!m_program->runnable)
{
GetResource(RES_TEXT, RT_PROGRAM_EXAMPLE, res);
SetInfoText(res, false);
}
else if (m_program->readOnly)
{
GetResource(RES_TEXT, RT_PROGRAM_READONLY, res);
SetInfoText(res, false);
}
UpdateFlux();
UpdateButtons();
AdjustEditScript();
}
// Repositions all the editing controls.
void CStudio::AdjustEditScript()
{
CWindow* pw;
CEdit* edit;
CButton* button;
CGroup* group;
CSlider* slider;
CList* list;
glm::vec2 wpos, wdim, pos, dim, ppos, ddim;
float hList;
wpos = m_editActualPos;
wdim = m_editActualDim;
pw = static_cast< CWindow* >(m_interface->SearchControl(EVENT_WINDOW3));
if ( pw != nullptr )
{
pw->SetPos(wpos);
pw->SetDim(wdim);
wdim = pw->GetDim();
}
if ( m_bRunning ) hList = 80.0f/480.0f;
else hList = 20.0f/480.0f;
pos.x = wpos.x+0.01f;
pos.y = wpos.y+0.09f+hList;
dim.x = wdim.x-0.02f;
dim.y = wdim.y-0.22f-hList;
edit = static_cast< CEdit* >(pw->SearchControl(EVENT_STUDIO_EDIT));
if ( edit != nullptr )
{
edit->SetPos(pos);
edit->SetDim(dim);
}
pos.x = wpos.x+0.01f;
pos.y = wpos.y+0.09f;
dim.x = wdim.x-0.02f;
dim.y = hList;
list = static_cast< CList* >(pw->SearchControl(EVENT_STUDIO_LIST));
if ( list != nullptr )
{
list->SetPos(pos);
list->SetDim(dim);
}
dim.x = 0.04f;
dim.y = 0.04f*1.5f;
dim.y = 25.0f/480.0f;
pos.y = wpos.y+wdim.y-dim.y-0.06f;
pos.x = wpos.x+0.01f;
button = static_cast< CButton* >(pw->SearchControl(EVENT_STUDIO_NEW));
if ( button != nullptr )
{
button->SetPos(pos);
button->SetDim(dim);
}
pos.x = wpos.x+0.05f;
button = static_cast< CButton* >(pw->SearchControl(EVENT_STUDIO_OPEN));
if ( button != nullptr )
{
button->SetPos(pos);
button->SetDim(dim);
}
pos.x = wpos.x+0.09f;
button = static_cast< CButton* >(pw->SearchControl(EVENT_STUDIO_SAVE));
if ( button != nullptr )
{
button->SetPos(pos);
button->SetDim(dim);
}
pos.x = wpos.x+0.14f;
button = static_cast< CButton* >(pw->SearchControl(EVENT_STUDIO_UNDO));
if ( button != nullptr )
{
button->SetPos(pos);
button->SetDim(dim);
}
pos.x = wpos.x+0.19f;
button = static_cast< CButton* >(pw->SearchControl(EVENT_STUDIO_CUT));
if ( button != nullptr )
{
button->SetPos(pos);
button->SetDim(dim);
}
pos.x = wpos.x+0.23f;
button = static_cast< CButton* >(pw->SearchControl(EVENT_STUDIO_COPY));
if ( button != nullptr )
{
button->SetPos(pos);
button->SetDim(dim);
}
pos.x = wpos.x+0.27f;
button = static_cast< CButton* >(pw->SearchControl(EVENT_STUDIO_PASTE));
if ( button != nullptr )
{
button->SetPos(pos);
button->SetDim(dim);
}
pos.x = wpos.x+0.32f;
slider = static_cast< CSlider* >(pw->SearchControl(EVENT_STUDIO_SIZE));
if ( slider != nullptr )
{
ppos = pos;
ddim.x = dim.x*0.7f;
ddim.y = dim.y;
ppos.y -= 3.0f/480.0f;
ddim.y += 6.0f/480.0f;
slider->SetPos(ppos);
slider->SetDim(ddim);
}
pos.x = wpos.x+0.36f;
group = static_cast< CGroup* >(pw->SearchControl(EVENT_LABEL1));
if ( group != nullptr )
{
group->SetPos(pos);
group->SetDim(dim);
}
pos.x = wpos.x+0.40f;
button = static_cast< CButton* >(pw->SearchControl(EVENT_STUDIO_TOOL));
if ( button != nullptr )
{
button->SetPos(pos);
button->SetDim(dim);
}
pos.x = wpos.x+0.44f;
button = static_cast< CButton* >(pw->SearchControl(EVENT_STUDIO_HELP));
if ( button != nullptr )
{
button->SetPos(pos);
button->SetDim(dim);
}
pos.y = wpos.y+0.02f;
pos.x = wpos.x+0.01f;
dim.x = 80.0f/640.0f;
dim.y = 25.0f/480.0f;
button = static_cast< CButton* >(pw->SearchControl(EVENT_STUDIO_OK));
if ( button != nullptr )
{
button->SetPos(pos);
button->SetDim(dim);
}
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 )
{
button->SetPos(pos);
button->SetDim(dim);
}
pos.x = wpos.x+0.28f;
dim.x = dim.y*0.75f;
button = static_cast< CButton* >(pw->SearchControl(EVENT_STUDIO_COMPILE));
if ( button != nullptr )
{
button->SetPos(pos);
button->SetDim(dim);
}
pos.x = wpos.x+0.28f+dim.x*1;
button = static_cast< CButton* >(pw->SearchControl(EVENT_STUDIO_RUN));
if ( button != nullptr )
{
button->SetPos(pos);
button->SetDim(dim);
}
pos.x = wpos.x+0.28f+dim.x*2;
button = static_cast< CButton* >(pw->SearchControl(EVENT_STUDIO_REALTIME));
if ( button != nullptr )
{
button->SetPos(pos);
button->SetDim(dim);
}
pos.x = wpos.x+0.28f+dim.x*3;
button = static_cast< CButton* >(pw->SearchControl(EVENT_STUDIO_STEP));
if ( button != nullptr )
{
button->SetPos(pos);
button->SetDim(dim);
}
}
// Ends edition of a program.
bool CStudio::StopEditScript(bool closeWithErrors)
{
CWindow* pw;
CEdit* edit;
pw = static_cast< CWindow* >(m_interface->SearchControl(EVENT_WINDOW3));
if ( pw == nullptr ) return false;
if ( !closeWithErrors && !m_script->IsRunning() )
{
edit = static_cast< CEdit* >(pw->SearchControl(EVENT_STUDIO_EDIT));
if ( edit != nullptr )
{
if ( !m_script->GetScript(edit) ) // compile
{
std::string error;
m_script->GetError(error);
SetInfoText(error, false);
return false;
}
}
}
m_script->SetStepMode(false);
m_interface->DeleteControl(EVENT_WINDOW3);
pw = static_cast<CWindow*>(m_interface->SearchControl(EVENT_WINDOW6));
if (pw != nullptr) pw->SetState(STATE_VISIBLE | STATE_ENABLE);
m_pause->DeactivatePause(m_editorPause);
m_editorPause = nullptr;
m_pause->DeactivatePause(m_runningPause);
m_runningPause = nullptr;
m_main->SetEditLock(false, true);
m_camera->SetType(m_editCamera);
m_settings->SetIOPos(m_dialogPos);
m_settings->SetIODim(m_dialogDim);
m_settings->SetWindowPos(m_windowPos);
m_settings->SetWindowDim(m_windowDim);
m_settings->SetWindowMax(m_bEditMaximized);
return true;
}
// Specifies the message to display.
// The messages are not clickable 8 seconds,
// even if a message was clickable poster before.
void CStudio::SetInfoText(std::string text, bool bClickable)
{
if ( bClickable && m_fixInfoTextTime > 0.0f ) return;
if ( !bClickable ) m_fixInfoTextTime = 8.0f;
CWindow* pw = static_cast< CWindow* >(m_interface->SearchControl(EVENT_WINDOW3));
if ( pw == nullptr ) return;
CList* list = static_cast< CList* >(pw->SearchControl(EVENT_STUDIO_LIST));
if ( list == nullptr ) return;
list->Flush(); // just text
list->SetItemName(0, text.c_str());
if ( text[0] == 0 ) bClickable = false;
list->SetSelectCap(bClickable);
if ( bClickable )
{
std::string res;
GetResource(RES_TEXT, RT_STUDIO_LISTTT, res);
list->SetTooltip(res);
list->SetState(STATE_ENABLE);
}
else
{
list->SetTooltip("");
//? list->ClearState(STATE_ENABLE);
list->SetState(STATE_ENABLE, text[0] != 0);
}
}
// Beginning of the display of a dialogue.
void CStudio::StartDialog(const Event &event)
{
if ( event.type == EVENT_STUDIO_OPEN )
{
m_fileDialog = std::make_unique<CFileDialog>();
m_fileDialog->SetDialogType(CFileDialog::Type::Open);
}
if ( event.type == EVENT_STUDIO_SAVE )
{
m_fileDialog = std::make_unique<CFileDialog>();
m_fileDialog->SetDialogType(CFileDialog::Type::Save);
}
if (m_fileDialog != nullptr) // a dialog was created?
{
m_main->SetSatComLock(true); // impossible to use the SatCom
m_fileDialog->SetWindowEvent(EVENT_WINDOW9);
m_fileDialog->SetWindowPos(m_dialogPos);
m_fileDialog->SetWindowDim(m_dialogDim);
m_fileDialog->SetAutoExtension(".cbot");
m_fileDialog->AddOptionalExtension(".txt");
m_fileDialog->SetUsePublicPrivate(true);
m_fileDialog->SetPublic(m_settings->GetIOPublic());
m_fileDialog->SetPublicFolder("program");
m_fileDialog->SetPrivateFolder(m_main->GetPlayerProfile()->GetSaveFile("program"));
if ( event.type == EVENT_STUDIO_SAVE )
{
m_fileDialog->SetConfirmOverwrite(true);
// filename in CScript may include sub-folder
std::string filename = m_script->GetFilename();
if (!filename.empty())
{
size_t pos = filename.find_last_of("/");
if (pos != std::string::npos) // split subfolder from filename
{
m_fileDialog->SetSubFolderPath(filename.substr(0, pos));
filename = filename.substr(pos+1, filename.length()-pos-1);
}
}
m_fileDialog->SetFilename(filename);
}
m_fileDialog->StartDialog();
}
}
// End of the display of a dialogue.
void CStudio::StopDialog()
{
if (m_fileDialog != nullptr) // a dialog exists?
{
m_settings->SetIOPublic(m_fileDialog->GetPublic());
m_dialogPos = m_fileDialog->GetWindowPos();
m_dialogDim = m_fileDialog->GetWindowDim();
m_fileDialog->StopDialog();
m_fileDialog.reset();
}
m_main->SetSatComLock(false); // possible to use the SatCom
}
// Management of events for a dialogue.
bool CStudio::EventDialog(const Event &event)
{
if (m_fileDialog != nullptr) // a dialog exists?
{
if ( event.type == EVENT_DIALOG_STOP )
{
StopDialog();
return true;
}
if (event.type == EVENT_DIALOG_ACTION) // operation complete ?
{
CWindow* pw = static_cast< CWindow* >(m_interface->SearchControl(EVENT_WINDOW3));
if ( pw == nullptr ) return false;
CEdit* pe = static_cast< CEdit* >(pw->SearchControl(EVENT_STUDIO_EDIT));
if ( pe == nullptr ) return false;
std::string path = m_fileDialog->GetBasePath() + "/"; // public/private folder
std::string subpath = m_fileDialog->GetSubFolderPath();// sub-folder
// filename in CScript may include sub-folder
std::string filename = subpath.empty() ? "" : subpath + "/";
filename += m_fileDialog->GetFilename();
CFileDialog::Type type = m_fileDialog->GetDialogType();
if ( type == CFileDialog::Type::Save )
{
if (!pe->WriteText(path + filename))
{
m_sound->Play(SOUND_TZOING);
return true;
}
if ( !m_program->readOnly )
m_script->SetFilename(filename);
}
else if ( type == CFileDialog::Type::Open )
{
if (!pe->ReadText(path + filename))
{
m_sound->Play(SOUND_TZOING);
return true;
}
m_script->SetFilename(filename);
ColorizeScript(pe);
}
StopDialog();
return true;
}
return m_fileDialog->EventProcess(event);
}
return true;
}
// Changing the size of a editing program.
void CStudio::ViewEditScript()
{
CWindow* pw;
CEdit* edit;
pw = static_cast< CWindow* >(m_interface->SearchControl(EVENT_WINDOW3));
if ( pw == nullptr ) return;
edit = static_cast< CEdit* >(pw->SearchControl(EVENT_STUDIO_EDIT));
if ( edit == nullptr ) return;
glm::ivec2 dim = m_engine->GetWindowSize();
edit->SetFontSize(m_settings->GetFontSize()/(dim.x/640.0f));
}
// Updates the operating mode.
void CStudio::UpdateFlux()
{
if ( m_bRunning )
{
if ( m_bRealTime ) // run?
{
m_pause->DeactivatePause(m_runningPause);
m_runningPause = nullptr;
}
else // step by step?
{
if (m_runningPause == nullptr)
{
m_runningPause = m_pause->ActivatePause(PAUSE_ENGINE|PAUSE_MUTE_SOUND);
}
}
}
else // stop?
{
if (m_runningPause == nullptr)
{
m_runningPause = m_pause->ActivatePause(PAUSE_ENGINE|PAUSE_MUTE_SOUND);
}
}
}
// Updates the buttons.
void CStudio::UpdateButtons()
{
CWindow* pw;
CEdit* edit;
CButton* button;
pw = static_cast< CWindow* >(m_interface->SearchControl(EVENT_WINDOW3));
if ( pw == nullptr ) return;
edit = static_cast< CEdit* >(pw->SearchControl(EVENT_STUDIO_EDIT));
if ( edit == nullptr ) return;
if ( m_bRunning )
{
edit->SetIcon(1); // red background
edit->SetEditCap(false); // just to see
edit->SetHighlightCap(true);
}
else
{
edit->SetIcon(m_program->readOnly ? 1 : 0); // standard background
edit->SetEditCap(!m_program->readOnly);
edit->SetHighlightCap(true);
}
button = static_cast< CButton* >(pw->SearchControl(EVENT_STUDIO_CLONE));
if ( button == nullptr ) return;
button->SetState(STATE_ENABLE, m_main->CanPlayerInteract() && (m_program->runnable && !m_bRunning));
button = static_cast< CButton* >(pw->SearchControl(EVENT_STUDIO_COMPILE));
if ( button == nullptr ) return;
button->SetState(STATE_ENABLE, m_main->CanPlayerInteract() && (m_program->runnable && !m_bRunning));
button = static_cast< CButton* >(pw->SearchControl(EVENT_STUDIO_RUN));
if ( button == nullptr ) return;
button->SetIcon(m_bRunning?8:21); // stop/run
button->SetState(STATE_ENABLE, m_main->CanPlayerInteract() && (m_program->runnable || m_bRunning));
button = static_cast< CButton* >(pw->SearchControl(EVENT_STUDIO_REALTIME));
if ( button == nullptr ) return;
button->SetIcon(m_bRealTime?64+22:64+21);
button->SetState(STATE_ENABLE, (!m_bRunning || !m_script->IsContinue()));
button = static_cast< CButton* >(pw->SearchControl(EVENT_STUDIO_STEP));
if ( button == nullptr ) return;
button->SetState(STATE_ENABLE, (m_bRunning && !m_bRealTime && !m_script->IsContinue()));
button = static_cast< CButton* >(pw->SearchControl(EVENT_STUDIO_NEW));
if ( button == nullptr ) return;
button->SetState(STATE_ENABLE, !m_program->readOnly);
button = static_cast< CButton* >(pw->SearchControl(EVENT_STUDIO_OPEN));
if ( button == nullptr ) return;
button->SetState(STATE_ENABLE, !m_program->readOnly);
button = static_cast< CButton* >(pw->SearchControl(EVENT_STUDIO_UNDO));
if ( button == nullptr ) return;
button->SetState(STATE_ENABLE, !m_program->readOnly);
button = static_cast< CButton* >(pw->SearchControl(EVENT_STUDIO_CUT));
if ( button == nullptr ) return;
button->SetState(STATE_ENABLE, !m_program->readOnly);
button = static_cast< CButton* >(pw->SearchControl(EVENT_STUDIO_PASTE));
if ( button == nullptr ) return;
button->SetState(STATE_ENABLE, !m_program->readOnly);
}
} // namespace Ui