wxArt2D
wxledit.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: wxledit.cpp
3 // Purpose: Different editors, consoles for wxLua
4 // Author: John Labenski
5 // Modified by:
6 // Created: 11/05/2002
7 // RCS-ID:
8 // Copyright: (c) John Labenski
9 // Licence: wxWidgets licence
10 /////////////////////////////////////////////////////////////////////////////
11 
12 #include "a2dprec.h"
13 
14 #ifdef __BORLANDC__
15 #pragma hdrstop
16 #endif
17 
18 #ifndef WX_PRECOMP
19 #include "wx/wx.h"
20 #endif // WX_PRECOMP
21 
22 #include "wx/filename.h"
23 #include "wx/splitter.h"
24 #include "wx/confbase.h"
25 
26 #include "wx/luawraps/wxledit.h"
27 #include "wxlua/debug/wxldebug.h"
28 #include "wxlua/debug/wxlstack.h"
29 
30 #include "wx/stedit/stemenum.h"
31 #include "wx/stedit/steevent.h"
32 
33 #include "../art/wxlua.xpm"
34 #include "../art/open.xpm"
35 #include "../art/save.xpm"
36 #include "../art/play.xpm"
37 #include "../art/stop.xpm"
38 
39 #define STC_DEF_MARGIN_WIDTH 16
40 
41 DEFINE_LOCAL_EVENT_TYPE(wxEVT_LUASHELL_wxLUA_CREATION)
42 DEFINE_LOCAL_EVENT_TYPE(wxEVT_LUAIDE_wxLUA_CREATION)
43 
44 //-----------------------------------------------------------------------------
45 // wxLuaShell
46 //-----------------------------------------------------------------------------
47 IMPLEMENT_ABSTRACT_CLASS(wxLuaShell, wxSTEditorShell)
48 
49 BEGIN_EVENT_TABLE(wxLuaShell, wxSTEditorShell)
50  EVT_STESHELL_ENTER ( wxID_ANY, wxLuaShell::OnSTEEvent )
51  EVT_LUA_PRINT ( wxID_ANY, wxLuaShell::OnLua )
52  EVT_LUA_ERROR ( wxID_ANY, wxLuaShell::OnLua )
53 END_EVENT_TABLE()
54 
55 void wxLuaShell::Init()
56 {
57  m_wxlstate_static = false;
58 }
59 
60 bool wxLuaShell::Create(wxWindow *parent, wxWindowID id,
61  const wxPoint& pos, const wxSize& size,
62  long style, const wxString& name)
63 {
64  if (!wxSTEditorShell::Create(parent, id, pos, size, style, name))
65  return false;
66 
67 #if wxCHECK_VERSION(2,9,0)
68  SetFileName(wxFileName(name), false);
69  SetLanguage(wxFileName(wxT("a.lua"))); // use the lua lexer
70 #else
71  SetFileName( name, false);
72  SetLanguage( wxT("a.lua") ); // use the lua lexer
73 #endif
74 
75  return true;
76 }
77 
78 wxLuaShell::~wxLuaShell()
79 {
80  if (m_wxlState.Ok() && !m_wxlstate_static)
81  {
82  m_wxlState.CloseLuaState(true); // force closing it since we're gone
83  }
84 }
85 
86 void wxLuaShell::SetwxLuaState(const wxLuaState& wxlState, bool is_static)
87 {
88  if (m_wxlState.Ok() && !m_wxlstate_static)
89  {
90  // try to close it nicely first
91  if (m_wxlState.IsRunning())
92  {
93  wxSafeYield();
94  m_wxlState.DebugHookBreak();
95  }
96 
97  m_wxlState.CloseLuaState(true); // force closing it since we own it
98  }
99 
100  m_wxlState = wxlState;
101  m_wxlstate_static = is_static;
102 }
103 
104 bool wxLuaShell::RecreatewxLuaState(wxEvtHandler *wxlStateEvtHandler, int win_id)
105 {
106  // ask if anyone else wants to create a new wxLuaState for us
107  wxLuaEvent event(wxEVT_LUASHELL_wxLUA_CREATION, GetId(), m_wxlState);
108  event.SetEventObject(this);
109  event.SetInt(0);
110  event.SetExtraLong(win_id);
111 
112  // return if handled, but not skipped.
113  if (GetEventHandler()->ProcessEvent(event))
114  return false;
115 
116  // Did they set a valid interpreter for the event and is it new?
117  // If it's not different then assume they didn't change it so we'll create
118  // a new one below. If they wanted to just adjust the current state they
119  // should have called event.Skip(false)
120  if (event.GetwxLuaState().Ok() && (event.GetwxLuaState() != m_wxlState))
121  {
122  SetwxLuaState(event.GetwxLuaState(), event.GetInt() == 1);
123  }
124  else
125  {
126  wxLuaState wxlState = wxLuaState(wxlStateEvtHandler, win_id);
127  wxlState.SetLuaDebugHook( LUA_MASKCOUNT, 1000, 50, false );
128  SetwxLuaState(wxlState, false);
129  }
130 
131  return m_wxlState.Ok();
132 }
133 
134 bool wxLuaShell::RunString(const wxString& string_, bool append_text)
135 {
136  bool ret = false;
137 
138  wxString string(string_);
139 
140  if (string.Trim(true).Trim(false).IsEmpty())
141  return ret;
142 
143  if (append_text)
144  {
145  if (!GetLine(GetLineCount()).IsEmpty())
146  AppendText(wxT("\n"));
147 
148  AppendText(string);
149  }
150 
151  AppendText(wxT("\n"));
152 
153  // restart the interpreter
154  if (string == wxT("reset"))
155  {
156  if (m_wxlstate_static)
157  {
158  AppendText(wxT("Unable to reset lua, interpreter locked by another process.\n"));
159  }
160  else
161  {
162  if (RecreatewxLuaState(GetEventHandler(), GetId()))
163  {
164  AppendText(wxT("Successfully reset interpreter.\n"));
165  ret = true;
166  }
167  else
168  AppendText(wxT("Unable to reset interpreter.\n"));
169  }
170  }
171  else if (m_wxlState.Ok())
172  {
173  // allow for syntax of "= 1+2+3" to print result
174  if (string.Trim(true).Find(wxT('=')) == 0)
175  string = wxT("return ") + string.AfterFirst('=');
176 
177  if (0 != m_wxlState.CompileString(string))
178  {
179  // try to see if we can return the value w/o error to print it
180  if (0 == m_wxlState.CompileString(wxT("return ") + string))
181  string = wxT("return ") + string;
182  }
183 
184  int top1 = m_wxlState.lua_GetTop();
185  ret = m_wxlState.RunString(string, wxT("wxLuaShell"), LUA_MULTRET) == 0;
186  int top2 = m_wxlState.lua_GetTop();
187 
188  if (ret && (top2 > top1))
189  {
190  m_wxlState.lua_GetGlobal("tostring");
191 
192  if (!m_wxlState.lua_IsFunction(-1))
193  {
194  // This code is also used in wxlua_printFunction()
195  AppendText(wxT("wxLua ERROR: Unable to print() without the tostring() function. Did you remove it?\n"));
196  m_wxlState.lua_Pop(1); // pop the nil or whatever replaced tostring()
197  top2 = top1; // don't let for loop run
198  }
199 
200  for (int n = top1+1; n <= top2; n++)
201  {
202  m_wxlState.lua_PushValue(-1); // push tostring function to be called
203  m_wxlState.lua_PushValue(n); // value to print
204  m_wxlState.lua_Call(1, 1); // run tostring function
205 
206  AppendText(m_wxlState.lua_TowxString(-1) + wxT("\n"));
207  m_wxlState.lua_Pop(1); // pop string from "tostring" function
208  }
209  }
210 
211  m_wxlState.lua_SetTop(top1);
212  }
213  else
214  AppendText(wxT("The lua interpreter is not available - try running 'reset'.\n"));
215 
216  CheckPrompt(true);
217 
218  return ret;
219 }
220 
221 size_t wxLuaShell::DoGetAutoCompleteKeyWords(const wxString& root, wxArrayString& words)
222 {
223  size_t count = wxSTEditorShell::DoGetAutoCompleteKeyWords(root, words);
224 
225  return count;
226 }
227 
228 void wxLuaShell::OnSTEEvent(wxSTEditorEvent& event)
229 {
230  event.Skip();
231  if (event.GetEventType() == wxEVT_STESHELL_ENTER)
232  {
233  // only bother to run it is it's not empty
234  wxString str = event.GetString().Strip(wxString::both);
235  if (!str.IsEmpty())
236  RunString(str, false);
237  }
238 }
239 
240 void wxLuaShell::OnLua(wxLuaEvent &event)
241 {
242  if (event.GetEventType() == wxEVT_LUA_PRINT)
243  {
244  AppendText(event.GetString() + wxT("\n"));
245  }
246  else if (event.GetEventType() == wxEVT_LUA_ERROR)
247  {
248  AppendText(wxT("\nError: ") + event.GetString() + wxT("\n"));
249  }
250 }
251 
252 void wxLuaShell::UpdateItems(wxMenu *menu, wxMenuBar *menuBar, wxToolBar *toolBar)
253 {
254  bool is_running = m_wxlState.Ok() && m_wxlState.IsRunning();
255 
256  wxSTEditorMenuManager::DoEnableItem(menu, menuBar, toolBar, ID_WXLUAIDE_RUN_LUA, !is_running);
257  wxSTEditorMenuManager::DoEnableItem(menu, menuBar, toolBar, ID_WXLUAIDE_BREAK_LUA, is_running);
258  wxSTEditorMenuManager::DoEnableItem(menu, menuBar, toolBar, ID_WXLUAIDE_SHOW_STACK, m_wxlState.Ok());
259 
260  wxSTEditor::UpdateItems(menu, menuBar, toolBar);
261 }
262 
263 //-----------------------------------------------------------------------------
264 // wxLuaEditor
265 //-----------------------------------------------------------------------------
266 IMPLEMENT_ABSTRACT_CLASS(wxLuaEditor, wxSTEditor)
267 
268 BEGIN_EVENT_TABLE(wxLuaEditor, wxSTEditor)
269  EVT_STC_MARGINCLICK(wxID_ANY, wxLuaEditor::OnMarginClick)
270  EVT_MENU(ID_WXLUAIDE_TOGGLE_BREAKPOINT, wxLuaEditor::OnMenu)
271 END_EVENT_TABLE()
272 
273 void wxLuaEditor::Init()
274 {
275  m_wxluaIDE = NULL;
276 }
277 
278 bool wxLuaEditor::Create(wxWindow *parent, int id,
279  const wxPoint& pos, const wxSize& size,
280  long style, const wxString& name)
281 {
282  if (!wxSTEditor::Create(parent, id, pos, size, style, name))
283  return false;
284 
285  SetVisiblePolicy(wxSTC_VISIBLE_SLOP, 3);
286  SetXCaretPolicy(wxSTC_CARET_SLOP, 10);
287  SetYCaretPolicy(wxSTC_CARET_SLOP, 3);
288 
289  // click on margin to set breakpoint
290  MarkerDefine(markerBreak, wxSTC_MARK_SMALLRECT, *wxBLACK, *wxRED);
291  MarkerDefine(markerError, wxSTC_MARK_SHORTARROW, *wxBLACK, *wxRED);
292 
293  SetMarginSensitive(marginBreak, true);
294  SetMarginType(marginError, wxSTC_MARGIN_SYMBOL);
295  SetMarginWidth(marginError, STC_DEF_MARGIN_WIDTH);
296  //SetMarginMask(marginError, (1<<markerError)|(1<<markerBreak)|(1<<STE_BOOKMARK_MARKER));
297 
298 #if wxCHECK_VERSION(2,9,0)
299  SetFileName(wxFileName(wxT("untitled.lua")));
300  SetLanguage(wxFileName(wxT("untitled.lua")));
301 #else
302  SetFileName( wxT("untitled.lua"), false);
303  SetLanguage( wxT("untitled.lua") ); // use the lua lexer
304 #endif
305  return true;
306 }
307 
308 void wxLuaEditor::OnMenu(wxCommandEvent& event)
309 {
310  HandleMenuEvent(event);
311 }
312 
313 bool wxLuaEditor::HandleMenuEvent(wxCommandEvent& event)
314 {
315  int line = LineFromPosition(GetInsertionPoint());
316 
317  switch (event.GetId())
318  {
319  case ID_WXLUAIDE_TOGGLE_BREAKPOINT :
320  {
321  if (HasBreakpoint(line))
322  DeleteBreakpoint(line);
323  else
324  AddBreakpoint(line);
325 
326  return true;
327  }
328  }
329 
330  return wxSTEditor::HandleMenuEvent(event);
331 }
332 
333 void wxLuaEditor::OnMarginClick( wxStyledTextEvent &event )
334 {
335  // unfortunately we can't get right or double clicks
336  event.Skip();
337  //int line = event.GetLine(); - not implemented
338  //wxPrintf(wxT("Margin line %d %d %d %d %d\n"), line, event.GetLine(), MarkerGet(line), event.GetModifiers(), event.GetKey()); fflush(stdout);
339 }
340 
341 bool wxLuaEditor::HasBreakpoint(int line)
342 {
343  if (line < 0)
344  return MarkerNext(markerBreak, 1<<markerBreak) >= 0;
345 
346  return (MarkerGet(line) & (1<<markerBreak)) != 0;
347 }
348 void wxLuaEditor::ClearBreakpoints()
349 {
350  MarkerDeleteAll(markerBreak);
351 }
352 void wxLuaEditor::AddBreakpoint(int line)
353 {
354  if ((line < 0) || (line > GetLineCount()) || HasBreakpoint(line))
355  return;
356 
357  (void)MarkerAdd(line, markerBreak);
358 }
359 void wxLuaEditor::DeleteBreakpoint(int line)
360 {
361  if (!HasBreakpoint(line))
362  return;
363 
364  MarkerDelete(line, markerBreak);
365 }
366 
367 void wxLuaEditor::UpdateItems(wxMenu *menu, wxMenuBar *menuBar, wxToolBar *toolBar)
368 {
369  wxLuaState wxlState;
370  if (GetwxLuaIDE())
371  wxlState = GetwxLuaIDE()->GetwxLuaState();
372 
373  bool is_running = wxlState.Ok() && wxlState.IsRunning();
374 
375  wxSTEditorMenuManager::DoEnableItem(menu, menuBar, toolBar, ID_WXLUAIDE_RUN_LUA, !is_running);
376  wxSTEditorMenuManager::DoEnableItem(menu, menuBar, toolBar, ID_WXLUAIDE_BREAK_LUA, is_running);
377  wxSTEditorMenuManager::DoEnableItem(menu, menuBar, toolBar, ID_WXLUAIDE_SHOW_STACK, wxlState.Ok() && !is_running);
378 
379  wxSTEditor::UpdateItems(menu, menuBar, toolBar);
380 }
381 
382 //-----------------------------------------------------------------------------
383 // wxLuaIDE
384 //-----------------------------------------------------------------------------
385 
386 IMPLEMENT_DYNAMIC_CLASS(wxLuaIDE, wxWindow);
387 
388 BEGIN_EVENT_TABLE(wxLuaIDE, wxWindow)
389  EVT_MENU (ID_WXLUAIDE_LOAD_LUA, wxLuaIDE::OnMenu)
390  EVT_MENU (ID_WXLUAIDE_SAVEAS_LUA, wxLuaIDE::OnMenu)
391  EVT_MENU (ID_WXLUAIDE_RUN_LUA, wxLuaIDE::OnMenu)
392  EVT_MENU (ID_WXLUAIDE_BREAK_LUA, wxLuaIDE::OnMenu)
393  EVT_MENU (ID_WXLUAIDE_SHOW_STACK, wxLuaIDE::OnMenu)
394 
395  EVT_STSPLITTER_CREATE_EDITOR(wxID_ANY, wxLuaIDE::OnCreateEditor)
396  EVT_SIZE (wxLuaIDE::OnSize)
397 
398  EVT_LUA_PRINT (wxID_ANY, wxLuaIDE::OnLua)
399  EVT_LUA_ERROR (wxID_ANY, wxLuaIDE::OnLua)
400  EVT_LUA_DEBUG_HOOK (wxID_ANY, wxLuaIDE::OnLua)
401 END_EVENT_TABLE()
402 
403 void wxLuaIDE::Init()
404 {
405  m_wxlstate_static = false;
406 
407  m_splitter = NULL;
408  m_editorNotebook = NULL;
409  m_msgNotebook = NULL;
410  m_luaOutput = NULL;
411  m_luaShell = NULL;
412  m_toolBar = NULL;
413 
414  m_options = 0;
415  m_show_stack = false;
416 }
417 
418 //#include "../src/wxext.h"
419 
420 bool wxLuaIDE::Create( wxWindow *parent, int id,
421  const wxPoint& pos, const wxSize& size,
422  long style, long options, const wxString& name)
423 {
424  m_options = options;
425 
426  if (!wxWindow::Create(parent, id, pos, size, style, name))
427  return false;
428 
429  if ((m_options & WXLUAIDE_TOOLBAR) != 0)
430  {
431  m_toolBar = new wxToolBar(this, wxID_ANY, wxDefaultPosition, wxDefaultSize);
432  PopulateToolBar(m_toolBar, m_options);
433  wxSTEditorMenuManager::DoEnableItem(NULL, GetMenuBar(), GetToolBar(), ID_WXLUAIDE_BREAK_LUA, false);
434  }
435 
436  m_splitter = new wxSplitterWindow(this, wxID_ANY);
437 
438  // Create the editor notebook
439  m_editorOptions = wxSTEditorOptions(STE_DEFAULT_OPTIONS);
440 
441  m_editorOptions.GetEditorPrefs().SetPrefBool(STE_PREF_VIEW_LINEMARGIN, true);
442  m_editorOptions.GetEditorPrefs().SetPrefBool(STE_PREF_VIEW_MARKERMARGIN, true);
443  m_editorOptions.SetToolBar(m_toolBar); // NULL is fine
444  m_editorOptions.SetDefaultFileName(wxT("untitled.lua"));
445  if (wxConfigBase::Get(false))
446  m_editorOptions.LoadConfig(*wxConfigBase::Get(false));
447 
448  m_editorNotebook = new wxSTEditorNotebook(m_splitter, ID_WXLUAIDE_EDITOR_NOTEBOOK,
449  wxDefaultPosition, wxSize(200,100), wxCLIP_CHILDREN);
450  m_editorNotebook->CreateOptions(m_editorOptions);
451  m_editorNotebook->InsertEditorSplitter(-1, wxID_ANY, wxT("untitled.lua"), true);
452 
453  m_editorNotebook->GetEditor()->MarkerDefine(wxLuaEditor::markerBreak, wxSTC_MARK_SMALLRECT, *wxBLACK, *wxRED);
454  m_editorNotebook->GetEditor()->MarkerDefine(wxLuaEditor::markerError, wxSTC_MARK_SHORTARROW, *wxBLACK, *wxRED);
455 
456  wxMenu *wxluaMenu = CreatewxLuaMenu();
457  m_editorOptions.GetEditorPopupMenu()->AppendSeparator();
458  m_editorOptions.GetEditorPopupMenu()->Append(wxID_ANY, wxT("wxLua"), wxluaMenu);
459 
460  // -----------------------------------------------------------------------
461  // Create the message notebook for shell and output window
462  m_shellOptions.SetSplitterOptions(STS_NO_EDITOR);
463  m_shellOptions.SetEditorStyles(m_editorOptions.GetEditorStyles());
464  m_shellOptions.SetEditorLangs(m_editorOptions.GetEditorLangs());
465  m_shellOptions.SetMenuManager(m_editorOptions.GetMenuManager(), true);
466  m_shellOptions.SetEditorPopupMenu(wxSTEditorMenuManager(0, 0, STE_MENU_EDIT_CUTCOPYPASTE|STE_MENU_EDIT_COMPLETEWORD).CreateEditMenu(), false);
467  m_shellOptions.SetToolBar(m_toolBar);
468 
469  m_msgNotebook = new wxSTEditorNotebook(m_splitter, ID_WXLUAIDE_MSG_NOTEBOOK,
470  wxDefaultPosition, wxDefaultSize, wxCLIP_CHILDREN);
471  m_msgNotebook->CreateOptions(m_shellOptions);
472 
473  // -----------------------------------------------------------------------
474  // Create the interactive lua shell
475  wxSTEditorSplitter *steSplitter = new wxSTEditorSplitter(m_msgNotebook, wxID_ANY,
476  wxDefaultPosition, wxDefaultSize, wxSP_3D);
477  steSplitter->CreateOptions(m_shellOptions);
478 
479  m_luaShell = new wxLuaShell(steSplitter, ID_WXLUAIDE_SHELL, wxDefaultPosition,
480  wxDefaultSize, 0);
481  m_luaShell->CreateOptions(m_shellOptions);
482  m_luaShell->SetWrapMode(wxSTC_WRAP_WORD);
483  //wxAcceleratorHelper::SetAcceleratorTable(m_luaShell, *m_shellOptions.GetMenuManager()->GetAcceleratorArray());
484  //wxAcceleratorHelper::SetAccelText(m_shellOptions.GetEditorPopupMenu(), *m_shellOptions.GetMenuManager()->GetAcceleratorArray());
485  m_luaShell->RecreatewxLuaState(m_luaShell->GetEventHandler(), m_luaShell->GetId());
486  m_luaShell->CheckPrompt(true);
487  steSplitter->Initialize(m_luaShell);
488  m_msgNotebook->InsertEditorSplitter(-1, steSplitter, true);
489 
490  // -----------------------------------------------------------------------
491  // Create the interactive lua shell for the output of the editor programs
492  steSplitter = new wxSTEditorSplitter(m_msgNotebook, wxID_ANY,
493  wxDefaultPosition, wxDefaultSize, wxSP_3D);
494  steSplitter->CreateOptions(m_shellOptions);
495  m_luaOutput = new wxLuaShell(steSplitter, ID_WXLUAIDE_OUTPUT_WIN,
496  wxDefaultPosition, wxDefaultSize, 0);
497  m_luaOutput->CreateOptions(m_shellOptions);
498  steSplitter->Initialize(m_luaOutput);
499  m_luaOutput->MarkerDeleteAll(wxLuaShell::PROMPT_MARKER);
500  m_luaOutput->SetwxLuaState(m_wxlState, true);
501  m_luaOutput->SetWrapMode(wxSTC_WRAP_NONE);
502 #if wxCHECK_VERSION(2,9,0)
503  m_luaOutput->SetFileName(wxFileName(wxT("Output")));
504 #else
505  m_luaOutput->SetFileName(wxT("Output"));
506 #endif
507 
508  m_msgNotebook->InsertEditorSplitter( -1, steSplitter, false );
509 
510  m_msgNotebook->InsertEditorSplitter(-1, steSplitter, false);
511 
512  m_splitter->SetSashGravity(0.8); // let upper window grow more
513  m_splitter->SetMinimumPaneSize(50);
514  m_splitter->SplitHorizontally(m_editorNotebook, m_msgNotebook, GetClientSize().y/2);
515 
516  return true;
517 }
518 
519 wxLuaIDE::~wxLuaIDE()
520 {
521  if (m_wxlState.Ok())
522  m_wxlState.CloseLuaState(true); // make sure all windows are destroyed
523 
524  m_wxlState.Destroy();
525 }
526 
527 void wxLuaIDE::OnSize(wxSizeEvent& event)
528 {
529  event.Skip();
530  if (!m_splitter) return;
531 
532  wxSize clientSize(GetClientSize());
533  int width = clientSize.x;
534  int height = clientSize.y;
535 
536  int h = 0;
537 
538  if (m_toolBar && (m_toolBar->GetParent() == this))
539  {
540  m_toolBar->SetSize(0, 1, width, -1); // y = 1 for wxGTK 2 at least
541  h = m_toolBar->GetSize().y + 1; // another +1 for bottom for wxGTK2
542  }
543 
544  if (m_splitter)
545  {
546  m_splitter->SetSize(0, h, width, height-h);
547  int sash = m_splitter->GetSashPosition();
548  if ((sash < 50) || (sash > height - 50))
549  m_splitter->SetSashPosition(wxMin(50, height/2));
550  }
551 }
552 
553 void wxLuaIDE::SetMenuBar(wxMenuBar *menuBar)
554 {
555  m_shellOptions.SetMenuBar(menuBar);
556  m_editorOptions.SetMenuBar(menuBar);
557 
558  if (menuBar && (menuBar->FindMenu(wxT("wxLua")) == wxNOT_FOUND))
559  {
560  wxMenu *wxluaMenu = CreatewxLuaMenu();
561  int pos = menuBar->FindMenu(wxT("Help"));
562  menuBar->Insert(pos, wxluaMenu, wxT("wx&Lua"));
563  }
564 
565  if (!m_wxlState.Ok() || !m_wxlState.IsRunning())
566  wxSTEditorMenuManager::DoEnableItem(NULL, GetMenuBar(), GetToolBar(), ID_WXLUAIDE_BREAK_LUA, false);
567 }
568 
569 void wxLuaIDE::SetToolBar(wxToolBar *toolBar)
570 {
571  m_shellOptions.SetToolBar(toolBar);
572  m_editorOptions.SetToolBar(toolBar);
573 
574  m_toolBar = toolBar;
575 
576  if (!m_wxlState.Ok() || !m_wxlState.IsRunning())
577  wxSTEditorMenuManager::DoEnableItem(NULL, GetMenuBar(), GetToolBar(), ID_WXLUAIDE_BREAK_LUA, false);
578 }
579 
580 void wxLuaIDE::PopulateToolBar(wxToolBar *toolBar, long options) const
581 {
582  bool add_sep = false;
583 
584  if ((options & WXLUAIDE_TB_FILE) != 0)
585  {
586  toolBar->AddTool( ID_WXLUAIDE_LOAD_LUA, wxT("Open file"), wxBitmap(open_xpm), wxT("Open lua program") );
587  toolBar->AddTool( ID_WXLUAIDE_SAVEAS_LUA, wxT("Save as..."), wxBitmap(save_xpm), wxT("Save lua program") );
588  add_sep = true;
589  }
590  if ((options & WXLUAIDE_TB_LUA) != 0)
591  {
592  if (add_sep) toolBar->AddSeparator();
593 
594  toolBar->AddTool( ID_WXLUAIDE_RUN_LUA, wxT("Run wxLua program"), wxBitmap(play_xpm), wxT("Run the wxLua program in the current editor") );
595  toolBar->AddTool( ID_WXLUAIDE_BREAK_LUA, wxT("Stop wxLua program"), wxBitmap(stop_xpm), wxT("Stop the running wxLua program") );
596  toolBar->AddSeparator();
597  toolBar->AddTool( ID_WXLUAIDE_SHOW_STACK, wxT("Show stack tree"), wxBitmap(LUA_xpm), wxT("Show the lua stack tree") );
598  }
599  toolBar->Realize();
600 }
601 
602 wxMenu* wxLuaIDE::CreatewxLuaMenu() const
603 {
604  wxSTEditorMenuManager s;
605  wxMenu *wxluaMenu = new wxMenu();
606  wxluaMenu->Append(s.MenuItem(wxluaMenu, ID_WXLUAIDE_RUN_LUA, wxT("&Run wxLua program\tCtrl+F5"), wxT("Run the wxLua program in the current editor") , wxITEM_NORMAL, wxBitmap(play_xpm)));
607  wxluaMenu->Append(s.MenuItem(wxluaMenu, ID_WXLUAIDE_BREAK_LUA, wxT("&Stop wxLua program\tShift+F5"), wxT("Stop the running wxLua program") , wxITEM_NORMAL, wxBitmap(stop_xpm)));
608  wxluaMenu->AppendSeparator();
609  wxluaMenu->Append(s.MenuItem(wxluaMenu, ID_WXLUAIDE_SHOW_STACK, wxT("Stack &tree"), wxT("Show the lua stack tree") , wxITEM_NORMAL, wxBitmap(LUA_xpm)));
610  wxluaMenu->AppendSeparator();
611  wxluaMenu->Append(ID_WXLUAIDE_TOGGLE_BREAKPOINT, wxT("Toggle &breakpoint\tF9"));
612  return wxluaMenu;
613 }
614 
615 void wxLuaIDE::SetwxLuaState(const wxLuaState& wxlState, bool is_static)
616 {
617  if (m_wxlState.Ok() && !m_wxlstate_static)
618  {
619  // try to close it nicely first
620  if (m_wxlState.IsRunning())
621  {
622  wxSafeYield();
623  m_wxlState.DebugHookBreak();
624  }
625 
626  m_wxlState.CloseLuaState(true); // force closing it since we own it
627  }
628 
629  m_wxlState = wxlState;
630  m_wxlstate_static = is_static;
631 }
632 
633 bool wxLuaIDE::RecreatewxLuaState(wxEvtHandler *wxlStateEvtHandler, int win_id)
634 {
635  // ask if anyone else wants to create a new wxLuaState for us
636  wxLuaEvent event(wxEVT_LUAIDE_wxLUA_CREATION, GetId(), wxNullLuaState);
637  event.SetEventObject(this);
638  event.SetInt(0);
639  event.SetExtraLong(win_id);
640 
641  // return if handled, but not skipped.
642  if (GetEventHandler()->ProcessEvent(event))
643  return false;
644 
645  // Did they set a valid interpreter for the event and is it new?
646  // If it's not different then assume they didn't change it so we'll create
647  // a new one below. If they wanted to just adjust the current state they
648  // should have called event.Skip(false)
649  if (event.GetwxLuaState().Ok())
650  {
651  SetwxLuaState(event.GetwxLuaState(), event.GetInt() == 1);
652  }
653  else
654  {
655  wxLuaState wxlState = wxLuaState(wxlStateEvtHandler, win_id);
656  wxlState.SetLuaDebugHook( LUA_MASKCOUNT, 1000, 50, false );
657  SetwxLuaState(wxlState, false);
658  }
659 
660  return m_wxlState.Ok();
661 }
662 
663 void wxLuaIDE::OnCreateEditor(wxCommandEvent &event)
664 {
665  wxWindow *win = (wxWindow*)event.GetEventObject();
666  wxLuaEditor *editor = new wxLuaEditor(win, event.GetInt(),
667  wxDefaultPosition, wxDefaultSize, 0);
668  editor->CreateOptions(m_editorOptions);
669  editor->SetwxLuaIDE(this);
670  event.SetEventObject(editor);
671 }
672 
673 void wxLuaIDE::OnMenu(wxCommandEvent &event)
674 {
675  //wxSTERecursionGuard guard(m_rGuard_OnMenu); can't have for BREAK
676  //if (guard.IsInside()) return;
677 
678  if (!HandleMenuEvent(event))
679  event.Skip();
680 }
681 
682 bool wxLuaIDE::HandleMenuEvent(wxCommandEvent& event)
683 {
684  //wxSTERecursionGuard guard(m_rGuard_HandleMenuEvent); can't have for BREAK
685  //if (guard.IsInside()) return false;
686 
687  wxLuaEditor *editor = wxDynamicCast(m_editorNotebook->GetEditor(), wxLuaEditor);
688  wxCHECK_MSG(editor, false, wxT("Invalid notebook page"));
689 
690  switch(event.GetId())
691  {
692  case ID_WXLUAIDE_LOAD_LUA :
693  {
694  wxFileName fn = editor->GetFileName();
695  wxString filename, path;
696 
697  if (fn.IsOk())
698  {
699  path = fn.GetPath();
700  filename = fn.GetFullName();
701  }
702 
703  wxFileDialog dlg(this, wxT("Open file"), path, filename,
704  wxT("Lua (*.lua)|*.lua|Any file (*)|*"),
705  wxFD_OPEN|wxFD_FILE_MUST_EXIST);
706  if (dlg.ShowModal() == wxID_OK)
707  {
708  filename = dlg.GetPath();
709 
710  if (!filename.IsEmpty())
711  editor->LoadFile(filename);
712  }
713 
714  return true;
715  }
716  case ID_WXLUAIDE_SAVEAS_LUA :
717  {
718  editor->SaveFile(true);
719  return true;
720  }
721  case ID_WXLUAIDE_RUN_LUA :
722  {
723  wxString program = editor->GetText();
724  if (program.IsEmpty()) return true;
725 
726  if (m_wxlState.Ok())
727  {
728  if (m_wxlState.Ok())
729  m_wxlState.CloseLuaState(true);
730 
731  m_wxlState.Destroy(); // FIXME
732  //wxCHECK_RET(m_wxlState.Destroy(), wxT("Can't destroy lua interpreter"));
733  }
734 
735  // Fresh start!
736  wxCHECK_MSG(RecreatewxLuaState(GetEventHandler(), editor->GetId()), true, wxT("Can't recreate lua interpreter"));
737 
738  wxSTEditorMenuManager::DoEnableItem(NULL, GetMenuBar(), GetToolBar(), ID_WXLUAIDE_RUN_LUA, false);
739  wxSTEditorMenuManager::DoEnableItem(NULL, GetMenuBar(), GetToolBar(), ID_WXLUAIDE_BREAK_LUA, true);
740  wxSTEditorMenuManager::DoEnableItem(NULL, GetMenuBar(), GetToolBar(), ID_WXLUAIDE_SHOW_STACK, false);
741 
742  editor->MarkerDeleteAll(wxLuaEditor::markerError);
743  wxString name = m_editorNotebook->GetPageText(m_editorNotebook->GetSelection());
744 
745  m_luaOutput->SetReadOnly(false);
746  m_luaOutput->ClearAll();
747  m_luaOutput->MarkerDeleteAll(wxLuaShell::PROMPT_MARKER);
748  WriteMessage(m_luaOutput, wxT("Running lua script '") + name + wxT("' : ") + wxNow() + wxT("\n"));
749  wxStopWatch stopWatch;
750  //m_luaOutput->SetReadOnly(true);
751 
752  wxSafeYield(); // allow tools to adjust (sometimes necessary?)
753 
754 #if wxCHECK_VERSION(2,9,0)
755  if (editor->GetFileName().IsOk())
756 #else
757  if (editor->GetFileName().IsEmpty())
758 #endif
759  {
760  wxFileName fn(editor->GetFileName());
761  if (fn.FileExists())
762  {
763  // ensure we have path of script added
764  // to LUA_PATH in case script calls require() with
765  // modules in same path as script
766  m_wxlState.AddLuaPath(fn);
767  }
768  }
769 
770  m_luaOutput->SetwxLuaState(m_wxlState, true);
771 
772  if (editor->HasBreakpoint(-1))
773  m_wxlState.SetLuaDebugHook(LUA_MASKCALL|LUA_MASKRET|LUA_MASKLINE|LUA_MASKCOUNT, 1, 50, true);
774  else
775  m_wxlState.SetLuaDebugHook(LUA_MASKCALL|LUA_MASKRET|LUA_MASKLINE|LUA_MASKCOUNT, 1000, 100, false);
776 
777  m_luaOutput->SetReadOnly(true);
778  editor->SetReadOnly(true);
779  m_wxlState.RunString(program, name);
780  editor->SetReadOnly(false);
781  m_luaOutput->SetReadOnly(false);
782 
783  WriteMessage(m_luaOutput, wxT("End lua script : ") + wxNow() + wxT("\n"));
784  WriteMessage(m_luaOutput, wxString::Format(wxT("Execution time : %.3lf(s)\n"), stopWatch.Time()/1000.0));
785 
786  m_luaOutput->CheckPrompt(true);
787 
788  wxSTEditorMenuManager::DoEnableItem(NULL, GetMenuBar(), GetToolBar(), ID_WXLUAIDE_RUN_LUA, true);
789  wxSTEditorMenuManager::DoEnableItem(NULL, GetMenuBar(), GetToolBar(), ID_WXLUAIDE_BREAK_LUA, false);
790  wxSTEditorMenuManager::DoEnableItem(NULL, GetMenuBar(), GetToolBar(), ID_WXLUAIDE_SHOW_STACK, true);
791 
792  return true;
793  }
794  case ID_WXLUAIDE_BREAK_LUA :
795  {
796  if (m_wxlState.Ok() && m_wxlState.IsRunning())
797  {
798  m_wxlState.DebugHookBreak(wxT("Interpreter stopped"));
799  }
800  else if (m_luaShell && m_luaShell->GetwxLuaState().Ok() && m_luaShell->GetwxLuaState().IsRunning())
801  {
802  m_luaShell->GetwxLuaState().DebugHookBreak(wxT("Interpreter stopped"));
803  }
804 
805  return true;
806  }
807  case ID_WXLUAIDE_SHOW_STACK :
808  {
809  m_show_stack = true;
810  // don't want recursive wxYields if some other interpreter is running
811  bool err = true;
812 
813  wxLuaState wxlState;
814  wxLuaShell *luaShell = NULL;
815 
816  if (m_msgNotebook->GetSelection() == 0)
817  {
818  wxlState = m_luaShell ? m_luaShell->GetwxLuaState() : wxNullLuaState;
819  luaShell = m_luaShell;
820  }
821  else
822  {
823  wxlState = m_wxlState;
824  luaShell = m_luaOutput;
825  }
826 
827  if (luaShell && wxlState.Ok())
828  {
829  int hook_count = wxlState.GetLuaDebugHookCount();
830  int hook_yield = wxlState.GetLuaDebugHookYield();
831  bool hook_send = wxlState.GetLuaDebugHookSendEvt();
832  int hook_mask = wxlState.GetLuaDebugHook();
833 
834  wxlState.SetLuaDebugHook(LUA_MASKCALL|LUA_MASKRET|LUA_MASKLINE|LUA_MASKCOUNT, 1, -1, true);
835  wxlState.RunString(wxT("print(\"Showing stack\")"));
836  wxlState.SetLuaDebugHook(hook_mask, hook_count, hook_yield, hook_send);
837  luaShell->CheckPrompt(true);
838  err = false;
839  }
840 
841  if (err)
842  wxMessageBox(wxT("Invalid lua interpreter."), wxT("Error showing stack"), wxOK, this);
843 
844  return true;
845 
846  }
847  default : break;
848  }
849 
850  return editor->HandleMenuEvent(event);
851 }
852 
853 void wxLuaIDE::OnLua(wxLuaEvent &event)
854 {
855  wxLuaShell *outEditor = NULL;
856 
857  if (event.GetwxLuaState() == m_luaShell->GetwxLuaState())
858  outEditor = m_luaShell;
859  else //if (event.GetwxLuaState() == m_wxlState) FIXME coroutines have own wxlStateRefData
860  outEditor = m_luaOutput;
861 
862  OutputLuaEvent(event, outEditor);
863 }
864 
865 void wxLuaIDE::OutputLuaEvent(wxLuaEvent &event, wxLuaShell *outEditor)
866 {
867  // perhaps there was an error at startup, but editor isn't created yet
868  if (outEditor == NULL)
869  return;
870 
871  if (event.GetEventType() == wxEVT_LUA_DEBUG_HOOK)
872  {
873  if (m_show_stack)
874  {
875  wxLuaStackDialog StackDialog(event.GetwxLuaState(), this);
876  StackDialog.ShowModal();
877  m_show_stack = false;
878  }
879  else if (event.GetwxLuaState() == m_wxlState)
880  {
881  wxLuaEditor *editor = wxDynamicCast(m_editorNotebook->FindWindow(event.GetId()), wxLuaEditor);
882  //wxCHECK_RET(editor, wxT("Invalid notebook page"));
883  if (editor != NULL)
884  {
885  int line = event.GetLineNum();
886  // The line is -1 within the require("wx") function
887  if ((line >= 0) && editor->HasBreakpoint(line-1))
888  m_wxlState.DebugHookBreak(wxString::Format(wxT("Stopped at breakpoint, line: %d"), line));
889  }
890  }
891  }
892  else if (event.GetEventType() == wxEVT_LUA_PRINT)
893  {
894  WriteMessage(outEditor, event.GetString() + wxT("\n"));
895  }
896  else if (event.GetEventType() == wxEVT_LUA_ERROR)
897  {
898  WriteMessage(outEditor, wxT("\nError: ") + event.GetString() + wxT("\n"));
899 
900  int line = event.GetLineNum();
901 
902  // the user generated an error from running something in the shell
903  if (event.GetString().Find(wxT("[string \"wxLuaShell\"]")) != wxNOT_FOUND)
904  line = -1;
905 
906  // Put a marker where the error occurred
907  if ((line >= 0) && (event.GetwxLuaState() == m_wxlState))
908  {
909  wxLuaEditor *editor = wxDynamicCast(m_editorNotebook->FindWindow(event.GetId()), wxLuaEditor);
910  //wxCHECK_RET(editor, wxT("Invalid notebook page"));
911  if (editor != NULL)
912  {
913  editor->MarkerDeleteAll(wxLuaEditor::markerError);
914  editor->MarkerAdd(line-1, wxLuaEditor::markerError);
915  editor->GotoLine(line-1);
916  editor->EnsureCaretVisible();
917  }
918  }
919  }
920 }
921 
922 void wxLuaIDE::WriteMessage(wxLuaShell *outputWin, const wxString& str)
923 {
924  wxCHECK_RET(outputWin, wxT("Invalid wxLuaShell to write message to."));
925 
926  // try to turn the message notebook page to show the message
927  if (m_msgNotebook)
928  {
929  int sel = m_msgNotebook->GetSelection();
930  if ((outputWin->GetId() == ID_WXLUAIDE_SHELL) && (sel != 0))
931  m_msgNotebook->SetSelection(0);
932  if ((outputWin->GetId() == ID_WXLUAIDE_OUTPUT_WIN) && (sel != 1))
933  m_msgNotebook->SetSelection(1);
934  }
935 
936 /*
937  if (m_msgNotebook)
938  {
939  // the parent of the wxLuaShell is probably a splitter
940  wxWindow* win = outputWin;
941  while (win->GetParent() && (win->GetParent() != m_msgNotebook))
942  win = win->GetParent();
943 
944  int sel = m_msgNotebook->GetSelection();
945  if (win && ((sel < 0) || (m_msgNotebook->GetPage(sel) != win)))
946  {
947  int n, count = m_msgNotebook->GetPageCount();
948 
949  for (n = 0; n < count; n++)
950  {
951  if ((n != sel) && (m_msgNotebook->GetPage(n) == win))
952  {
953  m_msgNotebook->SetSelection(n);
954  break;
955  }
956  }
957  }
958  }
959 */
960 
961  outputWin->AppendText(str);
962 }
#define wxDynamicCast(obj, className)
Define wxDynamicCast so that it will give a compiler error for unrelated types.
Definition: gen.h:75
wxledit.cpp Source File -- Sun Oct 12 2014 17:04:26 -- Sun Oct 12 2014 -- 1.8.5 -- wxArt2D -- . -- Main Page Reference Documentation