OSDN Git Service

The (experimental) command line version does not compile; empty MainView_resizeToFit...
[molby/Molby.git] / wxSources / ConsoleFrame.cpp
1 /*
2  *  ConsoleFrame.cpp
3  *  Molby
4  *
5  *  Created by Toshi Nagata on 08/10/27.
6  *  Copyright 2008 Toshi Nagata. All rights reserved.
7  *
8  This program is free software; you can redistribute it and/or modify
9  it under the terms of the GNU General Public License as published by
10  the Free Software Foundation version 2 of the License.
11  
12  This program is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  GNU General Public License for more details.
16  */
17
18 #include "ConsoleFrame.h"
19
20 #include "wx/menu.h"
21 #include "wx/regex.h"
22 #include "wx/colour.h"
23
24 #include "MyApp.h"
25 #include "../MolLib/Ruby_bind/Molby_extern.h"
26
27 BEGIN_EVENT_TABLE(ConsoleFrame, wxMDIChildFrame)
28         EVT_UPDATE_UI(wxID_CLOSE, ConsoleFrame::OnUpdateUI)
29         EVT_CLOSE(ConsoleFrame::OnCloseWindow)
30         EVT_MENU(wxID_CLOSE, ConsoleFrame::OnClose)
31         EVT_MENU(wxID_CUT, ConsoleFrame::OnCut)
32         EVT_MENU(wxID_COPY, ConsoleFrame::OnCopy)
33         EVT_MENU(wxID_PASTE, ConsoleFrame::OnPaste)
34         EVT_MENU(wxID_CLEAR, ConsoleFrame::OnClear)
35 END_EVENT_TABLE()
36
37 ConsoleFrame::ConsoleFrame(wxMDIParentFrame *parent, const wxString& title, const wxPoint& pos, const wxSize& size, long type):
38         wxMDIChildFrame(parent, wxID_ANY, title, pos, size, type)
39 {
40 }
41
42 ConsoleFrame::~ConsoleFrame()
43 {
44         wxGetApp().DocManager()->FileHistoryRemoveMenu(file_history_menu);
45 }
46
47 void
48 ConsoleFrame::OnCreate()
49 {
50         //  Make a text view
51 #warning "TODO: Set the sizer for the text control properly"
52         int width, height;
53         GetClientSize(&width, &height);
54         textCtrl = new wxTextCtrl(this, wxID_ANY, _T(""), wxPoint(0, 0), wxSize(width, height), wxTE_MULTILINE | wxTE_RICH);
55         
56         //  Connect "OnKeyDown" event handler
57         textCtrl->Connect(-1, wxEVT_KEY_DOWN, wxKeyEventHandler(ConsoleFrame::OnKeyDown), NULL, this);
58         
59         wxMenuBar *menu_bar = wxGetApp().CreateMenuBar(2, &file_history_menu, &edit_menu);
60         
61         //// Associate the menu bar with the frame
62         SetMenuBar(menu_bar);
63 }
64
65 ConsoleFrame *
66 ConsoleFrame::CreateConsoleFrame(wxMDIParentFrame *parent)
67 {
68 #ifdef __WXMSW__
69         wxPoint origin(0, 0);
70         wxSize size(640, 200);
71 #else
72         wxPoint origin(10, 24);
73         wxSize size(640, 200);
74 #endif
75         ConsoleFrame *frame = new ConsoleFrame(parent, _T("Console"), origin, size, wxDEFAULT_FRAME_STYLE | wxNO_FULL_REPAINT_ON_RESIZE);
76         
77         frame->OnCreate();
78         return frame;
79 }
80
81 bool
82 GetLineIncludingPosition(wxTextCtrl *ctrl, int pos, int *start, int *end)
83 {
84         int pos1, pos2, posend;
85         wxChar posChar;
86         
87         if (ctrl == NULL)
88                 return false;
89         if (pos == 0)
90                 pos1 = 0;
91         else {
92                 pos1 = pos;
93                 while (pos1 > 0) {
94                         posChar = ctrl->GetRange(pos1 - 1, pos1).GetChar(0);
95                         if (posChar == '\n')
96                                 break;
97                         pos1--;
98                 }
99         }
100         posend = ctrl->GetLastPosition();
101         posChar = ctrl->GetRange(posend - 1, posend).GetChar(0);
102         if (pos >= posend)
103                 pos2 = pos;
104         else {
105                 pos2 = pos;
106                 while (pos2 < posend) {
107                         posChar = ctrl->GetRange(pos2, pos2 + 1).GetChar(0);
108                         if (posChar == '\n') {
109                                 pos2++;
110                                 break;
111                         }
112                         pos2++;
113                 }
114         }
115         if (start != NULL)
116                 *start = pos1;
117         if (end != NULL)
118                 *end = pos2;
119         return true;
120 }
121
122 void
123 ConsoleFrame::OnCloseWindow(wxCloseEvent &event)
124 {
125         //  Do not delete this window; it may be reopened later
126         this->Hide();
127 }
128
129 void
130 ConsoleFrame::OnClose(wxCommandEvent &event)
131 {
132         this->Close();
133 }
134
135 void
136 ConsoleFrame::OnCut(wxCommandEvent &event)
137 {
138         textCtrl->Cut();
139 }
140
141 void
142 ConsoleFrame::OnCopy(wxCommandEvent &event)
143 {
144         textCtrl->Copy();
145 }
146
147 void
148 ConsoleFrame::OnPaste(wxCommandEvent &event)
149 {
150         textCtrl->Paste();
151 }
152
153 void
154 ConsoleFrame::OnClear(wxCommandEvent &event)
155 {
156         textCtrl->Clear();
157 }
158
159 void
160 ConsoleFrame::OnUpdateUI(wxUpdateUIEvent& event)
161 {
162         //  Why this is not automatically done??
163         int uid = event.GetId();
164         if (uid == wxID_CLOSE)
165                 event.Enable(true);
166 }
167
168 void
169 ConsoleFrame::OnEnterPressed(wxKeyEvent& event)
170 {
171         if (::wxGetKeyState(WXK_ALT)) {
172                 textCtrl->WriteText(wxT("\n> "));
173                 return;
174         }
175         
176         int start, pos, end, veryend, lastpos;
177         wxChar startChar;
178
179         //  Get the block of script to be executed
180         pos = textCtrl->GetInsertionPoint();
181         lastpos = textCtrl->GetLastPosition();
182         veryend = -1;
183         while (pos >= 0) {
184                 if (!GetLineIncludingPosition(textCtrl, pos, &start, &end) || start == end) {
185                         start = end = veryend = pos;
186                         break;
187                 }
188                 if (veryend < 0)
189                         veryend = end;
190                 startChar = textCtrl->GetRange(start, start + 1).GetChar(0);
191                 if (startChar == '%') {
192                         start++;
193                         break;
194                 } else if (startChar == '>') {
195                         pos = start - 1;
196                         continue;
197                 } else {
198                         start = end = veryend = pos;
199                         break;
200                 }
201         }
202         while (start < end && veryend < lastpos) {
203                 pos = veryend + 1;
204                 if (!GetLineIncludingPosition(textCtrl, pos, &pos, &end) || pos == end) {
205                         break;
206                 }
207                 startChar = textCtrl->GetRange(pos, pos + 1).GetChar(0);
208                 if (startChar != '>')
209                         break;
210                 veryend = end;
211         }
212
213         wxString string = textCtrl->GetRange(start, veryend);
214         int len = string.Len();
215         
216         //  Is there any non-whitespace characters?
217         wxChar ch;
218         int i;
219         for (i = 0; i < len; i++) {
220                 ch = string[i];
221                 if (ch != ' ' && ch != '\t' && ch != '\n' && ch != 'r')
222                         break;
223         }
224         if (i < len) {
225                 //  Input is not empty
226                 if (veryend < lastpos) {
227                         // Enter is pressed in the block not at the end
228                         // -> Insert the text at the end
229                         wxRegEx re1(wxT("[ \t\n]*$"));
230                         re1.ReplaceFirst(&string, wxT(""));
231                         wxRegEx re2(wxT("^[ \t\n]*"));
232                         re2.ReplaceFirst(&string, wxT(""));
233                         if (textCtrl->GetRange(lastpos - 1, lastpos).GetChar(0) != '\n')
234                                 textCtrl->AppendText(wxT("\n"));
235                         MyAppCallback_showRubyPrompt();
236                         MyAppCallback_setConsoleColor(3);
237                         textCtrl->AppendText(string);
238                 } else {
239                         wxTextAttr scriptAttr(*wxBLUE);
240                         textCtrl->SetStyle(start, veryend, scriptAttr);
241                 }
242                 string.Append(wxT("\n"));  //  To avoid choking Ruby interpreter
243                 wxRegEx re3(wxT("\n>"));
244                 re3.Replace(&string, wxT("\n"));
245                 if (textCtrl->GetRange(lastpos - 1, lastpos).GetChar(0) != '\n')
246                         textCtrl->AppendText(wxT("\n"));
247                 MyAppCallback_setConsoleColor(0);
248                 textCtrl->Update();
249                 
250                 //  Invoke ruby interpreter
251                 int status;
252                 RubyValue val;
253                 Molecule *mol = MoleculeCallback_currentMolecule();
254                 MoleculeLock(mol);
255                 val = Molby_evalRubyScriptOnMolecule(string.mb_str(wxConvUTF8), MoleculeCallback_currentMolecule(), &status);
256                 MoleculeUnlock(mol);
257                 if (status != -1) {  /*  Status -1 is already handled  */
258                         MyAppCallback_setConsoleColor(1);
259                         if (status != 0) {
260                                 Molby_showError(status);
261                         } else {
262                                 textCtrl->AppendText(wxT("-->"));
263                                 Molby_showRubyValue(val);
264                         }
265                         MyAppCallback_setConsoleColor(0);
266                         textCtrl->AppendText(wxT("\n"));
267                         MyAppCallback_showRubyPrompt();
268                 }
269         } else {
270                 textCtrl->AppendText(wxT("\n"));
271                 MyAppCallback_showRubyPrompt();
272         }
273 }
274
275 void
276 ConsoleFrame::OnKeyDown(wxKeyEvent &event)
277 {
278         int code = event.GetKeyCode();
279         //      printf("OnChar: %d\n", code);
280         if (code == WXK_RETURN || code == WXK_NUMPAD_ENTER)
281                 OnEnterPressed(event);
282         else
283                 event.Skip();
284 }