//+------------------------------------------------------------------+ //| Table.mqh | //| Copyright 2015, MetaQuotes Software Corp. | //| http://www.mql5.com | //+------------------------------------------------------------------+ #include "..\Element.mqh" #include "Pointer.mqh" #include "Scrolls.mqh" #include "TextEdit.mqh" #include "ComboBox.mqh" //+------------------------------------------------------------------+ //| Класс для создания нарисованной таблицы | //+------------------------------------------------------------------+ class CTable : public CElement { private: //--- Объекты для создания таблицы CRectCanvas m_headers; CRectCanvas m_table; CScrollV m_scrollv; CScrollH m_scrollh; CTextEdit m_edit; CComboBox m_combobox; CPointer m_column_resize; //--- Свойства ячеек таблицы struct CTCell { ENUM_TYPE_CELL m_type; // Тип ячейки CImage m_images[]; // Массив изображений int m_selected_image; // Индекс выбранной (отображаемой) картинки string m_full_text; // Полный текст string m_short_text; // Сокращённый текст string m_value_list[]; // Массив значений (для ячеек с комбо-боксами) int m_selected_item; // Выбранный пункт в списке комбо-бокса color m_text_color; // Цвет текста color m_back_color; // Цвет фона uint m_digits; // Количество знаков после запятой }; //--- Массив строк и свойства столбцов таблицы struct CTOptions { int m_x; // X-координата левого края столбца int m_x2; // X-координата правого края столбца int m_width; // Ширина столбца ENUM_DATATYPE m_data_type; // Тип данных в столбце ENUM_ALIGN_MODE m_text_align; // Способ выравнивания текста в ячейках столбца int m_text_x_offset; // Отступ текста int m_image_x_offset; // Отступ картинки от X-края ячейки int m_image_y_offset; // Отступ картинки от Y-края ячейки string m_header_text; // Текст заголовка столбца CTCell m_rows[]; // Массив строк таблицы }; CTOptions m_columns[]; //--- Массив свойств строк таблицы struct CTRowOptions { int m_y; // Y-координата верхнего края строки int m_y2; // Y-координата нижнего края строки }; CTRowOptions m_rows[]; //--- Количество строк и столбцов uint m_rows_total; uint m_columns_total; //--- Общий размер и размер видимой части таблицы int m_table_x_size; int m_table_y_size; int m_table_visible_x_size; int m_table_visible_y_size; //--- Наличие ячеек с полями ввода и комбо-боксами bool m_edit_state; bool m_combobox_state; //--- Индексы столбца и ряда последней редактированной ячейки int m_last_edit_row_index; int m_last_edit_column_index; //--- Минимальная ширина для столбцов int m_min_column_width; //--- Значения по умолчанию: (1) ширина, (2) тип данных, (3) выравнивание текста int m_default_width; ENUM_DATATYPE m_default_type_data; ENUM_ALIGN_MODE m_default_text_align; //--- Цвет сетки color m_grid_color; //--- Режим показа заголовков таблицы bool m_show_headers; //--- Размер (высота) заголовков int m_header_y_size; //--- Цвет заголовков (фон) в разных состояниях color m_headers_color; color m_headers_color_hover; color m_headers_color_pressed; //--- Цвет текста заголовков color m_headers_text_color; //--- Ярлыки для признака отсортированных данных CImage m_sort_arrows[]; //--- Отступы для ярлыка-признака отсортированных данных int m_sort_arrow_x_gap; int m_sort_arrow_y_gap; //--- Размер (высота) ячеек int m_cell_y_size; //--- Цвет ячеек в разных состояниях color m_cell_color; color m_cell_color_hover; //--- Цвет (1) фона и (2) текста выделенной строки color m_selected_row_color; color m_selected_row_text_color; //--- (1) Индекс и (2) текст выделенной строки int m_selected_item; string m_selected_item_text; //--- Индекс предыдущего выделенной строки int m_prev_selected_item; //--- Отступ от границ разделительных линий для показа указателя мыши в режиме изменения ширины столбцов int m_sep_x_offset; //--- Режим подсветки строки при наведении курсора мыши bool m_lights_hover; //--- Режим сортируемых данных по столбцам bool m_is_sort_mode; //--- Индекс отсортированного столбца (WRONG_VALUE - таблица не отсортирована) int m_is_sorted_column_index; //--- Последнее направление сортировки ENUM_CSORT_MODE m_last_sort_direction; //--- Режим выделяемой строки bool m_selectable_row; //--- Без отмены выделения строки при повторном нажатии bool m_is_without_deselect; //--- Режим форматирования в стиле "Зебра" color m_is_zebra_format_rows; //--- Состояние левой кнопки мыши (зажата/отжата) bool m_mouse_state; //--- Счётчик таймера для перемотки списка int m_timer_counter; //--- Для определения фокуса строки int m_item_index_focus; //--- Для определение момента перехода курсора мыши с одной строки на другую int m_prev_item_index_focus; //--- Для определение момента перехода курсора мыши с одного заголовка на другой int m_prev_header_index_focus; //--- Авторазмер столбцов bool m_autoresize_columns; //--- Режим авто-ширина столбцов (по максимальной ширине текста в столбце) bool m_auto_correct_columns_width_mode; //--- Режим изменения ширины столбцов bool m_column_resize_mode; //--- Состояние захвата границы заголовка для изменения ширины столбца int m_column_resize_control; //--- Вспомогательные поля для расчётов в изменении ширины столбцов int m_column_resize_x_fixed; int m_column_resize_prev_width; int m_column_resize_prev_thumb; //--- Для определения индексов видимой части таблицы uint m_visible_table_from_index; uint m_visible_table_to_index; //--- Размер шага для смещения по горизонтали int m_shift_x_step; //--- Ограничения на смещение int m_shift_x2_limit; int m_shift_y2_limit; //--- Отключение показа полос прокрутки bool m_is_disabled_scrolls; //--- public: CTable(void); ~CTable(void); //--- Методы для создания таблицы bool CreateTable(const int x_gap,const int y_gap); //--- private: void InitializeProperties(const int x_gap,const int y_gap); bool CreateCanvas(void); bool CreateHeaders(void); bool CreateTable(void); bool CreateScrollV(void); bool CreateScrollH(void); bool CreateEdit(void); bool CreateCombobox(void); bool CreateColumnResizePointer(void); //--- public: //--- Возвращает указатели на элементы CScrollV *GetScrollVPointer(void) { return(::GetPointer(m_scrollv)); } CScrollH *GetScrollHPointer(void) { return(::GetPointer(m_scrollh)); } CTextEdit *GetTextEditPointer(void) { return(::GetPointer(m_edit)); } CComboBox *GetComboboxPointer(void) { return(::GetPointer(m_combobox)); } //--- Возвращает наличие элементов (поле ввода, комбо-бокс) в ячейках таблицы bool HasEditElements(void) const { return(m_edit_state); } bool HasComboboxElements(void) const { return(m_combobox_state); } //--- Цвет (1) сетки и (2) ячеек таблицы void GridColor(const color clr) { m_grid_color=clr; } void CellColor(const color clr) { m_cell_color=clr; } void CellColorHover(const color clr) { m_cell_color_hover=clr; } //--- (1) Режим показа заголовков, высота (2) заголовков и (3) ячеек, (4) отключение полос прокрутки void ShowHeaders(const bool flag) { m_show_headers=flag; } void HeaderYSize(const int y_size) { m_header_y_size=y_size; } void CellYSize(const int y_size) { m_cell_y_size=y_size; } void IsDisabledScrolls(const bool flag) { m_is_disabled_scrolls=flag; } //--- Цвета (1) фона и (2) текста заголовков void HeadersColor(const color clr) { m_headers_color=clr; } void HeadersColorHover(const color clr) { m_headers_color_hover=clr; } void HeadersColorPressed(const color clr) { m_headers_color_pressed=clr; } void HeadersTextColor(const color clr) { m_headers_text_color=clr; } //--- Отступы для признака отсортированной таблицы void SortArrowXGap(const int x_gap) { m_sort_arrow_x_gap=x_gap; } void SortArrowYGap(const int y_gap) { m_sort_arrow_y_gap=y_gap; } //--- Установка картинок для признака отсортированных данных void SortArrowFileAscend(const string path) { m_sort_arrows[0].BmpPath(path); } void SortArrowFileDescend(const string path) { m_sort_arrows[1].BmpPath(path); } //--- Возвращает общее количество (1) рядов и (2) столбцов, (3) количество строк видимой части таблицы uint RowsTotal(void) const { return(m_rows_total); } uint ColumnsTotal(void) const { return(m_columns_total); } int VisibleRowsTotal(void); //--- Возвращает (1) индекс и (2) текст выделенного ряда в таблице int SelectedItem(void) const { return(m_selected_item); } string SelectedItemText(void) const { return(m_selected_item_text); } //--- Режимы (1) подсветка строк при наведении курсора мыши, (2) режим сортируемых данных void LightsHover(const bool flag) { m_lights_hover=flag; } void IsSortMode(const bool flag) { m_is_sort_mode=flag; } //--- Режимы (1) выделение строки, (2) без отмены выделения при повторном нажатии void SelectableRow(const bool flag) { m_selectable_row=flag; } void IsWithoutDeselect(const bool flag) { m_is_without_deselect=flag; } //--- (1) Формат строк типа "Зебра", (2) режим изменения ширины столбцов, (3) режим "Авторазмер столбцов", (4) режим автокоррекции ширины столбцов void IsZebraFormatRows(const color clr) { m_is_zebra_format_rows=clr; } void ColumnResizeMode(const bool flag) { m_column_resize_mode=flag; } void AutoResizeColumnsMode(const bool flag) { m_autoresize_columns=flag; } void AutoCorrectColumnsWidthMode(const bool flag) { m_auto_correct_columns_width_mode=flag; } //--- Авторазмер столбцов void AutoResizeColumns(void); void AutoCorrectWidthColumns(void); //--- Процесс изменения ширины столбцов bool ColumnResizeControl(void) const { return(m_column_resize_control!=WRONG_VALUE); } //--- Возвращает количество картинок в указанной ячейке int ImagesTotal(const uint column_index,const uint row_index); //--- Минимальная ширина столбцов void MinColumnWidth(const int width); //--- Значения по умолчанию: (1) ширина, (2) тип данных, (3) выравнивание текста void DefaultWidth(const int width) { m_default_width =width; } void DefaultTypeData(const ENUM_DATATYPE type) { m_default_type_data =type; } void DefaultTextAlign(const ENUM_ALIGN_MODE align) { m_default_text_align =align; } //--- Устанавливает основной размер таблицы void TableSize(const int columns_total,const int rows_total,const bool init=true); //--- Реконструкция таблицы void Rebuilding(const int columns_total,const int rows_total,const bool redraw=false); //--- Добавляет столбец в таблицу по указанному индексу void AddColumn(const int column_index,const bool redraw=false); //--- Удаляет столбец в таблице по указанному индексу void DeleteColumn(const int column_index,const bool redraw=false); //--- Добавляет строку в таблицу по указанному индексу void AddRow(const int row_index,const bool redraw=false); //--- Удаляет строку в таблице по указанному индексу void DeleteRow(const int row_index,const bool redraw=false); //--- Удаляет все строки void DeleteAllRows(const bool redraw=false); //--- Очищает таблицу. Остаётся только один столбец и одна строка. void Clear(const bool redraw=false); //--- (1) Установка текста в указанный заголовок, (2) получение текста указанного заголовка, (3) получение заголовков в переданный массив void SetHeaderText(const uint column_index,const string value); string GetHeaderText(const uint column_index); uint GetHeadersText(string &headers[]); //--- Установка (1) режима выравнивания текста, (2) отступ текста в ячейке по оси X и (3) ширины для каждого столбца void TextAlign(const ENUM_ALIGN_MODE &array[]); void TextAlign(const uint column_index,const ENUM_ALIGN_MODE align); void TextXOffset(const int &array[]); void ColumnsWidth(const int &array[]); //--- Смещение картинок по X- и Y-осям void ImageXOffset(const int &array[]); void ImageYOffset(const int &array[]); //--- Установка/получение типа данных void DataType(const uint column_index,const ENUM_DATATYPE type); ENUM_DATATYPE DataType(const uint column_index); //--- Установка/получение типа ячейки void CellType(const uint column_index,const uint row_index,const ENUM_TYPE_CELL type); ENUM_TYPE_CELL CellType(const uint column_index,const uint row_index); //--- Устанавливает картинки в указанную ячейку (путь к ресурсу) void SetImages(const uint column_index,const uint row_index,const string &bmp_file_path[]); //--- Устанавливает картинки в указанную ячейку (индекс к ресурсу) void SetImages(const uint column_index,const uint row_index,const uint &resource_index[]); //--- (1) Изменяет/получает (индекс) картинку в указанной ячейке, (2) возвращает индекс текущей картинки, (3) возвращает индекс выбранного пункта в списке комбо-бокса void ChangeImage(const uint column_index,const uint row_index,const uint image_index,const bool redraw=false); int SelectedImageIndex(const uint column_index,const uint row_index); int SelectedComboboxItemIndex(const uint column_index,const uint row_index); //--- Устанавливает цвет текста в указанную ячейку таблицы void TextColor(const uint column_index,const uint row_index,const color clr,const bool redraw=false); //--- (1) Устанавливает и (2) возвращает цвет фона в/из указанную-(ой) ячейку-(и) таблицы void BackColor(const uint column_index,const uint row_index,const color clr,const bool redraw=false); color BackColor(const uint column_index,const uint row_index); //--- Устанавливает/получает значение в указанной ячейке таблицы void SetValue(const uint column_index,const uint row_index,const string value="",const uint digits=0,const bool redraw=false); string GetValue(const uint column_index,const uint row_index); //--- Выделение строки в таблице void SelectRow(const int row_index); //--- Снятие выделения void DeselectRow(void) { m_selected_item=WRONG_VALUE; } //--- Добавить список значений в комбо-бокс void AddValueList(const uint column_index,const uint row_index,const string &array[],const uint selected_item=0); //--- Прокрутка таблицы: (1) вертикальная и (2) горизонтальная void VerticalScrolling(const int pos=WRONG_VALUE); void HorizontalScrolling(const int pos=WRONG_VALUE); //--- Смещение таблицы относительно позиций полос прокрутки void ShiftTable(void); //--- Сортировать данные по указанному столбцу void SortData(const uint column_index=0,const int direction=WRONG_VALUE); //--- (1) Текущее направление сортировки, (2) индекс отсортированного массива int IsSortDirection(void) const { return(m_last_sort_direction); } int IsSortedColumnIndex(void) const { return(m_is_sorted_column_index); } //--- Сброс сортировки void ResetSort(void) { m_is_sorted_column_index=WRONG_VALUE; } //--- public: //--- Изменение положения таблицы по оси X void MovingX(const int x_gap); //--- 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 Update(const bool redraw=false); //--- private: //--- Обработка нажатия на заголовке bool OnClickHeaders(const string clicked_object); //--- Обработка нажатия на таблице bool OnClickTable(const string clicked_object); //--- Обработка двойного нажатия на таблице bool OnDoubleClickTable(const string clicked_object); //--- Обработка окончания ввода значения в ячейку bool OnEndEditCell(const int id); //--- Обработка выбора пункта в выпадающем списке ячейки bool OnClickComboboxItem(const int id); //--- Обработка выделения ряда bool OnSelectRow(const int row_index); //--- Проверка элементов в ячейках на скрытие void CheckAndHideEdit(void); void CheckAndHideCombobox(void); //--- Возвращает индекс нажатой строки int PressedRowIndex(void); //--- Возвращает индекс столбца нажатой ячейки int PressedCellColumnIndex(void); //--- Проверяет, был ли задействован элемент в ячейке при нажатии bool CheckCellElement(const int column_index,const int row_index,const bool double_click=false); //--- Проверяет, было ли нажатие на кнопке в ячейке bool CheckPressedButton(const int column_index,const int row_index,const bool double_click=false); //--- Проверяет, было ли нажатие на чекбоксе в ячейке bool CheckPressedCheckBox(const int column_index,const int row_index,const bool double_click=false); //--- Проверяет, было ли нажатие на ячейке с полем ввода bool CheckPressedEdit(const int column_index,const int row_index,const bool double_click=false); //--- Проверяет, было ли нажатие на ячейке с комбо-боксом bool CheckPressedCombobox(const int column_index,const int row_index,const bool double_click=false); //--- private: //--- Метод быстрой сортировки void QuickSort(uint beg,uint end,uint column,const ENUM_CSORT_MODE mode=SORT_ASCEND); //--- Проверка условия сортировки bool CheckSortCondition(uint column_index,uint row_index,const string check_value,const bool direction); //--- Поменять значения в указанных ячейках местами void Swap(uint r1,uint r2); //--- Рассчитывает размеры таблицы void CalculateTableSize(void); //--- Рассчитывают полный размер таблицы по оси X и Y void CalculateTableXSize(void); void CalculateTableYSize(void); //--- Рассчитывают видимый размер таблицы по оси X и Y void CalculateTableVisibleXSize(void); void CalculateTableVisibleYSize(void); //--- Изменить основные размеры таблицы void ChangeMainSize(const int x_size,const int y_size); //--- Изменить размеры таблицы void ChangeTableSize(void); //--- Изменить размеры полос прокрутки void ChangeScrollsSize(void); //--- Определение индексов видимой области таблицы void VisibleTableIndexes(void); //--- private: //--- Возвращает текст string Text(const int column_index,const int row_index); //--- Возвращает X-координату текста в указанном столбце int TextX(const int column_index,const bool headers=false); //--- Возвращает способ выравнивания текста в указанном столбце uint TextAlign(const int column_index,const uint anchor); //--- Возвращает цвет текста ячейки uint TextColor(const int column_index,const int row_index); //--- Возвращает цвет фона ячейки uint BackColor(const int column_index,const int row_index); //--- Возвращает текущий цвет фона заголовка uint HeaderColorCurrent(const bool is_header_focus); //--- Возвращает текущий цвет фона строки uint RowColorCurrent(const int column_index,const int row_index,const bool is_row_focus); //--- Рисует элемент void Draw(void); //--- Рисует таблицу с учётом последних внесённых изменений void DrawTable(const bool only_visible=false); //--- Рисует заголовки таблицы void DrawTableHeaders(void); //--- Рисует заголовки void DrawHeaders(void); //--- Рисует сетку заголовков таблицы void DrawHeadersGrid(void); //--- Рисует признак возможности сортировки таблицы void DrawSignSortedData(void); //--- Рисует текст заголовков таблицы void DrawHeadersText(void); //--- Рисует фон строк таблицы void DrawRows(void); //--- Рисует выделенную строку void DrawSelectedRow(void); //--- Рисует сетку void DrawGrid(void); //--- Рисует все изображения таблицы void DrawImages(void); //--- Рисует изображение в указанной ячейке void DrawImage(const int column_index,const int row_index); //--- Рисует текст void DrawText(void); //--- Перерисовывает указанную ячейку таблицы void RedrawCell(const int column_index,const int row_index); //--- Рисует указанный ряд таблицы по указанному режиму void DrawRow(int &indexes[],const int item_index,const int prev_item_index,const bool is_user=true); //--- Перерисовывает указанный ряд таблицы по указанному режиму void RedrawRow(const bool is_selected_row=false); //--- private: //--- Проверка фокуса на заголовках void CheckHeaderFocus(void); //--- Проверка фокуса на строках таблицы int CheckRowFocus(void); //--- Проверка фокуса на границах заголовков для изменения их ширины void CheckColumnResizeFocus(void); //--- Изменяет ширину захваченного столбца void ChangeColumnWidth(void); //--- Проверяет размер переданного массива и возвращает скорректированное значение template int CheckArraySize(const T &array[]); //--- Проверить выход из диапазона столбцов bool CheckOutOfColumnRange(const uint column_index); //--- Проверить выход из диапазона столбцов и строк virtual bool CheckOutOfRange(const uint column_index,const uint row_index); //--- Расчёт с учётом последних изменений и изменение размеров таблицы void RecalculateAndResizeTable(const bool redraw=false); //--- Инициализация указанного столбца значениями по умолчанию void ColumnInitialize(const uint column_index); //--- Инициализация указанной ячейки значениями по умолчанию void CellInitialize(const uint column_index,const uint row_index); //--- Делает копию указанного столбца (source) в новое место (dest.) void ColumnCopy(const uint destination,const uint source); //--- Делает копию указанной ячейки (source) в новое место (dest.) void CellCopy(const uint column_dest,const uint row_dest,const uint column_source,const uint row_source); //--- Копирует данные изображения из одного массива в другой void ImageCopy(CImage &destination[],CImage &source[],const int index); //--- private: //--- Изменяет цвет объектов таблицы void ChangeObjectsColor(void); //--- Изменяет цвет заголовков при наведении курсора мыши void ChangeHeadersColor(void); //--- Изменение цвета строк при наведении курсора мыши void ChangeRowsColor(void); //--- Возвращает откорректированный текст по ширине столбца string CorrectingText(const int column_index,const int row_index,const bool headers=false); //--- Ускоренная перемотка таблицы void FastSwitching(void); //--- Изменить ширину по правому краю окна virtual void ChangeWidthByRightWindowSide(void); //--- Изменить высоту по нижнему краю окна virtual void ChangeHeightByBottomWindowSide(void); }; //+------------------------------------------------------------------+ //| Constructor | //+------------------------------------------------------------------+ CTable::CTable(void) : m_rows_total(1), m_columns_total(1), m_edit_state(false), m_combobox_state(false), m_last_edit_row_index(WRONG_VALUE), m_last_edit_column_index(WRONG_VALUE), m_shift_x_step(10), m_shift_x2_limit(0), m_shift_y2_limit(0), m_show_headers(false), m_header_y_size(20), m_cell_y_size(20), m_default_text_align(ALIGN_CENTER), m_default_width(100), m_default_type_data(TYPE_STRING), m_min_column_width(30), m_grid_color(clrLightGray), m_headers_color(C'255,244,213'), m_headers_color_hover(C'229,241,251'), m_headers_color_pressed(C'204,228,247'), m_headers_text_color(clrBlack), m_is_disabled_scrolls(false), m_is_sort_mode(false), m_last_sort_direction(SORT_ASCEND), m_is_sorted_column_index(WRONG_VALUE), m_sort_arrow_x_gap(10), m_sort_arrow_y_gap(8), m_cell_color(clrWhite), m_cell_color_hover(C'229,243,255'), m_prev_selected_item(WRONG_VALUE), m_selected_item(WRONG_VALUE), m_selected_item_text(""), m_sep_x_offset(5), m_lights_hover(false), m_selectable_row(false), m_is_without_deselect(false), m_autoresize_columns(false), m_auto_correct_columns_width_mode(false), m_column_resize_mode(false), m_column_resize_control(WRONG_VALUE), m_column_resize_x_fixed(0), m_column_resize_prev_width(0), m_column_resize_prev_thumb(0), m_item_index_focus(WRONG_VALUE), m_prev_item_index_focus(WRONG_VALUE), m_prev_header_index_focus(WRONG_VALUE), m_selected_row_color(C'51,153,255'), m_selected_row_text_color(clrWhite), m_is_zebra_format_rows(clrNONE), m_visible_table_from_index(WRONG_VALUE), m_visible_table_to_index(WRONG_VALUE) { //--- Сохраним имя класса элемента в базовом классе CElementBase::ClassName(CLASS_NAME); //--- Цвет текста по умолчанию m_label_color=clrBlack; //--- Установим размер таблицы TableSize(m_columns_total,m_rows_total); //--- Инициализация структуры признака сортировки ::ArrayResize(m_sort_arrows,2); m_sort_arrows[0].BmpPath(""); m_sort_arrows[1].BmpPath(""); } //+------------------------------------------------------------------+ //| Destructor | //+------------------------------------------------------------------+ CTable::~CTable(void) { } //+------------------------------------------------------------------+ //| Обработчик событий | //+------------------------------------------------------------------+ void CTable::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam) { //--- Обработка события перемещения курсора if(id==CHARTEVENT_MOUSE_MOVE) { //--- Если полоса прокрутки в действии if(m_scrollv.ScrollBarControl()) { ShiftTable(); m_scrollv.Update(true); return; } //--- Если полоса прокрутки в действии if(m_scrollh.ScrollBarControl()) { ShiftTable(); m_scrollh.Update(true); return; } //--- Выйти, если полоса прокрутки активирована if(m_scrollh.State() || m_scrollv.State()) return; //--- Проверка фокуса над элементами m_headers.MouseFocus(m_mouse.X()>m_headers.X() && m_mouse.X()m_headers.Y() && m_mouse.Y()m_table.X() && m_mouse.X()m_table.Y() && m_mouse.Y()0) VerticalScrolling(pos-1); //--- Обновить полосу прокрутки m_scrollv.Update(true); } return; } //--- Обработка нажатия на объектах if(id==CHARTEVENT_OBJECT_CLICK) { //--- Нажатие на заголовке if(OnClickHeaders(sparam)) return; //--- Нажатие на таблице if(OnClickTable(sparam)) return; //--- return; } //--- Обработка события окончания ввода if(id==CHARTEVENT_CUSTOM+ON_END_EDIT) { if(OnEndEditCell((int)lparam)) return; //--- return; } //--- Обработка события выбора пункта в списке if(id==CHARTEVENT_CUSTOM+ON_CLICK_COMBOBOX_ITEM) { if(OnClickComboboxItem((int)lparam)) return; //--- return; } //--- Обработка события нажатия на кнопках полосы прокрутки if(id==CHARTEVENT_CUSTOM+ON_CLICK_BUTTON) { //--- Выйти, если это нажатие на кнопке комбо-бокса if(m_combobox.CheckElementName(sparam)) return; //--- Выйти, если это нажатие не на кнопке полосы прокрутки if(!m_scrollv.GetIncButtonPointer().CheckElementName(sparam)) return; //--- Если было нажатие на кнопках вертикальной полосы прокрутки if(m_scrollv.OnClickScrollInc((uint)lparam,(uint)dparam) || m_scrollv.OnClickScrollDec((uint)lparam,(uint)dparam)) { //--- Сдвигает данные ShiftTable(); m_scrollv.Update(true); return; } //--- Если было нажатие на кнопках горизонтальной полосы прокрутки списка if(m_scrollh.OnClickScrollInc((uint)lparam,(uint)dparam) || m_scrollh.OnClickScrollDec((uint)lparam,(uint)dparam)) { //--- Сдвигает данные ShiftTable(); m_scrollh.Update(true); return; } } //--- Изменение состояния левой кнопки мыши if(id==CHARTEVENT_CUSTOM+ON_CHANGE_MOUSE_LEFT_BUTTON) { //--- Проверка поля ввода в ячейках на скрытие CheckAndHideEdit(); //--- Проверка комбо-бокса в ячейках на скрытие CheckAndHideCombobox(); //--- Выйти, если заголовки отключены if(!m_show_headers) return; //--- Если левая кнопка мыши отжата if(m_column_resize_control!=WRONG_VALUE && !m_mouse.LeftButtonState()) { //--- Сбросить режим изменения ширины m_column_resize_control=WRONG_VALUE; //--- Перерисовать таблицу DrawTable(); Update(); //--- Скрыть указатель m_column_resize.Hide(); //--- Отправим сообщение на определение доступных элементов ::EventChartCustom(m_chart_id,ON_SET_AVAILABLE,CElementBase::Id(),1,""); //--- Отправим сообщение об изменении в графическом интерфейсе ::EventChartCustom(m_chart_id,ON_CHANGE_GUI,CElementBase::Id(),0,""); } //--- Сбросить индекс последнего фокуса заголовка m_prev_header_index_focus=WRONG_VALUE; //--- Изменение цвета объектов ChangeObjectsColor(); return; } //--- Обработка двойного нажатия левой кнопки мыши if(id==CHARTEVENT_CUSTOM+ON_DOUBLE_CLICK) { //--- Выйти, если комбо-бокс есть и показан if(m_combobox_state && m_combobox.IsVisible()) return; //--- Нажатие на таблице if(OnDoubleClickTable(sparam)) return; //--- return; } } //+------------------------------------------------------------------+ //| Таймер | //+------------------------------------------------------------------+ void CTable::OnEventTimer(void) { //--- Ускоренная перемотка значений FastSwitching(); } //+------------------------------------------------------------------+ //| Создаёт нарисованную таблицу | //+------------------------------------------------------------------+ bool CTable::CreateTable(const int x_gap,const int y_gap) { //--- Выйти, если нет указателя на главный элемент if(!CElement::CheckMainPointer()) return(false); //--- Инициализация свойств InitializeProperties(x_gap,y_gap); //--- Рассчитаем размеры таблицы CalculateTableSize(); //--- Создание элемента if(!CreateCanvas()) return(false); if(!CreateTable()) return(false); if(!CreateHeaders()) return(false); if(!CreateScrollV()) return(false); if(!CreateScrollH()) return(false); if(!CreateEdit()) return(false); if(!CreateCombobox()) return(false); if(!CreateColumnResizePointer()) return(false); //--- Изменить размеры таблицы ChangeTableSize(); return(true); } //+------------------------------------------------------------------+ //| Изменение положения таблицы по оси X | //+------------------------------------------------------------------+ void CTable::MovingX(const int x_gap) { m_x=CElement::CalculateX(x_gap); CElementBase::XGap(x_gap); //--- m_canvas.X(m_x); m_canvas.XGap(CElement::CalculateXGap(m_x)); //--- int x=m_x+1; m_table.X(x); m_table.XGap(CElement::CalculateXGap(x)); //--- m_headers.X(x); m_headers.XGap(CElement::CalculateXGap(x)); //--- CElement::Moving(); } //+------------------------------------------------------------------+ //| Инициализация свойств | //+------------------------------------------------------------------+ void CTable::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<1 || m_auto_xresize_mode)? (m_anchor_right_window_side)? m_main.X2()-m_x-m_auto_xresize_right_offset : m_main.X2()-m_x-m_auto_xresize_right_offset : m_x_size; m_y_size =(m_y_size<1 || m_auto_yresize_mode)? (m_anchor_bottom_window_side)? m_main.Y2()-m_y-m_auto_yresize_bottom_offset : m_main.Y2()-m_y-m_auto_yresize_bottom_offset : m_y_size; //--- Свойства по умолчанию m_back_color =(m_back_color!=clrNONE)? m_back_color : clrWhite; m_label_color =(m_label_color!=clrNONE)? m_label_color : clrBlack; m_label_color_hover =(m_label_color_hover!=clrNONE)? m_label_color_hover : clrBlack; m_label_color_pressed =(m_label_color_pressed!=clrNONE)? m_label_color_pressed : clrWhite; m_border_color =(m_border_color!=clrNONE)? m_border_color : C'150,170,180'; m_icon_x_gap =(m_icon_x_gap>0)? m_icon_x_gap : 3; m_icon_y_gap =(m_icon_y_gap>0)? m_icon_y_gap : 2; m_label_x_gap =(m_label_x_gap>0)? m_label_x_gap : 5; m_label_y_gap =(m_label_y_gap>0)? m_label_y_gap : 4; //--- Отступы от крайней точки CElementBase::XGap(x_gap); CElementBase::YGap(y_gap); } //+------------------------------------------------------------------+ //| Создаёт фон для таблицы | //+------------------------------------------------------------------+ bool CTable::CreateCanvas(void) { //--- Формирование имени объекта string name=CElementBase::ElementName("table"); //--- Создание объекта if(!CElement::CreateCanvas(name,m_x,m_y,m_x_size,m_y_size)) return(false); //--- return(true); } //+------------------------------------------------------------------+ //| Создаёт таблицу | //+------------------------------------------------------------------+ bool CTable::CreateTable(void) { //--- Формирование имени объекта string name=CElementBase::ProgramName()+"_"+"table_grid"+"_"+(string)CElementBase::Id(); //--- Координаты int x =m_x+1; int y =m_y+((m_show_headers)? m_header_y_size : 1); //--- Создание объекта ::ResetLastError(); if(!m_table.CreateBitmapLabel(m_chart_id,m_subwin,name,x,y,m_table_x_size,m_header_y_size,COLOR_FORMAT_ARGB_NORMALIZE)) { ::Print(__FUNCTION__," > Не удалось создать холст для рисования таблицы: ",::GetLastError()); return(false); } //--- Получим указатель на базовый класс if(!m_table.Attach(m_chart_id,name,COLOR_FORMAT_ARGB_NORMALIZE)) { ::Print(__FUNCTION__," > Не удалось присоединить холст для рисования к графику: ",::GetLastError()); return(false); } //--- Свойства ::ObjectSetInteger(m_chart_id,m_table.ChartObjectName(),OBJPROP_ZORDER,m_zorder+1); ::ObjectSetString(m_chart_id,m_table.ChartObjectName(),OBJPROP_TOOLTIP,"\n"); //--- Координаты m_table.X(x); m_table.Y(y); //--- Сохраним размеры m_table.XSize(m_table_visible_x_size); m_table.YSize(m_table_visible_y_size); //--- Отступы от крайней точки панели m_table.XGap(CElement::CalculateXGap(x)); m_table.YGap(CElement::CalculateYGap(y)); //--- Установим размеры видимой области ::ObjectSetInteger(m_chart_id,m_table.ChartObjectName(),OBJPROP_XSIZE,m_table_visible_x_size); ::ObjectSetInteger(m_chart_id,m_table.ChartObjectName(),OBJPROP_YSIZE,m_table_visible_y_size); //--- Зададим смещение фрейма внутри изображения по осям X и Y ::ObjectSetInteger(m_chart_id,m_table.ChartObjectName(),OBJPROP_XOFFSET,0); ::ObjectSetInteger(m_chart_id,m_table.ChartObjectName(),OBJPROP_YOFFSET,0); return(true); } //+------------------------------------------------------------------+ //| Создаёт заголовки таблицы | //+------------------------------------------------------------------+ bool CTable::CreateHeaders(void) { //--- Выйти, если заголовки отключены if(!m_show_headers) return(true); //--- Формирование имени объекта string name=CElementBase::ProgramName()+"_"+"table_headers"+"_"+(string)CElementBase::Id(); //--- Координаты int x =m_x+1; int y =m_y+1; //--- Определим картинки, как признак возможности сортировки таблицы ::ArrayResize(m_sort_arrows,2); if(m_sort_arrows[0].ResourceIndex()==INT_MAX) m_sort_arrows[0].ResourceIndex(RESOURCE_SPIN_INC); if(m_sort_arrows[1].ResourceIndex()==INT_MAX) m_sort_arrows[1].ResourceIndex(RESOURCE_SPIN_DEC); //--- Сохранить картинки в массивы for(int i=0; i<2; i++) m_sort_arrows[i].ReadImageData(m_sort_arrows[i].ResourceIndex()); //--- Создание объекта ::ResetLastError(); if(!m_headers.CreateBitmapLabel(m_chart_id,m_subwin,name,x,y,m_table_x_size,m_header_y_size,COLOR_FORMAT_ARGB_NORMALIZE)) { ::Print(__FUNCTION__," > Не удалось создать холст для рисования заголовков таблицы: ",::GetLastError()); return(false); } //--- Получим указатель на базовый класс if(!m_headers.Attach(m_chart_id,name,COLOR_FORMAT_ARGB_NORMALIZE)) { ::Print(__FUNCTION__," > Не удалось присоединить холст для рисования к графику: ",::GetLastError()); return(false); } //--- Свойства ::ObjectSetInteger(m_chart_id,m_headers.ChartObjectName(),OBJPROP_ZORDER,m_zorder+1); ::ObjectSetString(m_chart_id,m_headers.ChartObjectName(),OBJPROP_TOOLTIP,"\n"); //--- Координаты m_headers.X(x); m_headers.Y(y); //--- Сохраним размеры m_headers.XSize(m_table_visible_x_size); m_headers.YSize(m_header_y_size); //--- Отступы от крайней точки панели m_headers.XGap(CElement::CalculateXGap(x)); m_headers.YGap(CElement::CalculateYGap(y)); //--- Установим размеры видимой области ::ObjectSetInteger(m_chart_id,m_headers.ChartObjectName(),OBJPROP_XSIZE,m_table_visible_x_size); ::ObjectSetInteger(m_chart_id,m_headers.ChartObjectName(),OBJPROP_YSIZE,m_header_y_size); //--- Зададим смещение фрейма внутри изображения по осям X и Y ::ObjectSetInteger(m_chart_id,m_headers.ChartObjectName(),OBJPROP_XOFFSET,0); ::ObjectSetInteger(m_chart_id,m_headers.ChartObjectName(),OBJPROP_YOFFSET,0); return(true); } //+------------------------------------------------------------------+ //| Создаёт вертикальный скролл | //+------------------------------------------------------------------+ bool CTable::CreateScrollV(void) { //--- Сохранить указатель родителя m_scrollv.MainPointer(this); //--- Координаты int x=16,y=1; //--- Свойства m_scrollv.Index(0); m_scrollv.XSize(15); m_scrollv.YSize(CElementBase::YSize()-2); m_scrollv.AnchorRightWindowSide(true); m_scrollv.Alpha(m_alpha); //--- Расчёт количества шагов для смещения uint rows_total =RowsTotal(); uint visible_rows_total =VisibleRowsTotal(); //--- Создание полосы прокрутки if(!m_scrollv.CreateScroll(x,y,rows_total,visible_rows_total)) return(false); //--- Скрыть, если сейчас не нужна if(!m_scrollv.IsScroll() || m_is_disabled_scrolls) m_scrollv.Hide(); //--- Добавить элемент в массив CElement::AddToArray(m_scrollv); return(true); } //+------------------------------------------------------------------+ //| Создаёт горизонтальный скролл | //+------------------------------------------------------------------+ bool CTable::CreateScrollH(void) { //--- Сохранить указатель на главный элемент m_scrollh.MainPointer(this); //--- Координаты int x=1,y=16; //--- Свойства m_scrollh.Index(1); m_scrollh.XSize(CElementBase::XSize()-2); m_scrollh.YSize(15); m_scrollh.AnchorBottomWindowSide(true); m_scrollh.Alpha(m_alpha); //--- Расчёт количества шагов для смещения uint x_size_total =m_table_x_size/m_shift_x_step; uint visible_x_size_total =m_table_visible_x_size/m_shift_x_step; //--- Создание полосы прокрутки if(!m_scrollh.CreateScroll(x,y,x_size_total,visible_x_size_total)) return(false); //--- Скрыть, если сейчас не нужна if(!m_scrollh.IsScroll() || m_is_disabled_scrolls) m_scrollh.Hide(); //--- Добавить элемент в массив CElement::AddToArray(m_scrollh); return(true); } //+------------------------------------------------------------------+ //| Создаёт поле ввода | //+------------------------------------------------------------------+ bool CTable::CreateEdit(void) { //--- Если нет ячеек с полем ввода if(!m_edit_state) return(true); //--- Сохраним указатель на главный элемент m_edit.MainPointer(this); //--- Координаты int x=-1,y=0; //--- Свойства m_edit.Alpha(0); m_edit.XSize(50); m_edit.YSize(21); m_edit.SetValue(""); m_edit.GetTextBoxPointer().XGap(1); m_edit.GetTextBoxPointer().XSize(50); m_edit.GetTextBoxPointer().TextYOffset(4); m_edit.GetTextBoxPointer().AutoSelectionMode(true); //--- Создадим элемент управления if(!m_edit.CreateTextEdit("",x,y)) return(false); //--- Скрыть m_edit.Hide(); //--- Добавить элемент в массив CElement::AddToArray(m_edit); return(true); } //+------------------------------------------------------------------+ //| Создаёт комбо-бокс | //+------------------------------------------------------------------+ bool CTable::CreateCombobox(void) { //--- Если нет ячеек с комбо-боксом if(!m_combobox_state) return(true); //--- Сохраним указатель на главный элемент m_combobox.MainPointer(this); //--- Координаты int x=-1,y=0; //--- Свойства m_combobox.Alpha(0); m_combobox.XSize(50); m_combobox.YSize(21); m_combobox.ItemsTotal(5); m_combobox.GetButtonPointer().XGap(1); m_combobox.GetButtonPointer().LabelYGap(4); m_combobox.GetButtonPointer().IconYGap(3); m_combobox.IsDropdown(CElementBase::IsDropdown()); //--- Получим указатель на список CListView *lv=m_combobox.GetListViewPointer(); //--- Установим свойства списка lv.YSize(93); lv.LightsHover(true); lv.GetScrollVPointer().Index(2); //--- Занесём значения в список for(int i=0; i<5; i++) m_combobox.SetValue(i,(string)i); //--- Выделим в списке первый пункт m_combobox.SelectItem(0); //--- Создадим элемент управления if(!m_combobox.CreateComboBox("",x,y)) return(false); //--- Скрыть m_combobox.Hide(); //--- Добавить элемент в массив CElement::AddToArray(m_combobox); return(true); } //+------------------------------------------------------------------+ //| Создаёт указатель курсора изменения ширины столбцов | //+------------------------------------------------------------------+ bool CTable::CreateColumnResizePointer(void) { //--- Выйти, если режим изменения ширины столбцов отключен if(!m_column_resize_mode) { m_column_resize.State(false); m_column_resize.IsVisible(false); return(true); } //--- Свойства m_column_resize.XGap(13); m_column_resize.YGap(14); m_column_resize.XSize(20); m_column_resize.YSize(20); m_column_resize.Id(CElementBase::Id()); m_column_resize.Type(MP_X_RESIZE_RELATIVE); //--- Создание элемента if(!m_column_resize.CreatePointer(m_chart_id,m_subwin)) return(false); //--- return(true); } //+------------------------------------------------------------------+ //| Возвращает количество видимых строк | //+------------------------------------------------------------------+ int CTable::VisibleRowsTotal(void) { double visible_rows_total =m_table_visible_y_size/m_cell_y_size; double check_y_size =visible_rows_total*m_cell_y_size; visible_rows_total=(check_y_size3)? width : 3; } //+------------------------------------------------------------------+ //| Устанавливает размер таблицы | //+------------------------------------------------------------------+ void CTable::TableSize(const int columns_total,const int rows_total,const bool init=true) { //--- Должно быть не менее одного столбца m_columns_total=(columns_total<1)? 1 : columns_total; //--- Должно быть не менее двух рядов m_rows_total=(rows_total<1)? 1 : rows_total; //--- Установить размер массивам рядов, столбцов и заголовков ::ArrayResize(m_rows,m_rows_total); ::ArrayResize(m_columns,m_columns_total); //--- Выйти, если не нужна инициализация по умолчанию if(!init) return; //--- Установить размер массивам таблицы for(uint c=0; c=(int)m_columns_total)?(int)m_columns_total-1 : column_index; //--- Сместить другие столбцы (двигаемся от конца массива к индексу добавляемого столбца) for(int c=array_size; c>=checked_column_index; c--) { //--- Сместить признак отсортированного массива if(c==m_is_sorted_column_index && m_is_sorted_column_index!=WRONG_VALUE) m_is_sorted_column_index++; //--- Индекс предыдущего столбца int prev_c=c-1; //--- В новом столбце инициализация значениями по умолчанию if(c==checked_column_index) ColumnInitialize(c); //--- Перемещаем данные из предыдущего столбца в текущий else ColumnCopy(c,prev_c); //--- for(uint r=0; r=array_size)? array_size-1 : column_index; //--- Сместить другие столбцы (двигаемся от указанного индекса до последнего столбца) for(int c=checked_column_index; c=(int)m_rows_total)?(int)m_rows_total-1 : row_index; //--- Сместить другие строки (двигаемся от конца массива к индексу добавляемой строки) for(int c=0; c<(int)m_columns_total; c++) { for(int r=array_size; r>=checked_row_index; r--) { //--- Инициализация ячейки новой строки значениями по умолчанию if(r==checked_row_index) { CellInitialize(c,r); continue; } //--- Индекс предыдущей строки uint prev_r=r-1; //--- Перемещаем данные из ячейки предыдущей строки в ячейку текущей CellCopy(c,r,c,prev_r); } } //--- Рассчитать и установить новые размеры таблицы if(redraw) RecalculateAndResizeTable(redraw); } //+------------------------------------------------------------------+ //| Удаляет строку в таблице по указанному индексу | //+------------------------------------------------------------------+ void CTable::DeleteRow(const int row_index,const bool redraw=false) { //--- Получим размер массива строк int array_size=(int)RowsTotal(); //--- Выйти, если осталась только одна строка if(array_size<2) return; //--- Корректировка индекса в случае выхода из диапазона int checked_row_index=(row_index>=(int)m_rows_total)?(int)m_rows_total-1 : row_index; //--- Сместить другие строки (двигаемся от указанного индекса к последней строке) for(int c=0; c<(int)m_columns_total; c++) { for(int r=checked_row_index; r=(uint)images_total) return; //--- Выйти, если указанная картинка совпадает с выбранной if(image_index==m_columns[column_index].m_rows[row_index].m_selected_image) return; //--- Сохранить индекс выбранной картинки ячейки m_columns[column_index].m_rows[row_index].m_selected_image=(int)image_index; //--- Перерисовать ячейку, если указано if(redraw) RedrawCell(column_index,row_index); } //+------------------------------------------------------------------+ //| Возвращает индекс картинки в указанной ячейке | //+------------------------------------------------------------------+ int CTable::SelectedImageIndex(const uint column_index,const uint row_index) { //--- Проверка на выход из диапазона if(!CheckOutOfRange(column_index,row_index)) return(WRONG_VALUE); //--- Вернуть значение return(m_columns[column_index].m_rows[row_index].m_selected_image); } //+------------------------------------------------------------------+ //| Возвращает индекс выбранного пункта | //| в списке комбо-бокса в указанной ячейке | //+------------------------------------------------------------------+ int CTable::SelectedComboboxItemIndex(const uint column_index,const uint row_index) { //--- Проверка на выход из диапазона if(!CheckOutOfRange(column_index,row_index)) return(WRONG_VALUE); //--- Вернуть значение return(m_columns[column_index].m_rows[row_index].m_selected_item); } //+------------------------------------------------------------------+ //| Устанавливает цвет текста в указанную ячейку таблицы | //+------------------------------------------------------------------+ void CTable::TextColor(const uint column_index,const uint row_index,const color clr,const bool redraw=false) { //--- Проверка на выход из диапазона if(!CheckOutOfRange(column_index,row_index)) return; //--- Установить цвет текста в общий массив m_columns[column_index].m_rows[row_index].m_text_color=clr; //--- Перерисовать ячейку, если указано if(redraw) RedrawCell(column_index,row_index); } //+------------------------------------------------------------------+ //| Устанавливает цвет фона в указанную ячейку таблицы | //+------------------------------------------------------------------+ void CTable::BackColor(const uint column_index,const uint row_index,const color clr,const bool redraw=false) { //--- Проверка на выход из диапазона if(!CheckOutOfRange(column_index,row_index)) return; //--- Установить цвет текста в общий массив m_columns[column_index].m_rows[row_index].m_back_color=clr; //--- Перерисовать ячейку, если указано if(redraw) RedrawCell(column_index,row_index); } //+------------------------------------------------------------------+ //| Возвращает цвет фона из указанной ячейки таблицы | //+------------------------------------------------------------------+ color CTable::BackColor(const uint column_index,const uint row_index) { //--- Проверка на выход из диапазона if(!CheckOutOfRange(column_index,row_index)) return(clrWhite); //--- return(m_columns[column_index].m_rows[row_index].m_back_color); } //+------------------------------------------------------------------+ //| Заполняет массив по указанным индексам | //+------------------------------------------------------------------+ void CTable::SetValue(const uint column_index,const uint row_index,const string value="",const uint digits=0,const bool redraw=false) { //--- Проверка на выход из диапазона if(!CheckOutOfRange(column_index,row_index)) return; //--- Установить значение в массив: // Строковое if(m_columns[column_index].m_data_type==TYPE_STRING) m_columns[column_index].m_rows[row_index].m_full_text=value; //--- Вещественное else if(m_columns[column_index].m_data_type==TYPE_DOUBLE) { m_columns[column_index].m_rows[row_index].m_digits=digits; double type_value=::StringToDouble(value); m_columns[column_index].m_rows[row_index].m_full_text=::DoubleToString(type_value,digits); } //--- Время else if(m_columns[column_index].m_data_type==TYPE_DATETIME) { datetime type_value=::StringToTime(value); m_columns[column_index].m_rows[row_index].m_full_text=::TimeToString(type_value); } //--- Любой другой тип будет установлен, как строка else m_columns[column_index].m_rows[row_index].m_full_text=value; //--- Скорректировать и сохранить текст, если не помещается в ячейке m_columns[column_index].m_rows[row_index].m_short_text=CorrectingText(column_index,row_index); //--- Перерисовать ячейку, если указано if(redraw) RedrawCell(column_index,row_index); } //+------------------------------------------------------------------+ //| Возвращает значение по указанным индексам | //+------------------------------------------------------------------+ string CTable::GetValue(const uint column_index,const uint row_index) { //--- Проверка на выход из диапазона if(!CheckOutOfRange(column_index,row_index)) return(""); //--- Вернуть значение return(m_columns[column_index].m_rows[row_index].m_full_text); } //+------------------------------------------------------------------+ //| Выделение указанной строки в таблице | //+------------------------------------------------------------------+ void CTable::SelectRow(const int row_index) { //--- Проверка на выход из диапазона if(!CheckOutOfRange(0,(uint)row_index)) return; //--- Если такая строка уже выделена if(m_selected_item==row_index) return; //--- Текущий и предыдущий индексы строк m_prev_selected_item =(m_selected_item==WRONG_VALUE)? row_index : m_selected_item; m_selected_item =row_index; //--- Массив для значений в определённой последовательности int indexes[2]; //--- Если здесь в первый раз if(m_prev_selected_item==WRONG_VALUE) indexes[0]=m_selected_item; else { indexes[0] =(m_selected_item>m_prev_selected_item)? m_prev_selected_item : m_selected_item; indexes[1] =(m_selected_item>m_prev_selected_item)? m_selected_item : m_prev_selected_item; } //--- Рисует указанный ряд таблицы по указанному режиму DrawRow(indexes,m_selected_item,m_prev_selected_item,false); //--- Получить индексы на границах видимой области VisibleTableIndexes(); //--- Переместить полосу прокрутки на указанную строку if(row_index==0) { VerticalScrolling(0); } else if((uint)row_index>=m_rows_total-1) { VerticalScrolling(WRONG_VALUE); } else if(row_index<(int)m_visible_table_from_index) { VerticalScrolling(m_scrollv.CurrentPos()-1); } else if(row_index>=(int)m_visible_table_to_index-1) { VerticalScrolling(m_scrollv.CurrentPos()+1); } } //+------------------------------------------------------------------+ //| Добавить список значений в комбо-бокс | //+------------------------------------------------------------------+ void CTable::AddValueList(const uint column_index,const uint row_index,const string &array[],const uint selected_item=0) { //--- Проверка на выход из диапазона if(!CheckOutOfRange(column_index,row_index)) return; //--- Установим размер списку указанной ячейки uint total=::ArraySize(array); ::ArrayResize(m_columns[column_index].m_rows[row_index].m_value_list,total); //--- Сохраним переданные значения ::ArrayCopy(m_columns[column_index].m_rows[row_index].m_value_list,array); //--- Проверка индекса выбранного пункта в списке uint check_item_index=(selected_item>=total)? total-1 : selected_item; //--- Сохранить выбранный пункт в списке m_columns[column_index].m_rows[row_index].m_selected_item=(int)check_item_index; //--- Сохранить текст выбранного пункта в ячейке m_columns[column_index].m_rows[row_index].m_full_text=array[check_item_index]; } //+------------------------------------------------------------------+ //| Горизонтальная прокрутка поля ввода | //+------------------------------------------------------------------+ void CTable::HorizontalScrolling(const int pos=WRONG_VALUE) { //--- Для определения позиции ползунка int index=0; //--- Индекс последней позиции int last_pos_index=int(m_table_x_size-m_table_visible_x_size); //--- Корректировка в случае выхода из диапазона if(pos<0) index=last_pos_index; else index=(pos>last_pos_index)? last_pos_index : pos; //--- Сдвигаем ползунок полосы прокрутки m_scrollh.MovingThumb(index); //--- Сдвигаем поле ввода ShiftTable(); } //+------------------------------------------------------------------+ //| Вертикальная прокрутка поля ввода | //+------------------------------------------------------------------+ void CTable::VerticalScrolling(const int pos=WRONG_VALUE) { //--- Для определения позиции ползунка int index=0; //--- Индекс последней позиции int last_pos_index=int(m_table_y_size-m_table_visible_y_size); //--- Корректировка в случае выхода из диапазона if(pos<0) index=last_pos_index; else index=(pos>last_pos_index)? last_pos_index : pos; //--- Сдвигаем ползунок полосы прокрутки m_scrollv.MovingThumb(index); //--- Сдвигаем поле ввода ShiftTable(); } //+------------------------------------------------------------------+ //| Сдвигает таблицу относительно полос прокрутки | //+------------------------------------------------------------------+ void CTable::ShiftTable(void) { //--- Получим текущие позиции ползунков горизонтальной и вертикальной полос прокрутки int h_offset =m_scrollh.CurrentPos()*m_shift_x_step; int v_offset =m_scrollv.CurrentPos()*m_cell_y_size; //--- Рассчитаем отступы для смещения int x_offset =(h_offset<1)? 0 : (h_offset>=m_shift_x2_limit)? m_shift_x2_limit-2 : h_offset; int y_offset =(v_offset<1)? 0 : (v_offset>=m_shift_y2_limit)? m_shift_y2_limit : v_offset; //--- Расчёт положения данных относительно ползунков полос прокрутки long x =(m_table_x_size>m_table_visible_x_size)? x_offset : 0; long y =(m_table_y_size>m_table_visible_y_size)? y_offset : 0; //--- Смещение таблицы ::ObjectSetInteger(m_chart_id,m_table.ChartObjectName(),OBJPROP_XOFFSET,x); ::ObjectSetInteger(m_chart_id,m_table.ChartObjectName(),OBJPROP_YOFFSET,y); ::ObjectSetInteger(m_chart_id,m_headers.ChartObjectName(),OBJPROP_XOFFSET,x); } //+------------------------------------------------------------------+ //| Сортировать данные по указанному столбцу | //+------------------------------------------------------------------+ void CTable::SortData(const uint column_index=0,const int direction=WRONG_VALUE) { //--- Выйти, если выходим за пределы таблицы if(column_index>=m_columns_total) return; //--- Индекс, с которого нужно начать сортировку uint first_index=0; //--- Последний индекс uint last_index=m_rows_total-1; //--- Без контроля направления пользователем if(direction==WRONG_VALUE) { //--- В первый раз будет отсортировано по возрастанию, а затем каждый раз в противоположном направлении if(m_is_sorted_column_index==WRONG_VALUE || column_index!=m_is_sorted_column_index || m_last_sort_direction==SORT_DESCEND) m_last_sort_direction=SORT_ASCEND; else m_last_sort_direction=SORT_DESCEND; } else { m_last_sort_direction=(ENUM_CSORT_MODE)direction; } //--- Запомним индекс последнего отсортированного столбца данных m_is_sorted_column_index=(int)column_index; //--- Сортировка QuickSort(first_index,last_index,column_index,m_last_sort_direction); } //+------------------------------------------------------------------+ //| Авто-изменение ширины столбцов | //+------------------------------------------------------------------+ void CTable::AutoResizeColumns(void) { if(!m_autoresize_columns) return; //--- int table_x_size =m_x_size-2; uint last_column_index =m_columns_total-1; //--- Сумма ширины всех столбцов int sum_width=0; for(uint c=0; c(uint)VisibleRowsTotal()) { if(sum_width==table_x_size) m_columns[last_column_index].m_width=m_columns[last_column_index].m_width-m_scrollv.XSize(); } else { if(sum_width!=table_x_size) { if(sum_width=m_columns[c].m_x && x<=m_columns[c].m_x2) { column_index=c; break; } } //--- Сортировка данных по указанному столбцу SortData(column_index); //--- Отправим сообщение об этом ::EventChartCustom(m_chart_id,ON_SORT_DATA,CElementBase::Id(),m_is_sorted_column_index,::EnumToString(DataType(column_index))); return(true); } //+------------------------------------------------------------------+ //| Обработка выделения ряда | //+------------------------------------------------------------------+ bool CTable::OnSelectRow(const int row_index) { //--- Если нажали на уже выделенном ряде if(row_index==m_selected_item) { //--- Снять выделение, если нет запрета if(!m_is_without_deselect) { m_prev_selected_item =m_selected_item; m_selected_item =WRONG_VALUE; m_selected_item_text =""; } return(true); } //--- Сохраним индекс ряда и строку первой ячейки m_prev_selected_item =(m_selected_item==WRONG_VALUE)? row_index : m_selected_item; m_selected_item =row_index; m_selected_item_text =m_columns[0].m_rows[row_index].m_full_text; return(true); } //+------------------------------------------------------------------+ //| Обработка нажатия на таблице | //+------------------------------------------------------------------+ bool CTable::OnClickTable(const string clicked_object) { //--- Выйти, если в процессе изменения ширины столбца if(m_column_resize_control!=WRONG_VALUE) return(false); //--- Выйдем, если полоса прокрутки в активном режиме if(m_scrollv.State() || m_scrollh.State()) return(false); //--- Выйдем, если чужое имя объекта if(m_table.ChartObjectName()!=clicked_object) return(false); //--- Определим ряд, на котором нажали int r=PressedRowIndex(); //--- Определим ячейку, на которой нажали int c=PressedCellColumnIndex(); //--- Проверим был ли задействован элемент в ячейке bool is_cell_element=CheckCellElement(c,r); //--- Если (1) включен режим выделения строки и (2) не задействован элемент в ячейке if(m_selectable_row && !is_cell_element) { OnSelectRow(r); //--- Изменить цвет RedrawRow(true); m_table.Update(); //--- Отправим сообщение об этом ::EventChartCustom(m_chart_id,ON_CLICK_LIST_ITEM,CElementBase::Id(),m_selected_item,string(c)+"_"+string(r)); } //--- return(true); } //+------------------------------------------------------------------+ //| Обработка двойного нажатия на таблице | //+------------------------------------------------------------------+ bool CTable::OnDoubleClickTable(const string clicked_object) { //--- Выйти, если таблица вне фокуса if(!m_table.MouseFocus()) return(false); //--- Определим ряд, на котором нажали int r=PressedRowIndex(); //--- Определим ячейку, на которой нажали int c=PressedCellColumnIndex(); //--- Проверим был ли задействован элемент в ячейке и вернём результат return(CheckCellElement(c,r,true)); } //+------------------------------------------------------------------+ //| Обработка окончания ввода значения в ячейку | //+------------------------------------------------------------------+ bool CTable::OnEndEditCell(const int id) { //--- Выйти, если (1) идентификаторы не совпадают или (2) ячеек с полями ввода нет if(id!=CElementBase::Id() || !m_edit_state) return(false); //--- Установить новое значение в ячейку таблицы SetValue(m_last_edit_column_index,m_last_edit_row_index,m_edit.GetValue(),0,true); Update(); //--- Деактивировать и скрыть поле ввода m_edit.GetTextBoxPointer().DeactivateTextBox(); m_edit.Hide(); m_chart.Redraw(); return(true); } //+------------------------------------------------------------------+ //| Обработка выбора пункта в комбо-боксе ячейки | //+------------------------------------------------------------------+ bool CTable::OnClickComboboxItem(const int id) { //--- Выйти, если (1) идентификаторы не совпадают или (2) ячеек с комбо-боксом нет if(id!=CElementBase::Id() || !m_combobox_state) return(false); //--- Индексы последней редактируемой ячейки int c=m_last_edit_column_index; int r=m_last_edit_row_index; //--- Запомним в ячейке индекс выбранного пункта m_columns[c].m_rows[r].m_selected_item=m_combobox.GetListViewPointer().SelectedItemIndex(); //--- Установить новое значение в ячейку таблицы SetValue(c,r,m_combobox.GetValue(),0,true); Update(); return(true); } //+------------------------------------------------------------------+ //| Проверка поля ввода в ячейках на скрытие | //+------------------------------------------------------------------+ void CTable::CheckAndHideEdit(void) { //--- Выйти, если (1) поля ввода нет или (2) оно скрыто if(!m_edit_state || !m_edit.IsVisible()) return; //--- Проверим фокус m_edit.GetTextBoxPointer().CheckMouseFocus(); //--- Деактивировать и скрыть поле ввода, если оно (1) вне фокуса и (2) кнопка мыши нажата if(!m_edit.GetTextBoxPointer().MouseFocus() && m_mouse.LeftButtonState()) { m_edit.GetTextBoxPointer().DeactivateTextBox(); m_edit.Hide(); m_chart.Redraw(); } } //+------------------------------------------------------------------+ //| Проверка комбо-бокса в ячейках на скрытие | //+------------------------------------------------------------------+ void CTable::CheckAndHideCombobox(void) { //--- Выйти, если (1) комбо-бокса нет или (2) оно скрыто if(!m_combobox_state || !m_combobox.IsVisible()) return; //--- Скрыть комбо-бокс, если он вне фокуса и кнопка мыши нажата if(!m_combobox.GetButtonPointer().MouseFocus() && m_mouse.LeftButtonState()) { m_combobox.Hide(); m_chart.Redraw(); } } //+------------------------------------------------------------------+ //| Возвращает индекс нажатой строки | //+------------------------------------------------------------------+ int CTable::PressedRowIndex(void) { int index=0; //--- Получим относительную Y-координату под курсором мыши int y=m_mouse.RelativeY(m_table); //--- Определим ряд, на котором нажали for(uint r=0; r=m_rows[r].m_y && y<=m_rows[r].m_y2)) continue; //--- index=(int)r; break; } //--- Вернуть индекс return(index); } //+------------------------------------------------------------------+ //| Возвращает индекс столбца нажатой ячейки | //+------------------------------------------------------------------+ int CTable::PressedCellColumnIndex(void) { int index=0; //--- Получим относительную X-координату под курсором мыши int x=m_mouse.RelativeX(m_table); //--- Определим ячейку, на которой нажали for(uint c=0; c=m_columns[c].m_x && x<=m_columns[c].m_x2) { index=(int)c; break; } } //--- Вернуть индекс столбца return(index); } //+------------------------------------------------------------------+ //| Проверяет, был ли при нажатии задействован элемент в ячейке | //+------------------------------------------------------------------+ bool CTable::CheckCellElement(const int column_index,const int row_index,const bool double_click=false) { //--- Выйти, если в ячейке нет элемента управления if(m_columns[column_index].m_rows[row_index].m_type==CELL_SIMPLE) return(false); //--- switch(m_columns[column_index].m_rows[row_index].m_type) { //--- Если это ячейка-кнопка case CELL_BUTTON : { if(!CheckPressedButton(column_index,row_index,double_click)) return(false); //--- break; } //--- Если это ячейка-чекбокс case CELL_CHECKBOX : { if(!CheckPressedCheckBox(column_index,row_index,double_click)) return(false); //--- break; } //--- Если это ячейка с полем ввода case CELL_EDIT : { if(!CheckPressedEdit(column_index,row_index,double_click)) return(false); //--- break; } //--- Если это ячейка с комбо-боксом case CELL_COMBOBOX : { if(!CheckPressedCombobox(column_index,row_index,double_click)) return(false); //--- break; } } //--- return(true); } //+------------------------------------------------------------------+ //| Проверяет, было ли нажатие на кнопке в ячейке | //+------------------------------------------------------------------+ bool CTable::CheckPressedButton(const int column_index,const int row_index,const bool double_click=false) { //--- Выйти, если нет картинок в ячейке if(ImagesTotal(column_index,row_index)<1) { ::Print(__FUNCTION__," > Установите минимум одну картинку для ячейки-кнопки!"); return(false); } //--- Получим относительные координаты под курсором мыши int x=m_mouse.RelativeX(m_table); //--- Получим правую границу картинки int image_x =int(m_columns[column_index].m_x+m_columns[column_index].m_image_x_offset); int image_x2 =int(image_x+m_columns[column_index].m_rows[row_index].m_images[0].Width()); //--- Выйти, если нажали не на картинке if(x>image_x2) return(false); else { //--- Если это не двойной клик, отправим сообщение if(!double_click) { int image_index=m_columns[column_index].m_rows[row_index].m_selected_image; ::EventChartCustom(m_chart_id,ON_CLICK_BUTTON,CElementBase::Id(),image_index,"cell"+string(column_index)+"_"+string(row_index)); } } //--- return(true); } //+------------------------------------------------------------------+ //| Проверяет, было ли нажатие на чекбоксе в ячейке | //+------------------------------------------------------------------+ bool CTable::CheckPressedCheckBox(const int column_index,const int row_index,const bool double_click=false) { //--- Выйти, если нет картинок в ячейке if(ImagesTotal(column_index,row_index)<2) { ::Print(__FUNCTION__," > Установите минимум две картинки для ячейки-чекбокса!"); return(false); } //--- Получим относительные координаты под курсором мыши int x=m_mouse.RelativeX(m_table); //--- Получим правую границу картинки int image_x =int(m_columns[column_index].m_x+m_icon_x_gap); int image_x2 =int(image_x+m_columns[column_index].m_rows[row_index].m_images[0].Width()); //--- Выйти, если (1) нажали не на картинке и (2) это не двойной клик if(x>image_x2 && !double_click) return(false); else { //--- Текущий индекс выбранной картинки int image_i=m_columns[column_index].m_rows[row_index].m_selected_image; //--- Определим следующий индекс для картинки int next_i=(image_i>1].m_full_text; //--- Выполнять алгоритм, пока левый индекс меньше найденного правого индекса while(r1), false (<) | //+------------------------------------------------------------------+ bool CTable::CheckSortCondition(uint column_index,uint row_index,const string check_value,const bool direction) { bool condition=false; //--- switch(m_columns[column_index].m_data_type) { case TYPE_STRING : { string v1=m_columns[column_index].m_rows[row_index].m_full_text; string v2=check_value; condition=(direction)? v1>v2 : v1v2 : v1v2 : v1v2 : v1m_rows[row_index].m_y && y<=m_rows[row_index].m_y2); } //--- Нарисовать фон ячейки m_table.FillRectangle(x1,y1,x2,y2,RowColorCurrent(column_index,row_index,is_row_focus)); //--- Рисуем картинку, если (1) она есть в этой ячейке и (2) в этом столбце выравнивание текста по левому краю if(ImagesTotal(column_index,row_index)>0 && m_columns[column_index].m_text_align==ALIGN_LEFT) CTable::DrawImage(column_index,row_index); //--- Получим способ выравнивания текста uint text_align=TextAlign(column_index,TA_TOP); //--- Рисуем текст for(uint c=0; c0)? 1 : 0); x2=m_columns[c].m_x2-1; m_table.FillRectangle(x1,y1[r],x2,y2[r],RowColorCurrent(c,indexes[r],(is_user)? is_item_focus : false)); } } //--- Рисуем границы for(uint r=0; r0 && m_columns[c].m_text_align==ALIGN_LEFT) CTable::DrawImage(c,indexes[r]); } } //--- Для расчёта координат int x=0,y=0; //--- Способ выравнивания текста uint text_align=0; //--- Рисуем текст for(uint c=0; cm_prev_item_index_focus || item_index==WRONG_VALUE) { indexes[0] =(item_index==WRONG_VALUE || prev_item_index!=WRONG_VALUE)? prev_item_index : item_index; indexes[1] =item_index; } //--- Если курсор мыши сдвинулся вверх else { indexes[0] =item_index; indexes[1] =prev_item_index; } //--- Рисует указанный ряд таблицы по указанному режиму DrawRow(indexes,item_index,prev_item_index); } //+------------------------------------------------------------------+ //| Рисует фон рядов таблицы | //+------------------------------------------------------------------+ void CTable::DrawRows(void) { //--- Координаты курсора мыши int y=0; //--- Координаты заголовков int x1=0,x2=m_table_x_size-2; int y1=0,y2=0; bool is_row_focus=false; //--- Получим относительную X-координату под курсором мыши y=m_mouse.RelativeY(m_table); //--- Рисование рядов for(uint r=m_visible_table_from_index; r0)? 1 : 0); y2 =m_rows[r].m_y2-1; //--- Проверим фокус is_row_focus=(m_lights_hover)?(y>y1 && y0)? 1 : 0); x2 =m_columns[c].m_x2-1; m_table.FillRectangle(x1,y1,x2,y2,RowColorCurrent(c,r,is_row_focus)); } } } //+------------------------------------------------------------------+ //| Рисует выделенный ряд | //+------------------------------------------------------------------+ void CTable::DrawSelectedRow(void) { //--- Выйти, если нет выделенного ряда if(m_selected_item==WRONG_VALUE || !m_selectable_row) return; //--- Зададим начальные координаты для проверки условия int y_offset=m_selected_item*m_cell_y_size; //--- Координаты int x1=0; int x2=0; int y1=y_offset+1; int y2=y_offset+m_cell_y_size-1; //--- Нарисовать фон ячеек for(uint c=0; c0)? 1 : 0); x2 =m_columns[c].m_x2-1; m_table.FillRectangle(x1,y1,x2,y2,::ColorToARGB(m_selected_row_color,m_alpha)); } } //+------------------------------------------------------------------+ //| Рисует сетку | //+------------------------------------------------------------------+ void CTable::DrawGrid(void) { //--- Цвет сетки uint clr=::ColorToARGB(m_grid_color); //--- Размер холста для рисования int x_size=m_table_x_size; int y_size=m_table_y_size-1; //--- Координаты int x1=0,x2=0,y1=0,y2=0; //--- Горизонтальные линии uint first_index=(m_show_headers)? 0 : 1; x1=0; y1=0; x2=x_size; y2=0; for(uint r=first_index; r0) { uint prev_i=i-1; m_columns[i].m_x=m_columns[prev_i].m_x+m_columns[prev_i].m_width; } } } //+------------------------------------------------------------------+ //| Рисует все изображения таблицы | //+------------------------------------------------------------------+ void CTable::DrawImages(void) { //--- Для расчёта координат int x=0,y=0; //--- Столбцы for(int c=0; c<(int)m_columns_total; c++) { //--- Если выравнивание текста не по левому краю, перейти к следующему столбцу if(m_columns[c].m_text_align!=ALIGN_LEFT) continue; //--- Строки for(int r=(int)m_visible_table_from_index; r<(int)m_visible_table_to_index; r++) { //--- Перейти к следующему, если в этой ячейке нет картинок if(ImagesTotal(c,r)<1) continue; //--- Выбранная картинка в ячейке (по умолчанию выбрана первая [0]) int selected_image=m_columns[c].m_rows[r].m_selected_image; //--- Перейти к следующему, если массив пикселей пуст if(m_columns[c].m_rows[r].m_images[selected_image].DataTotal()<1) continue; //--- Нарисовать картинку CTable::DrawImage(c,r); } } } //+------------------------------------------------------------------+ //| Рисует изображение в указанной ячейке | //+------------------------------------------------------------------+ void CTable::DrawImage(const int column_index,const int row_index) { //--- Расчёт координат int x =m_columns[column_index].m_x+m_columns[column_index].m_image_x_offset; int y =m_rows[row_index].m_y+m_columns[column_index].m_image_y_offset; //--- Выбранная картинка в ячейке и её размеры int selected_image =m_columns[column_index].m_rows[row_index].m_selected_image; uint image_height =m_columns[column_index].m_rows[row_index].m_images[selected_image].Height(); uint image_width =m_columns[column_index].m_rows[row_index].m_images[selected_image].Width(); //--- Рисуем for(uint ly=0,i=0; lym_columns[i].m_x+((i!=0)? sep_x_offset : 0) && x<=m_columns[i].m_x2+sep_x_offset) m_prev_header_index_focus=(int)i; //--- Определим цвет заголовка uint clr=(i==m_column_resize_control)? ::ColorToARGB(m_headers_color_hover,m_alpha) : HeaderColorCurrent(is_header_focus); //--- Нарисовать фон заголовка m_headers.FillRectangle(m_columns[i].m_x,y1,m_columns[i].m_x2,y2,clr); } } //+------------------------------------------------------------------+ //| Рисует сетку заголовков таблицы | //+------------------------------------------------------------------+ void CTable::DrawHeadersGrid(void) { //--- Цвет сетки uint clr=::ColorToARGB(m_grid_color); //--- Координаты int x1=0,x2=0,y1=0,y2=0; x2=m_table_x_size-1; y2=m_header_y_size-1; //--- Нарисовать рамку m_headers.Line(x1,y2,x2,y2,clr); //--- Разделительные линии x2=x1=m_columns[0].m_width; for(uint i=1; i=::ArraySize(m_columns)) return; //--- Расчёт координат int x =m_columns[m_is_sorted_column_index].m_x2-m_sort_arrow_x_gap; int y =m_sort_arrow_y_gap; //--- Выбранная картинка по направлению сортировки int image_index=(m_last_sort_direction==SORT_ASCEND)? 0 : 1; //--- Рисуем for(uint ly=0,i=0; lym_rows[m_item_index_focus].m_y && y<=m_rows[m_item_index_focus].m_y2); //--- Если фокус изменился if(!condition) { //--- Получим индекс строки в фокусе m_item_index_focus=CheckRowFocus(); //--- Изменить цвет строки RedrawRow(); m_table.Update(); //--- Сохранить как предыдущий индекс в фокусе m_prev_item_index_focus=m_item_index_focus; } } } //+------------------------------------------------------------------+ //| Проверка фокуса на заголовке | //+------------------------------------------------------------------+ void CTable::CheckHeaderFocus(void) { //--- Выйти, если (1) заголовки отключены или (2) начали изменение ширины столбца if(!m_show_headers || m_column_resize_control!=WRONG_VALUE) return; //--- Получим относительную X-координату под курсором мыши int x=m_mouse.RelativeX(m_headers); //--- Отступ с учётом режима изменения ширины столбцов int sep_x_offset=(m_column_resize_mode)? m_sep_x_offset : 0; //--- Ищем фокус for(uint i=0; im_columns[i].m_x+sep_x_offset && x<=m_columns[i].m_x2+sep_x_offset) && m_prev_header_index_focus!=i) { m_prev_header_index_focus=WRONG_VALUE; break; } } } //+------------------------------------------------------------------+ //| Определение индексов видимой области таблицы | //+------------------------------------------------------------------+ void CTable::VisibleTableIndexes(void) { //--- Определяем границы с учётом смещения видимой области таблицы int yoffset1 =(int)::ObjectGetInteger(m_chart_id,m_table.ChartObjectName(),OBJPROP_YOFFSET); int yoffset2 =yoffset1+m_table_visible_y_size; //--- Определяем первый и последний индексы видимой области таблицы m_visible_table_from_index =int(double(yoffset1/m_cell_y_size)); m_visible_table_to_index =int(double(yoffset2/m_cell_y_size)); //--- Нижний индекс на один больше, если не выходим из диапазона m_visible_table_to_index=(m_visible_table_to_index+1>m_rows_total)? m_rows_total : m_visible_table_to_index+1; } //+------------------------------------------------------------------+ //| Проверка фокуса на рядах таблицы | //+------------------------------------------------------------------+ int CTable::CheckRowFocus(void) { int item_index_focus=WRONG_VALUE; //--- Получим относительную Y-координату под курсором мыши int y=m_mouse.RelativeY(m_table); ///--- Получим индексы локальной области таблицы VisibleTableIndexes(); //--- Ищем фокус for(uint i=m_visible_table_from_index; im_rows[i].m_y && y<=m_rows[i].m_y2) { item_index_focus=(int)i; break; } } //--- Вернём индекс строки в фокусе return(item_index_focus); } //+------------------------------------------------------------------+ //| Проверка фокуса на границах заголовков для изменения их ширины | //+------------------------------------------------------------------+ void CTable::CheckColumnResizeFocus(void) { //--- Выйти, если режим изменения ширины столбцов отключен if(!m_column_resize_mode || m_auto_correct_columns_width_mode) return; //--- Выйти, если начали изменение ширины столбца if(m_column_resize_control!=WRONG_VALUE) { //--- Обновить координаты указателя m_column_resize.Moving(m_mouse.X(),m_mouse.Y()); return; } //--- Для проверки фокуса над границами заголовков bool is_focus=false; //--- Если курсор мыши в области заголовков if(m_headers.MouseFocus()) { //--- Получим относительную X-координату под курсором мыши int x=m_mouse.RelativeX(m_headers); //--- Ищем фокус for(uint i=0; im_columns[i].m_x2-m_sep_x_offset && x<=m_columns[i].m_x2+m_sep_x_offset) break; } //--- Если есть фокус if(is_focus) { //--- Обновить координаты указателя и сделать его видимым m_column_resize.Moving(m_mouse.X(),m_mouse.Y()); m_column_resize.Reset(); m_chart.Redraw(); } else { m_column_resize.Hide(); } } //--- Скрыть указатель, если нет фокуса else if(!is_focus) m_column_resize.Hide(); } //+------------------------------------------------------------------+ //| Изменяет ширину захваченного столбца | //+------------------------------------------------------------------+ void CTable::ChangeColumnWidth(void) { //--- Выйти, если заголовки отключены if(!m_show_headers) return; //--- Проверка фокуса на границах заголовков CheckColumnResizeFocus(); //--- Если закончили, сбросим значения if(m_column_resize_control==WRONG_VALUE) { m_column_resize_x_fixed =0; m_column_resize_prev_width =0; m_column_resize_prev_thumb =0; return; } //--- Получим относительную X-координату под курсором мыши int x=m_mouse.RelativeX(m_headers); //--- Если только начали изменение ширины столбца if(m_column_resize_x_fixed<1) { //--- Запомним текущую X-координату и ширину столбца m_column_resize_x_fixed =x; m_column_resize_prev_width =m_columns[m_column_resize_control].m_width; m_column_resize_prev_thumb =m_scrollh.CurrentPos(); } //--- Рассчитаем новую ширину для столбца int new_width=m_column_resize_prev_width+(x-m_column_resize_x_fixed); //--- Оставить без изменений, если меньше установленного ограничения if(new_width int CTable::CheckArraySize(const T &array[]) { int total=0; int array_size=::ArraySize(array); //--- Выйти, если передан массив нулевого размера if(array_size<1) return(WRONG_VALUE); //--- Скорректировать значение для предотвращения выхода из диапазона массива total=(array_size<(int)m_columns_total)? array_size :(int)m_columns_total; //--- Вернуть скорректированный размер массива return(total); } //+------------------------------------------------------------------+ //| Проверить выход из диапазона столбцов | //+------------------------------------------------------------------+ bool CTable::CheckOutOfColumnRange(const uint column_index) { //--- Проверка на выход из диапазона столбцов uint csize=::ArraySize(m_columns); if(csize<1 || column_index>=csize) return(false); //--- return(true); } //+------------------------------------------------------------------+ //| Проверить выход из диапазона столбцов и рядов | //+------------------------------------------------------------------+ bool CTable::CheckOutOfRange(const uint column_index,const uint row_index) { //--- Проверка на выход из диапазона столбцов uint csize=::ArraySize(m_columns); if(csize<1 || column_index>=csize) return(false); //--- Проверка на выход из диапазона рядов uint rsize=::ArraySize(m_columns[column_index].m_rows); if(rsize<1 || row_index>=rsize) return(false); //--- return(true); } //+------------------------------------------------------------------+ //| Расчёт с учётом последних изменений и изменение размеров таблицы | //+------------------------------------------------------------------+ void CTable::RecalculateAndResizeTable(const bool redraw=false) { //--- Рассчитать размеры таблицы CalculateTableSize(); //--- Установить новый размер таблице ChangeTableSize(); //--- Обновить таблицу Update(redraw); //--- if(RowsTotal()>(uint)VisibleRowsTotal()) ::EventChartCustom(m_chart_id,ON_CHANGE_GUI,0,0.0,""); } //+------------------------------------------------------------------+ //| Инициализация указанного столбца значениями по умолчанию | //+------------------------------------------------------------------+ void CTable::ColumnInitialize(const uint column_index) { //--- Инициализация свойств столбцов значениями по умолчанию m_columns[column_index].m_x =0; m_columns[column_index].m_x2 =0; m_columns[column_index].m_width =m_default_width; m_columns[column_index].m_data_type =m_default_type_data; m_columns[column_index].m_text_align =m_default_text_align; m_columns[column_index].m_text_x_offset =m_label_x_gap; m_columns[column_index].m_image_x_offset =m_icon_x_gap; m_columns[column_index].m_image_y_offset =m_icon_y_gap; m_columns[column_index].m_header_text =""; } //+------------------------------------------------------------------+ //| Инициализация указанной ячейки значениями по умолчанию | //+------------------------------------------------------------------+ void CTable::CellInitialize(const uint column_index,const uint row_index) { m_columns[column_index].m_rows[row_index].m_full_text =""; m_columns[column_index].m_rows[row_index].m_short_text =""; m_columns[column_index].m_rows[row_index].m_selected_image =0; m_columns[column_index].m_rows[row_index].m_text_color =m_label_color; m_columns[column_index].m_rows[row_index].m_back_color =m_back_color; m_columns[column_index].m_rows[row_index].m_digits =0; m_columns[column_index].m_rows[row_index].m_type =CELL_SIMPLE; //--- По умолчанию у ячейки нет картинок ::ArrayFree(m_columns[column_index].m_rows[row_index].m_images); } //+------------------------------------------------------------------+ //| Делает копию указанного столбца (source) в новое место (dest.) | //+------------------------------------------------------------------+ void CTable::ColumnCopy(const uint destination,const uint source) { m_columns[destination].m_header_text =m_columns[source].m_header_text; m_columns[destination].m_width =m_columns[source].m_width; m_columns[destination].m_data_type =m_columns[source].m_data_type; m_columns[destination].m_text_align =m_columns[source].m_text_align; m_columns[destination].m_text_x_offset =m_columns[source].m_text_x_offset; m_columns[destination].m_image_x_offset =m_columns[source].m_image_x_offset; m_columns[destination].m_image_y_offset =m_columns[source].m_image_y_offset; } //+------------------------------------------------------------------+ //| Делает копию указанной ячейки (source) в новое место (dest.) | //+------------------------------------------------------------------+ void CTable::CellCopy(const uint column_dest,const uint row_dest,const uint column_source,const uint row_source) { m_columns[column_dest].m_rows[row_dest].m_type =m_columns[column_source].m_rows[row_source].m_type; m_columns[column_dest].m_rows[row_dest].m_digits =m_columns[column_source].m_rows[row_source].m_digits; m_columns[column_dest].m_rows[row_dest].m_full_text =m_columns[column_source].m_rows[row_source].m_full_text; m_columns[column_dest].m_rows[row_dest].m_short_text =m_columns[column_source].m_rows[row_source].m_short_text; m_columns[column_dest].m_rows[row_dest].m_text_color =m_columns[column_source].m_rows[row_source].m_text_color; m_columns[column_dest].m_rows[row_dest].m_back_color =m_columns[column_source].m_rows[row_source].m_back_color; m_columns[column_dest].m_rows[row_dest].m_selected_image =m_columns[column_source].m_rows[row_source].m_selected_image; //--- Копируем размер массива из источника в приёмник int images_total=::ArraySize(m_columns[column_source].m_rows[row_source].m_images); ::ArrayResize(m_columns[column_dest].m_rows[row_dest].m_images,images_total); //--- for(int i=0; i=0; i--) { //--- Удалим один символ temp_text=::StringSubstr(corrected_text,0,i); //--- Если ничего не осталось, оставим пустую строку if(temp_text=="") { corrected_text=""; break; } //--- Добавим многоточие перед проверкой int text_width=obj.TextWidth(temp_text+"..."); //--- Если помещаемся в ячейку if(text_widthm_table_visible_y_size) ? m_x_size-m_scrollh.ScrollWidth()-2 : m_x_size-2; //--- Зададим ширину фрейма для показа фрагмента изображения (видимой части таблицы таблицы) m_table_visible_x_size=x_size; //--- Корректировка размера видимой части по оси X m_table_visible_x_size=(m_table_visible_x_size>=m_table_x_size)? m_table_x_size : m_table_visible_x_size; //--- Сохраним ограничение по смещению m_shift_x2_limit=m_table_x_size-m_table_visible_x_size; } //+------------------------------------------------------------------+ //| Рассчитывает видимый размер таблицы по оси Y | //+------------------------------------------------------------------+ void CTable::CalculateTableVisibleYSize(void) { if(m_is_disabled_scrolls) { m_table_visible_y_size=m_table_y_size-1; return; } //--- Расчёт количества шагов для смещения uint x_size_total =m_table_x_size/m_shift_x_step; uint visible_x_size_total =m_table_visible_x_size/m_shift_x_step; //--- Если есть заголовки и гориз. полоса прокрутки, то скорректировать размер элемента по оси Y int header_y_size=(m_show_headers)? m_header_y_size : 2; int y_size=(x_size_total>visible_x_size_total) ? m_y_size-header_y_size-m_scrollv.ScrollWidth()-2 : m_y_size-header_y_size-2; //--- Зададим высоту фрейма для показа фрагмента изображения (видимой части таблицы таблицы) m_table_visible_y_size=y_size; //--- Корректировка размера видимой части по оси Y m_table_visible_y_size=(m_table_visible_y_size>=m_table_y_size)? m_table_y_size : m_table_visible_y_size; //--- Сохраним ограничение по смещению m_shift_y2_limit=m_table_y_size-m_table_visible_y_size; } //+------------------------------------------------------------------+ //| Изменить основные размеры таблицы | //+------------------------------------------------------------------+ void CTable::ChangeMainSize(const int x_size,const int y_size) { //--- Установить новый размер фону таблицы CElementBase::XSize(x_size); CElementBase::YSize(y_size); m_canvas.XSize(x_size); m_canvas.YSize(y_size); m_canvas.Resize(x_size,y_size); } //+------------------------------------------------------------------+ //| Изменить размеры таблицы | //+------------------------------------------------------------------+ void CTable::ChangeTableSize(void) { //--- Установить новый размер таблице m_table.XSize(m_table_visible_x_size); m_table.YSize(m_table_visible_y_size); m_headers.XSize(m_table_visible_x_size); m_headers.YSize(m_header_y_size); m_table.Resize(m_table_x_size,m_table_y_size); m_headers.Resize(m_table_x_size,m_header_y_size); //--- Установим размеры видимой области ::ObjectSetInteger(m_chart_id,m_table.ChartObjectName(),OBJPROP_XSIZE,m_table_visible_x_size); ::ObjectSetInteger(m_chart_id,m_table.ChartObjectName(),OBJPROP_YSIZE,m_table_visible_y_size); ::ObjectSetInteger(m_chart_id,m_headers.ChartObjectName(),OBJPROP_XSIZE,m_table_visible_x_size); ::ObjectSetInteger(m_chart_id,m_headers.ChartObjectName(),OBJPROP_YSIZE,m_header_y_size); //--- Изменить размеры полос прокрутки ChangeScrollsSize(); //--- Корректировка данных ShiftTable(); } //+------------------------------------------------------------------+ //| Изменить размеры полос прокрутки | //+------------------------------------------------------------------+ void CTable::ChangeScrollsSize(void) { //--- Расчёт количества шагов для смещения uint x_size_total =m_table_x_size/m_shift_x_step; uint visible_x_size_total =m_table_visible_x_size/m_shift_x_step; uint y_size_total =RowsTotal(); uint visible_y_size_total =VisibleRowsTotal(); //--- Рассчитать размеры полос прокрутки m_scrollh.Reinit(x_size_total,visible_x_size_total); m_scrollv.Reinit(y_size_total,visible_y_size_total); //--- Если горизонтальная полоса прокрутки не нужна if(!m_scrollh.IsScroll()) { //--- Скрыть горизонтальную полосу прокрутки m_scrollh.Hide(); //--- Рассчитать и изменить высоту вертикальной полосы прокрутки int y_size=CElementBase::YSize()-2; m_scrollv.ChangeYSize(y_size); } else { //--- Показать горизонтальную полосу прокрутки if(CElementBase::IsVisible() && !m_is_disabled_scrolls) m_scrollh.Show(); //--- Рассчитать и изменить высоту вертикальной полосы прокрутки int y_size=CElementBase::YSize()-m_scrollh.ScrollWidth()-2; m_scrollv.ChangeYSize(y_size); } //--- Если вертикальная полоса прокрутки не нужна if(!m_scrollv.IsScroll()) { //--- Скрыть вертикальную полосу прокрутки m_scrollv.Hide(); //--- Изменить ширину горизонтальной полосы прокрутки int x_size=CElementBase::XSize()-1; m_scrollh.ChangeXSize(x_size); } else { //--- Показать вертикальную полосу прокрутки if(CElementBase::IsVisible() && !m_is_disabled_scrolls) m_scrollv.Show(); //--- Рассчитать и изменить ширину горизонтальной полосы прокрутки int x_size=CElementBase::XSize()-m_scrollv.ScrollWidth()-1; m_scrollh.ChangeXSize(x_size); } } //+------------------------------------------------------------------+ //| Изменить ширину по правому краю формы | //+------------------------------------------------------------------+ void CTable::ChangeWidthByRightWindowSide(void) { //--- Выйти, если включен режим фиксации к правому краю формы if(m_anchor_right_window_side) return; //--- Размеры int x_size =m_main.X2()-m_canvas.X()-m_auto_xresize_right_offset; int y_size =(m_auto_yresize_mode)? m_main.Y2()-m_canvas.Y()-m_auto_yresize_bottom_offset : m_y_size; //--- Выйти, если размер меньше указанного if(x_size<100) return; //--- Установить новый размер фона таблицы ChangeMainSize(x_size,y_size); //--- Рассчитать размеры таблицы CalculateTableSize(); //--- Установить новый размер таблице ChangeTableSize(); //--- Нарисуем таблицу DrawTable(); if(m_scrollh.IsScroll()) m_scrollh.Update(true); if(m_scrollv.IsScroll()) m_scrollv.Update(true); } //+------------------------------------------------------------------+ //| Изменить высоту по нижнему краю окна | //+------------------------------------------------------------------+ void CTable::ChangeHeightByBottomWindowSide(void) { //--- Выйти, если включен режим фиксации к нижнему краю формы if(m_anchor_bottom_window_side) return; //--- Размеры int x_size =(m_auto_xresize_mode)? m_main.X2()-m_canvas.X()-m_auto_xresize_right_offset : m_x_size; int y_size =m_main.Y2()-m_canvas.Y()-m_auto_yresize_bottom_offset; //--- Выйти, если размер меньше указанного if(y_size<60) return; //--- Установить новый размер фона таблицы ChangeMainSize(x_size,y_size); //--- Рассчитать размеры таблицы CalculateTableSize(); //--- Установить новый размер таблице ChangeTableSize(); //--- Нарисуем таблицу DrawTable(); if(m_scrollh.IsScroll()) m_scrollh.Update(true); if(m_scrollv.IsScroll()) m_scrollv.Update(true); //--- Обновить Update(true); } //+------------------------------------------------------------------+