[email protected] 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. /******************************************************************************/
  2. #include "stdafx.h"
  3. /******************************************************************************/
  4. EnumEditor EnumEdit;
  5. /******************************************************************************/
  6. /******************************************************************************/
  7. cchar8 *EnumEditor::Type_t[]=
  8. {
  9. "Default", // 0
  10. "Byte" , // 1
  11. "UShort" , // 2
  12. "UInt" , // 3
  13. };
  14. /******************************************************************************/
  15. void EnumEditor::Enum::setColor() {color=GuiListTextColor(); if(removed)color.a/=2;}
  16. void EnumEditor::Enum::operator=(C EditEnum &src) {enum_id=src.id; name=src.name; removed=src.removed; setColor();}
  17. void EnumEditor::RenameWindow::create()
  18. {
  19. Gui+=::EE::Window::create(Rect_C(0, 0, 1, 0.14f), "Rename Enum").hide(); button[2].show();
  20. T +=textline.create(Rect (0, -clientHeight(), clientWidth(), 0).extend(-0.01f));
  21. }
  22. void EnumEditor::RenameWindow::activate(C UID &enum_id, C Str &name)
  23. {
  24. T.enum_id=enum_id;
  25. textline.set(name).selectAll().activate();
  26. ::EE::GuiObj::activate();
  27. }
  28. void EnumEditor::RenameWindow::update(C GuiPC &gpc)
  29. {
  30. ::EE::ClosableWindow::update(gpc);
  31. if(Gui.window()==this)
  32. {
  33. if(Kb.k(KB_ENTER)){if(EnumEdit.rename(enum_id, textline()))hide();else Gui.msgBox(S, "Invalid enum name.\nEnum may contain only letters, digits and underline characters.\nIt may not contain spaces, symbols or start with a digit."); Kb.eatKey();}
  34. }
  35. }
  36. int EnumEditor::ListEnum::getPos(C Vec2 &pos) {int p=screenToVisY(pos.y-elmHeight()/2); return (p>=0) ? p : visibleElms();}
  37. void EnumEditor::ListEnum::draw(C GuiPC &gpc)
  38. {
  39. if(visible() && gpc.visible)
  40. {
  41. GuiSkin skin;
  42. int elm=-1; if(Gui.dragging() && Gui.objAtPos(Gui.dragPos())==this)elm=getPos(Gui.dragPos());
  43. if( elm>=0)
  44. {
  45. if(Gui.skin)skin=*Gui.skin; skin.list.highlight_color.zero(); T.skin(&skin);
  46. }
  47. ::EE::_List::draw(gpc);
  48. if(elm>=0)
  49. {
  50. T.skin(null);
  51. D.clip(gpc.clip);
  52. flt y=visToScreenPos(elm, &gpc).y, b=0.005f;
  53. Rect(-D.w(), y-b, D.w(), y+b).draw(ColorAlpha(TURQ, 0.5f));
  54. }
  55. }
  56. }
  57. void EnumEditor::Change::create(ptr user)
  58. {
  59. enums=EnumEdit.enums;
  60. EnumEdit.undoVis();
  61. }
  62. void EnumEditor::Change::apply(ptr user)
  63. {
  64. EnumEdit.enums.undo(enums);
  65. EnumEdit.setChanged();
  66. EnumEdit.undoVis();
  67. }
  68. void EnumEditor::undoVis() {SetUndo(undos, undo, redo);}
  69. void EnumEditor::NewEnum(EnumEditor &ee) {ee.newEnum();}
  70. void EnumEditor::newEnum()
  71. {
  72. if(elm)FREP(1000)
  73. {
  74. Str name=S+"ENUM_"+i;
  75. REPA(enums)if(Equal(enums[i].name, name, true))goto exists;
  76. {
  77. undos.set("new", true);
  78. EditEnum &e=enums.New().setName(name); e.order_time.getUTC();
  79. setChanged();
  80. rename_window.activate(e.id, e.name);
  81. break;
  82. }
  83. exists:;
  84. }
  85. }
  86. bool EnumEditor::rename(C UID &enum_id, C Str &name)
  87. {
  88. if(ValidEnum(name))
  89. {
  90. REPA(enums)if(enums[i].id==enum_id)
  91. {
  92. undos.set("rename", true); enums[i].setName(name); setChanged(); break;
  93. }
  94. return true;
  95. }
  96. return false;
  97. }
  98. void EnumEditor::Undo(EnumEditor &editor) {editor.undos.undo();}
  99. void EnumEditor::Redo(EnumEditor &editor) {editor.undos.redo();}
  100. void EnumEditor::Locate(EnumEditor &editor) {Proj.elmLocate(editor.elm_id);}
  101. void EnumEditor::ShowRemoved(EnumEditor &editor) {editor.toGui();}
  102. void EnumEditor::TypeChanged(EnumEditor &editor)
  103. {
  104. editor.undos.set("type");
  105. editor.enums.type=EditEnums::TYPE(editor.type());
  106. editor.enums.type_time.getUTC();
  107. editor.setChanged();
  108. }
  109. void EnumEditor::create()
  110. {
  111. ListColumn lc[]=
  112. {
  113. ListColumn(MEMBER(Enum, name), LCW_MAX_DATA_PARENT, "name"),
  114. };
  115. Gui+=::EE::Window::create("Enum Editor").hide(); button[1].show(); button[2].func(HideProjAct, SCAST(GuiObj, T)).show(); flag|=WIN_RESIZABLE;
  116. T+=undo .create(Rect_LU(0.01f, -0.01f , 0.055f, 0.055f)).func(Undo, T).focusable(false).desc("Undo"); undo.image="Gui/Misc/undo.img";
  117. T+=redo .create(Rect_LU(undo.rect().ru(), 0.055f, 0.055f)).func(Redo, T).focusable(false).desc("Redo"); redo.image="Gui/Misc/redo.img";
  118. T+=locate.create(Rect_LU(redo.rect().ru()+Vec2(0.01f, 0), 0.15f, 0.055f), "Locate").func(Locate, T).focusable(false).desc("Locate this element in the Project");
  119. ts.reset().align.set(1, 0);
  120. T+=type_t.create(Rect_LU(locate.rect().ru()+Vec2(0.03f, 0), 0.09f, 0.055f), "Type:", &ts);
  121. T+=type .create(Rect_LU(type_t.rect().ru()+Vec2(0.01f, 0), 0.19f, 0.055f), Type_t, Elms(Type_t)).func(TypeChanged, T);
  122. T+=show_removed.create().func(ShowRemoved, T).focusable(false).desc("Show removed elements"); show_removed.image="Gui/Misc/trash.img"; show_removed.mode=BUTTON_TOGGLE;
  123. T+=new_enum.create("New Enum").func(NewEnum, T);
  124. T+=region.create();
  125. region+=list.create(lc, Elms(lc), true).desc("Double click to rename element\nDrag and drop to change order"); list.flag|=LIST_MULTI_SEL; list.setElmOffset(MEMBER(Enum, offset)).setElmTextColor(MEMBER(Enum, color));
  126. rect(Rect_C(0, 0, 0.6f, 1));
  127. rename_window.create();
  128. }
  129. Rect EnumEditor::sizeLimit( )C {Rect r=::EE::Window::sizeLimit(); r.min.set(0.61f, 0.35f); return r;}
  130. EnumEditor& EnumEditor::rect(C Rect &rect)
  131. {
  132. ::EE::Window::rect(rect);
  133. Rect_RU r(clientWidth()-0.01f, -0.01f, 0.23f, 0.055f); if(r.min.x-0.01f-type.rect().h()<type.rect().max.x+0.01f)r-=Vec2(0, type.rect().h()+0.01f);
  134. new_enum .rect(r);
  135. show_removed.rect(Rect_RU(new_enum.rect().lu()-Vec2(0.01f, 0), new_enum.rect().h()));
  136. region .rect(Rect(0, -clientHeight(), clientWidth(), new_enum.rect().min.y).extend(-0.01f));
  137. return T;
  138. }
  139. void EnumEditor::skinChanged()
  140. {
  141. REPAO(data).setColor();
  142. }
  143. void EnumEditor::flush()
  144. {
  145. if(elm && changed)
  146. {
  147. if(ElmEnum *data=elm->enumData()){data->newVer(); data->from(enums);} // modify just before saving/sending in case we've received data from server after edit
  148. Save(enums, Proj.editPath(elm->id));
  149. ::Enum e; enums.copyTo(e, elm->name); Save(e, Proj.gamePath(elm->id)); Proj.savedGame(*elm);
  150. Server.setElmLong(elm->id);
  151. Proj.enumChanged(elm->id);
  152. }
  153. changed=false;
  154. }
  155. void EnumEditor::setChanged()
  156. {
  157. if(elm)
  158. {
  159. changed=true;
  160. if(ElmEnum *data=elm->enumData()){data->newVer(); data->from(enums);}
  161. toGui();
  162. }
  163. }
  164. void EnumEditor::Remove(Enum &e) {EnumEdit.remove(e);}
  165. void EnumEditor::remove(Enum &e)
  166. {
  167. if(EditEnum *ee=enums.find(e.enum_id))
  168. {
  169. undos.set("remove", true);
  170. ee->setRemoved(!ee->removed);
  171. setChanged();
  172. }
  173. }
  174. void EnumEditor::toGui()
  175. {
  176. int v=0; flt h=list.elmHeight();
  177. data.clear(); FREPA(enums)if(!enums[i].removed || show_removed())
  178. {
  179. Enum &e=data.New(); e=enums[i];
  180. region+=e.remove.create(Rect_LU(0, -(v++)*h, h, h), "R").func(Remove, e).desc(enums[i].removed ? "Restore this element" : "Remove this element");
  181. e.offset=h;
  182. }
  183. list.setData(data);
  184. type.set(enums.type, QUIET);
  185. }
  186. void EnumEditor::set(Elm *elm)
  187. {
  188. if(elm && elm->type!=ELM_ENUM)elm=null;
  189. if(T.elm!=elm)
  190. {
  191. rename_window.hide();
  192. flush();
  193. undos.del(); undoVis();
  194. T.elm =elm;
  195. T.elm_id=(elm ? elm->id : UIDZero);
  196. if(elm)enums.load(Proj.editPath(elm->id));else enums.del();
  197. toGui();
  198. Proj.refresh(false, false);
  199. visible(T.elm!=null).moveToTop();
  200. }
  201. }
  202. void EnumEditor::activate(Elm *elm) {set(elm); if(T.elm)::EE::GuiObj::activate();}
  203. void EnumEditor::toggle(Elm *elm) {if(elm==T.elm)elm=null; set(elm);}
  204. EnumEditor& EnumEditor::hide( ){if(visible()){::EE::Window::hide(); set(null);} return T;}
  205. void EnumEditor::DragEnums(EnumEditor &ee, GuiObj *obj, C Vec2 &screen_pos) {ee.dragEnums(obj, screen_pos);}
  206. void EnumEditor::dragEnums( GuiObj *obj, C Vec2 &screen_pos)
  207. {
  208. if(elm && obj==&list)
  209. {
  210. list.sel.sort(Compare); // sort to make sure we're processing from first to last
  211. int target=list.visToAbs(list.getPos(screen_pos));
  212. if(list.sel.elms() && target>list.sel.first())target--;
  213. // if before 'target' there are other elements selected, then adjust 'target' to the first selected element (which is connected to target)
  214. int ti=list.sel.find(target); if(ti>=0)for(; InRange(ti-1, list.sel); )
  215. {
  216. int prev_target=list.sel[ti-1];
  217. if(list.absToVis(prev_target)==list.absToVis(target)-1){ti--; target=prev_target;}else break;
  218. }
  219. UID list_cur; if(Enum *e=list())list_cur=e->enum_id;else list_cur.zero();
  220. Memt<UID> enum_id; FREPA(list.sel)if(Enum *e=list.absToData(list.sel[i]))enum_id.add(e->enum_id);
  221. if(enum_id.elms())
  222. {
  223. undos.set("move", true);
  224. int tar=-1; if(InRange(target, list.totalElms()))if(Enum *e=list.absToData(target))tar=enums.findI(e->enum_id);
  225. if(!InRange(tar, enums))tar=enums.elms(); // move to end
  226. FREPA(enum_id)tar=enums.move(enum_id[i], tar);
  227. setChanged();
  228. REPD(v, list.visibleElms())if(Enum *e=list.visToData(v))if(e->enum_id==list_cur ){list.cur =v ; break;}
  229. FREPA(enum_id)REPD(a, list. totalElms())if(Enum *e=list.absToData(a))if(e->enum_id==enum_id[i]){list.sel.include(a); break;}
  230. }
  231. }
  232. }
  233. void EnumEditor::update(C GuiPC &gpc)
  234. {
  235. ::EE::ClosableWindow::update(gpc);
  236. if(Gui.window()==this)REPA(MT)if(MT.bp(i) && MT.guiObj(i)==&list)if(Enum *e=list())
  237. {
  238. if(list.selMode()==LSM_SET)Gui.drag(DragEnums, T, MT.touch(i));
  239. if(MT.bd(i))rename_window.activate(e->enum_id, e->name);
  240. }
  241. }
  242. void EnumEditor::elmChanged(C UID &enum_id)
  243. {
  244. if(enum_id==elm_id && enum_id.valid())
  245. {
  246. undos.set(null, true);
  247. EditEnums temp; if(temp.load(Proj.editPath(elm_id)))if(enums.sync(temp))toGui();
  248. }
  249. }
  250. void EnumEditor::erasing(C UID &elm_id) {if(elm && elm->id==elm_id)set(null);}
  251. EnumEditor::EnumEditor() : elm_id(UIDZero), elm(null), changed(false), undos(true) {}
  252. EnumEditor::Enum::Enum() : removed(false), color(BLACK), offset(0), enum_id(UIDZero) {}
  253. EnumEditor::RenameWindow::RenameWindow() : enum_id(UIDZero) {}
  254. /******************************************************************************/