1
///////////////////////////////////////////////////////////////////////////////
3
// Purpose: wxSTEditorShell
4
// Author: John Labenski
8
// Copyright: (c) John Labenski
9
// Licence: wxWidgets licence
10
///////////////////////////////////////////////////////////////////////////////
14
#include "wx/stedit/stedit.h"
15
#include "wx/stedit/steshell.h"
17
//-----------------------------------------------------------------------------
19
//-----------------------------------------------------------------------------
20
IMPLEMENT_DYNAMIC_CLASS(wxSTEditorShell, wxSTEditor)
22
BEGIN_EVENT_TABLE(wxSTEditorShell, wxSTEditor)
23
EVT_KEY_DOWN ( wxSTEditorShell::OnKeyDown)
24
EVT_STC_UPDATEUI (wxID_ANY, wxSTEditorShell::OnSTCUpdateUI)
27
void wxSTEditorShell::Init()
29
m_line_history_index = 0;
30
m_max_history_lines = 100;
32
m_max_lines = 10000; // arbitrary, seems reasonable
33
m_overflow_lines = 2000;
35
m_writeable_count = 0;
38
bool wxSTEditorShell::Create(wxWindow *parent, wxWindowID id,
39
const wxPoint& pos, const wxSize& size,
40
long style, const wxString& name)
42
if (!wxSTEditor::Create(parent, id, pos, size, style, name))
45
// set this up in case they don't want to bother with the preferences
46
SetMarginWidth(STE_MARGIN_NUMBER, 0);
47
SetMarginWidth(STE_MARGIN_FOLD, 0);
48
SetMarginWidth(PROMPT_MARGIN, 16);
50
SetMarginType(PROMPT_MARGIN, wxSTC_MARGIN_SYMBOL);
51
SetMarginMask(PROMPT_MARGIN, 1<<PROMPT_MARKER);
52
// after creation you can change this to whatever prompt you prefer
53
MarkerDefine(PROMPT_MARKER, wxSTC_MARK_ARROWS, *wxBLACK, wxColour(255,255,0));
57
wxSTEditorShell::~wxSTEditorShell()
61
void wxSTEditorShell::AppendText(const wxString &text)
63
BeginWriteable(); // make it writeable
65
wxSTEditor::AppendText(text); // write the text
66
SetMaxLines(m_max_lines, m_overflow_lines); // check for line count overflow
67
GotoPos(GetLength()); // put cursor at end
68
EmptyUndoBuffer(); // don't let them undo what you wrote!
69
// but they can undo their own typing
71
EndWriteable(); // end the writeable state
74
void wxSTEditorShell::SetPromptText(const wxString& text)
77
int length = GetLength();
78
int prompt_line = GetPromptLine();
79
int start_pos = PositionFromLine(prompt_line);
80
SetTargetStart(start_pos);
87
wxString wxSTEditorShell::GetPromptText()
89
int prompt_line = GetPromptLine();
90
int start_pos = PositionFromLine(prompt_line);
91
int end_pos = GetLength();
92
wxString text(GetTextRange(start_pos, end_pos));
96
void wxSTEditorShell::BeginWriteable(bool make_writeable)
99
if (make_writeable && GetReadOnly())
102
void wxSTEditorShell::EndWriteable(bool check_ro)
104
if (m_writeable_count > 0)
107
if (check_ro && (m_writeable_count == 0))
111
int wxSTEditorShell::GetPromptLine()
113
int total_lines = GetLineCount();
114
return MarkerPrevious(total_lines+1, (1<<PROMPT_MARKER));
116
// single line entry, return text on last line FIXME - double check this
117
// Scintilla doesn't complain if you enter a line greater than the length to get last prompt
118
//int marker = MarkerGet(total_lines);
119
//if (((marker & (1<<PROMPT_MARKER)) != 0)
121
// text = GetLineText(total_lines); //.Strip(wxString::both);
125
// int marker_line = MarkerPrevious(total_lines+1, (1<<PROMPT_MARKER));
129
bool wxSTEditorShell::CaretOnPromptLine(STE_CaretPos_Type option)
131
int prompt_line = GetPromptLine();
132
bool on_last = (GetCurrentLine() >= prompt_line);
134
//wxPrintf(wxT("Caret on last line total %d current %d onlast %d\n"), total_lines, GetCurrentLine(), (int)on_last);
136
if (!on_last && (option != STE_CARET_MOVE_NONE))
138
if ((option & STE_CARET_MOVE_LASTLINE) != 0)
139
GotoLine(prompt_line);
140
else if ((option & STE_CARET_MOVE_ENDTEXT) != 0)
141
GotoPos(GetLength());
144
return GetCurrentLine() >= prompt_line;
147
bool wxSTEditorShell::CheckReadOnly(bool set)
149
bool make_ro = !CaretOnPromptLine(STE_CARET_MOVE_NONE);
153
// also check selection and make ro so they can't cut text not on last line
154
int prompt_line = GetPromptLine();
155
make_ro |= ((LineFromPosition(GetSelectionStart()) < prompt_line) ||
156
(LineFromPosition(GetSelectionEnd()) < prompt_line));
159
if (set && (make_ro != GetReadOnly()))
160
SetReadOnly(make_ro);
165
bool wxSTEditorShell::CheckPrompt(bool set)
167
int total_lines = GetLineCount();
168
total_lines = wxMax(0, total_lines-1);
169
bool has_prompt = (MarkerGet(total_lines) & (1<<PROMPT_MARKER)) != 0;
171
if (set && !has_prompt)
173
MarkerAdd(total_lines, PROMPT_MARKER);
180
void wxSTEditorShell::OnSTCUpdateUI(wxStyledTextEvent &event)
183
if (m_writeable_count == 0)
187
wxString wxSTEditorShell::GetNextHistoryLine(bool forwards, const wxString &line)
189
int count = (int)m_lineHistoryArray.GetCount();
191
// no history, just return ""
193
return wxEmptyString;
195
// return current one if it's different
196
if ((m_line_history_index >= 0) && (m_line_history_index < count) &&
197
(line != m_lineHistoryArray[m_line_history_index]))
198
return m_lineHistoryArray[m_line_history_index];
202
if (m_line_history_index >= count - 1)
204
m_line_history_index = (int)(count - 1); // fix it up
205
return wxEmptyString;
208
m_line_history_index++;
212
if (m_line_history_index < 1) // already checked for empty array
214
m_line_history_index = 0; // fix it up
215
return wxEmptyString;
218
m_line_history_index--;
221
return m_lineHistoryArray[m_line_history_index];
224
void wxSTEditorShell::AddHistoryLine(const wxString& string, bool set_index_to_last)
226
size_t count = m_lineHistoryArray.GetCount();
228
// don't add same line twice
229
if ((count > 0) && (string == m_lineHistoryArray[count-1]))
232
m_lineHistoryArray.Add(string);
233
if (set_index_to_last)
234
m_line_history_index = (int)(m_lineHistoryArray.GetCount() - 1);
236
SetMaxHistoryLines(GetMaxHistoryLines()); // remove any extra
239
void wxSTEditorShell::SetMaxHistoryLines(int max_lines)
241
m_max_history_lines = max_lines;
243
int extra = int(m_lineHistoryArray.GetCount()) - m_max_history_lines;
244
if ((m_max_history_lines >= 0) && (extra > 0))
245
m_lineHistoryArray.RemoveAt(0, extra);
247
m_line_history_index = wxMin(m_line_history_index, int(m_lineHistoryArray.GetCount())-1);
250
bool wxSTEditorShell::SetMaxLines(int max_lines, int overflow_lines)
252
m_max_lines = max_lines;
253
m_overflow_lines = overflow_lines;
254
if (m_max_lines < 0) return false;
256
int total_lines = GetLineCount();
257
total_lines = wxMax(0, total_lines-1);
259
// delete lines when more than m_max_lines, you'll eventually crash otherwise
260
if (total_lines > m_max_lines + m_overflow_lines)
264
int marker = MarkerGet(total_lines - m_max_lines);
267
SetTargetEnd(PositionFromLine(total_lines - m_max_lines));
268
ReplaceTarget(wxEmptyString);
270
// wipe marker that has moved up if there shouldn't be a marker
271
if ((marker & (1<<PROMPT_MARKER)) == 0)
272
MarkerDelete(0, PROMPT_MARKER);
281
void wxSTEditorShell::OnKeyDown(wxKeyEvent &event)
283
// don't steal any keys from the autocomplete dropdown
284
if (AutoCompActive())
293
switch (event.GetKeyCode())
295
case WXK_UP : case WXK_NUMPAD_UP :
297
// you can scroll up through multiline entry
298
int current_line = GetCurrentLine();
299
int prompt_line = GetPromptLine();
300
if ((current_line < prompt_line) || (current_line > prompt_line))
303
// up/down arrows go through the history buffer
304
wxString promptText = GetPromptText();
305
SetPromptText(GetNextHistoryLine(false, promptText));
308
case WXK_DOWN : case WXK_NUMPAD_DOWN :
310
// you can scroll down through multiline entry
311
int total_lines = GetLineCount();
312
total_lines = wxMax(0, total_lines - 1);
313
int current_line = GetCurrentLine();
314
if (current_line < total_lines)
317
// up/down arrows go through the history buffer
318
wxString promptText = GetPromptText();
319
SetPromptText(GetNextHistoryLine(true, promptText));
322
case WXK_LEFT : case WXK_NUMPAD_LEFT :
324
int current_line = GetCurrentLine();
325
int prompt_line = GetPromptLine();
326
if (current_line >= prompt_line)
329
GetCurLine(&caret_pos);
336
case WXK_PAGEUP : case WXK_NUMPAD_PAGEUP :
337
case WXK_PAGEDOWN : case WXK_NUMPAD_PAGEDOWN :
338
case WXK_END : case WXK_NUMPAD_END :
339
case WXK_HOME : case WXK_NUMPAD_HOME :
340
case WXK_RIGHT : case WXK_NUMPAD_RIGHT :
346
// default processing for these keys
351
case WXK_RETURN : case WXK_NUMPAD_ENTER :
353
// put cursor at end if not already on the last line
354
if (!CaretOnPromptLine(STE_CARET_MOVE_NONE))
356
GotoPos(GetLength());
360
int current_line = GetCurrentLine();
361
int prompt_line = GetPromptLine();
363
// allow multiline entry for shift+enter
364
if ((current_line >= prompt_line) && event.ShiftDown())
370
wxString promptText = GetPromptText();
372
// goto the end of the line and store the line for the history
374
if (promptText.Length())
375
AddHistoryLine(promptText, true);
377
// just send the event, the receiver can do what they like
378
SendEvent(wxEVT_STESHELL_ENTER, 0, GetState(), promptText);
383
// go to the end of the last line if not on last line
384
if (!CaretOnPromptLine(STE_CARET_MOVE_NONE))
386
GotoPos(GetLength());
389
// don't let them backspace into previous line
391
GetCurLine(&caret_pos);
397
default : // move cursor to end if not already there
399
// reset history to start at most recent again
400
m_line_history_index = (int)(m_lineHistoryArray.GetCount() - 1);
402
CaretOnPromptLine(STE_CARET_MOVE_ENDTEXT);