diff --git a/.hgignore b/.hgignore
--- a/.hgignore
+++ b/.hgignore
@@ -1,89 +1,63 @@
syntax: glob
+.vs
.DS_Store
-Lgi*.sdf
-Lgi*.suo
Lib
-Win32*
-x64*
-Debug*
-Release*
*.o
+*.obj
*.d
+*.VC.db
+*.Matthew
+*.matthew
+*.user
*/.DS_Store
*.xcuserstate
*.xcbkptlist
xcschememanagement.plist
contents.xcworkspacedata
-HtmlEditor/HtmlEdit*.sdf
-HtmlEditor/HtmlEdit*.suo
-HtmlEditor/x64Debug
-HtmlEditor/x64Release
-HtmlEditor/build
-HtmlEditor/Gtk3/build
-
-HtmlTest/Files/*
-HtmlTest/HtmlTest*.sdf
-HtmlTest/HtmlTest*.suo
-HtmlTest/x64Debug
-HtmlTest/x64Release
-HtmlTest/MacCarbon/build
-HtmlTest/MacCocoa/build
+x64ReleaseNoOptimize*
+x64Debug*
+x64Release*
Ide/HtmlTest*.sdf
Ide/HtmlTest*.suo
-Ide/x64Debug*
-Ide/Debug*
-Ide/x64Release*
-Ide/Release*
Ide/LgiIde.xml.*
-Ide/LgiIde*.sdf
-Ide/LgiIde*.suo
Ide/Gtk3/build*
-Ide/MacCarbon/build
Ide/MacCocoa/build
-
-LgiTest/Test*.sdf
-LgiTest/Test*.suo
-LgiTest/x64
-LgiTest/Mac/build
+Ide/haiku/haikuPassword.txt
Lvc/Lvc.xml
-Lvc/Lvc*.sdf
-Lvc/Lvc*.suo
-Lvc/x64*
-Lvc/MacCarbon/build/*
Lvc/MacCocoa/build/*
-ResourceEditor/x64*
-ResourceEditor/MacCarbon/build
-ResourceEditor/MacCocoa/build
+ResourceEditor/mac/build
ScriptingUnitTests/Win32*
ScriptingUnitTests/x64*
src/common/Gdc2/Path/test/*.sdf
src/common/Gdc2/Path/test/*.suo
src/common/Gdc2/Path/test/x64*
src/mac/carbon/build
src/mac/cocoa/build
src/mac/lldb_callback/build
src/common/INet/libntlm-0.4.2/build-win32/Win32*
src/common/INet/libntlm-0.4.2/build-win32/x64*
Static_Win32*
Static_x64*
tests/Debug
tests/Release
tests/x64
+test/HtmlViewer/Files
+test/HtmlViewer/Output
+test/HtmlEditor/TestCases
-Updater/Updater*.user
Updater/Win32*
Updater/x64*
VsLaunch/VsLaunch*.sdf
VsLaunch/VsLaunch*.suo
VsLaunch/Win32*
VsLaunch/x64*
diff --git a/src/common/Net/libntlm-0.4.2/build-win32/libntlm_vs2019.vcxproj b/src/common/Net/libntlm-0.4.2/build-win32/libntlm_vs2019.vcxproj
--- a/src/common/Net/libntlm-0.4.2/build-win32/libntlm_vs2019.vcxproj
+++ b/src/common/Net/libntlm-0.4.2/build-win32/libntlm_vs2019.vcxproj
@@ -1,411 +1,228 @@
-
- Debug
- Win32
-
Debug
x64
-
- ReleaseNoOptimize
- Win32
-
ReleaseNoOptimize
x64
-
- Release
- Win32
-
Release
x64
libntlm
{F97AAACA-BF41-46B8-B534-A1639589A1A3}
libntlm
10.0
-
- DynamicLibrary
- v142
- false
- MultiByte
-
-
- DynamicLibrary
- v142
- false
- MultiByte
-
-
- DynamicLibrary
- v142
- false
- MultiByte
-
DynamicLibrary
v142
false
MultiByte
DynamicLibrary
v142
false
MultiByte
DynamicLibrary
v142
false
MultiByte
-
-
-
-
-
-
-
-
-
-
-
-
<_ProjectFileVersion>12.0.30501.0
-
- ..\..\..\..\..\lib\
- $(Platform)$(Configuration)19\
- true
- $(ProjectName)14x32d
-
..\..\..\..\..\lib\
$(Platform)$(Configuration)19\
true
$(ProjectName)19x64d
-
- ..\..\..\..\..\lib\
- $(Platform)$(Configuration)19\
- false
- $(ProjectName)14x32
-
..\..\..\..\..\lib\
$(Platform)$(Configuration)19\
false
$(ProjectName)19x64
-
- ..\..\..\..\..\lib\
- $(Platform)$(Configuration)19\
- false
- $(ProjectName)14x32nop
-
..\..\..\..\..\lib\
$(Platform)$(Configuration)19\
false
$(ProjectName)19x64nop
-
-
- _DEBUG;%(PreprocessorDefinitions)
- true
- true
- Win32
- .\Debug/libntlm.tlb
-
-
-
- Disabled
- ..;..\build-win32;..\lib;..\..\..\..\..\include;%(AdditionalIncludeDirectories)
- WIN32;_DEBUG;WINDOWS;_USRDLL;LIBNTLM_EXPORTS;LGI_STATIC;%(PreprocessorDefinitions)
- EnableFastChecks
- MultiThreadedDebug
- .\$(IntDir)libntlm.pch
- .\$(IntDir)
- .\$(IntDir)
- .\$(IntDir)
- true
- ProgramDatabase
-
-
- _DEBUG;%(PreprocessorDefinitions)
- 0x0c09
-
-
- $(OutputPath)$(TargetName).dll
- true
- true
- $(OutDir)$(TargetName).pdb
- false
-
- ../../../../../lib/$(TargetName).lib
- MachineX86
-
-
- true
- .\Debug/libntlm.bsc
-
-
_DEBUG;%(PreprocessorDefinitions)
true
true
X64
.\Debug/libntlm.tlb
Disabled
..;..\build-win32;..\lib;..\..\..\..\..\include;%(AdditionalIncludeDirectories)
WIN64;_DEBUG;WINDOWS;_USRDLL;LIBNTLM_EXPORTS;LGI_STATIC;%(PreprocessorDefinitions)
EnableFastChecks
MultiThreadedDebug
$(IntDir)libntlm.pch
$(IntDir)
$(IntDir)
$(IntDir)
true
ProgramDatabase
_DEBUG;%(PreprocessorDefinitions)
0x0c09
$(OutputPath)$(TargetName).dll
true
true
$(OutDir)$(TargetName).pdb
false
../../../../../lib/$(TargetName).lib
MachineX64
true
.\Debug/libntlm.bsc
-
-
- NDEBUG;%(PreprocessorDefinitions)
- true
- true
- Win32
- .\Release/libntlm.tlb
-
-
-
- MaxSpeed
- OnlyExplicitInline
- ..;..\build-win32;..\lib;..\..\..\..\..\include;%(AdditionalIncludeDirectories)
- WIN32;NDEBUG;WINDOWS;_USRDLL;LIBNTLM_EXPORTS;LGI_STATIC;%(PreprocessorDefinitions)
- true
- MultiThreaded
- true
- .\Release/libntlm.pch
- .\$(IntDir)
- .\$(IntDir)
- .\$(IntDir)
- true
-
-
- NDEBUG;%(PreprocessorDefinitions)
- 0x0c09
-
-
- $(OutputPath)$(TargetName).dll
- true
- $(OutDir)$(TargetName).pdb
- false
-
- ../../../../../lib/$(TargetName).lib
- MachineX86
-
-
- true
- .\Release/libntlm.bsc
-
-
NDEBUG;%(PreprocessorDefinitions)
true
true
X64
.\Release/libntlm.tlb
MaxSpeed
OnlyExplicitInline
..;..\build-win32;..\lib;..\..\..\..\..\include;%(AdditionalIncludeDirectories)
WIN64;NDEBUG;WINDOWS;_USRDLL;LIBNTLM_EXPORTS;LGI_STATIC;%(PreprocessorDefinitions)
true
MultiThreaded
true
$(IntDir)libntlm.pch
$(IntDir)
$(IntDir)
$(IntDir)
true
NDEBUG;%(PreprocessorDefinitions)
0x0c09
$(OutputPath)$(TargetName).dll
true
$(OutDir)$(TargetName).pdb
false
../../../../../lib/$(TargetName).lib
MachineX64
true
.\Release/libntlm.bsc
-
-
- NDEBUG;%(PreprocessorDefinitions)
- true
- true
- Win32
- .\Release/libntlm.tlb
-
-
-
- Disabled
- OnlyExplicitInline
- ..;..\build-win32;..\lib;..\..\..\..\..\include;%(AdditionalIncludeDirectories)
- WIN32;NDEBUG;WINDOWS;_USRDLL;LIBNTLM_EXPORTS;LGI_STATIC;%(PreprocessorDefinitions)
- true
- MultiThreaded
- true
- .\Release/libntlm.pch
- .\$(IntDir)
- .\$(IntDir)
- .\$(IntDir)
- true
-
-
- NDEBUG;%(PreprocessorDefinitions)
- 0x0c09
-
-
- $(OutputPath)$(TargetName).dll
- true
- $(OutDir)$(TargetName).pdb
- false
-
- ../../../../../lib/$(TargetName).lib
- MachineX86
-
-
- true
- .\Release/libntlm.bsc
-
-
NDEBUG;%(PreprocessorDefinitions)
true
true
X64
.\Release/libntlm.tlb
MaxSpeed
OnlyExplicitInline
..;..\build-win32;..\lib;..\..\..\..\..\include;%(AdditionalIncludeDirectories)
WIN64;NDEBUG;WINDOWS;_USRDLL;LIBNTLM_EXPORTS;LGI_STATIC;%(PreprocessorDefinitions)
true
MultiThreaded
true
$(IntDir)libntlm.pch
$(IntDir)
$(IntDir)
$(IntDir)
true
NDEBUG;%(PreprocessorDefinitions)
0x0c09
$(OutputPath)$(TargetName).dll
true
$(OutDir)$(TargetName).pdb
false
../../../../../lib/$(TargetName).lib
MachineX64
true
.\Release/libntlm.bsc
\ No newline at end of file
diff --git a/src/win/Lgi/View.cpp b/src/win/Lgi/View.cpp
--- a/src/win/Lgi/View.cpp
+++ b/src/win/Lgi/View.cpp
@@ -1,2191 +1,2193 @@
/*hdr
** FILE: LView.cpp
** AUTHOR: Matthew Allen
** DATE: 23/4/98
** DESCRIPTION: Win32 LView Implementation
**
** Copyright (C) 1998-2003, Matthew Allen
** fret@memecode.com
*/
#include
#include
#include "lgi/common/Lgi.h"
#include "lgi/common/Base64.h"
#include "lgi/common/Com.h"
#include "lgi/common/DragAndDrop.h"
#include "lgi/common/DropFiles.h"
#include "lgi/common/GdiLeak.h"
#include "lgi/common/Css.h"
#include "lgi/common/Edit.h"
#include "lgi/common/LgiRes.h"
#include "lgi/common/Menu.h"
#include "lgi/common/Thread.h"
#include "ViewPriv.h"
#define DEBUG_MOUSE_CLICKS 0
#define DEBUG_OVER 0
#define OLD_WM_CHAR_MODE 1
////////////////////////////////////////////////////////////////////////////////////////////////////
bool In_SetWindowPos = false;
HWND LViewPrivate::hPrevCapture = 0;
LViewPrivate::LViewPrivate(LView *view) : View(view)
{
WndStyle = WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN;
IsThemed = LResources::DefaultColours;
}
LViewPrivate::~LViewPrivate()
{
while (EventTargets.Length())
delete EventTargets[0];
if (hTheme)
{
CloseThemeData(hTheme);
hTheme = NULL;
}
if (FontOwnType == GV_FontOwned)
{
DeleteObj(Font);
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
// Helper Stuff
#include "zmouse.h"
int MouseRollMsg = 0;
#ifdef __GNUC__
#define MSH_WHEELMODULE_CLASS "MouseZ"
#define MSH_WHEELMODULE_TITLE "Magellan MSWHEEL"
#define MSH_SCROLL_LINES "MSH_SCROLL_LINES_MSG"
#endif
int _lgi_mouse_wheel_lines()
{
UINT nScrollLines;
if (SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, (PVOID) &nScrollLines, 0))
return nScrollLines;
return 3;
}
#define SetKeyFlag(v, k, f) if (GetKeyState(k)&0xFF00) { v |= f; }
int _lgi_get_key_flags()
{
int Flags = 0;
if (LGetOs() == LGI_OS_WIN9X)
{
SetKeyFlag(Flags, VK_MENU, LGI_EF_ALT);
SetKeyFlag(Flags, VK_SHIFT, LGI_EF_SHIFT);
SetKeyFlag(Flags, VK_CONTROL, LGI_EF_CTRL);
}
else // is NT/2K/XP
{
SetKeyFlag(Flags, VK_LMENU, LGI_EF_LALT);
SetKeyFlag(Flags, VK_RMENU, LGI_EF_RALT);
SetKeyFlag(Flags, VK_LSHIFT, LGI_EF_LSHIFT);
SetKeyFlag(Flags, VK_RSHIFT, LGI_EF_RSHIFT);
SetKeyFlag(Flags, VK_LCONTROL, LGI_EF_LCTRL);
SetKeyFlag(Flags, VK_RCONTROL, LGI_EF_RCTRL);
}
if (GetKeyState(VK_CAPITAL))
SetFlag(Flags, LGI_EF_CAPS_LOCK);
return Flags;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
int GetInputACP()
{
char16 Str[16];
LCID Lcid = (NativeInt)GetKeyboardLayout(GetCurrentThreadId()) & 0xffff;
GetLocaleInfo(Lcid, LOCALE_IDEFAULTANSICODEPAGE, Str, sizeof(Str));
return _wtoi(Str);
}
LKey::LKey(int v, uint32_t flags)
{
const char *Cp = 0;
vkey = v;
Data = flags;
c16 = 0;
#if OLD_WM_CHAR_MODE
c16 = vkey;
#else
typedef int (WINAPI *p_ToUnicode)(UINT, UINT, PBYTE, LPWSTR, int, UINT);
static bool First = true;
static p_ToUnicode ToUnicode = 0;
if (First)
{
ToUnicode = (p_ToUnicode) GetProcAddress(LoadLibrary("User32.dll"), "ToUnicode");
First = false;
}
if (ToUnicode)
{
BYTE state[256];
GetKeyboardState(state);
char16 w[4];
int r = ToUnicode(vkey, flags & 0x7f, state, w, CountOf(w), 0);
if (r == 1)
{
c16 = w[0];
}
}
#endif
}
////////////////////////////////////////////////////////////////////////////////////////////////////
template
bool CastHwnd(T *&Ptr, HWND hWnd)
{
#if _MSC_VER >= _MSC_VER_VS2005
LONG_PTR user = GetWindowLongPtr(hWnd, GWLP_USERDATA);
#else
LONG user = GetWindowLong(hWnd, GWL_USERDATA);
#endif
LONG magic = GetWindowLong(hWnd, GWL_LGI_MAGIC);
if (magic != LGI_GViewMagic)
{
TCHAR ClsName[256] = {0};
int Ch = GetClassName(hWnd, ClsName, CountOf(ClsName));
LString Cls = ClsName;
// LgiTrace("%s:%i - Error: hWnd=%p/%s, GWL_LGI_MAGIC=%i\n", _FL, hWnd, Cls.Get(), magic);
return false;
}
Ptr = dynamic_cast((LViewI*)user);
return Ptr != NULL;
}
bool SetLgiMagic(HWND hWnd)
{
SetLastError(0);
LONG res = SetWindowLong(hWnd, GWL_LGI_MAGIC, LGI_GViewMagic);
bool Status = res != 0;
if (!Status)
{
DWORD err = GetLastError();
Status = err == 0;
}
LONG v = GetWindowLong(hWnd, GWL_LGI_MAGIC);
// LgiTrace("set LGI_GViewMagic for %p, %i, %i\n", hWnd, Status, v);
return Status;
}
LRESULT CALLBACK LWindowsClass::Redir(HWND hWnd, UINT m, WPARAM a, LPARAM b)
{
if (m == WM_NCCREATE)
{
LPCREATESTRUCT Info = (LPCREATESTRUCT) b;
LViewI *ViewI = (LViewI*) Info->lpCreateParams;
if (ViewI)
{
LView *View = ViewI->GetGView();
if (View) View->_View = hWnd;
#if _MSC_VER >= _MSC_VER_VS2005
SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR)ViewI);
#else
SetWindowLong(hWnd, GWL_USERDATA, (LONG)ViewI);
#endif
SetLgiMagic(hWnd);
}
}
LViewI *Wnd = (LViewI*)
#if _MSC_VER >= _MSC_VER_VS2005
GetWindowLongPtr(hWnd, GWLP_USERDATA);
#else
GetWindowLong(hWnd, GWL_USERDATA);
#endif
if (Wnd)
{
LMessage Msg(m, a, b);
Msg.hWnd = hWnd;
return Wnd->OnEvent(&Msg);
}
return DefWindowProcW(hWnd, m, a, b);
}
LRESULT CALLBACK LWindowsClass::SubClassRedir(HWND hWnd, UINT m, WPARAM a, LPARAM b)
{
if (m == WM_NCCREATE)
{
LPCREATESTRUCT Info = (LPCREATESTRUCT) b;
LViewI *ViewI = 0;
if (Info->lpCreateParams)
{
if (ViewI = (LViewI*) Info->lpCreateParams)
{
LView *View = ViewI->GetGView();
if (View)
View->_View = hWnd;
}
}
#if _MSC_VER >= _MSC_VER_VS2005
SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR) ViewI);
#else
SetWindowLong(hWnd, GWL_USERDATA, (LONG) ViewI);
#endif
SetLgiMagic(hWnd);
}
LViewI *Wnd = (LViewI*)
#if _MSC_VER >= _MSC_VER_VS2005
GetWindowLongPtr(hWnd, GWLP_USERDATA);
#else
GetWindowLong(hWnd, GWL_USERDATA);
#endif
if (Wnd)
{
LMessage Msg(m, a, b);
Msg.hWnd = hWnd;
LMessage::Result Status = Wnd->OnEvent(&Msg);
return Status;
}
return DefWindowProcW(hWnd, m, a, b);
}
LWindowsClass::LWindowsClass(const char *name)
{
Name(name);
ZeroObj(Class);
Class.lpfnWndProc = (WNDPROC) Redir;
Class.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;
Class.cbWndExtra = GWL_EXTRA_BYTES;
Class.cbSize = sizeof(Class);
ParentProc = 0;
}
LWindowsClass::~LWindowsClass()
{
UnregisterClassW(NameW(), LProcessInst());
Class.lpszClassName = NULL;
}
LWindowsClass *LWindowsClass::Create(const char *ClassName)
{
if (!LAppInst)
return NULL;
LApp::ClassContainer *Classes = LAppInst->GetClasses();
if (!Classes)
return NULL;
LWindowsClass *c = Classes->Find(ClassName);
if (!c)
{
c = new LWindowsClass(ClassName);
if (c)
Classes->Add(ClassName, c);
}
return c;
}
bool LWindowsClass::IsSystem(const char *Cls)
{
if (!_stricmp(Cls, WC_BUTTONA) ||
!_stricmp(Cls, WC_COMBOBOXA) ||
!_stricmp(Cls, WC_STATICA)||
!_stricmp(Cls, WC_LISTBOXA)||
!_stricmp(Cls, WC_SCROLLBARA)||
!_stricmp(Cls, WC_HEADERA)||
!_stricmp(Cls, WC_LISTVIEWA)||
!_stricmp(Cls, WC_TREEVIEWA)||
!_stricmp(Cls, WC_COMBOBOXEXA)||
!_stricmp(Cls, WC_TABCONTROLA)||
!_stricmp(Cls, WC_IPADDRESSA)||
!_stricmp(Cls, WC_EDITA))
{
return true;
}
return false;
}
bool LWindowsClass::Register()
{
bool Status = false;
if (IsSystem(Name()))
{
ZeroObj(Class);
Class.cbSize = sizeof(Class);
Status = GetClassInfoExW(LProcessInst(), NameW(), &Class) != 0;
LAssert(Status);
}
else // if (!Class.lpszClassName)
{
Class.hInstance = LProcessInst();
if (!Class.lpszClassName)
Class.lpszClassName = NameW();
Status = RegisterClassExW(&Class) != 0;
if (!Status)
{
auto err = GetLastError();
if (err == 1410)
Status = true;
else
LAssert(Status);
}
}
return Status;
}
bool LWindowsClass::SubClass(char *Parent)
{
bool Status = false;
if (!Class.lpszClassName)
{
HBRUSH hBr = Class.hbrBackground;
LAutoWString p(Utf8ToWide(Parent));
if (p)
{
if (GetClassInfoExW(LProcessInst(), p, &Class))
{
ParentProc = Class.lpfnWndProc;
if (hBr)
{
Class.hbrBackground = hBr;
}
Class.cbWndExtra = max(Class.cbWndExtra, GWL_EXTRA_BYTES);
Class.hInstance = LProcessInst();
Class.lpfnWndProc = (WNDPROC) SubClassRedir;
Class.lpszClassName = NameW();
Status = RegisterClassExW(&Class) != 0;
LAssert(Status);
}
}
}
else Status = true;
return Status;
}
LRESULT CALLBACK LWindowsClass::CallParent(HWND hWnd, UINT m, WPARAM a, LPARAM b)
{
if (!ParentProc)
return 0;
if (IsWindowUnicode(hWnd))
{
return CallWindowProcW(ParentProc, hWnd, m, a, b);
}
else
{
return CallWindowProcA(ParentProc, hWnd, m, a, b);
}
}
//////////////////////////////////////////////////////////////////////////////
LViewI *LWindowFromHandle(HWND hWnd)
{
if (hWnd)
{
SetLastError(0);
int32 m = GetWindowLong(hWnd, GWL_LGI_MAGIC);
#if 0 //def _DEBUG
DWORD err = GetLastError();
if (err == 1413)
{
TCHAR name[256];
if (GetClassName(hWnd, name, sizeof(name)))
{
WNDCLASSEX cls;
ZeroObj(cls);
cls.cbSize = sizeof(WNDCLASSEX);
if (GetClassInfoEx(LAppInst->GetInstance(), name, &cls))
{
if (cls.cbWndExtra >= 8)
{
LAssert(!"Really?");
}
}
}
}
#endif
if (m == LGI_GViewMagic)
{
return (LViewI*)
#if _MSC_VER >= _MSC_VER_VS2005
GetWindowLongPtr(hWnd, GWLP_USERDATA);
#else
GetWindowLong(hWnd, GWL_USERDATA);
#endif
}
}
return 0;
}
//////////////////////////////////////////////////////////////////////////////
const char *LView::GetClass()
{
return "LView";
}
void LView::_Delete()
{
if (_View && d->DropTarget)
{
RevokeDragDrop(_View);
}
#ifdef _DEBUG
// Sanity check..
// LArray HasView;
for (auto c: Children)
{
auto par = c->GetParent();
bool ok = ((LViewI*)par) == this || par == NULL;
if (!ok)
LAssert(!"heirachy error");
}
#endif
// Delete myself out of my parent's list
if (d->Parent)
{
d->Parent->OnChildrenChanged(this, false);
d->Parent->DelView(this);
d->Parent = 0;
d->ParentI = 0;
}
// Delete all children
LViewI *c;
while (c = Children[0])
{
// If it has no parent, remove the pointer from the child list,
// Because the child isn't going to do it...
if (c->GetParent() == 0)
Children.Delete(c);
// Delete the child view
DeleteObj(c);
}
// Delete the OS representation of myself
if (_View && IsWindow(_View))
{
WndFlags |= GWF_DESTRUCTOR;
BOOL Status = DestroyWindow(_View);
LAssert(Status != 0);
}
// NULL my handles and flags
_View = 0;
WndFlags = 0;
// Remove static references to myself
if (_Over == this) _Over = 0;
if (_Capturing == this)
{
#if DEBUG_CAPTURE
LgiTrace("%s:%i - _Capturing %p/%s -> NULL\n",
_FL, this, GetClass());
#endif
_Capturing = 0;
}
LWindow *Wnd = GetWindow();
if (Wnd)
Wnd->SetFocus(this, LWindow::ViewDelete);
// this should only exist in an ex-LWindow, due to the way
// C++ deletes objects it needs to be here.
DeleteObj(_Lock);
}
void LView::Quit(bool DontDelete)
{
if (_View)
{
if (!DontDelete)
{
WndFlags |= GWF_QUIT_WND;
}
DestroyWindow(_View);
}
}
uint32_t LView::GetDlgCode()
{
return d->WndDlgCode;
}
void LView::SetDlgCode(uint32_t i)
{
d->WndDlgCode = i;
}
uint32_t LView::GetStyle()
{
return d->WndStyle;
}
void LView::SetStyle(uint32_t i)
{
d->WndStyle = i;
}
uint32_t LView::GetExStyle()
{
return d->WndExStyle;
}
void LView::SetExStyle(uint32_t i)
{
d->WndExStyle = i;
}
const char *LView::GetClassW32()
{
return d->WndClass;
}
void LView::SetClassW32(const char *c)
{
d->WndClass = c;
}
LWindowsClass *LView::CreateClassW32(const char *Class, HICON Icon, int AddStyles)
{
if (Class)
{
SetClassW32(Class);
}
if (GetClassW32())
{
LWindowsClass *c = LWindowsClass::Create(GetClassW32());
if (c)
{
if (Icon)
{
c->Class.hIcon = Icon;
}
if (AddStyles)
{
c->Class.style |= AddStyles;
}
c->Register();
return c;
}
}
return 0;
}
bool LView::IsAttached()
{
return _View && IsWindow(_View);
}
bool LView::Attach(LViewI *p)
{
bool Status = false;
SetParent(p);
LView *Parent = d->GetParent();
if (Parent && !_Window)
_Window = Parent->_Window;
const char *ClsName = GetClassW32();
if (!ClsName)
ClsName = GetClass();
if (ClsName)
{
// Real window with HWND
bool Enab = Enabled();
// Check the class is created
bool IsSystemClass = LWindowsClass::IsSystem(ClsName);
LWindowsClass *Cls = LWindowsClass::Create(ClsName);
if (Cls)
{
auto r = Cls->Register();
if (!r)
{
LAssert(0);
}
}
else if (!IsSystemClass)
return false;
LAssert(!Parent || Parent->Handle() != 0);
DWORD Style = GetStyle();
DWORD ExStyle = GetExStyle() & ~WS_EX_CONTROLPARENT;
if (!TestFlag(WndFlags, GWF_SYS_BORDER))
ExStyle &= ~(WS_EX_CLIENTEDGE | WS_EX_WINDOWEDGE);
auto Text = LBase::NameW();
LAutoWString WCls(Utf8ToWide(ClsName));
bool hasCaption = (GetStyle() & WS_CAPTION) != 0;
int Shadow = WINDOWS_SHADOW_AMOUNT;
/*
LgiTrace("%p/%s::Attach %s\n", this, Name(), Pos.GetStr());
LRect r = Pos;
r.x2 += Shadow;
r.y2 += Shadow;
LgiTrace(" %s\n", r.GetStr());
*/
_View = CreateWindowExW(ExStyle,
WCls,
Text,
Style,
Pos.x1,
Pos.y1,
Pos.X(),
Pos.Y(),
Parent ? Parent->Handle() : 0,
NULL,
LProcessInst(),
(LViewI*) this);
#ifdef _DEBUG
if (!_View)
{
DWORD e = GetLastError();
LgiTrace("%s:%i - CreateWindowExW failed with 0x%x\n", _FL, e);
LAssert(!"CreateWindowEx failed");
}
#endif
if (_View)
{
Status = (_View != NULL);
if (d->Font)
SendMessage(_View, WM_SETFONT, (WPARAM) d->Font->Handle(), 0);
if (d->DropTarget)
RegisterDragDrop(_View, d->DropTarget);
if (TestFlag(WndFlags, GWF_FOCUS))
SetFocus(_View);
if (d->WantsPulse > 0)
{
SetPulse(d->WantsPulse);
d->WantsPulse = -1;
}
}
OnAttach();
}
else
{
// Virtual window (no HWND)
Status = true;
}
if (Status && d->Parent)
{
- if (!d->Parent->HasView(this))
+ auto isWnd = dynamic_cast(this);
+ if (!isWnd)
{
- d->Parent->AddView(this);
+ if (!d->Parent->HasView(this))
+ d->Parent->AddView(this);
+ d->Parent->OnChildrenChanged(this, true);
}
- d->Parent->OnChildrenChanged(this, true);
}
return Status;
}
bool LView::Detach()
{
bool Status = false;
if (_Window)
{
LWindow *Wnd = dynamic_cast(_Window);
if (Wnd)
Wnd->SetFocus(this, LWindow::ViewDelete);
_Window = NULL;
}
if (d->Parent)
{
d->Parent->DelView(this);
d->Parent->OnChildrenChanged(this, false);
d->Parent = 0;
d->ParentI = 0;
Status = true;
WndFlags &= ~GWF_FOCUS;
if (_Capturing == this)
{
if (_View)
ReleaseCapture();
#if DEBUG_CAPTURE
LgiTrace("%s:%i - _Capturing %p/%s -> NULL\n",
_FL, this, GetClass());
#endif
_Capturing = 0;
}
if (_View)
{
WndFlags &= ~GWF_QUIT_WND;
BOOL Status = DestroyWindow(_View);
DWORD Err = GetLastError();
LAssert(Status != 0);
}
}
return Status;
}
LRect &LView::GetClient(bool InClientSpace)
{
static LRect Client;
if (_View)
{
RECT rc;
GetClientRect(_View, &rc);
Client = rc;
}
else
{
Client.Set(0, 0, Pos.X()-1, Pos.Y()-1);
if (dynamic_cast(this) ||
dynamic_cast(this))
{
Client.x1 += GetSystemMetrics(SM_CXFRAME);
Client.x2 -= GetSystemMetrics(SM_CXFRAME);
Client.y1 += GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYCAPTION);
Client.y2 -= GetSystemMetrics(SM_CYFRAME);
}
else if (Sunken() || Raised())
{
Client.Inset(_BorderSize, _BorderSize);
}
}
if (InClientSpace)
Client.Offset(-Client.x1, -Client.y1);
return Client;
}
LCursor LView::GetCursor(int x, int y)
{
return LCUR_Normal;
}
#ifndef GCL_HCURSOR
#define GCL_HCURSOR -12
#endif
bool LgiToWindowsCursor(OsView Hnd, LCursor Cursor)
{
char16 *Set = 0;
switch (Cursor)
{
case LCUR_UpArrow:
Set = IDC_UPARROW;
break;
case LCUR_Cross:
Set = IDC_CROSS;
break;
case LCUR_Wait:
Set = IDC_WAIT;
break;
case LCUR_Ibeam:
Set = IDC_IBEAM;
break;
case LCUR_SizeVer:
Set = IDC_SIZENS;
break;
case LCUR_SizeHor:
Set = IDC_SIZEWE;
break;
case LCUR_SizeBDiag:
Set = IDC_SIZENESW;
break;
case LCUR_SizeFDiag:
Set = IDC_SIZENWSE;
break;
case LCUR_SizeAll:
Set = IDC_SIZEALL;
break;
case LCUR_PointingHand:
{
LArray Ver;
int Os = LGetOs(&Ver);
if
(
(
Os == LGI_OS_WIN32
||
Os == LGI_OS_WIN64
)
&&
Ver[0] >= 5)
{
#ifndef IDC_HAND
#define IDC_HAND MAKEINTRESOURCE(32649)
#endif
Set = IDC_HAND;
}
// else not supported
break;
}
case LCUR_Forbidden:
Set = IDC_NO;
break;
// Not impl
case LCUR_SplitV:
break;
case LCUR_SplitH:
break;
case LCUR_Blank:
break;
}
HCURSOR cur = LoadCursor(0, Set ? Set : IDC_ARROW);
SetCursor(cur);
if (Hnd)
SetWindowLongPtr(Hnd, GCL_HCURSOR, (LONG_PTR)cur);
return true;
}
bool LView::PointToScreen(LPoint &p)
{
POINT pt = {p.x, p.y};
LViewI *t = this;
while ( t &&
t->GetParent() &&
!t->Handle())
{
pt.x += t->GetPos().x1;
pt.y += t->GetPos().y1;
t = t->GetParent();
}
ClientToScreen(t->Handle(), &pt);
p.x = pt.x;
p.y = pt.y;
return true;
}
bool LView::PointToView(LPoint &p)
{
POINT pt = {p.x, p.y};
LViewI *t = this;
while ( t &&
t->GetParent() &&
!t->Handle())
{
pt.x -= t->GetPos().x1;
pt.y -= t->GetPos().y1;
t = t->GetParent();
}
ScreenToClient(t->Handle(), &pt);
p.x = pt.x;
p.y = pt.y;
return true;
}
bool LView::GetMouse(LMouse &m, bool ScreenCoords)
{
// position
POINT p;
GetCursorPos(&p);
if (!ScreenCoords)
{
ScreenToClient(_View, &p);
}
m.x = p.x;
m.y = p.y;
m.Target = this;
// buttons
m.Flags = ((GetAsyncKeyState(VK_LBUTTON)&0x8000) ? LGI_EF_LEFT : 0) |
((GetAsyncKeyState(VK_MBUTTON)&0x8000) ? LGI_EF_MIDDLE : 0) |
((GetAsyncKeyState(VK_RBUTTON)&0x8000) ? LGI_EF_RIGHT : 0) |
((GetAsyncKeyState(VK_CONTROL)&0x8000) ? LGI_EF_CTRL : 0) |
((GetAsyncKeyState(VK_MENU) &0x8000) ? LGI_EF_ALT : 0) |
((GetAsyncKeyState(VK_LWIN) &0x8000) ? LGI_EF_SYSTEM : 0) |
((GetAsyncKeyState(VK_RWIN) &0x8000) ? LGI_EF_SYSTEM : 0) |
((GetAsyncKeyState(VK_SHIFT) &0x8000) ? LGI_EF_SHIFT : 0);
if (m.Flags & (LGI_EF_LEFT | LGI_EF_MIDDLE | LGI_EF_RIGHT))
{
m.Flags |= LGI_EF_DOWN;
}
return true;
}
bool LView::SetPos(LRect &p, bool Repaint)
{
bool Status = true;
LRect OldPos = Pos;
if (Pos != p)
{
Pos = p;
if (_View)
{
HWND hOld = GetFocus();
bool WasVis = IsWindowVisible(_View) != 0;
int Shadow = WINDOWS_SHADOW_AMOUNT;
In_SetWindowPos = true;
Status = SetWindowPos( _View,
NULL,
Pos.x1,
Pos.y1,
Pos.X() + Shadow,
Pos.Y() + Shadow,
// ((Repaint) ? 0 : SWP_NOREDRAW) |
SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOOWNERZORDER) != 0;
In_SetWindowPos = false;
}
else if (GetParent())
{
OnPosChange();
}
if (Repaint)
{
Invalidate();
}
}
return Status;
}
bool LView::Invalidate(LRect *r, bool Repaint, bool Frame)
{
if (_View)
{
bool Status = false;
if (Frame)
{
RedrawWindow( _View,
NULL,
NULL,
RDW_FRAME |
RDW_INVALIDATE |
RDW_ALLCHILDREN |
((Repaint) ? RDW_UPDATENOW : 0));
}
else
{
if (r)
{
Status = InvalidateRect(_View, &((RECT)*r), false) != 0;
}
else
{
RECT c = GetClient();
Status = InvalidateRect(_View, &c, false) != 0;
}
}
if (Repaint)
{
UpdateWindow(_View);
}
return Status;
}
else
{
LRect Up;
LViewI *p = this;
if (r)
{
Up = *r;
}
else
{
Up.Set(0, 0, Pos.X()-1, Pos.Y()-1);
}
if (dynamic_cast(this))
return true;
while (p && !p->Handle())
{
LViewI *Par = p->GetParent();
LView *VPar = Par?Par->GetGView():0;
LRect w = p->GetPos();
LRect c = p->GetClient(false);
if (Frame && p == this)
Up.Offset(w.x1, w.y1);
else
Up.Offset(w.x1 + c.x1, w.y1 + c.y1);
p = Par;
}
if (p && p->Handle())
{
return p->Invalidate(&Up, Repaint);
}
}
return false;
}
void
CALLBACK
LView::TimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, uint32_t dwTime)
{
LView *View = (LView*) idEvent;
if (View)
{
View->OnPulse();
}
}
void LView::SetPulse(int Length)
{
if (_View)
{
if (Length > 0)
{
d->TimerId = SetTimer(_View, (UINT_PTR) this, Length, (TIMERPROC) TimerProc);
}
else
{
KillTimer(_View, d->TimerId);
d->TimerId = 0;
}
}
else
{
d->WantsPulse = Length;
}
}
static int ConsumeTabKey = 0;
bool SysOnKey(LView *w, LMessage *m)
{
if (m->a == VK_TAB &&
(m->m == WM_KEYDOWN ||
m->m == WM_SYSKEYDOWN) )
{
if (!TestFlag(w->d->WndDlgCode, DLGC_WANTTAB) &&
!TestFlag(w->d->WndDlgCode, DLGC_WANTALLKEYS))
{
// push the focus to the next control
bool Shifted = (GetAsyncKeyState(VK_SHIFT) & 0x8000) != 0;
LViewI *Wnd = GetNextTabStop(w, Shifted);
if (Wnd)
{
if (In_SetWindowPos)
{
assert(0);
LgiTrace("%s:%i - SetFocus(%p)\\n", _FL, Wnd->Handle());
}
ConsumeTabKey = 2;
::SetFocus(Wnd->Handle());
return true;
}
}
}
return false;
}
#ifdef _MSC_VER
#include "vsstyle.h"
void LView::DrawThemeBorder(LSurface *pDC, LRect &r)
{
if (!d->hTheme)
d->hTheme = OpenThemeData(_View, VSCLASS_EDIT);
if (d->hTheme)
{
RECT rc = r;
int StateId;
if (!Enabled())
StateId = EPSN_DISABLED;
else if (GetFocus() == _View)
StateId = EPSN_FOCUSED;
else
StateId = EPSN_NORMAL;
// LgiTrace("ThemeDraw %s: %i\n", GetClass(), StateId);
RECT clip[4];
clip[0] = LRect(r.x1, r.y1, r.x1 + 1, r.y2); // left
clip[1] = LRect(r.x1 + 2, r.y1, r.x2 - 2, r.y1 + 1); // top
clip[2] = LRect(r.x2 - 1, r.y1, r.x2, r.y2); // right
clip[3] = LRect(r.x1 + 2, r.y2 - 1, r.x2 - 2, r.y2); // bottom
LColour cols[4] =
{
LColour(255, 0, 0),
LColour(0, 255, 0),
LColour(0, 0, 255),
LColour(255, 255, 0)
};
for (int i=0; iColour(cols[i]);
pDC->Rectangle(&tmp);
#else
DrawThemeBackground(d->hTheme,
pDC->Handle(),
EP_EDITBORDER_NOSCROLL,
StateId,
&rc,
&clip[i]);
#endif
}
pDC->Colour(L_MED);
pDC->Set(r.x1, r.y1);
pDC->Set(r.x2, r.y1);
pDC->Set(r.x1, r.y2);
pDC->Set(r.x2, r.y2);
r.Inset(2, 2);
}
else
{
LWideBorder(pDC, r, Sunken() ? DefaultSunkenEdge : DefaultRaisedEdge);
d->IsThemed = false;
}
}
#else
void LView::DrawThemeBorder(LSurface *pDC, LRect &r)
{
LWideBorder(pDC, r, DefaultSunkenEdge);
}
#endif
bool IsKeyChar(LKey &k, int vk)
{
if (k.Ctrl() || k.Alt() || k.System())
return false;
switch (vk)
{
case VK_BACK:
case VK_TAB:
case VK_RETURN:
case VK_SPACE:
case 0xba: // ;
case 0xbb: // =
case 0xbc: // ,
case 0xbd: // -
case 0xbe: // .
case 0xbf: // /
case 0xc0: // `
case 0xdb: // [
case 0xdc: // |
case 0xdd: // ]
case 0xde: // '
return true;
}
if (vk >= VK_NUMPAD0 && vk <= VK_DIVIDE)
return true;
if (vk >= '0' && vk <= '9')
return true;
if (vk >= 'A' && vk <= 'Z')
return true;
return false;
}
#define KEY_FLAGS (~(MK_LBUTTON | MK_MBUTTON | MK_RBUTTON))
LMessage::Result LView::OnEvent(LMessage *Msg)
{
int Status = 0;
if (Msg->Msg() == MouseRollMsg)
{
HWND hFocus = GetFocus();
if (_View)
{
int Flags = ((GetKeyState(VK_SHIFT)&0xF000) ? VK_SHIFT : 0) |
((GetKeyState(VK_CONTROL)&0xF000) ? VK_CONTROL : 0);
PostMessage(hFocus, WM_MOUSEWHEEL, MAKELONG(Flags, (short)Msg->a), Msg->b);
}
return 0;
}
for (auto target: d->EventTargets)
{
if (target->Msgs.Length() == 0 ||
target->Msgs.Find(Msg->Msg()))
target->OnEvent(Msg);
}
if (_View)
{
switch (Msg->m)
{
#if 1
case WM_CTLCOLORBTN:
case WM_CTLCOLOREDIT:
case WM_CTLCOLORSTATIC:
{
HDC hdc = (HDC)Msg->A();
HWND hwnd = (HWND)Msg->B();
LViewI *v = FindControl(hwnd);
LView *gv = v ? v->GetGView() : NULL;
if (gv)
{
int Depth = dynamic_cast(gv) ? 1 : 10;
LColour Fore = gv->StyleColour(LCss::PropColor, LColour(), Depth);
LColour Back = gv->StyleColour(LCss::PropBackgroundColor, LColour(), Depth);
if (Fore.IsValid())
{
COLORREF c = RGB(Fore.r(), Fore.g(), Fore.b());
SetTextColor(hdc, c);
}
if (Back.IsValid())
{
COLORREF c = RGB(Back.r(), Back.g(), Back.b());
SetBkColor(hdc, c);
SetDCBrushColor(hdc, c);
}
if (Fore.IsValid() || Back.IsValid())
{
#if !defined(DC_BRUSH)
#define DC_BRUSH 18
#endif
return (LRESULT) GetStockObject(DC_BRUSH);
}
}
goto ReturnDefaultProc;
return 0;
}
#endif
case 5700:
{
// I forget what this is for...
break;
}
case WM_ERASEBKGND:
{
return 1;
}
case WM_GETFONT:
{
LFont *f = GetFont();
if (!f || f == LSysFont)
return (LMessage::Result) LSysFont->Handle();
return (LMessage::Result) f->Handle();
break;
}
case WM_MENUCHAR:
case WM_MEASUREITEM:
{
return LMenu::_OnEvent(Msg);
break;
}
case WM_DRAWITEM:
{
DRAWITEMSTRUCT *di = (DRAWITEMSTRUCT*)Msg->B();
if (di)
{
if (di->CtlType == ODT_MENU)
{
return LMenu::_OnEvent(Msg);
}
/*
else if (di->CtlType == ODT_BUTTON)
{
LView *b;
if (CastHwnd(b, di->hwndItem) &&
b->GetCss())
{
LScreenDC dc(di->hDC, di->hwndItem);
switch (di->itemAction)
{
case ODA_DRAWENTIRE:
{
LRect c = di->rcItem;
LMemDC m(c.X(), c.Y(), GdcD->GetColourSpace());
HDC hdc = m.StartDC();
m.Colour(LColour(255, 0, 255));
m.Line(0, 0, m.X()-1, m.Y()-1);
LONG s = GetWindowLong(_View, GWL_STYLE);
SetWindowLong(_View, GWL_STYLE, (s & ~BS_TYPEMASK) | BS_PUSHBUTTON);
SendMessage(_View, WM_PRINT, (WPARAM)hdc, PRF_ERASEBKGND|PRF_CLIENT);
SetWindowLong(_View, GWL_STYLE, (s & ~BS_TYPEMASK) | BS_OWNERDRAW);
m.EndDC();
dc.Blt(0, 0, &m);
break;
}
case ODA_FOCUS:
{
break;
}
case ODA_SELECT:
{
break;
}
}
return true;
}
}
*/
}
if (!(WndFlags & GWF_DIALOG))
goto ReturnDefaultProc;
break;
}
case WM_ENABLE:
{
Invalidate(&Pos);
break;
}
case WM_HSCROLL:
case WM_VSCROLL:
{
LViewI *Wnd = FindControl((HWND) Msg->b);
if (Wnd)
{
Wnd->OnEvent(Msg);
}
break;
}
case WM_GETDLGCODE:
{
// we handle all tab control stuff
return DLGC_WANTALLKEYS; // d->WndDlgCode | DLGC_WANTTAB;
}
case WM_MOUSEWHEEL:
{
// short fwKeys = LOWORD(Msg->a); // key flags
short zDelta = (short) HIWORD(Msg->a); // wheel rotation
int nScrollLines = - _lgi_mouse_wheel_lines();
double Lines = ((double)zDelta * (double)nScrollLines) / WHEEL_DELTA;
if (ABS(Lines) < 1.0)
Lines *= 1.0 / ABS(Lines);
// LgiTrace("Lines = %g, zDelta = %i, nScrollLines = %i\n", Lines, zDelta, nScrollLines);
// Try giving the event to the current window...
if (!OnMouseWheel(Lines))
{
// Find the window under the cursor... and try giving it the mouse wheel event
short xPos = (short) LOWORD(Msg->b); // horizontal position of pointer
short yPos = (short) HIWORD(Msg->b); // vertical position of pointer
POINT Point = {xPos, yPos};
HWND hUnder = ::WindowFromPoint(Point);
HWND hParent = ::GetParent(hUnder);
if (hUnder &&
hUnder != _View && // Don't want to send ourselves a message...
hParent != _View) // WM_MOUSEWHEEL will propagate back up to us and cause an infinite loop
{
// Do a post event in case the window is deleting... at least it won't crash.
PostMessage(hUnder, Msg->m, Msg->a, Msg->b);
}
}
return 0;
}
case M_CHANGE:
{
LWindow *w = GetWindow();
LAutoPtr note((LNotification*)Msg->B());
LViewI *Ctrl = w ? w->FindControl((int)Msg->a) : 0;
if (Ctrl)
{
LAssert(note.Get() != NULL);
return OnNotify(Ctrl, note ? *note : LNotifyNull);
}
else
{
LgiTrace("Ctrl %i not found.\n", Msg->a);
}
break;
}
case M_COMMAND:
{
// LViewI *Ci = FindControl((HWND) Msg->b);
// LView *Ctrl = Ci ? Ci->GetGView() : 0;
LView *Ctrl;
if (Msg->b &&
CastHwnd(Ctrl, (HWND)Msg->b))
{
short Code = HIWORD(Msg->a);
switch (Code)
{
case CBN_CLOSEUP:
{
PostMessage(_View, WM_COMMAND, MAKELONG(Ctrl->GetId(), CBN_EDITCHANGE), Msg->b);
break;
}
case CBN_EDITCHANGE: // COMBO
{
Ctrl->SysOnNotify(Msg->Msg(), Code);
OnNotify(Ctrl, LNotifyValueChanged);
break;
}
/*
case BN_CLICKED: // BUTTON
case EN_CHANGE: // EDIT
*/
default:
{
Ctrl->SysOnNotify(Msg->Msg(), Code);
break;
}
}
}
break;
}
case WM_NCDESTROY:
{
#if _MSC_VER >= _MSC_VER_VS2005
SetWindowLongPtr(_View, GWLP_USERDATA, 0);
#else
SetWindowLong(_View, GWL_USERDATA, 0);
#endif
_View = NULL;
if (WndFlags & GWF_QUIT_WND)
{
delete this;
}
break;
}
case WM_CLOSE:
{
if (OnRequestClose(false))
{
Quit();
}
break;
}
case WM_DESTROY:
{
OnDestroy();
break;
}
case WM_CREATE:
{
SetId(d->CtrlId);
LWindow *w = GetWindow();
if (w && w->GetFocus() == this)
{
HWND hCur = GetFocus();
if (hCur != _View)
{
if (In_SetWindowPos)
{
assert(0);
LgiTrace("%s:%i - SetFocus(%p) (%s)\\n", __FILE__, __LINE__, Handle(), GetClass());
}
SetFocus(_View);
}
}
if (TestFlag(GViewFlags, GWF_DROP_TARGET))
{
DropTarget(true);
}
OnCreate();
break;
}
case WM_SETFOCUS:
{
LWindow *w = GetWindow();
if (w)
{
w->SetFocus(this, LWindow::GainFocus);
}
else
{
// This can happen in popup sub-trees of views. Where the focus
// is tracked separately from the main LWindow.
OnFocus(true);
Invalidate((LRect*)NULL, false, true);
}
break;
}
case WM_KILLFOCUS:
{
LWindow *w = GetWindow();
if (w)
{
w->SetFocus(this, LWindow::LoseFocus);
}
else
{
// This can happen when the LWindow is being destroyed
Invalidate((LRect*)NULL, false, true);
OnFocus(false);
}
break;
}
case WM_WINDOWPOSCHANGED:
{
if (!IsIconic(_View))
{
WINDOWPOS *Info = (LPWINDOWPOS) Msg->b;
if (Info)
{
if (Info->x == -32000 &&
Info->y == -32000)
{
#if 0
LgiTrace("WM_WINDOWPOSCHANGED %i,%i,%i,%i (icon=%i)\\n",
Info->x,
Info->y,
Info->cx,
Info->cy,
IsIconic(Handle()));
#endif
}
else
{
int Shadow = WINDOWS_SHADOW_AMOUNT;
LRect r;
r.ZOff(Info->cx-1, Info->cy-1);
r.Offset(Info->x, Info->y);
if (r.Valid() && r != Pos)
{
Pos = r;
/*
LgiTrace("%p/%s::PosChange %s\n", this, Name(), Pos.GetStr());
Pos.x2 -= Shadow;
Pos.y2 -= Shadow;
LgiTrace(" %s\n", Pos.GetStr());
*/
}
}
}
OnPosChange();
}
if (!(WndFlags & GWF_DIALOG))
{
goto ReturnDefaultProc;
}
break;
}
case WM_CAPTURECHANGED:
{
LViewI *Wnd;
if (Msg->B() &&
CastHwnd(Wnd, (HWND)Msg->B()))
{
if (Wnd != _Capturing)
{
#if DEBUG_CAPTURE
LgiTrace("%s:%i - _Capturing %p/%s -> %p/%s\n",
_FL,
_Capturing, _Capturing?_Capturing->GetClass():0,
Wnd, Wnd?Wnd->GetClass() : 0);
#endif
_Capturing = Wnd;
}
}
else if (_Capturing)
{
#if DEBUG_CAPTURE
LgiTrace("%s:%i - _Capturing %p/%s -> NULL\n",
_FL,
_Capturing, _Capturing?_Capturing->GetClass():0);
#endif
_Capturing = NULL;
}
break;
}
case M_MOUSEENTER:
{
LMouse Ms;
Ms.Target = this;
Ms.x = (short) (Msg->b&0xFFFF);
Ms.y = (short) (Msg->b>>16);
Ms.Flags = 0;
LViewI *MouseOver = WindowFromPoint(Ms.x, Ms.y);
if (MouseOver &&
_Over != MouseOver &&
!(MouseOver == this || MouseOver->Handle() == 0))
{
if (_Capturing)
{
if (MouseOver == _Capturing)
{
Ms = lgi_adjust_click(Ms, _Capturing);
_Capturing->OnMouseEnter(Ms);
}
}
else
{
if (_Over)
{
LMouse m = lgi_adjust_click(Ms, _Over);
_Over->OnMouseExit(m);
#if DEBUG_OVER
LgiTrace("Enter.LoseOver=%p/%s '%-20s'\n", _Over, _Over->GetClass(), _Over->Name());
#endif
}
_Over = MouseOver;
if (_Over)
{
#if DEBUG_OVER
LgiTrace("Enter.GetOver=%p/%s '%-20s'\n", _Over, _Over->GetClass(), _Over->Name());
#endif
LMouse m = lgi_adjust_click(Ms, _Over);
_Over->OnMouseEnter(m);
}
}
}
break;
}
case M_MOUSEEXIT:
{
if (_Over)
{
LMouse Ms;
Ms.Target = this;
Ms.x = (short) (Msg->b&0xFFFF);
Ms.y = (short) (Msg->b>>16);
Ms.Flags = 0;
bool Mine = false;
if (_Over->Handle())
{
Mine = _Over == this;
}
else
{
for (LViewI *o = _Capturing ? _Capturing : _Over; o; o = o->GetParent())
{
if (o == this)
{
Mine = true;
break;
}
}
}
if (Mine)
{
if (_Capturing)
{
LMouse m = lgi_adjust_click(Ms, _Capturing);
_Capturing->OnMouseExit(m);
}
else
{
#if DEBUG_OVER
LgiTrace("Exit.LoseOver=%p '%-20s'\n", _Over, _Over->Name());
#endif
_Over->OnMouseExit(Ms);
_Over = 0;
}
}
}
break;
}
case WM_MOUSEMOVE:
{
LMouse Ms;
Ms.Target = this;
Ms.x = (short) (Msg->b&0xFFFF);
Ms.y = (short) (Msg->b>>16);
Ms.Flags = _lgi_get_key_flags();
Ms.IsMove(true);
if (TestFlag(Msg->a, MK_LBUTTON)) SetFlag(Ms.Flags, LGI_EF_LEFT);
if (TestFlag(Msg->a, MK_RBUTTON)) SetFlag(Ms.Flags, LGI_EF_RIGHT);
if (TestFlag(Msg->a, MK_MBUTTON)) SetFlag(Ms.Flags, LGI_EF_MIDDLE);
SetKeyFlag(Ms.Flags, VK_MENU, MK_ALT);
Ms.Down((Msg->a & (MK_LBUTTON|MK_MBUTTON|MK_RBUTTON)) != 0);
LViewI *MouseOver = WindowFromPoint(Ms.x, Ms.y);
if (_Over != MouseOver)
{
if (_Over)
{
#if DEBUG_OVER
LgiTrace("Move.LoseOver=%p/%s '%-20s'\n", _Over, _Over->GetClass(), _Over->Name());
#endif
LMouse m = lgi_adjust_click(Ms, _Over);
_Over->OnMouseExit(m);
}
_Over = MouseOver;
if (_Over)
{
LMouse m = lgi_adjust_click(Ms, _Over);
_Over->OnMouseEnter(m);
#if DEBUG_OVER
LgiTrace("Move.GetOver=%p/%s '%-20s'\n", _Over, _Over->GetClass(), _Over->Name());
#endif
}
}
// int CurX = Ms.x, CurY = Ms.y;
LCursor Cursor = (_Over ? _Over : this)->GetCursor(Ms.x, Ms.y);
LgiToWindowsCursor(_View, Cursor);
#if 0
LgiTrace("WM_MOUSEMOVE %i,%i target=%p/%s, over=%p/%s, cap=%p/%s\n",
Ms.x, Ms.y,
Ms.Target, Ms.Target?Ms.Target->GetClass():0,
_Over, _Over?_Over->GetClass():0,
_Capturing, _Capturing?_Capturing->GetClass():0);
#endif
if (_Capturing)
Ms = lgi_adjust_click(Ms, _Capturing, true);
else if (_Over)
Ms = lgi_adjust_click(Ms, _Over);
else
return 0;
LWindow *Wnd = GetWindow();
if (!Wnd || Wnd->HandleViewMouse(dynamic_cast(Ms.Target), Ms))
{
Ms.Target->OnMouseMove(Ms);
}
break;
}
case WM_NCHITTEST:
{
POINT Pt = { LOWORD(Msg->b), HIWORD(Msg->b) };
ScreenToClient(_View, &Pt);
int Hit = OnHitTest(Pt.x, Pt.y);
if (Hit >= 0)
{
// LgiTrace("%I64i Hit=%i\n", LCurrentTime(), Hit);
return Hit;
}
if (!(WndFlags & GWF_DIALOG))
{
goto ReturnDefaultProc;
}
break;
}
case WM_LBUTTONDBLCLK:
case WM_LBUTTONDOWN:
case WM_LBUTTONUP:
{
LMouse Ms;
Ms.x = (short) (Msg->b&0xFFFF);
Ms.y = (short) (Msg->b>>16);
Ms.Flags = _lgi_get_key_flags() | LGI_EF_LEFT;
Ms.Down(Msg->m != WM_LBUTTONUP);
Ms.Double(Msg->m == WM_LBUTTONDBLCLK);
if (_Capturing)
Ms = lgi_adjust_click(Ms, _Capturing, true);
else if (_Over)
Ms = lgi_adjust_click(Ms, _Over);
else
Ms.Target = this;
#if DEBUG_MOUSE_CLICKS
LString Msg;
Msg.Printf("%s.Click", Ms.Target->GetClass());
Ms.Trace(Msg);
#endif
LWindow *Wnd = GetWindow();
if (!Wnd || Wnd->HandleViewMouse(dynamic_cast(Ms.Target), Ms))
Ms.Target->OnMouseClick(Ms);
break;
}
case WM_RBUTTONDBLCLK:
case WM_RBUTTONDOWN:
case WM_RBUTTONUP:
{
LMouse Ms;
Ms.x = (short) (Msg->b&0xFFFF);
Ms.y = (short) (Msg->b>>16);
Ms.Flags = _lgi_get_key_flags() | LGI_EF_RIGHT;
Ms.Down(Msg->m != WM_RBUTTONUP);
Ms.Double(Msg->m == WM_RBUTTONDBLCLK);
if (_Capturing)
Ms = lgi_adjust_click(Ms, _Capturing, true);
else if (_Over)
Ms = lgi_adjust_click(Ms, _Over);
else
Ms.Target = this;
#if DEBUG_MOUSE_CLICKS
LString Msg;
Msg.Printf("%s.Click", Ms.Target->GetClass());
Ms.Trace(Msg);
#endif
LWindow *Wnd = GetWindow();
if (!Wnd || Wnd->HandleViewMouse(dynamic_cast(Ms.Target), Ms))
Ms.Target->OnMouseClick(Ms);
break;
}
case WM_MBUTTONDBLCLK:
case WM_MBUTTONDOWN:
case WM_MBUTTONUP:
{
LMouse Ms;
Ms.x = (short) (Msg->b&0xFFFF);
Ms.y = (short) (Msg->b>>16);
Ms.Flags = _lgi_get_key_flags() | LGI_EF_MIDDLE;
Ms.Down(Msg->m != WM_MBUTTONUP);
Ms.Double(Msg->m == WM_MBUTTONDBLCLK);
if (_Capturing)
Ms = lgi_adjust_click(Ms, _Capturing, true);
else if (_Over)
Ms = lgi_adjust_click(Ms, _Over);
else
Ms.Target = this;
LWindow *Wnd = GetWindow();
if (!Wnd || Wnd->HandleViewMouse(dynamic_cast(Ms.Target), Ms))
Ms.Target->OnMouseClick(Ms);
break;
}
case WM_XBUTTONDBLCLK:
case WM_XBUTTONDOWN:
case WM_XBUTTONUP:
{
LMouse Ms;
int Clicked = (Msg->a >> 16) & 0xffff;
Ms.x = (short) (Msg->b&0xFFFF);
Ms.y = (short) (Msg->b>>16);
Ms.Flags = _lgi_get_key_flags() | LGI_EF_MIDDLE;
Ms.Button1(TestFlag(Clicked, XBUTTON1));
Ms.Button2(TestFlag(Clicked, XBUTTON2));
Ms.Down(Msg->m != WM_XBUTTONUP);
Ms.Double(Msg->m == WM_XBUTTONDBLCLK);
if (_Capturing)
Ms = lgi_adjust_click(Ms, _Capturing, true);
else if (_Over)
Ms = lgi_adjust_click(Ms, _Over);
else
Ms.Target = this;
LWindow *Wnd = GetWindow();
if (!Wnd || Wnd->HandleViewMouse(dynamic_cast(Ms.Target), Ms))
Ms.Target->OnMouseClick(Ms);
break;
}
case WM_SYSKEYUP:
case WM_SYSKEYDOWN:
case WM_KEYDOWN:
case WM_KEYUP:
{
static char AltCode[32];
bool IsDialog = TestFlag(WndFlags, GWF_DIALOG);
bool IsDown = Msg->m == WM_KEYDOWN || Msg->m == WM_SYSKEYDOWN;
int KeyFlags = _lgi_get_key_flags();
HWND hwnd = _View;
if (SysOnKey(this, Msg))
{
// LgiTrace("SysOnKey true, Msg=0x%x %x,%x\n", Msg->m, Msg->a, Msg->b);
return 0;
}
else
{
// Key
LKey Key((int)Msg->a, (int)Msg->b);
Key.Flags = KeyFlags;
Key.Down(IsDown);
Key.IsChar = false;
if (Key.Ctrl())
{
Key.c16 = (char16)Msg->a;
}
if (Key.c16 == VK_TAB && ConsumeTabKey)
{
ConsumeTabKey--;
}
else
{
LWindow *Wnd = GetWindow();
if (Wnd)
{
if (Key.Alt() ||
Key.Ctrl() ||
(Key.c16 < 'A' || Key.c16 > 'Z'))
{
Wnd->HandleViewKey(this, Key);
}
}
else
{
OnKey(Key);
}
}
if (Msg->m == WM_SYSKEYUP || Msg->m == WM_SYSKEYDOWN)
{
if (Key.vkey >= VK_F1 &&
Key.vkey <= VK_F12 &&
Key.Alt() == false)
{
// So in LgiIde if you press F10 (debug next) you get a hang
// sometimes in DefWindowProc. Until I figure out what's going
// on this code exits before calling DefWindowProc without
// breaking other WM_SYSKEY* functionality (esp Alt+F4).
return 0;
}
}
}
if (!IsDialog)
{
// required for Alt-Key function (eg Alt-F4 closes window)
goto ReturnDefaultProc;
}
break;
}
#if OLD_WM_CHAR_MODE
case WM_CHAR:
{
LKey Key((int)Msg->a, (int)Msg->b);
Key.Flags = _lgi_get_key_flags();
Key.Down(true);
Key.IsChar = true;
bool Shift = Key.Shift();
bool Caps = TestFlag(Key.Flags, LGI_EF_CAPS_LOCK);
if (!(Shift ^ Caps))
{
Key.c16 = ToLower(Key.c16);
}
else
{
Key.c16 = ToUpper(Key.c16);
}
if (Key.c16 == LK_TAB && ConsumeTabKey)
{
ConsumeTabKey--;
}
else
{
LWindow *Wnd = GetWindow();
if (Wnd)
{
Wnd->HandleViewKey(this, Key);
}
else
{
OnKey(Key);
}
}
break;
}
#endif
case M_SET_WND_STYLE:
{
SetWindowLong(Handle(), GWL_STYLE, (LONG)Msg->b);
SetWindowPos( Handle(),
0, 0, 0, 0, 0,
SWP_NOMOVE | SWP_NOZORDER | SWP_NOSIZE | SWP_FRAMECHANGED);
break;
}
case WM_PAINT:
{
_Paint();
break;
}
case WM_NCPAINT:
{
if (GetWindow() != this &&
!TestFlag(WndFlags, GWF_SYS_BORDER))
{
HDC hDC = GetWindowDC(_View);
LScreenDC Dc(hDC, _View, true);
LRect p(0, 0, Dc.X()-1, Dc.Y()-1);
OnNcPaint(&Dc, p);
}
goto ReturnDefaultProc;
break;
}
case WM_NCCALCSIZE:
{
LMessage::Param Status = 0;
int Edge = (Sunken() || Raised()) ? _BorderSize : 0;
RECT *rc = NULL;
if (Msg->a)
{
NCCALCSIZE_PARAMS *p = (NCCALCSIZE_PARAMS*) Msg->b;
rc = p->rgrc;
}
else
{
rc = (RECT*)Msg->b;
}
if (!(WndFlags & GWF_DIALOG))
{
Status = DefWindowProcW(_View, Msg->m, Msg->a, Msg->b);
}
if (Edge && rc && !TestFlag(WndFlags, GWF_SYS_BORDER))
{
rc->left += Edge;
rc->top += Edge;
rc->right -= Edge;
rc->bottom -= Edge;
return 0;
}
return Status;
}
case WM_NOTIFY:
{
NMHDR *Hdr = (NMHDR*)Msg->B();
if (Hdr)
{
LView *Wnd;
if (CastHwnd(Wnd, Hdr->hwndFrom))
Wnd->SysOnNotify(Msg->Msg(), Hdr->code);
}
break;
}
case M_THREAD_COMPLETED:
{
auto Th = (LThread*)Msg->A();
if (!Th)
break;
Th->OnComplete();
if (Th->GetDeleteOnExit())
delete Th;
return true;
}
default:
{
if (!(WndFlags & GWF_DIALOG))
goto ReturnDefaultProc;
break;
}
}
}
return 0;
ReturnDefaultProc:
#ifdef _DEBUG
uint64 start = LCurrentTime();
#endif
LRESULT r = DefWindowProcW(_View, Msg->m, Msg->a, Msg->b);
#ifdef _DEBUG
uint64 now = LCurrentTime();
if (now - start > 1000)
{
LgiTrace("DefWindowProc(0x%.4x, %i, %i) took %ims\n",
Msg->m, Msg->a, Msg->b, (int)(now - start));
}
#endif
return r;
}
LViewI *LView::FindControl(OsView hCtrl)
{
if (_View == hCtrl)
{
return this;
}
for (List::I i = Children.begin(); i.In(); i++)
{
LViewI *Ctrl = (*i)->FindControl(hCtrl);
if (Ctrl)
return Ctrl;
}
return 0;
}
diff --git a/test/HtmlViewer/HtmlViewer.lr8 b/test/HtmlViewer/HtmlViewer.lr8
new file mode 100644
--- /dev/null
+++ b/test/HtmlViewer/HtmlViewer.lr8
@@ -0,0 +1,18 @@
+
+
+
+