4028 líneas
338 KiB
MQL5
4028 líneas
338 KiB
MQL5
//+------------------------------------------------------------------+
|
|
//| 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<typename T>
|
|
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.X2() &&
|
|
m_mouse.Y()>m_headers.Y() && m_mouse.Y()<m_headers.Y2());
|
|
m_table.MouseFocus(m_mouse.X()>m_table.X() && m_mouse.X()<m_table.X2() &&
|
|
m_mouse.Y()>m_table.Y() && m_mouse.Y()<m_table.Y2());
|
|
//--- Изменение цвета объектов
|
|
ChangeObjectsColor();
|
|
//--- Изменить ширину захваченного столбца
|
|
ChangeColumnWidth();
|
|
return;
|
|
}
|
|
//--- Обработка события колёсика мыши
|
|
if(id==CHARTEVENT_MOUSE_WHEEL)
|
|
{
|
|
//--- Если курсор в таблице
|
|
if(m_table.MouseFocus())
|
|
{
|
|
//--- Получим текущую позицию полосы прокрутки
|
|
int pos=(m_scrollv.CurrentPos()-1<0)? 1 : m_scrollv.CurrentPos();
|
|
//--- Если колёсико мыши сместилось вниз
|
|
if(dparam<0)
|
|
VerticalScrolling(pos+1);
|
|
//--- Если колёсико мыши сместилось вверх
|
|
else if(dparam>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_size<m_table_visible_y_size-1)? visible_rows_total-1 : visible_rows_total;
|
|
return((int)visible_rows_total);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Возвращает количество картинок в указанной ячейке |
|
|
//+------------------------------------------------------------------+
|
|
int CTable::ImagesTotal(const uint column_index,const uint row_index)
|
|
{
|
|
//--- Проверка на выход из диапазона
|
|
if(!CheckOutOfRange(column_index,row_index))
|
|
return(WRONG_VALUE);
|
|
//--- Вернём размер массива картинок
|
|
return(::ArraySize(m_columns[column_index].m_rows[row_index].m_images));
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Минимальная ширина столбцов |
|
|
//+------------------------------------------------------------------+
|
|
void CTable::MinColumnWidth(const int width)
|
|
{
|
|
//--- Ширина столбца не менее 3-ёх пикселей
|
|
m_min_column_width=(width>3)? 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<m_columns_total; c++)
|
|
{
|
|
::ArrayResize(m_columns[c].m_rows,m_rows_total);
|
|
//--- Инициализация свойств столбцов значениями по умолчанию
|
|
ColumnInitialize(c);
|
|
//--- Инициализация свойств ячеек
|
|
for(uint r=0; r<m_rows_total; r++)
|
|
CellInitialize(c,r);
|
|
}
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Реконструкция таблицы |
|
|
//+------------------------------------------------------------------+
|
|
void CTable::Rebuilding(const int columns_total,const int rows_total,const bool redraw=false)
|
|
{
|
|
m_selected_item =WRONG_VALUE;
|
|
m_prev_selected_item =WRONG_VALUE;
|
|
//--- Установить новый размер
|
|
TableSize(columns_total,rows_total);
|
|
//--- Рассчитать и установить новые размеры таблицы
|
|
RecalculateAndResizeTable(redraw);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Добавляет столбец в таблицу по указанному индексу |
|
|
//+------------------------------------------------------------------+
|
|
void CTable::AddColumn(const int column_index,const bool redraw=false)
|
|
{
|
|
//--- Увеличим размер массива на один элемент
|
|
int array_size=(int)ColumnsTotal();
|
|
m_columns_total=array_size+1;
|
|
::ArrayResize(m_columns,m_columns_total);
|
|
//--- Установить размер массивам рядов
|
|
::ArrayResize(m_columns[array_size].m_rows,m_rows_total);
|
|
//--- Корректировка индекса в случае выхода из диапазона
|
|
int checked_column_index=(column_index>=(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<m_rows_total; r++)
|
|
{
|
|
//--- Инициализация ячеек нового столбца значениями по умолчанию
|
|
if(c==checked_column_index)
|
|
{
|
|
CellInitialize(c,r);
|
|
continue;
|
|
}
|
|
//--- Перемещаем данные из ячейки предыдущего столбца в ячейку текущего
|
|
CellCopy(c,r,prev_c,r);
|
|
}
|
|
}
|
|
//--- Рассчитать и установить новые размеры таблицы
|
|
RecalculateAndResizeTable(redraw);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Удаляет столбец в таблице по указанному индексу |
|
|
//+------------------------------------------------------------------+
|
|
void CTable::DeleteColumn(const int column_index,const bool redraw=false)
|
|
{
|
|
//--- Получим размер массива столбцов
|
|
int array_size=(int)ColumnsTotal();
|
|
//--- Выйти, если остался только один столбец
|
|
if(array_size<2)
|
|
return;
|
|
//--- Корректировка индекса в случае выхода из диапазона
|
|
int checked_column_index=(column_index>=array_size)? array_size-1 : column_index;
|
|
//--- Сместить другие столбцы (двигаемся от указанного индекса до последнего столбца)
|
|
for(int c=checked_column_index; c<array_size-1; c++)
|
|
{
|
|
//--- Сместить признак отсортированного массива
|
|
if(c!=checked_column_index)
|
|
{
|
|
if(c==m_is_sorted_column_index && m_is_sorted_column_index!=WRONG_VALUE)
|
|
m_is_sorted_column_index--;
|
|
}
|
|
//--- Обнулить, если удалён отсортированный столбец
|
|
else
|
|
m_is_sorted_column_index=WRONG_VALUE;
|
|
//--- Индекс следующего столбца
|
|
int next_c=c+1;
|
|
//--- Перемещаем данные из следующего столбца в текущий
|
|
ColumnCopy(c,next_c);
|
|
//--- Перемещаем данные из ячеек следующего столбца в ячейки текущего
|
|
for(uint r=0; r<m_rows_total; r++)
|
|
CellCopy(c,r,next_c,r);
|
|
}
|
|
//--- Уменьшим массив столбцов на один элемент
|
|
m_columns_total=array_size-1;
|
|
::ArrayResize(m_columns,m_columns_total);
|
|
//--- Рассчитать и установить новые размеры таблицы
|
|
RecalculateAndResizeTable(redraw);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Добавляет строку в таблицу по указанному индексу |
|
|
//+------------------------------------------------------------------+
|
|
void CTable::AddRow(const int row_index,const bool redraw=false)
|
|
{
|
|
//--- Увеличим размер массива на один элемент
|
|
int array_size=(int)RowsTotal();
|
|
m_rows_total=array_size+1;
|
|
//--- Установить размер массивам рядов
|
|
for(uint i=0; i<m_columns_total; i++)
|
|
{
|
|
::ArrayResize(m_rows,m_rows_total,100000);
|
|
::ArrayResize(m_columns[i].m_rows,m_rows_total,100000);
|
|
}
|
|
//--- Корректировка индекса в случае выхода из диапазона
|
|
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=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<array_size-1; r++)
|
|
{
|
|
//--- Индекс следующей строки
|
|
uint next_r=r+1;
|
|
//--- Перемещаем данные из ячейки следующей строки в ячейку текущей
|
|
CellCopy(c,r,c,next_r);
|
|
}
|
|
}
|
|
//--- Уменьшим размер массива строк на один элемент
|
|
m_rows_total=array_size-1;
|
|
//--- Установить размер массивам рядов
|
|
for(uint i=0; i<m_columns_total; i++)
|
|
{
|
|
::ArrayResize(m_rows,m_rows_total);
|
|
::ArrayResize(m_columns[i].m_rows,m_rows_total);
|
|
}
|
|
//--- Рассчитать и установить новые размеры таблицы
|
|
RecalculateAndResizeTable(redraw);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Удаляет все строки |
|
|
//+------------------------------------------------------------------+
|
|
void CTable::DeleteAllRows(const bool redraw=false)
|
|
{
|
|
//--- Установить размерность
|
|
TableSize(m_columns_total,1,false);
|
|
//--- Очистить ячейки
|
|
for(uint i=0; i<m_columns_total; i++)
|
|
{
|
|
m_columns[i].m_data_type=TYPE_STRING;
|
|
SetValue(i,0,"");
|
|
BackColor(i,0,clrWhite);
|
|
}
|
|
//--- Установить значения по умолчанию
|
|
m_selected_item_text ="";
|
|
m_selected_item =WRONG_VALUE;
|
|
m_last_sort_direction =SORT_ASCEND;
|
|
m_is_sorted_column_index =WRONG_VALUE;
|
|
//--- Рассчитать и установить новые размеры таблицы
|
|
RecalculateAndResizeTable(redraw);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Очищает таблицу. Остаётся только один столбец и одна строка. |
|
|
//+------------------------------------------------------------------+
|
|
void CTable::Clear(const bool redraw=false)
|
|
{
|
|
//--- Установить минимальный размер 1x1
|
|
TableSize(1,1);
|
|
//--- Установить значения по умолчанию
|
|
m_selected_item_text ="";
|
|
m_selected_item =WRONG_VALUE;
|
|
m_last_sort_direction =SORT_ASCEND;
|
|
m_is_sorted_column_index =WRONG_VALUE;
|
|
//--- Рассчитать и установить новые размеры таблицы
|
|
RecalculateAndResizeTable(redraw);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Заполняет массив заголовков по указанному индексу |
|
|
//+------------------------------------------------------------------+
|
|
void CTable::SetHeaderText(const uint column_index,const string value)
|
|
{
|
|
//--- Проверка на выход из диапазона столбцов
|
|
if(!CheckOutOfColumnRange(column_index))
|
|
return;
|
|
//--- Установить значение в массив
|
|
m_columns[column_index].m_header_text=value;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Получение текста указанного заголовка |
|
|
//+------------------------------------------------------------------+
|
|
string CTable::GetHeaderText(const uint column_index)
|
|
{
|
|
//--- Проверка на выход из диапазона столбцов
|
|
if(!CheckOutOfColumnRange(column_index))
|
|
return("");
|
|
//--- Установить значение в массив
|
|
return(m_columns[column_index].m_header_text);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Получение заголовков в переданный массив |
|
|
//+------------------------------------------------------------------+
|
|
uint CTable::GetHeadersText(string &headers[])
|
|
{
|
|
int columns_total=::ArraySize(m_columns);
|
|
::ArrayResize(headers,columns_total);
|
|
for(int c=0; c<columns_total; c++)
|
|
headers[c]=m_columns[c].m_header_text;
|
|
//--- Вернуть количество заголовков
|
|
return(columns_total);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Заполняет массив режимом выравнивания текста |
|
|
//+------------------------------------------------------------------+
|
|
void CTable::TextAlign(const ENUM_ALIGN_MODE &array[])
|
|
{
|
|
int total=0;
|
|
//--- Выйти, если передан массив нулевого размера
|
|
if((total=CheckArraySize(array))==WRONG_VALUE)
|
|
return;
|
|
//--- Сохранить значения в структуре
|
|
for(int c=0; c<total; c++)
|
|
m_columns[c].m_text_align=array[c];
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Заполняет массив режимом выравнивания текста |
|
|
//+------------------------------------------------------------------+
|
|
void CTable::TextAlign(const uint column_index,const ENUM_ALIGN_MODE align)
|
|
{
|
|
//--- Проверка на выход из диапазона столбцов
|
|
if(!CheckOutOfColumnRange(column_index))
|
|
return;
|
|
//--- Установить способ выравнивания для указанного столбца
|
|
m_columns[column_index].m_text_align=align;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Заполняет массив отступа текста в ячейке по оси X |
|
|
//+------------------------------------------------------------------+
|
|
void CTable::TextXOffset(const int &array[])
|
|
{
|
|
int total=0;
|
|
//--- Выйти, если передан массив нулевого размера
|
|
if((total=CheckArraySize(array))==WRONG_VALUE)
|
|
return;
|
|
//--- Сохранить значения в структуре
|
|
for(int c=0; c<total; c++)
|
|
m_columns[c].m_text_x_offset=array[c];
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Заполняет массив ширины столбцов |
|
|
//+------------------------------------------------------------------+
|
|
void CTable::ColumnsWidth(const int &array[])
|
|
{
|
|
int total=0;
|
|
//--- Выйти, если передан массив нулевого размера
|
|
if((total=CheckArraySize(array))==WRONG_VALUE)
|
|
return;
|
|
//--- Сохранить значения в структуре
|
|
for(int c=0; c<total; c++)
|
|
m_columns[c].m_width=array[c];
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Отступы картинок от краёв ячеек по оси X |
|
|
//+------------------------------------------------------------------+
|
|
void CTable::ImageXOffset(const int &array[])
|
|
{
|
|
int total=0;
|
|
//--- Выйти, если передан массив нулевого размера
|
|
if((total=CheckArraySize(array))==WRONG_VALUE)
|
|
return;
|
|
//--- Сохранить значения в структуре
|
|
for(int c=0; c<total; c++)
|
|
m_columns[c].m_image_x_offset=array[c];
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Отступы картинок от краёв ячеек по оси Y |
|
|
//+------------------------------------------------------------------+
|
|
void CTable::ImageYOffset(const int &array[])
|
|
{
|
|
int total=0;
|
|
//--- Выйти, если передан массив нулевого размера
|
|
if((total=CheckArraySize(array))==WRONG_VALUE)
|
|
return;
|
|
//--- Сохранить значения в структуре
|
|
for(int c=0; c<total; c++)
|
|
m_columns[c].m_image_y_offset=array[c];
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Установка типа данных в указанном столбце |
|
|
//+------------------------------------------------------------------+
|
|
void CTable::DataType(const uint column_index,const ENUM_DATATYPE type)
|
|
{
|
|
//--- Проверка на выход из диапазона столбцов
|
|
if(!CheckOutOfColumnRange(column_index))
|
|
return;
|
|
//--- Установить тип данных для указанного столбца
|
|
m_columns[column_index].m_data_type=type;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Получение типа данных в указанном столбце |
|
|
//+------------------------------------------------------------------+
|
|
ENUM_DATATYPE CTable::DataType(const uint column_index)
|
|
{
|
|
//--- Проверка на выход из диапазона столбцов
|
|
if(!CheckOutOfColumnRange(column_index))
|
|
return(WRONG_VALUE);
|
|
//--- Вернуть тип данных для указанного столбца
|
|
return(m_columns[column_index].m_data_type);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Устанавливает тип ячейки |
|
|
//+------------------------------------------------------------------+
|
|
void CTable::CellType(const uint column_index,const uint row_index,const ENUM_TYPE_CELL type)
|
|
{
|
|
//--- Проверка на выход из диапазона
|
|
if(!CheckOutOfRange(column_index,row_index))
|
|
return;
|
|
//--- Установить тип ячейки
|
|
m_columns[column_index].m_rows[row_index].m_type=type;
|
|
//--- Признак наличия поля ввода
|
|
if(type==CELL_EDIT && !m_edit_state)
|
|
m_edit_state=true;
|
|
//--- Признак наличия комбо-бокса
|
|
else if(type==CELL_COMBOBOX && !m_combobox_state)
|
|
m_combobox_state=true;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Получение типа ячейки |
|
|
//+------------------------------------------------------------------+
|
|
ENUM_TYPE_CELL CTable::CellType(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_type);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Устанавливает картинки в указанную ячейку |
|
|
//+------------------------------------------------------------------+
|
|
void CTable::SetImages(const uint column_index,const uint row_index,const string &bmp_file_path[])
|
|
{
|
|
//--- Проверка на выход из диапазона
|
|
if(!CheckOutOfRange(column_index,row_index))
|
|
return;
|
|
//--- Выйти, если передан массив нулевого размера
|
|
int total=0;
|
|
if((total=::ArraySize(bmp_file_path))<1)
|
|
return;
|
|
//--- Установить новый размер массивам
|
|
::ArrayResize(m_columns[column_index].m_rows[row_index].m_images,total);
|
|
//---
|
|
for(int i=0; i<total; i++)
|
|
{
|
|
//--- По умолчанию выбрана первая картинка массива
|
|
m_columns[column_index].m_rows[row_index].m_selected_image=0;
|
|
//--- Записать переданную картинку в массив и запомнить её размеры
|
|
if(!m_columns[column_index].m_rows[row_index].m_images[i].ReadImageData(bmp_file_path[i]))
|
|
return;
|
|
}
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Устанавливает картинки в указанную ячейку |
|
|
//+------------------------------------------------------------------+
|
|
void CTable::SetImages(const uint column_index,const uint row_index,const uint &resource_index[])
|
|
{
|
|
//--- Проверка на выход из диапазона
|
|
if(!CheckOutOfRange(column_index,row_index))
|
|
return;
|
|
//--- Выйти, если передан массив нулевого размера
|
|
int total=0;
|
|
if((total=::ArraySize(resource_index))<1)
|
|
return;
|
|
//--- Установить новый размер массивам
|
|
::ArrayResize(m_columns[column_index].m_rows[row_index].m_images,total);
|
|
//---
|
|
for(int i=0; i<total; i++)
|
|
{
|
|
//--- По умолчанию выбрана первая картинка массива
|
|
m_columns[column_index].m_rows[row_index].m_selected_image=0;
|
|
//--- Записать переданную картинку в массив и запомнить её размеры
|
|
if(!m_columns[column_index].m_rows[row_index].m_images[i].ReadImageData(resource_index[i]))
|
|
return;
|
|
}
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Изменяет картинку в указанной ячейке |
|
|
//+------------------------------------------------------------------+
|
|
void CTable::ChangeImage(const uint column_index,const uint row_index,const uint image_index,const bool redraw=false)
|
|
{
|
|
//--- Проверка на выход из диапазона
|
|
if(!CheckOutOfRange(column_index,row_index))
|
|
return;
|
|
//--- Получим количество картинок ячейки
|
|
int images_total=ImagesTotal(column_index,row_index);
|
|
//--- Выйти, если (1) картинок нет или (2) выходим из диапазона
|
|
if(images_total==WRONG_VALUE || image_index>=(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<m_columns_total; c++)
|
|
sum_width+=m_columns[c].m_width;
|
|
//--- Корректируем ширину последнего столбца
|
|
if(m_rows_total>(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<table_x_size)
|
|
{
|
|
int difference=table_x_size-sum_width;
|
|
m_columns[last_column_index].m_width=m_columns[last_column_index].m_width+difference;
|
|
}
|
|
else
|
|
{
|
|
int difference=sum_width-(table_x_size);
|
|
m_columns[last_column_index].m_width=m_columns[last_column_index].m_width-difference;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Авто-коррекция ширины столбцов по тексту |
|
|
//+------------------------------------------------------------------+
|
|
void CTable::AutoCorrectWidthColumns(void)
|
|
{
|
|
if(!m_auto_correct_columns_width_mode || m_column_resize_mode)
|
|
return;
|
|
//--- Определяем максимальную ширину для каждого столбца
|
|
uint max_width[];
|
|
::ArrayResize(max_width,m_columns_total);
|
|
for(uint c=0; c<m_columns_total; c++)
|
|
{
|
|
uint width =0;
|
|
uint height =0;
|
|
::TextGetSize(GetHeaderText(c),width,height);
|
|
max_width[c]=width;
|
|
//---
|
|
for(uint r=0; r<m_rows_total; r++)
|
|
{
|
|
string text=m_columns[c].m_rows[r].m_full_text;
|
|
::TextGetSize(text,width,height);
|
|
max_width[c]=(uint)::fmax((double)width,(double)max_width[c]);
|
|
}
|
|
//---
|
|
m_columns[c].m_width=(int)max_width[c]+25;
|
|
}
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Обновление таблицы |
|
|
//+------------------------------------------------------------------+
|
|
void CTable::Update(const bool redraw=false)
|
|
{
|
|
//--- Перерисовать таблицу, если указано
|
|
if(redraw)
|
|
{
|
|
//--- Авторазмер столбцов
|
|
AutoCorrectWidthColumns();
|
|
AutoResizeColumns();
|
|
//--- Установить новый размер фона таблицы
|
|
ChangeMainSize(m_x_size,m_y_size);
|
|
//--- Рассчитать размеры таблицы
|
|
CalculateTableSize();
|
|
//--- Установить новый размер таблице
|
|
ChangeTableSize();
|
|
//--- Перерисовать таблицу
|
|
DrawTable();
|
|
//--- Обновить таблицу
|
|
m_canvas.Update();
|
|
m_table.Update();
|
|
//--- Обновить заголовки, если они включены
|
|
if(m_show_headers)
|
|
m_headers.Update();
|
|
//--- Обновить полосы прокрутки
|
|
m_scrollv.Update(true);
|
|
m_scrollh.Update(true);
|
|
return;
|
|
}
|
|
//--- Авторазмер столбцов
|
|
AutoCorrectWidthColumns();
|
|
AutoResizeColumns();
|
|
//--- Обновить таблицу
|
|
m_canvas.Update();
|
|
m_table.Update();
|
|
//--- Обновить заголовки, если они включены
|
|
if(m_show_headers)
|
|
m_headers.Update();
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Обработка нажатия на заголовке |
|
|
//+------------------------------------------------------------------+
|
|
bool CTable::OnClickHeaders(const string clicked_object)
|
|
{
|
|
//--- Выйти, если (1) режим сортировки отключен или (2) в процессе изменения ширины столбца
|
|
if(!m_is_sort_mode || m_column_resize_control!=WRONG_VALUE)
|
|
return(false);
|
|
//--- Выйти, если в ячейках есть поля ввода или комбо-боксы в ячейках
|
|
if(m_edit_state && m_combobox_state)
|
|
return(false);
|
|
//--- Выйдем, если полоса прокрутки в активном режиме
|
|
if(m_scrollv.State() || m_scrollh.State())
|
|
return(false);
|
|
//--- Выйдем, если чужое имя объекта
|
|
if(m_headers.ChartObjectName()!=clicked_object)
|
|
return(false);
|
|
//--- Для определения индекса столбца
|
|
uint column_index=0;
|
|
//--- Получим относительную X-координату под курсором мыши
|
|
int x=m_mouse.RelativeX(m_headers);
|
|
//--- Определим заголовок, на котором нажали
|
|
for(uint c=0; c<m_columns_total; c++)
|
|
{
|
|
//--- Если нашли заголовок, запомним его индекс
|
|
if(x>=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_total; r++)
|
|
{
|
|
//--- Если нажатие было не на этом ряде, перейти к следующему
|
|
if(!(y>=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_total; c++)
|
|
{
|
|
//--- Если на этой ячейке нажали, запомним индекс столбца
|
|
if(x>=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<ImagesTotal(column_index,row_index)-1)?++image_i : 0;
|
|
//--- Выбрать следующую картинку
|
|
//if(m_selectable_row)
|
|
// {
|
|
// ChangeImage(column_index,row_index,next_i);
|
|
// RedrawRow(true);
|
|
// }
|
|
//else
|
|
|
|
ChangeImage(column_index,row_index,next_i,true);
|
|
//--- Обновить таблицу
|
|
m_table.Update();
|
|
//--- Отправим сообщение об этом
|
|
::EventChartCustom(m_chart_id,ON_CLICK_CHECKBOX,CElementBase::Id(),next_i,string(column_index)+"_"+string(row_index));
|
|
}
|
|
//---
|
|
return(true);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Проверяет, было ли нажатие на поле ввода в ячейке |
|
|
//+------------------------------------------------------------------+
|
|
bool CTable::CheckPressedEdit(const int column_index,const int row_index,const bool double_click=false)
|
|
{
|
|
//--- Выйти, если это не двойной клик
|
|
if(!double_click)
|
|
return(false);
|
|
//--- Сохранить индексы
|
|
m_last_edit_row_index =row_index;
|
|
m_last_edit_column_index =column_index;
|
|
//--- Сдвиг по двум осям
|
|
int x_offset =(int)::ObjectGetInteger(m_chart_id,m_table.ChartObjectName(),OBJPROP_XOFFSET);
|
|
int y_offset =(int)::ObjectGetInteger(m_chart_id,m_table.ChartObjectName(),OBJPROP_YOFFSET);
|
|
//--- Установить новые координаты
|
|
m_edit.XGap(m_columns[column_index].m_x-x_offset);
|
|
m_edit.YGap(m_rows[row_index].m_y+((m_show_headers)? m_header_y_size : 0)-y_offset);
|
|
//--- Размеры
|
|
int x_size =m_columns[column_index].m_x2-m_columns[column_index].m_x+1;
|
|
int y_size =m_cell_y_size+1;
|
|
//--- Установить размер
|
|
m_edit.GetTextBoxPointer().ChangeSize(x_size,y_size);
|
|
//--- Установить значение из ячейки таблицы
|
|
m_edit.SetValue(m_columns[column_index].m_rows[row_index].m_full_text);
|
|
//--- Активировать поле ввода
|
|
m_edit.GetTextBoxPointer().ActivateTextBox();
|
|
//--- Установить фокус
|
|
m_edit.GetTextBoxPointer().MouseFocus(true);
|
|
//--- Показать поле ввода
|
|
m_edit.Reset();
|
|
//--- Перерисовать график
|
|
m_chart.Redraw();
|
|
return(true);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Проверяет, было ли нажатие на комбо-боксе в ячейке |
|
|
//+------------------------------------------------------------------+
|
|
bool CTable::CheckPressedCombobox(const int column_index,const int row_index,const bool double_click=false)
|
|
{
|
|
//--- Выйти, если это не двойной клик
|
|
if(!double_click)
|
|
return(false);
|
|
//--- Сохранить индексы
|
|
m_last_edit_row_index =row_index;
|
|
m_last_edit_column_index =column_index;
|
|
//--- Сдвиг по двум осям
|
|
int x_offset =(int)::ObjectGetInteger(m_chart_id,m_table.ChartObjectName(),OBJPROP_XOFFSET);
|
|
int y_offset =(int)::ObjectGetInteger(m_chart_id,m_table.ChartObjectName(),OBJPROP_YOFFSET);
|
|
//--- Установить новые координаты
|
|
m_combobox.XGap(m_columns[column_index].m_x-x_offset);
|
|
m_combobox.YGap(m_rows[row_index].m_y+((m_show_headers)? m_header_y_size : 0)-y_offset);
|
|
//--- Установить размер кнопке
|
|
int x_size =m_columns[column_index].m_x2-m_columns[column_index].m_x+1;
|
|
int y_size =m_cell_y_size+1;
|
|
m_combobox.GetButtonPointer().ChangeSize(x_size,y_size);
|
|
//--- Установить размер списку
|
|
y_size=m_combobox.GetListViewPointer().YSize();
|
|
m_combobox.GetListViewPointer().ChangeSize(x_size,y_size);
|
|
//--- Установить размер списка ячейки
|
|
int total=::ArraySize(m_columns[column_index].m_rows[row_index].m_value_list);
|
|
m_combobox.GetListViewPointer().Rebuilding(total);
|
|
//--- Установить список из ячейки
|
|
for(int i=0; i<total; i++)
|
|
m_combobox.GetListViewPointer().SetValue(i,m_columns[column_index].m_rows[row_index].m_value_list[i]);
|
|
//--- Установить пункт из ячейки
|
|
int index=m_columns[column_index].m_rows[row_index].m_selected_item;
|
|
m_combobox.SelectItem(index);
|
|
//--- Обновить элемент
|
|
m_combobox.GetButtonPointer().MouseFocus(true);
|
|
m_combobox.GetButtonPointer().Update(true);
|
|
m_combobox.GetListViewPointer().Update(true);
|
|
//--- Показать поле ввода
|
|
m_combobox.Reset();
|
|
//--- Перерисовать график
|
|
m_chart.Redraw();
|
|
//--- Отправим сообщение об изменении в графическом интерфейсе
|
|
::EventChartCustom(m_chart_id,ON_CHANGE_GUI,CElementBase::Id(),0,"");
|
|
return(true);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Алгоритм быстрой сортировки |
|
|
//+------------------------------------------------------------------+
|
|
void CTable::QuickSort(uint beg,uint end,uint column,const ENUM_CSORT_MODE mode=SORT_ASCEND)
|
|
{
|
|
uint r1 =beg;
|
|
uint r2 =end;
|
|
uint c =column;
|
|
string temp =NULL;
|
|
string value =NULL;
|
|
uint data_total =m_rows_total-1;
|
|
//--- Выполнять алгоритм, пока левый индекс меньше самого крайнего правого индекса
|
|
while(r1<end)
|
|
{
|
|
//--- Получим значение из середины ряда
|
|
value=m_columns[c].m_rows[(beg+end)>>1].m_full_text;
|
|
//--- Выполнять алгоритм, пока левый индекс меньше найденного правого индекса
|
|
while(r1<r2)
|
|
{
|
|
//--- Смещать индекс вправо, пока находим значение по указанному условию
|
|
while(CheckSortCondition(c,r1,value,(mode==SORT_ASCEND)? false : true))
|
|
{
|
|
//--- Контроль выхода за границы массива
|
|
if(r1==data_total)
|
|
break;
|
|
r1++;
|
|
}
|
|
//--- Смещать индекс влево, пока находим значение по указанному условию
|
|
while(CheckSortCondition(c,r2,value,(mode==SORT_ASCEND)? true : false))
|
|
{
|
|
//--- Контроль выхода за границы массива
|
|
if(r2==0)
|
|
break;
|
|
r2--;
|
|
}
|
|
//--- Если левый индекс ещё не больше правого
|
|
if(r1<=r2)
|
|
{
|
|
//--- Поменять значения местами
|
|
Swap(r1,r2);
|
|
//--- Если дошли до предела слева
|
|
if(r2==0)
|
|
{
|
|
r1++;
|
|
break;
|
|
}
|
|
//---
|
|
r1++;
|
|
r2--;
|
|
}
|
|
}
|
|
//--- Рекурсивное продолжение алгоритма, пока не дойдём до начала диапазона
|
|
if(beg<r2)
|
|
QuickSort(beg,r2,c,mode);
|
|
//--- Cужение диапазона для следующей итерации
|
|
beg=r1;
|
|
r2=end;
|
|
}
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Сравнение значений по указанному условию сортировки |
|
|
//+------------------------------------------------------------------+
|
|
//| direction: true (>), 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 : v1<v2;
|
|
break;
|
|
}
|
|
//---
|
|
case TYPE_DOUBLE :
|
|
{
|
|
double v1=double(m_columns[column_index].m_rows[row_index].m_full_text);
|
|
double v2=double(check_value);
|
|
condition=(direction)? v1>v2 : v1<v2;
|
|
break;
|
|
}
|
|
//---
|
|
case TYPE_DATETIME :
|
|
{
|
|
datetime v1=::StringToTime(m_columns[column_index].m_rows[row_index].m_full_text);
|
|
datetime v2=::StringToTime(check_value);
|
|
condition=(direction)? v1>v2 : v1<v2;
|
|
break;
|
|
}
|
|
//---
|
|
default :
|
|
{
|
|
long v1=(long)m_columns[column_index].m_rows[row_index].m_full_text;
|
|
long v2=(long)check_value;
|
|
condition=(direction)? v1>v2 : v1<v2;
|
|
break;
|
|
}
|
|
}
|
|
//---
|
|
return(condition);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Меняет элементы местами |
|
|
//+------------------------------------------------------------------+
|
|
void CTable::Swap(uint r1,uint r2)
|
|
{
|
|
//--- Пройдёмся в цикле по всем столбцам
|
|
for(uint c=0; c<m_columns_total; c++)
|
|
{
|
|
//--- Меняем местами полный текст
|
|
string temp_text =m_columns[c].m_rows[r1].m_full_text;
|
|
m_columns[c].m_rows[r1].m_full_text =m_columns[c].m_rows[r2].m_full_text;
|
|
m_columns[c].m_rows[r2].m_full_text =temp_text;
|
|
//--- Меняем местами краткий текст
|
|
temp_text =m_columns[c].m_rows[r1].m_short_text;
|
|
m_columns[c].m_rows[r1].m_short_text =m_columns[c].m_rows[r2].m_short_text;
|
|
m_columns[c].m_rows[r2].m_short_text =temp_text;
|
|
//--- Меняем местами кол-во знаков после запятой
|
|
uint temp_digits =m_columns[c].m_rows[r1].m_digits;
|
|
m_columns[c].m_rows[r1].m_digits =m_columns[c].m_rows[r2].m_digits;
|
|
m_columns[c].m_rows[r2].m_digits =temp_digits;
|
|
//--- Меняем местами цвет текста
|
|
color temp_text_color =m_columns[c].m_rows[r1].m_text_color;
|
|
m_columns[c].m_rows[r1].m_text_color =m_columns[c].m_rows[r2].m_text_color;
|
|
m_columns[c].m_rows[r2].m_text_color =temp_text_color;
|
|
//--- Меняем местами цвет фона
|
|
color temp_back_color =m_columns[c].m_rows[r1].m_back_color;
|
|
m_columns[c].m_rows[r1].m_back_color =m_columns[c].m_rows[r2].m_back_color;
|
|
m_columns[c].m_rows[r2].m_back_color =temp_back_color;
|
|
//--- Меняем местами индекс выбранной картинки
|
|
int temp_selected_image =m_columns[c].m_rows[r1].m_selected_image;
|
|
m_columns[c].m_rows[r1].m_selected_image =m_columns[c].m_rows[r2].m_selected_image;
|
|
m_columns[c].m_rows[r2].m_selected_image =temp_selected_image;
|
|
//--- Проверим, есть ли картинки в ячейках
|
|
int r1_images_total=::ArraySize(m_columns[c].m_rows[r1].m_images);
|
|
int r2_images_total=::ArraySize(m_columns[c].m_rows[r2].m_images);
|
|
//--- Переходим к следующему столбцу, если в обеих ячейках нет картинок
|
|
if(r1_images_total<1 && r2_images_total<1)
|
|
continue;
|
|
//--- Меняем местами картинки
|
|
CImage r1_temp_images[];
|
|
//---
|
|
::ArrayResize(r1_temp_images,r1_images_total);
|
|
for(int i=0; i<r1_images_total; i++)
|
|
ImageCopy(r1_temp_images,m_columns[c].m_rows[r1].m_images,i);
|
|
//---
|
|
::ArrayResize(m_columns[c].m_rows[r1].m_images,r2_images_total);
|
|
for(int i=0; i<r2_images_total; i++)
|
|
ImageCopy(m_columns[c].m_rows[r1].m_images,m_columns[c].m_rows[r2].m_images,i);
|
|
//---
|
|
::ArrayResize(m_columns[c].m_rows[r2].m_images,r1_images_total);
|
|
for(int i=0; i<r1_images_total; i++)
|
|
ImageCopy(m_columns[c].m_rows[r2].m_images,r1_temp_images,i);
|
|
}
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Рисует элемент |
|
|
//+------------------------------------------------------------------+
|
|
void CTable::Draw(void)
|
|
{
|
|
DrawTable();
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Рисует таблицу |
|
|
//+------------------------------------------------------------------+
|
|
void CTable::DrawTable(const bool only_visible=false)
|
|
{
|
|
//--- Если не указано перерисовать только видимую часть таблицы
|
|
if(!only_visible)
|
|
{
|
|
//--- Установим индексы строк всей таблицы от самого начала и до конца
|
|
m_visible_table_from_index =0;
|
|
m_visible_table_to_index =m_rows_total;
|
|
}
|
|
//--- Получим индексы строк видимой части таблицы
|
|
else
|
|
VisibleTableIndexes();
|
|
//--- Нарисовать фон
|
|
CElement::DrawBackground();
|
|
//--- Нарисовать рамку
|
|
CElement::DrawBorder();
|
|
//--- Нарисовать сетку
|
|
DrawGrid();
|
|
//--- Нарисовать фон строк таблицы
|
|
DrawRows();
|
|
//--- Нарисовать выделенную строку
|
|
DrawSelectedRow();
|
|
//--- Нарисовать картинку
|
|
DrawImages();
|
|
//--- Нарисовать текст
|
|
DrawText();
|
|
//--- Обновить заголовки, если они включены
|
|
if(m_show_headers)
|
|
DrawTableHeaders();
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Перерисовывает указанную ячейку таблицы |
|
|
//+------------------------------------------------------------------+
|
|
void CTable::RedrawCell(const int column_index,const int row_index)
|
|
{
|
|
//--- Координаты
|
|
int x1=m_columns[column_index].m_x+1;
|
|
int x2=m_columns[column_index].m_x2-1;
|
|
int y1=m_rows[row_index].m_y+1;
|
|
int y2=m_rows[row_index].m_y2-1;
|
|
//--- Для расчёта координат
|
|
int x=0,y=0;
|
|
//--- Для проверки фокуса
|
|
bool is_row_focus=false;
|
|
//--- Если включен режим подсветки строк таблицы
|
|
if(m_lights_hover)
|
|
{
|
|
//--- (1) Получим относительную Y-координату курсора мыши и (2) фокус на указанной строке таблицы
|
|
y=m_mouse.RelativeY(m_table);
|
|
is_row_focus=(y>m_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; c<m_columns_total; c++)
|
|
{
|
|
//--- Получим X-координату текста
|
|
x=TextX(c);
|
|
//--- Остановим цикл
|
|
if(c==column_index)
|
|
break;
|
|
}
|
|
//--- (1) Рассчитать Y-координату и (2) нарисовать текст
|
|
y=y1+m_label_y_gap-1;
|
|
m_table.TextOut(x,y,m_columns[column_index].m_rows[row_index].m_short_text,TextColor(column_index,row_index),text_align);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Рисует указанный ряд таблицы по указанному режиму |
|
|
//+------------------------------------------------------------------+
|
|
void CTable::DrawRow(int &indexes[],const int item_index,const int prev_item_index,const bool is_user=true)
|
|
{
|
|
int x1=0,x2=m_table_x_size-2;
|
|
int y1[2]={0},y2[2]={0};
|
|
//--- Количество строк и столбцов для рисования
|
|
uint rows_total =0;
|
|
uint columns_total =m_columns_total-1;
|
|
//--- Если это программный метод выделения строки
|
|
if(!is_user)
|
|
rows_total=(prev_item_index!=WRONG_VALUE && item_index!=prev_item_index)? 2 : 1;
|
|
else
|
|
rows_total=(item_index!=WRONG_VALUE && prev_item_index!=WRONG_VALUE && item_index!=prev_item_index)? 2 : 1;
|
|
//--- Рисуем фон строк
|
|
for(uint r=0; r<rows_total; r++)
|
|
{
|
|
//--- Расчёт координат верхней и нижней границ строки
|
|
y1[r] =m_rows[indexes[r]].m_y+1;
|
|
y2[r] =m_rows[indexes[r]].m_y2-1;
|
|
//--- Определим фокус на строке относительно режима подсветки
|
|
bool is_item_focus=false;
|
|
if(!m_lights_hover)
|
|
is_item_focus=(indexes[r]==item_index && item_index!=WRONG_VALUE);
|
|
else
|
|
is_item_focus=(item_index==WRONG_VALUE)?(indexes[r]==prev_item_index) :(indexes[r]==item_index);
|
|
//--- Нарисовать фон ячейки
|
|
for(uint c=0; c<m_columns_total; c++)
|
|
{
|
|
x1=m_columns[c].m_x+((c>0)? 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; r<rows_total; r++)
|
|
{
|
|
for(uint c=0; c<columns_total; c++)
|
|
m_table.Line(m_columns[c].m_x2,y1[r],m_columns[c].m_x2,y2[r],::ColorToARGB(m_grid_color));
|
|
}
|
|
//--- Рисуем картинки
|
|
for(uint r=0; r<rows_total; r++)
|
|
{
|
|
for(uint c=0; c<m_columns_total; c++)
|
|
{
|
|
//--- Рисуем картинку, если (1) она есть в этой ячейке и (2) в этом столбце выравнивание текста по левому краю
|
|
if(ImagesTotal(c,indexes[r])>0 && 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; c<m_columns_total; c++)
|
|
{
|
|
//--- Получим (1) X-координату текста и (2) способ выравнивания текста
|
|
x =TextX(c);
|
|
text_align =TextAlign(c,TA_TOP);
|
|
//---
|
|
for(uint r=0; r<rows_total; r++)
|
|
{
|
|
//--- (1) Рассчитать координату и (2) нарисовать текст
|
|
y=m_rows[indexes[r]].m_y+m_label_y_gap;
|
|
m_table.TextOut(x,y,m_columns[c].m_rows[indexes[r]].m_short_text,TextColor(c,indexes[r]),text_align);
|
|
}
|
|
}
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Перерисовывает указанный ряд таблицы по указанному режиму |
|
|
//+------------------------------------------------------------------+
|
|
void CTable::RedrawRow(const bool is_selected_row=false)
|
|
{
|
|
//--- Текущий и предыдущий индексы строк
|
|
int item_index =WRONG_VALUE;
|
|
int prev_item_index =WRONG_VALUE;
|
|
//--- Инициализиция индексов строк относительного указанного режима
|
|
if(is_selected_row)
|
|
{
|
|
item_index =m_selected_item;
|
|
prev_item_index =m_prev_selected_item;
|
|
}
|
|
else
|
|
{
|
|
item_index =m_item_index_focus;
|
|
prev_item_index =m_prev_item_index_focus;
|
|
}
|
|
//--- Выйти, если индексы не определены
|
|
if(prev_item_index==WRONG_VALUE && item_index==WRONG_VALUE)
|
|
return;
|
|
//--- Массив для значений в определённой последовательности
|
|
int indexes[2];
|
|
//--- Если (1) курсор мыши сдвинулся вниз или (2) в первый раз здесь
|
|
if(item_index>m_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; r<m_visible_table_to_index; r++)
|
|
{
|
|
//--- Расчёт координат границ ряда с сохранением значений
|
|
m_rows[r].m_y =(int)(r*m_cell_y_size);
|
|
m_rows[r].m_y2 =m_rows[r].m_y+m_cell_y_size;
|
|
y1 =m_rows[r].m_y+((r>0)? 1 : 0);
|
|
y2 =m_rows[r].m_y2-1;
|
|
//--- Проверим фокус
|
|
is_row_focus=(m_lights_hover)?(y>y1 && y<y2) : false;
|
|
//--- Нарисовать фон ячейки
|
|
for(uint c=0; c<m_columns_total; c++)
|
|
{
|
|
x1 =m_columns[c].m_x+((c>0)? 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; c<m_columns_total; c++)
|
|
{
|
|
x1 =m_columns[c].m_x+((c>0)? 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; r<m_rows_total; r++)
|
|
{
|
|
//--- Расчёт координат границ ряда с сохранением значений
|
|
m_rows[r].m_y =y1 =(int)(r*m_cell_y_size);
|
|
m_rows[r].m_y2 =y2 =y1+m_cell_y_size;
|
|
m_table.Line(x1,m_rows[r].m_y,x2,m_rows[r].m_y,clr);
|
|
}
|
|
//--- Вертикальные линии
|
|
x1=0; y1=0; x2=0; y2=y_size;
|
|
for(uint i=0; i<m_columns_total; i++)
|
|
{
|
|
m_columns[i].m_x2=x2=x1+=m_columns[i].m_width;
|
|
m_table.Line(x1,y1,x2,y2,clr);
|
|
//--- Сохраним X-координату столбца
|
|
if(i>0)
|
|
{
|
|
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; ly<image_height; ly++)
|
|
{
|
|
for(uint lx=0; lx<image_width; lx++,i++)
|
|
{
|
|
//--- Если нет цвета, перейти к следующему пикселю
|
|
if(m_columns[column_index].m_rows[row_index].m_images[selected_image].Data(i)<1)
|
|
continue;
|
|
//--- Получаем цвет нижнего слоя (фона ячейки) и цвет указанного пикселя картинки
|
|
uint background =(row_index==m_selected_item)? m_selected_row_color : m_canvas.PixelGet(x+lx,y+ly);
|
|
uint pixel_color =m_columns[column_index].m_rows[row_index].m_images[selected_image].Data(i);
|
|
//--- Смешиваем цвета
|
|
uint foreground=::ColorToARGB(m_clr.BlendColors(background,pixel_color));
|
|
//--- Рисуем пиксель наслаиваемого изображения
|
|
m_table.PixelSet(x+lx,y+ly,foreground);
|
|
}
|
|
}
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Рисует текст |
|
|
//+------------------------------------------------------------------+
|
|
void CTable::DrawText(void)
|
|
{
|
|
//--- Для расчёта координат и отступов
|
|
int x=0,y=0;
|
|
uint text_align=0;
|
|
//--- Свойства шрифта
|
|
m_table.FontSet(CElement::Font(),-CElement::FontSize()*10,FW_NORMAL);
|
|
//--- Столбцы
|
|
for(uint c=0; c<m_columns_total; c++)
|
|
{
|
|
//--- Получим X-координату текста
|
|
x=TextX(c);
|
|
//--- Получим способ выравнивания текста
|
|
text_align=TextAlign(c,TA_TOP);
|
|
//--- Ряды
|
|
for(uint r=m_visible_table_from_index; r<m_visible_table_to_index; r++)
|
|
{
|
|
//--- Рассчитаем Y-координату
|
|
y=m_rows[r].m_y+m_label_y_gap;
|
|
//--- Нарисовать текст
|
|
m_table.TextOut(x,y,Text(c,r),TextColor(c,r),text_align);
|
|
}
|
|
//--- Обнулить координату Y для следующего цикла
|
|
y=0;
|
|
}
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Рисует заголовки таблицы |
|
|
//+------------------------------------------------------------------+
|
|
void CTable::DrawTableHeaders(void)
|
|
{
|
|
//--- Нарисовать заголовки
|
|
DrawHeaders();
|
|
//--- Нарисовать сетку
|
|
DrawHeadersGrid();
|
|
//--- Нарисовать текст заголовков
|
|
DrawHeadersText();
|
|
//--- Нарисовать признак возможности сортировки таблицы
|
|
DrawSignSortedData();
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Рисует фон заголовков |
|
|
//+------------------------------------------------------------------+
|
|
void CTable::DrawHeaders(void)
|
|
{
|
|
//--- Если не в фокусе, сбросить цвет заголовков
|
|
if(!m_headers.MouseFocus() && m_column_resize_control==WRONG_VALUE)
|
|
{
|
|
m_headers.Erase(::ColorToARGB(m_headers_color,m_alpha));
|
|
return;
|
|
}
|
|
//--- Для проверки фокуса над заголовками
|
|
bool is_header_focus=false;
|
|
//--- Координаты курсора мыши
|
|
int x=0;
|
|
//--- Координаты
|
|
int y1=0,y2=m_header_y_size;
|
|
//--- Получим относительную X-координату под курсором мыши
|
|
if(::CheckPointer(m_mouse)!=POINTER_INVALID)
|
|
x=m_mouse.RelativeX(m_headers);
|
|
//--- Очистить фон заголовков
|
|
m_headers.Erase(::ColorToARGB(clrNONE,m_alpha));
|
|
//--- Отступ с учётом режима изменения ширины столбцов
|
|
int sep_x_offset=(m_column_resize_mode)? m_sep_x_offset : 0;
|
|
//--- Рисуем фон заголовков
|
|
for(uint i=0; i<m_columns_total; i++)
|
|
{
|
|
//--- Проверим фокус
|
|
if(is_header_focus=x>m_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<m_columns_total; i++)
|
|
m_headers.Line(m_columns[i].m_x,y1,m_columns[i].m_x,y2,clr);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Рисует признак возможности сортировки таблицы |
|
|
//+------------------------------------------------------------------+
|
|
void CTable::DrawSignSortedData(void)
|
|
{
|
|
//--- Выйти, если (1) сортировка отключена или (2) ещё не была осуществлена
|
|
if(!m_is_sort_mode || m_is_sorted_column_index==WRONG_VALUE)
|
|
return;
|
|
//--- Выйти, если в ячейках есть поля ввода или комбо-боксы в ячейках
|
|
if(m_edit_state && m_combobox_state)
|
|
return;
|
|
//--- Выйти, если выход за пределы массива
|
|
if(m_is_sorted_column_index>=::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; ly<m_sort_arrows[image_index].Height(); ly++)
|
|
{
|
|
for(uint lx=0; lx<m_sort_arrows[image_index].Width(); lx++,i++)
|
|
{
|
|
//--- Если нет цвета, перейти к следующему пикселю
|
|
if(m_sort_arrows[image_index].Data(i)<1)
|
|
continue;
|
|
//--- Получаем цвет нижнего слоя (фона заголовка) и цвет указанного пикселя картинки
|
|
uint background =m_headers.PixelGet(x+lx,y+ly);
|
|
uint pixel_color =m_sort_arrows[image_index].Data(i);
|
|
//--- Смешиваем цвета
|
|
uint foreground=::ColorToARGB(m_clr.BlendColors(background,pixel_color));
|
|
//--- Рисуем пиксель наслаиваемого изображения
|
|
m_headers.PixelSet(x+lx,y+ly,foreground);
|
|
}
|
|
}
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Рисует текст заголовков таблицы |
|
|
//+------------------------------------------------------------------+
|
|
void CTable::DrawHeadersText(void)
|
|
{
|
|
//--- Для расчёта координат и отступов
|
|
int x=0,y=m_header_y_size/2;
|
|
int column_offset =0;
|
|
uint text_align =0;
|
|
//--- Цвет текста
|
|
uint clr=::ColorToARGB(m_headers_text_color);
|
|
//--- Свойства шрифта
|
|
m_headers.FontSet(CElement::Font(),-CElement::FontSize()*10,FW_NORMAL);
|
|
//--- Нарисовать текст
|
|
for(uint c=0; c<m_columns_total; c++)
|
|
{
|
|
//--- Получим X-координату текста
|
|
x=TextX(c,true);
|
|
//--- Получим способ выравнивания текста
|
|
text_align=TextAlign(c,TA_VCENTER);
|
|
//--- Нарисовать название столбца
|
|
m_headers.TextOut(x,y,CorrectingText(c,0,true),clr,text_align);
|
|
}
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Изменение цвета объектов таблицы |
|
|
//+------------------------------------------------------------------+
|
|
void CTable::ChangeObjectsColor(void)
|
|
{
|
|
//--- Отслеживаем изменение цвета, только если не в режиме изменения ширины столбца
|
|
if(m_column_resize_control!=WRONG_VALUE)
|
|
return;
|
|
//--- Изменение цвета заголовков
|
|
ChangeHeadersColor();
|
|
//--- Изменение цвета рядов при наведении курсора мыши
|
|
ChangeRowsColor();
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Изменение цвета заголовков при наведении курсора мыши |
|
|
//+------------------------------------------------------------------+
|
|
void CTable::ChangeHeadersColor(void)
|
|
{
|
|
//--- Выйти, если заголовки отключены
|
|
if(!m_show_headers)
|
|
return;
|
|
//--- Если указатель курсора активирован
|
|
if(m_column_resize_control==WRONG_VALUE &&
|
|
m_column_resize.IsVisible() && m_mouse.LeftButtonState())
|
|
{
|
|
//--- Запомним индекс захваченного столбца
|
|
m_column_resize_control=m_prev_header_index_focus;
|
|
//--- Отправим сообщение на определение доступных элементов
|
|
::EventChartCustom(m_chart_id,ON_SET_AVAILABLE,CElementBase::Id(),0,"");
|
|
//--- Отправим сообщение об изменении в графическом интерфейсе
|
|
::EventChartCustom(m_chart_id,ON_CHANGE_GUI,CElementBase::Id(),0,"");
|
|
return;
|
|
}
|
|
//--- Если не в фокусе
|
|
if(!m_headers.MouseFocus())
|
|
{
|
|
//--- Если ещё не отмечено, что не в фокусе
|
|
if(m_prev_header_index_focus!=WRONG_VALUE)
|
|
{
|
|
//--- Сбросить фокус
|
|
m_prev_header_index_focus=WRONG_VALUE;
|
|
//--- Изменить цвет
|
|
DrawTableHeaders();
|
|
m_headers.Update();
|
|
}
|
|
}
|
|
//--- Если в фокусе
|
|
else
|
|
{
|
|
//--- Проверить фокус над заголовками
|
|
CheckHeaderFocus();
|
|
//--- Если нет фокуса
|
|
if(m_prev_header_index_focus==WRONG_VALUE)
|
|
{
|
|
//--- Изменить цвет
|
|
DrawTableHeaders();
|
|
m_headers.Update();
|
|
}
|
|
}
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Изменение цвета рядов при наведении курсора мыши |
|
|
//+------------------------------------------------------------------+
|
|
void CTable::ChangeRowsColor(void)
|
|
{
|
|
//--- Выйти, если отключена подсветка строк при наведении
|
|
if(!m_lights_hover)
|
|
return;
|
|
//--- Если не в фокусе
|
|
if(!m_table.MouseFocus())
|
|
{
|
|
//--- Если ещё не отмечено, что не в фокусе
|
|
if(m_prev_item_index_focus!=WRONG_VALUE)
|
|
{
|
|
m_item_index_focus=WRONG_VALUE;
|
|
//--- Изменить цвет
|
|
RedrawRow();
|
|
m_table.Update();
|
|
//--- Сбросить фокус
|
|
m_prev_item_index_focus=WRONG_VALUE;
|
|
}
|
|
}
|
|
//--- Если в фокусе
|
|
else
|
|
{
|
|
//--- Проверить фокус над строками
|
|
if(m_item_index_focus==WRONG_VALUE)
|
|
{
|
|
//--- Получим индекс строки в фокусе
|
|
m_item_index_focus=CheckRowFocus();
|
|
//--- Изменить цвет строки
|
|
RedrawRow();
|
|
m_table.Update();
|
|
//--- Сохранить как предыдущий индекс в фокусе
|
|
m_prev_item_index_focus=m_item_index_focus;
|
|
return;
|
|
}
|
|
//--- Получим относительную Y-координату под курсором мыши
|
|
int y=m_mouse.RelativeY(m_table);
|
|
//--- Проверка фокуса
|
|
bool condition=(y>m_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; i<m_columns_total; i++)
|
|
{
|
|
//--- Если фокус заголовка изменился
|
|
if((x>m_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; i<m_visible_table_to_index; i++)
|
|
{
|
|
//--- Если фокус строки изменился
|
|
if(y>m_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; i<m_columns_total; i++)
|
|
{
|
|
if(is_focus=x>m_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<m_min_column_width)
|
|
return;
|
|
//--- Сохраним новую ширину столбца
|
|
m_columns[m_column_resize_control].m_width=new_width;
|
|
//--- Рассчитать размеры таблицы
|
|
CalculateTableSize();
|
|
//--- Установить новый размер таблице
|
|
ChangeTableSize();
|
|
//--- Корректируем ползунок полосы прокрутки, если его позиция изменилась
|
|
if(m_scrollh.CurrentPos()!=m_column_resize_prev_thumb)
|
|
{
|
|
m_scrollh.MovingThumb(m_column_resize_prev_thumb);
|
|
//--- Корректировка таблицы относительно полос прокрутки
|
|
ShiftTable();
|
|
}
|
|
//--- Нарисуем таблицу
|
|
DrawTable(true);
|
|
Update();
|
|
if(m_scrollh.IsScroll())
|
|
m_scrollh.Update(true);
|
|
if(m_scrollv.IsScroll())
|
|
m_scrollv.Update(true);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Проверить выход из диапазона столбцов |
|
|
//+------------------------------------------------------------------+
|
|
template<typename T>
|
|
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<images_total; i++)
|
|
{
|
|
//--- Копировать, если есть картинки
|
|
if(m_columns[column_source].m_rows[row_source].m_images[i].DataTotal()<1)
|
|
continue;
|
|
//--- Делаем копию картинки
|
|
ImageCopy(m_columns[column_dest].m_rows[row_dest].m_images,m_columns[column_source].m_rows[row_source].m_images,i);
|
|
}
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Копирует данные изображения из одного массива в другой |
|
|
//+------------------------------------------------------------------+
|
|
void CTable::ImageCopy(CImage &destination[],CImage &source[],const int index)
|
|
{
|
|
//--- Копируем пиксели картинки
|
|
destination[index].CopyImageData(source[index]);
|
|
//--- Копируем свойства картинки
|
|
destination[index].Width(source[index].Width());
|
|
destination[index].Height(source[index].Height());
|
|
destination[index].BmpPath(source[index].BmpPath());
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Возвращает текст |
|
|
//+------------------------------------------------------------------+
|
|
string CTable::Text(const int column_index,const int row_index)
|
|
{
|
|
string text="";
|
|
//--- Корректируем текст, если не в режиме изменения ширины столбца
|
|
if(m_column_resize_control==WRONG_VALUE)
|
|
text=CorrectingText(column_index,row_index);
|
|
//--- Если же в режиме изменения ширины столбца, то...
|
|
else
|
|
{
|
|
//--- ...корректируем текст только для того столбца, ширину которого изменяем
|
|
if(column_index==m_column_resize_control)
|
|
text=CorrectingText(column_index,row_index);
|
|
//--- Для всех остальных используем уже ранее откорректированный текст
|
|
else
|
|
text=m_columns[column_index].m_rows[row_index].m_short_text;
|
|
}
|
|
//--- Вернём текст
|
|
return(text);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Возвращает X-координату текста в указанном столбце |
|
|
//+------------------------------------------------------------------+
|
|
int CTable::TextX(const int column_index,const bool headers=false)
|
|
{
|
|
int x=0;
|
|
//--- Выравнивание текста в ячейках по установленному режиму для каждого столбца
|
|
switch(m_columns[column_index].m_text_align)
|
|
{
|
|
//--- По центру
|
|
case ALIGN_CENTER :
|
|
x=m_columns[column_index].m_x+(m_columns[column_index].m_width/2);
|
|
break;
|
|
//--- Cправа
|
|
case ALIGN_RIGHT :
|
|
{
|
|
int x_offset=0;
|
|
//---
|
|
if(headers)
|
|
{
|
|
bool condition=(m_is_sorted_column_index!=WRONG_VALUE && m_is_sorted_column_index==column_index);
|
|
x_offset=(condition)? m_label_x_gap+m_sort_arrow_x_gap : m_label_x_gap;
|
|
}
|
|
else
|
|
x_offset=m_columns[column_index].m_text_x_offset;
|
|
//---
|
|
x=m_columns[column_index].m_x2-x_offset;
|
|
break;
|
|
}
|
|
//--- Слева
|
|
case ALIGN_LEFT :
|
|
x=m_columns[column_index].m_x+((headers)? m_label_x_gap : m_columns[column_index].m_text_x_offset);
|
|
break;
|
|
}
|
|
//--- Вернуть способ выравнивания
|
|
return(x);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Возвращает способ выравнивания текста в указанном столбце |
|
|
//+------------------------------------------------------------------+
|
|
uint CTable::TextAlign(const int column_index,const uint anchor)
|
|
{
|
|
uint text_align=0;
|
|
//--- Выравнивание текста для текущего столбца
|
|
switch(m_columns[column_index].m_text_align)
|
|
{
|
|
case ALIGN_CENTER :
|
|
text_align=TA_CENTER|anchor;
|
|
break;
|
|
case ALIGN_RIGHT :
|
|
text_align=TA_RIGHT|anchor;
|
|
break;
|
|
case ALIGN_LEFT :
|
|
text_align=TA_LEFT|anchor;
|
|
break;
|
|
}
|
|
//--- Вернуть способ выравнивания
|
|
return(text_align);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Возвращает цвет текста ячейки |
|
|
//+------------------------------------------------------------------+
|
|
uint CTable::TextColor(const int column_index,const int row_index)
|
|
{
|
|
uint clr=(row_index==m_selected_item)? m_selected_row_text_color : m_columns[column_index].m_rows[row_index].m_text_color;
|
|
//--- Вернуть цвет заголовка
|
|
return(::ColorToARGB(clr));
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Возвращает цвет фона ячейки |
|
|
//+------------------------------------------------------------------+
|
|
uint CTable::BackColor(const int column_index,const int row_index)
|
|
{
|
|
uint clr=(row_index==m_selected_item)? m_selected_row_color : m_columns[column_index].m_rows[row_index].m_back_color;
|
|
//--- Вернуть цвет заголовка
|
|
return(::ColorToARGB(clr));
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Возвращает текущий цвет фона заголовка |
|
|
//+------------------------------------------------------------------+
|
|
uint CTable::HeaderColorCurrent(const bool is_header_focus)
|
|
{
|
|
uint clr=clrNONE;
|
|
//--- Если нет фокуса
|
|
if(!is_header_focus || !m_headers.MouseFocus())
|
|
clr=m_headers_color;
|
|
else
|
|
{
|
|
//--- Если левая кнопка мыши нажата и не в процессе изменения ширины столбца
|
|
bool condition=(m_mouse.LeftButtonState() && m_column_resize_control==WRONG_VALUE);
|
|
clr=(condition)? m_headers_color_pressed : m_headers_color_hover;
|
|
}
|
|
//--- Вернуть цвет заголовка
|
|
return(::ColorToARGB(clr,m_alpha));
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Возвращает текущий цвет фона строки |
|
|
//+------------------------------------------------------------------+
|
|
uint CTable::RowColorCurrent(const int column_index,const int row_index,const bool is_row_focus)
|
|
{
|
|
//--- Если выделенная строка
|
|
if(row_index==m_selected_item)
|
|
return(::ColorToARGB(m_selected_row_color,m_alpha));
|
|
//--- Цвет ряда
|
|
uint clr=m_cell_color;
|
|
//--- Если (1) нет фокуса или (2) в процессе изменения ширины столбца или (3) форма заблокирована
|
|
bool condition=(!is_row_focus || !m_table.MouseFocus() || m_column_resize_control!=WRONG_VALUE || m_main.CElementBase::IsLocked());
|
|
//--- Если включен режим форматирования в стиле "Зебра"
|
|
if(m_is_zebra_format_rows!=clrNONE)
|
|
{
|
|
if(condition)
|
|
clr=(row_index%2!=0)? m_is_zebra_format_rows : m_cell_color;
|
|
else
|
|
clr=m_cell_color_hover;
|
|
}
|
|
else
|
|
{
|
|
clr=(condition)? m_columns[column_index].m_rows[row_index].m_back_color : m_cell_color_hover;
|
|
}
|
|
//--- Вернуть цвет
|
|
return(::ColorToARGB(clr,m_alpha));
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Возвращает откорректированный текст по ширине столбца |
|
|
//+------------------------------------------------------------------+
|
|
string CTable::CorrectingText(const int column_index,const int row_index,const bool headers=false)
|
|
{
|
|
//--- Получим текущий текст
|
|
string corrected_text=(headers)? m_columns[column_index].m_header_text : m_columns[column_index].m_rows[row_index].m_full_text;
|
|
//--- Отступы от краёв ячейки по оси X
|
|
int x_offset=0;
|
|
//---
|
|
if(headers)
|
|
x_offset=(m_is_sorted_column_index==WRONG_VALUE)? m_label_x_gap*2 : m_label_x_gap+m_sort_arrow_x_gap;
|
|
else
|
|
x_offset=m_label_x_gap+m_columns[column_index].m_text_x_offset;
|
|
//--- Получим указатель на объект холста
|
|
CRectCanvas *obj=(headers)? ::GetPointer(m_headers) : ::GetPointer(m_table);
|
|
//--- Получим ширину текста
|
|
int full_text_width=obj.TextWidth(corrected_text);
|
|
//--- Пространство для строки
|
|
int space_width=m_columns[column_index].m_width-x_offset;
|
|
//--- Если помещаемся в ячейку, сохраним скорректированный текст в отдельный массив и вернём его
|
|
if(full_text_width<=space_width)
|
|
{
|
|
//--- Если это не заголовки, сохраним откорректированный текст
|
|
if(!headers)
|
|
m_columns[column_index].m_rows[row_index].m_short_text=corrected_text;
|
|
//---
|
|
return(corrected_text);
|
|
}
|
|
//--- Если текст не помещается в ячейку, нужно скорректировать его (обрезать лишние символы и добавить многоточие)
|
|
else
|
|
{
|
|
//--- Для работы со строкой
|
|
string temp_text="";
|
|
//--- Получим длину строки
|
|
int total=::StringLen(corrected_text);
|
|
//--- Будем удалять у строки по одному символу, пока не достигнем нужной ширины текста
|
|
for(int i=total-1; 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_width<space_width)
|
|
{
|
|
//--- Сохраняем текст и останавливаем цикл
|
|
corrected_text=temp_text+"...";
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
//--- Если это не заголовки, сохраним откорректированный текст
|
|
if(!headers)
|
|
m_columns[column_index].m_rows[row_index].m_short_text=corrected_text;
|
|
//--- Вернём скорректированный текст
|
|
return(corrected_text);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Перемещение элемента |
|
|
//+------------------------------------------------------------------+
|
|
void CTable::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_table.X(m_main.X2()-m_table.XGap());
|
|
m_headers.X(m_main.X2()-m_headers.XGap());
|
|
}
|
|
else
|
|
{
|
|
CElementBase::X(m_main.X()+XGap());
|
|
m_table.X(m_main.X()+m_table.XGap());
|
|
m_headers.X(m_main.X()+m_headers.XGap());
|
|
}
|
|
//--- Если привязка снизу
|
|
if(m_anchor_bottom_window_side)
|
|
{
|
|
CElementBase::Y(m_main.Y2()-YGap());
|
|
m_table.Y(m_main.Y2()-m_table.YGap());
|
|
m_headers.Y(m_main.Y2()-m_headers.YGap());
|
|
}
|
|
else
|
|
{
|
|
CElementBase::Y(m_main.Y()+YGap());
|
|
m_table.Y(m_main.Y()+m_table.YGap());
|
|
m_headers.Y(m_main.Y()+m_headers.YGap());
|
|
}
|
|
//--- Обновление координат графических объектов
|
|
::ObjectSetInteger(m_chart_id,m_table.ChartObjectName(),OBJPROP_XDISTANCE,m_table.X());
|
|
::ObjectSetInteger(m_chart_id,m_table.ChartObjectName(),OBJPROP_YDISTANCE,m_table.Y());
|
|
::ObjectSetInteger(m_chart_id,m_headers.ChartObjectName(),OBJPROP_XDISTANCE,m_headers.X());
|
|
::ObjectSetInteger(m_chart_id,m_headers.ChartObjectName(),OBJPROP_YDISTANCE,m_headers.Y());
|
|
//--- Переместить остальные элементы
|
|
CElement::Moving(only_visible);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Показывает элемент |
|
|
//+------------------------------------------------------------------+
|
|
void CTable::Show(void)
|
|
{
|
|
//--- Выйти, если элемент уже видим
|
|
if(CElementBase::IsVisible())
|
|
return;
|
|
//--- Состояние видимости
|
|
CElementBase::IsVisible(true);
|
|
//--- Перемещение элемента
|
|
Moving();
|
|
//--- Сделать видимыми все объекты
|
|
::ObjectSetInteger(m_chart_id,m_canvas.ChartObjectName(),OBJPROP_TIMEFRAMES,OBJ_ALL_PERIODS);
|
|
::ObjectSetInteger(m_chart_id,m_table.ChartObjectName(),OBJPROP_TIMEFRAMES,OBJ_ALL_PERIODS);
|
|
::ObjectSetInteger(m_chart_id,m_headers.ChartObjectName(),OBJPROP_TIMEFRAMES,OBJ_ALL_PERIODS);
|
|
//---
|
|
if(!m_is_disabled_scrolls)
|
|
{
|
|
if(m_scrollv.IsScroll())
|
|
m_scrollv.Show();
|
|
if(m_scrollh.IsScroll())
|
|
m_scrollh.Show();
|
|
}
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Скрывает элемент |
|
|
//+------------------------------------------------------------------+
|
|
void CTable::Hide(void)
|
|
{
|
|
//--- Выйти, если элемент уже скрыт
|
|
if(!CElementBase::IsVisible())
|
|
return;
|
|
//--- Скрыть все объекты
|
|
::ObjectSetInteger(m_chart_id,m_canvas.ChartObjectName(),OBJPROP_TIMEFRAMES,OBJ_NO_PERIODS);
|
|
::ObjectSetInteger(m_chart_id,m_table.ChartObjectName(),OBJPROP_TIMEFRAMES,OBJ_NO_PERIODS);
|
|
::ObjectSetInteger(m_chart_id,m_headers.ChartObjectName(),OBJPROP_TIMEFRAMES,OBJ_NO_PERIODS);
|
|
m_scrollv.Hide();
|
|
m_scrollh.Hide();
|
|
//--- Состояние видимости
|
|
CElementBase::IsVisible(false);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Удаление |
|
|
//+------------------------------------------------------------------+
|
|
void CTable::Delete(void)
|
|
{
|
|
//--- Удаление графических объектов
|
|
m_table.Destroy();
|
|
m_canvas.Destroy();
|
|
m_headers.Destroy();
|
|
m_column_resize.Delete();
|
|
//--- Освобождение массивов элемента
|
|
for(uint c=0; c<m_columns_total; c++)
|
|
{
|
|
for(uint r=0; r<m_rows_total; r++)
|
|
{
|
|
for(int i=0; i<ImagesTotal(c,r); i++)
|
|
m_columns[c].m_rows[r].m_images[i].DeleteImageData();
|
|
//---
|
|
::ArrayFree(m_columns[c].m_rows[r].m_images);
|
|
}
|
|
}
|
|
//---
|
|
for(uint c=0; c<m_columns_total; c++)
|
|
::ArrayFree(m_columns[c].m_rows);
|
|
//---
|
|
uint total=ArraySize(m_sort_arrows);
|
|
for(uint i=0; i<total; i++)
|
|
m_sort_arrows[i].DeleteImageData();
|
|
//---
|
|
::ArrayFree(m_rows);
|
|
::ArrayFree(m_columns);
|
|
::ArrayFree(m_sort_arrows);
|
|
//--- Инициализация переменных значениями по умолчанию
|
|
CElementBase::IsVisible(true);
|
|
m_is_sorted_column_index=WRONG_VALUE;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Установка приоритетов |
|
|
//+------------------------------------------------------------------+
|
|
void CTable::SetZorders(void)
|
|
{
|
|
CElement::SetZorders();
|
|
::ObjectSetInteger(m_chart_id,m_table.ChartObjectName(),OBJPROP_ZORDER,m_zorder+1);
|
|
::ObjectSetInteger(m_chart_id,m_headers.ChartObjectName(),OBJPROP_ZORDER,m_zorder+1);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Сброс приоритетов |
|
|
//+------------------------------------------------------------------+
|
|
void CTable::ResetZorders(void)
|
|
{
|
|
CElement::ResetZorders();
|
|
::ObjectSetInteger(m_chart_id,m_table.ChartObjectName(),OBJPROP_ZORDER,WRONG_VALUE);
|
|
::ObjectSetInteger(m_chart_id,m_headers.ChartObjectName(),OBJPROP_ZORDER,WRONG_VALUE);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Ускоренная промотка полосы прокрутки |
|
|
//+------------------------------------------------------------------+
|
|
void CTable::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;
|
|
//--- Смещает таблицу
|
|
ShiftTable();
|
|
//--- Обновить полосы прокрутки
|
|
if(scroll_v) m_scrollv.Update(true);
|
|
if(scroll_h) m_scrollh.Update(true);
|
|
}
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Рассчитывает размеры таблицы |
|
|
//+------------------------------------------------------------------+
|
|
void CTable::CalculateTableSize(void)
|
|
{
|
|
//--- Рассчитаем общую ширину и высоту таблицы
|
|
CalculateTableXSize();
|
|
CalculateTableYSize();
|
|
//--- Рассчитывает видимые размеры таблицы (два раза на случай, когда нужно отобразить обе полосы прокрутки)
|
|
for(int i=0; i<2; i++)
|
|
{
|
|
CalculateTableVisibleXSize();
|
|
CalculateTableVisibleYSize();
|
|
}
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Рассчитывает полный размер таблицы по оси X |
|
|
//+------------------------------------------------------------------+
|
|
void CTable::CalculateTableXSize(void)
|
|
{
|
|
//--- Рассчитаем общую ширину таблицы
|
|
m_table_x_size=0;
|
|
for(uint c=0; c<m_columns_total; c++)
|
|
m_table_x_size=m_table_x_size+m_columns[c].m_width;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Рассчитывает полный размер таблицы по оси Y |
|
|
//+------------------------------------------------------------------+
|
|
void CTable::CalculateTableYSize(void)
|
|
{
|
|
//--- Рассчитаем общую высоту таблицы
|
|
m_table_y_size=(int)(m_cell_y_size*m_rows_total)+1;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Рассчитывает видимый размер таблицы по оси X |
|
|
//+------------------------------------------------------------------+
|
|
void CTable::CalculateTableVisibleXSize(void)
|
|
{
|
|
if(m_is_disabled_scrolls)
|
|
{
|
|
m_table_visible_x_size=m_table_x_size-1;
|
|
return;
|
|
}
|
|
//--- Ширина таблицы с учётом наличия вертикальной полосы прокрутки
|
|
int x_size=(m_table_y_size>m_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);
|
|
}
|
|
//+------------------------------------------------------------------+
|