//+------------------------------------------------------------------+
//|                                                     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;
   //---
   bool              m_green_checkbox;
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;        }
   void              GreenCheckBox(const bool state)                     { m_green_checkbox=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) выделение пункта
   void              SetValue(const uint item_index,const string value,const bool redraw=false);
   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);
   //---
   bool              GetState(const uint item_index);
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);
   //---
   //--- Возвращает индекс пункта, на котором нажали
   int               PressedItemIndex(void);
private:
   //--- Обработка нажатия на пункте списка
   bool              OnClickList(const string pressed_object);

   //--- Изменение цвета пунктов списка при наведении
   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_green_checkbox(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();
      return;
     }
//--- Обработка нажатия на объектах
   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);
  }
//+------------------------------------------------------------------+
//| Создаёт объект для рисования                                     |
//+------------------------------------------------------------------+
#resource "\\Images\\EasyAndFastGUI\\Controls\\checkbox_off.bmp"
#resource "\\Images\\EasyAndFastGUI\\Controls\\checkbox_off_locked.bmp"
#resource "\\Images\\EasyAndFastGUI\\Controls\\checkbox_on.bmp"
#resource "\\Images\\EasyAndFastGUI\\Controls\\checkbox_on_g.bmp"
#resource "\\Images\\EasyAndFastGUI\\Controls\\checkbox_on_locked.bmp"
//---
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("Images\\EasyAndFastGUI\\Controls\\checkbox_off.bmp");
      IconFileLocked("Images\\EasyAndFastGUI\\Controls\\checkbox_off_locked.bmp");
      if(m_green_checkbox)
         IconFilePressed("Images\\EasyAndFastGUI\\Controls\\checkbox_on_g.bmp");
      else
         IconFilePressed("Images\\EasyAndFastGUI\\Controls\\checkbox_on.bmp");
      IconFilePressedLocked("Images\\EasyAndFastGUI\\Controls\\checkbox_on_locked.bmp");
     }
//--- Координаты
   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);
  }
//+------------------------------------------------------------------+
//| Получение состояния чек-бокса по указанному индексу              |
//+------------------------------------------------------------------+
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);
  }
//+------------------------------------------------------------------+
//| Возвращает количество видимых пунктов                            |
//+------------------------------------------------------------------+
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);
  }
//+------------------------------------------------------------------+
//| Устанавливает размер списка                                      |
//+------------------------------------------------------------------+
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)
  {
//--- Установим нулевой размер
   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.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.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);
  }
//+------------------------------------------------------------------+
