TextResourceEditor.cpp 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  1. // Copyright (c) 2014-2015, THUNDERBEAST GAMES LLC All rights reserved
  2. // Please see LICENSE.md in repository root for license information
  3. // https://github.com/AtomicGameEngine/AtomicGameEngine
  4. #include "AtomicEditor.h"
  5. #include <Atomic/Container/ArrayPtr.h>
  6. #include <Atomic/UI/UI.h>
  7. #include <Atomic/IO/Log.h>
  8. #include <Atomic/IO/File.h>
  9. #include <Atomic/IO/FileSystem.h>
  10. #include <Atomic/Resource/ResourceCache.h>
  11. #include <Atomic/Core/CoreEvents.h>
  12. #include "../AEEvents.h"
  13. #include "../UI/UIFindTextWidget.h"
  14. #include "TextResourceEditor.h"
  15. #include <TurboBadger/tb_message_window.h>
  16. #include <TurboBadger/tb_editfield.h>
  17. #include <TurboBadger/tb_style_edit.h>
  18. #include <TurboBadger/tb_style_edit_content.h>
  19. using namespace tb;
  20. namespace AtomicEditor
  21. {
  22. TextResourceEditor ::TextResourceEditor(Context* context, const String &fullpath, TBTabContainer *container) :
  23. ResourceEditor(context, fullpath, container),
  24. styleEdit_(0),
  25. editField_(0),
  26. modified_(false),
  27. currentFindPos_(-1)
  28. {
  29. TBLayout* layout = new TBLayout();
  30. layout->SetLayoutDistribution(LAYOUT_DISTRIBUTION_GRAVITY);
  31. layout->SetGravity(WIDGET_GRAVITY_ALL);
  32. rootContentWidget_->AddChild(layout);
  33. TBContainer* c = new TBContainer();
  34. c->SetGravity(WIDGET_GRAVITY_ALL);
  35. TBEditField* text = editField_ = new TBEditField();
  36. text->SetMultiline(true);
  37. text->SetWrapping(true);
  38. text->SetGravity(WIDGET_GRAVITY_ALL);
  39. text->SetStyling(true);
  40. text->SetSkinBg(TBIDC("TextCode"));
  41. TBFontDescription fd;
  42. fd.SetID(TBIDC("Monaco"));
  43. fd.SetSize(12);
  44. text->SetFontDescription(fd);
  45. SharedPtr<File> jsFile(GetSubsystem<ResourceCache>()->GetFile(fullpath));
  46. assert(jsFile);
  47. String source;
  48. jsFile->ReadText(source);
  49. text->SetText(source.CString());
  50. c->AddChild(text);
  51. layout->AddChild(c);
  52. layout->SetSpacing(0);
  53. TBStyleEdit* sedit = text->GetStyleEdit();
  54. sedit->text_change_listener = this;
  55. TBTextTheme* theme = new TBTextTheme();
  56. for (unsigned i = 0; i < TB_MAX_TEXT_THEME_COLORS; i++)
  57. theme->themeColors[i] = TBColor(255, 255, 255);
  58. sedit->SetTextTheme(theme);
  59. styleEdit_ = sedit;
  60. SubscribeToEvent(E_UPDATE, HANDLER(TextResourceEditor, HandleUpdate));
  61. // FIXME: Set the size at the end of setup, so all children are updated accordingly
  62. // future size changes will be handled automatically
  63. TBRect rect = container_->GetContentRoot()->GetRect();
  64. rootContentWidget_->SetSize(rect.w, rect.h);
  65. }
  66. TextResourceEditor::~TextResourceEditor()
  67. {
  68. }
  69. bool TextResourceEditor::OnEvent(const TBWidgetEvent &ev)
  70. {
  71. if (ev.type == EVENT_TYPE_KEY_DOWN)
  72. {
  73. if (ev.special_key == TB_KEY_ESC)
  74. {
  75. SendEvent(E_FINDTEXTCLOSE);
  76. }
  77. }
  78. if (ev.type == EVENT_TYPE_SHORTCUT)
  79. {
  80. if (ev.ref_id == TBIDC("close"))
  81. {
  82. if (modified_)
  83. {
  84. TBMessageWindow *msg_win = new TBMessageWindow(container_, TBIDC("unsaved_jsmodifications_dialog"));
  85. TBMessageWindowSettings settings(TB_MSG_OK_CANCEL, TBID(uint32(0)));
  86. settings.dimmer = true;
  87. settings.styling = true;
  88. msg_win->Show("Unsaved Modifications", "There are unsaved modications.\nDo you wish to discard them and close?", &settings, 640, 360);
  89. }
  90. else
  91. {
  92. Close();
  93. }
  94. }
  95. if (ev.ref_id == TBIDC("save") && modified_)
  96. {
  97. TBStr text;
  98. styleEdit_->GetText(text);
  99. File file(context_, fullpath_, FILE_WRITE);
  100. file.Write((void*) text.CStr(), text.Length());
  101. file.Close();
  102. ResourceCache* cache = GetSubsystem<ResourceCache>();
  103. //SharedPtr<File> jsFile (GetSubsystem<ResourceCache>()->GetFile<File>(fullpath_));
  104. //cache->ReloadResource(jsFile);
  105. String filename = GetFileNameAndExtension(fullpath_);
  106. button_->SetText(filename.CString());
  107. modified_ = false;
  108. SendEvent(E_JAVASCRIPTSAVED);
  109. return true;
  110. }
  111. else if (ev.ref_id == TBIDC("find"))
  112. {
  113. using namespace FindTextOpen;
  114. SendEvent(E_FINDTEXTOPEN);
  115. }
  116. else if (ev.ref_id == TBIDC("findnext") || ev.ref_id == TBIDC("findprev"))
  117. {
  118. String text;
  119. FindTextWidget* finder = GetSubsystem<FindTextWidget>();
  120. finder->GetFindText(text);
  121. // TODO: get flags from finder
  122. unsigned flags = FINDTEXT_FLAG_NONE;
  123. if (ev.ref_id == TBIDC("findnext"))
  124. flags |= FINDTEXT_FLAG_NEXT;
  125. else if (ev.ref_id == TBIDC("findprev"))
  126. flags |= FINDTEXT_FLAG_PREV;
  127. flags |= FINDTEXT_FLAG_WRAP;
  128. finder->Find(text, flags);
  129. }
  130. else if (ev.ref_id == TBIDC("cut") || ev.ref_id == TBIDC("copy") || ev.ref_id == TBIDC("paste")
  131. || ev.ref_id == TBIDC("selectall") || ev.ref_id == TBIDC("undo") || ev.ref_id == TBIDC("redo") )
  132. {
  133. editField_->OnEvent(ev);
  134. }
  135. }
  136. if (ev.type == EVENT_TYPE_CLICK)
  137. {
  138. if (ev.target->GetID() == TBIDC("unsaved_jsmodifications_dialog"))
  139. {
  140. if (ev.ref_id == TBIDC("TBMessageWindow.ok"))
  141. {
  142. Close();
  143. }
  144. else
  145. {
  146. SetFocus();
  147. }
  148. return true;
  149. }
  150. }
  151. return false;
  152. }
  153. void TextResourceEditor::HandleUpdate(StringHash eventType, VariantMap& eventData)
  154. {
  155. if (!styleEdit_)
  156. return;
  157. }
  158. void TextResourceEditor::FindTextClose()
  159. {
  160. editField_->SetFocus(WIDGET_FOCUS_REASON_UNKNOWN);
  161. styleEdit_->selection.SelectNothing();
  162. }
  163. void TextResourceEditor::OnChange(TBStyleEdit* styleEdit)
  164. {
  165. modified_ = true;
  166. String filename = GetFileNameAndExtension(fullpath_);
  167. filename += "*";
  168. button_->SetText(filename.CString());
  169. }
  170. bool TextResourceEditor::FindText(const String& findText, unsigned flags)
  171. {
  172. // TODO: this should be shared with the JS resource editor
  173. unsigned findLength = findText.Length();
  174. if (!findLength)
  175. return true;
  176. TBStr _source;
  177. styleEdit_->GetText(_source);
  178. String source = _source.CStr();
  179. unsigned pos = String::NPOS;
  180. int startPos = currentFindPos_;
  181. if (currentFindPos_ == -1)
  182. startPos = styleEdit_->caret.GetGlobalOfs();
  183. else
  184. {
  185. if (flags & FINDTEXT_FLAG_NEXT)
  186. startPos += findLength;
  187. }
  188. if (flags & FINDTEXT_FLAG_PREV)
  189. {
  190. String pretext = source.Substring(0, startPos);
  191. pos = pretext.FindLast(findText, String::NPOS, flags & FINDTEXT_FLAG_CASESENSITIVE ? true : false);
  192. }
  193. else
  194. {
  195. pos = source.Find(findText, startPos, flags & FINDTEXT_FLAG_CASESENSITIVE ? true : false);
  196. }
  197. if (pos == String::NPOS)
  198. {
  199. if (flags & FINDTEXT_FLAG_WRAP)
  200. {
  201. if (flags & FINDTEXT_FLAG_PREV)
  202. {
  203. pos = source.FindLast(findText, String::NPOS, flags & FINDTEXT_FLAG_CASESENSITIVE ? true : false);
  204. }
  205. else
  206. {
  207. pos = source.Find(findText, 0, flags & FINDTEXT_FLAG_CASESENSITIVE ? true : false);
  208. }
  209. }
  210. if (pos == String::NPOS)
  211. {
  212. styleEdit_->selection.SelectNothing();
  213. return true;
  214. }
  215. }
  216. currentFindPos_ = pos;
  217. styleEdit_->caret.SetGlobalOfs((int) pos + findLength);
  218. int height = styleEdit_->layout_height;
  219. int newy = styleEdit_->caret.y - height/2;
  220. styleEdit_->SetScrollPos(styleEdit_->scroll_x, newy);
  221. styleEdit_->selection.Select(pos, pos + findLength);
  222. return true;
  223. }
  224. void TextResourceEditor::SetFocus()
  225. {
  226. editField_->SetFocus(WIDGET_FOCUS_REASON_UNKNOWN);
  227. }
  228. bool TextResourceEditor::HasUnsavedModifications()
  229. {
  230. return modified_;
  231. }
  232. }