FreeBASIC в России

   

 Главная   Исходники   Русскоязычный форум   Полезные файлы   Пользователи   Поиск

 

 FB Wiki   Уроки   Скачать FreeBASIC   Проекты   Ссылки   Загрузить   Каталог ссылок

 
 

 Замечания и предложения по работе сайта оставляйте здесь.

Сейчас на сайте:

Вы вошли как: Guest   Регистрация   

Логин:     Пароль:     

Создай бесплатно WebMoney кошелёк на своём мобильном всего за 5 минут

 

Делаем dll своими руками

Хэндл окна

Графические средства языка

Точка пересечения отрезков

Окна без рамки

Физика поведения ядра

Win32 API Введение

►Урок 1 Win32 API

►Урок 2 Win32 API

►Урок 3 Win32 API

►Урок 4 Win32 API

►Урок 5 Win32 API

►Урок 6 Win32 API

►Урок 7 Win32 API

►Урок 8 Win32 API

►Урок 9 Win32 API

►Урок 10 Win32 API

►Урок 11 Win32 API

►Урок 12 Win32 API

►Урок 13 Win32 API

►Урок 14 Win32 API

►Урок 15 Win32 API

►Урок 16 Win32 API

►Урок 17 Win32 API

►Урок 18 Win32 API

►Урок 19 Win32 API

►Урок 20 Win32 API

►Урок 21 Win32 API

►Урок 22 Win32 API

►Урок 23 Win32 API

►Урок 24 Win32 API

Ассоциация файлов

Определить OS

Выводит имя компьютера

 

 

 

Win32 API. Урок 19. Tree View Control.

Опытом поделился и оптимизировал под FreeBASIC:   15.01.2011

 

Реклама:

Продажа готовых московских фирм. Услуги регистрация, продажа готовых фирм, финансовый контроль.;Курсы валютного кассира с трудоустройством.;В салон красоты - со скидкой - каре стрижки обучение. Специалист по субсидиям.

В этом туториале мы изучим как использовать контрол tree view. Более того, мы также узнаем как реализовать drag and drop для этого контрола и как использовать image list.

Теория:

Контрол tree view - это особый вид окна, который представляет объекты в иерархическом порядке. В качестве примера может служить левая панель Windows Explorer'а. Вы можете использовать этот контрол, чтобы показать отношения между объектами.

Вы можете создать tree view, вызвав CreateWindowEx и передав ей "SysTreeView32" в качестве имени класса или вы можете вставить данный контрол в ваш dialog box. Не забудте поместить вызов InitCommonControls в ваш код.

Есть несколько стилей присущих только tree view. Вот наиболее часто используемые:

• TVS_HASBUTTONS - отображает кнопки плюс (+) и минус (-) перед родительским пунктом. Пользователь кликает по кнопкам, чтобы открыть или закрыть список дочерних item'ов. Чтобы вставить кнопки с пунктами в корень tree view, также должен быть указан TVS_LINESATROOT.

• TVS_HASLINES - используются линии для показа иерархии пунктов.

• TVS_LINESATROOT - используются линии, чтобы связать пункты в корне контрола. Этот стиль игнорируется, если не указан TVS_HASLINES.

Tree view, как и любой другой common control, взаимодействует с родительским окном с помощью сообщений. Родительское окно может посылать различные сообщения tree view, а тот может посылать "уведомительные" сообщения своему родительскому окну. В этом отношении tree view ничем не отличается от других окон.

Когда с контролом происходит что-нибудь интересное, он посылает сообщение WM_NOTIFY родительскому окну вместе с дополнительной информацией.

• wparam - ID контрола, но то, что оно будет уникальным не гарантируется, поэтому не используйте его. Вместо этого мы будем использовать hwndFrom или IDFrom из структуры NMHDR, на которую указывает lparam.
• lparam - указатель на структуру NMHDR. Некоторые контролы могут передавать указатель на большую структуру, но они должны иметь в качестве первого поля структуру NMHDR. Поэтому вы можете быть уверены, что lparam по крайней мере указывает на NMHDR.

Затем мы проанализируем структуру NMHDR.

type NMHDR
hwndFrom as HWND
idFrom as UINT
code as UINT
end type

hwndFrom - это хэндл окна контрола, который послал это сообщение.

idFrom - это ID этого контрола.

code - это настоящее сообщение, которое контрол хотел послать родительскому окну.

Уведомления от tree view начинаются с префикса TVN_.

Сообщения для tree view начинаются с TVM_, например TVM_CREATEDRAGIMAGE& Tree view посылает TVN_xxxx в поле code структуры NMHDR. родительское окно может посылать TVM_xxxx контролу.

Добавление пунктов в tree view

После того, как вы создадите контрол tree view, вы можете добавить в него пункты. Вы можете сделать это, послав контролу TVM_INSERTITEM.

TVM_INSERTITEM

• wparam = 0;
• lparam = pointer to a TV_INSERTSTRUCT;

Вам следует знать кое-какую терминологию, касающуюся взаимоотношений между item'ами в tree view.

Item может быть родительским, дочерним или тем и другим одновременно. родительский item - это такой item, с которым ассоциированы под-item'ы. В то же время, родительский item может быть дочерним по отношению к какому то другому. Item, у которого нет родителя, называется корнем (root). В tree view может быть много корневых элементов. Теперь мы проанализируем структуру TV_INSERTSTRUCT.

type TV_INSERTSTRUCT
hParent as HTREEITEM
hInsertAfter as HTREEITEM
union
itemex as TVITEMEX
item as TVITEM
end union
end type

hParent - хэндл родительского item'а. Если этот параметр равен TVI_ROOT или NULL, тогда item вставляется в корень tree view.

hInsertAfter - хэндл item'а, после которого будет вставляться новый item, или одно из следующих значений:

TVI_ROOT - вставка элемента в корень
• TVI_FIRST - вставка элемента в начало списка.
• TVI_LAST - вставка элемента в конец списка.
• TVI_SORT - вставка элемента в список согласно алфавитному порядку.

union
itemex as TVITEMEX
item as TVITEM
end union

Мы будем использовать только TVITEM.

type TV_ITEM
mask as UINT
hItem as HTREEITEM
state as UINT
stateMask as UINT
pszText as LPSTR
cchTextMax as integer
iImage as integer
iSelectedImage as integer
cChildren as integer
lParam as LPARAM
end type

Эта структура используется для отсылки и получения информации об элементе tree view (в зависимости от сообщений). Например, с помощью TVM_INSERTITEM, она используется для указания атрибутов item'а, который должен быть вставлен в tree view. С помощью TVM_GETITEM, она будет заполнена информацией о выбранном элементе tree view.

imask используется для указания, какой член структуры TV_ITEM верен. Например, если значение в imask равно TVIF_TEXT, оно означает, что только pszText верно. Вы можете комбинировать несколько флагов вместе.

hItem - это хэндл элемента tree view. Каждый item имеет хэндл, как и в случае с окнами. Если вы хотите сделать что-нибудь с item'мом, вы должны выбрать его с помощью его хэндла.

pszText - это указатель на строку, оканчивающуюся NULL'ом, которая является названием элемента tree view.

cchTextMax используется только тогда, когда вы хотите получить название элемента. Windows надо будет знать размер предоставленного вами буфера (pszText), поэтому этот элемент используется именно для этого.

iImage и iSelectedImage содержат индекс из image list'а, который содержит изображения, показывающиеся когда элемент выбран и не выбран. Если вспомните левую панель Windows Explorer'а, то изображения директорий задаются именно этими двумя параметрами.

Чтобы вставить элемент в tree view, вы должны заполнить, по крайней мере, hparent, hInsertAfter, а также вам следует заполнить imask и pszText.

Добавление изображений в tree view

Если вы хотите поместить изображение слева от названия элемента, вам следует создать image list и ассоциировать его с контролом tree view.

function ImageList_Create _
(byval cx as integer, _
byval cy as integer, _
byval flags as UINT, _
byval cInitial as integer, _
byval cGrow as integer) as HIMAGELIST

Если вызов пройдет успешно, функция возвратит хэндл на пустой image list.

cx - ширина любого изображения в этом image list'е в пикселях.

cy - высота любого изображения в этом image list'е в пикселях. Все изображения в image list'е должны быть равны друг другу по размеру. Если вы укажете больший bitmap, Windows разрежет его на несколько кусков согласно значению в cx и cy. Поэтому вам следует тщательно подготовить необходимые изображения.

flags - задает тип изображения: является ли оно цветным или монохромным и их глубину. Проконсультируйтесь с вашим справочником по Win32 API.

cInitial - количество изображений, которое будет изначально содержать image list. Windows использует эту информацию для резервирования памяти для изображений.

cGrow - количество изображений, на которое должен увеличиваться image list, когда системе необходимо изменить размер списка, чтобы выделить место для новых изображений. Этот параметр представляет количество новых изображений, которое может содержать image list, изменивший размер.

Image list - это не окно! Это только хранилище изображений, которые будут использоваться другими окнами.

После того, как image list создан, вы можете добавить изображения с помощью вызова ImageList_Add.

function ImageList_Add _
(byval himl as HIMAGELIST, _
byval hbmImage as HBITMAP, _
byval hbmMask as HBITMAP) as integer

Если во время вызова произойдет какая-либо ошибка, будет возвращен -1.

himl - хэндл image list'а, в который вы хотите добавить изображения. Это значение возвращается ImageList_Create.

hbmImage - хэндл битмапа, который должен быть добавлен в image list. Обычно изображения задаются в ресурсах и вызываются с помощью LoadBitmap.

Заметьте, что вам не надо указывать количество изображений, содержащихся в этом bitmap'е, потому что это вытекает из параметров cx и cy, переданных ImageList_Create.

hbmMask - хэндл битмапа, в котором содержится маска. Если маска в image list'е не используется, этот параметр игнорируется.

Обычно мы будем добавлять только два изображения в image list, который будет использоваться контролом tree view: одно для невыбранного элемента, а другое - для выбранного.

Когда image list готов, мы ассоциируем его с tree view, посылая тому сообщение TVM_SETIMAGELIST:

• wparam - тип image list'а. Есть две возможности:

• TMSIL_NORMAL - задает обычный image list, который содержит изображения выбранного и невыбранного элементов.
• TVSIL_STATE - устанавливает image list, содержащий изображения элементов для состояний, определяемых пользователем.

• lparam - хэндл image list'а.

Получение информации о элементе tree view

Вы можете получить информацию об элементе tree view, послав ей сообщение TVM_GETITEM:

• wparam = 0
• lparam = pointer to the TV_ITEM structure to be filled with the information

Прежде, чем вы пошлете это сообщение, вы должны заполнить параметр imask флагами, которые укажут, какие из полей TV_ITEM должны быть заполнены Windows.
А самое главное, вы должны заполнить hItem хэндлом элемента, о котором вы хотите получить информацию. И это порождает следующую проблему: где взять этот хэндл? Надо ли вам сохранять все хэндлы tree view?

Ответ достаточно прост: вам не надо этого делать. Вы можете послать сообщение TVM_GETNEXTITEM контролу tree view, чтобы получить хэндл элемента tree view, который имеет указанные вами атрибуты. Например, вы можете получить хэндл первого дочернего элемента, корневого элемента, выбранного элемента и так далее.

TVM_GETNEXTITEM:

• wparam = флаг
• lparam - хэндл на элемент tree view (не всегда необходим)

Значение wparam очень важно, поэтому я привожу ниже все возможные флаги:

• TVGN_CARET - получение хэндла выбранного элемента.
• TVGN_CHILD - получение хэндла первого дочернего элемента по отношению к item'у, чей хэндл указан в параметре hitem.
• TVGN_DROрHILITE - получение хэндла item'а, который является целью операции drag-and-drop.
• TVGN_FIRSTVISIBLE - получение хэндла первого видимого item'а.
• TVGN_NEXT - получение хэндла следующего родственного элемента.
• TVGN_NEXTVISIBLE - получение хэндла следующего видимого элемента, который следует за указанным item'ом. Указанный элемент должен быть видимым. Используйте сообщение TVM_GETITEMRECT, чтобы определить, является ли item видимым.
• TVGN_PARENT - получение хэндла указанного родительского элемента по отношению к указанному.
• TVGN_PREVIOUS - получение хэндла предыдущего родственного элемента.
• TVGN_PREVIOUSVISIBLE - получение хэндла первого видимого элемента, который предшествует указанному item'у, который должен быть видимым. Используйте сообщение TVM_GETITEMRECT, чтобы определить, является ли item видимым.
• TVGN_ROOT - получает хэндл самого первого из корневых элементов tree view.

Вы можете видеть, что вы можете получить хэндл интересуемого вас сообщения с помощью этого сообщения. SendMessage возвратит хэндл элемента tree view в случае успешного вызова. Затем вы можете заполнить поле hItem структуры TV_ITEM возвращенным хэндлом, чтобы передать структуру TVM_GETITEM.

Операции Drag-and-Drop над контролом tree view

Именно из-за этой части я написал этот туториал. Когда я попытался следовать примеру из справочника по Win32 API (win32.hlp от Inprise), я был сильно обескуражен отсутствием жизненно важной информации. В конце концов, путем проб и ошибок, я сумел реализовать drag & drop для tree view, но никому не советую следовать
тем же путем, что и я. Ниже изложены правильные действия.

Когда пользователь пытается перетащить элемент, tree view посылает уведомление TVN_BEGINDRAG родительскому окну. Вы можете использовать эту возможность для создания специального изображения, которое будет представлять элемент, когда его тащат. Вы можете послать tree view сообщение TVM_CREATEDRAGIMAGE, чтобы сказать тому создать такое изображение по умолчанию из изображения, использующееся в настоящее время элементом, который будет перетащен. Tree view создаст image list с одним drag-изображением и возвратит вам. хэндл этого image list'а

После того, как drag-изображение создано, вы указываете его "горячую точку", вызывая ImageList_BeginDrag.

function ImageList_BeginDrag _
(byval himlTrack as HIMAGELIST, _
byval iTrack as integer, _
byval dxHotspot as integer, _
byval dyHotspot as integer) as BOOL

• himlTrack - это хэндл image list'а, который содержит drag-изображение.
• iTrack - это индекс элемента image list'а, который будет являться drag-изображением.
• dxHotspot указывает относительную горизонтальную координату "горячей точки" (которая нам необходима, так как мы будем использовать drag-изображение вместо курсора мыши. У стандартного курсора "горячая точка" находится на кончике стрелки).
• dyHotspot указывает относительную вертикальную координату "горячей точки".
• Как правило, iTrack будет равен 0, если вам нужно сказать tree view, чтобы тот создал для вас drag-изображение. dxHotspot и dyHotspot могут быть равными 0, если вы хотите, чтобы левый верхний угол drag-изображения был "горячей точкой".

Когда drag-изображение готово, мы вызываем ImageList_DragEnter, чтобы отобразить его в окне.

function ImageList_DragEnter _
(byval hwndLock as HWND, _
byval x as integer, _
byval y as integer) as BOOL

hwndLock - это хэндл окна, которому принадлежит drag-изображение. Drag-изображение нельзя будет двигать за пределы этого окна.

x и y - это x- и y-координата места, где drag-изображение должно быть отображено сначала. Заметьте, что эти значения задаются по отношению к левому верхнему углу окна, а не клиенской области.

Теперь, когда drag-изображение отображено в окне, вам следует поддерживать операцию перетаскивания в контроле tree view. Тем не менее, здесь появляется небольшая проблема. Мы должны отслеживать путь перетаскивания с помощью WM_MOUSEMOVE и позицию сброса (drop) с помощью WM_LBUTTONUp. Однако, если drag-изображение находится над каким-нибудь дочерним окном, родительское окно никогда не получит никаких сообщений от мыши. решение состоит в том, чтобы взять контроль над сообщениями от мыши с помощью SetCapture. Эта функция позволяет направить мышиные сообщения напрямую определенному окну, вне зависимости от того, где находится курсор мыши.

Внутри обработчика WM_MOUSEMOVE, вы будете отслеживать drag-путь с помощью вызова ImageList_DragMove. Эта функция передвигает изображение относительно пути переноса. Более того, если вы захотите, вы можете подсвечивать элемент, над которым находится drag-изображение, посылая сообщение TVM_HITTEST, проверяя, находится ли изображение над каким-нибудь элементом. Если это так, вы можете послать TVM_SELECTITEM с флагом TVGN_DROPHILITE, чтобы подсветить элемент.
Заметьте, что прежде, чем послать сообщение TVM_SELECTITEM, вы должны спрятать drag-изображение или оно будет оставлять уродливый след. Это можно сделать, вызвав ImageList_DragShowNolock, а после того, как элемент будет подсвечен, необходимо вызвать ImageList_DragShowNolock, чтобы снова отобразить drag-изображение.

Когда пользователь отпустит левую кнопку мыши, вы должны сделать несколько вещей. Если вы подсветили элемент, вам нужно перевести его в обычное состояние, снова послав TVM_SELECTITEM с флагом TVGN_DROPHILITE, но в этот раз lparam должен быть равен нулю. Затем вы должны вызвать ImageList_DragLeave, за которым должен следовать вызов ImageList_EndDrag. Вы должны освободить мышь с помощью ReleaseCapture. Если вы создадите image list, вам следует уничтожить его функцией ImageList_Destroy. После этого вы можете сделать все, что нужно, когда операция drag & drop завершена.

Пример:

файл tree.bas

Скопировать данный код в буфер обмена

Анализ:

Внутри обработчика WM_CREATE вы создаете контрол tree view.

hwndTreeView = CreateWindowEx _
(NULL, _
TreeViewClass, _
NULL, _
WS_CHILD+WS_VISIBLE+TVS_HASLINES+TVS_HASBUTTONS+TVS_LINESATROOT, _
0, _
0, _
200, _
400, _
hWnd, _
NULL, _
hModule, _
NULL)

Обратите внимание на стили. TVS_xxxx - это стили, присущие tree view.

hImageList = ImageList_Create _
(16, _
16, _
ILC_COLOR16, _
2, _
10)
hBitmap = LoadBitmap _ ' загрузим Bitmap(hModule, _ ' хэндл программы
cptr(LPCSTR,IDB_TREE))
ImageList_Add _
(hImageList, _
hBitmap, _
NULL)
DeleteObject _
(hBitmap)
SendMessage _
(hwndTreeView, _
TVM_SETIMAGELIST, _
0, _
cptr(LPARAM,hImageList))

Затем вы создаете пустой image list, который будет принимать изображения размером 16x16 пикселей и с глубиной цвета 16 бит. Вначале он будет содержать 2 изображения, но будет расширен до 10, если это потребуется. Далее мы загружаем bitmap из ресурса и добавляем его в только что созданный image list. После этого мы удаляем хэндл битмапа, так как он больше нам не нужен. Как только image list готов, мы ассоциируем его с tree view, посылая ему TVM_SETIMAGELIST.

tvinsert.hparent = NULL
tvinsert.hInsertAfter = TVI_ROOT
tvinsert.item.mask = TVIF_TEXT+TVIF_IMAGE+TVIF_SELECTEDIMAGE
tvinsert.item.pszText = @parent
tvinsert.item.iImage = 0
tvinsert.item.iSelectedImage = 1
hParent = SendMessage _
(hwndTreeView, _
TVM_INSERTITEM, _
0, _
cPtr(LPARAM,@tvinsert))

Мы вставляем элементы в контрол tree view, начиная с корневого элемента. Так как это будет корневой item, параметр hparent равен NULL, а hInsertAfter - TVI_ROOT. mask указывает, что pszText, iImage и iSelectedImage структуры TV_ITEM верны. Мы заполняем эти три параметра соответствующими значениями. pszText содержит название корневого элемента, iImage - это индекс изображения в image list'е, который будет отображаться слева от невыбранного элемента, а iSelectedImage - индекс изображения выбранного элемента. Когда все требуемые параметры заполнены, мы посылаем сообщение TVM_INSERTITEM контролу tree view, чтобы добавить в него корневой элемент.

tvinsert.hparent = cPtr(HTREEITEM,hParent)
tvinsert.hInsertAfter = TVI_LAST
tvinsert.item.pszText = @Child1
SendMessage _
(hwndTreeView, _
TVM_INSERTITEM, _
0, _
cPtr(LPARAM,@tvinsert))
tvinsert.item.pszText = @Child2
SendMessage _
(hwndTreeView, _
TVM_INSERTITEM, _
0, _
cptr(LPARAM,@tvinsert))

После этого мы добавляем дочерние элементы. hparent теперь заполнен хэндлом родительского элемента. Мы будем использовать те же изображения, поэтому не меняем iImage и iSelectedImage.

case WM_NOTIFY
scope
dim tw as NM_TREEVIEW ptr
tw = cPtr(NM_TREEVIEW ptr,lparam)
if tw->hdr.code = TVN_BEGINDRAG then
hDragImageList = SendMessage _
(hwndTreeView, _ ' хэндл Tree View
TVM_CREATEDRAGIMAGE, _ '
0, _
cPtr(LPARAM,tw->itemNew.hItem))
ImageList_BeginDrag _
(cPtr(HIMAGELIST,hDragImageList), _
0,0,0)
ImageList_DragEnter _
(hwndTreeView, _
tw->ptDrag.x, _
tw->ptDrag.y)
SetCapture(hWnd)
DragMode = TRUE
end if
end scope

Теперь, когда юзер попытается перетащить item, tree view пошлет сообщение WM_NOTIFY с кодом TVN_BEGINDRAG. lparam - это указатель на структуру NM_TREEVIEW, которая содержит некоторую информацию, которая необходима нам, поэтому мы помещаем значение lparam в tw и используем tw как указатель на структуру NM_TREEVIEW.
Затем мы создаем drag-изображение, посылая TVM_CREATEDRAGIMAGE tree view. Сообщение возвращает хэндл на созданный image list, внутри которого содержится drag-изображение. Мы вызываем ImageList_BeginDrag, чтобы установить его "горячую точку". После этого начинаем операцию переноса с помощью ImageList_DragEnter. Эта функция отображает drag-изображение в указанном месте заданного окна.

Мы используем структуру ptDrag, которая является членом структуры NM_TREEVIEW в качестве точки, в которой должно быть показано drag-изображение. Затем перехватываем мышь и устанавливаем флаг, который показывает, что мы находимся в drag-режиме.

case WM_MOUSEMOVE
if DragMode = TRUE then
tvhit.pt.x = loword(lparam)
tvhit.pt.y = hiword(lparam)
ImageList_DragMove(loword(lparam),hiword(lparam))
ImageList_DragShowNolock (FALSE)
scope
dim ht as LRESULT
ht = SendMessage _
(hwndTreeView, _
TVM_HITTEST, _
NULL, _
cptr(LPARAM,@tvhit))
if ht <> NULL then
SendMessage _
(hwndTreeView, _
TVM_SELECTITEM, _
TVGN_DROPHILITE, _
cptr(LPARAM,ht))
end if
end scope
ImageList_DragShowNolock (TRUE)
end if

Теперь мы концентрируемся на WM_MOUSEMOVE. Когда пользователь перетаскивает drag-изображение, наше родительское окно получает сообщения WM_MOUSEMOVE. В ответ на них мы обновляем позицию drag-изображения функцией ImageList_DragMove, после чего проверяем, не находится ли оно над каким-нибудь элементом с помощью сообщения TVM_HITTEST с указанием координаты проверяемой точки. Если drag-изображение находится над каким-либо элементом, тот подсвечивается сообщением TVM_SELECTITEM с флагом TVGN_DROPHILITE. Во время операции подсветки мы прячем drag-изображение, чтобы не было лишних глюков.

case WM_LBUTTONUP
if DragMode = TRUE then
ImageList_DragLeave _
(hwndTreeView)
ImageList_EndDrag()
ImageList_Destroy _
(cPtr(HIMAGELIST,hDragImageList))
scope
dim dd as LRESULT
dd = SendMessage _
(hwndTreeView, _
TVM_GETNEXTITEM, _ '
TVGN_DROPHILITE, _
0)
SendMessage _
(hwndTreeView, _
TVM_SELECTITEM, _
TVGN_CARET, _
dd)
SendMessage _
(hwndTreeView, _
TVM_SELECTITEM, _
TVGN_DROPHILITE, _
0)
ReleaseCapture()
DragMode = FALSE
end scope
end if

Когда пользователь отпускает левую кнопку мыши, операция переноса закончена. Мы выходим из drag-режима, последовательно вызывая функции ImageList_DragLeave, ImageList_EndDrag и ImageList_Destroy. Также мы проверяем последний подсвеченный элемент и выбираем его. Мы также должны убрать его подсветку, иначе другие элементы не будут подсвечиваться, когда их будут выбирать. И наконец, мы убираем перехват сообщений от мыши.

[C] Iczelion, пер. Aquila.

 

 

Прокомментировать

Ваше имя:  

Ваш e-mail:  

Сообщение:



Введите код: 

 

 

   Спасибо можно сказать, посетив любую ссылку:

 

 

© 2010-2012

DEPOzit (Попов Денис Владимирович)

WebMoney кошелёк: WMID#302963000004

ICQ:279786014 или R549103331586   Z116647355686