From 33565baa3a3aa0ee72f9fd081204705e2abdeb24 Mon Sep 17 00:00:00 2001 From: cxl Date: Wed, 25 Apr 2018 17:26:13 +0000 Subject: [PATCH] VirtualGui, fixed issue with Splitter and Frame widgets git-svn-id: svn://ultimatepp.org/upp/trunk@11914 f0d560ea-af0d-0410-9eb7-867de7ffcac7 --- uppsrc/CtrlCore/CtrlChild.cpp | 36 ++ uppsrc/CtrlCore/CtrlCore.h | 12 +- uppsrc/CtrlCore/src.tpp/Ctrl_en-us.tpp | 27 +- uppsrc/CtrlLib/Splitter.cpp | 38 +- uppsrc/VirtualGui/After.h | 7 + uppsrc/VirtualGui/ChSysInit.cpp | 21 + uppsrc/VirtualGui/Clip.cpp | 238 +++++++++++ uppsrc/VirtualGui/Ctrl.cpp | 87 ++++ uppsrc/VirtualGui/Ctrl.h | 76 ++++ uppsrc/VirtualGui/DnD.cpp | 150 +++++++ uppsrc/VirtualGui/DrawDragRect.cpp | 92 +++++ uppsrc/VirtualGui/Event.cpp | 210 ++++++++++ uppsrc/VirtualGui/FB.iml | 63 +++ uppsrc/VirtualGui/Gui.h | 358 ++++++++++++++++ uppsrc/VirtualGui/Image.cpp | 47 +++ uppsrc/VirtualGui/Keys.h | 124 ++++++ uppsrc/VirtualGui/Local.h | 65 +++ uppsrc/VirtualGui/SDL2GL/Cursor.cpp | 70 ++++ uppsrc/VirtualGui/SDL2GL/Draw.cpp | 18 + uppsrc/VirtualGui/SDL2GL/Event.cpp | 256 ++++++++++++ uppsrc/VirtualGui/SDL2GL/Keys.cpp | 133 ++++++ uppsrc/VirtualGui/SDL2GL/SDL2GL.h | 48 +++ uppsrc/VirtualGui/SDL2GL/SDL2GL.upp | 11 + uppsrc/VirtualGui/SDL2GL/Window.cpp | 74 ++++ uppsrc/VirtualGui/Top.cpp | 153 +++++++ uppsrc/VirtualGui/Top.h | 16 + uppsrc/VirtualGui/TopFrame.cpp | 236 +++++++++++ uppsrc/VirtualGui/VirtualGui.h | 127 ++++++ uppsrc/VirtualGui/VirtualGui.upp | 32 ++ uppsrc/VirtualGui/Wnd.cpp | 550 +++++++++++++++++++++++++ uppsrc/VirtualGui/main.conf | 1 + 31 files changed, 3357 insertions(+), 19 deletions(-) create mode 100644 uppsrc/VirtualGui/After.h create mode 100644 uppsrc/VirtualGui/ChSysInit.cpp create mode 100644 uppsrc/VirtualGui/Clip.cpp create mode 100644 uppsrc/VirtualGui/Ctrl.cpp create mode 100644 uppsrc/VirtualGui/Ctrl.h create mode 100644 uppsrc/VirtualGui/DnD.cpp create mode 100644 uppsrc/VirtualGui/DrawDragRect.cpp create mode 100644 uppsrc/VirtualGui/Event.cpp create mode 100644 uppsrc/VirtualGui/FB.iml create mode 100644 uppsrc/VirtualGui/Gui.h create mode 100644 uppsrc/VirtualGui/Image.cpp create mode 100644 uppsrc/VirtualGui/Keys.h create mode 100644 uppsrc/VirtualGui/Local.h create mode 100644 uppsrc/VirtualGui/SDL2GL/Cursor.cpp create mode 100644 uppsrc/VirtualGui/SDL2GL/Draw.cpp create mode 100644 uppsrc/VirtualGui/SDL2GL/Event.cpp create mode 100644 uppsrc/VirtualGui/SDL2GL/Keys.cpp create mode 100644 uppsrc/VirtualGui/SDL2GL/SDL2GL.h create mode 100644 uppsrc/VirtualGui/SDL2GL/SDL2GL.upp create mode 100644 uppsrc/VirtualGui/SDL2GL/Window.cpp create mode 100644 uppsrc/VirtualGui/Top.cpp create mode 100644 uppsrc/VirtualGui/Top.h create mode 100644 uppsrc/VirtualGui/TopFrame.cpp create mode 100644 uppsrc/VirtualGui/VirtualGui.h create mode 100644 uppsrc/VirtualGui/VirtualGui.upp create mode 100644 uppsrc/VirtualGui/Wnd.cpp create mode 100644 uppsrc/VirtualGui/main.conf diff --git a/uppsrc/CtrlCore/CtrlChild.cpp b/uppsrc/CtrlCore/CtrlChild.cpp index 174acf6ba..14365eda3 100644 --- a/uppsrc/CtrlCore/CtrlChild.cpp +++ b/uppsrc/CtrlCore/CtrlChild.cpp @@ -151,6 +151,42 @@ Ctrl * Ctrl::GetIndexChild(int ii) const return c; } +int Ctrl::GetViewChildIndex(const Ctrl *child) const +{ + GuiLock __; + int i = 0; + for (Ctrl *c = GetFirstChild(); c; c = c->GetNext()) + if(!c->InFrame()) { + if(c == child) return i; + i++; + } + return -1; +} + +int Ctrl::GetViewChildCount() const +{ + GuiLock __; + int n = 0; + for (Ctrl *c = GetFirstChild(); c; c = c->GetNext()) + if(!c->InFrame()) + n++; + return n; +} + +Ctrl * Ctrl::GetViewIndexChild(int ii) const +{ + GuiLock __; + Ctrl *c = GetFirstChild(); + int i = 0; + for (Ctrl *c = GetFirstChild(); c; c = c->GetNext()) + if(!c->InFrame()) { + if(i == ii) + return c; + i++; + } + return NULL; +} + bool Ctrl::HasChild(Ctrl *q) const { GuiLock __; diff --git a/uppsrc/CtrlCore/CtrlCore.h b/uppsrc/CtrlCore/CtrlCore.h index 050eec490..bd6204f86 100644 --- a/uppsrc/CtrlCore/CtrlCore.h +++ b/uppsrc/CtrlCore/CtrlCore.h @@ -11,6 +11,9 @@ #include #ifndef GUIPLATFORM_INCLUDE + #ifdef flagVIRTUALGUI + #define VIRTUALGUI 1 + #endif #ifdef flagTURTLE #define GUIPLATFORM_KEYCODES_INCLUDE @@ -19,6 +22,9 @@ #define GUIPLATFORM_NOSCROLL #define PLATFORM_TURTLE #define TURTLE + #elif flagVIRTUALGUI + #define GUIPLATFORM_KEYCODES_INCLUDE + #define GUIPLATFORM_INCLUDE #elif PLATFORM_WIN32 #define GUIPLATFORM_INCLUDE "Win32Gui.h" #else @@ -31,7 +37,7 @@ #define GUIPLATFORM_INCLUDE "Gtk.h" #endif #endif - + #endif #include GUIPLATFORM_INCLUDE @@ -899,6 +905,10 @@ public: Ctrl *GetIndexChild(int i) const; int GetChildCount() const; + int GetViewChildIndex(const Ctrl *child) const; + int GetViewChildCount() const; + Ctrl *GetViewIndexChild(int ii) const; + bool IsChild() const { return parent; } Ctrl *ChildFromPoint(Point& pt) const; diff --git a/uppsrc/CtrlCore/src.tpp/Ctrl_en-us.tpp b/uppsrc/CtrlCore/src.tpp/Ctrl_en-us.tpp index c6d625461..8aed7cf2e 100644 --- a/uppsrc/CtrlCore/src.tpp/Ctrl_en-us.tpp +++ b/uppsrc/CtrlCore/src.tpp/Ctrl_en-us.tpp @@ -986,13 +986,38 @@ of child (results in O(n) complexity).&] st]&] [s2; Returns the number of child ctrls. Note that this function performs sequential scan of child (results in O(n) complexity).&] -[s3;%- &] +[s3; &] [s4;%- &] [s5;:Ctrl`:`:GetIndexChild`(int`)const:%- [_^Ctrl^ Ctrl]_`*[* GetIndexChild]([@(0.0.255) in t]_[*@3 i])_[@(0.0.255) const]&] [s2; Retruns child at index [%-*@3 i] or NULL if there is none. Note that this function performs sequential scan of child (results in O(n) complexity).&] +[s3;%- &] +[s4;%- &] +[s5;:Upp`:`:Ctrl`:`:GetViewChildIndex`(const Upp`:`:Ctrl`*`)const:%- [@(0.0.255) int]_[* G +etViewChildIndex]([@(0.0.255) const]_[_^Upp`:`:Ctrl^ Ctrl]_`*[*@3 child])_[@(0.0.255) con +st]&] +[s2; Returns the index of view [%-*@3 child] (first child has index +0, second child 1 etc...). If [%-*@3 child] is not present in this +Ctrl or is in frame, returns `-1. Note that this function performs +sequential scan of child (results in O(n) complexity). This is +similar to GetChildIndex, but frame widgets are ignored.&] +[s3; &] +[s4;%- &] +[s5;:Upp`:`:Ctrl`:`:GetViewChildCount`(`)const:%- [@(0.0.255) int]_[* GetViewChildCount]( +)_[@(0.0.255) const]&] +[s2; Returns the number of child ctrls. Note that this function performs +sequential scan of child (results in O(n) complexity). This is +similar to GetChildCount, but frame widgets are ignored.&] +[s3;%- &] +[s4;%- &] +[s5;:Upp`:`:Ctrl`:`:GetViewIndexChild`(int`)const:%- [_^Upp`:`:Ctrl^ Ctrl]_`*[* GetViewIn +dexChild]([@(0.0.255) int]_[*@3 ii])_[@(0.0.255) const]&] +[s2; Retruns view child at index [%-*@3 i] or NULL if there is none. +Note that this function performs sequential scan of child (results +in O(n) complexity). This is similar to GetIndexChild, but frame +widgets are ignored.&] [s3; &] [s4;%- &] [s5;:Ctrl`:`:IsChild`(`)const:%- [@(0.0.255) bool]_[* IsChild]()_[@(0.0.255) const]&] diff --git a/uppsrc/CtrlLib/Splitter.cpp b/uppsrc/CtrlLib/Splitter.cpp index c81b4261f..821afa1be 100644 --- a/uppsrc/CtrlLib/Splitter.cpp +++ b/uppsrc/CtrlLib/Splitter.cpp @@ -23,7 +23,7 @@ int Splitter::PosToClient(int pos) const void Splitter::Layout() { Size sz = GetSize(); - int count = GetChildCount(); + int count = GetViewChildCount(); if(count == 0) return; mins.SetCount(count, 0); @@ -37,11 +37,13 @@ void Splitter::Layout() { if(style >= 0) { int i = 0; for(Ctrl *q = GetFirstChild(); q; q = q->GetNext()) { - if(style == i) - q->SizePos().Show(); - else - q->Hide(); - i++; + if(!q->InFrame()) { + if(style == i) + q->SizePos().Show(); + else + q->Hide(); + i++; + } } return; } @@ -51,14 +53,16 @@ void Splitter::Layout() { int i = 0; for(Ctrl *q = GetFirstChild(); q; q = q->GetNext()) { - int lo = i > 0 ? PosToClient(pos[i - 1]) + rw : 0; - int hi = i < count ? PosToClient(pos[i]) - lw : vert ? sz.cy : sz.cx; - q->Show(); - if(vert) - q->SetRect(0, lo, sz.cx, hi - lo); - else - q->SetRect(lo, 0, hi - lo, sz.cy); - i++; + if(!q->InFrame()) { + int lo = i > 0 ? PosToClient(pos[i - 1]) + rw : 0; + int hi = i < count ? PosToClient(pos[i]) - lw : vert ? sz.cy : sz.cx; + q->Show(); + if(vert) + q->SetRect(0, lo, sz.cx, hi - lo); + else + q->SetRect(lo, 0, hi - lo, sz.cy); + i++; + } } } @@ -232,7 +236,7 @@ void Splitter::Serialize(Stream& s) { pos.Clear(); s.LoadError(); } - if(style >= GetChildCount()) { + if(style >= GetViewChildCount()) { style = -1; s.LoadError(); } @@ -244,7 +248,7 @@ void Splitter::Remove(Ctrl& ctrl) { int n = 0; Ctrl *c = GetFirstChild(); - while(c){ + while(c) { if(c == &ctrl){ if(c->GetNext()) pos.Remove(n); @@ -253,7 +257,7 @@ void Splitter::Remove(Ctrl& ctrl) pos.Remove(n-1); mins.Remove(n); minpx.Remove(n); - RemoveChild(c); + RemoveChild(c); break; } c = c->GetNext(); diff --git a/uppsrc/VirtualGui/After.h b/uppsrc/VirtualGui/After.h new file mode 100644 index 000000000..93e50e5fb --- /dev/null +++ b/uppsrc/VirtualGui/After.h @@ -0,0 +1,7 @@ +class ViewDraw : public SystemDraw { +public: + ViewDraw(Ctrl *ctrl); + ~ViewDraw(); +}; + +class DHCtrl : Ctrl {}; diff --git a/uppsrc/VirtualGui/ChSysInit.cpp b/uppsrc/VirtualGui/ChSysInit.cpp new file mode 100644 index 000000000..841b6c753 --- /dev/null +++ b/uppsrc/VirtualGui/ChSysInit.cpp @@ -0,0 +1,21 @@ +#include "Local.h" + +#ifdef VIRTUALGUI + +NAMESPACE_UPP + +void ChSysInit() +{ + CtrlImg::Reset(); + CtrlsImg::Reset(); + ChReset(); +} + +void ChHostSkin() +{ + ChSysInit(); +} + +END_UPP_NAMESPACE + +#endif diff --git a/uppsrc/VirtualGui/Clip.cpp b/uppsrc/VirtualGui/Clip.cpp new file mode 100644 index 000000000..980e81e24 --- /dev/null +++ b/uppsrc/VirtualGui/Clip.cpp @@ -0,0 +1,238 @@ +#include "Local.h" + +#ifdef VIRTUALGUI + +NAMESPACE_UPP + +#define LLOG(x) // LOG(x) + +static VectorMap fbClipboard; + +void ClearClipboard() +{ + GuiLock __; + fbClipboard.Clear(); +} + +void AppendClipboard(const char *format, const Value& data, String (*render)(const Value&)) +{ + GuiLock __; + ClipData& cd = fbClipboard.GetAdd(format); + cd.data = data; + cd.render = render; +} + +static String sRawRender(const Value& v) +{ + return v; +} + +void AppendClipboard(const char *format, const String& data) +{ + GuiLock __; + AppendClipboard(format, data, sRawRender); +} + +void AppendClipboard(const char *format, const byte *data, int length) +{ + GuiLock __; + AppendClipboard(format, String(data, length)); +} + +String ReadClipboard(const char *format) +{ + GuiLock __; + int q = fbClipboard.Find(format); + return q >= 0 ? (*fbClipboard[q].render)(fbClipboard[q].data) : String(); +} + +void AppendClipboardText(const String& s) +{ + AppendClipboard("text", ToSystemCharset(s)); +} + +void AppendClipboardUnicodeText(const WString& s) +{ + AppendClipboard("wtext", (byte *)~s, 2 * s.GetLength()); +} + +const char *ClipFmtsText() +{ + return "wtext;text"; +} + +String GetString(PasteClip& clip) +{ + GuiLock __; + if(clip.Accept("wtext")) { + String s = ~clip; + return WString((const wchar *)~s, wstrlen((const wchar *)~s)).ToString(); + } + if(clip.IsAvailable("text")) + return ~clip; + return Null; +} + +WString GetWString(PasteClip& clip) +{ + GuiLock __; + if(clip.Accept("wtext")) { + String s = ~clip; + return WString((const wchar *)~s, wstrlen((const wchar *)~s)); + } + if(clip.IsAvailable("text")) + return (~clip).ToWString(); + return Null; +} + + +bool AcceptText(PasteClip& clip) +{ + return clip.Accept(ClipFmtsText()); +} + +static String sText(const Value& data) +{ + return data; +} + +static String sWText(const Value& data) +{ + return Unicode__(WString(data)); +} + +void Append(VectorMap& data, const String& text) +{ + data.GetAdd("text", ClipData(text, sText)); + data.GetAdd("wtext", ClipData(text, sWText)); +} + +void Append(VectorMap& data, const WString& text) +{ + data.GetAdd("text", ClipData(text, sText)); + data.GetAdd("wtext", ClipData(text, sWText)); +} + +String GetTextClip(const WString& text, const String& fmt) +{ + if(fmt == "text") + return text.ToString(); + if(fmt == "wtext") + return Unicode__(text); + return Null; +} + +String GetTextClip(const String& text, const String& fmt) +{ + if(fmt == "text") + return text; + if(fmt == "wtext") + return Unicode__(text.ToWString()); + return Null; +} + +String ReadClipboardText() +{ + String w = ReadClipboard("text"); + return w.GetCount() ? w : ReadClipboardUnicodeText().ToString(); +} + +WString ReadClipboardUnicodeText() +{ + String w = ReadClipboard("wtext"); + if(w.GetCount()) + return WString((const wchar *)~w, w.GetLength() / 2); + return ReadClipboard("text").ToWString(); +} + +bool IsClipboardAvailable(const char *id) +{ + return fbClipboard.Find(id) >= 0; +} + +bool IsClipboardAvailableText() +{ + return IsClipboardAvailable("text") || IsClipboardAvailable("wtext"); +} + +const char *ClipFmtsImage() +{ + static const char *q; + ONCELOCK { + static String s = "dib;" + ClipFmt(); + q = s; + } + return q; +} + +bool AcceptImage(PasteClip& clip) +{ + GuiLock __; + return clip.Accept(ClipFmtsImage()); +} + +Image GetImage(PasteClip& clip) +{ + GuiLock __; + Image m; + if(Accept(clip)) { + LoadFromString(m, ~clip); + if(!m.IsEmpty()) + return m; + } + return Null; +} + +Image ReadClipboardImage() +{ + GuiLock __; + PasteClip d = Ctrl::Clipboard(); + return GetImage(d); +} + +String sImage(const Value& image) +{ + Image img = image; + return StoreAsString(const_cast(img)); +} + +String GetImageClip(const Image& img, const String& fmt) +{ + GuiLock __; + if(img.IsEmpty()) return Null; + if(fmt == ClipFmt()) + return sImage(img); + return Null; +} + +void AppendClipboardImage(const Image& img) +{ + GuiLock __; + if(img.IsEmpty()) return; + AppendClipboard(ClipFmt(), img, sImage); +} + +bool AcceptFiles(PasteClip& clip) +{ + if(clip.Accept("files")) { + clip.SetAction(DND_COPY); + return true; + } + return false; +} + +bool IsAvailableFiles(PasteClip& clip) +{ + return clip.IsAvailable("files"); +} + +Vector GetFiles(PasteClip& clip) +{ + GuiLock __; + Vector f; + return f; +} + +END_UPP_NAMESPACE + +#endif diff --git a/uppsrc/VirtualGui/Ctrl.cpp b/uppsrc/VirtualGui/Ctrl.cpp new file mode 100644 index 000000000..3661593e3 --- /dev/null +++ b/uppsrc/VirtualGui/Ctrl.cpp @@ -0,0 +1,87 @@ +#include "Local.h" + +#ifdef VIRTUALGUI + +#define LLOG(x) // DLOG(x) + +NAMESPACE_UPP + +void Ctrl::GuiPlatformConstruct() +{ +} + +void Ctrl::GuiPlatformRemove() +{ +} + +void Ctrl::GuiPlatformGetTopRect(Rect& r) const +{ +} + +bool Ctrl::GuiPlatformRefreshFrameSpecial(const Rect& r) +{ + return false; +} + +bool Ctrl::GuiPlatformSetFullRefreshSpecial() +{ + return false; +} + +void Ctrl::PaintCaret(SystemDraw& w) +{ +} + +String GuiPlatformGetKeyDesc(dword key) +{ + return Null; +} + +void Ctrl::GuiPlatformSelection(PasteClip&) +{ +} + +void GuiPlatformAdjustDragImage(ImageBuffer&) +{ +} + +bool GuiPlatformHasSizeGrip() +{ + return true; +} + +void GuiPlatformGripResize(TopWindow *q) +{ + q->GripResize(); +} + +Color GuiPlatformGetScreenPixel(int x, int y) +{ + return Null; +} + +void GuiPlatformAfterMenuPopUp() +{ +} + +String Ctrl::Name() const { + GuiLock __; +#ifdef CPU_64 + String s = String(typeid(*this).name()) + " : 0x" + FormatIntHex(this); +#else + String s = String(typeid(*this).name()) + " : " + Format("0x%x", (int) this); +#endif + if(IsChild()) + s << "(parent " << String(typeid(*parent).name()) << ")"; + return s; +} + +void Ctrl::SetMouseCursor(const Image& image) +{ + GuiLock __; + VirtualGuiPtr->SetMouseCursor(image); +} + +END_UPP_NAMESPACE + +#endif diff --git a/uppsrc/VirtualGui/Ctrl.h b/uppsrc/VirtualGui/Ctrl.h new file mode 100644 index 000000000..2ff03c944 --- /dev/null +++ b/uppsrc/VirtualGui/Ctrl.h @@ -0,0 +1,76 @@ +//$ class Ctrl { +private: + static Ptr desktop; + static Vector topctrl; + static bool invalid; + + static Point fbCursorPos; + static Image fbCursorImage; + + static Rect fbCaretRect; + static int fbCaretTm; + + static bool fbEndSession; + static int64 fbEventLoop; + static int64 fbEndSessionLoop; + + static void CursorSync(); + + int FindTopCtrl() const; + static Rect GetClipBound(const Vector& inv, const Rect& r); + static void DoPaint(); + static void SyncTopWindows(); + +// static void AddInvalid(const Rect& rect); + + void DestroyWnd(); + + void NewTop() { DDUMP(this); top = new Top; top->owner_window = NULL; } + void PutForeground(); + static void MouseEventFB(Ptr t, int event, Point p, int zdelta); + + static void DrawLine(const Vector& clip, int x, int y, int cx, int cy, bool horz, + const byte *pattern, int animation); + static void DragRectDraw0(const Vector& clip, const Rect& rect, int n, + const byte *pattern, int animation); + + friend class TopWindowFrame; + friend class SystemDraw; + friend struct DnDLoop; + + void SetOpen(bool b) { isopen = b; } + + static void DeleteDesktopTop(); + +protected: + static int PaintLock; + +public: + static void DoMouseFB(int event, Point p, int zdelta = 0); + static bool DoKeyFB(dword key, int cnt); + + static void InitFB(); + static void ExitFB(); + static void EndSession(); + + static void PaintAll() { DoPaint(); } + + static void SetDesktop(Ctrl& q); + static Ctrl *GetDesktop() { return desktop; } + static void SetDesktopSize(Size sz); + + static void Invalidate() { invalid = true; } + + void DragRectDraw(const Rect& rect1, const Rect& rect2, const Rect& clip, int n, + Color color, int type, int animation); + + static Ctrl *FindMouseTopCtrl(); + + static void PaintScene(SystemDraw& draw); + static void PaintCaretCursor(SystemDraw& draw); + + static bool SystemCursor; + + enum { DRAWDRAGRECT_SCREEN = 0x8000 }; + +//$ }; diff --git a/uppsrc/VirtualGui/DnD.cpp b/uppsrc/VirtualGui/DnD.cpp new file mode 100644 index 000000000..c70d4ba16 --- /dev/null +++ b/uppsrc/VirtualGui/DnD.cpp @@ -0,0 +1,150 @@ +#include "Local.h" + +#ifdef VIRTUALGUI + +NAMESPACE_UPP + +#define LLOG(x) // DLOG(x) + +// -------------------------------------------------------------------------------------------- + +Ptr sDnDSource; + +Ctrl * Ctrl::GetDragAndDropSource() +{ + return sDnDSource; +} + +struct DnDLoop : LocalLoop { + const VectorMap *data; + Vector fmts; + + Image move, copy, reject; + Ptr target; + int action; + byte actions; + + void Sync(); + String GetData(const String& f); + void DnD(bool paste); + + virtual void LeftUp(Point, dword); + virtual bool Key(dword, int); + virtual void MouseMove(Point p, dword); + virtual Image CursorImage(Point, dword); +}; + +Ptr dndloop; + +bool PasteClip::IsAvailable(const char *fmt) const +{ + GuiLock __; + return dnd ? dndloop && FindIndex(dndloop->fmts, fmt) >= 0 + : IsClipboardAvailable(fmt); +} + +String DnDLoop::GetData(const String& f) +{ + GuiLock __; + int i = data->Find(f); + String d; + if(i >= 0) + d = (*data)[i].Render(); + else + if(sDnDSource) + d = sDnDSource->GetDropData(f); + return d; +} + +String PasteClip::Get(const char *fmt) const +{ + return dnd ? dndloop ? dndloop->GetData(fmt) : String() : ReadClipboard(fmt); +} + +void PasteClip::GuiPlatformConstruct() +{ + dnd = false; +} + +void DnDLoop::DnD(bool paste) +{ + PasteClip d; + d.paste = paste; + d.accepted = false; + d.allowed = (byte)actions; + d.action = GetCtrl() ? DND_COPY : DND_MOVE; + d.dnd = true; + if(target) + target->DnD(GetMousePos(), d); + action = d.IsAccepted() ? d.GetAction() : DND_NONE; +} + +void DnDLoop::Sync() +{ + GuiLock __; + Ptr t = FindMouseTopCtrl(); + if(t != target) + if(target) + target->DnDLeave(); + target = t; + DnD(false); +} + +void DnDLoop::LeftUp(Point, dword) +{ + GuiLock __; + LLOG("DnDLoop::LeftUp"); + DnD(true); + EndLoop(); +} + +void DnDLoop::MouseMove(Point p, dword) +{ + GuiLock __; + LLOG("DnDLoop::MouseMove"); + Sync(); +} + +bool DnDLoop::Key(dword, int) +{ + GuiLock __; + LLOG("DnDLoop::Key"); + Sync(); + return false; +} + +Image DnDLoop::CursorImage(Point, dword) +{ + GuiLock __; + return action == DND_MOVE ? move : action == DND_COPY ? copy : reject; +} + +int Ctrl::DoDragAndDrop(const char *fmts, const Image& sample, dword actions, + const VectorMap& data) +{ + GuiLock __; + DnDLoop d; + d.actions = (byte)actions; + d.reject = actions & DND_EXACTIMAGE ? CtrlCoreImg::DndNone() : MakeDragImage(CtrlCoreImg::DndNone(), sample); + if(actions & DND_COPY) + d.copy = actions & DND_EXACTIMAGE ? sample : MakeDragImage(CtrlCoreImg::DndCopy(), sample); + if(actions & DND_MOVE) + d.move = actions & DND_EXACTIMAGE ? sample : MakeDragImage(CtrlCoreImg::DndMoveX11(), sample); + d.SetMaster(*this); + d.data = &data; + d.action = DND_NONE; + d.fmts = Split(fmts, ';'); + dndloop = &d; + sDnDSource = this; + d.Run(); + sDnDSource = NULL; + SyncCaret(); + LLOG("DoDragAndDrop finished"); + return d.action; +} + +void Ctrl::SetSelectionSource(const char *fmts) {} + +END_UPP_NAMESPACE + +#endif diff --git a/uppsrc/VirtualGui/DrawDragRect.cpp b/uppsrc/VirtualGui/DrawDragRect.cpp new file mode 100644 index 000000000..067ea68dd --- /dev/null +++ b/uppsrc/VirtualGui/DrawDragRect.cpp @@ -0,0 +1,92 @@ +#include "Local.h" + +NAMESPACE_UPP + +struct DrawDragRectInfo { + Rect rect1, rect2, clip; + int n; + int type; + int animation; +}; + +void DrawDragLine(SystemDraw& w, bool horz, int x, int y, int len, int n, const int *pattern, int animation) +{ + if(len <= 0) + return; + if(horz) + w.Clip(x, y, len, n); + else + w.Clip(x, y, n, len); + + (horz ? x : y) -= animation; + len += animation; + bool ch = false; + while(len > 0) { + int segment = pattern[ch]; + int d = segment + pattern[2]; + if(horz) { + w.DrawRect(x, y, segment, n, InvertColor()); + x += d; + } + else { + w.DrawRect(x, y, n, segment, InvertColor()); + y += d; + } + len -= d; + ch = !ch; + } + w.End(); +} + +void DrawDragFrame(SystemDraw& w, const Rect& r, int n, const int *pattern, int animation) +{ + DrawDragLine(w, true, r.left, r.top, r.GetWidth(), n, pattern, animation); + DrawDragLine(w, false, r.left, r.top + n, r.GetHeight() - 2 * n, n, pattern, animation); + DrawDragLine(w, false, r.right - n, r.top + n, r.GetHeight() - 2 * n, n, pattern, animation); + DrawDragLine(w, true, r.left, r.bottom - n, r.GetWidth(), n, pattern, animation); +} + +void DrawDragRect(Ctrl& q, const DrawDragRectInfo& f) +{ + SystemDraw& w = VirtualGuiPtr->BeginDraw(); + Ctrl::PaintScene(w); + w.Clip(f.clip); + static int dashes[3][3] = { + { 32, 32, 0 }, + { 1, 1, 1 }, + { 5, 1, 2 }, + }; + const int *dash = dashes[minmax(f.type, 0, 2)]; + DrawDragFrame(w, f.rect1, f.n, dash, f.animation); + DrawDragFrame(w, f.rect2, f.n, dash, f.animation); + w.End(); + Ctrl::PaintCaretCursor(w); + VirtualGuiPtr->CommitDraw(); +} + +void DrawDragRect(Ctrl& q, const Rect& rect1, const Rect& rect2, const Rect& clip, int n, + Color color, int type, int animation) +{ + Ctrl *top = q.GetTopCtrl(); + if(top) { + Point off = q.GetScreenView().TopLeft(); + DrawDragRectInfo f; + f.rect1 = rect1.Offseted(off); + f.rect2 = rect2.Offseted(off); + f.clip = (clip & q.GetSize()).Offseted(off); + f.n = n; + f.type = type; + f.animation = animation; + DrawDragRect(*top, f); + } +} + +void FinishDragRect(Ctrl& q) +{ + SystemDraw& w = VirtualGuiPtr->BeginDraw(); + Ctrl::PaintScene(w); + Ctrl::PaintCaretCursor(w); + VirtualGuiPtr->CommitDraw(); +} + +END_UPP_NAMESPACE diff --git a/uppsrc/VirtualGui/Event.cpp b/uppsrc/VirtualGui/Event.cpp new file mode 100644 index 000000000..2aac20fff --- /dev/null +++ b/uppsrc/VirtualGui/Event.cpp @@ -0,0 +1,210 @@ +#include "Local.h" + +#ifdef VIRTUALGUI + +NAMESPACE_UPP + +#define LLOG(x) // LOG(x) +#define LDUMP(x) //DDUMP(x) + +static Point fbmousepos; +static dword mouseb = 0; +static dword modkeys = 0; + +Point GetMousePos() { + return fbmousepos; +} + +bool GetMouseLeft() { return VirtualGuiPtr->GetMouseButtons() & (1<<0); } +bool GetMouseRight() { return VirtualGuiPtr->GetMouseButtons() & (1<<1); } +bool GetMouseMiddle() { return VirtualGuiPtr->GetMouseButtons() & (1<<2); } +bool GetShift() { return VirtualGuiPtr->GetModKeys() & KM_SHIFT; } +bool GetCtrl() { return VirtualGuiPtr->GetModKeys() & KM_CTRL; } +bool GetAlt() { return VirtualGuiPtr->GetModKeys() & KM_ALT; } +bool GetCapsLock() { return VirtualGuiPtr->GetModKeys() & KM_CAPS; } + +void Ctrl::MouseEventFB(Ptr t, int event, Point p, int zdelta) +{ + if(!t->IsEnabled()) + return; + Rect rr = t->GetRect(); + if((event & Ctrl::ACTION) == DOWN) { + Ptr q = t; + TopWindowFrame *wf = dynamic_cast(~t); + if(wf) + q = wf->window; + if(q) q->ClickActivateWnd(); + if(q) q->SetForeground(); + if(ignoreclick) + return; + } + if(t) + t->DispatchMouse(event, p - rr.TopLeft(), zdelta); + if(t) + t->PostInput(); +} + +Ctrl *Ctrl::FindMouseTopCtrl() +{ + for(int i = topctrl.GetCount() - 1; i >= 0; i--) { + Ctrl *t = topctrl[i]; + if(t->GetRect().Contains(fbmousepos)) + return t->IsEnabled() ? t : NULL; + } + return desktop->IsEnabled() ? desktop : NULL; +} + +void Ctrl::DoMouseFB(int event, Point p, int zdelta) +{ + fbmousepos = p; + int a = event & Ctrl::ACTION; + if(a == Ctrl::UP && Ctrl::ignoreclick) { + EndIgnore(); + return; + } + else + if(a == Ctrl::DOWN && ignoreclick) + return; + LLOG("### Mouse event: " << event << " position " << p << " zdelta " << zdelta << ", capture " << Upp::Name(captureCtrl)); + if(captureCtrl) + MouseEventFB(captureCtrl->GetTopCtrl(), event, p, zdelta); + else + for(int i = topctrl.GetCount() - 1; i >= 0; i--) { + Ptr t = topctrl[i]; + Rect rr = t->GetRect(); + if(rr.Contains(p)) { + MouseEventFB(t, event, p, zdelta); + return; + } + } + Ctrl *desktop = GetDesktop(); + if(desktop) { + desktop->DispatchMouse(event, p, zdelta); + desktop->PostInput(); + } +} + +bool Ctrl::DoKeyFB(dword key, int cnt) +{ + LLOG("DoKeyFB " << GetKeyDesc(key) << ", " << cnt); + + bool b = DispatchKey(key, cnt); + SyncCaret(); + Ctrl *desktop = GetDesktop(); + if(desktop) + desktop->PostInput(); + return b; +} + +void Ctrl::SetCaret(int x, int y, int cx, int cy) +{ + GuiLock __; + caretx = x; + carety = y; + caretcx = cx; + caretcy = cy; + fbCaretTm = GetTickCount(); + SyncCaret(); +} + +void Ctrl::SyncCaret() +{ + CursorSync(); +} + +void Ctrl::CursorSync() +{ + LLOG("@ CursorSync"); + Point p = GetMousePos() - fbCursorImage.GetHotSpot(); + Rect cr = Null; + if(focusCtrl && (((GetTickCount() - fbCaretTm) / 500) & 1) == 0) + cr = (RectC(focusCtrl->caretx, focusCtrl->carety, focusCtrl->caretcx, focusCtrl->caretcy) + + focusCtrl->GetScreenView().TopLeft()) & focusCtrl->GetScreenView(); + if(fbCursorPos != p && !SystemCursor || cr != fbCaretRect) { + fbCaretRect = cr; + fbCursorPos = p; + Invalidate(); + } +} + +bool Ctrl::ProcessEvent(bool *quit) +{ + LLOG("@ ProcessEvent"); + ASSERT(IsMainThread()); + if(!GetMouseLeft() && !GetMouseRight() && !GetMouseMiddle()) + ReleaseCtrlCapture(); + bool ret = VirtualGuiPtr->ProcessEvent(quit); + DefferedFocusSync(); + SyncCaret(); + SyncTopWindows(); + return ret; +} + +bool Ctrl::ProcessEvents(bool *quit) +{ + //LOGBLOCK("@ ProcessEvents"); +// MemoryCheckDebug(); + bool ret = ProcessEvent(quit); + while(ProcessEvent(quit) && (!LoopCtrl || LoopCtrl->InLoop())); + TimeStop tm; + LLOG("TimerProc invoked at " << msecs()); + TimerProc(GetTickCount()); + LLOG("TimerProc elapsed: " << tm); + SweepMkImageCache(); + DoPaint(); + return ret; +} + +void Ctrl::EventLoop(Ctrl *ctrl) +{ + GuiLock __; + ASSERT(IsMainThread()); + ASSERT(LoopLevel == 0 || ctrl); + LoopLevel++; + LLOG("Entering event loop at level " << LoopLevel << LOG_BEGIN); + Ptr ploop; + if(ctrl) { + ploop = LoopCtrl; + LoopCtrl = ctrl; + ctrl->inloop = true; + } + + bool quit = false; + int64 loopno = ++EventLoopNo; + ProcessEvents(&quit); + while(loopno > EndSessionLoopNo && !quit && (ctrl ? ctrl->IsOpen() && ctrl->InLoop() : GetTopCtrls().GetCount())) + { +// LLOG(GetSysTime() << " % " << (unsigned)msecs() % 10000 << ": EventLoop / GuiSleep"); + SyncCaret(); + GuiSleep(20); +// LLOG(GetSysTime() << " % " << (unsigned)msecs() % 10000 << ": EventLoop / ProcessEvents"); + ProcessEvents(&quit); +// LLOG(GetSysTime() << " % " << (unsigned)msecs() % 10000 << ": EventLoop / after ProcessEvents"); + LDUMP(loopno); + LDUMP(fbEndSessionLoop); + } + + if(ctrl) + LoopCtrl = ploop; + LoopLevel--; + LLOG(LOG_END << "Leaving event loop "); +} + +void Ctrl::GuiSleep(int ms) +{ + GuiLock __; + ASSERT(IsMainThread()); + LLOG("GuiSleep"); + int level = LeaveGuiMutexAll(); + VirtualGuiPtr->WaitEvent(ms); + EnterGuiMutex(level); +} + +void WakeUpGuiThread() +{ + VirtualGuiPtr->WakeUpGuiThread(); +} + +END_UPP_NAMESPACE + +#endif diff --git a/uppsrc/VirtualGui/FB.iml b/uppsrc/VirtualGui/FB.iml new file mode 100644 index 000000000..c36090ae7 --- /dev/null +++ b/uppsrc/VirtualGui/FB.iml @@ -0,0 +1,63 @@ +PREMULTIPLIED +IMAGE_ID(Arrow) +IMAGE_ID(IBeam) +IMAGE_ID(Wait) +IMAGE_ID(No) +IMAGE_ID(SizeAll) +IMAGE_ID(SizeHorz) +IMAGE_ID(SizeRight) +IMAGE_ID(SizeLeft) +IMAGE_ID(SizeVert) +IMAGE_ID(SizeTopLeft) +IMAGE_ID(SizeTop) +IMAGE_ID(SizeTopRight) +IMAGE_ID(SizeBottomLeft) +IMAGE_ID(SizeBottom) +IMAGE_ID(SizeBottomRight) +IMAGE_ID(overlap) +IMAGE_ID(maximize) +IMAGE_ID(close) +IMAGE_ID(bgtitle) +IMAGE_ID(title) +IMAGE_ID(border) +IMAGE_ID(Hand) + +IMAGE_BEGIN_DATA +IMAGE_DATA(120,156,237,90,61,104,20,65,20,30,77,162,9,92,144,248,135,160,133,117,42,177,18,21,4,171,84,65,76,22,4,149) +IMAGE_DATA(136,17,37,49,66,4,13,40,72,34,4,145,128,120,133,196,20,49,30,24,11,207,104,33,105,196,4,114,133,34,66,68) +IMAGE_DATA(52,129,67,20,65,4,145,52,218,217,61,103,214,157,117,118,110,126,222,91,247,240,135,157,229,177,55,51,223,247,230,205) +IMAGE_DATA(247,222,206,94,244,88,129,109,98,162,173,97,171,196,13,184,5,12,223,128,200,129,114,153,196,129,239,223,183,195,244,244) +IMAGE_DATA(22,44,7,190,125,219,13,95,191,238,131,169,169,29,24,14,172,172,28,128,47,95,186,225,243,231,195,48,62,190,223,199) +IMAGE_DATA(129,79,159,122,225,227,199,83,240,225,195,25,120,255,254,28,20,139,7,93,28,120,247,238,60,188,125,123,1,170,213,97) +IMAGE_DATA(88,90,186,2,175,95,95,131,177,177,99,54,14,44,47,143,194,155,55,87,225,213,171,235,240,242,229,4,188,120,113,7) +IMAGE_DATA(158,63,159,134,209,209,126,19,135,99,138,176,184,120,131,227,38,225,217,179,123,176,176,176,16,217,3,24,30,30,208,57) +IMAGE_DATA(220,215,4,199,77,194,211,167,119,160,82,121,24,98,75,165,146,196,169,22,226,43,149,91,220,74,48,63,127,23,230,230) +IMAGE_DATA(238,195,227,199,143,156,251,125,242,228,54,92,188,120,58,246,51,52,52,232,196,15,13,245,169,243,194,96,112,112,64,141) +IMAGE_DATA(33,129,55,105,208,223,127,210,170,167,97,44,92,163,183,247,152,109,13,83,131,158,158,35,148,186,13,215,8,130,110,210) +IMAGE_DATA(26,93,93,7,41,248,128,16,143,185,53,177,117,108,53,91,27,26,211,18,47,76,54,237,115,28,176,214,255,231,199,44) +IMAGE_DATA(251,173,209,133,21,184,112,77,92,180,166,164,112,88,11,51,183,245,222,184,211,20,44,147,248,109,101,179,41,248,120,83) +IMAGE_DATA(155,175,93,50,114,196,152,152,211,240,65,203,174,157,176,254,236,137,4,71,124,22,99,98,142,25,158,36,149,227,193,38) +IMAGE_DATA(56,98,125,97,30,108,204,209,180,115,98,9,254,41,241,83,245,161,234,79,201,47,181,126,104,245,217,198,175,230,232,178) +IMAGE_DATA(9,103,33,163,143,70,132,89,147,230,193,81,230,93,241,186,252,164,225,215,36,80,233,99,215,183,125,166,196,111,138,139) +IMAGE_DATA(194,151,205,231,195,199,247,249,192,240,77,62,108,251,196,232,100,251,236,203,117,205,97,237,136,203,23,131,105,140,194,255) +IMAGE_DATA(157,231,129,82,79,212,231,22,227,203,204,69,28,72,63,189,242,38,94,217,226,142,8,194,200,47,151,203,130,15,209,157) +IMAGE_DATA(228,71,229,243,110,42,63,81,252,9,97,162,109,185,14,139,68,12,160,180,200,101,220,92,177,168,92,137,83,125,216,48) +IMAGE_DATA(166,253,171,241,234,62,212,125,170,250,232,250,233,205,54,166,250,49,233,135,53,25,119,22,113,100,161,71,86,121,201,170) +IMAGE_DATA(62,212,102,210,153,82,167,186,62,204,160,95,26,63,105,248,170,31,148,6,109,252,107,127,51,107,8,77,39,251,4,176) +IMAGE_DATA(9,109,43,22,155,15,234,195,99,106,236,15,60,60,152,56,178,208,35,147,188,228,137,206,19,157,39,250,127,74,244,90) +IMAGE_DATA(158,234,134,40,213,186,67,87,2,93,137,241,9,174,196,155,16,72,235,199,65,203,57,211,134,254,230,57,215,254,92,186) +IMAGE_DATA(184,244,116,229,65,205,83,77,254,90,249,181,38,186,106,235,19,87,61,166,96,41,28,204,151,17,149,211,222,222,142,230) +IMAGE_DATA(72,49,132,117,118,118,122,121,74,18,2,41,40,134,167,182,44,121,152,167,88,231,97,79,15,201,19,122,178,72,91,44) +IMAGE_DATA(135,41,249,195,228,91,47,106,12,199,88,139,249,201,84,191,57,215,254,92,186,212,253,100,114,53,107,165,120,56,212,138) +IMAGE_DATA(76,83,249,212,39,140,250,36,83,79,12,204,201,164,36,27,125,2,74,61,169,39,173,212,132,114,162,51,150,254,205,193) +IMAGE_DATA(8,111,40,106,77,229,5,155,23,172,147,195,254,182,130,205,95,165,245,155,115,237,207,165,75,221,95,165,105,42,69,110) +IMAGE_DATA(66,15,150,194,201,191,228,219,121,174,19,208,198,251,175,191,228,23,248,149,81,3,143,153,240,46,95,105,241,152,56,116) +IMAGE_DATA(188,111,205,172,240,24,125,234,165,139,58,70,201,19,190,101,80,76,190,224,40,98,153,48,57,62,123,60,37,95,248,246) +IMAGE_DATA(187,197,180,177,177,49,216,219,218,10,226,142,153,19,253,61,220,244,113,137,149,115,182,113,209,55,141,153,214,13,231,11) +IMAGE_DATA(133,208,108,216,4,71,96,35,156,248,108,195,82,241,148,120,168,251,77,171,39,54,95,164,214,200,47,217,186,186,38,224) +IMAGE_DATA(80,223,12,28,189,60,3,199,111,206,0,181,31,59,107,8,255,111,102,4,90,218,203,176,33,88,134,109,195,226,37,76) +IMAGE_DATA(236,139,50,111,226,87,244,183,44,246,121,74,188,249,125,77,252,166,90,197,255,250,77,182,217,70,70,70,114,124,157,240) +IMAGE_DATA(178,239,179,52,181,16,22,147,227,31,70,228,175,156,212,187,11,7,197,98,49,113,183,112,226,249,106,181,154,184,91,56) +IMAGE_DATA(53,56,121,87,214,97,234,198,108,120,101,157,56,142,142,142,14,52,94,244,165,97,240,179,179,179,9,142,201,20,124,32) +IMAGE_DATA(98,17,49,33,241,94,142,88,95,195,199,28,19,94,140,219,114,230,139,229,7,18,241,124,50,0,0,0,0,0,0,0) +IMAGE_END_DATA(1184, 22) diff --git a/uppsrc/VirtualGui/Gui.h b/uppsrc/VirtualGui/Gui.h new file mode 100644 index 000000000..c09221f60 --- /dev/null +++ b/uppsrc/VirtualGui/Gui.h @@ -0,0 +1,358 @@ +#define VIRTUALGUI + +NAMESPACE_UPP + +class SystemDraw : public Draw { +public: + virtual dword GetInfo() const; + virtual Size GetPageSize() const; + + virtual void BeginOp(); + virtual void EndOp(); + virtual void OffsetOp(Point p); + virtual bool ClipOp(const Rect& r); + virtual bool ClipoffOp(const Rect& r); + virtual bool ExcludeClipOp(const Rect& r); + virtual bool IntersectClipOp(const Rect& r); + virtual bool IsPaintingOp(const Rect& r) const; + virtual Rect GetPaintRect() const; + + virtual void DrawRectOp(int x, int y, int cx, int cy, Color color); + virtual void DrawImageOp(int x, int y, int cx, int cy, const Image& img, const Rect& src, Color color); + virtual void DrawLineOp(int x1, int y1, int x2, int y2, int width, Color color); + + virtual void DrawPolyPolylineOp(const Point *vertices, int vertex_count, + const int *counts, int count_count, + int width, Color color, Color doxor); + virtual void DrawPolyPolyPolygonOp(const Point *vertices, int vertex_count, + const int *subpolygon_counts, int scc, + const int *disjunct_polygon_counts, int dpcc, + Color color, int width, Color outline, + uint64 pattern, Color doxor); + virtual void DrawArcOp(const Rect& rc, Point start, Point end, int width, Color color); + + virtual void DrawEllipseOp(const Rect& r, Color color, int pen, Color pencolor); + virtual void DrawTextOp(int x, int y, int angle, const wchar *text, Font font, + Color ink, int n, const int *dx); + + virtual Size GetNativeDpi() const; + virtual void BeginNative(); + virtual void EndNative(); + + virtual int GetCloffLevel() const; + +private: + Size pageSize; + Size nativeSize; + Size nativeDpi; + bool palette:1; + bool color16:1; + bool is_mono:1; + int native; + + friend class ImageDraw; + friend class FontInfo; + friend class Font; + + friend void StaticExitDraw_(); + + Point actual_offset_bak; + + struct Cloff : Moveable { + Point org; + HRGN hrgn; + Rect drawingclip; + }; + + Array cloff; + Rect drawingclip; + + COLORREF lastTextColor; + Color lastColor; + HBRUSH orgBrush; + HBRUSH actBrush; + HPEN orgPen; + HPEN actPen; + int lastPen; + Color lastPenColor; + + void Unselect0(); + void Cinit(); + + void LoadCaps(); + void SetPrinterMode(); + void Reset(); + void SetOrg(); + friend HPALETTE GetQlibPalette(); + void DotsMode(); + + static void InitColors(); + + friend class BackDraw; + friend class ScreenDraw; + friend class PrintDraw; + +protected: + dword style; + HDC handle; + Point actual_offset; + + SystemDraw(); + void Init(); + void InitClip(const Rect& clip); + +public: + static Rect GetVirtualScreenArea(); + + static void SetAutoPalette(bool ap); + static bool AutoPalette(); + bool PaletteMode() { return palette; } + + static void Flush() { GdiFlush(); } + + COLORREF GetColor(Color color) const; + + Point GetOffset() const { return actual_offset; } + +#ifndef PLATFORM_WINCE + Point LPtoDP(Point p) const; + Point DPtoLP(Point p) const; + Rect LPtoDP(const Rect& r) const; + Rect DPtoLP(const Rect& r) const; +#endif + + void SetColor(Color color); + void SetDrawPen(int width, Color color); + + Size GetSizeCaps(int i, int j) const; + HDC BeginGdi(); + void EndGdi(); + HDC GetHandle() { return handle; } + operator HDC() const { return handle; } + void Unselect(); + void Attach(HDC ahandle) { handle = ahandle; Init(); } + HDC Detach() { Unselect(); HDC h = handle; handle = NULL; return h; } + + SystemDraw(HDC hdc); + virtual ~SystemDraw(); + + bool CanSetSurface() { return IsGui() && IsWinNT(); } +}; + +#ifndef PLATFORM_WINCE +class WinMetaFile { + Size size; + HENHMETAFILE hemf; + + void Init(); + +public: + void Attach(HENHMETAFILE emf); + HENHMETAFILE Detach(); + + void Set(const void *data, dword len); + void Set(const String& data) { Set(~data, data.GetCount()); } + + String Get() const; + + operator bool() const { return hemf; } + void SetSize(const Size& sz) { size = sz; } + Size GetSize() const { return hemf ? size : Size(0, 0); } + + void Clear(); + + void Paint(Draw& w, const Rect& r) const; + void Paint(Draw& w, int x, int y, int cx, int cy) const; + + void Serialize(Stream& s); + + void ReadClipboard(); + void WriteClipboard() const; + void Load(const char *file) { Set(LoadFile(file)); } + + WinMetaFile() { Init(); } + WinMetaFile(HENHMETAFILE hemf); + WinMetaFile(HENHMETAFILE hemf, Size sz); + WinMetaFile(const char *file); + WinMetaFile(void *data, int len); + WinMetaFile(const String& data); + + ~WinMetaFile() { Clear(); } + + HENHMETAFILE GetHEMF() const { return hemf; } +}; + +class WinMetaFileDraw : public SystemDraw { + Size size; + +public: + bool Create(HDC hdc, int cx, int cy, const char *app = NULL, const char *name = NULL, const char *file = NULL); + bool Create(int cx, int cy, const char *app = NULL, const char *name = NULL, const char *file = NULL); + WinMetaFile Close(); + + WinMetaFileDraw() {} + WinMetaFileDraw(HDC hdc, int cx, int cy, const char *app = NULL, const char *name = NULL, const char *file = NULL); + WinMetaFileDraw(int cx, int cy, const char *app = NULL, const char *name = NULL, const char *file = NULL); + ~WinMetaFileDraw(); +}; + +void DrawWMF(Draw& w, int x, int y, int cx, int cy, const String& wmf); +void DrawWMF(Draw& w, int x, int y, const String& wmf); +Drawing LoadWMF(const char *path, int cx, int cy); +Drawing LoadWMF(const char *path); + +String AsWMF(const Drawing& iw); + +#endif + +class ScreenDraw : public SystemDraw { +public: + ScreenDraw(bool ic = false); + ~ScreenDraw(); +}; + +#ifndef PLATFORM_WINCE +class PrintDraw : public SystemDraw { +public: + virtual void StartPage(); + virtual void EndPage(); + +private: + bool aborted; + + void InitPrinter(); +public: + PrintDraw(HDC hdc, const char *jobname); + ~PrintDraw(); +}; +#endif + +inline bool BitBlt(HDC ddc, Point d, HDC sdc, const Rect& s, dword rop = SRCCOPY) +{ return BitBlt(ddc, d.x, d.y, s.Width(), s.Height(), sdc, s.left, s.top, rop); } + +inline bool StretchBlt(HDC ddc, const Rect& r, HDC sdc, const Rect& s, dword rop = SRCCOPY) +{ return StretchBlt(ddc, r.left, r.top, r.Width(), r.Height(), sdc, s.left, s.top, s.Width(), s.Height(), rop); } + +inline bool PatBlt(HDC dc, const Rect& r, dword rop = PATCOPY) +{ return PatBlt(dc, r.left, r.top, r.Width(), r.Height(), rop); } + +inline void MoveTo(HDC hdc, Point pt) { MoveToEx(hdc, pt.x, pt.y, 0); } +inline void LineTo(HDC hdc, Point pt) { LineTo(hdc, pt.x, pt.y); } + +inline void DrawLine(HDC hdc, Point p, Point q) { MoveTo(hdc, p); LineTo(hdc, q); } +inline void DrawLine(HDC hdc, int px, int py, int qx, int qy) { MoveToEx(hdc, px, py, 0); LineTo(hdc, qx, qy); } + +#ifndef PLATFORM_WINCE +inline void DrawArc(HDC hdc, const Rect& rc, Point p, Point q){ Arc(hdc, rc.left, rc.top, rc.right, rc.bottom, p.x, p.y, q.x, q.y); } +#endif +inline void DrawCircle(HDC hdc, int x, int y, int radius) { Ellipse(hdc, x - radius, y - radius, x + radius + 1, y + radius + 1); } +inline void DrawCircle(HDC hdc, Point centre, int radius) { DrawCircle(hdc, centre.x, centre.y, radius); } +inline void DrawEllipse(HDC hdc, const Rect& rc) { Ellipse(hdc, rc.left, rc.top, rc.right, rc.bottom); } + +inline void DrawRect(HDC hdc, const Rect& rc) { Rectangle(hdc, rc.left, rc.top, rc.right, rc.bottom); } + +HDC ScreenHDC(); +HPALETTE GetQlibPalette(); + +Image Win32Icon(LPCSTR id, int iconsize = 0); +Image Win32Icon(int id, int iconsize = 0); +Image Win32Cursor(LPCSTR id); +Image Win32Cursor(int id); +HICON IconWin32(const Image& img, bool cursor = false); +Image Win32DllIcon(const char *dll, int ii, bool large); + +class BackDraw : public SystemDraw { +public: + virtual bool IsPaintingOp(const Rect& r) const; + +protected: + HBITMAP hbmpold; + HBITMAP hbmp; + + Size size; + Draw *painting; + Point painting_offset; + +public: + void Put(SystemDraw& w, int x, int y); + void Put(SystemDraw& w, Point p) { Put(w, p.x, p.y); } + + void Create(SystemDraw& w, int cx, int cy); + void Create(SystemDraw& w, Size sz) { Create(w, sz.cx, sz.cy); } + void Destroy(); + + void SetPaintingDraw(Draw& w, Point off) { painting = &w; painting_offset = off; } + + BackDraw(); + ~BackDraw(); +}; + +class ImageDraw : public SystemDraw { + Size size; + + struct Section { + HDC dc; + HBITMAP hbmp, hbmpOld; + RGBA *pixels; + + void Init(int cx, int cy); + ~Section(); + }; + + Section rgb; + Section a; + SystemDraw alpha; + + + bool has_alpha; + + void Init(); + Image Get(bool pm) const; + +public: + Draw& Alpha(); + + operator Image() const; + + Image GetStraight() const; + + ImageDraw(Size sz); + ImageDraw(int cx, int cy); + ~ImageDraw(); +}; + +END_UPP_NAMESPACE + +#define GUIPLATFORM_KEYCODES_INCLUDE "Win32Keys.h" + + +#define GUIPLATFORM_CTRL_TOP_DECLS \ + HWND hwnd; \ + UDropTarget *dndtgt; \ + + +#define GUIPLATFORM_CTRL_DECLS_INCLUDE "Win32Ctrl.h" + + +#define GUIPLATFORM_PASTECLIP_DECLS \ + UDropTarget *dt; \ + +#define GUIPLATFORM_TOPWINDOW_DECLS_INCLUDE "Win32Top.h" + +NAMESPACE_UPP + +inline unsigned GetHashValue(const HWND& hwnd) +{ + return (unsigned)(intptr_t)hwnd; +} +END_UPP_NAMESPACE + +#ifdef PLATFORM_WIN32 +#ifndef PLATFORM_WINCE + +#include + +#endif +#endif + +#define GUIPLATFORM_INCLUDE_AFTER "Win32GuiA.h" diff --git a/uppsrc/VirtualGui/Image.cpp b/uppsrc/VirtualGui/Image.cpp new file mode 100644 index 000000000..4eaa97666 --- /dev/null +++ b/uppsrc/VirtualGui/Image.cpp @@ -0,0 +1,47 @@ +#include + +#ifdef VIRTUALGUI + +NAMESPACE_UPP + +#define LTIMING(x) // RTIMING(x) + +void SetSurface(SystemDraw& w, int x, int y, int cx, int cy, const RGBA *pixels) +{ + GuiLock __; + // Empty as CanSetSurface is false +} + +void SetSurface(SystemDraw& w, const Rect& dest, const RGBA *pixels, Size psz, Point poff) +{ + GuiLock __; + // Empty as CanSetSurface is false +} + +#define IMAGECLASS FBImg +#define IMAGEFILE +#include + +#define STD_CURSOR(name) \ +Image Image::name() { static Image img; ONCELOCK { img = FBImg::name(); } return img; } + +STD_CURSOR(Arrow) +STD_CURSOR(Wait) +STD_CURSOR(IBeam) +STD_CURSOR(No) +STD_CURSOR(SizeAll) +STD_CURSOR(SizeHorz) +STD_CURSOR(SizeVert) +STD_CURSOR(SizeTopLeft) +STD_CURSOR(SizeTop) +STD_CURSOR(SizeTopRight) +STD_CURSOR(SizeLeft) +STD_CURSOR(SizeRight) +STD_CURSOR(SizeBottomLeft) +STD_CURSOR(SizeBottom) +STD_CURSOR(SizeBottomRight) +STD_CURSOR(Hand) + +END_UPP_NAMESPACE + +#endif diff --git a/uppsrc/VirtualGui/Keys.h b/uppsrc/VirtualGui/Keys.h new file mode 100644 index 000000000..e88a86de0 --- /dev/null +++ b/uppsrc/VirtualGui/Keys.h @@ -0,0 +1,124 @@ +//handled extra in fbKEYtoK +K_TAB = 9, //SDLK_TAB, + +K_SPACE = 32, //SDLK_SPACE, + +K_RETURN = 13, //SDLK_RETURN, +K_ENTER = K_RETURN, + +K_BACK = K_DELTA, +K_BACKSPACE, + +K_SHIFT_KEY, +K_CTRL_KEY, +K_ALT_KEY, +K_CAPSLOCK, +K_ESCAPE, +K_PAGEUP, +K_PAGEDOWN, +K_END, +K_HOME, +K_LEFT, +K_UP, +K_RIGHT, +K_DOWN, +K_INSERT, +K_DELETE, + +K_NUMPAD0, +K_NUMPAD1, +K_NUMPAD2, +K_NUMPAD3, +K_NUMPAD4, +K_NUMPAD5, +K_NUMPAD6, +K_NUMPAD7, +K_NUMPAD8, +K_NUMPAD9, +K_MULTIPLY, +K_ADD, +K_SEPARATOR, +K_SUBTRACT, +K_DECIMAL, +K_DIVIDE, +K_SCROLL, + +K_F1, +K_F2, +K_F3, +K_F4, +K_F5, +K_F6, +K_F7, +K_F8, +K_F9, +K_F10, +K_F11, +K_F12, + +K_A, +K_B, +K_C, +K_D, +K_E, +K_F, +K_G, +K_H, +K_I, +K_J, +K_K, +K_L, +K_M, +K_N, +K_O, +K_P, +K_Q, +K_R, +K_S, +K_T, +K_U, +K_V, +K_W, +K_X, +K_Y, +K_Z, +K_0, +K_1, +K_2, +K_3, +K_4, +K_5, +K_6, +K_7, +K_8, +K_9, + +K_CTRL_LBRACKET, +K_CTRL_RBRACKET, +K_CTRL_MINUS, +K_CTRL_GRAVE, +K_CTRL_SLASH, +K_CTRL_BACKSLASH, +K_CTRL_COMMA, +K_CTRL_PERIOD, +K_CTRL_SEMICOLON, +K_CTRL_EQUAL, +K_CTRL_APOSTROPHE, + +K_BREAK, // Is it really? + +K_PLUS, +K_MINUS, +K_COMMA, +K_PERIOD, +K_SEMICOLON, + +K_SLASH, +K_GRAVE, +K_LBRACKET, +K_BACKSLASH, +K_RBRACKET, +K_QUOTEDBL, + +K_PRIOR = K_PAGEUP, +K_NEXT = K_PAGEDOWN, diff --git a/uppsrc/VirtualGui/Local.h b/uppsrc/VirtualGui/Local.h new file mode 100644 index 000000000..dc50257f8 --- /dev/null +++ b/uppsrc/VirtualGui/Local.h @@ -0,0 +1,65 @@ +#include + +#ifdef VIRTUALGUI + +namespace Upp { + +class TopWindowFrame : public Ctrl { +public: + virtual void Layout(); + virtual void Paint(Draw& w); + virtual Image CursorImage(Point p, dword keyflags); + virtual void LeftDown(Point p, dword keyflags); + virtual void LeftHold(Point p, dword keyflags); + virtual void LeftDouble(Point p, dword keyflags); + virtual void MouseMove(Point p, dword keyflags); + virtual void CancelMode(); + virtual void LeftUp(Point p, dword keyflags); + +private: + Point dir; + Point startpos; + Rect startrect; + + bool maximized; + Rect overlapped; + + bool holding; + TimeCallback hold; + + Point GetDragMode(Point p); + Image GetDragImage(Point dragmode); + void StartDrag(); + Rect Margins() const; + Rect ComputeClient(Rect r); + void Hold(); + + typedef TopWindowFrame CLASSNAME; + +public: + String title; + Button close, maximize; + Image icon; + Size minsize; + bool sizeable; + TopWindow *window; + + void SetTitle(const String& s) { title = s; Refresh(); } + Rect GetClient() const; + void SetClient(Rect r); + void GripResize(); + + void Maximize(); + void Overlap(); + void ToggleMaximize(); + bool IsMaximized() const { return maximized; } + void SyncRect(); + + TopWindowFrame(); +}; + +extern VirtualGui *VirtualGuiPtr; + +} + +#endif diff --git a/uppsrc/VirtualGui/SDL2GL/Cursor.cpp b/uppsrc/VirtualGui/SDL2GL/Cursor.cpp new file mode 100644 index 000000000..4197349ab --- /dev/null +++ b/uppsrc/VirtualGui/SDL2GL/Cursor.cpp @@ -0,0 +1,70 @@ +#include "SDL2GL.h" + +namespace Upp { + +#define LLOG(x) LOG(x) +#define LDUMP(x) //DDUMP(x) + +struct RectSDL { + SDL_Rect sr; + + operator SDL_Rect *() { return &sr; } + + RectSDL(const Rect& r) + { + sr.x = r.left; + sr.y = r.top; + sr.w = r.GetWidth(); + sr.h = r.GetHeight(); + } +}; + +SDL_Texture *SDLTextureFromImage(SDL_Renderer *renderer, const Image& m) +{ + Size isz = m.GetSize(); + SDL_Texture *texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, + SDL_TEXTUREACCESS_STATIC, isz.cx, isz.cy); + if(texture) { + SDL_UpdateTexture(texture, RectSDL(isz), ~m, isz.cx * sizeof(RGBA)); + SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND); + } + return texture; +} + + +void SDL2GUI::SetMouseCursor(const Image& image) +{ + GuiLock __; + static Image fbCursorImage; + static Point fbCursorPos; + static SDL_Cursor *sdl_cursor; + static SDL_Surface *sdl_cursor_surface; + static Buffer data; + if(image.GetSerialId() != fbCursorImage.GetSerialId()) { + fbCursorImage = image; + fbCursorPos = Null; + SDL_ShowCursor(true); + if(sdl_cursor) + SDL_FreeCursor(sdl_cursor); + if(sdl_cursor_surface) + SDL_FreeSurface(sdl_cursor_surface); + int64 a = image.GetAuxData(); + if(a) + sdl_cursor = SDL_CreateSystemCursor(SDL_SystemCursor(a - 1)); + else { + sdl_cursor = NULL; + data.Alloc(image.GetLength()); + Copy(data, image, image.GetLength()); + sdl_cursor_surface = SDL_CreateRGBSurfaceFrom(~data, image.GetWidth(), image.GetHeight(), + 32, sizeof(RGBA) * image.GetWidth(), + 0xff0000, 0xff00, 0xff, 0xff000000); + Point h = image.GetHotSpot(); + if(sdl_cursor_surface) + sdl_cursor = SDL_CreateColorCursor(sdl_cursor_surface, h.x, h.y); + } + if(sdl_cursor) + SDL_SetCursor(sdl_cursor); + } +} + +} diff --git a/uppsrc/VirtualGui/SDL2GL/Draw.cpp b/uppsrc/VirtualGui/SDL2GL/Draw.cpp new file mode 100644 index 000000000..1d3d1925e --- /dev/null +++ b/uppsrc/VirtualGui/SDL2GL/Draw.cpp @@ -0,0 +1,18 @@ +#include "SDL2GL.h" + +namespace Upp { + +SystemDraw& SDL2GUI::BeginDraw() +{ + gldraw.Init(GetSize(), (uint64)glcontext); + sysdraw.SetTarget(&gldraw); + return sysdraw; +} + +void SDL2GUI::CommitDraw() +{ + gldraw.Finish(); + SDL_GL_SwapWindow(win); +} + +}; \ No newline at end of file diff --git a/uppsrc/VirtualGui/SDL2GL/Event.cpp b/uppsrc/VirtualGui/SDL2GL/Event.cpp new file mode 100644 index 000000000..ba1b8b361 --- /dev/null +++ b/uppsrc/VirtualGui/SDL2GL/Event.cpp @@ -0,0 +1,256 @@ +#include "SDL2GL.h" + +#define LLOG(x) + +namespace Upp { + +dword fbKEYtoK(dword chr) { + if(chr == SDLK_TAB) + chr = K_TAB; + else + if(chr == SDLK_SPACE) + chr = K_SPACE; + else + if(chr == SDLK_RETURN) + chr = K_RETURN; + else { + extern Tuple SDL_key_map[]; + for(int i = 0; SDL_key_map[i].a; i++) + if(chr == SDL_key_map[i].b) { + chr = SDL_key_map[i].a; + break; + } + } + if(chr == K_ALT_KEY || chr == K_CTRL_KEY || chr == K_SHIFT_KEY) + return chr; + if(GetCtrl()) chr |= K_CTRL; + if(GetAlt()) chr |= K_ALT; + if(GetShift()) chr |= K_SHIFT; + + return chr; +} + +dword lastbdowntime[8] = {0}; +dword isdblclick[8] = {0}; + +dword mouseb; +dword modkeys; +bool sdlMouseIsIn; + +bool SDL2GUI::IsMouseIn() +{ + return sdlMouseIsIn; +} + +dword SDL2GUI::GetMouseButtons() +{ + return mouseb; +} + +dword SDL2GUI::GetModKeys() +{ + return modkeys; +} + +void HandleSDLEvent(SDL_Event* event) +{ + LLOG("HandleSDLEvent " << event->type); + SDL_Event next_event; + dword keycode; + switch(event->type) { +// case SDL_ACTIVEEVENT: //SDL_ActiveEvent +// break; + case SDL_TEXTINPUT: { + //send respective keyup things as char events as well + WString text = FromUtf8(event->text.text); + for(int i = 0; i < text.GetCount(); i++) { + int c = text[i]; + if(c != 127) + Ctrl::DoKeyFB(c, 1); + } + break; + } + case SDL_KEYDOWN: + switch(event->key.keysym.sym) { + case SDLK_LSHIFT: modkeys |= KM_LSHIFT; break; + case SDLK_RSHIFT: modkeys |= KM_RSHIFT; break; + case SDLK_LCTRL: modkeys |= KM_LCTRL; break; + case SDLK_RCTRL: modkeys |= KM_RCTRL; break; + case SDLK_LALT: modkeys |= KM_LALT; break; + case SDLK_RALT: modkeys |= KM_RALT; break; + } + + keycode = fbKEYtoK((dword)event->key.keysym.sym); + + if(keycode != K_SPACE) { //dont send space on keydown + static int repeat_count; + SDL_PumpEvents(); + if(SDL_PeepEvents(&next_event, 1, SDL_PEEKEVENT, SDL_KEYDOWN, SDL_KEYDOWN) && + next_event.key.keysym.sym == event->key.keysym.sym) { + repeat_count++; // Keyboard repeat compression + break; + } + Ctrl::DoKeyFB(keycode, 1 + repeat_count); + repeat_count = 0; + } + break; + case SDL_KEYUP: //SDL_KeyboardEvent + switch(event->key.keysym.sym) { + case SDLK_LSHIFT: modkeys &= ~KM_LSHIFT; break; + case SDLK_RSHIFT: modkeys &= ~KM_RSHIFT; break; + case SDLK_LCTRL: modkeys &= ~KM_LCTRL; break; + case SDLK_RCTRL: modkeys &= ~KM_RCTRL; break; + case SDLK_LALT: modkeys &= ~KM_LALT; break; + case SDLK_RALT: modkeys &= ~KM_RALT; break; + } + + Ctrl::DoKeyFB(fbKEYtoK((dword)event->key.keysym.sym) | K_KEYUP, 1); + break; + case SDL_MOUSEMOTION: + SDL_PumpEvents(); + if(SDL_PeepEvents(&next_event, 1, SDL_PEEKEVENT, SDL_MOUSEMOTION, SDL_MOUSEMOTION) > 0) + break; // MouseMove compression + Ctrl::DoMouseFB(Ctrl::MOUSEMOVE, Point(event->motion.x, event->motion.y)); + break; + case SDL_MOUSEWHEEL: + Ctrl::DoMouseFB(Ctrl::MOUSEWHEEL, GetMousePos(), sgn(event->wheel.y) * 120); + break; + case SDL_MOUSEBUTTONDOWN: { + Point p(event->button.x, event->button.y); + int bi = event->button.button; + dword ct = SDL_GetTicks(); + if(isdblclick[bi] && (abs(int(ct) - int(lastbdowntime[bi])) < 400)) + { + switch(bi) + { + case SDL_BUTTON_LEFT: Ctrl::DoMouseFB(Ctrl::LEFTDOUBLE, p); break; + case SDL_BUTTON_RIGHT: Ctrl::DoMouseFB(Ctrl::RIGHTDOUBLE, p); break; + case SDL_BUTTON_MIDDLE: Ctrl::DoMouseFB(Ctrl::MIDDLEDOUBLE, p); break; + } + isdblclick[bi] = 0; //reset, to go ahead sending repeats + } + else + { + lastbdowntime[bi] = ct; + isdblclick[bi] = 0; //prepare for repeat + switch(bi) + { + case SDL_BUTTON_LEFT: mouseb |= (1<<0); Ctrl::DoMouseFB(Ctrl::LEFTDOWN, p); break; + case SDL_BUTTON_RIGHT: mouseb |= (1<<1); Ctrl::DoMouseFB(Ctrl::RIGHTDOWN, p); break; + case SDL_BUTTON_MIDDLE: mouseb |= (1<<2); Ctrl::DoMouseFB(Ctrl::MIDDLEDOWN, p); break; + } + } + } + break; + case SDL_MOUSEBUTTONUP: { + int bi = event->button.button; + isdblclick[bi] = 1; //indicate maybe a dblclick + + Point p(event->button.x, event->button.y); + switch(bi) + { + case SDL_BUTTON_LEFT: mouseb &= ~(1<<0); Ctrl::DoMouseFB(Ctrl::LEFTUP, p); break; + case SDL_BUTTON_RIGHT: mouseb &= ~(1<<1); Ctrl::DoMouseFB(Ctrl::RIGHTUP, p); break; + case SDL_BUTTON_MIDDLE: mouseb &= ~(1<<2); Ctrl::DoMouseFB(Ctrl::MIDDLEUP, p); break; + } + } + break; +/* case SDL_VIDEORESIZE: //SDL_ResizeEvent + { + width = event->resize.w; + height = event->resize.h; + + SDL_FreeSurface(screen); + screen = CreateScreen(width, height, bpp, videoflags); + ASSERT(screen); + Ctrl::SetFramebufferSize(Size(width, height)); + } + break; + case SDL_VIDEOEXPOSE: //SDL_ExposeEvent + break;*/ + case SDL_WINDOWEVENT: + switch (event->window.event) { + case SDL_WINDOWEVENT_SHOWN: + break; + case SDL_WINDOWEVENT_HIDDEN: + break; + case SDL_WINDOWEVENT_EXPOSED: + break; + case SDL_WINDOWEVENT_MOVED: + break; +// case SDL_WINDOWEVENT_SIZE_CHANGED: +// SDLwidth = event->window.data1; +// SDLheight = event->window.data2; +// break; + case SDL_WINDOWEVENT_RESIZED: + break; + case SDL_WINDOWEVENT_MINIMIZED: + break; + case SDL_WINDOWEVENT_MAXIMIZED: + break; + case SDL_WINDOWEVENT_RESTORED: + break; + case SDL_WINDOWEVENT_ENTER: + sdlMouseIsIn = true; + Ctrl::PaintAll(); + break; + case SDL_WINDOWEVENT_LEAVE: + sdlMouseIsIn = false; + Ctrl::PaintAll(); + break; + case SDL_WINDOWEVENT_FOCUS_GAINED: + break; + case SDL_WINDOWEVENT_FOCUS_LOST: + break; + case SDL_WINDOWEVENT_CLOSE: + break; + } + break; + case SDL_QUIT: //SDL_QuitEvent + Ctrl::EndSession(); + break; + } +} + +bool SDL2GUI::ProcessEvent(bool *quit) +{ + bool ret = false; + SDL_Event event; + if(SDL_PollEvent(&event)) { + if(event.type == SDL_QUIT && quit) + *quit = true; + HandleSDLEvent(&event); + ret = true; + } + return ret; +} + + +void SDL2GUI::WaitEvent(int ms) +{ + SDL_WaitEventTimeout(NULL, ms); +} + +bool SDL2GUI::IsWaitingEvent() +{ + SDL_PumpEvents(); + SDL_Event events; + return SDL_PeepEvents(&events, 1, SDL_PEEKEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT) > 0; +} + +SDL_TimerID waketimer_id = 0; +Uint32 WakeCb(Uint32 interval, void *param) +{ + //wake up message que, FIXME maybe it can be done better? + SDL_Event event; + event.type=SDL_USEREVENT; + SDL_PushEvent(&event); + return 0; +} + +void SDL2GUI::WakeUpGuiThread() +{ + waketimer_id = SDL_AddTimer(20, WakeCb, NULL); +} + +} diff --git a/uppsrc/VirtualGui/SDL2GL/Keys.cpp b/uppsrc/VirtualGui/SDL2GL/Keys.cpp new file mode 100644 index 000000000..6ed6bf9e2 --- /dev/null +++ b/uppsrc/VirtualGui/SDL2GL/Keys.cpp @@ -0,0 +1,133 @@ +#include "SDL2GL.h" + +namespace Upp { + +Tuple SDL_key_map[] = { +#if 0 + { K_BACK, SDLK_BACKSPACE }, + { K_BACKSPACE, SDLK_BACKSPACE }, + + //handled extra in fbKEYtoK + { K_TAB, SDLK_TAB }, + + { K_SPACE, SDLK_SPACE }, + + { K_RETURN, SDLK_RETURN }, + { K_ENTER, K_RETURN }, +#endif + + { K_SHIFT_KEY, SDLK_LSHIFT }, + { K_CTRL_KEY, SDLK_LCTRL }, + { K_ALT_KEY, SDLK_LALT }, + { K_CAPSLOCK, SDLK_CAPSLOCK }, + { K_ESCAPE, SDLK_ESCAPE }, + { K_PAGEUP, SDLK_PAGEUP }, + { K_PAGEDOWN, SDLK_PAGEDOWN }, + { K_END, SDLK_END }, + { K_HOME, SDLK_HOME }, + { K_LEFT, SDLK_LEFT }, + { K_UP, SDLK_UP }, + { K_RIGHT, SDLK_RIGHT }, + { K_DOWN, SDLK_DOWN }, + { K_INSERT, SDLK_INSERT }, + { K_DELETE, SDLK_DELETE }, + + { K_NUMPAD0, SDLK_KP_0 }, + { K_NUMPAD1, SDLK_KP_1 }, + { K_NUMPAD2, SDLK_KP_2 }, + { K_NUMPAD3, SDLK_KP_3 }, + { K_NUMPAD4, SDLK_KP_4 }, + { K_NUMPAD5, SDLK_KP_5 }, + { K_NUMPAD6, SDLK_KP_6 }, + { K_NUMPAD7, SDLK_KP_7 }, + { K_NUMPAD8, SDLK_KP_8 }, + { K_NUMPAD9, SDLK_KP_9 }, + { K_MULTIPLY, SDLK_KP_MULTIPLY }, + { K_ADD, SDLK_KP_PLUS }, + { K_SEPARATOR, SDLK_KP_PERIOD }, + { K_SUBTRACT, SDLK_KP_MINUS }, + { K_DECIMAL, SDLK_KP_PERIOD }, + { K_DIVIDE, SDLK_KP_DIVIDE }, + { K_SCROLL, SDLK_SCROLLLOCK }, + + { K_F1, SDLK_F1 }, + { K_F2, SDLK_F2 }, + { K_F3, SDLK_F3 }, + { K_F4, SDLK_F4 }, + { K_F5, SDLK_F5 }, + { K_F6, SDLK_F6 }, + { K_F7, SDLK_F7 }, + { K_F8, SDLK_F8 }, + { K_F9, SDLK_F9 }, + { K_F10, SDLK_F10 }, + { K_F11, SDLK_F11 }, + { K_F12, SDLK_F12 }, + + { K_A, SDLK_a }, + { K_B, SDLK_b }, + { K_C, SDLK_c }, + { K_D, SDLK_d }, + { K_E, SDLK_e }, + { K_F, SDLK_f }, + { K_G, SDLK_g }, + { K_H, SDLK_h }, + { K_I, SDLK_i }, + { K_J, SDLK_j }, + { K_K, SDLK_k }, + { K_L, SDLK_l }, + { K_M, SDLK_m }, + { K_N, SDLK_n }, + { K_O, SDLK_o }, + { K_P, SDLK_p }, + { K_Q, SDLK_q }, + { K_R, SDLK_r }, + { K_S, SDLK_s }, + { K_T, SDLK_t }, + { K_U, SDLK_u }, + { K_V, SDLK_v }, + { K_W, SDLK_w }, + { K_X, SDLK_x }, + { K_Y, SDLK_y }, + { K_Z, SDLK_z }, + { K_0, SDLK_0 }, + { K_1, SDLK_1 }, + { K_2, SDLK_2 }, + { K_3, SDLK_3 }, + { K_4, SDLK_4 }, + { K_5, SDLK_5 }, + { K_6, SDLK_6 }, + { K_7, SDLK_7 }, + { K_8, SDLK_8 }, + { K_9, SDLK_9 }, + + { K_CTRL_LBRACKET, K_CTRL|219 }, + { K_CTRL_RBRACKET, K_CTRL|221 }, + { K_CTRL_MINUS, K_CTRL|0xbd }, + { K_CTRL_GRAVE, K_CTRL|0xc0 }, + { K_CTRL_SLASH, K_CTRL|0xbf }, + { K_CTRL_BACKSLASH, K_CTRL|0xdc }, + { K_CTRL_COMMA, K_CTRL|0xbc }, + { K_CTRL_PERIOD, K_CTRL|0xbe }, + { K_CTRL_SEMICOLON, K_CTRL|0xbe }, + { K_CTRL_EQUAL, K_CTRL|0xbb }, + { K_CTRL_APOSTROPHE, K_CTRL|0xde }, + + { K_BREAK, SDLK_PAUSE }, // Is it really? + + { K_PLUS, SDLK_PLUS }, + { K_MINUS, SDLK_MINUS }, + { K_COMMA, SDLK_COMMA }, + { K_PERIOD, SDLK_PERIOD }, + { K_SEMICOLON, SDLK_SEMICOLON }, + + { K_SLASH, SDLK_SLASH }, + { K_GRAVE, SDLK_CARET }, + { K_LBRACKET, SDLK_LEFTBRACKET }, + { K_BACKSLASH, SDLK_BACKSLASH }, + { K_RBRACKET, SDLK_RIGHTBRACKET }, + { K_QUOTEDBL, SDLK_QUOTEDBL }, + + { 0, 0 }, +}; + +} \ No newline at end of file diff --git a/uppsrc/VirtualGui/SDL2GL/SDL2GL.h b/uppsrc/VirtualGui/SDL2GL/SDL2GL.h new file mode 100644 index 000000000..64e420510 --- /dev/null +++ b/uppsrc/VirtualGui/SDL2GL/SDL2GL.h @@ -0,0 +1,48 @@ +#ifndef _SDL2GUI_SDL2GUI_h +#define _SDL2GUI_SDL2GUI_h + +#include +#include + +#ifdef PLATFORM_POSIX +#include +#else +#include +#endif + +namespace Upp { + +struct SDL2GUI : VirtualGui { + virtual Size GetSize(); + virtual dword GetMouseButtons(); + virtual dword GetModKeys(); + virtual bool IsMouseIn(); + virtual bool ProcessEvent(bool *quit); + virtual void WaitEvent(int ms); + virtual bool IsWaitingEvent(); + virtual void WakeUpGuiThread(); + virtual void SetMouseCursor(const Image& image); + virtual SystemDraw& BeginDraw(); + virtual void CommitDraw(); + + virtual void Quit(); + + SDL_Window *win; + SDL_GLContext glcontext; + int64 serial; + GLDraw gldraw; + SystemDraw sysdraw; + + void Attach(SDL_Window *win, SDL_GLContext glcontext); + void Detach(); + + bool Create(const Rect& rect, const char *title); + void Destroy(); + + SDL2GUI(); + ~SDL2GUI(); +}; + +}; + +#endif diff --git a/uppsrc/VirtualGui/SDL2GL/SDL2GL.upp b/uppsrc/VirtualGui/SDL2GL/SDL2GL.upp new file mode 100644 index 000000000..7625dd9e7 --- /dev/null +++ b/uppsrc/VirtualGui/SDL2GL/SDL2GL.upp @@ -0,0 +1,11 @@ +uses + VirtualGui; + +file + SDL2GL.h, + Window.cpp, + Draw.cpp, + Keys.cpp, + Event.cpp, + Cursor.cpp; + diff --git a/uppsrc/VirtualGui/SDL2GL/Window.cpp b/uppsrc/VirtualGui/SDL2GL/Window.cpp new file mode 100644 index 000000000..dc1d3063b --- /dev/null +++ b/uppsrc/VirtualGui/SDL2GL/Window.cpp @@ -0,0 +1,74 @@ +#include "SDL2GL.h" + +namespace Upp { + +Size SDL2GUI::GetSize() +{ + int w, h; + SDL_GetWindowSize(win, &w, &h); + return Size(w, h); +} + +bool SDL2GUI::Create(const Rect& rect, const char *title) +{ + SDL_Init(SDL_INIT_VIDEO|SDL_INIT_TIMER); + + win = SDL_CreateWindow(title, rect.left, rect.top, rect.GetWidth(), rect.GetHeight(), + SDL_WINDOW_SHOWN|SDL_WINDOW_OPENGL|SDL_WINDOW_BORDERLESS); + if(!win) + return false; + MemoryIgnoreLeaksBegin(); + glcontext = SDL_GL_CreateContext(win); + MemoryIgnoreLeaksEnd(); + if(!glcontext) { + Destroy(); + return false; + } + return true; +} + +extern SDL_TimerID waketimer_id; + +void SDL2GUI::Destroy() +{ + if(glcontext) { + SDL_GL_DeleteContext(glcontext); + glcontext = NULL; + GLDraw::ResetCache(); + } + if(win) { + SDL_RemoveTimer(waketimer_id); + SDL_DestroyWindow(win); + win = NULL; + } +} + +void SDL2GUI::Attach(SDL_Window *win_, SDL_GLContext glcontext_) +{ + win = win_; + glcontext = glcontext_; +} + +void SDL2GUI::Detach() +{ + win = NULL; + glcontext = NULL; +} + +SDL2GUI::SDL2GUI() +{ + glcontext = NULL; + win = NULL; +} + +SDL2GUI::~SDL2GUI() +{ + Destroy(); +} + +void SDL2GUI::Quit() +{ + SDL_Quit(); +} + +} \ No newline at end of file diff --git a/uppsrc/VirtualGui/Top.cpp b/uppsrc/VirtualGui/Top.cpp new file mode 100644 index 000000000..b7e80e324 --- /dev/null +++ b/uppsrc/VirtualGui/Top.cpp @@ -0,0 +1,153 @@ +#include "Local.h" + +#ifdef VIRTUALGUI + +NAMESPACE_UPP + +#define LLOG(x) // LOG(x) + +void TopWindow::SyncFrameRect(const Rect& r) +{ + frame->SetClient(r); +} + +void TopWindow::DestroyFrame() +{ + if(frame->IsOpen()) + frame->DestroyWnd(); +} + +void TopWindow::GripResize() +{ + frame->GripResize(); +} + +void TopWindow::SyncSizeHints() +{ + SyncCaption(); +} + +void TopWindow::SyncTitle() +{ + SyncCaption(); +} + +void TopWindow::SyncCaption() +{ + GuiLock __; + frame->title = title.ToString(); + frame->minsize = minsize; + frame->close.Show(!noclosebox); + frame->maximize.Show(maximizebox); + frame->sizeable = sizeable; + frame->RefreshLayout(); + frame->Refresh(); + frame->close ^= [=] { WhenClose(); }; + frame->icon = icon; + frame->Enable(IsEnabled()); +} + +void TopWindow::State(int reason) +{ + SyncCaption(); +} + +void TopWindow::SyncRect() +{ + frame->SyncRect(); + Rect r = frame->GetClient(); + if(r != GetRect()) + SetRect(r); +} + +void TopWindow::Open(Ctrl *owner) +{ + GuiLock __; + LLOG("Open " << Upp::Name(owner)); + Rect r = GetRect(); + if(r.IsEmpty()) + SetRect(GetDefaultWindowRect()); + else + if(r.left == 0 && r.top == 0) + if(owner && center == 1) + SetRect(owner->GetRect().CenterRect(r.GetSize())); + else + if(center) + SetRect(GetWorkArea().CenterRect(r.GetSize())); + frame->SetClient(GetRect()); + frame->window = this; + frame->PopUp(owner, false, true); + PopUp(frame, false, true); + popup = false; + if(fullscreen) + SetRect(GetWorkArea()); + else + SetRect(frame->GetClient()); + SyncCaption(); + if(state == MAXIMIZED) + frame->Maximize(); +} + +void TopWindow::Open() +{ + Open(GetActiveCtrl()); +} + +void TopWindow::OpenMain() +{ + Open(NULL); +} + +void TopWindow::Minimize(bool effect) +{ +// state = MINIMIZED; +} + +TopWindow& TopWindow::FullScreen(bool b) +{ + fullscreen = true; + return *this; +} + +void TopWindow::Maximize(bool effect) +{ + state = MAXIMIZED; + frame->Maximize(); +} + +void TopWindow::Overlap(bool effect) +{ + GuiLock __; + state = OVERLAPPED; + frame->Overlap(); +} + +TopWindow& TopWindow::TopMost(bool b, bool stay_top) +{ + GuiLock __; + return *this; +} + +bool TopWindow::IsTopMost() const +{ + return true; +} + +void TopWindow::GuiPlatformConstruct() +{ + frame = new TopWindowFrame; +} + +void TopWindow::GuiPlatformDestruct() +{ + delete frame; +} + +void TopWindow::SerializePlacement(Stream& s, bool reminimize) +{ + GuiLock __; +} + +END_UPP_NAMESPACE + +#endif diff --git a/uppsrc/VirtualGui/Top.h b/uppsrc/VirtualGui/Top.h new file mode 100644 index 000000000..2e9b12c16 --- /dev/null +++ b/uppsrc/VirtualGui/Top.h @@ -0,0 +1,16 @@ +//$ class TopWindow { +public: + virtual void State(int reason); + +private: + TopWindowFrame *frame; + + void SyncRect(); + void SyncFrameRect(const Rect& r); + void DestroyFrame(); + + friend class Ctrl; + +public: + void GripResize(); +//$ }; diff --git a/uppsrc/VirtualGui/TopFrame.cpp b/uppsrc/VirtualGui/TopFrame.cpp new file mode 100644 index 000000000..7c85b2b5f --- /dev/null +++ b/uppsrc/VirtualGui/TopFrame.cpp @@ -0,0 +1,236 @@ +#include "Local.h" + +#ifdef VIRTUALGUI + +NAMESPACE_UPP + +#define LLOG(x) // LOG(x) +#define LDUMP(x) //DDUMP(x) + +TopWindowFrame::TopWindowFrame() +{ + close.SetImage(FBImg::close()); + close.EdgeStyle(); + Add(close); + maximize.SetImage(FBImg::maximize()); + maximize.EdgeStyle(); + Add(maximize); + maximize <<= THISBACK(ToggleMaximize); + maximized = false; + sizeable = false; + holding = false; +} + +void TopWindowFrame::SyncRect() +{ + if(maximized) { + Size sz = GetWorkArea().GetSize(); + if(GetRect().GetSize() != sz) + SetRect(sz); + } +} + +void TopWindowFrame::Maximize() +{ + if(!maximized && maximize.IsShown()) { + maximized = true; + overlapped = GetRect(); + SetRect(GetWorkArea().GetSize()); + maximize.SetImage(FBImg::overlap()); + } +} + +void TopWindowFrame::Overlap() +{ + if(maximized && maximize.IsShown()) { + maximized = false; + SetRect(overlapped); + maximize.SetImage(FBImg::maximize()); + } +} + +void TopWindowFrame::ToggleMaximize() +{ + if(maximized) + Overlap(); + else + Maximize(); +} + +Rect TopWindowFrame::Margins() const +{ + return maximized ? Rect(0, 0, 0, 0) : ChMargins(FBImg::border()); +} + +void TopWindowFrame::Paint(Draw& w) +{ + Size sz = GetSize(); + Rect m = Margins(); + int c = GetStdFontCy() + 4; + ChPaintEdge(w, sz, FBImg::border()); + ChPaint(w, m.left, m.top, sz.cx - m.left - m.right, GetStdFontCy() + 4, + window->IsForeground() ? FBImg::title() : FBImg::bgtitle()); + int tx = m.left + 2; + int tcx = sz.cx - m.left - m.right - 4 - c * (close.IsShown() + maximize.IsShown()); + if(!IsNull(icon)) { + Image h = icon; + if(h.GetWidth() > c || h.GetHeight() > c) + h = Rescale(h, GetFitSize(h.GetSize(), Size(c))); + w.DrawImage(tx, m.top + 2, h); + tx += c; + tcx -= c; + } + DrawTextEllipsis(w, tx, m.top + 2, tcx, title, "..", StdFont(), SColorHighlightText()); +} + +void TopWindowFrame::Layout() +{ + Size sz = GetSize(); + Rect m = Margins(); + int c = GetStdFontCy() + 4; + int x = sz.cx - m.right; + if(close.IsShown()) + close.SetRect(x -= c, m.top, c, c); + if(maximize.IsShown()) + maximize.SetRect(x -= c, m.top, c, c); +} + +Rect TopWindowFrame::GetClient() const +{ + Rect r = GetRect(); + Rect m = Margins(); + r.left += m.left; + r.right -= m.right; + r.top += m.top; + r.bottom -= m.bottom; + r.top += GetStdFontCy() + 4; + return r; +} + +Rect TopWindowFrame::ComputeClient(Rect r) +{ + Rect m = Margins(); + r.left -= m.left; + r.right += m.right; + r.top -= m.top; + r.bottom += m.bottom; + r.top -= GetStdFontCy() + 4; + return r; +} + +void TopWindowFrame::SetClient(Rect r) +{ + SetRect(ComputeClient(r)); +} + +Point TopWindowFrame::GetDragMode(Point p) +{ + Size sz = GetSize(); + Rect m = ChMargins(FBImg::border()); + Point dir; + dir.y = p.y < m.top ? -1 : p.y > sz.cy - m.top ? 1 : 0; + dir.x = p.x < m.left ? -1 : p.x > sz.cx - m.right ? 1 : 0; + return dir; +} + +void TopWindowFrame::StartDrag() +{ + if(maximized) + return; + if(!sizeable && (dir.x || dir.y)) + return; + SetCapture(); + startrect = GetRect(); + startpos = GetMousePos(); + LLOG("START DRAG ---------------"); +} + +void TopWindowFrame::GripResize() +{ + dir = Point(1, 1); + StartDrag(); +} + +void TopWindowFrame::LeftDown(Point p, dword keyflags) +{ + dir = GetDragMode(p); + StartDrag(); +} + +void TopWindowFrame::CancelMode() +{ + holding = false; +} + +void TopWindowFrame::LeftUp(Point p, dword keyflags) +{ + holding = false; +} + +void TopWindowFrame::Hold() +{ + if(HasCapture()) { + if(HasMouse() && GetMouseLeft() && holding) + StartDrag(); + ReleaseCapture(); + holding = false; + } +} + +void TopWindowFrame::LeftHold(Point p, dword keyflags) +{ +/* if(HasCapture() || FullWindowDrag) + return; + dir = GetDragMode(p); + if(!dir.x && !dir.y) + StartDrag();*/ +} + +void TopWindowFrame::LeftDouble(Point p, dword keyflags) +{ + ToggleMaximize(); + IgnoreMouseUp(); +} + +void TopWindowFrame::MouseMove(Point, dword) +{ + LDUMP(HasWndCapture()); + LDUMP(HasCapture()); + if(!HasCapture() || holding) + return; + Size msz = ComputeClient(minsize).GetSize(); + Point p = GetMousePos() - startpos; + Rect r = startrect; + if(dir.x == -1) + r.left = min(r.left + p.x, startrect.right - msz.cx); + if(dir.x == 1) + r.right = max(r.right + p.x, startrect.left + msz.cx); + if(dir.y == -1) + r.top = min(r.top + p.y, startrect.bottom - msz.cy); + if(dir.y == 1) + r.bottom = max(r.bottom + p.y, startrect.top + msz.cy); + if(dir.y == 0 && dir.x == 0) + r.Offset(p); + SetRect(r); +} + +Image TopWindowFrame::GetDragImage(Point dir) +{ + static Image (*im[9])() = { + Image::SizeTopLeft, Image::SizeLeft, Image::SizeBottomLeft, + Image::SizeTop, Image::Arrow, Image::SizeBottom, + Image::SizeTopRight, Image::SizeRight, Image::SizeBottomRight, + }; + return (*im[(dir.x + 1) * 3 + (dir.y + 1)])(); +} + +Image TopWindowFrame::CursorImage(Point p, dword) +{ + if(!sizeable) + return Image::Arrow(); + return GetDragImage(HasCapture() ? dir : GetDragMode(p)); +} + +END_UPP_NAMESPACE + +#endif diff --git a/uppsrc/VirtualGui/VirtualGui.h b/uppsrc/VirtualGui/VirtualGui.h new file mode 100644 index 000000000..0d80351e1 --- /dev/null +++ b/uppsrc/VirtualGui/VirtualGui.h @@ -0,0 +1,127 @@ +#ifdef PLATFORM_POSIX +#include +#endif + +namespace Upp { + +#define IMAGECLASS FBImg +#define IMAGEFILE +#include + +class SystemDraw : public DrawProxy { +public: + bool CanSetSurface() { return false; } + static void Flush() {} +}; + +enum KM { + KM_NONE = 0x00, + + KM_LSHIFT= 0x01, + KM_RSHIFT= 0x02, + KM_LCTRL = 0x04, + KM_RCTRL = 0x08, + KM_LALT = 0x10, + KM_RALT = 0x20, + + KM_CAPS = 0x40, + KM_NUM = 0x80, + + KM_CTRL = KM_LCTRL | KM_RCTRL, + KM_SHIFT = KM_LSHIFT | KM_RSHIFT, + KM_ALT = KM_LALT | KM_RALT, +}; + +struct VirtualGui { + virtual Size GetSize() = 0; + virtual dword GetMouseButtons() = 0; + virtual dword GetModKeys() = 0; + virtual bool IsMouseIn() = 0; + virtual bool ProcessEvent(bool *quit) = 0; + virtual void WaitEvent(int ms) = 0; + virtual void WakeUpGuiThread() = 0; + virtual void SetMouseCursor(const Image& image) = 0; + virtual void Quit() = 0; + virtual bool IsWaitingEvent() = 0; + virtual SystemDraw& BeginDraw() = 0; + virtual void CommitDraw() = 0; +}; + +void RunVirtualGui(VirtualGui *gui, Event<> app_main); + +struct BackDraw__ : public SystemDraw { + BackDraw__() : SystemDraw() {} +}; + +class BackDraw : public BackDraw__ { // Dummy only, as we are running in GlobalBackBuffer mode + Size size; + Draw *painting; + Point painting_offset; + ImageBuffer ib; + +public: + virtual bool IsPaintingOp(const Rect& r) const; + +public: + void Put(SystemDraw& w, int x, int y) {} + void Put(SystemDraw& w, Point p) { Put(w, p.x, p.y); } + + void Create(SystemDraw& w, int cx, int cy) {} + void Create(SystemDraw& w, Size sz) { Create(w, sz.cx, sz.cy); } + void Destroy() {} + + void SetPaintingDraw(Draw& w, Point off) { painting = &w; painting_offset = off; } + + Point GetOffset() const { return Point(0, 0); } + + BackDraw(); + ~BackDraw(); +}; + +class ImageDraw : public SImageDraw { // using software renderer +public: + ImageDraw(Size sz) : SImageDraw(sz) {} + ImageDraw(int cx, int cy) : SImageDraw(cx, cy) {} +}; + +void DrawDragRect(SystemDraw& w, const Rect& rect1, const Rect& rect2, const Rect& clip, int n, + Color color, uint64 pattern); + +class TopWindowFrame; + +#define GUIPLATFORM_CTRL_TOP_DECLS Ctrl *owner_window; + +#define GUIPLATFORM_CTRL_DECLS_INCLUDE + +#define GUIPLATFORM_PASTECLIP_DECLS \ + bool dnd; \ + friend struct DnDLoop; \ + +#define GUIPLATFORM_TOPWINDOW_DECLS_INCLUDE + +class PrinterJob { // Dummy only... + NilDraw nil; + Vector pages; + +public: + Draw& GetDraw() { return nil; } + operator Draw&() { return GetDraw(); } + const Vector& GetPages() const { return pages; } + int operator[](int i) const { return 0; } + int GetPageCount() const { return 0; } + + bool Execute() { return false; } + + PrinterJob& Landscape(bool b = true) { return *this; } + PrinterJob& MinMaxPage(int minpage, int maxpage) { return *this; } + PrinterJob& PageCount(int n) { return *this; } + PrinterJob& CurrentPage(int currentpage) { return *this; } + PrinterJob& Name(const char *_name) { return *this; } + + PrinterJob(const char *name = NULL) {} + ~PrinterJob() {} +}; + +} + +#define GUIPLATFORM_INCLUDE_AFTER diff --git a/uppsrc/VirtualGui/VirtualGui.upp b/uppsrc/VirtualGui/VirtualGui.upp new file mode 100644 index 000000000..38abb8e45 --- /dev/null +++ b/uppsrc/VirtualGui/VirtualGui.upp @@ -0,0 +1,32 @@ +description "SlaveGui backend\377"; + +uses + Painter, + CtrlLib, + GLDraw, + PdfDraw; + +library(POSIX) "SDL2 SDL2main GL"; + +library(WIN32) "SDL2.lib SDL2main.lib OpenGL32.lib"; + +file + Local.h, + VirtualGui.h, + main.conf, + Keys.h, + After.h, + Image.cpp, + FB.iml, + Ctrl.h, + DrawDragRect.cpp, + Ctrl.cpp, + Wnd.cpp, + Event.cpp, + Top.h, + TopFrame.cpp, + Top.cpp, + Clip.cpp, + DnD.cpp, + ChSysInit.cpp; + diff --git a/uppsrc/VirtualGui/Wnd.cpp b/uppsrc/VirtualGui/Wnd.cpp new file mode 100644 index 000000000..f51332e7d --- /dev/null +++ b/uppsrc/VirtualGui/Wnd.cpp @@ -0,0 +1,550 @@ +#include "Local.h" + +#ifdef VIRTUALGUI + +NAMESPACE_UPP + +#define LLOG(x) LOG(x) +#define LDUMP(x) //DDUMP(x) +#define LDUMPC(x) //DDUMPC(x) +#define LTIMING(x) RTIMING(x) + +VirtualGui *VirtualGuiPtr; + +Ptr Ctrl::desktop; +Vector Ctrl::topctrl; + +bool Ctrl::invalid; + +Point Ctrl::fbCursorPos = Null; +Image Ctrl::fbCursorImage; +Rect Ctrl::fbCaretRect; +int Ctrl::fbCaretTm; +bool Ctrl::fbEndSession; +int Ctrl::PaintLock; + +bool Ctrl::SystemCursor; + +int Ctrl::FindTopCtrl() const +{ + for(int i = 0; i < topctrl.GetCount(); i++) + if(this == topctrl[i]) + return i; + return -1; +} + +bool Ctrl::IsAlphaSupported() +{ + return false; +} + +bool Ctrl::IsCompositedGui() +{ + return false; +} + +Vector Ctrl::GetTopCtrls() +{ + Vector ctrl; + if(desktop) + ctrl.Add(desktop); + for(int i = 0; i < topctrl.GetCount(); i++) + if(!dynamic_cast(topctrl[i])) + ctrl.Add(topctrl[i]); + return ctrl; +} + +Ctrl *Ctrl::GetOwner() +{ + GuiLock __; + int q = FindTopCtrl(); + if(q > 0 && topctrl[q]->top) { + Ctrl *x = topctrl[q]->top->owner_window; + LDUMP(Upp::Name(x)); + return dynamic_cast(x) ? x->GetOwner() : x; + } + return NULL; +} + +Ctrl *Ctrl::GetActiveCtrl() +{ + GuiLock __; + return focusCtrl ? focusCtrl->GetTopCtrl() : NULL; +} + +// Vector Ctrl::hotkey; + +int Ctrl::RegisterSystemHotKey(dword key, Function cb) +{ +/* ASSERT(key >= K_DELTA); + int q = hotkey.GetCount(); + for(int i = 0; i < hotkey.GetCount(); i++) + if(!hotkey[i]) { + q = i; + break; + } + hotkey.At(q) = cb; + dword mod = 0; + if(key & K_ALT) + mod |= MOD_ALT; + if(key & K_SHIFT) + mod |= MOD_SHIFT; + if(key & K_CTRL) + mod |= MOD_CONTROL; + + return RegisterHotKey(NULL, q, mod, key & 0xffff) ? q : -1;*/ + return -1; +} + +void Ctrl::UnregisterSystemHotKey(int id) +{ +/* if(id >= 0 && id < hotkey.GetCount()) { + UnregisterHotKey(NULL, id); + hotkey[id].Clear(); + }*/ +} + +bool Ctrl::IsWaitingEvent() +{ + return VirtualGuiPtr->IsWaitingEvent(); +} + +void Ctrl::SyncTopWindows() +{ + for(int i = 0; i < topctrl.GetCount(); i++) { + TopWindow *w = dynamic_cast(topctrl[i]); + if(w) + w->SyncRect(); + } +} + +/* +ViewDraw::ViewDraw(Ctrl *ctrl) +{ + if(Ctrl::invalid) + Ctrl::DoPaint(); + Ctrl::invalid = false; + Ctrl::RemoveCursor(); + Ctrl::RemoveCaret(); + Rect r = ctrl->GetScreenView(); + Ctrl::invalid.Add(r); + Ctrl::AddUpdate(r); + for(int i = max(ctrl->GetTopCtrl()->FindTopCtrl() + 1, 0); i < Ctrl::topctrl.GetCount(); i++) { + Rect rr = Ctrl::topctrl[i]->GetScreenRect(); + ExcludeClip(rr); + Subtract(Ctrl::invalid, rr); + } + Offset(r.TopLeft()); +} + +ViewDraw::~ViewDraw() +{ + Ctrl::DoUpdate(); +} +*/ + +Rect Ctrl::GetClipBound(const Vector& inv, const Rect& r) +{ + Rect ri = Null; + for(int j = 0; j < inv.GetCount(); j++) { + Rect rr = inv[j] & r; + if(!rr.IsEmpty()) + ri = IsNull(ri) ? rr : rr | ri; + } + return ri; +} + +void Ctrl::PaintScene(SystemDraw& draw) +{ + if(!desktop) + return; + LLOG("@ DoPaint"); + LTIMING("DoPaint paint"); + draw.Begin(); + Vector invalid; + invalid.Add(VirtualGuiPtr->GetSize()); + for(int i = topctrl.GetCount() - 1; i >= 0; i--) { + Rect r = topctrl[i]->GetRect(); + Rect ri = GetClipBound(invalid, r); + if(!IsNull(ri)) { + draw.Clipoff(r); + topctrl[i]->UpdateArea(draw, ri - r.TopLeft()); + draw.End(); + Subtract(invalid, r); + draw.ExcludeClip(r); + } + } + Rect ri = GetClipBound(invalid, desktop->GetRect().GetSize()); + if(!IsNull(ri)) + desktop->UpdateArea(draw, ri); + draw.End(); +} + +void Ctrl::PaintCaretCursor(SystemDraw& draw) +{ + if(!IsNull(fbCaretRect)) + draw.DrawRect(fbCaretRect, InvertColor); + if(VirtualGuiPtr->IsMouseIn() && !SystemCursor) + draw.DrawImage(fbCursorPos.x, fbCursorPos.y, fbCursorImage); +} + +void Ctrl::DoPaint() +{ + if(!PaintLock) { + if(invalid && desktop) { + invalid = false; + SystemDraw& draw = VirtualGuiPtr->BeginDraw(); + PaintScene(draw); + PaintCaretCursor(draw); + VirtualGuiPtr->CommitDraw(); + } + } +} + +void Ctrl::WndUpdate(const Rect&) +{ + GuiLock __; + Invalidate(); + DoPaint(); +} + +Rect Ctrl::GetWndScreenRect() const +{ + GuiLock __; + return GetRect(); +} + +void Ctrl::WndShow(bool b) +{ + GuiLock __; +} + +void Ctrl::WndUpdate() +{ + GuiLock __; +} + +bool Ctrl::IsWndOpen() const { + GuiLock __; + return FindTopCtrl() >= 0 || this == desktop; +} + +void Ctrl::SetAlpha(byte alpha) +{ + GuiLock __; +} + +Rect Ctrl::GetWorkArea() const +{ + GuiLock __; + return GetVirtualScreenArea(); +} + +void Ctrl::GetWorkArea(Array& rc) +{ + GuiLock __; + Array r; + r.Add(GetVirtualScreenArea()); +} + +Rect Ctrl::GetVirtualWorkArea() +{ + return GetVirtualScreenArea(); +} +/* +Rect Ctrl::GetWorkArea(Point pt) +{ + return GetVirtualScreenArea(); +} +*/ +Rect Ctrl::GetVirtualScreenArea() +{ + GuiLock __; + DDUMP(desktop->GetRect()); + return desktop ? desktop->GetRect() : Rect(0, 0, 0, 0); +} + +Rect Ctrl::GetPrimaryWorkArea() +{ + return GetVirtualScreenArea(); +} + +Rect Ctrl::GetPrimaryScreenArea() +{ + return GetVirtualScreenArea(); +} + +int Ctrl::GetKbdDelay() +{ + GuiLock __; + return 500; +} + +int Ctrl::GetKbdSpeed() +{ + GuiLock __; + return 1000 / 32; +} + +void Ctrl::DestroyWnd() +{ + for(int i = 0; i < topctrl.GetCount(); i++) + if(topctrl[i]->top && topctrl[i]->top->owner_window == this) + topctrl[i]->WndDestroy(); + int q = FindTopCtrl(); + if(q >= 0) { + Invalidate(); + topctrl.Remove(q); + } + if(top) { + delete top; + top = NULL; + } + isopen = false; + TopWindow *win = dynamic_cast(this); + if(win) + win->DestroyFrame(); +} + +void Ctrl::WndDestroy() +{ + DestroyWnd(); + if(topctrl.GetCount()) + topctrl.Top()->ActivateWnd(); +} + +void Ctrl::PutForeground() +{ + int q = FindTopCtrl(); + if(q >= 0) { + Invalidate(); + topctrl.Remove(q); + topctrl.Add(this); + } + Vector< Ptr > fw; + for(int i = 0; i < topctrl.GetCount(); i++) + if(topctrl[i] && topctrl[i]->top && topctrl[i]->top->owner_window == this && topctrl[i] != this) + fw.Add(topctrl[i]); + for(int i = 0; i < fw.GetCount(); i++) + if(fw[i]) + fw[i]->PutForeground(); +} + +void Ctrl::SetWndForeground() +{ + GuiLock __; + ASSERT(IsOpen()); + if(IsWndForeground()) + return; + Ctrl *to = this; + while(to->top && to->top->owner_window) + to = to->top->owner_window; + to->PutForeground(); + if(this != focusCtrl) + ActivateWnd(); +} + +bool Ctrl::IsWndForeground() const +{ + GuiLock __; + bool b = false; + for(int i = 0; i < topctrl.GetCount(); i++) { + const TopWindow *tw = dynamic_cast(topctrl[i]); + if(tw) + b = tw == this; + } + return b; +} + +void Ctrl::WndEnable(bool) +{ + GuiLock __; +} + +bool Ctrl::SetWndFocus() +{ + GuiLock __; + return true; +} + +bool Ctrl::HasWndFocus() const +{ + GuiLock __; + return focusCtrl && focusCtrl->GetTopCtrl() == this; +} + +bool Ctrl::SetWndCapture() +{ + GuiLock __; + ASSERT(IsMainThread()); + return true; +} + +bool Ctrl::ReleaseWndCapture() +{ + GuiLock __; + ASSERT(IsMainThread()); + return true; +} + +bool Ctrl::HasWndCapture() const +{ + GuiLock __; + return captureCtrl && captureCtrl->GetTopCtrl() == this; +} + +void Ctrl::WndInvalidateRect(const Rect&) +{ + GuiLock __; + Invalidate(); +} + +void Ctrl::WndSetPos(const Rect& rect) +{ + GuiLock __; + TopWindow *w = dynamic_cast(this); + if(w) + w->SyncFrameRect(rect); + Invalidate(); + SetWndRect(rect); +} + +void Ctrl::WndScrollView(const Rect& r, int dx, int dy) +{ + GuiLock __; + LLOG("ScrollView " << rect); + WndInvalidateRect(r); +} + +void Ctrl::PopUp(Ctrl *owner, bool savebits, bool activate, bool dropshadow, bool topmost) +{ + ASSERT(!IsChild() && !IsOpen() && FindTopCtrl() < 0); + NewTop(); + if(owner) { + Ctrl *owner_window = owner->GetTopWindow(); + if(!owner_window) + owner_window = owner->GetTopCtrl(); + ASSERT(owner_window->IsOpen()); + if(owner_window != desktop) { + owner_window->SetForeground(); + top->owner_window = owner_window; + } + } + topctrl.Add(this); + popup = isopen = true; + RefreshLayoutDeep(); + if(activate) SetFocusWnd(); + Invalidate(); +} + +Rect Ctrl::GetDefaultWindowRect() { + GuiLock __; + static int ii = 0; + Rect rect = GetVirtualScreenArea(); + Size sz = rect.GetSize(); + rect.Deflate(sz / 10); + rect.Offset(Size(GetStdFontCy(), 2 * GetStdFontCy()) * (++ii % 8)); + return rect; +} + +Vector SplitCmdLine__(const char *cmd) +{ + Vector out; + while(*cmd) + if((byte)*cmd <= ' ') + cmd++; + else if(*cmd == '\"') { + WString quoted; + while(*++cmd && (*cmd != '\"' || *++cmd == '\"')) + quoted.Cat(FromSystemCharset(String(cmd, 1)).ToWString()); + out.Add(quoted); + } + else { + const char *begin = cmd; + while((byte)*cmd > ' ') + cmd++; + out.Add(String(begin, cmd).ToWString()); + } + return out; +} + +void Ctrl::InstallPanicBox() +{ +} + +void Ctrl::SysEndLoop() +{ +} + +void Ctrl::DeleteDesktopTop() +{ + if(desktop && desktop->top) { + DLOG("delete desktop->top " << desktop->top); + delete desktop->top; + desktop->top = NULL; + } +} + +void Ctrl::SetDesktop(Ctrl& q) +{ + DLOG("SetDesktop " << &q); + DeleteDesktopTop(); + desktop = &q; + desktop->SetOpen(true); + desktop->NewTop(); + invalid = true; + if(VirtualGuiPtr) + SetDesktopSize(VirtualGuiPtr->GetSize()); +} + +void Ctrl::SetDesktopSize(Size sz) +{ + if(desktop) + desktop->SetRect(sz); + invalid = true; + SyncTopWindows(); +} + +void Ctrl::InitFB() +{ + Ctrl::GlobalBackBuffer(); + Ctrl::InitTimer(); + + SetStdFont(ScreenSans(12)); + ChStdSkin(); + + static StaticRect x; + x.Color(Cyan()); + SetDesktop(x); +} + +void Ctrl::EndSession() +{ + GuiLock __; + LLOG("Ctrl::EndSession"); + fbEndSession = true; + EndSessionLoopNo = EventLoopNo; +} + +void Ctrl::ExitFB() +{ + TopWindow::ShutdownWindows(); + Ctrl::CloseTopCtrls(); + DeleteDesktopTop(); + if(fbEndSession) + VirtualGuiPtr->Quit(); + VirtualGuiPtr = NULL; +} + +void RunVirtualGui(VirtualGui *gui, Event<> app_main) +{ + VirtualGuiPtr = gui; + Ctrl::InitFB(); + Ctrl::SetDesktopSize(gui->GetSize()); + app_main(); + Ctrl::ExitFB(); +} + +END_UPP_NAMESPACE + +#endif diff --git a/uppsrc/VirtualGui/main.conf b/uppsrc/VirtualGui/main.conf new file mode 100644 index 000000000..f40e6fcfd --- /dev/null +++ b/uppsrc/VirtualGui/main.conf @@ -0,0 +1 @@ +#define VIRTUALGUI 1