EasyAndFastMod/Controls/ListView.mqh
2026-01-15 07:23:17 -05:00

1524 lines
125 KiB
MQL5

//+------------------------------------------------------------------+
//| ListView.mqh |
//| Copyright 2015, MetaQuotes Software Corp. |
//| http://www.mql5.com |
//+------------------------------------------------------------------+
#include "..\Element.mqh"
#include "Scrolls.mqh"
//+------------------------------------------------------------------+
//| Класс для создания списка |
//+------------------------------------------------------------------+
class CListView : public CElement
{
private:
//--- Объекты для создания списка
CRectCanvas m_listview;
CScrollV m_scrollv;
//--- Массив свойств пунктов списка
struct LVItemOptions
{
int m_y; // Y-координата верхнего края строки
int m_y2; // Y-координата нижнего края строки
string m_value; // Текст пункта
bool m_state; // Состояние чек-бокса
};
LVItemOptions m_items[];
//--- Размер списка и его видимой части
int m_items_total;
//--- Общий размер и размер видимой части списка
int m_list_y_size;
int m_list_visible_y_size;
//--- Общее смещение списка
int m_y_offset;
//--- Размер пунктов по оси Y
int m_item_y_size;
//--- (1) Индекс и (2) текст выбранного пункта
int m_selected_item;
string m_selected_item_text;
//--- Индекс предыдущего выделенного пункта
int m_prev_selected_item;
//--- Для определения фокуса строки
int m_item_index_focus;
//--- Для определение момента перехода курсора мыши с одной строки на другую
int m_prev_item_index_focus;
//--- Режим списка с чек-боксами
bool m_checkbox_mode;
//--- Для расчёта границ видимой части поля ввода
int m_y_limit;
int m_y2_limit;
//--- Режим подсветки при наведении курсора
bool m_lights_hover;
//--- Счётчик таймера для перемотки списка
int m_timer_counter;
//--- Для определения индексов видимой части списка
int m_visible_list_from_index;
int m_visible_list_to_index;
//---
public:
CListView(void);
~CListView(void);
//--- Методы для создания списка
bool CreateListView(const int x_gap,const int y_gap);
//---
private:
void InitializeProperties(const int x_gap,const int y_gap);
bool CreateCanvas(void);
bool CreateList(void);
bool CreateScrollV(void);
//---
public:
//--- Возвращает указатель на полосу прокрутки
CScrollV *GetScrollVPointer(void) { return(::GetPointer(m_scrollv)); }
//--- (1) Высота пункта, возвращает (2) размер списка и (3) видимой его части
void ItemYSize(const int y_size) { m_item_y_size=y_size; }
int ItemsTotal(void) const { return(::ArraySize(m_items)); }
int VisibleItemsTotal(void);
//--- (1) Состояние полосы прокрутки, (2) режим подсветки пунктов при наведении, (3) режим списка с чек-боксами
bool ScrollState(void) const { return(m_scrollv.State()); }
void LightsHover(const bool state) { m_lights_hover=state; }
void CheckBoxMode(const bool state) { m_checkbox_mode=state; }
//--- Возвращает (1) индекс и (2) текст выделенного пункта в списке
int SelectedItemIndex(void) const { return(m_selected_item); }
string SelectedItemText(void) const { return(m_selected_item_text); }
//--- Установка ярлыков для кнопки в нажатом состоянии (доступен/заблокирован)
void IconFilePressed(const string file_path);
void IconFilePressedLocked(const string file_path);
//--- (1) Установка значения, (2) получение значения, (3) получение состояния
void SetValue(const uint item_index,const string value,const bool redraw=false);
string GetValue(const uint item_index);
bool GetState(const uint item_index);
//--- Выделение пункта
void SelectItem(const uint item_index,const bool redraw=false);
//--- Установка (1) размера списка и (2) видимой его части
void ListSize(const int items_total);
//--- Реконструкция списка
void Rebuilding(const int items_total,const bool redraw=false);
//--- Добавляет пункт в список
void AddItem(const int item_index,const string value="",const bool redraw=false);
//--- Удаляет пункт из списка
void DeleteItem(const int item_index,const bool redraw=false);
//--- Очищает список (удаление всех пунктов)
void Clear(const bool redraw=false);
//--- Прокрутка списка
void Scrolling(const int pos=WRONG_VALUE);
//--- Изменение размеров
void ChangeSize(const uint x_size,const uint y_size);
//---
public:
//--- Обработчик событий графика
virtual void OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam);
//--- Таймер
virtual void OnEventTimer(void);
//--- Перемещение элемента
virtual void Moving(const bool only_visible=true);
//--- Управление
virtual void Show(void);
virtual void Hide(void);
virtual void Delete(void);
//--- (1) Установка, (2) сброс приоритетов на нажатие левой кнопки мыши
virtual void SetZorders(void);
virtual void ResetZorders(void);
//--- Рисует элемент
virtual void Draw(void);
//--- Обновление элемента
virtual void Update(const bool redraw=false);
//---
private:
//--- Обработка нажатия на пункте списка
bool OnClickList(const string pressed_object);
//--- Возвращает индекс пункта, на котором нажали
int PressedItemIndex(void);
//--- Изменение цвета пунктов списка при наведении
void ChangeItemsColor(void);
//--- Проверка фокуса строки списка при наведении курсора
int CheckItemFocus(void);
//--- Смещение списка относительно позиции полосы прокрутки
void ShiftData(void);
//--- Ускоренная перемотка списка
void FastSwitching(void);
//--- Рассчитывает размер списка
void CalculateListYSize(void);
//--- Изменить основные размеры элемента
void ChangeMainSize(const int x_size,const int y_size);
//--- Изменить размеры списка
void ChangeListSize(void);
//--- Изменить размеры полос прокрутки
void ChangeScrollsSize(void);
//--- Расчёт с учётом последних изменений и изменение размеров списка
void RecalculateAndResizeList(const bool redraw=false);
//--- Инициализация указанного пункта значениями по умолчанию
void ItemInitialize(const uint item_index);
//--- Делает копию указанного пункта (source) в новое место (dest.)
void ItemCopy(const uint item_dest,const uint item_source);
//--- Расчёт Y-координаты пункта
int CalculationItemY(const int item_index=0);
//--- Расчёт ширины пунктов
int CalculationItemsWidth(void);
//--- Расчёт границ поля ввода по оси Y
void CalculateYBoundaries(void);
//--- Корректировка вертикальной полосы прокрутки
void CorrectingVerticalScrollThumb(void);
//--- Расчёт Y-позиции ползунка полосы прокрутки
int CalculateScrollPosY(const bool to_down=false);
//--- Расчёт Y-координат полосы прокрутки в верхней/нижней границе списка
int CalculateScrollThumbY(void);
int CalculateScrollThumbY2(void);
//--- Определение индексов видимой области списка
void VisibleListIndexes(void);
//--- Рисует список
virtual void DrawList(const bool only_visible=false);
//--- Рисует рамку
virtual void DrawBorder(void);
//--- Рисует картинки пунктов
virtual void DrawImages(void);
//--- Рисует картинку
virtual void DrawImage(void);
//--- Рисует текст пунктов
virtual void DrawText(void);
//--- Перерисовывает указанный пункт списка
void RedrawItem(const int item_index);
//--- Перерисовывает пункты списка по указанному режиму
void RedrawItemsByMode(const bool is_selected_row=false);
//--- Возвращает текущий цвет фона пункта
uint ItemColorCurrent(const int item_index,const bool is_item_focus);
//--- Возвращает цвет текста пункта
uint TextColor(const int item_index);
//--- Изменить ширину по правому краю окна
virtual void ChangeWidthByRightWindowSide(void);
//--- Изменить высоту по нижнему краю окна
virtual void ChangeHeightByBottomWindowSide(void);
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CListView::CListView(void) : m_item_y_size(18),
m_lights_hover(false),
m_items_total(0),
m_y_offset(0),
m_checkbox_mode(false),
m_selected_item(WRONG_VALUE),
m_selected_item_text(""),
m_prev_selected_item(WRONG_VALUE),
m_item_index_focus(WRONG_VALUE),
m_prev_item_index_focus(WRONG_VALUE),
m_visible_list_from_index(WRONG_VALUE),
m_visible_list_to_index(WRONG_VALUE)
{
//--- Сохраним имя класса элемента в базовом классе
CElementBase::ClassName(CLASS_NAME);
//--- Установим размер списка и его видимой части
ListSize(m_items_total);
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CListView::~CListView(void)
{
}
//+------------------------------------------------------------------+
//| Обработчик событий |
//+------------------------------------------------------------------+
void CListView::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
{
//--- Обработка события перемещения курсора
if(id==CHARTEVENT_MOUSE_MOVE)
{
//--- Смещаем список, если управление ползунком полосы прокрутки в действии
if(m_scrollv.ScrollBarControl())
{
//--- Обновить список и полосу прокрутки
ShiftData();
m_scrollv.Update(true);
return;
}
//--- Сброс цвета
if(!CElementBase::MouseFocus())
{
if(m_prev_item_index_focus==WRONG_VALUE)
return;
//--- Снять фокус
m_canvas.MouseFocus(false);
//--- Изменяет цвет строк списка при наведении
ChangeItemsColor();
return;
}
//--- Проверка фокуса над списком
int x_offset=(m_scrollv.IsVisible())? m_scrollv.ScrollWidth() : 0;
m_canvas.MouseFocus(m_mouse.X()>m_canvas.X() && m_mouse.X()<X2()-x_offset &&
m_mouse.Y()>m_canvas.Y() && m_mouse.Y()<m_canvas.Y2());
//--- Изменяет цвет строк списка при наведении
ChangeItemsColor();
//--- Определим режим отслеживания прокручивания колёсика мыши
if(m_canvas.MouseFocus())
::ChartSetInteger(m_chart_id,CHART_EVENT_MOUSE_WHEEL,true);
else
::ChartSetInteger(m_chart_id,CHART_EVENT_MOUSE_WHEEL,false);
return;
}
//--- Обработка события колёсика мыши
if(id==CHARTEVENT_MOUSE_WHEEL)
{
//--- Получим текущую позицию полосы прокрутки
int pos=(m_scrollv.CurrentPos()-1<0)? 1 : m_scrollv.CurrentPos();
//--- Если колёсико мыши сместилось вниз
if(dparam<0)
Scrolling(pos+1);
//--- Если колёсико мыши сместилось вверх
else if(dparam>0)
Scrolling(pos-1);
//--- Обновить полосу прокрутки
m_scrollv.Update(true);
}
//--- Обработка нажатия на объектах
if(id==CHARTEVENT_OBJECT_CLICK)
{
//--- Если было нажатие на списке
if(OnClickList(sparam))
return;
}
//--- Обработка события нажатия на кнопках полосы прокрутки
if(id==CHARTEVENT_CUSTOM+ON_CLICK_BUTTON)
{
//--- Если было нажатие на кнопках полосы прокрутки списка
if(m_scrollv.OnClickScrollInc((uint)lparam,(uint)dparam) ||
m_scrollv.OnClickScrollDec((uint)lparam,(uint)dparam))
{
//--- Сдвигает список относительно полосы прокрутки
ShiftData();
m_scrollv.Update(true);
return;
}
}
}
//+------------------------------------------------------------------+
//| Таймер |
//+------------------------------------------------------------------+
void CListView::OnEventTimer(void)
{
//--- Ускоренная перемотка значений
FastSwitching();
}
//+------------------------------------------------------------------+
//| Создаёт список |
//+------------------------------------------------------------------+
bool CListView::CreateListView(const int x_gap,const int y_gap)
{
//--- Выйти, если нет указателя на главный элемент
if(!CElement::CheckMainPointer())
return(false);
//--- Инициализация свойств
InitializeProperties(x_gap,y_gap);
//--- Рассчитаем размеры списка
CalculateListYSize();
//--- Создание списка
if(!CreateCanvas())
return(false);
if(!CreateList())
return(false);
if(!CreateScrollV())
return(false);
//---
return(true);
}
//+------------------------------------------------------------------+
//| Инициализация свойств |
//+------------------------------------------------------------------+
void CListView::InitializeProperties(const int x_gap,const int y_gap)
{
m_x =CElement::CalculateX(x_gap);
m_y =CElement::CalculateY(y_gap);
m_x_size =(m_x_size<0 || m_auto_xresize_mode)? m_main.X2()-CElementBase::X()-m_auto_xresize_right_offset : m_x_size;
m_y_size =(m_y_size<0 || m_auto_yresize_mode)? m_main.Y2()-CElementBase::Y()-m_auto_yresize_bottom_offset : m_y_size;
m_selected_item =(m_selected_item==WRONG_VALUE && !m_checkbox_mode) ? 0 : m_selected_item;
//--- Цвета пунктов в различных состояниях
m_back_color =(m_back_color!=clrNONE)? m_back_color : clrWhite;
m_back_color_hover =(m_back_color_hover!=clrNONE)? m_back_color_hover : C'229,243,255';
m_back_color_pressed =(m_back_color_pressed!=clrNONE)? m_back_color_pressed : C'51,153,255';
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 : 7;
m_icon_y_gap =(m_icon_y_gap>0)? m_icon_y_gap : 4;
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 CListView::CreateCanvas(void)
{
//--- Формирование имени объекта
string name=CElementBase::ElementName("listview");
//--- Создание объекта
if(!CElement::CreateCanvas(name,m_x,m_y,m_x_size,m_y_size))
return(false);
//---
return(true);
}
//+------------------------------------------------------------------+
//| Создаёт объект для рисования |
//+------------------------------------------------------------------+
bool CListView::CreateList(void)
{
//--- Формирование имени объекта
string name=CElementBase::ProgramName()+"_"+"listview_array"+"_"+(string)CElementBase::Id();
//--- Размер
int x_size=m_x_size-2;
//--- Координаты
int x =m_x+1;
int y =m_y+1;
//--- Создание объекта
::ResetLastError();
if(!m_listview.CreateBitmapLabel(m_chart_id,m_subwin,name,x,y,x_size,m_list_y_size,COLOR_FORMAT_ARGB_NORMALIZE))
{
::Print(__FUNCTION__," > Не удалось создать холст для рисования списка: ",::GetLastError());
return(false);
}
//--- Прикрепить к графику
if(!m_listview.Attach(m_chart_id,name,COLOR_FORMAT_ARGB_NORMALIZE))
{
::Print(__FUNCTION__," > Не удалось присоединить холст для рисования к графику: ",::GetLastError());
return(false);
}
//--- Свойства
::ObjectSetInteger(m_chart_id,m_listview.ChartObjectName(),OBJPROP_ZORDER,m_zorder+1);
::ObjectSetString(m_chart_id,m_listview.ChartObjectName(),OBJPROP_TOOLTIP,"\n");
//--- Если нужен список с чек-боксами
if(m_checkbox_mode)
{
IconFile(RESOURCE_CHECKBOX_OFF);
IconFileLocked(RESOURCE_CHECKBOX_OFF_LOCKED);
CElement::IconFilePressed(RESOURCE_CHECKBOX_ON);
CElement::IconFilePressedLocked(RESOURCE_CHECKBOX_ON_LOCKED);
}
//--- Координаты
m_listview.X(x);
m_listview.Y(y);
//--- Сохраним размеры
m_listview.XSize(x_size);
m_listview.YSize(m_list_y_size);
m_listview.Resize(x_size,m_list_y_size);
//--- Отступы от крайней точки панели
m_listview.XGap(CElement::CalculateXGap(x));
m_listview.YGap(CElement::CalculateYGap(y));
//--- Установим размеры видимой области
::ObjectSetInteger(m_chart_id,m_listview.ChartObjectName(),OBJPROP_XSIZE,x_size);
::ObjectSetInteger(m_chart_id,m_listview.ChartObjectName(),OBJPROP_YSIZE,m_list_visible_y_size);
//--- Зададим смещение фрейма внутри изображения по осям X и Y
::ObjectSetInteger(m_chart_id,m_listview.ChartObjectName(),OBJPROP_XOFFSET,0);
::ObjectSetInteger(m_chart_id,m_listview.ChartObjectName(),OBJPROP_YOFFSET,0);
return(true);
}
//+------------------------------------------------------------------+
//| Создаёт вертикальный скролл |
//+------------------------------------------------------------------+
bool CListView::CreateScrollV(void)
{
//--- Сохранить указатель на главный элемент
m_scrollv.MainPointer(this);
//--- Координаты
int x=16,y=1;
//--- Свойства
m_scrollv.Index((m_scrollv.Index()!=WRONG_VALUE)? m_scrollv.Index() : 0);
m_scrollv.XSize(15);
m_scrollv.YSize(CElementBase::YSize()-2);
m_scrollv.IsDropdown(CElementBase::IsDropdown());
m_scrollv.AnchorRightWindowSide(true);
//--- Расчёт количества шагов для смещения
uint items_total =ItemsTotal();
uint visible_items_total =VisibleItemsTotal();
//--- Создание полосы прокрутки
if(!m_scrollv.CreateScroll(x,y,items_total,visible_items_total))
return(false);
//--- Скрыть полосу прокрутки, если видимая часть больше, чем размер списка
if(m_list_visible_y_size>m_list_y_size)
m_scrollv.Hide();
//--- Добавить элемент в массив
CElement::AddToArray(m_scrollv);
return(true);
}
//+------------------------------------------------------------------+
//| Выделяет указанный пункт |
//+------------------------------------------------------------------+
void CListView::SelectItem(const uint item_index,const bool redraw=false)
{
//--- Выйти, если нет пунктов в списке
if(ItemsTotal()<1)
return;
//--- Корректировка в случае выхода из диапазона
int checked_index=(item_index>=(uint)m_items_total)? m_items_total-1 :(int)item_index;
//--- Если это список с чек-боксами
if(m_checkbox_mode)
{
m_selected_item =WRONG_VALUE;
m_selected_item_text ="";
//--- Установим противоположное значение чек-боксу
m_items[checked_index].m_state=!m_items[checked_index].m_state;
//--- Перерисовать пункт, если указано
if(redraw)
RedrawItem(item_index);
//---
return;
}
//--- Сохраним индекс и текст выделенного пункта
m_selected_item =checked_index;
m_selected_item_text =m_items[m_selected_item].m_value;
//--- Перерисовать список, если указано
if(redraw)
Update(true);
}
//+------------------------------------------------------------------+
//| Возвращает количество видимых пунктов |
//+------------------------------------------------------------------+
int CListView::VisibleItemsTotal(void)
{
double visible_items_total =m_list_visible_y_size/m_item_y_size;
double check_y_size =visible_items_total*m_item_y_size;
//---
visible_items_total=(check_y_size<m_list_visible_y_size+(m_y_offset*2)+1)? visible_items_total : visible_items_total;
return((int)visible_items_total);
}
//+------------------------------------------------------------------+
//| Установка картинки для нажатого состояния (доступен) |
//+------------------------------------------------------------------+
void CListView::IconFilePressed(const string file_path)
{
//--- Выйти, если режим списка с чек-боксами отключен
if(!m_checkbox_mode)
return;
//--- Добавить место для изображения, если его ещё нет
while(!CElement::CheckOutOfRange(0,2))
AddImage(0,"");
//--- Установить картинку
CElement::SetImage(0,2,file_path);
}
//+------------------------------------------------------------------+
//| Установка картинки для нажатого состояния (заблокирован) |
//+------------------------------------------------------------------+
void CListView::IconFilePressedLocked(const string file_path)
{
//--- Выйти, если режим списка с чек-боксами отключен
if(!m_checkbox_mode)
return;
//--- Добавить место для изображения, если его ещё нет
while(!CElement::CheckOutOfRange(0,3))
AddImage(0,"");
//--- Установить картинку
CElement::SetImage(0,3,file_path);
}
//+------------------------------------------------------------------+
//| Установка значения в списке по указанному индексу |
//+------------------------------------------------------------------+
void CListView::SetValue(const uint item_index,const string value,const bool redraw=false)
{
uint array_size=ItemsTotal();
//--- Если нет ни одного пункта в списке, сообщить об этом
if(array_size<1)
::Print(__FUNCTION__," > Вызов этого метода нужно осуществлять, когда в списке есть хотя бы один пункт!");
//--- Корректировка в случае выхода из диапазона
uint i=(item_index>=array_size)? array_size-1 : item_index;
//--- Сохраним значение в списке
m_items[i].m_value=value;
//--- Перерисовать пункт, если указано
if(redraw)
RedrawItem(item_index);
}
//+------------------------------------------------------------------+
//| Получение значения в списке по указанному индексу |
//+------------------------------------------------------------------+
string CListView::GetValue(const uint item_index)
{
uint array_size=ItemsTotal();
//--- Если нет ни одного пункта в списке, сообщить об этом
if(array_size<1)
::Print(__FUNCTION__," > Вызов этого метода нужно осуществлять, когда в списке есть хотя бы один пункт!");
//--- Корректировка в случае выхода из диапазона
uint i=(item_index>=array_size)? array_size-1 : item_index;
//--- Сохраним значение в списке
return(m_items[i].m_value);
}
//+------------------------------------------------------------------+
//| Получение состояния чек-бокса по указанному индексу |
//+------------------------------------------------------------------+
bool CListView::GetState(const uint item_index)
{
uint array_size=ItemsTotal();
//--- Если нет ни одного пункта в списке, сообщить об этом
if(array_size<1)
::Print(__FUNCTION__," > Вызов этого метода нужно осуществлять, когда в списке есть хотя бы один пункт!");
//--- Корректировка в случае выхода из диапазона
uint i=(item_index>=array_size)? array_size-1 : item_index;
//--- Сохраним значение в списке
return(m_items[i].m_state);
}
//+------------------------------------------------------------------+
//| Устанавливает размер списка |
//+------------------------------------------------------------------+
void CListView::ListSize(const int items_total)
{
//--- Не имеет смысла делать список менее двух пунктов
m_items_total=(items_total<1) ? 0 : items_total;
::ArrayResize(m_items,m_items_total);
//--- Инициализация пунктов значениями по умолчанию
for(int i=0; i<m_items_total; i++)
ItemInitialize(i);
}
//+------------------------------------------------------------------+
//| Реконструкция списка |
//+------------------------------------------------------------------+
void CListView::Rebuilding(const int items_total,const bool redraw=false)
{
//--- Установим нулевой размер
ListSize(items_total);
//--- Рассчитать и установить новые размеры списка
RecalculateAndResizeList(redraw);
}
//+------------------------------------------------------------------+
//| Добавляет пункт в список |
//+------------------------------------------------------------------+
void CListView::AddItem(const int item_index,const string value="",const bool redraw=false)
{
//--- Резервное количество
int reserve=100;
//--- Увеличим размер массива на один элемент
int array_size=ItemsTotal();
m_items_total=array_size+1;
::ArrayResize(m_items,m_items_total,reserve);
//--- Корректировка индекса в случае выхода из диапазона
int checked_item_index=(item_index>=m_items_total)? m_items_total-1 : item_index;
//--- Сместить другие пункты (двигаемся от конца массива к индексу добавляемого пункта)
for(int i=array_size; i>=checked_item_index; i--)
{
//--- Инициализация нового пункта значениями по умолчанию
if(i==checked_item_index)
{
ItemInitialize(i);
m_items[i].m_value=value;
continue;
}
//--- Индекс предыдущего пункта
uint prev_i=i-1;
//--- Перемещаем данные из предыдущего пункта в текущий
ItemCopy(i,prev_i);
}
//--- Рассчитать и установить новые размеры списка
RecalculateAndResizeList(redraw);
}
//+------------------------------------------------------------------+
//| Удаляет пункт из списка |
//+------------------------------------------------------------------+
void CListView::DeleteItem(const int item_index,const bool redraw=false)
{
//--- Увеличим размер массива на один элемент
int array_size=ItemsTotal();
//--- Корректировка индекса в случае выхода из диапазона
int checked_item_index=(item_index>=m_items_total)? m_items_total-1 : item_index;
//--- Сместить другие пункты (двигаемся от указанного индекса к последнему пункту)
for(int i=checked_item_index; i<array_size-1; i++)
{
//--- Индекс следующего пункта
uint next_i=i+1;
//--- Перемещаем данные из следующего пункта в текущий
ItemCopy(i,next_i);
}
//--- Уменьшим размер массива на один элемент
m_items_total=array_size-1;
::ArrayResize(m_items,m_items_total);
//--- Рассчитать и установить новые размеры списка
RecalculateAndResizeList(redraw);
}
//+------------------------------------------------------------------+
//| Очищает список (удаление всех пунктов) |
//+------------------------------------------------------------------+
void CListView::Clear(const bool redraw=false)
{
//--- Обнулить вспомогательные поля
m_item_index_focus =WRONG_VALUE;
m_prev_selected_item =WRONG_VALUE;
m_prev_item_index_focus =WRONG_VALUE;
//--- Установим нулевой размер
ListSize(0);
//--- Рассчитать и установить новые размеры списка
RecalculateAndResizeList(redraw);
}
//+------------------------------------------------------------------+
//| Прокрутка списка |
//+------------------------------------------------------------------+
void CListView::Scrolling(const int pos=WRONG_VALUE)
{
//--- Выйти, если полоса прокрутки не нужна
if(m_list_y_size<=m_list_visible_y_size)
return;
//--- Для определения позиции ползунка
int index=0;
//--- Индекс последней позиции
int last_pos_index=m_list_y_size-m_list_visible_y_size;
//--- Корректировка в случае выхода из диапазона
if(pos<0)
index=last_pos_index;
else
index=(pos>last_pos_index)? last_pos_index : pos;
//--- Сдвигаем ползунок полосы прокрутки
m_scrollv.MovingThumb(index);
//--- Сдвигаем список
ShiftData();
}
//+------------------------------------------------------------------+
//| Изменение размеров |
//+------------------------------------------------------------------+
void CListView::ChangeSize(const uint x_size,const uint y_size)
{
//--- Установить новый размер
CElementBase::XSize(x_size);
CElementBase::YSize(y_size);
m_canvas.XSize(m_x_size);
m_canvas.YSize(m_y_size);
m_canvas.Resize(m_x_size,m_y_size);
}
//+------------------------------------------------------------------+
//| Изменение цвета строки списка при наведении курсора |
//+------------------------------------------------------------------+
void CListView::ChangeItemsColor(void)
{
//--- Выйдем, если отключена подсветка при наведении курсора или прокрутка списка активна
if(!m_lights_hover || m_scrollv.State())
return;
//--- Выйдем, если элемент не выпадающий и форма заблокирована
if(!CElementBase::IsDropdown() && m_main.CElementBase::IsLocked())
return;
//--- Если не в фокусе
if(!m_canvas.MouseFocus())
{
//--- Если ещё не отмечено, что не в фокусе
if(m_prev_item_index_focus!=WRONG_VALUE)
{
m_item_index_focus=WRONG_VALUE;
//--- Изменить цвет
RedrawItemsByMode();
//--- Сбросить фокус
m_prev_item_index_focus=WRONG_VALUE;
}
}
//--- Если в фокусе
else
{
//--- Проверить фокус над строками
if(m_item_index_focus==WRONG_VALUE)
{
//--- Получим индекс строки в фокусе
m_item_index_focus=CheckItemFocus();
//--- Изменить цвет строки
RedrawItemsByMode();
//--- Сохранить как предыдущий индекс в фокусе
m_prev_item_index_focus=m_item_index_focus;
return;
}
//--- Получим относительную Y-координату под курсором мыши
int y=m_mouse.RelativeY(m_listview);
//--- Проверка фокуса
bool condition=(y>m_items[m_item_index_focus].m_y && y<=m_items[m_item_index_focus].m_y2);
//--- Если фокус изменился
if(!condition)
{
//--- Получим индекс строки в фокусе
m_item_index_focus=CheckItemFocus();
//--- Выйти, если вышли из области списка
if(m_item_index_focus<0)
return;
//--- Изменить цвет строки
RedrawItemsByMode();
//--- Сохранить как предыдущий индекс в фокусе
m_prev_item_index_focus=m_item_index_focus;
}
}
}
//+------------------------------------------------------------------+
//| Проверка фокуса строки списка при наведении курсора |
//+------------------------------------------------------------------+
int CListView::CheckItemFocus(void)
{
int item_index_focus=WRONG_VALUE;
//--- Получим относительную Y-координату под курсором мыши
int y=m_mouse.RelativeY(m_listview);
///--- Получим индексы локальной области таблицы
VisibleListIndexes();
//--- Ищем фокус
for(int i=m_visible_list_from_index; i<m_visible_list_to_index; i++)
{
//--- Если фокус строки изменился
if(y>m_items[i].m_y && y<=m_items[i].m_y2)
{
item_index_focus=(int)i;
break;
}
}
//--- Вернём индекс строки в фокусе
return(item_index_focus);
}
//+------------------------------------------------------------------+
//| Смещение списка относительно позиции полосы прокрутки |
//+------------------------------------------------------------------+
void CListView::ShiftData(void)
{
//--- Сохраним ограничение по смещению
int shift_y2_limit=m_list_y_size-m_list_visible_y_size;
//--- Получим текущую позицию ползунка полосы прокрутки
int v_offset=(m_scrollv.CurrentPos()*m_item_y_size);
//--- Рассчитаем отступы для смещения
int y_offset=(v_offset<m_y_offset)? 0 :(v_offset>=shift_y2_limit-(m_y_offset*2+1))? shift_y2_limit : v_offset;
//--- Первая позиция, если полосы прокрутки нет
long y=(!m_scrollv.IsVisible())? 0 : y_offset;
//--- Смещение данных
::ObjectSetInteger(m_chart_id,m_listview.ChartObjectName(),OBJPROP_YOFFSET,y);
}
//+------------------------------------------------------------------+
//| Перемещение элемента |
//+------------------------------------------------------------------+
void CListView::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_listview.X(m_main.X2()-m_listview.XGap());
}
else
{
CElementBase::X(m_main.X()+XGap());
m_listview.X(m_main.X()+m_listview.XGap());
}
//--- Если привязка снизу
if(m_anchor_bottom_window_side)
{
CElementBase::Y(m_main.Y2()-YGap());
m_listview.Y(m_main.Y2()-m_listview.YGap());
}
else
{
CElementBase::Y(m_main.Y()+YGap());
m_listview.Y(m_main.Y()+m_listview.YGap());
}
//--- Обновление координат графических объектов
::ObjectSetInteger(m_chart_id,m_listview.ChartObjectName(),OBJPROP_XDISTANCE,m_listview.X());
::ObjectSetInteger(m_chart_id,m_listview.ChartObjectName(),OBJPROP_YDISTANCE,m_listview.Y());
//--- Обновить положение объектов
CElement::Moving(only_visible);
}
//+------------------------------------------------------------------+
//| Показывает список |
//+------------------------------------------------------------------+
void CListView::Show(void)
{
//--- Выйти, если элемент уже видим
if(CElementBase::IsVisible())
return;
//--- Показать элемент
::ObjectSetInteger(m_chart_id,m_canvas.ChartObjectName(),OBJPROP_TIMEFRAMES,OBJ_ALL_PERIODS);
::ObjectSetInteger(m_chart_id,m_listview.ChartObjectName(),OBJPROP_TIMEFRAMES,OBJ_ALL_PERIODS);
//--- Состояние видимости
CElementBase::IsVisible(true);
//--- Обновить положение объектов
Moving();
//--- Показать полосу прокрутки
if(m_scrollv.IsScroll())
m_scrollv.Show();
}
//+------------------------------------------------------------------+
//| Скрывает список |
//+------------------------------------------------------------------+
void CListView::Hide(void)
{
if(!CElementBase::IsVisible())
return;
//--- Скрыть элемент
::ObjectSetInteger(m_chart_id,m_canvas.ChartObjectName(),OBJPROP_TIMEFRAMES,OBJ_NO_PERIODS);
::ObjectSetInteger(m_chart_id,m_listview.ChartObjectName(),OBJPROP_TIMEFRAMES,OBJ_NO_PERIODS);
//--- Скрыть полосу прокрутки
m_scrollv.Hide();
//--- Состояние видимости
CElementBase::IsVisible(false);
}
//+------------------------------------------------------------------+
//| Удаление |
//+------------------------------------------------------------------+
void CListView::Delete(void)
{
CElement::Delete();
m_listview.Destroy();
//--- Освободить массив
::ArrayFree(m_items);
}
//+------------------------------------------------------------------+
//| Установка приоритетов |
//+------------------------------------------------------------------+
void CListView::SetZorders(void)
{
CElement::SetZorders();
::ObjectSetInteger(m_chart_id,m_listview.ChartObjectName(),OBJPROP_ZORDER,m_zorder+1);
}
//+------------------------------------------------------------------+
//| Сброс приоритетов |
//+------------------------------------------------------------------+
void CListView::ResetZorders(void)
{
CElement::ResetZorders();
::ObjectSetInteger(m_chart_id,m_listview.ChartObjectName(),OBJPROP_ZORDER,WRONG_VALUE);
}
//+------------------------------------------------------------------+
//| Рисует элемент |
//+------------------------------------------------------------------+
void CListView::Draw(void)
{
DrawList();
}
//+------------------------------------------------------------------+
//| Обновление элемента |
//+------------------------------------------------------------------+
void CListView::Update(const bool redraw=false)
{
//--- Перерисовать таблицу, если указано
if(redraw)
{
//--- Рассчитать размеры
CalculateListYSize();
//--- Установить новый размер
ChangeListSize();
//--- Нарисовать
Draw();
//--- Применить
m_canvas.Update();
m_listview.Update();
return;
}
//--- Применить
m_canvas.Update();
m_listview.Update();
}
//+------------------------------------------------------------------+
//| Обработка нажатия на пункте списка |
//+------------------------------------------------------------------+
bool CListView::OnClickList(const string pressed_object)
{
//--- Выйти, если (1) список не в фокусе или (2) полоса прокрутки в активном режиме
if(!CElementBase::MouseFocus() || m_scrollv.State())
return(false);
//--- Выйдем, если (1) чужое имя объекта или (2) список чист
if(m_listview.ChartObjectName()!=pressed_object || ItemsTotal()<1)
return(false);
//--- Определим пункт, на котором нажали
int index=PressedItemIndex();
//--- Если список без чек-боксов
if(!m_checkbox_mode)
{
//--- Скорректируем вертикальную полосу прокрутки
CorrectingVerticalScrollThumb();
//--- Изменить цвет пункта
RedrawItemsByMode(true);
}
else
{
//--- Изменим состояние чек-бокса на противоположное
m_items[index].m_state=!m_items[index].m_state;
//--- Обновить список
RedrawItem(index);
}
//--- Отправим сообщение об этом
::EventChartCustom(m_chart_id,ON_CLICK_LIST_ITEM,CElementBase::Id(),m_selected_item,"");
return(true);
}
//+------------------------------------------------------------------+
//| Возвращает индекс пункта, на котором нажали |
//+------------------------------------------------------------------+
int CListView::PressedItemIndex(void)
{
int index=0;
//--- Получим относительную Y-координату под курсором мыши
int y=m_mouse.RelativeY(m_listview);
//--- Определим ряд, на котором нажали
for(int i=0; i<m_items_total; i++)
{
//--- Если нажатие было не на этом ряде, перейти к следующему
if(!(y>=m_items[i].m_y && y<=m_items[i].m_y2))
continue;
//--- Запомним индекс
index=i;
//--- Если список без чек-боксов
if(!m_checkbox_mode)
{
//--- Сохраним индекс ряда и строку первой ячейки
m_prev_selected_item =(m_selected_item==WRONG_VALUE)? index : m_selected_item;
m_selected_item =index;
m_selected_item_text =m_items[index].m_value;
}
break;
}
//--- Вернуть индекс
return(index);
}
//+------------------------------------------------------------------+
//| Ускоренная перемотка списка |
//+------------------------------------------------------------------+
void CListView::FastSwitching(void)
{
//--- Выйдем, если нет фокуса на списке
if(!CElementBase::MouseFocus())
return;
//--- Вернём счётчик к первоначальному значению, если кнопка мыши отжата
if(!m_mouse.LeftButtonState())
m_timer_counter=SPIN_DELAY_MSC;
//--- Если же кнопка мыши нажата
else
{
//--- Увеличим счётчик на установленный интервал
m_timer_counter+=TIMER_STEP_MSC;
//--- Выйдем, если меньше нуля
if(m_timer_counter<0)
return;
//--- Флаг перемотки
bool scroll_v=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;
}
//--- Выйти, если кнопки не нажаты
if(!scroll_v)
return;
//--- Обновить список
ShiftData();
m_scrollv.Update(true);
}
}
//+------------------------------------------------------------------+
//| Рассчитывает полный размер списка по оси Y |
//+------------------------------------------------------------------+
void CListView::CalculateListYSize(void)
{
//--- Рассчитаем общую высоту таблицы
int y_size =(m_item_y_size*m_items_total)+(m_y_offset*2)+1;
m_list_y_size =(y_size<=m_y_size)? m_y_size-2 : y_size;
//--- Зададим высоту фрейма для показа фрагмента изображения (видимой части таблицы таблицы)
m_list_visible_y_size=m_y_size-2;
//--- Корректировка размера видимой части по оси Y
m_list_visible_y_size=(m_list_visible_y_size>=m_list_y_size)? m_list_y_size : m_list_visible_y_size;
//--- Расчёт координат
for(int i=0; i<m_items_total; i++)
{
//--- Рассчитаем Y-координаты
m_items[i].m_y =(i<1)? m_y_offset : m_items[i-1].m_y2;
m_items[i].m_y2 =m_items[i].m_y+m_item_y_size;
}
}
//+------------------------------------------------------------------+
//| Изменить основные размеры элемента |
//+------------------------------------------------------------------+
void CListView::ChangeMainSize(const int x_size,const int y_size)
{
//--- Установить новый размер
CElementBase::XSize(x_size);
CElementBase::YSize(y_size);
}
//+------------------------------------------------------------------+
//| Изменить размеры поля ввода |
//+------------------------------------------------------------------+
void CListView::ChangeListSize(void)
{
int x_size=m_x_size-2;
//--- Установить новый размер таблице
m_canvas.XSize(m_x_size);
m_canvas.YSize(m_y_size);
m_canvas.Resize(m_x_size,m_y_size);
m_listview.XSize(x_size);
m_listview.YSize(m_list_y_size);
m_listview.Resize(x_size,m_list_y_size);
//--- Установим размеры видимой области
::ObjectSetInteger(m_chart_id,m_listview.ChartObjectName(),OBJPROP_XSIZE,x_size);
::ObjectSetInteger(m_chart_id,m_listview.ChartObjectName(),OBJPROP_YSIZE,m_list_visible_y_size);
//--- Изменить размеры полос прокрутки
ChangeScrollsSize();
//--- Корректировка данных
ShiftData();
}
//+------------------------------------------------------------------+
//| Изменить размеры полос прокрутки |
//+------------------------------------------------------------------+
void CListView::ChangeScrollsSize(void)
{
//--- Расчёт количества шагов для смещения
uint y_size_total =ItemsTotal();
uint visible_y_size_total =VisibleItemsTotal();
//--- Рассчитать размеры полос прокрутки
m_scrollv.Reinit(y_size_total,visible_y_size_total);
//--- Установить новый размер
m_scrollv.ChangeYSize(CElementBase::YSize()-2);
//--- Если вертикальная полоса прокрутки не нужна
if(!m_scrollv.IsScroll())
{
//--- Скрыть вертикальную полосу прокрутки
m_scrollv.Hide();
}
else
{
//--- Показать вертикальную полосу прокрутки
if(CElementBase::IsVisible())
m_scrollv.Show();
}
}
//+------------------------------------------------------------------+
//| Расчёт с учётом последних изменений и изменение размеров списка |
//+------------------------------------------------------------------+
void CListView::RecalculateAndResizeList(const bool redraw=false)
{
//--- Рассчитать размеры списка
CalculateListYSize();
//--- Установить новый размер
ChangeListSize();
//--- Обновить
Update(redraw);
}
//+------------------------------------------------------------------+
//| Инициализация указанного пункта значениями по умолчанию |
//+------------------------------------------------------------------+
void CListView::ItemInitialize(const uint item_index)
{
m_items[item_index].m_y =0;
m_items[item_index].m_y2 =0;
m_items[item_index].m_value ="";
m_items[item_index].m_state =false;
}
//+------------------------------------------------------------------+
//| Делает копию указанного пункта (source) в новое место (dest.) |
//+------------------------------------------------------------------+
void CListView::ItemCopy(const uint item_dest,const uint item_source)
{
m_items[item_dest].m_value =m_items[item_source].m_value;
m_items[item_dest].m_state =m_items[item_source].m_state;
}
//+------------------------------------------------------------------+
//| Расчёт ширины пунктов |
//+------------------------------------------------------------------+
int CListView::CalculationItemsWidth(void)
{
return((m_scrollv.IsScroll()) ? CElementBase::XSize()-m_scrollv.ScrollWidth()-3 : CElementBase::XSize()-3);
}
//+------------------------------------------------------------------+
//| Расчёт границ элемента по оси Y |
//+------------------------------------------------------------------+
void CListView::CalculateYBoundaries(void)
{
//--- Выйти, если полосы прокрутки нет
if(!m_scrollv.IsVisible())
return;
//--- Получим Y-координату и смещение по оси Y
int y =(int)::ObjectGetInteger(m_chart_id,m_listview.ChartObjectName(),OBJPROP_YDISTANCE);
int yoffset =(int)::ObjectGetInteger(m_chart_id,m_listview.ChartObjectName(),OBJPROP_YOFFSET);
//--- Рассчитаем границы видимой части поля ввода
m_y_limit =(y+yoffset)-y;
m_y2_limit =(y+yoffset+m_y_size)-y;
}
//+------------------------------------------------------------------+
//| Корректировка вертикальной полосы прокрутки |
//+------------------------------------------------------------------+
void CListView::CorrectingVerticalScrollThumb(void)
{
//--- Получим границы видимой части поля ввода
CalculateYBoundaries();
//--- Если текстовый курсор вышел из поля видимости вверх
if(m_items[m_selected_item].m_y<=m_y_limit)
{
Scrolling(CalculateScrollPosY());
}
//--- Если текстовый курсор вышел из поля видимости вниз
else if(m_items[m_selected_item].m_y2>=m_y2_limit)
{
Scrolling(CalculateScrollPosY(true));
}
}
//+------------------------------------------------------------------+
//| Расчёт Y-позиции ползунка полосы прокрутки |
//+------------------------------------------------------------------+
int CListView::CalculateScrollPosY(const bool to_down=false)
{
int calc_y =(!to_down)? CalculateScrollThumbY() : CalculateScrollThumbY2();
double pos_y_value =(calc_y-::fmod((double)calc_y,(double)m_item_y_size))/m_item_y_size+((!to_down)? 0 : 1);
//---
return((int)pos_y_value);
}
//+------------------------------------------------------------------+
//| Расчёт Y-координаты полосы прокрутки в верхней границе списка |
//+------------------------------------------------------------------+
int CListView::CalculateScrollThumbY(void)
{
return(m_items[m_selected_item].m_y-m_y_offset);
}
//+------------------------------------------------------------------+
//| Расчёт Y-координаты полосы прокрутки в нижней границе списка |
//+------------------------------------------------------------------+
int CListView::CalculateScrollThumbY2(void)
{
//--- Рассчитать и вернуть значение
return(m_items[m_selected_item].m_y-m_y_size+m_item_y_size);
}
//+------------------------------------------------------------------+
//| Определение индексов видимой области списка |
//+------------------------------------------------------------------+
void CListView::VisibleListIndexes(void)
{
//--- Определяем границы с учётом смещения видимой области таблицы
int yoffset1 =(int)::ObjectGetInteger(m_chart_id,m_listview.ChartObjectName(),OBJPROP_YOFFSET);
int yoffset2 =yoffset1+m_list_visible_y_size;
//--- Определяем первый и последний индексы видимой области таблицы
m_visible_list_from_index =int(double(yoffset1/m_item_y_size));
m_visible_list_to_index =int(double(yoffset2/m_item_y_size));
//--- Нижний индекс на один больше, если не выходим из диапазона
m_visible_list_to_index=(m_visible_list_to_index+1>m_items_total)? m_items_total : m_visible_list_to_index+1;
}
//+------------------------------------------------------------------+
//| Рисует список |
//+------------------------------------------------------------------+
void CListView::DrawList(const bool only_visible=false)
{
//--- Если не указано перерисовать только видимую часть списка
if(!only_visible)
{
//--- Установим индексы строк всего списка от самого начала и до конца
m_visible_list_from_index =0;
m_visible_list_to_index =m_items_total;
}
//--- Получим индексы строк видимой части списка
else
VisibleListIndexes();
//--- Нарисовать фон
DrawBackground();
m_listview.Erase(::ColorToARGB(m_back_color,m_alpha));
//--- Нарисовать картинки
DrawImages();
//--- Нарисовать текст
DrawText();
//--- Нарисовать рамку
DrawBorder();
}
//+------------------------------------------------------------------+
//| Рисует рамку поля ввода |
//+------------------------------------------------------------------+
void CListView::DrawBorder(void)
{
//--- Получим смещение по оси X
int x_offset =(int)::ObjectGetInteger(m_chart_id,m_canvas.ChartObjectName(),OBJPROP_XOFFSET);
int y_offset =(int)::ObjectGetInteger(m_chart_id,m_canvas.ChartObjectName(),OBJPROP_YOFFSET);
//--- Границы
int x_size =(int)::ObjectGetInteger(m_chart_id,m_canvas.ChartObjectName(),OBJPROP_XSIZE);
int y_size =(int)::ObjectGetInteger(m_chart_id,m_canvas.ChartObjectName(),OBJPROP_YSIZE);
//--- Координаты
int x1 =x_offset;
int y1 =y_offset;
int x2 =x_offset+x_size;
int y2 =y_offset+y_size;
//--- Рисуем прямоугольник без заливки
m_canvas.Rectangle(x1,y1,x2-1,y2-1,::ColorToARGB(m_border_color));
}
//+------------------------------------------------------------------+
//| Рисует картинки |
//+------------------------------------------------------------------+
void CListView::DrawImages(void)
{
//--- Выйти, если чек-боксы отключены
if(!m_checkbox_mode)
return;
//--- Рисуем чек-боксы в пунктах
for(int i=m_visible_list_from_index; i<m_visible_list_to_index; i++)
{
//--- Расчёт координат
m_images_group[0].m_y_gap=m_items[i].m_y+m_icon_y_gap;
//--- Установить соответствующую картинку
CElement::ChangeImage(0,(m_items[i].m_state)? 2 : 0);
CListView::DrawImage();
}
}
//+------------------------------------------------------------------+
//| Рисует картинку |
//+------------------------------------------------------------------+
void CListView::DrawImage(void)
{
//--- Индекс изображения
int i=SelectedImage();
//--- Если нет изображений
if(i==WRONG_VALUE)
return;
//--- Координаты
int x =m_images_group[0].m_x_gap;
int y =m_images_group[0].m_y_gap;
//--- Размеры
uint height =m_images_group[0].m_image[i].Height();
uint width =m_images_group[0].m_image[i].Width();
//--- Рисуем
for(uint ly=0,p=0; ly<height; ly++)
{
for(uint lx=0; lx<width; lx++,p++)
{
//--- Если нет цвета, перейти к следующему пикселю
if(m_images_group[0].m_image[i].Data(p)<1)
continue;
//--- Получаем цвет нижнего слоя (фона ячейки) и цвет указанного пикселя картинки
uint background =::ColorToARGB(m_listview.PixelGet(x+lx,y+ly));
uint pixel_color =m_images_group[0].m_image[i].Data(p);
//--- Смешиваем цвета
uint foreground=::ColorToARGB(m_clr.BlendColors(background,pixel_color));
//--- Рисуем пиксель наслаиваемого изображения
m_listview.PixelSet(x+lx,y+ly,foreground);
}
}
}
//+------------------------------------------------------------------+
//| Рисует картинку |
//+------------------------------------------------------------------+
void CListView::DrawText(void)
{
//--- Для расчёта координат и отступов
int x=0,y=0;
//--- Свойства шрифта
m_listview.FontSet(CElement::Font(),-CElement::FontSize()*10,FW_NORMAL);
//--- Ряды
for(int i=m_visible_list_from_index; i<m_visible_list_to_index; i++)
{
//--- Нарисовать фон строки
int x1 =0;
int x2 =CalculationItemsWidth();
int y1 =m_items[i].m_y;
int y2 =m_items[i].m_y2;
//---
if(i==m_selected_item)
{
m_listview.FillRectangle(x1,y1,x2,y2,ItemColorCurrent(i,false));
m_listview.Rectangle(x1,y1,x2,y2,::ColorToARGB(m_back_color,m_alpha));
}
//--- Нарисовать текст
x =m_label_x_gap;
y =m_items[i].m_y+m_label_y_gap;
m_listview.TextOut(x,y,m_items[i].m_value,TextColor(i),TA_LEFT|TA_TOP);
}
}
//+------------------------------------------------------------------+
//| Перерисовывает указанный пункт списка |
//+------------------------------------------------------------------+
void CListView::RedrawItem(const int item_index)
{
//--- Координаты
int x1 =0;
int x2 =CalculationItemsWidth();
int y1 =m_items[item_index].m_y;
int y2 =m_items[item_index].m_y2;
//--- Для расчёта координат
int x=0,y=0;
//--- Для проверки фокуса
bool is_item_focus=false;
//--- Если включен режим подсветки строк списка
if(m_lights_hover)
{
//--- (1) Получим относительную Y-координату курсора мыши и (2) фокус на указанной строке таблицы
y=m_mouse.RelativeY(m_listview);
is_item_focus=(y>m_items[item_index].m_y && y<=m_items[item_index].m_y2);
}
//--- Нарисовать пункт
m_listview.FillRectangle(x1,y1,x2,y2,ItemColorCurrent(item_index,is_item_focus));
//--- Нарисовать рамку
m_listview.Rectangle(x1,y1,x2,y2,::ColorToARGB(m_back_color,m_alpha));
//--- Рисуем картинки, если список с чек-боксами
if(m_checkbox_mode)
{
//--- Расчёт координат
m_images_group[0].m_y_gap=m_items[item_index].m_y+m_icon_y_gap;
//--- Установить соответствующую картинку
CElement::ChangeImage(0,(m_items[item_index].m_state)? 2 : 0);
CListView::DrawImage();
}
//--- Нарисовать текст
x1 =m_label_x_gap;
y1 =m_items[item_index].m_y+m_label_y_gap;
m_listview.TextOut(x1,y1,m_items[item_index].m_value,TextColor(item_index),TA_LEFT|TA_TOP);
//--- Обновить холст
m_listview.Update();
}
//+------------------------------------------------------------------+
//| Перерисовывает пункты списка по указанному режиму |
//+------------------------------------------------------------------+
void CListView::RedrawItemsByMode(const bool is_selected_item=false)
{
//--- Текущий и предыдущий индексы строк
int item_index =WRONG_VALUE;
int prev_item_index =WRONG_VALUE;
//--- Инициализиция индексов строк относительного указанного режима
if(is_selected_item)
{
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;
//--- Количество пунктов для рисования
uint items_total=(item_index!=WRONG_VALUE && prev_item_index!=WRONG_VALUE && item_index!=prev_item_index)? 2 : 1;
//--- Координаты
int x1=0;
int x2=CalculationItemsWidth();
int y1[2]={0},y2[2]={0};
//--- Массив для значений в определённой последовательности
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;
}
//--- Рисуем фон пунктов
for(uint i=0; i<items_total; i++)
{
//--- Расчёт координат верхней и нижней границ строки
y1[i] =m_items[indexes[i]].m_y;
y2[i] =m_items[indexes[i]].m_y2;
//--- Определим фокус на строке относительно режима подсветки
bool is_item_focus=false;
if(!m_lights_hover)
is_item_focus=(indexes[i]==item_index && item_index!=WRONG_VALUE);
else
is_item_focus=(item_index==WRONG_VALUE)?(indexes[i]==prev_item_index) :(indexes[i]==item_index);
//--- Нарисовать пункт
m_listview.FillRectangle(x1,y1[i],x2,y2[i],ItemColorCurrent(indexes[i],is_item_focus));
//--- Нарисовать рамку
m_listview.Rectangle(x1,y1[i],x2,y2[i],::ColorToARGB(m_back_color,m_alpha));
}
//--- Рисуем картинки, если список с чек-боксами
if(m_checkbox_mode)
{
for(uint i=0; i<items_total; i++)
{
//--- Расчёт координат
m_images_group[0].m_y_gap=m_items[indexes[i]].m_y+m_icon_y_gap;
//--- Установить соответствующую картинку
CElement::ChangeImage(0,(m_items[indexes[i]].m_state)? 2 : 0);
CListView::DrawImage();
}
}
//--- Для расчёта координат
int x=0,y=0;
//--- Получим X-координату текста
x=m_label_x_gap;
//--- Рисуем текст
for(uint i=0; i<items_total; i++)
{
//--- (1) Рассчитать координату и (2) нарисовать текст
y=m_items[indexes[i]].m_y+m_label_y_gap;
m_listview.TextOut(x,y,m_items[indexes[i]].m_value,TextColor(indexes[i]),TA_TOP|TA_LEFT);
}
//--- Применить
m_listview.Update();
}
//+------------------------------------------------------------------+
//| Возвращает текущий цвет фона пункта |
//+------------------------------------------------------------------+
uint CListView::ItemColorCurrent(const int item_index,const bool is_item_focus)
{
//--- Если выделенная строка
if(item_index==m_selected_item)
return(::ColorToARGB(m_back_color_pressed,m_alpha));
//--- Цвет пункта
uint clr=m_back_color;
//--- Если (1) нет фокуса или (2) форма заблокирована
bool condition=(!is_item_focus || !m_canvas.MouseFocus() || m_main.CElementBase::IsLocked());
//---
clr=(condition)? m_back_color : m_back_color_hover;
//--- Вернуть цвет
return(::ColorToARGB(clr,m_alpha));
}
//+------------------------------------------------------------------+
//| Возвращает цвет текста пункта |
//+------------------------------------------------------------------+
uint CListView::TextColor(const int item_index)
{
uint clr=(item_index==m_selected_item)? m_label_color_pressed : m_label_color;
//--- Вернуть цвет заголовка
return(::ColorToARGB(clr));
}
//+------------------------------------------------------------------+
//| Изменить ширину по правому краю формы |
//+------------------------------------------------------------------+
void CListView::ChangeWidthByRightWindowSide(void)
{
//--- Выйти, если включен режим фиксации к правому краю формы
if(m_anchor_right_window_side)
return;
//--- Размеры
int x_size =m_main.X2()-CElementBase::X()-m_auto_xresize_right_offset;
int y_size =(m_auto_yresize_mode)? m_main.Y2()-CElementBase::Y()-m_auto_yresize_bottom_offset : m_y_size;
//--- Установить новый размер
ChangeMainSize(x_size,y_size);
//--- Рассчитать размеры поля ввода
CalculateListYSize();
//--- Установить новый размер полю ввода
ChangeListSize();
//--- Нарисовать элемент
Draw();
Update();
if(m_scrollv.IsScroll())
m_scrollv.Update(true);
}
//+------------------------------------------------------------------+
//| Изменить высоту по нижнему краю окна |
//+------------------------------------------------------------------+
void CListView::ChangeHeightByBottomWindowSide(void)
{
//--- Выйти, если включен режим фиксации к нижнему краю формы
if(m_anchor_bottom_window_side)
return;
//--- Размеры
int x_size =(m_auto_xresize_mode)? m_main.X2()-CElementBase::X()-m_auto_xresize_right_offset : m_x_size;
int y_size =m_main.Y2()-CElementBase::Y()-m_auto_yresize_bottom_offset;
//--- Установить новый размер
ChangeMainSize(x_size,y_size);
//--- Рассчитать размеры списка
CalculateListYSize();
//--- Установить новый размер полю ввода
ChangeListSize();
//--- Нарисовать элемент
Draw();
Update();
if(m_scrollv.IsScroll())
m_scrollv.Update(true);
}
//+------------------------------------------------------------------+