OSDN Git Service

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