//+------------------------------------------------------------------+ //| TreeView.mqh | //| Copyright 2015, MetaQuotes Software Corp. | //| http://www.mql5.com | //+------------------------------------------------------------------+ #include "..\Element.mqh" #include "TreeItem.mqh" #include "Scrolls.mqh" #include "Pointer.mqh" //+------------------------------------------------------------------+ //| Класс для создания древовидного списка | //+------------------------------------------------------------------+ class CTreeView : public CElement { private: //--- Объекты для создания элемента CTreeItem m_items[]; CTreeItem m_content_items[]; CScrollV m_scrollv; CScrollV m_content_scrollv; CPointer m_x_resize; //--- Структура элементов закреплённых за каждым пунктом-вкладкой struct TVElements { CElement *elements[]; int list_index; }; TVElements m_tab_items[]; //--- Массивы для всех пунктов древовидного списка (полный список) int m_t_list_index[]; int m_t_prev_node_list_index[]; string m_t_item_text[]; string m_t_path_bmp[]; int m_t_item_index[]; int m_t_node_level[]; int m_t_prev_node_item_index[]; int m_t_items_total[]; int m_t_folders_total[]; bool m_t_item_state[]; bool m_t_is_folder[]; //--- Массивы для списка отображаемых пунктов древовидного списка int m_td_list_index[]; //--- Массивы для списка содержания пунктов выделенных в древовидном списке (полный список) int m_c_list_index[]; int m_c_tree_list_index[]; string m_c_item_text[]; //--- Массивы для списка отображаемых пунктов в списке содержания int m_cd_list_index[]; int m_cd_tree_list_index[]; string m_cd_item_text[]; //--- Общее количество пунктов и количество в видимой части списков int m_items_total; int m_content_items_total; int m_visible_items_total; //--- Индексы выделенных пунктов в списках int m_selected_item_index; int m_selected_content_item_index; //--- Текст выделенного пункта в списке. // Только для файлов в случае использования класса для создания файлового навигатора. // Если в списке выбран не файл, то в этом поле должна быть пустая строка "". string m_selected_item_file_name; //--- Ширина области древовидного списка int m_treeview_width; //--- Высота пунктов int m_item_y_size; //--- Режим файлового навигатора ENUM_FILE_NAVIGATOR_MODE m_file_navigator_mode; //--- Режим подсветки при наведении курсора bool m_lights_hover; //--- Режим показа содержания пункта в рабочей области bool m_show_item_content; //--- Режим изменения ширины списков bool m_resize_list_mode; //--- Режим пунктов-вкладок bool m_tab_items_mode; //--- Счётчик таймера для перемотки списка int m_timer_counter; //--- (1) Минимальный и (2) максимальный уровень узла int m_min_node_level; int m_max_node_level; //--- Количество пунктов в корневом каталоге int m_root_items_total; //--- public: CTreeView(void); ~CTreeView(void); //--- Методы для создания древовидного списка bool CreateTreeView(const int x_gap,const int y_gap); //--- private: void InitializeProperties(const int x_gap,const int y_gap); bool CreateCanvas(void); bool CreateItems(void); bool CreateScrollV(void); bool CreateContentItems(void); bool CreateContentScrollV(void); bool CreateXResizePointer(void); //--- public: //--- Указатели полос прокрутки списков CScrollV *GetScrollVPointer(void) { return(::GetPointer(m_scrollv)); } CScrollV *GetContentScrollVPointer(void) { return(::GetPointer(m_content_scrollv)); } CPointer *GetMousePointer(void) { return(::GetPointer(m_x_resize)); } //--- Возвращает (1) указатель пункта древовидного списка, (2) указатель пункта списка содержания, CTreeItem *ItemPointer(const uint index); CTreeItem *ContentItemPointer(const uint index); //--- (1) Режим файлового навигатора, (2) режим подсветки при наведении курсора мыши, // (3) режим изменения ширины списков, (4) режим пунктов-вкладок void NavigatorMode(const ENUM_FILE_NAVIGATOR_MODE mode) { m_file_navigator_mode=mode; } void LightsHover(const bool state) { m_lights_hover=state; } void ResizeListMode(const bool state) { m_resize_list_mode=state; } void TabItemsMode(const bool state) { m_tab_items_mode=state; } bool TabItemsMode(void) const { return(m_tab_items_mode); } //--- Режим показа содержания пункта, void ShowItemContent(const bool state) { m_show_item_content=state; } bool ShowItemContent(void) const { return(m_show_item_content); } //--- Количество пунктов (1) в древовидном списке, (2) в списке содержания и (3) видимое количество пунктов int ItemsTotal(void) const { return(::ArraySize(m_items)); } int ContentItemsTotal(void) const { return(::ArraySize(m_content_items)); } void VisibleItemsTotal(const int total) { m_visible_items_total=total; } //--- (1) Высота пункта, (2) ширина древовидного списка и (3) списка содержания void ItemYSize(const int y_size) { m_item_y_size=y_size; } void TreeViewWidth(const int x_size) { m_treeview_width=x_size; } //--- (1) Выделяет пункт по индексу и (2) возвращает индекс выделенного пункта, (3) возвращает название файла void SelectedItemIndex(const int index) { m_selected_item_index=index; } int SelectedItemIndex(void) const { return(m_selected_item_index); } string SelectedItemFileName(void) const { return(m_selected_item_file_name); } //--- Добавляет пункт в древовидный список void AddItem(const int list_index,const int list_id,const string item_name,const string path_bmp,const int item_index, const int node_number,const int item_number,const int items_total,const int folders_total,const bool item_state,const bool is_folder=true); //--- Добавляет элемент в массив пункта-вкладки void AddToElementsArray(const int item_index,CElement &object); //--- Показать элементы только выделенного пункта-вкладки void ShowTabElements(void); //--- Возвращает полный путь выделенного пункта string CurrentFullPath(void); //--- public: //--- Обработчик событий графика virtual void OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam); //--- Таймер virtual void OnEventTimer(void); //--- Доступность элемента virtual void IsAvailable(const bool state,const bool without_items=false); //--- Управление virtual void Show(void); virtual void Hide(void); virtual void Delete(void); //--- Рисует элемент virtual void Draw(void); //--- private: //--- Обработка нажатия на кнопке сворачивания/разворачивания списка пункта bool OnClickItemArrow(const string clicked_object,const int id,const int index); //--- Обработка нажатия на пункте древовидного списка bool OnClickTreeItem(const string clicked_object,const int id,const int index); //--- Обработка нажатия на пункте в списке содержания bool OnClickContentItem(const string clicked_object,const int id,const int index); //--- Формирует массив пунктов-вкладок void GenerateTabItemsArray(void); //--- Определение и установка (1) границ узлов и (2) размера корневого каталога void SetNodeLevelBoundaries(void); void SetRootItemsTotal(void); //--- Смещение списков void ShiftTreeList(void); void ShiftContentList(void); //--- Ускоренная перемотка списка void FastSwitching(void); //--- Управляет шириной списков void ResizeListArea(void); //--- Проверка готовности для изменения ширины списков void CheckXResizePointer(const int x,const int y); //--- Проверка на выход за ограничения bool CheckOutOfArea(const int x,const int y); //--- Обновление ширины элементов списка void UpdateXSize(const int x); //--- Добавляет пункт в список в области содержания void AddDisplayedTreeItem(const int list_index); //--- Формирует (1) древовидный список и (2) список содержания void FormTreeList(void); void FormContentList(void); //--- public: //--- Перерисовка списков void RedrawTreeList(void); void RedrawContentList(void); //--- Обновляет (1) древовидный список и (2) список содержания void UpdateTreeList(void); void UpdateContentList(void); //--- private: //--- Проверка индекса выделенного пункта на выход из диапазона void CheckSelectedItemIndex(void); //--- Рисует границу между областями virtual void DrawResizeBorder(void); //--- Изменить ширину по правому краю окна virtual void ChangeWidthByRightWindowSide(void); }; //+------------------------------------------------------------------+ //| Constructor | //+------------------------------------------------------------------+ CTreeView::CTreeView(void) : m_treeview_width(150), m_item_y_size(20), m_visible_items_total(12), m_tab_items_mode(false), m_lights_hover(false), m_show_item_content(false), m_resize_list_mode(false), m_timer_counter(SPIN_DELAY_MSC), m_selected_item_index(WRONG_VALUE), m_selected_content_item_index(WRONG_VALUE) { //--- Сохраним имя класса элемента в базовом классе CElementBase::ClassName(CLASS_NAME); } //+------------------------------------------------------------------+ //| Destructor | //+------------------------------------------------------------------+ CTreeView::~CTreeView(void) { } //+------------------------------------------------------------------+ //| Обработчик событий | //+------------------------------------------------------------------+ void CTreeView::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam) { //--- Обработка события перемещения курсора if(id==CHARTEVENT_MOUSE_MOVE) { //--- Смещаем древовидный список, если управление ползунком полосы прокрутки в действии if(m_scrollv.ScrollBarControl()) { ShiftTreeList(); m_scrollv.Update(true); return; } //--- Заходим, только если есть список if(m_t_items_total[m_selected_item_index]>0) { //--- Смещаем список содержания, если управление ползунком полосы прокрутки в действии if(m_content_scrollv.ScrollBarControl()) { ShiftContentList(); m_content_scrollv.Update(true); return; } } //--- Управление шириной области содержания ResizeListArea(); return; } //--- Обработка события нажатия на кнопках полосы прокрутки if(id==CHARTEVENT_CUSTOM+ON_CLICK_BUTTON) { //--- Выйти, если в режиме измененения размера области списка содержания if(m_x_resize.IsVisible() || m_x_resize.State()) return; //--- Обработка нажатия на стрелке пункта if(OnClickItemArrow(sparam,(int)lparam,(int)dparam)) return; //--- Обработка нажатия на пункте древовидного списка if(OnClickTreeItem(sparam,(int)lparam,(int)dparam)) return; //--- Обработка нажатия на пункте в списке содержания if(OnClickContentItem(sparam,(int)lparam,(int)dparam)) return; //--- Если было нажатие на кнопках полосы прокрутки списка if(m_scrollv.OnClickScrollInc((uint)lparam,(uint)dparam) || m_scrollv.OnClickScrollDec((uint)lparam,(uint)dparam)) { ShiftTreeList(); m_scrollv.Update(true); return; } //--- Если было нажатие на кнопках полосы прокрутки списка if(m_content_scrollv.OnClickScrollInc((uint)lparam,(uint)dparam) || m_content_scrollv.OnClickScrollDec((uint)lparam,(uint)dparam)) { ShiftContentList(); m_content_scrollv.Update(true); return; } return; } } //+------------------------------------------------------------------+ //| Таймер | //+------------------------------------------------------------------+ void CTreeView::OnEventTimer(void) { //--- Ускоренная перемотка значений FastSwitching(); } //+------------------------------------------------------------------+ //| Создаёт элемент | //+------------------------------------------------------------------+ bool CTreeView::CreateTreeView(const int x_gap,const int y_gap) { //--- Выйти, если нет указателя на главный элемент if(!CElement::CheckMainPointer()) return(false); //--- Инициализация свойств InitializeProperties(x_gap,y_gap); //--- Создание элемента if(!CreateCanvas()) return(false); if(!CreateItems()) return(false); if(!CreateScrollV()) return(false); if(!CreateContentItems()) return(false); if(!CreateContentScrollV()) return(false); if(!CreateXResizePointer()) return(false); //--- Сформируем массив пунктов-вкладок GenerateTabItemsArray(); //--- Определение и установка (1) границ узлов и (2) размера корневого каталога SetNodeLevelBoundaries(); SetRootItemsTotal(); //--- Обновить списки FormTreeList(); FormContentList(); return(true); } //+------------------------------------------------------------------+ //| Инициализация свойств | //+------------------------------------------------------------------+ void CTreeView::InitializeProperties(const int x_gap,const int y_gap) { m_x =CElement::CalculateX(x_gap); m_y =CElement::CalculateY(y_gap); m_x_size =(m_x_size<1 || m_auto_xresize_mode)? m_main.X2()-CElementBase::X()-m_auto_xresize_right_offset : m_x_size; m_y_size =m_item_y_size*m_visible_items_total+2; //--- Ширина списка if(!m_show_item_content) m_treeview_width=m_x_size; else m_treeview_width=(m_treeview_width>=m_x_size)? m_x_size>>1 : m_treeview_width; //--- Цвета по умолчанию m_back_color =(m_back_color!=clrNONE)? m_back_color : clrWhite; m_border_color =(m_border_color!=clrNONE)? m_border_color : C'150,170,180'; //--- Проверка индекса выделенного пункта на выход из диапазона CheckSelectedItemIndex(); //--- Отступы от крайней точки CElementBase::XGap(x_gap); CElementBase::YGap(y_gap); } //+------------------------------------------------------------------+ //| Создаёт объект для рисования | //+------------------------------------------------------------------+ bool CTreeView::CreateCanvas(void) { //--- Формирование имени объекта string name=CElementBase::ElementName("tree_view"); //--- Создание объекта if(!CElement::CreateCanvas(name,m_x,m_y,m_x_size,m_y_size)) return(false); //--- return(true); } //+------------------------------------------------------------------+ //| Создаёт древовидный список | //+------------------------------------------------------------------+ bool CTreeView::CreateItems(void) { //--- Координаты int x=1,y=1; //--- int items_total=::ArraySize(m_items); for(int i=0; i0)? y+m_item_y_size : y; //--- Сохраним указатель родителя m_items[i].MainPointer(this); //--- Свойства m_items[i].NamePart("tree_item"); m_items[i].Index(m_t_list_index[i]); m_items[i].XSize(m_treeview_width); m_items[i].YSize(m_item_y_size); m_items[i].IconXGap(m_items[i].ArrowXGap(m_t_node_level[i])+17); m_items[i].IconYGap(2); m_items[i].IconFile(m_t_path_bmp[i]); m_items[i].IsHighlighted(m_lights_hover); //--- Определим тип пункта ENUM_TYPE_TREE_ITEM type=TI_SIMPLE; if(m_file_navigator_mode==FN_ALL) { type=(m_t_items_total[i]>0)? TI_HAS_ITEMS : TI_SIMPLE; } else // FN_ONLY_FOLDERS { type=(m_t_folders_total[i]>0)? TI_HAS_ITEMS : TI_SIMPLE; } //--- Корректировка начального состояния пункта m_t_item_state[i]=(type==TI_HAS_ITEMS)? m_t_item_state[i]: false; //--- Создание элемента if(!m_items[i].CreateTreeItem(x,y,type,m_t_list_index[i],m_t_node_level[i],m_t_item_text[i],m_t_item_state[i])) return(false); //--- Добавить элемент в массив CElement::AddToArray(m_items[i]); } //--- Установить цвет выделенному пункту if(!m_tab_items_mode && m_selected_item_index>=0) m_items[m_selected_item_index].IsPressed(true); //--- return(true); } //+------------------------------------------------------------------+ //| Создаёт вертикальный скролл | //+------------------------------------------------------------------+ bool CTreeView::CreateScrollV(void) { //--- Сохранить указатель формы m_scrollv.MainPointer(this); //--- Координаты int x=m_treeview_width-((m_show_item_content)? 15 : 16); int y=1; //--- Установим свойства m_scrollv.Index(0); m_scrollv.XSize(m_scrollv.ScrollWidth()); m_scrollv.YSize(CElementBase::YSize()-2); //--- Создание полосы прокрутки if(!m_scrollv.CreateScroll(x,y,m_items_total,m_visible_items_total)) return(false); //--- Добавить элемент в массив CElement::AddToArray(m_scrollv); return(true); } //+------------------------------------------------------------------+ //| Создаёт список содержания выделенного пункта | //+------------------------------------------------------------------+ bool CTreeView::CreateContentItems(void) { //--- Выйти, если (1) содержание пункта не нужно показывать или (2) включен режим вкладок if(!m_show_item_content || m_tab_items_mode) return(true); //--- Резервный размер массива int reserve_size=10000; //--- Координаты и ширина int x=m_treeview_width,y=1; int w=m_x_size-m_treeview_width-2; //--- Счётчик количества пунктов int c=0; //--- int items_total=::ArraySize(m_items); for(int i=0; i0)? y+m_item_y_size : y; //--- Передадим объект панели m_content_items[c].MainPointer(this); //--- Установим свойства перед созданием m_content_items[c].NamePart("content_item"); m_content_items[c].Index(m_t_list_index[i]); m_content_items[c].XSize(w); m_content_items[c].YSize(m_item_y_size); m_content_items[c].IconXGap(7); m_content_items[c].IconYGap(2); m_content_items[c].IconFile(m_t_path_bmp[i]); m_content_items[c].IsHighlighted(m_lights_hover); //--- Создание объекта if(!m_content_items[c].CreateTreeItem(x,y,TI_SIMPLE,c,0,m_t_item_text[i],false)) return(false); //--- Добавить элемент в массив CElement::AddToArray(m_content_items[c]); //--- Сохранить (1) индекс общего списка содержания, (2) индекс древовидного списка и (3) текст пункта m_c_list_index[c] =c; m_c_tree_list_index[c] =m_t_list_index[i]; m_c_item_text[c] =m_t_item_text[i]; //--- c++; } //--- Сохранить размер списка m_content_items_total=::ArraySize(m_content_items); return(true); } //+------------------------------------------------------------------+ //| Создаёт вертикальный скролл для рабочей области | //+------------------------------------------------------------------+ bool CTreeView::CreateContentScrollV(void) { //--- Сохранить указатель формы m_content_scrollv.MainPointer(this); //--- Выйти, если содержание пункта не нужно показывать if(!m_show_item_content) return(true); //--- Координаты int x=16,y=1; //--- Свойства m_content_scrollv.Index(1); m_content_scrollv.XSize(m_content_scrollv.ScrollWidth()); m_content_scrollv.YSize(CElementBase::YSize()-2); m_content_scrollv.AnchorRightWindowSide(true); //--- Создание полосы прокрутки if(!m_content_scrollv.CreateScroll(x,y,m_content_items_total,m_visible_items_total)) return(false); //--- Добавить элемент в массив CElement::AddToArray(m_content_scrollv); return(true); } //+------------------------------------------------------------------+ //| Создаёт указатель курсора изменения ширины | //+------------------------------------------------------------------+ bool CTreeView::CreateXResizePointer(void) { //--- Выйти, если ширину области содержания не нужно изменять или включен режим пунктов-вкладок if(!m_resize_list_mode || m_tab_items_mode) { m_x_resize.State(false); m_x_resize.IsVisible(false); return(true); } //--- Свойства m_x_resize.XGap(12); m_x_resize.YGap(9); m_x_resize.XSize(25); m_x_resize.Type(MP_X_RESIZE); m_x_resize.Id(CElementBase::Id()); //--- Создание элемента if(!m_x_resize.CreatePointer(m_chart_id,m_subwin)) return(false); //--- return(true); } //+------------------------------------------------------------------+ //| Возвращает указатель пункта древовидного списка по индексу | //+------------------------------------------------------------------+ CTreeItem *CTreeView::ItemPointer(const uint index) { uint array_size=::ArraySize(m_items); //--- Если нет ни одного пункта в контекстном меню, сообщить об этом if(array_size<1) { ::Print(__FUNCTION__," > Вызов этого метода нужно осуществлять, " "когда в контекстном меню есть хотя бы один пункт!"); } //--- Корректировка в случае выхода из диапазона uint i=(index>=array_size)? array_size-1 : index; //--- Вернуть указатель return(::GetPointer(m_items[i])); } //+------------------------------------------------------------------+ //| Возвращает указатель пункта области содержания по индексу | //+------------------------------------------------------------------+ CTreeItem *CTreeView::ContentItemPointer(const uint index) { uint array_size=::ArraySize(m_content_items); //--- Если нет ни одного пункта в контекстном меню, сообщить об этом if(array_size<1) { ::Print(__FUNCTION__," > Вызов этого метода нужно осуществлять, " "когда в контекстном меню есть хотя бы один пункт!"); } //--- Корректировка в случае выхода из диапазона uint i=(index>=array_size)? array_size-1 : index; //--- Вернуть указатель return(::GetPointer(m_content_items[i])); } //+------------------------------------------------------------------+ //| Добавляет пункт в общий массив древовидного списка | //+------------------------------------------------------------------+ void CTreeView::AddItem(const int list_index,const int prev_node_list_index,const string item_text,const string path_bmp,const int item_index, const int node_level,const int prev_node_item_index,const int items_total,const int folders_total,const bool item_state,const bool is_folder) { //--- Резервный размер массива int reserve_size=10000; //--- Увеличим размер массивов на один элемент int array_size =::ArraySize(m_items); m_items_total =array_size+1; ::ArrayResize(m_items,m_items_total,reserve_size); ::ArrayResize(m_t_list_index,m_items_total,reserve_size); ::ArrayResize(m_t_prev_node_list_index,m_items_total,reserve_size); ::ArrayResize(m_t_item_text,m_items_total,reserve_size); ::ArrayResize(m_t_path_bmp,m_items_total,reserve_size); ::ArrayResize(m_t_item_index,m_items_total,reserve_size); ::ArrayResize(m_t_node_level,m_items_total,reserve_size); ::ArrayResize(m_t_prev_node_item_index,m_items_total,reserve_size); ::ArrayResize(m_t_items_total,m_items_total,reserve_size); ::ArrayResize(m_t_folders_total,m_items_total,reserve_size); ::ArrayResize(m_t_item_state,m_items_total,reserve_size); ::ArrayResize(m_t_is_folder,m_items_total,reserve_size); //--- Сохраним значения переданных параметров m_t_list_index[array_size] =list_index; m_t_prev_node_list_index[array_size] =prev_node_list_index; m_t_item_text[array_size] =item_text; m_t_path_bmp[array_size] =path_bmp; m_t_item_index[array_size] =item_index; m_t_node_level[array_size] =node_level; m_t_prev_node_item_index[array_size] =prev_node_item_index; m_t_items_total[array_size] =items_total; m_t_folders_total[array_size] =folders_total; m_t_item_state[array_size] =item_state; m_t_is_folder[array_size] =is_folder; } //+------------------------------------------------------------------+ //| Добавляет элемент в массив указанной вкладки | //+------------------------------------------------------------------+ void CTreeView::AddToElementsArray(const int tab_index,CElement &object) { //--- Выйти, если режим пунктов-вкладок отключен if(!m_tab_items_mode) return; //--- Проверка на выход из диапазона int array_size=::ArraySize(m_tab_items); if(array_size<1 || tab_index<0 || tab_index>=array_size) return; //--- Добавим указатель переданного элемента в массив указанной вкладки int size=::ArraySize(m_tab_items[tab_index].elements); ::ArrayResize(m_tab_items[tab_index].elements,size+1); m_tab_items[tab_index].elements[size]=::GetPointer(object); } //+------------------------------------------------------------------+ //| Показывает элементы только выделенного пункта-вкладки | //+------------------------------------------------------------------+ void CTreeView::ShowTabElements(void) { //--- Выйти, если (1) элемент скрыт или (2) режим пунктов-вкладок отключен if(!CElementBase::IsVisible() || !m_tab_items_mode) return; //--- Индекс выделенной вкладки int tab_index=WRONG_VALUE; //--- Определим индекс выделенной вкладки int tab_items_total=::ArraySize(m_tab_items); for(int i=0; i=0; i--) ::StringAdd(path,path_parts[i]+"\\"); //--- Если выделенный в древовидном списке пункт - папка if(m_t_is_folder[m_selected_item_index]) { m_selected_item_file_name=""; //--- Если пункт в области содержания выделен if(m_selected_content_item_index>0) { //--- Если выделенный пункт - файл, сохраним его название if(!m_t_is_folder[m_c_tree_list_index[m_selected_content_item_index]]) m_selected_item_file_name=m_c_item_text[m_selected_content_item_index]; } } //--- Если выделенный в древовидном списке пункт - файл else //--- Сохраним его название m_selected_item_file_name=m_t_item_text[m_selected_item_index]; //--- Вернуть директорию return(path); } //+------------------------------------------------------------------+ //| Доступность элемента | //+------------------------------------------------------------------+ void CTreeView::IsAvailable(const bool state,const bool without_items=false) { //--- Если без пунктов if(without_items) { m_is_available=state; return; } //--- Если с пунктами else { m_is_available=state; int elements_total=CElement::ElementsTotal(); for(int i=0; im_items[list_index].ArrowXGap()+16) return(false); //--- Получим состояние стрелки пункта и установим противоположное m_t_item_state[list_index]=!m_t_item_state[list_index]; //--- Подсветить выделенный пункт m_items[list_index].ItemState(m_t_item_state[list_index]); m_items[list_index].IsPressed((list_index==m_selected_item_index)? true : false); m_items[list_index].Update(true); //--- Сформировать древовидный список FormTreeList(); //--- Обновить UpdateTreeList(); //--- Рассчитать положение ползунка полосы прокрутки m_scrollv.MovingThumb(m_scrollv.CurrentPos()); //--- Показать элементы выделенного пункта-вкладки ShowTabElements(); //--- Отправим сообщение об изменении в графическом интерфейсе ::EventChartCustom(m_chart_id,ON_CHANGE_GUI,CElementBase::Id(),0,""); return(true); } //+------------------------------------------------------------------+ //| Нажатие на пункте в древовидном списке | //+------------------------------------------------------------------+ bool CTreeView::OnClickTreeItem(const string clicked_object,const int id,const int index) { //--- Выйдем, если полоса прокрутки в активном режиме if(m_scrollv.State() || m_content_scrollv.State()) return(false); //--- Выйдем, если чужое имя объекта if(::StringFind(clicked_object,CElementBase::ProgramName()+"_tree_item_",0)<0) return(false); //--- Выйти, если идентификаторы не совпадают if(id!=CElementBase::Id()) return(false); //--- Получим текущую позицию ползунка полосы прокрутки int v=m_scrollv.CurrentPos(); //--- Пройдёмся по списку for(int r=0; r=0 && v0) { m_items[li].IsPressed(false); m_items[li].Update(true); break; } } //--- Установим цвет предыдущему выделенному пункту m_items[m_selected_item_index].IsPressed(false); m_items[m_selected_item_index].Update(true); //--- Запомним индекс для текущего и изменим его цвет m_selected_item_index=li; m_items[li].IsPressed(true); m_items[li].Update(true); break; } v++; } } //--- Сбросить цвета в области содержания if(m_selected_content_item_index>=0) { m_content_items[m_selected_content_item_index].IsPressed(false); m_content_items[m_selected_content_item_index].Update(); } //--- Сброс выделенного пункта m_selected_content_item_index=WRONG_VALUE; //--- Обновить список содержания FormContentList(); UpdateContentList(); //--- Рассчитать положение ползунка полосы прокрутки m_content_scrollv.MovingThumb(m_content_scrollv.CurrentPos()); //--- Показать элементы выделенного пункта-вкладки ShowTabElements(); //--- Отправить сообщение о выборе новой директории в древовидном списке ::EventChartCustom(m_chart_id,ON_CHANGE_TREE_PATH,0,0,""); //--- Отправим сообщение об изменении в графическом интерфейсе ::EventChartCustom(m_chart_id,ON_CHANGE_GUI,CElementBase::Id(),0,""); return(true); } //+------------------------------------------------------------------+ //| Нажатие на пункте в списке содержания | //+------------------------------------------------------------------+ bool CTreeView::OnClickContentItem(const string clicked_object,const int id,const int index) { //--- Выйти, если область содержания отключена if(!m_show_item_content) return(false); //--- Выйдем, если полоса прокрутки в активном режиме if(m_scrollv.State() || m_content_scrollv.State()) return(false); //--- Выйдем, если чужое имя объекта if(::StringFind(clicked_object,CElementBase::ProgramName()+"_content_item_",0)<0) return(false); //--- Выйти, если идентификаторы не совпадают if(id!=CElementBase::Id()) return(false); //--- Получим количество пунктов в списке содержания int content_items_total=::ArraySize(m_cd_list_index); //--- Получим текущую позицию ползунка полосы прокрутки int v=m_content_scrollv.CurrentPos(); //--- Пройдёмся по списку for(int r=0; r=0 && v=0) { m_content_items[m_selected_content_item_index].IsPressed(false); m_content_items[m_selected_content_item_index].Update(true); } //--- Запомним индекс для текущего и изменим цвет m_selected_content_item_index=li; m_content_items[li].IsPressed(true); m_content_items[li].Update(true); } v++; } } //--- Отправить сообщение о выборе новой директории в древовидном списке ::EventChartCustom(m_chart_id,ON_CHANGE_TREE_PATH,0,0,""); return(true); } //+------------------------------------------------------------------+ //| Формирует массив пунктов-вкладок | //+------------------------------------------------------------------+ void CTreeView::GenerateTabItemsArray(void) { //--- Выйти, если режим пунктов-вкладок отключен if(!m_tab_items_mode) return; //--- Добавим в массив пунктов-вкладок только пустые пункты int items_total=::ArraySize(m_items); for(int i=0; i0) continue; //--- Увеличим размер массива пунктов-вкладок на один элемент int array_size=::ArraySize(m_tab_items); ::ArrayResize(m_tab_items,array_size+1); //--- Сохраним общий индекс пункта m_tab_items[array_size].list_index=i; } //--- Если отключен показ содержания пунктов if(!m_show_item_content) { //--- Получим размер массива пунктов-вкладок int tab_items_total=::ArraySize(m_tab_items); //--- Скорректируем индекс, если выход из диапазона if(m_selected_item_index>=tab_items_total) m_selected_item_index=tab_items_total-1; //--- Индекс выделенной вкладки int tab_index=m_tab_items[m_selected_item_index].list_index; m_selected_item_index=tab_index; m_items[tab_index].IsPressed(true); m_items[tab_index].Update(); } } //+------------------------------------------------------------------+ //| Определение и установка границ узлов | //+------------------------------------------------------------------+ void CTreeView::SetNodeLevelBoundaries(void) { //--- Определим минимальный и максимальный уровень узлов m_min_node_level =m_t_node_level[::ArrayMinimum(m_t_node_level)]; m_max_node_level =m_t_node_level[::ArrayMaximum(m_t_node_level)]; } //+------------------------------------------------------------------+ //| Определение и установка размера корневого каталога | //+------------------------------------------------------------------+ void CTreeView::SetRootItemsTotal(void) { //--- Определим количество пунктов в корневом каталоге int items_total=::ArraySize(m_items); for(int i=0; i=0 && v0)? y+m_item_y_size : y; //--- Получим общий индекс пункта древовидного списка int li=m_td_list_index[v]; //--- Установить координаты и ширину m_items[li].UpdateX(x); m_items[li].UpdateY(y); //--- Показать пункт m_items[li].Show(); v++; } } //--- Перерисовать полосу прокрутки if(m_scrollv.IsScroll()) m_scrollv.Show(); } //+------------------------------------------------------------------+ //| Сдвигает список содержания относительно полосы прокрутки | //+------------------------------------------------------------------+ void CTreeView::ShiftContentList(void) { //--- Выйти, если (1) содержание пункта не нужно показывать или (2) элемент скрыт if(!m_show_item_content || !CElementBase::IsVisible()) return; //--- Скрыть все пункты в списке содержания m_content_items_total=ContentItemsTotal(); for(int i=0; im_visible_items_total; //--- Расчёт ширины пунктов списка int w=(is_scroll)? m_x_size-m_treeview_width-m_content_scrollv.ScrollWidth()-2 : m_x_size-m_treeview_width-2; //--- Определение позиции скролла int v=(is_scroll)? m_content_scrollv.CurrentPos() : 0; m_content_scrollv.CurrentPos(v); //--- Координата X int x=m_treeview_width+1; //--- Координата Y первого пункта древовидного списка int y=1; //--- for(int r=0; r=0 && v0)? y+m_item_y_size : y; //--- Получим общий индекс пункта древовидного списка int li=m_cd_list_index[v]; //--- Установить координаты и ширину m_content_items[li].UpdateX(x); m_content_items[li].UpdateY(y); //--- Показать пункт m_content_items[li].Show(); v++; } } //--- Перерисовать полосу прокрутки if(is_scroll) m_content_scrollv.Show(); } //+------------------------------------------------------------------+ //| Ускоренная перемотка списков | //+------------------------------------------------------------------+ void CTreeView::FastSwitching(void) { //--- Определение фокуса на одной из кнопок полос прокрутки bool spin_buttons_focus=m_scrollv.GetIncButtonPointer().MouseFocus() || m_scrollv.GetDecButtonPointer().MouseFocus() || m_content_scrollv.GetIncButtonPointer().MouseFocus() || m_content_scrollv.GetDecButtonPointer().MouseFocus(); //--- Выйти, если (1) вне области элемента или (2) активирован режим изменения ширины области содержания if((!CElementBase::MouseFocus() && !spin_buttons_focus) || m_x_resize.State()) { //--- Отправим сообщение об изменении в графическом интерфейсе if(m_timer_counter!=SPIN_DELAY_MSC) ::EventChartCustom(m_chart_id,ON_CHANGE_GUI,CElementBase::Id(),0,""); //--- Вернём счётчик к первоначальному значению m_timer_counter=SPIN_DELAY_MSC; return; } //--- Если кнопка мыши отжата if(!m_mouse.LeftButtonState()) { //--- Отправим сообщение об изменении в графическом интерфейсе if(m_timer_counter!=SPIN_DELAY_MSC) ::EventChartCustom(m_chart_id,ON_CHANGE_GUI,CElementBase::Id(),0,""); //--- Вернём счётчик к первоначальному значению m_timer_counter=SPIN_DELAY_MSC; } //--- Если же кнопка мыши нажата else { //--- Выйти, если ни одна кнопка не зажата if(!spin_buttons_focus) return; //--- Увеличим счётчик на установленный интервал 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) { //--- Обновить список ShiftTreeList(); m_scrollv.Update(true); return; } //--- Выйти, если область содержания отключена if(!m_show_item_content) return; //--- Если прокрутка вверх if(m_content_scrollv.GetIncButtonPointer().MouseFocus()) { m_content_scrollv.OnClickScrollInc((uint)Id(),2); scroll_v=true; } //--- Если прокрутка вниз else if(m_content_scrollv.GetDecButtonPointer().MouseFocus()) { m_content_scrollv.OnClickScrollDec((uint)Id(),3); scroll_v=true; } //--- Если кнопка нажата if(scroll_v) { //--- Обновить список ShiftContentList(); m_content_scrollv.Update(true); } } } //+------------------------------------------------------------------+ //| Управляет шириной списков | //+------------------------------------------------------------------+ void CTreeView::ResizeListArea(void) { //--- Выйти, (1) если ширину области содержания не нужно изменять или // (2) включен режим пунктов-вкладок или (3) полоса прокрутки активна if(!m_resize_list_mode || !m_show_item_content || m_tab_items_mode || m_scrollv.State()) return; //--- Координаты int x =m_mouse.RelativeX(m_canvas); int y =m_mouse.RelativeY(m_canvas); //--- Проверка готовности для изменения ширины списков CheckXResizePointer(x,y); //--- Выйти, если курсор отключен if(!m_x_resize.State()) return; //--- Проверка на выход за установленные ограничения if(!CheckOutOfArea(x,y)) return; //--- Установим X-координату объекту по центру курсора мыши m_x_resize.UpdateX(m_mouse.X()); //--- Y-координату устанавливаем, только если не вышли за область элемента if(y>0 && y0 && ym_treeview_width && xm_x_size-area_limit) { // ... перемещаем указатель только по вертикали, не выходя за границы if(y>0 && y=0 && v=0 && vm_min_node_level && m_t_prev_node_list_index[i]!=l_prev_node_list_index[nl]) continue; //--- Запомним локальный индекс пункта, если следующий будет не меньше размера локального списка if(m_t_item_index[i]+1>=l_items_total[nl]) ii=m_t_item_index[i]; //--- Если список текущего пункта развёрнут if(m_t_item_state[i]) { //--- Добавим пункт в массив отображаемых пунктов в древовидном списке AddDisplayedTreeItem(i); //--- Запомним текущие значения и перейдём к следующему узлу int n=nl+1; l_prev_node_list_index[n] =m_t_list_index[i]; l_item_index[nl] =m_t_item_index[i]; l_items_total[n] =m_t_items_total[i]; l_folders_total[n] =m_t_folders_total[i]; //--- Обнулим счётчик локальных индексов пунктов ii=0; //--- Перейдём к следующему узлу break; } //--- Добавим пункт в массив отображаемых пунктов в древовидном списке AddDisplayedTreeItem(i); //--- Увеличим счётчик локальных индексов пунктов ii++; //--- Если дошли до последнего пункта в корневом каталоге if(nl==m_min_node_level && ii>=m_root_items_total) { //--- Установим флаг и завершим текущий цикл end_list=true; break; } //--- Если до последнего пункта в корневом каталоге ещё не дошли else if(nl>m_min_node_level) { //--- Получим количество пунктов в текущем узле int total=(m_file_navigator_mode==FN_ONLY_FOLDERS)? l_folders_total[nl]: l_items_total[nl]; //--- Если это не последний локальный индекс пункта, перейдём к следующему if(ii=l_items_total[nl-1]) { if(nl-1==m_min_node_level) break; //--- nl--; continue; } //--- break; } //--- Перейдём на предыдущий узел nl=nl-2; //--- Обнулим счётчик локальных индексов пунктов и перейдём к следующему узлу ii=0; break; } } } //--- Перерисовка списка RedrawTreeList(); } //+------------------------------------------------------------------+ //| Формирует список содержания | //+------------------------------------------------------------------+ void CTreeView::FormContentList(void) { //--- Индекс выделенного пункта int li=m_selected_item_index; //--- Освободим массивы списка содержания ::ArrayFree(m_cd_item_text); ::ArrayFree(m_cd_list_index); ::ArrayFree(m_cd_tree_list_index); //--- Сформируем список содержания int items_total=::ArraySize(m_items); for(int i=0; i0) { //--- Счётчик пунктов int c=0; //--- Пройдёмся по списку int c_items_total=::ArraySize(m_c_list_index); for(int i=0; i=cd_items_total) break; } } } //--- Перерисовка списка RedrawContentList(); } //+------------------------------------------------------------------+ //| Перерисовка списка | //+------------------------------------------------------------------+ void CTreeView::RedrawTreeList(void) { //--- Скрыть пункты списка int items_total=::ArraySize(m_items); for(int i=0; i0)? y+m_item_y_size : y; //--- Получим общий индекс пункта в списке int li=m_td_list_index[i]; //--- Обновим координаты и размер m_items[li].UpdateY(y); m_items[li].UpdateWidth(w); } //--- Показать пункты списка for(int i=0; i0)? y+m_item_y_size : y; //--- Получим общий индекс пункта в списке int li=m_cd_list_index[i]; //--- Обновим координаты и размер m_content_items[li].UpdateY(y); m_content_items[li].UpdateWidth(w); } //--- Если элемент не скрыт, показать пункты списка if(CElementBase::IsVisible()) { for(int i=0; i=array_size) { //--- Будет выделен первый пункт в списке m_selected_item_index=0; return; } } //+------------------------------------------------------------------+ //| Рисует границу между областями | //+------------------------------------------------------------------+ void CTreeView::DrawResizeBorder(void) { //--- Выйти, если режим отключен if(!m_show_item_content) return; //--- Координаты int x=m_treeview_width; int y1=0,y2=m_y_size; //--- Нарисовать линию m_canvas.LineVertical(x,y1,y2,::ColorToARGB(m_border_color)); } //+------------------------------------------------------------------+ //| Изменить ширину по правому краю формы | //+------------------------------------------------------------------+ void CTreeView::ChangeWidthByRightWindowSide(void) { //--- Выйти, если включен режим фиксации к правому краю формы if(m_anchor_right_window_side) return; //--- Координаты и ширина int x=0,w=0; //--- Размеры int x_size =m_main.X2()-CElementBase::X()-m_auto_xresize_right_offset; int y_size =(m_auto_yresize_mode)? m_main.Y2()-CElementBase::Y()-m_auto_yresize_bottom_offset : m_y_size; //--- Установить новый размер CElementBase::XSize(x_size); m_canvas.XSize(x_size); m_canvas.Resize(x_size,y_size); //--- Если без списка содержания if(!m_show_item_content) { //--- Рассчитаем и установим ширину для пунктов в списке w=(m_scrollv.IsScroll())? CElementBase::XSize()-m_scrollv.ScrollWidth()-3 : CElementBase::XSize()-2; //--- int v=(m_scrollv.IsScroll())? m_scrollv.CurrentPos() : 0; //--- Получим количество отображаемых пунктов в списке содержания int total=::ArraySize(m_td_list_index); for(int r=0; r=0 && v=0 && v