Что нового

GUICtrlOnHover - Обработка событии при наведении мышки

Автор
CreatoR

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
Обновление библиотеки...

Список изменении:
[v1.9] - [21.05.2010]
* Библиотека теперь совместима с AutoIt 3.3.6.1.
* Библиотека переименована в GUICtrlOnHover.au3.
* Изменено название главной функции на _GUICtrl_OnHoverRegister, из соображении обратной совместимости, старые имена функции по прежнему поддерживаются:
Код:
   _GUICtrl_SetOnHover, GUICtrl_SetOnHover, GUICtrlSetOnHover, _GUICtrlSetOnHover
* Исправлена(?) проблема связанная с работой библиотеки на 64-битной ОС.
* Переименование глобальных переменных и внутренних функции (исключительно из "косметических" соображении).
* Оптимизирован код библиотеки для более удобного чтения.
 

kzru_hunter

Осваивающий
Сообщения
144
Репутация
49
Заметил баг в примере Letters Hovering Example.au3: если навести курсор на какую-нибудь букву и потом нажать esc, то скрипт зависает. Если закоментировать _GUICtrl_OnHoverRegister, то такого не происходит.
 
Автор
CreatoR

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
kzru_hunter [?]
Если закоментировать _GUICtrl_OnHoverRegister, то такого не происходит
Так и пример тогда не работает :smile:
Нужно просто перед Exit добавить GUIDelete(). Спасибо, поправлю.
 

kzru_hunter

Осваивающий
Сообщения
144
Репутация
49
Если добавить GuiDelete() перед Exit, то форма закрывается, но скрипт все ещё продолжает работать и грузит проц на 100%.

Исправить можно, если убрать sleep в главном цикле и использовать задержку другими функциями, например GuiGetMsg().
Но sleep все равно может когда-нибудь понадобится.
 
Автор
CreatoR

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
kzru_hunter [?]
Исправить можно, если убрать sleep в главном цикле
Его можно выставить на 1000, это частично решает проблему, но также желательно в UDF таймер запускать режже чем каждые 10 мс, например каждые 30, но это уже влияет на скорость Hovering'а.


Добавлено:
Сообщение автоматически объединено:

kzru_hunter [?]
Если добавить GuiDelete() перед Exit, то форма закрывается, но скрипт все ещё продолжает работать и грузит проц на 100%.
Этот баг связан с тикетом который я недавно открыл, но разработчики затрудняются его воспроизвести.

Кстатит если установить:
Код:
_GUICtrl_SetHoverOnBackWindow(0)

то скрипт завершается нормально, а значит проблема в __GUICtrl_SOH_ControlGetHovered().
 

kzru_hunter

Осваивающий
Сообщения
144
Репутация
49
CreatoR Ставил любые значения для Sleep, а также менял значение для SetTimer. Всё равно виснет.

CreatoR сказал(а):
Этот баг связан с тикетом который я недавно открыл, но разработчики затрудняются его воспроизвести.
Получалось случайно воспроизвести, но редко.

CreatoR сказал(а):
Кстатит если установить:
_GUICtrl_SetHoverOnBackWindow(0)
то скрипт завершается нормально, а значит проблема в __GUICtrl_SOH_ControlGetHovered().
Тоже нормально завершается, но использовав функцию __GUICtrl_SOH_ControlGetHovered в своём примере, проблема не возникает.

Может это из-за таймера? И почему именно таймер, а не AdlibRegister? :smile:
 
Автор
CreatoR

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
kzru_hunter [?]
почему именно таймер, а не AdlibRegister?
Потому что когда я писал UDF, AdlibRegister ещё не существовал ;) - Надо будет попробовать с ним сделать, хотя это нарушит обратную совместимость.


Добавлено:
Сообщение автоматически объединено:

[?]
Потому что когда я писал UDF, AdlibRegister ещё не существовал
А также потому что функция заданная таймером выполняется даже если скрипт блокирован такой функцией как MsgBox (чтобы убедиться в этом, просто нажми на любую букву в примере, и наводи курсор над буквами после появления MsgBox).
 

kzru_hunter

Осваивающий
Сообщения
144
Репутация
49
CreatoR [?]
А также потому что функция заданная таймером выполняется даже если скрипт блокирован такой функцией как MsgBox (чтобы убедиться в этом, просто нажми на любую букву в примере, и наводи курсор над буквами после появления MsgBox).
Об этом не знал, Спасибо :smile:

Ещё заметил, что такой баг возникает, если быстро нажать и отпустить esc. Если нажать и держать, то не возникает.

Похоже баг в автоите
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
CreatoR сказал(а):
Потому что когда я писал UDF, AdlibRegister ещё не существовал ;) - Надо будет попробовать с ним сделать, хотя это нарушит обратную совместимость.

AdlibRegister() так же тупит, как и AdlibEnable(). И MsgBox(), и контекстное меню, и при перетаскивании окна тормозится. Вряд ли это баг, типо так задумано...
 

kzru_hunter

Осваивающий
Сообщения
144
Репутация
49
Обнаружил ещё кое-что: если в _Leave_Hover_Func добавить MessageBox, то будет печальная ситуация :smile:; если добавить его в _Hover_Func, то перестанет срабатывать _Leave_Hover_Func при появлении messagebox'a.
 
Автор
CreatoR

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481

kzru_hunter

Осваивающий
Сообщения
144
Репутация
49
CreatoR [?]
Да, и об этом написано в шапке UDF.
Такой баг возникал из-за того, что код, который находился после вызова Hover и LeaveHover функций не срабатывал и по новому вызывалась функция таймера, пока висел MsgBox, но уже со старыми значениями переменных. Перед тем вызвать Hover и LeaveHover функцию надо было записать новые значения глобальным переменным.

Вообщем, вот исправленный код (в ветви на линии 329 и рядом с 421 линией ):
Код:
#include-once

#Region Header

#CS UDF Info

	Name.........:      GUICtrlOnHover.au3
	Forum link...:      http://www.autoitscript.com/forum/index.php?s=&showtopic=55120
	Author.......:      G.Sandler a.k.a MrCreatoR (CreatoR's Lab, www.creator-lab.ucoz.ru, www.autoit-script.ru)
	Remarks......:
						1)	TreeView/ListView Items can not be set :(.
						2)	When the window is not active, the hover/leave hover functions will still called, but not when the window is disabled.
						3)	The hover/leave hover functions will be called even if the script is paused by such functions as MsgBox().
						4)	The $sHover_Func/$sLeaveHover_Func functions should not introduce significant delays in the main script,
							for example by calling functions like Sleep() or MsgBox().
						5) IMPORTANT!
							A)	Do not call _GUICtrl_OnHoverRegister inside $sHover_Func/$sLeaveHover_Func functions, it's not a good idea.

							B)	This UDF registering WM_COMMAND and WM_LBUTTONDOWN window messages.
								Please ensure that those messages are not used after including this library,
								if they do, you will have to call __GUICtrl_SOH_WM_COMMAND and __GUICtrl_SOH_WM_LBUTTONDOWN inside those functions. Example:

								Func MY_WM_COMMAND($hWnd, $iMsg, $wParam, $lParam)
									__GUICtrl_SOH_WM_COMMAND($hWnd, $iMsg, $wParam, $lParam)
 									...
								EndFunc


	*** Version History ***

	[v1.9] - [21.05.2010]
	* UDF library now compatible with AutoIt 3.3.6.1.
	* UDF library renamed to GUICtrlOnHover.au3.
	* Changed the main function name to _GUICtrl_OnHoverRegister, For backwards compatibility reasons, other (old) function names are still supported:
		_GUICtrl_SetOnHover, GUICtrl_SetOnHover, GUICtrlSetOnHover, _GUICtrlSetOnHover

	* Fixed(?) issue when the UDF is not working under 64-bit OS.
	* Global variables and internal functions renaming (for "cosmetic" reasons only).
	* UDF's code is more readable now.


	[v1.8] - [28.09.2009]
	* Few Global variables now have more unique name.
	* Fixed an issue with false calling of function on PrimaryDown event.
		I.e when the user clicks on other place (not on the hovered control) and drag the cursor to the control, the PrimaryDown function was called.
	* Due to (and as a result of) previous issue, the UDF now registering WM_COMMAND and WM_LBUTTONDOWN messages at first UDF call.


	[v1.7] - [07.07.2009]
	+ Added _GUICtrl_SetHoverOnBackWindow...
		Allows to set the hovering mode:
				$iSetBackWin = 1 (default) hovering process will proceed even when GUI is not active (in background).
				$iSetBackWin <> 1 hovering process will NOT proceed when GUI is not active.


	[v1.6] - [12.06.2009]
	* Now the UDF compatible with scripts (or other udfs) that uses OnAutoItExit function.
		i.e: "OnAutoItExit" function that was *previously* set by user will be called as well.

	+ Added new parameter $iKeepCall_Hover_Func. If this parameter = 1,
		then the $sHover_Func function *Will* be called constantly untill the control is no longer been hovered
		(default is 0, do not call the function constantly).
	+ Added new arguments to calling function...
		The OnPrimaryDown/Up function now can recieve one more argument:
			$iClickMode - Defines the Click mode (1 - Pressed, 2 - Released)

	* Changed return value - function will return 2 when $iCtrlID is redefined (ReSet, already exists in the controls list).
	* Fixed incorrect documentation parts.
	* Fixed "OnClick" handeling. When using multiple GUIs, the active gui was not recognized properly.
	* Fixed(?) bug with "dimension range exceeded" when trying to UnSet a Control.

	[v1.5]
	+ Added AutoIt 3.2.10.0+ support, but 3.2.8.1 or less is dropped :( (due to lack of native CallBack functions).
	+ Added Primary Down and Primary Up support. Helping to handle with the buttons pressing.
	+ Added new arguments to calling function...
		The OnHover function now can recieve two more arguments:
			$iHoverMode - Defines the hover mode (1 - Hover, 2 - Leaves Hovering)
			$hWnd_Hovered - Control Handle where the mouse is moved to (after hovering).

	* Almost all code of this UDF was rewritted.
	* Now the main function name is _GUICtrl_SetOnHover(),
		but for backwards compatibility reasons, other (old) function names are still supported.
	* Fixed bug with hovering controls in other apps.
	* Improvements in generaly, the UDF working more stable now.

	[v1.?]
	* Beta changes, see "Forum link" for more details.

	[v1.0]
	* First release.

#CE

#EndRegion Header

#Region Internal Global Variables

Global $a__GUICtrl_SOH_Ctrls[1][1]
Global $a__GUICtrl_SOH_LastHoveredElements[2] 		= [-1, -1]
Global $a__GUICtrl_SOH_LastHoveredElementsMark 		= -1
Global $h__GUICtrl_SOH_LastClickedElementMark 		= -1
Global $i__GUICtrl_SOH_CtrlsModified				= 0
Global $i__GUICtrl_SOH_HoverOnBackWin				= 1
Global $i__GUICtrl_SOH_LastPrimaryDownCtrlID		= 0

Global $p__GUICtrl_SOH_TimerProc 					= 0
Global $i__GUICtrl_SOH_TimerID 						= 0

Global $s__GUICtrl_SOH_User32_Dll					= @SystemDir & "\User32.dll"
Global $s__GUICtrl_SOH_OnExitFunc 					= ""

If @AutoItVersion < "3.3.2.0" Then
	$s__GUICtrl_SOH_OnExitFunc = Execute('Opt("OnExitFunc", "__GUICtrl_SOH_Exit")')
Else
	Execute('OnAutoItExitRegister("__GUICtrl_SOH_Exit")')
EndIf

Global Const $n__GUICtrl_SOH_WM_COMMAND				= 0x0111
Global Const $n__GUICtrl_SOH_WM_LBUTTONDOWN			= 0x0201

#EndRegion Internal Global Variables

#Region Public Functions

; #FUNCTION# ====================================================================================================
; Name...........:	_GUICtrl_OnHoverRegister
; Description....:	Registers a function to be called when GUI elements been hovered.
; Syntax.........:	_GUICtrl_OnHoverRegister($iCtrlID [, $sHover_Func="" [, $sLeaveHover_Func=-1 [, $sPrimaryDownFunc=-1 [, $sPrimaryUpFunc=-1 [, $iKeepCall_PrDn_Func=1 [, $iKeepCall_Hover_Func=0 ]]]]]])
;
; Parameters.....:	$iCtrlID              - The Ctrl ID to set hovering for (can be a -1 as indication to the last item created).
;
;                   $sHover_Func          - [Optional] Function to call when the mouse is hovering the control.
;                                             If this parameter passed as empty string (""),
;                                             then the specified CtrlID is UnSet from Hovering Handler list.
;
;                   $sLeaveHover_Func     - [Optional] Function to call when the mouse is leaving hovering the control
;                       (-1 no function used).
;                     * For both parameters, $sHover_FuncName and $sLeaveHover_FuncName,
;                       the specified function called with maximum 3 parameters:
;                                                     $iCtrlID      - CtrlID of hovered control.
;                                                     $iHoverMode   - Defines the hover mode (1 - Hover, 2 - Leaves Hovering).
;                                                     $hWnd_Hovered - Control Handle where the mouse is moved to (after hovering).
;
;                   $sPrimaryDownFunc     - [Optional] Function to call when Primary mouse button is *clicked* on the control.
;                       (-1 -> function is not called).
;
;                   $sPrimaryUpFunc       - [Optional] Function to call when Primary mouse button is *released* the control.
;                       (-1 -> function is not called).
;
;                     * For both parameters, $sPrimaryDownFunc and $sPrimaryUpFunc,
;                       the specified function called with maximum 2 parameters:
;                                                     $iCtrlID      - CtrlID of clicked control.
;                                                     $iClickMode   - Defines the click mode (1 - Pressed, 2 - Released).
;
;                   $iKeepCall_PrDn_Func  - [Optional] If this parameter < 1,
;                                            then the $sPrimaryDownFunc function will *Not* be called constantly untill
;                                            the primary mouse button is released (default behaviour - $iKeepCall_PrDn_Func = 1).
;
;                   $iKeepCall_Hover_Func - [Optional] If this parameter = 1,
;                                            then the $sHover_Func function *Will* be called constantly untill
;                                            the control is no longer been hovered (default behaviour - $iKeepCall_Hover_Func = 0).
;
; Return values..:	Success               - Returns 1 if the function registered succesefully.
;                                           When $iCtrlID is redefined (ReSet, already exists in the controls list), the return value is 2.
;					Failure               - Set @error to 1 and return 0 if $iCtrlID is not a GUI Control Identifier.
;
; Author.........:	G.Sandler (a.k.a CreatoR), www.creator-lab.ucoz.ru, www.autoit-script.ru.
; Modified.......:
; Remarks........:	1) TreeView/ListView Items can not be set :(.
;                   2) When the window is not active, the hover/leave hover functions will still called, but not when the window is disabled.
;                   3) The hover/leave hover functions will be called even if the script is paused by such functions as MsgBox().
;                   4) The $sHover_Func/$sLeaveHover_Func functions should not introduce significant delays in the main script,
;                      for example by calling functions like Sleep() or MsgBox().
;                   5) IMPORTANT!
;                      A) Do not call _GUICtrl_OnHoverRegister inside $sHover_Func/$sLeaveHover_Func functions, it's not a good idea.
;
;                      B) This UDF registering WM_COMMAND and WM_LBUTTONDOWN window messages.
;                      Please ensure that those messages are not used after including this library,
;                      if they do, you will have to call __GUICtrl_SOH_WM_COMMAND and __GUICtrl_SOH_WM_LBUTTONDOWN inside those functions. Example:
;
;							Func MY_WM_COMMAND($hWnd, $iMsg, $wParam, $lParam)
;								__GUICtrl_SOH_WM_COMMAND($hWnd, $iMsg, $wParam, $lParam)
; 								...
;							EndFunc
;
; Related........:
; Link...........:	http://www.autoitscript.com/forum/index.php?s=&showtopic=55120
; Example........:	Yes.
; ===============================================================================================================
Func _GUICtrl_OnHoverRegister($iCtrlID, $sHover_Func="", $sLeaveHover_Func=-1, $sPrimaryDownFunc=-1, $sPrimaryUpFunc=-1, $iKeepCall_PrDn_Func=1, $iKeepCall_Hover_Func=0)
	Local $hCtrlID = GUICtrlGetHandle($iCtrlID)

	If Not $hCtrlID Then
		Return SetError(1, 0, 0)
	EndIf

	If $p__GUICtrl_SOH_TimerProc = 0 Then
		$p__GUICtrl_SOH_TimerProc = DllCallbackRegister("__GUICtrl_SOH_CALLBACK", "none", "hwnd;int;int;dword")
		$i__GUICtrl_SOH_TimerID = DllCall($s__GUICtrl_SOH_User32_Dll, "int", "SetTimer", _
			"hwnd", 0, "uint_ptr", Round(TimerInit()), "uint", 10, "ptr", DllCallbackGetPtr($p__GUICtrl_SOH_TimerProc))

		GUIRegisterMsg($n__GUICtrl_SOH_WM_COMMAND, "__GUICtrl_SOH_WM_COMMAND")
		GUIRegisterMsg($n__GUICtrl_SOH_WM_LBUTTONDOWN, "__GUICtrl_SOH_WM_LBUTTONDOWN")

		If IsArray($i__GUICtrl_SOH_TimerID) Then
			$i__GUICtrl_SOH_TimerID = $i__GUICtrl_SOH_TimerID[0]
		EndIf
	EndIf

	;UnSet Hovering for specified control (remove control id from hovering checking process)
	If $sHover_Func = "" And @NumParams <= 2 Then
		Local $a__GUICtrl_SOH_Ctrls_Tmp[1][1]
		Local $a__GUICtrl_SOH_Ctrls_Swap = $a__GUICtrl_SOH_Ctrls ;This one prevents a bug with "dimension range exceeded"

		For $i = 1 To $a__GUICtrl_SOH_Ctrls_Swap[0][0]
			If $hCtrlID <> $a__GUICtrl_SOH_Ctrls_Swap[$i][0] Then
				$a__GUICtrl_SOH_Ctrls_Tmp[0][0] += 1
				ReDim $a__GUICtrl_SOH_Ctrls_Tmp[$a__GUICtrl_SOH_Ctrls_Tmp[0][0]+1][7]

				$a__GUICtrl_SOH_Ctrls_Tmp[$a__GUICtrl_SOH_Ctrls_Tmp[0][0]][0] = $a__GUICtrl_SOH_Ctrls_Swap[$i][0]
				$a__GUICtrl_SOH_Ctrls_Tmp[$a__GUICtrl_SOH_Ctrls_Tmp[0][0]][1] = $a__GUICtrl_SOH_Ctrls_Swap[$i][1]
				$a__GUICtrl_SOH_Ctrls_Tmp[$a__GUICtrl_SOH_Ctrls_Tmp[0][0]][2] = $a__GUICtrl_SOH_Ctrls_Swap[$i][2]
				$a__GUICtrl_SOH_Ctrls_Tmp[$a__GUICtrl_SOH_Ctrls_Tmp[0][0]][3] = $a__GUICtrl_SOH_Ctrls_Swap[$i][3]
				$a__GUICtrl_SOH_Ctrls_Tmp[$a__GUICtrl_SOH_Ctrls_Tmp[0][0]][4] = $a__GUICtrl_SOH_Ctrls_Swap[$i][4]
				$a__GUICtrl_SOH_Ctrls_Tmp[$a__GUICtrl_SOH_Ctrls_Tmp[0][0]][5] = $a__GUICtrl_SOH_Ctrls_Swap[$i][5]
				$a__GUICtrl_SOH_Ctrls_Tmp[$a__GUICtrl_SOH_Ctrls_Tmp[0][0]][6] = $a__GUICtrl_SOH_Ctrls_Swap[$i][6]
			EndIf
		Next

		If $a__GUICtrl_SOH_Ctrls_Tmp[0][0] < 1 Then
			__GUICtrl_SOH_ReleaseResources() ;Release the callbacks
		Else
			$i__GUICtrl_SOH_CtrlsModified = 1
			$a__GUICtrl_SOH_Ctrls = $a__GUICtrl_SOH_Ctrls_Tmp
		EndIf

		Return 1
	EndIf

	;Check if the hovering process already handle the passed CtrlID, if so, just assign new values (functions)
	For $i = 1 To $a__GUICtrl_SOH_Ctrls[0][0]
		If $hCtrlID = $a__GUICtrl_SOH_Ctrls[$i][0] Then
			$a__GUICtrl_SOH_Ctrls[$i][0] = $hCtrlID
			$a__GUICtrl_SOH_Ctrls[$i][1] = $sHover_Func
			$a__GUICtrl_SOH_Ctrls[$i][2] = $sLeaveHover_Func
			$a__GUICtrl_SOH_Ctrls[$i][3] = $sPrimaryDownFunc
			$a__GUICtrl_SOH_Ctrls[$i][4] = $sPrimaryUpFunc
			$a__GUICtrl_SOH_Ctrls[$i][5] = $iKeepCall_PrDn_Func
			$a__GUICtrl_SOH_Ctrls[$i][6] = $iKeepCall_Hover_Func

			Return 2
		EndIf
	Next

	$a__GUICtrl_SOH_Ctrls[0][0] += 1
	ReDim $a__GUICtrl_SOH_Ctrls[$a__GUICtrl_SOH_Ctrls[0][0]+1][7]

	$a__GUICtrl_SOH_Ctrls[$a__GUICtrl_SOH_Ctrls[0][0]][0] = $hCtrlID
	$a__GUICtrl_SOH_Ctrls[$a__GUICtrl_SOH_Ctrls[0][0]][1] = $sHover_Func
	$a__GUICtrl_SOH_Ctrls[$a__GUICtrl_SOH_Ctrls[0][0]][2] = $sLeaveHover_Func
	$a__GUICtrl_SOH_Ctrls[$a__GUICtrl_SOH_Ctrls[0][0]][3] = $sPrimaryDownFunc
	$a__GUICtrl_SOH_Ctrls[$a__GUICtrl_SOH_Ctrls[0][0]][4] = $sPrimaryUpFunc
	$a__GUICtrl_SOH_Ctrls[$a__GUICtrl_SOH_Ctrls[0][0]][5] = $iKeepCall_PrDn_Func
	$a__GUICtrl_SOH_Ctrls[$a__GUICtrl_SOH_Ctrls[0][0]][6] = $iKeepCall_Hover_Func

	Return 1
EndFunc

;Set the hovering mode:
;                      $iSetBackWin = 1 (default) hovering process will proceed even when GUI is not active (in background).
;                      $iSetBackWin <> 1 hovering process will NOT proceed when GUI is not active.
Func _GUICtrl_SetHoverOnBackWindow($iSetBackWin)
	$i__GUICtrl_SOH_HoverOnBackWin = Number($iSetBackWin = 1)
EndFunc

#EndRegion Public Functions

#Region Backwards Compatibility Functions

;Backwards compatibility function #1
Func _GUICtrl_SetOnHover($iCtrlID, $sHover_Func="", $sLeaveHover_Func=-1, $sPrimaryDownFunc=-1, $sPrimaryUpFunc=-1, $iKeepCall_PrDn_Func=1, $iKeepCall_Hover_Func=0)
	_GUICtrl_OnHoverRegister($iCtrlID, $sHover_Func, $sLeaveHover_Func, $sPrimaryDownFunc, $sPrimaryUpFunc, $iKeepCall_PrDn_Func, $iKeepCall_Hover_Func)
EndFunc

;Backwards compatibility function #2
Func GUICtrl_SetOnHover($iCtrlID, $sHover_Func="", $sLeaveHover_Func=-1, $sPrimaryDownFunc=-1, $sPrimaryUpFunc=-1, $iKeepCall_PrDn_Func=1, $iKeepCall_Hover_Func=0)
	_GUICtrl_OnHoverRegister($iCtrlID, $sHover_Func, $sLeaveHover_Func, $sPrimaryDownFunc, $sPrimaryUpFunc, $iKeepCall_PrDn_Func, $iKeepCall_Hover_Func)
EndFunc

;Backwards compatibility function #3
Func GUICtrlSetOnHover($iCtrlID, $sHover_Func="", $sLeaveHover_Func=-1, $sPrimaryDownFunc=-1, $sPrimaryUpFunc=-1, $iKeepCall_PrDn_Func=1, $iKeepCall_Hover_Func=0)
	_GUICtrl_OnHoverRegister($iCtrlID, $sHover_Func, $sLeaveHover_Func, $sPrimaryDownFunc, $sPrimaryUpFunc, $iKeepCall_PrDn_Func, $iKeepCall_Hover_Func)
EndFunc

;Backwards compatibility function #4
Func _GUICtrlSetOnHover($iCtrlID, $sHover_Func="", $sLeaveHover_Func=-1, $sPrimaryDownFunc=-1, $sPrimaryUpFunc=-1, $iKeepCall_PrDn_Func=1, $iKeepCall_Hover_Func=0)
	_GUICtrl_OnHoverRegister($iCtrlID, $sHover_Func, $sLeaveHover_Func, $sPrimaryDownFunc, $sPrimaryUpFunc, $iKeepCall_PrDn_Func, $iKeepCall_Hover_Func)
EndFunc

#EndRegion Backwards Compatibility Functions

#Region Internal Functions

;CallBack function to handle the hovering process
Func __GUICtrl_SOH_CALLBACK($hWnd, $uiMsg, $idEvent, $dwTime)
	$i__GUICtrl_SOH_CtrlsModified = 0

	If $a__GUICtrl_SOH_Ctrls[0][0] < 1 Then
		Return
	EndIf

	If $i__GUICtrl_SOH_HoverOnBackWin Then
		Local $iControl_Hovered = __GUICtrl_SOH_ControlGetHovered()
	Else
		Local $iControl_Hovered = GUIGetCursorInfo()

		If Not IsArray($iControl_Hovered) Then
			Return
		EndIf

		$iControl_Hovered = GUICtrlGetHandle($iControl_Hovered[4])
	EndIf

	Local $sCheck_LHE = $a__GUICtrl_SOH_LastHoveredElements[1]
	Local $iCheck_LCEM = $h__GUICtrl_SOH_LastClickedElementMark
	Local $iCtrlID

	;Leave Hovering Process and reset variables
	If Not $iControl_Hovered Or ($sCheck_LHE <> -1 And $iControl_Hovered <> $sCheck_LHE) Then
		If $a__GUICtrl_SOH_LastHoveredElementsMark = -1 Then
			Return
		EndIf

		Local $LastHoveredElements[2] = [$a__GUICtrl_SOH_LastHoveredElements[0],$a__GUICtrl_SOH_LastHoveredElements[1]]

		$a__GUICtrl_SOH_LastHoveredElements[0] = -1
		$a__GUICtrl_SOH_LastHoveredElements[1] = -1
		$a__GUICtrl_SOH_LastHoveredElementsMark = -1
		$h__GUICtrl_SOH_LastClickedElementMark = -1

		If $LastHoveredElements[0] <> -1 Then
			$iCtrlID = DllCall($s__GUICtrl_SOH_User32_Dll, "int", "GetDlgCtrlID", "hwnd", $LastHoveredElements[1])

			If IsArray($iCtrlID) Then
				$iCtrlID = $iCtrlID[0]
			EndIf

			;2 is the indicator of OnLeavHover process
			__GUICtrl_SOH_Call($LastHoveredElements[0], $iCtrlID, 2, $iControl_Hovered)
		EndIf
	Else ;Hovering Process, Primary Down/Up handler, and set $a__GUICtrl_SOH_LastHoveredElements
		If $i__GUICtrl_SOH_CtrlsModified = 1 Then
			$i__GUICtrl_SOH_CtrlsModified = 0
			Return
		EndIf

		Local $iUbound = UBound($a__GUICtrl_SOH_Ctrls)-1

		For $i = 1 To $a__GUICtrl_SOH_Ctrls[0][0]
			If $i > $iUbound Then
				ExitLoop
			EndIf

			If $a__GUICtrl_SOH_Ctrls[$i][0] = $iControl_Hovered Then
				$iCtrlID = DllCall($s__GUICtrl_SOH_User32_Dll, "int", "GetDlgCtrlID", "hwnd", $iControl_Hovered)

				If IsArray($iCtrlID) Then
					$iCtrlID = $iCtrlID[0]
				EndIf

				;Primary Down/Up handler
				If ($a__GUICtrl_SOH_Ctrls[$i][3] <> "" Or $a__GUICtrl_SOH_Ctrls[$i][4] <> "") And ($iCheck_LCEM = -1 Or $iCheck_LCEM = $iControl_Hovered) Then
					Local $aCursorInfo = 0
					Local $hParent_Wnd = DllCall($s__GUICtrl_SOH_User32_Dll, "hwnd", "GetParent", "hwnd", $iControl_Hovered)

					If Not @error And IsArray($hParent_Wnd) Then
						$hParent_Wnd = $hParent_Wnd[0]
						$aCursorInfo = GUIGetCursorInfo($hParent_Wnd)
					Else
						$aCursorInfo = GUIGetCursorInfo()
					EndIf

					If IsArray($aCursorInfo) Then
						;Primary Down...
						;* First condition is to prevent function call when holding down m.button from other control
						;* Last condition is to Prevent/Allow multiple function call
						;(depending on $iKeepCall_PrDn_Func param).
						If $i__GUICtrl_SOH_LastPrimaryDownCtrlID = $iControl_Hovered And WinActive($hParent_Wnd) And _
							$aCursorInfo[2] = 1 And $a__GUICtrl_SOH_Ctrls[$i][3] <> -1 And _
							(($a__GUICtrl_SOH_Ctrls[$i][5] < 1 And $iCheck_LCEM <> $iControl_Hovered) Or $a__GUICtrl_SOH_Ctrls[$i][5] > 0) Then

							;1 is the indicator of Primary*Down* event
							__GUICtrl_SOH_Call($a__GUICtrl_SOH_Ctrls[$i][3], $iCtrlID, 1)

							$h__GUICtrl_SOH_LastClickedElementMark = $iControl_Hovered
						;Primary Up
						ElseIf $aCursorInfo[2] = 0 And $a__GUICtrl_SOH_Ctrls[$i][4] <> -1 And $iCheck_LCEM = $iControl_Hovered Then
							;2 is the indicator of Primary*Up* event
							__GUICtrl_SOH_Call($a__GUICtrl_SOH_Ctrls[$i][4], $iCtrlID, 2)

							$h__GUICtrl_SOH_LastClickedElementMark = -1
						EndIf
					EndIf
				EndIf

				If $i__GUICtrl_SOH_CtrlsModified = 1 Then
					ExitLoop
				EndIf

				If $a__GUICtrl_SOH_Ctrls[$i][6] < 1 And $a__GUICtrl_SOH_LastHoveredElementsMark = $a__GUICtrl_SOH_Ctrls[$i][0] Then
					ExitLoop
				Else
					$a__GUICtrl_SOH_LastHoveredElementsMark = $a__GUICtrl_SOH_Ctrls[$i][0]
				EndIf

				If $a__GUICtrl_SOH_Ctrls[$i][2] <> -1 Then
					$a__GUICtrl_SOH_LastHoveredElements[0] = $a__GUICtrl_SOH_Ctrls[$i][2]
					$a__GUICtrl_SOH_LastHoveredElements[1] = $iControl_Hovered
				EndIf

				__GUICtrl_SOH_Call($a__GUICtrl_SOH_Ctrls[$i][1], $iCtrlID, 1, 0) ;1 is the indicator of OnHover process

				If $i__GUICtrl_SOH_CtrlsModified = 1 Then
					ExitLoop
				EndIf

				ExitLoop
			EndIf
		Next
	EndIf

	$i__GUICtrl_SOH_CtrlsModified = 0
EndFunc

Func __GUICtrl_SOH_WM_COMMAND($hWndGUI, $MsgID, $WParam, $LParam)
	$i__GUICtrl_SOH_LastPrimaryDownCtrlID = $LParam
EndFunc

Func __GUICtrl_SOH_WM_LBUTTONDOWN($hWndGUI, $MsgID, $WParam, $LParam)
	$i__GUICtrl_SOH_LastPrimaryDownCtrlID = 0
EndFunc

;Thanks to amel27 for that one!!!
Func __GUICtrl_SOH_ControlGetHovered()
	Local $iOld_Opt_MCM = Opt("MouseCoordMode", 1)

	Local $aRet = DllCall($s__GUICtrl_SOH_User32_Dll, "hwnd", "WindowFromPoint", "long", MouseGetPos(0), "long", MouseGetPos(1))
	;$aRet = DllCall($s__GUICtrl_SOH_User32_Dll, "int", "GetDlgCtrlID", "hwnd", $aRet[0])

	Opt("MouseCoordMode", $iOld_Opt_MCM)

	Return $aRet[0]
EndFunc

;Call() function wrapper
Func __GUICtrl_SOH_Call($sFunction, $sParam1="", $sParam2="", $sParam3="", $sParam4="", $sParam5="")
	Local $sCall_Params = 'Call("' & $sFunction & '"'
	Local $sEval = ''

	For $i = 2 To @NumParams
		$sEval = Eval("sParam" & $i-1)

		If IsNumber($sEval) Then
			$sCall_Params &= ', Number(' & $sEval & ')'
		Else
			$sCall_Params &= ', "' & $sEval & '"'
		EndIf
	Next

	If @NumParams < 2 Then
		$sCall_Params &= '"'
	EndIf

	$sCall_Params &= ')'

	Local $iRet = Execute($sCall_Params)
	Local $iError = @error

	While $iError <> 0
		$sCall_Params = StringRegExpReplace($sCall_Params, '(.*), .*\)$', '\1)', 1)
		If @extended = 0 Then
			ExitLoop
		EndIf

		$iRet = Execute($sCall_Params)
		$iError = @error
	WEnd

	Return SetError($iError, 0, $iRet)
EndFunc

;Release resources function
Func __GUICtrl_SOH_ReleaseResources()
	If $p__GUICtrl_SOH_TimerProc > 0 Then
		DllCallbackFree($p__GUICtrl_SOH_TimerProc)
	EndIf

	If $i__GUICtrl_SOH_TimerID > 0 Then
		DllCall($s__GUICtrl_SOH_User32_Dll, "int", "KillTimer", "hwnd", 0, "uint_ptr", $i__GUICtrl_SOH_TimerID)
	EndIf

	GUIRegisterMsg($n__GUICtrl_SOH_WM_COMMAND, "")
	GUIRegisterMsg($n__GUICtrl_SOH_WM_LBUTTONDOWN, "")

	$p__GUICtrl_SOH_TimerProc = 0
	$i__GUICtrl_SOH_TimerID = 0
EndFunc

;Release the CallBack resources when exit
Func __GUICtrl_SOH_Exit()
	If $s__GUICtrl_SOH_OnExitFunc <> "" Then
		Call($s__GUICtrl_SOH_OnExitFunc)
	EndIf

	__GUICtrl_SOH_ReleaseResources()
EndFunc

#EndRegion Internal Functions
 

kzru_hunter

Осваивающий
Сообщения
144
Репутация
49
Автоит и так очень медленно работает по отношению к другим языкам программирования (для сравнения, цикл For...Next на автоите работает в 20 раз медленнее, чем в С++), поэтому предлагаю всем, кто пишет UDF, по максимуму его оптимизировать. Только вот для этого надо написать статью по оптимизации скорости работы скриптов и вынести её в массы.

Предлагаю в этом UDF оптимизировать функцию __GUICtrl_SOH_Call:
Код:
Func __GUICtrl_SOH_Call($CallFunc, $Param1 = "", $Param2 = "", $Param3 = "", $Param4 = "", $Param5 = "")
	Call($CallFunc,$Param1, $Param2, $Param3, $Param4, $Param5)
	If not @extended Then Return
	Call($CallFunc,$Param1, $Param2, $Param3, $Param4)
	If not @extended Then Return
	Call($CallFunc,$Param1, $Param2, $Param3)
	If not @extended Then Return
	Call($CallFunc,$Param1, $Param2)
	If not @extended Then Return
	Call($CallFunc,$Param1)
	If not @extended Then Return
	Call($CallFunc)
	If not @extended Then Return
	Return SetError(1)
EndFunc
Работает в 2.0-4.3 раза быстрее в зависимости от количества параметров в вызываемой функции.
 
Автор
CreatoR

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
kzru_hunter [?]
цикл For...Next на автоите работает в 20 раз медленнее, чем в С++
AutoIt написан именно на нём ;)

предлагаю всем, кто пишет UDF, по максимуму его оптимизировать
Оптимизируем, по максимум возможного. Не стоит забывать, что UDF пишутся в одно время, на одной версии, а используются и расматриваются в другое время и на другой версии, более новой и усовершенствованной, поэтому оптимизация понятие относительное и периодное.

Только вот для этого надо написать статью по оптимизации скорости работы скриптов
Буду только рад такой статье, повешу на главной, и на всех известных и доступных мне ресурсах по AutoIt.
 
Автор
CreatoR

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
kzru_hunter [?]
Предлагаю в этом UDF оптимизировать функцию __GUICtrl_SOH_Call
Тогда лучше уже так:

Код:
Func __GUICtrl_SOH_Call($sFunction, $sParam1="", $sParam2="", $sParam3="", $sParam4="", $sParam5="")
	Local $iRet = Call($sFunction)
	
	If @error <> 0xDEAD Then
		Return $iRet
	EndIf
	
	$iRet = Call($sFunction, $sParam1)
	
	If @error <> 0xDEAD Then
		Return $iRet
	EndIf
	
	$iRet = Call($sFunction, $sParam1, $sParam2)
	
	If @error <> 0xDEAD Then
		Return $iRet
	EndIf
	
	$iRet = Call($sFunction, $sParam1, $sParam2, $sParam3)
	
	If @error <> 0xDEAD Then
		Return $iRet
	EndIf
	
	$iRet = Call($sFunction, $sParam1, $sParam2, $sParam3, $sParam4)
	
	If @error <> 0xDEAD Then
		Return $iRet
	EndIf
	
	$iRet = Call($sFunction, $sParam1, $sParam2, $sParam3, $sParam4, $sParam5)
	
	If @error <> 0xDEAD Then
		Return $iRet
	EndIf
	
	Return SetError(1, 0, 0)
EndFunc



Добавлено:
Сообщение автоматически объединено:

Обновление библиотеки...

Список изменении:
[v2.0] - [09.06.2010]
* Исправлена потенциальная проблема с вызовом функции $sPrimaryDownFunc (первый вызов происходил только после получения WM_COMMAND сообщения, которое является событием для элемента управления в GUI).
* Исправлена проблема связанная с блокированием функции OnHover (вызываемая при навидении) - функция OnLeaveHover не вызывалась до тех пор пока функция OnHover была заблокированна (например вызовом MsgBox).
* Исправлена(?) (снова) проблема связанная с работой библиотеки на 64-битной ОС.
* Оптимизирована внутренняя функция "__GUICtrl_SOH_Call" для более быстрой обработки вызываемых функции параметров.
 

kzru_hunter

Осваивающий
Сообщения
144
Репутация
49
CreatoR [?]
Тогда лучше уже так:
Макрос @error в 3 раза дольше обрабатывается, чем @extended :smile:
@extended или @error может возвращать 0:rofl:EAD для @error (0xBEEF для @extended) либо 0: сравнивать с 0:rofl:EAD(0xBEEF) необязательно.
Зачем что-то возвращать из функции __GUICtrl_SOH_Call? )
И про последовательность вызова Call: может такая ситуация случиться (в очень редком случае), что HoverFunc может быть так задана
Код:
_Hover_Proc($iCtrlID, $iParam = 0)

В этом случае будет вызвана Call($sFunction, $sParam1) и $iParam так и останется нулём.
 
Автор
CreatoR

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
kzru_hunter [?]
Макрос @error в 3 раза дольше обрабатывается, чем @extended
Ничего подобного, вот пример который доказывает что они одинаково обрабатываются:

Код:
If $CmdLine[0] = 0 Then
	$iTimer = TimerInit()
	_SetExtendedError()
	If @extended = 1 Then MsgBox(64, 'TimerDiff - @extended', TimerDiff($iTimer))
	
	Run(@AutoItExe & ' /AutoIt3ExecuteScript "' & @ScriptFullPath & '" @Error')
	Exit
Else
	$iTimer = TimerInit()
	_SetExtendedError()
	If @error = 1 Then MsgBox(64, 'TimerDiff - @error', TimerDiff($iTimer))
EndIf

Func _SetExtendedError()
	Return SetError(1, 1, 0)
EndFunc



@extended или @error может возвращать 0:rofl:EAD для @error (0xBEEF для @extended) либо 0: сравнивать с 0:rofl:EAD(0xBEEF) необязательно.
Несмотря на неясность первого выражения в этом предложении, я всё же отвечу, что сравнивать с 0:rofl:EAD это корректно с точки зрения документации к функции.

Зачем что-то возвращать из функции __GUICtrl_SOH_Call?
Опять же, для “порядочности”, так правильнее.

В этом случае будет вызвана Call($sFunction, $sParam1) и $iParam так и останется нулём
Почему? впрочем это неправильное использования функции, зачем параметры делать опционально?
 
Автор
CreatoR

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
Новый пример, при навидений на кнопку/надпись показывает самодельную всплывающую подсказу:

Код:
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>

#include "GUICtrlOnHover.au3"

Global $sBtn_Image = @Systemdir & "\oobe\images\wpakey.jpg"
Global $sLbl_Image = @Systemdir & "\oobe\images\merlin.gif"

If Not FileExists($sBtn_Image) Or Not FileExists($sLbl_Image) Then
	$sBtn_Image = @TempDir & "\wpakey.jpg"
	$sLbl_Image = @TempDir & "\merlin.gif"
	
	InetGet("http://creator-lab.ucoz.ru/Images/wpakey.jpg", $sBtn_Image)
	InetGet("http://creator-lab.ucoz.ru/Images/merlin.gif", $sLbl_Image)
EndIf

$hGUI = GUICreate("Control ToolTip OnHover Example",500,400)

$nButton = GUICtrlCreateButton("Button", 100, 100, 50, 50)
_GUICtrl_OnHoverRegister(-1, "_ShowToolTip_Proc", "_ShowToolTip_Proc")

$nLabel = GUICtrlCreateLabel("Label", 300, 100, -1, 15)
_GUICtrl_OnHoverRegister(-1, "_ShowToolTip_Proc", "_ShowToolTip_Proc")

GUISetState(@SW_SHOW, $hGUI)

$hButton_ToolTip = _GUIToolTipCreate("My Button ToolTip", "Some Info", $sBtn_Image, 0x4E6FD6)
$hLabel_ToolTip = _GUIToolTipCreate("My Label ToolTip", "Some Info", $sLbl_Image, 0xFFFFFF)

While 1
    $nMsg = GUIGetMsg()
	
    Switch $nMsg
		Case $GUI_EVENT_CLOSE
			ExitLoop
	EndSwitch
WEnd

Func _GUIToolTipCreate($sTitle, $sText, $sImage = '', $nBkColor = 0xECEC00)
	Local $hToolTip = GUICreate($sTitle, 300, 200, -1, -1, BitOR($WS_POPUP, $WS_BORDER), $WS_EX_TOPMOST, $hGUI)
	GUISetBkColor($nBkColor, $hToolTip)
	GUICtrlCreatePic($sImage, 10, 10, 80, 80, $WS_BORDER)
	GUICtrlCreateLabel($sTitle, 100, 10, 180, 20)
	GUICtrlSetFont(-1, 10, 800)
	GUICtrlCreateLabel($sText, 100, 50, 180, 120)
	Return $hToolTip
EndFunc

Func _ShowToolTip_Proc($iCtrlID, $iHoverMode)
	Local $hToolTip
	
	Switch $iCtrlID
		Case $nButton
			$hToolTip = $hButton_ToolTip
		Case $nLabel
			$hToolTip = $hLabel_ToolTip
	EndSwitch
	
	Switch $iHoverMode
		Case 1 ;Hover proc
			$aMousePos = MouseGetPos()
			WinMove($hToolTip, "", $aMousePos[0]+10, $aMousePos[1]+10)
			GUISetState(@SW_SHOWNOACTIVATE, $hToolTip)
		Case 2 ;Leave hover proc
			GUISetState(@SW_HIDE, $hToolTip)
	EndSwitch
EndFunc
 

saavaage

Знающий
Сообщения
171
Репутация
17
Столкнулся с такой проблемой. Есть следующий пример, который работает корректно:

Код:
#include <ButtonConstants.au3>
#include <GUIConstantsEx.au3>
#include <StaticConstants.au3>
#include <WindowsConstants.au3>
#include <GUICtrlOnHover.au3>

Opt("GUIOnEventMode", 1)


$hGUI = GUICreate('Тест', 619, 475, -1, -1,  $WS_SIZEBOX)
GUISetOnEvent($GUI_EVENT_CLOSE, "CLOSEClicked")
$hStatus_Pre = GUICtrlCreateLabel('', 0,418,619,32, $SS_SUNKEN)
$hStatus = GUICtrlCreateLabel('Вывод пояснительной инфо по кнопкам', 10,420,599,28, $BS_MULTILINE+$SS_RIGHT)
GUICtrlSetColor(-1, 0x0066ff)

$icon = GUICtrlCreateIcon("shell32.dll", 10, 150, 20)
_GUICtrl_OnHoverRegister(-1, '_Hover_Func', '_Leave_Hover_Func')
GUICtrlSetCursor(-1, 0)

$combo = GUICtrlCreateCombo('Комбо', 200, 25, 50)
_GUICtrl_OnHoverRegister(-1, '_Hover_Func', '_Leave_Hover_Func')
GUICtrlSetCursor(-1, 0)

$btn = GUICtrlCreateButton('Кнопка', 250, 95, 100, 25)
_GUICtrl_OnHoverRegister(-1, '_Hover_Func', '_Leave_Hover_Func')
GUICtrlSetCursor(-1, 0)

$lbl = GUICtrlCreateLabel("Лэйбл", 250, 200, 330, 100)
_GUICtrl_OnHoverRegister(-1, '_Hover_Func', '_Leave_Hover_Func')
GUICtrlSetCursor(-1, 0)

$ckb = GUICtrlCreateCheckbox("Чекбокс", 105, 65, 70, 25)
_GUICtrl_OnHoverRegister(-1, '_Hover_Func', '_Leave_Hover_Func')
GUICtrlSetCursor(-1, 0)

GUISetState()

While 1
    Sleep(100)
WEnd


Func CLOSEClicked()
   Exit
EndFunc

Func _Hover_Func($CtrlID)
    Switch $CtrlID
        Case $icon
            GUICtrlSetData($hStatus, 'ИКОНКА РАБОТАЕТ!  для всех разделов одинаковых размер Корзины: от 0 до 15%. Внимание!! После 9%, 0xa=10%, 0xb=11%, 0xc=12%, 0xd=13%, 0xe=14%, 0xf=15%.1111111111111111111111 22222222222222222 333333333333101')
        Case $btn
            GUICtrlSetData($hStatus, 'Кнопка Работает!. 1111111111 222222222222222 3 333333333')
		Case $lbl
            GUICtrlSetData($hStatus, 'Лэйбл Работает!!!')
		Case $combo
            GUICtrlSetData($hStatus, 'Комбо Работает!!!')
		Case $ckb
            GUICtrlSetData($hStatus, 'Чекбокс Работает!!!')
    EndSwitch
EndFunc   ;==>_Hover_Func

Func _Leave_Hover_Func($CtrlID)
    GuiCtrlSetData($hStatus, 'Вывод пояснительной инфо по кнопкам')
EndFunc   ;==>_Leave_Hover_Func

Но как только я пытаюсь его применить в серьезном скрипте, где очень большое кол-во контроллов, по которым необходимо выводить подсказки (больше 100), при попытке выйти через закрытие формы по клику на ESC (крестик в правом верхнем углу формы) (GUISetOnEvent($GUI_EVENT_CLOSE, "CLOSEClicked")), периодически происходит зависание с выдачей такого сообщения:

Код:
F:\LABORATORY\WORK_1(SmartXP)\SmartXP.au3 (1216) : ==> Recursion level has been exceeded - AutoIt will quit to prevent stack overflow.:
Sleep(100)

Эксперименты с увеличением sleep() до sleep(1000) в крнструкции

Код:
While 1
    Sleep(100)
WEnd


к успеху не привели.. :(

PS Есть подозрение на функцию _Leave_Hover_Func
 
Автор
CreatoR

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
saavaage [?]
происходит зависание с выдачей такого сообщения
Придётся посмотреть на полный скрипт, иначе трудно сказать.
 
Верх