//+------------------------------------------------------------------+ //| TextBox.mqh | //| Copyright 2016, MetaQuotes Software Corp. | //| http://www.mql5.com | //+------------------------------------------------------------------+ #include "Scrolls.mqh" #include "..\Keys.mqh" #include "..\Element.mqh" #include "..\TimeCounter.mqh" #include //+------------------------------------------------------------------+ //| Класс для создания многострочного текстового поля | //+------------------------------------------------------------------+ class CTextBox : public CElement { private: //--- Экземпляр класса для работы с клавиатурой CKeys m_keys; //--- Объект для работы со счётчиком таймера CTimeCounter m_counter; //--- Объекты для создания элемента CRectCanvas m_textbox; CScrollV m_scrollv; CScrollH m_scrollh; //--- Символы и их свойства struct StringOptions { string m_symbol[]; // Символы int m_width[]; // Ширина символов bool m_end_of_line; // Признак окончания строки }; StringOptions m_lines[]; //--- Общий размер и размер видимой части элемента int m_area_x_size; int m_area_y_size; int m_area_visible_x_size; int m_area_visible_y_size; //--- Цвет фона и символов выделенного текста color m_selected_back_color; color m_selected_text_color; //--- Начальные и конечные индексы строк и символов (выделенного текста) int m_selected_line_from; int m_selected_line_to; int m_selected_symbol_from; int m_selected_symbol_to; //--- Цвет текста по умолчанию color m_default_text_color; //--- Текст по умолчанию string m_default_text; //--- Переменная для работы со строкой string m_temp_input_string; //--- Отступы для текста от краёв поля ввода int m_text_x_offset; int m_text_y_offset; //--- Текущие координаты текстового курсора int m_text_cursor_x; int m_text_cursor_y; //--- Текущая позиция текстового курсора uint m_text_cursor_x_pos; uint m_text_cursor_y_pos; //--- Для расчёта границ видимой части поля ввода int m_x_limit; int m_y_limit; int m_x2_limit; int m_y2_limit; //--- Размер шага для смещения по горизонтали int m_shift_x_step; //--- Ограничения на смещение int m_shift_x2_limit; int m_shift_y2_limit; //--- Многострочный режим bool m_multi_line_mode; //--- Режим "Перенос по словам" bool m_word_wrap_mode; //--- Режим "Только для чтения" bool m_read_only_mode; //--- Режим авто выделения текста bool m_auto_selection_mode; //--- Состояние поля ввода bool m_text_edit_state; //--- Счётчик таймера для перемотки списка int m_timer_counter; //--- public: CTextBox(void); ~CTextBox(void); //--- Методы для создания элемента bool CreateTextBox(const int x_gap,const int y_gap); //--- private: void InitializeProperties(const int x_gap,const int y_gap); bool CreateCanvas(void); bool CreateTextBox(void); bool CreateScrollV(void); bool CreateScrollH(void); //--- public: //--- Возвращает указатели на полосы прокрутки CScrollV *GetScrollVPointer(void) { return(::GetPointer(m_scrollv)); } CScrollH *GetScrollHPointer(void) { return(::GetPointer(m_scrollh)); } //--- Цвет фона и символов выделенного текста void SelectedBackColor(const color clr) { m_selected_back_color=clr; } void SelectedTextColor(const color clr) { m_selected_text_color=clr; } //--- (1) Текст по умолчанию и (2) цвет текста по умолчанию void DefaultText(const string text) { m_default_text=text; } void DefaultTextColor(const color clr) { m_default_text_color=clr; } //--- (1) Многострочный режим, (2) режим "Перенос по словам" void MultiLineMode(const bool mode) { m_multi_line_mode=mode; } bool MultiLineMode(void) const { return(m_multi_line_mode); } void WordWrapMode(const bool mode) { m_word_wrap_mode=mode; } //--- (1) Режим "Только для чтения", (2) состояние поля ввода, (3) режим для автоматического выделения текста bool ReadOnlyMode(void) const { return(m_read_only_mode); } void ReadOnlyMode(const bool mode) { m_read_only_mode=mode; } bool TextEditState(void) const { return(m_text_edit_state); } void AutoSelectionMode(const bool state) { m_auto_selection_mode=state; } //--- (1) Отступы для текста от краёв поля ввода, (2) режим выравнивания текста void TextXOffset(const int x_offset) { m_text_x_offset=x_offset; } void TextYOffset(const int y_offset) { m_text_y_offset=y_offset; } //--- Возвращает индекс (1) строки, (2) символа, на котором находится текстовый курсор, // (3) количество строк, (4) количество видимых строк uint TextCursorLine(void) { return(m_text_cursor_y_pos); } uint TextCursorColumn(void) { return(m_text_cursor_x_pos); } uint LinesTotal(void) { return(::ArraySize(m_lines)); } uint VisibleLinesTotal(void); //--- Количество символов в указанной строке uint ColumnsTotal(const uint line_index); //--- Информация текстового курсора (строка/количество строк, столбец/количество столбцов) string TextCursorInfo(void); //--- Добавляет строку void AddLine(const string added_text=""); //--- Добавляет текст в указанную строку void AddText(const uint line_index,const string added_text); //--- Возвращает текст из указанной строки string GetValue(const uint line_index=0); //--- Очищает текстовое поле ввода void ClearTextBox(void); //--- Прокрутка таблицы: (1) вертикальная и (2) горизонтальная void VerticalScrolling(const int pos=WRONG_VALUE); void HorizontalScrolling(const int pos=WRONG_VALUE); //--- Смещение данных относительно позиций полос прокрутки void ShiftData(void); //--- Корректировка размеров поля ввода void CorrectSize(void); //--- Активация поля ввода void ActivateTextBox(void); //--- Дезактивирует поле ввода void DeactivateTextBox(void); //--- Изменение размеров void ChangeSize(const uint x_size,const uint y_size); //--- public: //--- Обработчик событий графика virtual void OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam); //--- Таймер virtual void OnEventTimer(void); //--- Перемещение элемента virtual void Moving(const bool only_visible=true); //--- Управление virtual void Show(void); virtual void Hide(void); virtual void Delete(void); //--- (1) Установка, (2) сброс приоритетов на нажатие левой кнопки мыши virtual void SetZorders(void); virtual void ResetZorders(void); //--- Рисует элемент virtual void Draw(void); //--- Обновление элемента virtual void Update(const bool redraw=false); //--- private: //--- Обработка нажатия на элемент bool OnClickTextBox(const string clicked_object); //--- Обработка нажатия на клавише bool OnPressedKey(const long key_code); //--- Обработка нажатия на клавише "Backspace" bool OnPressedKeyBackspace(const long key_code); //--- Обработка нажатия на клавише "Enter" bool OnPressedKeyEnter(const long key_code); //--- Обработка нажатия на клавише "Left" bool OnPressedKeyLeft(const long key_code); //--- Обработка нажатия на клавише "Right" bool OnPressedKeyRight(const long key_code); //--- Обработка нажатия на клавише "Up" bool OnPressedKeyUp(const long key_code); //--- Обработка нажатия на клавише "Down" bool OnPressedKeyDown(const long key_code); //--- Обработка нажатия на клавише "Home" bool OnPressedKeyHome(const long key_code); //--- Обработка нажатия на клавише "End" bool OnPressedKeyEnd(const long key_code); //--- Обработка нажатия на клавише Ctrl + Left bool OnPressedKeyCtrlAndLeft(const long key_code); //--- Обработка нажатия на клавише Ctrl + Right bool OnPressedKeyCtrlAndRight(const long key_code); //--- Обработка одновременного нажатия клавиш Ctrl + Home bool OnPressedKeyCtrlAndHome(const long key_code); //--- Обработка одновременного нажатия клавиш Ctrl + End bool OnPressedKeyCtrlAndEnd(const long key_code); //--- Обработка нажатия на клавише Shift + Left bool OnPressedKeyShiftAndLeft(const long key_code); //--- Обработка нажатия на клавише Shift + Right bool OnPressedKeyShiftAndRight(const long key_code); //--- Обработка нажатия на клавише Shift + Up bool OnPressedKeyShiftAndUp(const long key_code); //--- Обработка нажатия на клавише Shift + Down bool OnPressedKeyShiftAndDown(const long key_code); //--- Обработка нажатия на клавише Shift + Home bool OnPressedKeyShiftAndHome(const long key_code); //--- Обработка нажатия на клавише Shift + End bool OnPressedKeyShiftAndEnd(const long key_code); //--- Обработка нажатия на клавише Ctrl + Shift + Left bool OnPressedKeyCtrlShiftAndLeft(const long key_code); //--- Обработка нажатия на клавише Ctrl + Shift + Right bool OnPressedKeyCtrlShiftAndRight(const long key_code); //--- Обработка нажатия на клавише Ctrl + Shift + Home bool OnPressedKeyCtrlShiftAndHome(const long key_code); //--- Обработка нажатия на клавише Ctrl + Shift + End bool OnPressedKeyCtrlShiftAndEnd(const long key_code); //--- private: //--- Устанавливает (1) начальные и (2) конечные индексы для выделения текста void SetStartSelectedTextIndexes(void); void SetEndSelectedTextIndexes(void); //--- Выделить весь текст void SelectAllText(void); //--- Сбросить выделенный текст void ResetSelectedText(void); //--- Ускоренная перемотка поля ввода void FastSwitching(void); //--- Вывод текста на холст void TextOut(void); //--- Рисует рамку virtual void DrawBorder(void); //--- Рисует текстовый курсор void DrawCursor(void); //--- Отображает текст и мигающий курсор void DrawTextAndCursor(const bool show_state=false); //--- Возвращает текущий цвет фона uint AreaColorCurrent(void); //--- Возвращает текущий цвет текста uint TextColorCurrent(void); //--- Возвращает текущий цвет рамки uint BorderColorCurrent(void); //--- Изменение цвета объектов void ChangeObjectsColor(void); //--- Собирает строку из символов string CollectString(const uint line_index,const uint symbols_total=0); //--- Добавляет символ и его свойства в массивы структуры void AddSymbol(const string key_symbol); //--- Удаляет символ void DeleteSymbol(void); //--- Удаляет (1) выделенный текст, (2) на одной строке, (3) на нескольких строках bool DeleteSelectedText(void); void DeleteTextOnOneLine(void); void DeleteTextOnMultipleLines(void); // void InsertToString(const uint line_index, const uint start_pos, const string text); //--- Возвращает высоту строки uint LineHeight(void); //--- Возвращает ширину строки от указанного символа в пикселях uint LineWidth(const uint symbol_index,const uint line_index); //--- Возвращает максимальную ширину строки uint MaxLineWidth(void); //--- Смещает строки на одну позицию вверх void ShiftOnePositionUp(void); //--- Смещает строки на одну позицию вниз void ShiftOnePositionDown(void); //--- Проверка наличия выделенного текста bool CheckSelectedText(const uint line_index,const uint symbol_index); //--- Проверка на наличие обязательной первой строки uint CheckFirstLine(void); //--- Устанавливает новый размер массивам свойств указанной строки void ArraysResize(const uint line_index,const uint new_size); //--- Делает копию указанной (source) строки в новое место (destination) void LineCopy(const uint destination,const uint source); //--- Очищает указанную строку void ClearLine(const uint line_index); //--- Перемещение текстового курсора в указанном направлении void MoveTextCursor(const ENUM_MOVE_TEXT_CURSOR direction); void MoveTextCursor(const ENUM_MOVE_TEXT_CURSOR direction,const bool with_highlighted_text); //--- Перемещение текстового курсора влево void MoveTextCursorToLeft(const bool to_next_word=false); //--- Перемещение текстового курсора вправо void MoveTextCursorToRight(const bool to_next_word=false); //--- Перемещение текстового курсора на одну строку вверх void MoveTextCursorToUp(void); //--- Перемещение текстового курсора на одну строку вниз void MoveTextCursorToDown(void); //--- Устанавливает курсор по указанным позициям void SetTextCursor(const uint x_pos,const uint y_pos); //--- Устанавливает курсор по указанным позициям по курсору мыши void SetTextCursorByMouseCursor(void); //--- Корректировка текстового курсора по оси X void CorrectingTextCursorXPos(const int x_pos=WRONG_VALUE); //--- Расчёт координат для текстового курсора void CalculateTextCursorX(void); void CalculateTextCursorY(void); //--- Расчёт границ поля ввода void CalculateBoundaries(void); void CalculateXBoundaries(void); void CalculateYBoundaries(void); //--- Расчёт X-позиции ползунка полосы прокрутки в левой границе поля ввода int CalculateScrollThumbX(void); //--- Расчёт X-позиции ползунка полосы прокрутки в правой границе поля ввода int CalculateScrollThumbX2(void); //--- Расчёт X-позиции ползунка полосы прокрутки int CalculateScrollPosX(const bool to_right=false); //--- Расчёт Y-позиции ползунка полосы прокрутки в верхней границе поля ввода int CalculateScrollThumbY(void); //--- Расчёт Y-позиции ползунка полосы прокрутки в нижней границе поля ввода int CalculateScrollThumbY2(void); //--- Расчёт Y-позиции ползунка полосы прокрутки int CalculateScrollPosY(const bool to_down=false); //--- Корректировка горизонтальной полосы прокрутки void CorrectingHorizontalScrollThumb(void); //--- Корректировка вертикальной полосы прокрутки void CorrectingVerticalScrollThumb(void); //--- Рассчитывает размеры текстого поля ввода void CalculateTextBoxSize(void); bool CalculateTextBoxXSize(void); bool CalculateTextBoxYSize(void); //--- Изменить основные размеры элемента void ChangeMainSize(const int x_size,const int y_size); //--- Изменить размеры поля ввода void ChangeTextBoxSize(const bool x_offset=false,const bool y_offset=false); //--- Изменить размеры полос прокрутки void ChangeScrollsSize(void); //--- Перенос по словам void WordWrap(void); //--- Возвращает индексы первых видимых символа и пробела bool CheckForOverflow(const uint line_index,int &symbol_index,int &space_index); //--- Количество слов в указанной строке uint WordsTotal(const uint line_index); //--- Возвращает количество переносимых символов bool WrapSymbolsTotal(const uint line_index,uint &wrap_symbols_total); //--- Возвращает индекс символа пробела по его номеру uint SymbolIndexBySpaceNumber(const uint line_index,const uint space_index); //--- Перемещает строки void MoveLines(const uint from_index,const uint to_index,const uint count,const bool to_down=true); //--- Перемещение символов в указанной строке void MoveSymbols(const uint line_index,const uint from_pos,const uint to_pos,const bool to_left=true); //--- Добавление текста в указанную строку void AddToString(const uint line_index,const string text); //--- Копирует в переданный массив символы для переноса на другую строку void CopyWrapSymbols(const uint line_index,const uint start_pos,const uint symbols_total,string &array[]); //--- Вставляет символы из переданного массива в указанную строку void PasteWrapSymbols(const uint line_index,const uint start_pos,string &array[]); //--- Перенос текста на следующую строку void WrapTextToNewLine(const uint curr_line_index,const uint symbol_index,const bool by_pressed_enter=false); //--- Перенос текста из указанной строки в предыдущую void WrapTextToPrevLine(const uint next_line_index,const uint wrap_symbols_total,const bool is_all_text=false); //--- Изменить ширину по правому краю окна virtual void ChangeWidthByRightWindowSide(void); //--- Изменить высоту по нижнему краю окна virtual void ChangeHeightByBottomWindowSide(void); }; //+------------------------------------------------------------------+ //| Constructor | //+------------------------------------------------------------------+ CTextBox::CTextBox(void) : m_selected_text_color(clrWhite), m_selected_back_color(C'51,153,255'), m_selected_line_from(WRONG_VALUE), m_selected_line_to(WRONG_VALUE), m_selected_symbol_from(WRONG_VALUE), m_selected_symbol_to(WRONG_VALUE), m_default_text_color(clrTomato), m_default_text(""), m_temp_input_string(""), m_text_x_offset(5), m_text_y_offset(4), m_multi_line_mode(false), m_word_wrap_mode(false), m_read_only_mode(false), m_auto_selection_mode(false), m_text_edit_state(false), m_text_cursor_x_pos(0), m_text_cursor_y_pos(0), m_shift_x_step(10), m_shift_x2_limit(0), m_shift_y2_limit(0) { //--- Сохраним имя класса элемента в базовом классе CElementBase::ClassName(CLASS_NAME); //--- Исходные координаты текстового курсора m_text_cursor_x=m_text_x_offset; m_text_cursor_y=m_text_y_offset; //--- Установка параметров для счётчика таймера m_counter.SetParameters(16,200); //--- Обязательная первая строка многострочного поля ввода ::ArrayResize(m_lines,1); //--- Установим признак окончания строки m_lines[0].m_end_of_line=true; } //+------------------------------------------------------------------+ //| Destructor | //+------------------------------------------------------------------+ CTextBox::~CTextBox(void) { } //+------------------------------------------------------------------+ //| Обработчик событий графика | //+------------------------------------------------------------------+ void CTextBox::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam) { //--- Обработка события перемещения курсора if(id==CHARTEVENT_MOUSE_MOVE) { //--- Проверка статуса полос прокрутки bool is_scroll_state=m_scrollv.ScrollBarControl() || ((m_multi_line_mode)? m_scrollh.ScrollBarControl() : false); //--- if(m_text_edit_state) { //--- Если (1) не в фокусе и (2) левая кнопка мыши нажата и (3) не в режиме перемещения полос прокрутки if(!CElementBase::MouseFocus() && m_mouse.LeftButtonState() && !is_scroll_state) { //--- Отправим сообщение об окончании ввода строки в поле ввода, если поле было активно string str=(m_multi_line_mode)? TextCursorInfo() : ""; ::EventChartCustom(m_chart_id,ON_END_EDIT,CElementBase::Id(),CElementBase::Index(),str); //--- Дезактивируем поле ввода DeactivateTextBox(); //--- Обновить Update(true); } } //--- Изменение цвета объектов ChangeObjectsColor(); //--- Выйти, если многострочный режим отключен if(!m_multi_line_mode) return; //--- Если полоса прокрутки в действии if(is_scroll_state) { //--- Сдвинуть данные относительно полос прокрутки ShiftData(); //--- Дезактивируем поле ввода DeactivateTextBox(); //--- Обновить Update(true); //--- Обновить полосу прокрутки в действии if(m_scrollh.State()) m_scrollh.Update(true); if(m_scrollv.State()) m_scrollv.Update(true); } //--- Если одна из кнопок полос прокрутки нажата if(m_mouse.LeftButtonState() && (m_scrollv.ScrollIncState() || m_scrollv.ScrollDecState() || m_scrollh.ScrollIncState() || m_scrollh.ScrollDecState())) { //--- Дезактивируем поле ввода DeactivateTextBox(); //--- Обновить Update(true); } //--- return; } //--- Обработка события нажатия левой кнопки мыши на объекте if(id==CHARTEVENT_OBJECT_CLICK) { //--- Нажатие на поле ввода if(OnClickTextBox(sparam)) return; //--- return; } //--- Обработка события нажатия на кнопках полосы прокрутки if(id==CHARTEVENT_CUSTOM+ON_CLICK_BUTTON) { //--- Если было нажатие на кнопках полосы прокрутки списка if(m_scrollv.OnClickScrollInc((uint)lparam,(uint)dparam) || m_scrollv.OnClickScrollDec((uint)lparam,(uint)dparam)) { //--- Сдвигает данные ShiftData(); m_scrollv.Update(true); return; } //--- Если было нажатие на кнопках полосы прокрутки списка if(m_scrollh.OnClickScrollInc((uint)lparam,(uint)dparam) || m_scrollh.OnClickScrollDec((uint)lparam,(uint)dparam)) { //--- Сдвигает данные ShiftData(); m_scrollh.Update(true); return; } } //--- Обработка нажатия кнопки на клавиатуре if(id==CHARTEVENT_KEYDOWN) { //--- Выйти, если поле ввода не активировано if(!m_text_edit_state) return; //--- Нажатие на символьной клавише if(OnPressedKey(lparam)) return; //--- Нажатие на клавише "Backspace" if(OnPressedKeyBackspace(lparam)) return; //--- Нажатие на клавише "Enter" if(OnPressedKeyEnter(lparam)) return; //--- Нажатие на клавише "Left" if(OnPressedKeyLeft(lparam)) return; //--- Нажатие на клавише "Right" if(OnPressedKeyRight(lparam)) return; //--- Нажатие на клавише "Up" if(OnPressedKeyUp(lparam)) return; //--- Нажатие на клавише "Down" if(OnPressedKeyDown(lparam)) return; //--- Нажатие на клавише "Home" if(OnPressedKeyHome(lparam)) return; //--- Нажатие на клавише "End" if(OnPressedKeyEnd(lparam)) return; //--- Одновременное нажатие клавиш Ctrl + Left if(OnPressedKeyCtrlAndLeft(lparam)) return; //--- Одновременное нажатие клавиш Ctrl + Right if(OnPressedKeyCtrlAndRight(lparam)) return; //--- Одновременное нажатие клавиш Ctrl + Home if(OnPressedKeyCtrlAndHome(lparam)) return; //--- Одновременное нажатие клавиш Ctrl + End if(OnPressedKeyCtrlAndEnd(lparam)) return; //--- Одновременное нажатие клавиш Shift + Left if(OnPressedKeyShiftAndLeft(lparam)) return; //--- Одновременное нажатие клавиш Shift + Right if(OnPressedKeyShiftAndRight(lparam)) return; //--- Одновременное нажатие клавиш Shift + Up if(OnPressedKeyShiftAndUp(lparam)) return; //--- Одновременное нажатие клавиш Shift + Down if(OnPressedKeyShiftAndDown(lparam)) return; //--- Одновременное нажатие клавиш Shift + Home if(OnPressedKeyShiftAndHome(lparam)) return; //--- Одновременное нажатие клавиш Shift + End if(OnPressedKeyShiftAndEnd(lparam)) return; //--- Одновременное нажатие клавиш Ctrl + Shift + Left if(OnPressedKeyCtrlShiftAndLeft(lparam)) return; //--- Одновременное нажатие клавиш Ctrl + Shift + Right if(OnPressedKeyCtrlShiftAndRight(lparam)) return; //--- Одновременное нажатие клавиш Ctrl + Shift + Home if(OnPressedKeyCtrlShiftAndHome(lparam)) return; //--- Одновременное нажатие клавиш Ctrl + Shift + End if(OnPressedKeyCtrlShiftAndEnd(lparam)) return; //--- return; } } //+------------------------------------------------------------------+ //| Таймер | //+------------------------------------------------------------------+ void CTextBox::OnEventTimer(void) { //--- Ускоренная перемотка значений FastSwitching(); //--- Пауза между обновлением текстового курсора if(m_counter.CheckTimeCounter()) { //--- Обновим текстовый курсор, если элемент видим и поле ввода активировано if(CElementBase::IsVisible() && m_text_edit_state) DrawTextAndCursor(); } } //+------------------------------------------------------------------+ //| Создаёт элемент "Текстовое поле ввода" | //+------------------------------------------------------------------+ bool CTextBox::CreateTextBox(const int x_gap,const int y_gap) { //--- Выйти, если нет указателя на главный элемент if(!CElement::CheckMainPointer()) return(false); //--- Инициализация свойств InitializeProperties(x_gap,y_gap); //--- Рассчитаем размеры текстового поля ввода CalculateTextBoxSize(); //--- Создание элемента if(!CreateCanvas()) return(false); if(!CreateTextBox()) return(false); if(!CreateScrollV()) return(false); if(!CreateScrollH()) return(false); //--- Изменить размеры текстового поля ввода ChangeTextBoxSize(); //--- В режиме переноса слов нужно повторно пересчитать и установить размеры if(m_word_wrap_mode) { CalculateTextBoxSize(); ChangeTextBoxSize(); } //--- return(true); } //+------------------------------------------------------------------+ //| Инициализация свойств | //+------------------------------------------------------------------+ void CTextBox::InitializeProperties(const int x_gap,const int y_gap) { m_x =CElement::CalculateX(x_gap); m_y =CElement::CalculateY(y_gap); m_x_size =(m_x_size<0 || m_auto_xresize_mode)? m_main.X2()-CElementBase::X()-m_auto_xresize_right_offset : m_x_size; m_y_size =(m_y_size<0 || m_auto_yresize_mode)? m_main.Y2()-CElementBase::Y()-m_auto_yresize_bottom_offset : m_y_size; //--- Цвета по умолчанию m_back_color =(m_back_color!=clrNONE)? m_back_color : clrWhite; m_back_color_locked =(m_back_color_locked!=clrNONE)? m_back_color_locked : clrWhiteSmoke; m_border_color =(m_border_color!=clrNONE)? m_border_color : clrGray; m_border_color_hover =(m_border_color_hover!=clrNONE)? m_border_color_hover : clrBlack; m_border_color_locked =(m_border_color_locked!=clrNONE)? m_border_color_locked : clrSilver; m_border_color_pressed =(m_border_color_pressed!=clrNONE)? m_border_color_pressed : clrCornflowerBlue; m_label_color =(m_label_color!=clrNONE)? m_label_color : clrBlack; m_label_color_locked =(m_label_color_locked!=clrNONE)? m_label_color_locked : clrSilver; //--- Отступы от крайней точки CElementBase::XGap(x_gap); CElementBase::YGap(y_gap); } //+------------------------------------------------------------------+ //| Создаёт холст для рисования фона | //+------------------------------------------------------------------+ bool CTextBox::CreateCanvas(void) { //--- Формирование имени объекта string name=CElementBase::ElementName("textbox"); //--- Создание объекта if(!CElement::CreateCanvas(name,m_x,m_y,m_x_size,m_y_size)) return(false); //--- Проверка на наличие обязательной первой строки CheckFirstLine(); return(true); } //+------------------------------------------------------------------+ //| Создаёт холст для рисования поля ввода | //+------------------------------------------------------------------+ bool CTextBox::CreateTextBox(void) { //--- Формирование имени объекта string name=""; if(m_index==WRONG_VALUE) name=m_program_name+"_"+"textbox_edit"+"_"+(string)m_id; else name=m_program_name+"_"+"textbox_edit"+"_"+(string)m_index+"__"+(string)m_id; //--- Координаты int x =m_x+1; int y =m_y+1; //--- Размер int x_size =m_area_x_size-2; int y_size =m_area_y_size-2; //--- Создание объекта ::ResetLastError(); if(!m_textbox.CreateBitmapLabel(m_chart_id,m_subwin,name,x,y,x_size,y_size,COLOR_FORMAT_ARGB_NORMALIZE)) { ::Print(__FUNCTION__," > Не удалось создать холст для рисования поля ввода: ",::GetLastError()); return(false); } //--- Получим указатель на базовый класс if(!m_textbox.Attach(m_chart_id,name,COLOR_FORMAT_ARGB_NORMALIZE)) { ::Print(__FUNCTION__," > Не удалось присоединить холст для рисования к графику: ",::GetLastError()); return(false); } //--- Свойства ::ObjectSetInteger(m_chart_id,m_textbox.ChartObjectName(),OBJPROP_ZORDER,m_zorder+1); ::ObjectSetString(m_chart_id,m_textbox.ChartObjectName(),OBJPROP_TOOLTIP,"\n"); //--- Координаты m_textbox.X(x); m_textbox.Y(y); //--- Отступы от крайней точки панели m_textbox.XGap(CElement::CalculateXGap(x)); m_textbox.YGap(CElement::CalculateYGap(y)); //--- Установим размеры видимой области ::ObjectSetInteger(m_chart_id,m_textbox.ChartObjectName(),OBJPROP_XSIZE,m_area_visible_x_size); ::ObjectSetInteger(m_chart_id,m_textbox.ChartObjectName(),OBJPROP_YSIZE,m_area_visible_y_size); //--- Зададим смещение фрейма внутри изображения по осям X и Y ::ObjectSetInteger(m_chart_id,m_textbox.ChartObjectName(),OBJPROP_XOFFSET,0); ::ObjectSetInteger(m_chart_id,m_textbox.ChartObjectName(),OBJPROP_YOFFSET,0); return(true); } //+------------------------------------------------------------------+ //| Создаёт вертикальный скролл | //+------------------------------------------------------------------+ bool CTextBox::CreateScrollV(void) { //--- Сохранить указатель родительского элемента m_scrollv.MainPointer(this); //--- Если отключен многострочный режим if(!m_multi_line_mode) { //--- Инициализация вертикальной полосы прокрутки m_scrollv.Reinit(m_area_y_size,m_area_visible_y_size); //--- Сохранить указатель родительского элемента m_scrollv.GetIncButtonPointer().MainPointer(m_scrollv); m_scrollv.GetDecButtonPointer().MainPointer(m_scrollv); return(true); } //--- Координаты int x =m_scrollv.ScrollWidth()+1; int y =1; //--- Установим свойства m_scrollv.Index(0); m_scrollv.IsDropdown(CElementBase::IsDropdown()); m_scrollv.XSize(m_scrollv.ScrollWidth()); m_scrollv.YSize(m_y_size-m_scrollv.ScrollWidth()-1); m_scrollv.AnchorRightWindowSide(true); //--- Расчёт количества шагов для смещения uint lines_total =LinesTotal()+1; uint visible_lines_total =VisibleLinesTotal(); //--- Создание полосы прокрутки if(!m_scrollv.CreateScroll(x,y,lines_total,visible_lines_total)) return(false); //--- Добавить элемент в массив CElement::AddToArray(m_scrollv); return(true); } //+------------------------------------------------------------------+ //| Создаёт горизонтальный скролл | //+------------------------------------------------------------------+ bool CTextBox::CreateScrollH(void) { //--- Сохранить указатель родительского элемента m_scrollh.MainPointer(this); //--- Если отключен многострочный режим if(!m_multi_line_mode) { //--- Инициализация горизонтальной полосы прокрутки m_scrollh.Reinit(m_area_x_size,m_area_visible_x_size); //--- Сохранить указатель главного элемента m_scrollh.GetIncButtonPointer().MainPointer(m_scrollh); m_scrollh.GetDecButtonPointer().MainPointer(m_scrollh); return(true); } //--- Координаты int x =1; int y =m_scrollh.ScrollWidth()+1; //--- Установим свойства m_scrollh.Index(1); m_scrollh.IsDropdown(CElementBase::IsDropdown()); m_scrollh.XSize(CElementBase::XSize()-m_scrollv.ScrollWidth()-1); m_scrollh.YSize(m_scrollv.ScrollWidth()); m_scrollh.AnchorBottomWindowSide(true); //--- Расчёт количества шагов для смещения uint x_size_total =m_area_x_size/m_shift_x_step; uint visible_x_size_total =m_area_visible_x_size/m_shift_x_step; //--- Создание полосы прокрутки if(!m_scrollh.CreateScroll(x,y,x_size_total,visible_x_size_total)) return(false); //--- Добавить элемент в массив CElement::AddToArray(m_scrollh); return(true); } //+------------------------------------------------------------------+ //| Возвращает количество видимых строк | //+------------------------------------------------------------------+ uint CTextBox::VisibleLinesTotal(void) { return((m_area_visible_y_size-(m_text_y_offset*2))/LineHeight()); } //+------------------------------------------------------------------+ //| Возвращает количество символов в указанной строке | //+------------------------------------------------------------------+ uint CTextBox::ColumnsTotal(const uint line_index) { //--- Получим размер массива строк uint lines_total=::ArraySize(m_lines); //--- Предотвращение выхода из диапазона uint check_index=(line_index=lines_total) { l=i; break; } //--- j++; } } } //--- uint insert_pos = (l == m_text_cursor_y_pos) ? m_text_cursor_x_pos : ::ArraySize(m_lines[l].m_symbol); //--- Установим шрифт m_textbox.FontSet(CElement::Font(),-CElement::FontSize()*10,FW_NORMAL); //--- Добавим текст в строку InsertToString(l,insert_pos,added_text); } //+------------------------------------------------------------------+ //| Возвращает текст из указанной строки | //+------------------------------------------------------------------+ string CTextBox::GetValue(const uint line_index=0) { //--- Получим размер массива строк, с проверкой на наличие обязательной первой строки uint lines_total=CheckFirstLine(); //--- Предотвращение выхода из диапазона uint l=(line_indexlast_pos_index)? last_pos_index : pos; //--- Сдвигаем ползунок полосы прокрутки m_scrollh.MovingThumb(index); //--- Сдвигаем поле ввода ShiftData(); //--- Обновить полосу прокрутки m_scrollh.Update(); } //+------------------------------------------------------------------+ //| Вертикальная прокрутка поля ввода | //+------------------------------------------------------------------+ void CTextBox::VerticalScrolling(const int pos=WRONG_VALUE) { //--- Для определения позиции ползунка int index=0; //--- Индекс последней позиции int last_pos_index=int((m_area_y_size-m_area_visible_y_size)/(double)LineHeight()); //--- Корректировка в случае выхода из диапазона if(pos<0) index=last_pos_index; else index=(pos>last_pos_index)? last_pos_index : pos; //--- Сдвигаем ползунок полосы прокрутки m_scrollv.MovingThumb(index); //--- Сдвигаем поле ввода ShiftData(); //--- Обновить полосу прокрутки m_scrollv.Update(true); } //+------------------------------------------------------------------+ //| Сдвигает данные относительно полос прокрутки | //+------------------------------------------------------------------+ void CTextBox::ShiftData(void) { //--- Получим текущие позиции ползунков горизонтальной и вертикальной полос прокрутки int h_offset =m_scrollh.CurrentPos()*m_shift_x_step; int v_offset =m_text_y_offset+(m_scrollv.CurrentPos()*(int)LineHeight())-2; //--- Рассчитаем отступы для смещения int x_offset =(h_offset<1)? 0 : (h_offset>=m_shift_x2_limit)? m_shift_x2_limit : h_offset; int y_offset =(v_offset<1)? 0 : (v_offset>=m_shift_y2_limit)? m_shift_y2_limit : v_offset; //--- Расчёт положения данных относительно ползунков полос прокрутки long x =(m_area_x_size>m_area_visible_x_size && !m_word_wrap_mode)? x_offset : 0; long y =(m_area_y_size>m_area_visible_y_size)? y_offset : 0; //--- Смещение данных ::ObjectSetInteger(m_chart_id,m_textbox.ChartObjectName(),OBJPROP_XOFFSET,x); ::ObjectSetInteger(m_chart_id,m_textbox.ChartObjectName(),OBJPROP_YOFFSET,y); } //+------------------------------------------------------------------+ //| Корректировка размеров поля ввода | //+------------------------------------------------------------------+ void CTextBox::CorrectSize(void) { //--- Рассчитать размеры поля ввода CalculateTextBoxSize(); //--- Установить новый размер полю ввода ChangeTextBoxSize(true,true); } //+------------------------------------------------------------------+ //| Активация поля ввода | //+------------------------------------------------------------------+ void CTextBox::ActivateTextBox(void) { OnClickTextBox(m_textbox.ChartObjectName()); } //+------------------------------------------------------------------+ //| Изменение размеров | //+------------------------------------------------------------------+ void CTextBox::ChangeSize(const uint x_size,const uint y_size) { //--- Установить новый размер ChangeMainSize(x_size,y_size); //--- Рассчитать размеры поля ввода CalculateTextBoxSize(); //--- Установить новый размер полю ввода ChangeTextBoxSize(); } //+------------------------------------------------------------------+ //| Перемещение элемента | //+------------------------------------------------------------------+ void CTextBox::Moving(const bool only_visible=true) { //--- Выйти, если элемент скрыт if(only_visible) if(!CElementBase::IsVisible()) return; //--- Если привязка справа if(m_anchor_right_window_side) { //--- Сохранение координат в полях элемента CElementBase::X(m_main.X2()-XGap()); //--- Сохранение координат в полях объектов m_textbox.X(m_main.X2()-m_textbox.XGap()); } else { CElementBase::X(m_main.X()+XGap()); m_textbox.X(m_main.X()+m_textbox.XGap()); } //--- Если привязка снизу if(m_anchor_bottom_window_side) { CElementBase::Y(m_main.Y2()-YGap()); m_textbox.Y(m_main.Y2()-m_textbox.YGap()); } else { CElementBase::Y(m_main.Y()+YGap()); m_textbox.Y(m_main.Y()+m_textbox.YGap()); } //--- Обновление координат ::ObjectSetInteger(m_chart_id,m_textbox.ChartObjectName(),OBJPROP_XDISTANCE,m_textbox.X()); ::ObjectSetInteger(m_chart_id,m_textbox.ChartObjectName(),OBJPROP_YDISTANCE,m_textbox.Y()); //--- Обновить положение объектов CElement::Moving(only_visible); } //+------------------------------------------------------------------+ //| Показывает элемент | //+------------------------------------------------------------------+ void CTextBox::Show(void) { //--- Выйти, если элемент уже видим if(CElementBase::IsVisible()) return; //--- Сделать видимыми все объекты ::ObjectSetInteger(m_chart_id,m_canvas.ChartObjectName(),OBJPROP_TIMEFRAMES,OBJ_ALL_PERIODS); ::ObjectSetInteger(m_chart_id,m_textbox.ChartObjectName(),OBJPROP_TIMEFRAMES,OBJ_ALL_PERIODS); //--- Состояние видимости CElementBase::IsVisible(true); //--- Обновить положение элемента Moving(); //--- Показать полосы прокрутки if(m_scrollv.IsScroll()) m_scrollv.Show(); if(m_scrollh.IsScroll()) m_scrollh.Show(); } //+------------------------------------------------------------------+ //| Скрывает элемент | //+------------------------------------------------------------------+ void CTextBox::Hide(void) { //--- Выйти, если элемент скрыт if(!CElementBase::IsVisible()) return; //--- Скрыть все объекты ::ObjectSetInteger(m_chart_id,m_canvas.ChartObjectName(),OBJPROP_TIMEFRAMES,OBJ_NO_PERIODS); ::ObjectSetInteger(m_chart_id,m_textbox.ChartObjectName(),OBJPROP_TIMEFRAMES,OBJ_NO_PERIODS); m_scrollv.Hide(); m_scrollh.Hide(); //--- Состояние видимости CElementBase::IsVisible(false); } //+------------------------------------------------------------------+ //| Удаление | //+------------------------------------------------------------------+ void CTextBox::Delete(void) { //--- Удаление объектов m_canvas.Destroy(); m_textbox.Destroy(); //--- Получим размер массива строк uint lines_total=::ArraySize(m_lines); //--- Освобождение массивов элемента for(uint i=0; im_area_visible_x_size) needs_full_recalc=true; } //--- Si el modo de ajuste de palabras está desactivado else { //--- Se necesita recálculo si la línea supera el área total actual // (necesitará expandir el canvas o ajustar scroll) if((line_width+m_text_x_offset*2+xscrrol)>m_area_x_size) needs_full_recalc=true; } //--- Si se necesita recálculo completo if(needs_full_recalc) { //--- Calcular dimensiones del campo de entrada CalculateTextBoxSize(); //--- Establecer nuevo tamaño al campo de entrada ChangeTextBoxSize(true,true); //--- Corregir barra de desplazamiento horizontal CorrectingHorizontalScrollThumb(); //--- Si el modo de ajuste de palabras está activado, corregir barra vertical if(m_word_wrap_mode) CorrectingVerticalScrollThumb(); } //--- Si no se necesita recálculo completo else { //--- Obtener coordenada X del cursor CalculateTextCursorX(); //--- Corregir barra de desplazamiento horizontal si el cursor salió del área visible int x_offset=(int)::ObjectGetInteger(m_chart_id,m_textbox.ChartObjectName(),OBJPROP_XOFFSET); if(m_text_cursor_x-x_offset>=m_area_visible_x_size-m_text_x_offset) CorrectingHorizontalScrollThumb(); } //--- Actualizar texto en el campo de entrada DrawTextAndCursor(true); //--- Enviar mensaje sobre esto ::EventChartCustom(m_chart_id,ON_MODIFY_TEXTBOX,CElementBase::Id(),CElementBase::Index(),pressed_key); return(true); } /* //+------------------------------------------------------------------+ //| Обработка нажатия специальных символов с Shift/Alt | //+------------------------------------------------------------------+ bool CTextBox::OnPressedKeySpecial(const long key_code) { //--- Obtener estado de modificadores if(!m_keys.KeyShiftState()) return(false); //--- Mapa de caracteres especiales string special_char = ""; //--- Con Shift if(is_shift && !is_alt) { switch((int)key_code) { case 188: special_char = "<"; break; // Shift + , case 190: special_char = ">"; break; // Shift + . case 191: special_char = "?"; break; // Shift + / case 186: special_char = ":"; break; // Shift + ; case 222: special_char = "\""; break; // Shift + ' case 219: special_char = "{"; break; // Shift + [ case 221: special_char = "}"; break; // Shift + ] case 220: special_char = "|"; break; // Shift + \ case 49: special_char = "!"; break; // Shift + 1 case 50: special_char = "@"; break; // Shift + 2 case 51: special_char = "#"; break; // Shift + 3 case 52: special_char = "$"; break; // Shift + 4 case 53: special_char = "%"; break; // Shift + 5 case 54: special_char = "^"; break; // Shift + 6 case 55: special_char = "&"; break; // Shift + 7 case 56: special_char = "*"; break; // Shift + 8 case 57: special_char = "("; break; // Shift + 9 case 48: special_char = ")"; break; // Shift + 0 case 189: special_char = "_"; break; // Shift + - case 187: special_char = "+"; break; // Shift + = case 192: special_char = "~"; break; // Shift + ` } } //--- Sin Shift (caracteres normales que Keys.mqh no captura) else if(!is_shift && !is_alt) { switch((int)key_code) { case 188: special_char = ","; break; case 190: special_char = "."; break; case 191: special_char = "/"; break; case 186: special_char = ";"; break; case 222: special_char = "'"; break; case 219: special_char = "["; break; case 221: special_char = "]"; break; case 220: special_char = "\\"; break; case 189: special_char = "-"; break; case 187: special_char = "="; break; case 192: special_char = "`"; break; } } //--- Si no encontramos carácter especial, salir if(special_char == "") return(false); //--- Si hay texto seleccionado, eliminarlo DeleteSelectedText(); //--- Agregar el carácter especial AddSymbol(special_char); //--- Recalcular dimensiones CalculateTextBoxSize(); ChangeTextBoxSize(true, true); //--- Corregir scrollbars CorrectingHorizontalScrollThumb(); if(m_word_wrap_mode) CorrectingVerticalScrollThumb(); //--- Redibujar DrawTextAndCursor(true); //--- Enviar evento de modificación ::EventChartCustom(m_chart_id, ON_MODIFY_TEXTBOX, CElementBase::Id(), CElementBase::Index(), special_char); return(true); } */ //+------------------------------------------------------------------+ //| Обработка нажатия на клавише 'Backspace' | //+------------------------------------------------------------------+ bool CTextBox::OnPressedKeyBackspace(const long key_code) { //--- Выйти, если это не клавиша 'Backspace' if(key_code!=KEY_BACKSPACE) return(false); //--- Если есть выделенный текст, удалим его и выйдем if(DeleteSelectedText()) return(true); //--- Удалить символ, если позиция больше нуля if(m_text_cursor_x_pos>0) DeleteSymbol(); //--- Если нулевая позиция и не первая строка, // удалить строку и сместить строки на одну позицию вверх else if(m_text_cursor_y_pos>0) ShiftOnePositionUp(); //--- Рассчитать размеры поля ввода CalculateTextBoxSize(); //--- Установить новый размер полю ввода ChangeTextBoxSize(true,true); //--- Корректируем полосы прокрутки CorrectingHorizontalScrollThumb(); CorrectingVerticalScrollThumb(); //--- Обновить текст в поле ввода DrawTextAndCursor(true); //--- Отправим сообщение об этом //::EventChartCustom(m_chart_id,ON_MOVE_TEXT_CURSOR,CElementBase::Id(),CElementBase::Index(),TextCursorInfo()); // Modifuqe esto agrege un nuevo evento ::EventChartCustom(m_chart_id,ON_MODIFY_TEXTBOX,CElementBase::Id(),CElementBase::Index(),"backspace"); return(true); } //+------------------------------------------------------------------+ //| Обработка нажатия на клавише "Enter" | //+------------------------------------------------------------------+ bool CTextBox::OnPressedKeyEnter(const long key_code) { //--- Выйти, если это не клавиша 'Enter' if(key_code!=KEY_ENTER) return(false); //--- Если есть выделенный текст, удалим его DeleteSelectedText(); //--- Если отключен многострочный режим if(!m_multi_line_mode) { //--- Дезактивировать поле ввода DeactivateTextBox(); //--- Обновить Update(true); //--- Отправим сообщение об этом string str=(m_multi_line_mode)? TextCursorInfo() : ""; ::EventChartCustom(m_chart_id,ON_END_EDIT,CElementBase::Id(),CElementBase::Index(),str); return(false); } //--- Сместим строки на одну позицию вниз ShiftOnePositionDown(); //--- Рассчитать размеры поля ввода CalculateTextBoxSize(); //--- Установить новый размер полю ввода ChangeTextBoxSize(); //--- Корректируем вертикальную полосу прокрутки CorrectingVerticalScrollThumb(); //--- Переместить курсор в начало строки SetTextCursor(0,m_text_cursor_y_pos); //--- Переместить полосу прокрутки в начало HorizontalScrolling(0); //--- Обновить текст в поле ввода DrawTextAndCursor(true); //--- Отправим сообщение об этом //::EventChartCustom(m_chart_id,ON_MOVE_TEXT_CURSOR,CElementBase::Id(),CElementBase::Index(),TextCursorInfo()); // Modifuqe esto agrege un nuevo evento ::EventChartCustom(m_chart_id,ON_MODIFY_TEXTBOX,CElementBase::Id(),CElementBase::Index(),"\n"); return(true); } //+------------------------------------------------------------------+ //| Обработка нажатия на клавише 'Left' | //+------------------------------------------------------------------+ bool CTextBox::OnPressedKeyLeft(const long key_code) { //--- Выйти, если (1) это не клавиша 'Left' или (2) нажата клавиша 'Ctrl' или (3) клавиша 'Shift' нажата if(key_code!=KEY_LEFT || m_keys.KeyCtrlState() || m_keys.KeyShiftState()) return(false); //--- Сместить текстовый курсор влево на один символ MoveTextCursor(TO_NEXT_LEFT_SYMBOL,false); return(true); } //+------------------------------------------------------------------+ //| Обработка нажатия на клавише 'Right' | //+------------------------------------------------------------------+ bool CTextBox::OnPressedKeyRight(const long key_code) { //--- Выйти, если (1) это не клавиша 'Right' или (2) нажата клавиша 'Ctrl' или (3) клавиша 'Shift' нажата if(key_code!=KEY_RIGHT || m_keys.KeyCtrlState() || m_keys.KeyShiftState()) return(false); //--- Сместить текстовый курсор вправо на один символ MoveTextCursor(TO_NEXT_RIGHT_SYMBOL,false); return(true); } //+------------------------------------------------------------------+ //| Обработка нажатия на клавише 'Up' | //+------------------------------------------------------------------+ bool CTextBox::OnPressedKeyUp(const long key_code) { //--- Выйти, если отключен многострочный режим if(!m_multi_line_mode) return(false); //--- Выйти, если (1) это не клавиша 'Up' или (2) клавиша 'Shift' нажата if(key_code!=KEY_UP || m_keys.KeyShiftState()) return(false); //--- Сместить текстовый курсор вверх на одну строку MoveTextCursor(TO_NEXT_UP_LINE,false); return(true); } //+------------------------------------------------------------------+ //| Обработка нажатия на клавише 'Down' | //+------------------------------------------------------------------+ bool CTextBox::OnPressedKeyDown(const long key_code) { //--- Выйти, если отключен многострочный режим if(!m_multi_line_mode) return(false); //--- Выйти, если (1) это не клавиша 'Down' или (2) клавиша 'Shift' нажата if(key_code!=KEY_DOWN || m_keys.KeyShiftState()) return(false); //--- Сместить текстовый курсор вниз на одну строку MoveTextCursor(TO_NEXT_DOWN_LINE,false); return(true); } //+------------------------------------------------------------------+ //| Обработка нажатия на клавише 'Home' | //+------------------------------------------------------------------+ bool CTextBox::OnPressedKeyHome(const long key_code) { //--- Выйти, если (1) это не клавиша 'Home' или (2) клавиша 'Ctrl' нажата или (3) клавиша 'Shift' нажата if(key_code!=KEY_HOME || m_keys.KeyCtrlState() || m_keys.KeyShiftState()) return(false); //--- Переместить курсор в начало текущей строки MoveTextCursor(TO_BEGIN_LINE,false); return(true); } //+------------------------------------------------------------------+ //| Обработка нажатия на клавише 'End' | //+------------------------------------------------------------------+ bool CTextBox::OnPressedKeyEnd(const long key_code) { //--- Выйти, если (1) это не клавиша 'End' или (2) клавиша 'Ctrl' нажата или (3) клавиша 'Shift' нажата if(key_code!=KEY_END || m_keys.KeyCtrlState() || m_keys.KeyShiftState()) return(false); //--- Переместить курсор в конец текущей строки MoveTextCursor(TO_END_LINE,false); return(true); } //+------------------------------------------------------------------+ //| Обработка одновременного нажатия клавиш Ctrl + Left | //+------------------------------------------------------------------+ bool CTextBox::OnPressedKeyCtrlAndLeft(const long key_code) { //--- Выйти, если (1) это не клавиша 'Left' и (2) клавиша 'Ctrl' не нажата или (3) клавиша 'Shift' нажата if(!(key_code==KEY_LEFT && m_keys.KeyCtrlState()) || m_keys.KeyShiftState()) return(false); //--- Сместить текстовый курсор влево на одно слово MoveTextCursor(TO_NEXT_LEFT_WORD,false); return(true); } //+------------------------------------------------------------------+ //| Обработка одновременного нажатия клавиш Ctrl + Right | //+------------------------------------------------------------------+ bool CTextBox::OnPressedKeyCtrlAndRight(const long key_code) { //--- Выйти, если (1) это не клавиша 'Right' и (2) клавиша 'Ctrl' не нажата или (3) клавиша 'Shift' нажата if(!(key_code==KEY_RIGHT && m_keys.KeyCtrlState()) || m_keys.KeyShiftState()) return(false); //--- Сместить текстовый курсор вправо на одно слово MoveTextCursor(TO_NEXT_RIGHT_WORD,false); return(true); } //+------------------------------------------------------------------+ //| Обработка одновременного нажатия клавиш Ctrl + Home | //+------------------------------------------------------------------+ bool CTextBox::OnPressedKeyCtrlAndHome(const long key_code) { //--- Выйти, если (1) это не клавиша 'Home' и (2) клавиша 'Ctrl' не нажата или (3) клавиша 'Shift' нажата if(!(key_code==KEY_HOME && m_keys.KeyCtrlState()) || m_keys.KeyShiftState()) return(false); //--- Переместить курсор в начало первой строки MoveTextCursor(TO_BEGIN_FIRST_LINE,false); return(true); } //+------------------------------------------------------------------+ //| Обработка одновременного нажатия клавиш Ctrl + End | //+------------------------------------------------------------------+ bool CTextBox::OnPressedKeyCtrlAndEnd(const long key_code) { //--- Выйти, если (1) это не клавиша 'End' и (2) клавиша 'Ctrl' не нажата или (3) клавиша 'Shift' нажата if(!(key_code==KEY_END && m_keys.KeyCtrlState()) || m_keys.KeyShiftState()) return(false); //--- Переместить курсор в конец последней строки MoveTextCursor(TO_END_LAST_LINE,false); return(true); } //+------------------------------------------------------------------+ //| Обработка нажатия на клавише Shift + Left | //+------------------------------------------------------------------+ bool CTextBox::OnPressedKeyShiftAndLeft(const long key_code) { //--- Выйти, если (1) это не клавиша 'Left' или (2) клавиша 'Ctrl' нажата или (3) клавиша 'Shift' не нажата if(key_code!=KEY_LEFT || m_keys.KeyCtrlState() || !m_keys.KeyShiftState()) return(false); //--- Сместить текстовый курсор влево на один символ MoveTextCursor(TO_NEXT_LEFT_SYMBOL,true); return(true); } //+------------------------------------------------------------------+ //| Обработка нажатия на клавише Shift + Right | //+------------------------------------------------------------------+ bool CTextBox::OnPressedKeyShiftAndRight(const long key_code) { //--- Выйти, если (1) это не клавиша 'Right' или (2) клавиша 'Ctrl' нажата или (3) клавиша 'Shift' не нажата if(key_code!=KEY_RIGHT || m_keys.KeyCtrlState() || !m_keys.KeyShiftState()) return(false); //--- Сместить текстовый курсор вправо на один символ MoveTextCursor(TO_NEXT_RIGHT_SYMBOL,true); return(true); } //+------------------------------------------------------------------+ //| Обработка нажатия на клавише Shift + Up | //+------------------------------------------------------------------+ bool CTextBox::OnPressedKeyShiftAndUp(const long key_code) { //--- Выйти, если (1) это не клавиша 'Up' или (2) клавиша 'Ctrl' нажата или (3) клавиша 'Shift' не нажата if(key_code!=KEY_UP || m_keys.KeyCtrlState() || !m_keys.KeyShiftState()) return(false); //--- Сместить текстовый курсор вверх на одну строку MoveTextCursor(TO_NEXT_UP_LINE,true); return(true); } //+------------------------------------------------------------------+ //| Обработка нажатия на клавише Shift + Down | //+------------------------------------------------------------------+ bool CTextBox::OnPressedKeyShiftAndDown(const long key_code) { //--- Выйти, если (1) это не клавиша 'Down' или (2) клавиша 'Ctrl' нажата или (3) клавиша 'Shift' не нажата if(key_code!=KEY_DOWN || m_keys.KeyCtrlState() || !m_keys.KeyShiftState()) return(false); //--- Сместить текстовый курсор вниз на одну строку MoveTextCursor(TO_NEXT_DOWN_LINE,true); return(true); } //+------------------------------------------------------------------+ //| Обработка нажатия на клавише Shift + Home | //+------------------------------------------------------------------+ bool CTextBox::OnPressedKeyShiftAndHome(const long key_code) { //--- Выйти, если (1) это не клавиша 'Home' или (2) клавиша 'Ctrl' нажата или (3) клавиша 'Shift' не нажата if(key_code!=KEY_HOME || m_keys.KeyCtrlState() || !m_keys.KeyShiftState()) return(false); //--- Переместить курсор в начало текущей строки MoveTextCursor(TO_BEGIN_LINE,true); return(true); } //+------------------------------------------------------------------+ //| Обработка нажатия на клавише Shift + End | //+------------------------------------------------------------------+ bool CTextBox::OnPressedKeyShiftAndEnd(const long key_code) { //--- Выйти, если (1) это не клавиша 'End' или (2) клавиша 'Ctrl' нажата или (3) клавиша 'Shift' не нажата if(key_code!=KEY_END || m_keys.KeyCtrlState() || !m_keys.KeyShiftState()) return(false); //--- Переместить курсор в конец текущей строки MoveTextCursor(TO_END_LINE,true); return(true); } //+------------------------------------------------------------------+ //| Обработка нажатия на клавише Ctrl + Shift + Left | //+------------------------------------------------------------------+ bool CTextBox::OnPressedKeyCtrlShiftAndLeft(const long key_code) { //--- Выйти, если (1) это не клавиша 'Left' и (2) клавиша 'Ctrl' не нажата и (3) клавиша 'Shift' нажата if(!(key_code==KEY_LEFT && m_keys.KeyCtrlState() && m_keys.KeyShiftState())) return(false); //--- Сместить текстовый курсор влево на одно слово MoveTextCursor(TO_NEXT_LEFT_WORD,true); return(true); } //+------------------------------------------------------------------+ //| Обработка нажатия на клавише Ctrl + Shift + Right | //+------------------------------------------------------------------+ bool CTextBox::OnPressedKeyCtrlShiftAndRight(const long key_code) { //--- Выйти, если (1) это не клавиша 'Right' и (2) клавиша 'Ctrl' не нажата и (3) клавиша 'Shift' нажата if(!(key_code==KEY_RIGHT && m_keys.KeyCtrlState() && m_keys.KeyShiftState())) return(false); //--- Сместить текстовый курсор вправо на одно слово MoveTextCursor(TO_NEXT_RIGHT_WORD,true); return(true); } //+------------------------------------------------------------------+ //| Обработка нажатия на клавише Ctrl + Shift + Home | //+------------------------------------------------------------------+ bool CTextBox::OnPressedKeyCtrlShiftAndHome(const long key_code) { //--- Выйти, если (1) это не клавиша 'Home' и (2) клавиша 'Ctrl' не нажата и (3) клавиша 'Shift' нажата if(!(key_code==KEY_HOME && m_keys.KeyCtrlState() && m_keys.KeyShiftState())) return(false); //--- Переместить курсор в начало первой строки MoveTextCursor(TO_BEGIN_FIRST_LINE,true); return(true); } //+------------------------------------------------------------------+ //| Обработка нажатия на клавише Ctrl + Shift + End | //+------------------------------------------------------------------+ bool CTextBox::OnPressedKeyCtrlShiftAndEnd(const long key_code) { //--- Выйти, если (1) это не клавиша 'End' и (2) клавиша 'Ctrl' не нажата и (3) клавиша 'Shift' нажата if(!(key_code==KEY_END && m_keys.KeyCtrlState() && m_keys.KeyShiftState())) return(false); //--- Переместить курсор в конец последней строки MoveTextCursor(TO_END_LAST_LINE,true); return(true); } //+------------------------------------------------------------------+ //| Установить начальные индексы для выделенния текста | //+------------------------------------------------------------------+ void CTextBox::SetStartSelectedTextIndexes(void) { //--- Если начальные индексы для выделения текста ещё не установлены if(m_selected_line_from==WRONG_VALUE) { m_selected_line_from =(int)m_text_cursor_y_pos; m_selected_symbol_from =(int)m_text_cursor_x_pos; } } //+------------------------------------------------------------------+ //| Установить конечные индексы для выделенния текста | //+------------------------------------------------------------------+ void CTextBox::SetEndSelectedTextIndexes(void) { //--- Установить конечные индексы для выделения текста m_selected_line_to =(int)m_text_cursor_y_pos; m_selected_symbol_to =(int)m_text_cursor_x_pos; //--- Если все индексы равны, то сбросить выделение if(m_selected_line_from==m_selected_line_to && m_selected_symbol_from==m_selected_symbol_to) ResetSelectedText(); } //+------------------------------------------------------------------+ //| Выделить весь текст | //+------------------------------------------------------------------+ void CTextBox::SelectAllText(void) { //--- Получим размер массива символов int symbols_total=::ArraySize(m_lines[0].m_symbol); //--- Установить индексы для выделения текста m_selected_line_from =0; m_selected_line_to =0; m_selected_symbol_from =0; m_selected_symbol_to =symbols_total; //--- Переместить ползунок горизонтальной полосы прокрутки на последнюю позицию HorizontalScrolling(); //--- Переместить курсор в конец строки SetTextCursor(symbols_total,0); } //+------------------------------------------------------------------+ //| Сбросить выделенный текст | //+------------------------------------------------------------------+ void CTextBox::ResetSelectedText(void) { m_selected_line_from =WRONG_VALUE; m_selected_line_to =WRONG_VALUE; m_selected_symbol_from =WRONG_VALUE; m_selected_symbol_to =WRONG_VALUE; } //+------------------------------------------------------------------+ //| Дезактивация поля ввода | //+------------------------------------------------------------------+ void CTextBox::DeactivateTextBox(void) { //--- Выйти, если уже дезактивировано if(!m_text_edit_state) return; //--- Дезактивировать m_text_edit_state=false; //--- Включим управление графиком m_chart.SetInteger(CHART_KEYBOARD_CONTROL,true); //--- Сброс выделения ResetSelectedText(); //--- Если многострочный режим отключен if(!m_multi_line_mode) { //--- Переместить курсор в начало строки SetTextCursor(0,0); //--- Сместить полосу прокрутки в начало строки HorizontalScrolling(0); } } //+------------------------------------------------------------------+ //| Ускоренная промотка полосы прокрутки | //+------------------------------------------------------------------+ void CTextBox::FastSwitching(void) { //--- Выйдем, если нет фокуса на элементе if(!CElementBase::MouseFocus()) return; //--- Вернём счётчик к первоначальному значению, если кнопка мыши отжата if(!m_mouse.LeftButtonState() || m_scrollv.State() || m_scrollh.State()) m_timer_counter=SPIN_DELAY_MSC; //--- Если же кнопка мыши нажата else { //--- Увеличим счётчик на установленный интервал m_timer_counter+=TIMER_STEP_MSC; //--- Выйдем, если меньше нуля if(m_timer_counter<0) return; //--- bool scroll_v=false,scroll_h=false; //--- Если прокрутка вверх if(m_scrollv.GetIncButtonPointer().MouseFocus()) { m_scrollv.OnClickScrollInc((uint)Id(),0); scroll_v=true; } //--- Если прокрутка вниз else if(m_scrollv.GetDecButtonPointer().MouseFocus()) { m_scrollv.OnClickScrollDec((uint)Id(),1); scroll_v=true; } //--- Если прокрутка влево else if(m_scrollh.GetIncButtonPointer().MouseFocus()) { m_scrollh.OnClickScrollInc((uint)Id(),2); scroll_h=true; } //--- Если прокрутка вправо else if(m_scrollh.GetDecButtonPointer().MouseFocus()) { m_scrollh.OnClickScrollDec((uint)Id(),3); scroll_h=true; } //--- Выйти, если ни одна кнопка не нажата if(!scroll_v && !scroll_h) return; //--- Смещает поле ввода ShiftData(); //--- Обновить полосы прокрутки if(scroll_v) m_scrollv.Update(true); if(scroll_h) m_scrollh.Update(true); } } //+------------------------------------------------------------------+ //| Рисует текст | //+------------------------------------------------------------------+ void CTextBox::Draw(void) { //--- Выводим текст CTextBox::TextOut(); //--- Рисуем рамку DrawBorder(); } //+------------------------------------------------------------------+ //| Обновление элемента | //+------------------------------------------------------------------+ void CTextBox::Update(const bool redraw=false) { //--- Перерисовать таблицу, если указано if(redraw) { //--- Нарисовать Draw(); //--- Применить m_canvas.Update(); m_textbox.Update(); return; } //--- Применить m_canvas.Update(); m_textbox.Update(); } //+------------------------------------------------------------------+ //| Вывод текста на холст | //+------------------------------------------------------------------+ void CTextBox::TextOut(void) { //--- Очистить холст m_textbox.Erase(AreaColorCurrent()); //--- Получим размер массива строк uint lines_total=::ArraySize(m_lines); //--- Корректировка в случае выхода из диапазона m_text_cursor_y_pos=(m_text_cursor_y_pos>=lines_total)? lines_total-1 : m_text_cursor_y_pos; //--- Получим размер массива символов uint symbols_total=::ArraySize(m_lines[m_text_cursor_y_pos].m_symbol); //--- Если включен многострочный режим или количество символов больше нуля if(m_multi_line_mode || symbols_total>0) { //--- Цвет текста uint text_color=TextColorCurrent(); //--- Получим ширину строки int line_width=(int)LineWidth(m_text_cursor_x_pos,m_text_cursor_y_pos); //--- Получим высоту строки и пройдёмся по всем строкам в цикле int line_height=(int)LineHeight(); m_textbox.FontSet(); for(uint i=0; i0) { if(i==symbols_total) break; } //--- ::StringAdd(m_temp_input_string,m_lines[line_index].m_symbol[i]); } //--- Вернуть собранную строку return(m_temp_input_string); } //+------------------------------------------------------------------+ //| Добавляет символ и его свойства в массивы структуры | //+------------------------------------------------------------------+ void CTextBox::AddSymbol(const string key_symbol) { //--- Получим размер массива символов uint symbols_total=::ArraySize(m_lines[m_text_cursor_y_pos].m_symbol); //--- Установим новый размер массивам ArraysResize(m_text_cursor_y_pos,symbols_total+1); //--- Сместить все символы от конца массива к индексу добавляемого символа MoveSymbols(m_text_cursor_y_pos,0,m_text_cursor_x_pos,false); //--- Получим ширину символа int width=m_textbox.TextWidth(key_symbol); //--- Добавить символ в освободившийся элемент m_lines[m_text_cursor_y_pos].m_symbol[m_text_cursor_x_pos] =key_symbol; m_lines[m_text_cursor_y_pos].m_width[m_text_cursor_x_pos] =width; //--- Увеличить счётчик позиции курсора m_text_cursor_x_pos++; } //+------------------------------------------------------------------+ //| Удаляет символ | //+------------------------------------------------------------------+ void CTextBox::DeleteSymbol(void) { //--- Получим размер массива символов uint symbols_total=::ArraySize(m_lines[m_text_cursor_y_pos].m_symbol); //--- Если массив пустой if(symbols_total<1) { //--- Установим курсор на нулевую позицию текщей строки SetTextCursor(0,m_text_cursor_y_pos); return; } //--- Получим позицию предыдущего символа int check_pos=(int)m_text_cursor_x_pos-1; //--- Выйти, если выход из диапазона if(check_pos<0) return; //--- Сместить все символы на один элемент влево от индекса удаляемого символа MoveSymbols(m_text_cursor_y_pos,m_text_cursor_x_pos,check_pos); //--- Уменьшить счётчик позиции курсора m_text_cursor_x_pos--; //--- Установим новый размер массивам ArraysResize(m_text_cursor_y_pos,symbols_total-1); } //+------------------------------------------------------------------+ //| Удаляет выделенный текст | //+------------------------------------------------------------------+ bool CTextBox::DeleteSelectedText(void) { //--- Выйти, если текст не выделен if(m_selected_line_from==WRONG_VALUE) return(false); //--- Если удаляются символы на одной строке if(m_selected_line_from==m_selected_line_to) DeleteTextOnOneLine(); //--- Если удаляются символы с нескольких строк else DeleteTextOnMultipleLines(); //--- Сброс выделенного текста ResetSelectedText(); //--- Рассчитать размеры поля ввода CalculateTextBoxSize(); //--- Установить новый размер полю ввода ChangeTextBoxSize(); //--- Корректируем полосы прокрутки CorrectingHorizontalScrollThumb(); CorrectingVerticalScrollThumb(); //--- Обновить текст в поле ввода DrawTextAndCursor(true); //--- Отправим сообщение об этом ::EventChartCustom(m_chart_id,ON_MOVE_TEXT_CURSOR,CElementBase::Id(),CElementBase::Index(),TextCursorInfo()); return(true); } //+------------------------------------------------------------------+ //| Удаляет выделенный на одной строке текст | //+------------------------------------------------------------------+ void CTextBox::DeleteTextOnOneLine(void) { int symbols_total =::ArraySize(m_lines[m_text_cursor_y_pos].m_symbol); int symbols_to_delete =::fabs(m_selected_symbol_from-m_selected_symbol_to); //--- Если начальный индекс символа справа if(m_selected_symbol_tom_selected_line_to) { //--- Скопируем в массив символы, которые нужно перенести string array[]; CopyWrapSymbols(m_selected_line_from,m_selected_symbol_from,symbols_to_delete_in_line_from,array); //--- Установим новый размер строке-приёмнику uint new_size=m_selected_symbol_to+symbols_to_delete_in_line_from; ArraysResize(m_selected_line_to,new_size); //--- Добавить данные в массивы структуры строки-приёмника PasteWrapSymbols(m_selected_line_to,m_selected_symbol_to,array); //--- Получим размер массива строк uint lines_total=::ArraySize(m_lines); //--- Сместим строки вверх на количество удаляемых строк MoveLines(m_selected_line_to+1,lines_total-lines_to_delete,lines_to_delete,false); //--- Установим новый размер массиву строк ::ArrayResize(m_lines,lines_total-lines_to_delete); } //--- Если начальная строка выше конечной else { //--- Скопируем в массив символы, которые нужно перенести string array[]; CopyWrapSymbols(m_selected_line_to,m_selected_symbol_to,symbols_to_delete_in_line_to,array); //--- Установим новый размер строке-приёмнику uint new_size=m_selected_symbol_from+symbols_to_delete_in_line_to; ArraysResize(m_selected_line_from,new_size); //--- Добавить данные в массивы структуры строки-приёмника PasteWrapSymbols(m_selected_line_from,m_selected_symbol_from,array); //--- Получим размер массива строк uint lines_total=::ArraySize(m_lines); //--- Сместим строки вверх на количество удаляемых строк MoveLines(m_selected_line_from+1,lines_total-lines_to_delete,lines_to_delete,false); //--- Установим новый размер массиву строк ::ArrayResize(m_lines,lines_total-lines_to_delete); //--- Переместить курсор на начальную позицию в выделении SetTextCursor(m_selected_symbol_from,m_selected_line_from); } } //+------------------------------------------------------------------+ //| Возвращает высоту строки | //+------------------------------------------------------------------+ uint CTextBox::LineHeight(void) { //--- Установим шрифт для отображения на холсте (нужно, чтобы получить высоту строки) m_textbox.FontSet(CElement::Font(),-CElement::FontSize()*10,FW_NORMAL); //--- Вернём высоту строки return(m_textbox.TextHeight("|")); } //+------------------------------------------------------------------+ //| Возвращает ширину строки от начала до указанной позиции | //+------------------------------------------------------------------+ uint CTextBox::LineWidth(const uint symbol_index,const uint line_index) { //--- Получим размер массива строк uint lines_total=::ArraySize(m_lines); //--- Предотвращение выхода из диапазона uint l=(line_indexmax_line_width) max_line_width=line_width; } //--- Вернуть максимальную ширину строки return(max_line_width); } //+------------------------------------------------------------------+ //| Смещает строки на одну позицию вверх | //+------------------------------------------------------------------+ void CTextBox::ShiftOnePositionUp(void) { //--- Если включен перенос слов if(m_word_wrap_mode) { //--- Индекс предыдущей строки uint prev_line_index=m_text_cursor_y_pos-1; //--- Получим размер массива символов uint symbols_total=::ArraySize(m_lines[prev_line_index].m_symbol); //--- Если предыдущая строка имеет признак окончания if(m_lines[prev_line_index].m_end_of_line) { //--- (1) Уберём признак окончания и (2) переместим текстовый курсор в конец строки m_lines[prev_line_index].m_end_of_line=false; SetTextCursor(symbols_total,prev_line_index); } else { //--- (1) Переместим текстовый курсор в конец строки и (2) удалим символ SetTextCursor(symbols_total,prev_line_index); DeleteSymbol(); } return; } //--- Получим размер массива строк uint lines_total=::ArraySize(m_lines); //--- Получим размер массива символов uint symbols_total=::ArraySize(m_lines[m_text_cursor_y_pos].m_symbol); //--- Если есть символы в этой строке, запомним их, чтобы добавить к предыдущей строке m_temp_input_string=(symbols_total>0)? CollectString(m_text_cursor_y_pos) : ""; //--- Сместим строки от следующего элемента на одну строку вверх MoveLines(m_text_cursor_y_pos,lines_total-1,1,false); //--- Установим новый размер массиву строк ::ArrayResize(m_lines,lines_total-1); //--- Уменьшим счётчик строк m_text_cursor_y_pos--; //--- Получим размер массива символов symbols_total=::ArraySize(m_lines[m_text_cursor_y_pos].m_symbol); //--- Переместим курсор в конец m_text_cursor_x_pos=symbols_total; //--- Получим X-координату курсора CalculateTextCursorX(); //--- Если есть строка, которую нужно добавить к предыдущей if(m_temp_input_string!="") AddToString(m_text_cursor_y_pos,m_temp_input_string); } //+------------------------------------------------------------------+ //| Смещает строки на одну позицию вниз | //+------------------------------------------------------------------+ void CTextBox::ShiftOnePositionDown(void) { //--- Получим размер массива строк uint lines_total=::ArraySize(m_lines); //--- Увеличим массив на один элемент uint new_size=lines_total+1; ::ArrayResize(m_lines,new_size); //--- Сместим строки от текущей позиции на один пункт вниз (начиная с конца массива) MoveLines(lines_total,m_text_cursor_y_pos+1,1); //--- Перенесём текст на новую строку WrapTextToNewLine(m_text_cursor_y_pos,m_text_cursor_x_pos,true); } //+------------------------------------------------------------------+ //| Проверка наличия выделенного текста | //+------------------------------------------------------------------+ bool CTextBox::CheckSelectedText(const uint line_index,const uint symbol_index) { bool is_selected_text=false; //--- Выйти, если нет выделенного текста if(m_selected_line_from==WRONG_VALUE) return(false); //--- Если начальный индекс на строке ниже if(m_selected_line_from>m_selected_line_to) { //--- Конечная строка и символ справа от конечного выделенного if((int)line_index==m_selected_line_to && (int)symbol_index>=m_selected_symbol_to) { is_selected_text=true; } //--- Начальная строка и символ слева от начального выделенного else if((int)line_index==m_selected_line_from && (int)symbol_indexm_selected_line_to && (int)line_index=m_selected_symbol_from) { is_selected_text=true; } //--- Промежуточная строка (выделяются все символы) else if((int)line_indexm_selected_line_from) { is_selected_text=true; } } //--- Если начальный и конечный индекс на одной строке else { //--- Нашли проверяемую строку if((int)line_index>=m_selected_line_to && (int)line_index<=m_selected_line_from) { //--- Если смещение курсора вправо и символ в выделенном диапазоне if(m_selected_symbol_from>m_selected_symbol_to) { if((int)symbol_index>=m_selected_symbol_to && (int)symbol_index=m_selected_symbol_from && (int)symbol_index0) { //--- Сместим его на предыдущий символ m_text_cursor_x-=m_lines[m_text_cursor_y_pos].m_width[m_text_cursor_x_pos-1]; //--- Уменьшим счётчик символов m_text_cursor_x_pos--; } else { //--- Если это не первая строка if(m_text_cursor_y_pos>0) { //--- Перейдём в конец предыдущей строки m_text_cursor_y_pos--; CorrectingTextCursorXPos(); } } return; } //--- Получим размер массива строк uint lines_total=::ArraySize(m_lines); //--- Получим количество символов в текущей строке uint symbols_total=::ArraySize(m_lines[m_text_cursor_y_pos].m_symbol); //--- Если курсор в начале текущей строки и это не первая строка, // переместим курсор в конец предыдущей строки if(m_text_cursor_x_pos==0 && m_text_cursor_y_pos>0) { //--- Получим индекс предыдущей строки uint prev_line_index=m_text_cursor_y_pos-1; //--- Получим количество символов предыдущей строки symbols_total=::ArraySize(m_lines[prev_line_index].m_symbol); //--- Переместим курсор в конец предыдущей строки SetTextCursor(symbols_total,prev_line_index); } //--- Если курсор не в начале текущей строки или курсор на первой строке else { //--- Найдём начало непрерывной последовательности символов (справа налево) for(uint i=m_text_cursor_x_pos; i<=symbols_total; i--) { //--- Перейти к следующему, если курсор в конце строки if(i==symbols_total) continue; //--- Если это первый символ строки if(i==0) { //--- Установим курсор в начало строки SetTextCursor(0,m_text_cursor_y_pos); break; } //--- Если это не первый символ строки else { //--- Если нашли начало непрерывной последовательности, на которой впервые. // Началом считается пробел на следующем индексе. if(i!=m_text_cursor_x_pos && m_lines[m_text_cursor_y_pos].m_symbol[i]!=SPACE && m_lines[m_text_cursor_y_pos].m_symbol[i-1]==SPACE) { //--- Установим курсор в начало новой непрерывной последовательности SetTextCursor(i,m_text_cursor_y_pos); break; } } } } } //+------------------------------------------------------------------+ //| Перемещение текстового курсора на один символ вправо | //+------------------------------------------------------------------+ void CTextBox::MoveTextCursorToRight(const bool to_next_word=false) { //--- Если перейти к следующему символу if(!to_next_word) { //--- Получим размер массива символов uint symbols_total=::ArraySize(m_lines[m_text_cursor_y_pos].m_width); //--- Если это не конец строки if(m_text_cursor_x_pos=symbols_total-1) { SetTextCursor(symbols_total,m_text_cursor_y_pos); break; } //--- Если нашли начало непрерывной последовательности, на которой впервые. // Началом считается пробел на предыдущем индексе. if(i!=m_text_cursor_x_pos && m_lines[m_text_cursor_y_pos].m_symbol[i]!=SPACE && m_lines[m_text_cursor_y_pos].m_symbol[i-1]==SPACE) { //--- Установим курсор в конец новой непрерывной последовательности SetTextCursor(i,m_text_cursor_y_pos); break; } } } } //+------------------------------------------------------------------+ //| Перемещение текстового курсора на одну строку вверх | //+------------------------------------------------------------------+ void CTextBox::MoveTextCursorToUp(void) { //--- Получим размер массива строк uint lines_total=::ArraySize(m_lines); //--- Если не выходим за пределы массива if(m_text_cursor_y_pos-1=y_offset && y=y_offset; //--- Если нажатие было не на этой строке, перейти к следующей if(!y_pos_check) continue; //--- Получим размер массива символов uint symbols_total=::ArraySize(m_lines[l].m_width); //--- Если это пустая строка, переместить курсор на указанную позицию и выйти из цикла if(symbols_total<1) { SetTextCursor(0,l); HorizontalScrolling(0); break; } //--- Найдём символ, на который нажали for(uint s=0; s=x_offset && xx_offset) { SetTextCursor(s+1,l); l=lines_total; break; } } } } //+------------------------------------------------------------------+ //| Корректировка текстового курсора по оси X | //+------------------------------------------------------------------+ void CTextBox::CorrectingTextCursorXPos(const int x_pos=WRONG_VALUE) { //--- Получим размер массива символов uint symbols_total=::ArraySize(m_lines[m_text_cursor_y_pos].m_width); //--- Опеределим позицию курсора uint text_cursor_x_pos=0; //--- Если позиция указана if(x_pos!=WRONG_VALUE) text_cursor_x_pos=(x_pos>(int)symbols_total-1)? symbols_total : x_pos; //--- Если позиция не указана, то установим курсор в конец строки else text_cursor_x_pos=symbols_total; //--- Нулевая позиция, если в строке нет символов m_text_cursor_x_pos=(symbols_total<1)? 0 : text_cursor_x_pos; //--- Получим X-координату курсора CalculateTextCursorX(); } //+------------------------------------------------------------------+ //| Расчёт X-координаты для текстового курсора | //+------------------------------------------------------------------+ void CTextBox::CalculateTextCursorX(void) { //--- Получим ширину строки int line_width=(int)LineWidth(m_text_cursor_x_pos,m_text_cursor_y_pos); //--- Рассчитать и сохранить X-координату курсора m_text_cursor_x=m_text_x_offset+line_width; } //+------------------------------------------------------------------+ //| Расчёт Y-координаты для текстового курсора | //+------------------------------------------------------------------+ void CTextBox::CalculateTextCursorY(void) { //--- Получим высоту строки int line_height=(int)LineHeight(); //--- Получим Y-координату курсора m_text_cursor_y=m_text_y_offset+int(line_height*m_text_cursor_y_pos); } //+------------------------------------------------------------------+ //| Расчёт границ поля ввода по двум осям | //+------------------------------------------------------------------+ void CTextBox::CalculateBoundaries(void) { CalculateXBoundaries(); CalculateYBoundaries(); } //+------------------------------------------------------------------+ //| Расчёт границ поля ввода по оси X | //+------------------------------------------------------------------+ void CTextBox::CalculateXBoundaries(void) { //--- Получим X-координату и смещение по оси X int x =(int)::ObjectGetInteger(m_chart_id,m_textbox.ChartObjectName(),OBJPROP_XDISTANCE); int xoffset =(int)::ObjectGetInteger(m_chart_id,m_textbox.ChartObjectName(),OBJPROP_XOFFSET); //--- Рассчитаем границы видимой части поля ввода m_x_limit =(x+xoffset)-x; m_x2_limit =(m_multi_line_mode)? (x+xoffset+m_x_size-m_scrollv.ScrollWidth()-m_text_x_offset)-x : (x+xoffset+m_x_size-m_text_x_offset)-x; } //+------------------------------------------------------------------+ //| Расчёт границ поля ввода по оси Y | //+------------------------------------------------------------------+ void CTextBox::CalculateYBoundaries(void) { //--- Выйти, если отключен многострочный режим if(!m_multi_line_mode) return; //--- Получим Y-координату и смещение по оси Y int y =(int)::ObjectGetInteger(m_chart_id,m_textbox.ChartObjectName(),OBJPROP_YDISTANCE); int yoffset =(int)::ObjectGetInteger(m_chart_id,m_textbox.ChartObjectName(),OBJPROP_YOFFSET); //--- Рассчитаем границы видимой части поля ввода m_y_limit =(y+yoffset)-y; m_y2_limit =(y+yoffset+m_y_size-m_scrollh.ScrollWidth())-y; } //+------------------------------------------------------------------+ //| Расчёт X-координаты полосы прокрутки в левой границе поля ввода | //+------------------------------------------------------------------+ int CTextBox::CalculateScrollThumbX(void) { return(m_text_cursor_x-m_text_x_offset); } //+------------------------------------------------------------------+ //| Расчёт X-координаты полосы прокрутки в правой границе поля ввода | //+------------------------------------------------------------------+ int CTextBox::CalculateScrollThumbX2(void) { return((m_multi_line_mode)? m_text_cursor_x-m_x_size+m_scrollv.ScrollWidth()+m_text_x_offset : m_text_cursor_x-m_x_size+m_text_x_offset*2); } //+------------------------------------------------------------------+ //| Расчёт X-позиции ползунка полосы прокрутки | //+------------------------------------------------------------------+ int CTextBox::CalculateScrollPosX(const bool to_right=false) { int calc_x =(!to_right)? CalculateScrollThumbX() : CalculateScrollThumbX2(); double pos_x_value =(calc_x-::fmod((double)calc_x,(double)m_shift_x_step))/m_shift_x_step+((!to_right)? 0 : 1); //--- return((int)pos_x_value); } //+------------------------------------------------------------------+ //| Расчёт Y-координаты полосы прокрутки в верхней границе поля ввода| //+------------------------------------------------------------------+ int CTextBox::CalculateScrollThumbY(void) { return(m_text_cursor_y-m_text_y_offset); } //+------------------------------------------------------------------+ //| Расчёт Y-координаты полосы прокрутки в нижней границе поля ввода | //+------------------------------------------------------------------+ int CTextBox::CalculateScrollThumbY2(void) { //--- Установим шрифт для отображения на холсте (нужно, чтобы получить высоту строки) m_textbox.FontSet(CElement::Font(),-CElement::FontSize()*10,FW_NORMAL); //--- Получим высоту строки int line_height=m_textbox.TextHeight("|"); //--- Рассчитать и вернуть значение return(m_text_cursor_y-m_y_size+m_scrollh.ScrollWidth()+m_text_y_offset+line_height); } //+------------------------------------------------------------------+ //| Расчёт Y-позиции ползунка полосы прокрутки | //+------------------------------------------------------------------+ int CTextBox::CalculateScrollPosY(const bool to_down=false) { int calc_y =(!to_down)? CalculateScrollThumbY() : CalculateScrollThumbY2(); double pos_y_value =(calc_y-::fmod((double)calc_y,(double)LineHeight()))/LineHeight()+((!to_down)? 0 : 1); //--- return((int)pos_y_value); } //+------------------------------------------------------------------+ //| Корректировка горизонтальной полосы прокрутки | //+------------------------------------------------------------------+ void CTextBox::CorrectingHorizontalScrollThumb(void) { //--- Получим границы видимой части поля ввода CalculateXBoundaries(); //--- Получим X-координату курсора CalculateTextCursorX(); //--- Если текстовый курсор вышел из поля видимости влево if(m_text_cursor_x<=m_x_limit) { HorizontalScrolling(CalculateScrollPosX()); } //--- Если текстовый курсор вышел из поля видимости вправо else if(m_text_cursor_x>=m_x2_limit) { HorizontalScrolling(CalculateScrollPosX(true)); } } //+------------------------------------------------------------------+ //| Корректировка вертикальной полосы прокрутки | //+------------------------------------------------------------------+ void CTextBox::CorrectingVerticalScrollThumb(void) { //--- Получим границы видимой части поля ввода CalculateYBoundaries(); //--- Получим Y-координату курсора CalculateTextCursorY(); //--- Если текстовый курсор вышел из поля видимости вверх if(m_text_cursor_y<=m_y_limit) { VerticalScrolling(CalculateScrollPosY()); } //--- Если текстовый курсор вышел из поля видимости вниз else if(m_text_cursor_y+(int)LineHeight()>=m_y2_limit) { VerticalScrolling(CalculateScrollPosY(true)); } } //+------------------------------------------------------------------+ //| Рассчитывает размеры текстового поля ввода | //+------------------------------------------------------------------+ void CTextBox::CalculateTextBoxSize(void) { CalculateTextBoxXSize(); CalculateTextBoxYSize(); } //+------------------------------------------------------------------+ //| Рассчитывает ширину текстового поля ввода | //+------------------------------------------------------------------+ bool CTextBox::CalculateTextBoxXSize(void) { //--- Запомним текущие размеры int area_x_size_curr=m_area_x_size; //--- Получим максимальную ширину строки из текстового поля ввода int max_line_width=int((m_text_x_offset*2)+MaxLineWidth()+m_scrollv.ScrollWidth()); //--- Определим общую ширину m_area_x_size=(max_line_width>m_x_size)? max_line_width : m_x_size; //--- Определим видимую ширину m_area_visible_x_size=m_x_size-2; //--- Сохраним ограничение по смещению m_shift_x2_limit=m_area_x_size-m_area_visible_x_size; //--- Признак того, что размеры не изменились if(area_x_size_curr==m_area_x_size) return(false); //--- Признак того, что размеры были изменились return(true); } //+------------------------------------------------------------------+ //| Рассчитывает высоту текстового поля ввода |4 //+------------------------------------------------------------------+ bool CTextBox::CalculateTextBoxYSize(void) { //--- Запомним текущие размеры int area_y_size_curr=m_area_y_size; //--- Получим высоту строки int line_height=(int)LineHeight(); //--- Получим размер массива строк int lines_total=::ArraySize(m_lines); //--- Рассчитаем общую высоту элемента int lines_height=int((m_text_y_offset*2)+(line_height*lines_total)+m_scrollh.ScrollWidth());//*2); //--- Определим общую высоту m_area_y_size=(m_multi_line_mode && lines_height>m_y_size)? lines_height : m_y_size; //--- Определим видимую высоту m_area_visible_y_size=m_y_size-2; //--- Сохраним ограничение по смещению m_shift_y2_limit=m_area_y_size-m_area_visible_y_size; //--- Признак того, что размеры не изменились if(area_y_size_curr==m_area_y_size) return(false); //--- Признак того, что размеры были изменились return(true); } //+------------------------------------------------------------------+ //| Изменить основные размеры элемента | //+------------------------------------------------------------------+ void CTextBox::ChangeMainSize(const int x_size,const int y_size) { //--- Установить новый размер CElementBase::XSize(x_size); CElementBase::YSize(y_size); m_canvas.XSize(m_x_size); m_canvas.YSize(m_y_size); m_canvas.Resize(m_x_size,m_y_size); } //+------------------------------------------------------------------+ //| Изменить размеры поля ввода | //+------------------------------------------------------------------+ void CTextBox::ChangeTextBoxSize(const bool is_x_offset=false,const bool is_y_offset=false) { //--- Установить новый размер таблице m_textbox.XSize(m_area_x_size); m_textbox.YSize(m_area_y_size); m_textbox.Resize(m_area_x_size,m_area_y_size); //--- Установим размеры видимой области ::ObjectSetInteger(m_chart_id,m_textbox.ChartObjectName(),OBJPROP_XSIZE,m_area_visible_x_size); ::ObjectSetInteger(m_chart_id,m_textbox.ChartObjectName(),OBJPROP_YSIZE,m_area_visible_y_size); //--- Разница между общей шириной и видимой частью int x_different =m_area_x_size-m_area_visible_x_size; int y_different =m_area_y_size-m_area_visible_y_size; //--- Зададим смещение фрейма внутри изображения по осям X и Y int x_offset =(int)::ObjectGetInteger(m_chart_id,m_textbox.ChartObjectName(),OBJPROP_XOFFSET); int y_offset =(int)::ObjectGetInteger(m_chart_id,m_textbox.ChartObjectName(),OBJPROP_YOFFSET); int x_offset2 =(!is_x_offset)? 0 : (x_offset<=x_different)? x_offset : x_different; int y_offset2 =(!is_y_offset)? 0 : (y_offset<=y_different)? y_offset : y_different; ::ObjectSetInteger(m_chart_id,m_textbox.ChartObjectName(),OBJPROP_XOFFSET,x_offset2); ::ObjectSetInteger(m_chart_id,m_textbox.ChartObjectName(),OBJPROP_YOFFSET,y_offset2); //--- Изменить размеры полос прокрутки ChangeScrollsSize(); //--- Перенос по словам WordWrap(); //--- Корректировка данных ShiftData(); } //+------------------------------------------------------------------+ //| Изменить размеры полос прокрутки | //+------------------------------------------------------------------+ void CTextBox::ChangeScrollsSize(void) { //--- Расчёт количества шагов для смещения uint x_size_total =m_area_x_size/m_shift_x_step; uint visible_x_size_total =m_area_visible_x_size/m_shift_x_step; uint y_size_total =LinesTotal()+1; uint visible_y_size_total =VisibleLinesTotal(); //--- Рассчитать размеры полос прокрутки m_scrollh.Reinit(x_size_total,visible_x_size_total); m_scrollv.Reinit(y_size_total,visible_y_size_total); //--- Выйти, если это однострочное поле ввода if(!m_multi_line_mode) return; //--- Если (1) горизонтальная полоса прокрутки не нужна или (2) включен перенос по словам if(!m_scrollh.IsScroll() || m_word_wrap_mode) { HorizontalScrolling(0); //--- Скрыть горизонтальную полосу прокрутки m_scrollh.Hide(); //--- Изменить высоту вертикальной полосы прокрутки if(m_multi_line_mode) m_scrollv.ChangeYSize(CElementBase::YSize()-2); } else { //--- Показать горизонтальную полосу прокрутки if(CElementBase::IsVisible()) { m_scrollh.Show(); m_scrollh.GetIncButtonPointer().Show(); m_scrollh.GetDecButtonPointer().Show(); //--- Отправим сообщение об изменении в графическом интерфейсе ::EventChartCustom(m_chart_id,ON_CHANGE_GUI,CElementBase::Id(),0,""); } //--- Рассчитать и изменить высоту вертикальной полосы прокрутки if(m_multi_line_mode) m_scrollv.ChangeYSize(CElementBase::YSize()-m_scrollh.ScrollWidth()-2); } //--- Если вертикальная полоса прокрутки не нужна if(!m_scrollv.IsScroll()) { VerticalScrolling(0); //--- Скрыть вертикальную полосу прокрутки m_scrollv.Hide(); //--- Изменить ширину горизонтальной полосы прокрутки, если отключен перенос по словам if(!m_word_wrap_mode) m_scrollh.ChangeXSize(CElementBase::XSize()-1); } else { //--- Показать вертикальную полосу прокрутки if(CElementBase::IsVisible()) { m_scrollv.Show(); m_scrollv.GetIncButtonPointer().Show(); m_scrollv.GetDecButtonPointer().Show(); //--- Отправим сообщение об изменении в графическом интерфейсе ::EventChartCustom(m_chart_id,ON_CHANGE_GUI,CElementBase::Id(),0,""); } //--- Изменить ширину горизонтальной полосы прокрутки, если отключен перенос по словам if(!m_word_wrap_mode) m_scrollh.ChangeXSize(CElementBase::XSize()-m_scrollh.ScrollWidth()-1); } } //+------------------------------------------------------------------+ //| Перенос по словам | //+------------------------------------------------------------------+ void CTextBox::WordWrap(void) { //--- Выйти, если режимы (1) многострочного поля ввода или (2) переноса по словам отключены if(!m_multi_line_mode || !m_word_wrap_mode) return; //--- Получим размер массива строк uint lines_total=::ArraySize(m_lines); //--- Проверим, нужно ли выровнять текст по ширине поля ввода for(uint i=0; i=lines_total) continue; //--- Определим количество символов для переноса uint wrap_symbols_total=0; //--- Если нужно перенести оставшийся текст следующей строки на текущую if(WrapSymbolsTotal(i,wrap_symbols_total)) { WrapTextToPrevLine(next_line_index,wrap_symbols_total,true); //--- Обновить размер массива для дальнейшего использования в цикле lines_total=::ArraySize(m_lines); //--- Шаг назад, чтобы избежать пропуск строки для следующей проверки i--; } //--- Перенести только то, что помещается else WrapTextToPrevLine(next_line_index,wrap_symbols_total); } } } //+------------------------------------------------------------------+ //| Проверка на переполнение строки | //+------------------------------------------------------------------+ bool CTextBox::CheckForOverflow(const uint line_index,int &symbol_index,int &space_index) { //--- Получим размер массива символов uint symbols_total=::ArraySize(m_lines[line_index].m_symbol); //--- Отступы uint x_offset_plus=m_text_x_offset+m_scrollv.XSize(); //--- Получим полную ширину строки uint full_line_width=LineWidth(symbols_total,line_index)+x_offset_plus; //--- Если ширина этой строки помещается в поле if(full_line_width<(uint)m_area_visible_x_size) return(false); //--- Определим индексы символов переполнения for(uint s=symbols_total-1; s>0; s--) { //--- Получим (1) ширину подстроки от начала до текущего символа и (2) символ uint line_width =LineWidth(s,line_index)+x_offset_plus; string symbol =m_lines[line_index].m_symbol[s]; //--- Если ещё не нашли видимый символ if(symbol_index==WRONG_VALUE) { //--- Если ширина подстроки помещается в область поля ввода, запомним индекс символа if(line_width<(uint)m_area_visible_x_size) symbol_index=(int)s; //--- Перейти к следующему символу continue; } //--- Если это пробел, запомним его индекс и остановим цикл if(symbol==SPACE) { space_index=(int)s; break; } } //--- Выполнение условия означает, что строка не помещается bool is_overflow=(symbol_index!=WRONG_VALUE || space_index!=WRONG_VALUE); //--- Вернуть результат return(is_overflow); } //+------------------------------------------------------------------+ //| Возвращает количество слов в указанной строке | //+------------------------------------------------------------------+ uint CTextBox::WordsTotal(const uint line_index) { //--- Получим размер массива строк uint lines_total=::ArraySize(m_lines); //--- Предотвращение выхода из диапазона uint l=(line_indexfree_space && m_lines[line_index].m_symbol[symbols_total-1]!=SPACE && m_lines[next_line_index].m_symbol[next_line_symbols_total-1]!=SPACE) { //--- Определить количество символов, которые можно перенести со следующей строки for(uint s=next_line_symbols_total-1; s>=0; s--) { //--- Получим ширину подстроки от начала до указанного символа uint substring_width=LineWidth(s,next_line_index); //--- Если подстрока не помещается в свободное пространство указанного контейнера, перейти к следующему символу if(substring_width>=free_space) continue; //--- Если подстрока помещается, запомним значение и остановимся wrap_symbols_total=s; break; } } //--- Вернуть истину, если нужно перенести весь текст return(is_all_text); } //+------------------------------------------------------------------+ //| Возвращает индекс символа пробела по его номеру | //+------------------------------------------------------------------+ uint CTextBox::SymbolIndexBySpaceNumber(const uint line_index,const uint space_index) { //--- Получим размер массива строк uint lines_total=::ArraySize(m_lines); //--- Предотвращение выхода из диапазона uint l=(line_indexto_index; i--) { //--- Индекс предыдущего элемента массива строк uint prev_index=i-count; //--- Получим размер массива символов uint symbols_total=::ArraySize(m_lines[prev_index].m_symbol); //--- Установим новый размер массивам ArraysResize(i,symbols_total); //--- Сделать копию строки LineCopy(i,prev_index); //--- Если это последняя итерация if(prev_index==to_index) { //--- Выйти, если это первая строка if(to_index<1) break; } } } //--- Смещение строк по направлению вверх else { for(uint i=from_index; ito_pos; s--) { uint i=s-1; m_lines[line_index].m_symbol[s] =m_lines[line_index].m_symbol[i]; m_lines[line_index].m_width[s] =m_lines[line_index].m_width[i]; } } } //+------------------------------------------------------------------+ //| Добавляет текст в указанную строку | //+------------------------------------------------------------------+ void CTextBox::AddToString(const uint line_index,const string text) { //--- Переносим строку в массив uchar array[]; int total=::StringToCharArray(text,array)-1; if(total<0) return; //--- Получим размер массива символов uint symbols_total=::ArraySize(m_lines[line_index].m_symbol); //--- Установим новый размер массивам uint new_size=symbols_total+total; ArraysResize(line_index,new_size); //--- Добавить данные в массивы структуры for(uint i=symbols_total; i= (int)(start_pos + total); i--) { uint source_index = i - total; m_lines[line_index].m_symbol[i] = m_lines[line_index].m_symbol[source_index]; m_lines[line_index].m_width[i] = m_lines[line_index].m_width[source_index]; } //--- for(uint i = 0; i < uint(total); i++) { uint target_index = start_pos + i; m_lines[line_index].m_symbol[target_index] = ::CharToString(array[i]); m_lines[line_index].m_width[target_index] = m_textbox.TextWidth(m_lines[line_index].m_symbol[target_index]); } } //+------------------------------------------------------------------+ //| Копирует в переданный массив символы для переноса | //+------------------------------------------------------------------+ void CTextBox::CopyWrapSymbols(const uint line_index,const uint start_pos,const uint symbols_total,string &array[]) { //--- Установим размер массиву ::ArrayResize(array,symbols_total); //--- Скопируем в массив символы, которые нужно перенести for(uint i=0; ilast_symbol_index && symbol_index!=symbols_total)? last_symbol_index : symbol_index; //--- Индекс следующей строки uint next_line_index=line_index+1; //--- Количество символов, которые нужно перенести на новую строку uint new_line_size=symbols_total-check_symbol_index; //--- Скопируем в массив символы, которые нужно перенести string array[]; CopyWrapSymbols(line_index,check_symbol_index,new_line_size,array); //--- Установим новый размер массивам структуры в строке ArraysResize(line_index,symbols_total-new_line_size); //--- Установим новый размер массивам структуры в новой строке ArraysResize(next_line_index,new_line_size); //--- Добавить данные в массивы структуры новой строки PasteWrapSymbols(next_line_index,0,array); //--- Определим новое положение текстового курсора int x_pos=int(new_line_size-(symbols_total-m_text_cursor_x_pos)); m_text_cursor_x_pos =(x_pos<0)? (int)m_text_cursor_x_pos : x_pos; m_text_cursor_y_pos =(x_pos<0)? (int)line_index : (int)next_line_index; //--- Если указано, что вызов по нажатию на клавише Enter if(by_pressed_enter) { //--- Если строка имела признак окончания, то ставим признак окончания текущей и следующей if(m_lines[line_index].m_end_of_line) { m_lines[line_index].m_end_of_line =true; m_lines[next_line_index].m_end_of_line =true; } //--- Если нет, то только текущей else { m_lines[line_index].m_end_of_line =true; m_lines[next_line_index].m_end_of_line =false; } } else { //--- Если строка имела признак окончания, то продолжаем и устанавливаем признак на следующей строке if(m_lines[line_index].m_end_of_line) { m_lines[line_index].m_end_of_line =false; m_lines[next_line_index].m_end_of_line =true; } //--- Если строка не имела признак окончания, то продолжаем в обеих строках else { m_lines[line_index].m_end_of_line =false; m_lines[next_line_index].m_end_of_line =false; } } } //+------------------------------------------------------------------+ //| Перенос текста из следующей строки в текущую | //+------------------------------------------------------------------+ void CTextBox::WrapTextToPrevLine(const uint next_line_index,const uint wrap_symbols_total,const bool is_all_text=false) { //--- Получим размер массива символов из строки uint symbols_total=::ArraySize(m_lines[next_line_index].m_symbol); //--- Индекс предыдущей строки uint prev_line_index=next_line_index-1; //--- Скопируем в массив символы, которые нужно перенести string array[]; CopyWrapSymbols(next_line_index,0,wrap_symbols_total,array); //--- Получим размер массива символов из предыдущей строки uint prev_line_symbols_total=::ArraySize(m_lines[prev_line_index].m_symbol); //--- Увеличим размер массива предыдущей строки на добавляемое количество символов uint new_prev_line_size=prev_line_symbols_total+wrap_symbols_total; ArraysResize(prev_line_index,new_prev_line_size); //--- Добавить данные в массивы структуры новой строки PasteWrapSymbols(prev_line_index,new_prev_line_size-wrap_symbols_total,array); //--- Сместим символы на освободившееся место в текущей строке MoveSymbols(next_line_index,wrap_symbols_total,0); //--- Уменьшим размер массива текущей строки на извлечённое из неё количество символов ArraysResize(next_line_index,symbols_total-wrap_symbols_total); //--- Скорректировать текстовый курсор if((is_all_text && next_line_index==m_text_cursor_y_pos) || (!is_all_text && next_line_index==m_text_cursor_y_pos && wrap_symbols_total>0)) { m_text_cursor_x_pos=new_prev_line_size-(wrap_symbols_total-m_text_cursor_x_pos); m_text_cursor_y_pos--; } //--- Выйти, если это не весь оставшийся текст строки if(!is_all_text) return; //--- Добавить признак оконачания для предыдущей строки, если у текущей строки он тоже есть if(m_lines[next_line_index].m_end_of_line) m_lines[next_line_index-1].m_end_of_line=true; //--- Получим размер массива строк uint lines_total=::ArraySize(m_lines); //--- Сместим строки на одну вверх MoveLines(next_line_index,lines_total-1,1,false); //--- Установим новый размер массиву строк ::ArrayResize(m_lines,lines_total-1); } //+------------------------------------------------------------------+ //| Изменить ширину по правому краю формы | //+------------------------------------------------------------------+ void CTextBox::ChangeWidthByRightWindowSide(void) { //--- Выйти, если включен режим фиксации к правому краю формы if(m_anchor_right_window_side) return; //--- Координаты int x=0; //--- Размеры int x_size =m_main.X2()-CElementBase::X()-m_auto_xresize_right_offset; int y_size =(m_auto_yresize_mode)? m_main.Y2()-CElementBase::Y()-m_auto_yresize_bottom_offset : m_y_size; //--- Установить новый размер ChangeMainSize(x_size,y_size); //--- Рассчитать размеры поля ввода CalculateTextBoxSize(); //--- Установить новый размер полю ввода ChangeTextBoxSize(); //--- В режиме переноса слов нужно повторно пересчитать и установить размеры if(m_word_wrap_mode) { CalculateTextBoxSize(); ChangeTextBoxSize(); } //--- Нарисовать текст и дезактивировать поле ввода DeactivateTextBox(); //--- Перерисовать элемент Draw(); if(m_scrollh.IsScroll()) m_scrollh.Update(true); if(m_scrollv.IsScroll()) m_scrollv.Update(true); } //+------------------------------------------------------------------+ //| Изменить высоту по нижнему краю окна | //+------------------------------------------------------------------+ void CTextBox::ChangeHeightByBottomWindowSide(void) { //--- Выйти, если включен режим фиксации к нижнему краю формы if(m_anchor_bottom_window_side) return; //--- Координаты int y=0; //--- Размеры int x_size =(m_auto_xresize_mode)? m_main.X2()-CElementBase::X()-m_auto_xresize_right_offset : m_x_size; int y_size =m_main.Y2()-CElementBase::Y()-m_auto_yresize_bottom_offset; //--- Установить новый размер ChangeMainSize(x_size,y_size); //--- Рассчитать размеры поля ввода CalculateTextBoxSize(); //--- Установить новый размер полю ввода ChangeTextBoxSize(); //--- Нарисовать текст и дезактивировать поле ввода DeactivateTextBox(); //--- Перерисовать элемент Draw(); if(m_scrollh.IsScroll()) m_scrollh.Update(true); if(m_scrollv.IsScroll()) m_scrollv.Update(true); } //+------------------------------------------------------------------+