mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-05-15 14:16:07 -06:00
Input Method support (Win32, MacOS, Linux)
This commit is contained in:
parent
7ec93f4a40
commit
21eebae3db
28 changed files with 523 additions and 52 deletions
|
|
@ -1,11 +1,14 @@
|
|||
template <class Range>
|
||||
using ValueTypeOf = typename std::remove_reference<decltype(*((typename std::remove_reference<Range>::type *)0)->begin())>::type;
|
||||
template <class T>
|
||||
T *DeclPtr__();
|
||||
|
||||
template <class Range>
|
||||
using IteratorOf = decltype(((typename std::remove_reference<Range>::type *)0)->begin());
|
||||
using ValueTypeOf = typename std::remove_reference<decltype(*DeclPtr__<typename std::remove_reference<Range>::type>()->begin())>::type;
|
||||
|
||||
template <class Range>
|
||||
using ConstIteratorOf = decltype(((const typename std::remove_reference<Range>::type *)0)->begin());
|
||||
using IteratorOf = decltype(DeclPtr__<typename std::remove_reference<Range>::type>()->begin());
|
||||
|
||||
template <class Range>
|
||||
using ConstIteratorOf = decltype(DeclPtr__<const typename std::remove_reference<Range>::type>()->begin());
|
||||
|
||||
template <class I>
|
||||
class SubRangeClass {
|
||||
|
|
@ -16,7 +19,7 @@ public:
|
|||
typedef typename std::remove_reference<decltype(*l)>::type value_type;
|
||||
|
||||
int GetCount() const { return count; }
|
||||
|
||||
|
||||
SubRangeClass& Write() { return *this; }
|
||||
|
||||
value_type& operator[](int i) const { ASSERT(i >= 0 && i < count); return l[i]; }
|
||||
|
|
@ -61,15 +64,15 @@ template <class T>
|
|||
struct ConstRangeClass {
|
||||
T value;
|
||||
int count;
|
||||
|
||||
|
||||
typedef T value_type;
|
||||
typedef value_type ValueType;
|
||||
|
||||
|
||||
const value_type& operator[](int i) const { return value; }
|
||||
int GetCount() const { return count; }
|
||||
|
||||
|
||||
typedef ConstIIterator<ConstRangeClass> Iterator;
|
||||
|
||||
|
||||
Iterator begin() const { return Iterator(*this, 0); }
|
||||
Iterator end() const { return Iterator(*this, count); }
|
||||
|
||||
|
|
@ -102,14 +105,14 @@ ConstRangeClass<T> ConstRange(int count)
|
|||
template <class BaseRange>
|
||||
struct ReverseRangeClass {
|
||||
typename std::remove_reference<BaseRange>::type& r;
|
||||
|
||||
|
||||
typedef ValueTypeOf<BaseRange> value_type;
|
||||
typedef value_type ValueType;
|
||||
|
||||
|
||||
const value_type& operator[](int i) const { return r[r.GetCount() - i - 1]; }
|
||||
value_type& operator[](int i) { return r[r.GetCount() - i - 1]; }
|
||||
int GetCount() const { return r.GetCount(); }
|
||||
|
||||
|
||||
typedef IIterator<ReverseRangeClass> Iterator;
|
||||
typedef ConstIIterator<ReverseRangeClass> ConstIterator;
|
||||
|
||||
|
|
@ -117,7 +120,7 @@ struct ReverseRangeClass {
|
|||
|
||||
ConstIterator begin() const { return ConstIterator(*this, 0); }
|
||||
ConstIterator end() const { return ConstIterator(*this, r.GetCount()); }
|
||||
|
||||
|
||||
Iterator begin() { return Iterator(*this, 0); }
|
||||
Iterator end() { return Iterator(*this, r.GetCount()); }
|
||||
|
||||
|
|
@ -144,14 +147,14 @@ template <class BaseRange>
|
|||
struct ViewRangeClass {
|
||||
typename std::remove_reference<BaseRange>::type *r;
|
||||
Vector<int> ndx;
|
||||
|
||||
|
||||
typedef ValueTypeOf<BaseRange> value_type;
|
||||
typedef value_type ValueType;
|
||||
|
||||
|
||||
const value_type& operator[](int i) const { return (*r)[ndx[i]]; }
|
||||
value_type& operator[](int i) { return (*r)[ndx[i]]; }
|
||||
int GetCount() const { return ndx.GetCount(); }
|
||||
|
||||
|
||||
typedef IIterator<ViewRangeClass> Iterator;
|
||||
typedef ConstIIterator<ViewRangeClass> ConstIterator;
|
||||
|
||||
|
|
@ -159,7 +162,7 @@ struct ViewRangeClass {
|
|||
|
||||
ConstIterator begin() const { return ConstIterator(*this, 0); }
|
||||
ConstIterator end() const { return ConstIterator(*this, ndx.GetCount()); }
|
||||
|
||||
|
||||
Iterator begin() { return Iterator(*this, 0); }
|
||||
Iterator end() { return Iterator(*this, ndx.GetCount()); }
|
||||
|
||||
|
|
@ -198,4 +201,4 @@ template <class BaseRange>
|
|||
ViewRangeClass<BaseRange> SortedRange(BaseRange&& r)
|
||||
{
|
||||
return ViewRangeClass<BaseRange>(r, GetSortOrder(r));
|
||||
}
|
||||
}
|
||||
|
|
@ -323,8 +323,11 @@ public:
|
|||
void pop_back() { Drop(); } \
|
||||
|
||||
|
||||
template <class T>
|
||||
T *DeclPtr__();
|
||||
|
||||
template <class Range>
|
||||
using ValueTypeOfArray = typename std::remove_reference<decltype((*((Range *)0))[0])>::type;
|
||||
using ValueTypeOfArray = typename std::remove_reference<decltype((*DeclPtr__<Range>())[0])>::type;
|
||||
|
||||
template <class V>
|
||||
class ConstIIterator {
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ private:
|
|||
static Ptr<Ctrl> lastActive;
|
||||
|
||||
friend void CocoInit(int argc, const char **argv, const char **envptr);
|
||||
|
||||
|
||||
protected:
|
||||
virtual void MMClose() {}
|
||||
|
||||
|
|
@ -18,6 +18,7 @@ protected:
|
|||
static void SetNSAppImage(const Image& img);
|
||||
static void SyncAppIcon();
|
||||
static void ResetCocoaMouse();
|
||||
static void DoCancelPreedit();
|
||||
|
||||
public:
|
||||
static void EndSession() {}
|
||||
|
|
|
|||
|
|
@ -76,9 +76,11 @@ struct RectCG {
|
|||
RectCG();
|
||||
};
|
||||
|
||||
NSRect DesktopRect(const Upp::Rect& r);
|
||||
|
||||
}
|
||||
|
||||
@interface CocoView : NSView <NSWindowDelegate>
|
||||
@interface CocoView : NSView <NSWindowDelegate, NSTextInputClient>
|
||||
{
|
||||
@public
|
||||
Upp::Ptr<Upp::Ctrl> ctrl;
|
||||
|
|
|
|||
|
|
@ -102,6 +102,8 @@ struct MMImp {
|
|||
|
||||
static bool MouseEvent(CocoView *view, NSEvent *e, int event, double zd = 0)
|
||||
{
|
||||
if(!view->ctrl)
|
||||
return false;
|
||||
Flags(e);
|
||||
sCurrentMouseEvent__ = e;
|
||||
if((event & Ctrl::ACTION) == Ctrl::UP && Ctrl::ignoreclick) {
|
||||
|
|
@ -167,6 +169,8 @@ struct MMImp {
|
|||
|
||||
static bool MouseDownEvent(CocoView *view, NSEvent *e, int button)
|
||||
{
|
||||
if(!view->ctrl)
|
||||
return false;
|
||||
Upp::Ctrl::lastActive = view->ctrl;
|
||||
if(Ctrl::ignoremouseup) {
|
||||
Ctrl::KillRepeat();
|
||||
|
|
@ -196,11 +200,15 @@ struct MMImp {
|
|||
|
||||
static void Paint(Upp::Ctrl *ctrl, Upp::SystemDraw& w, const Rect& r)
|
||||
{
|
||||
if(!ctrl)
|
||||
return;
|
||||
ctrl->fullrefresh = false;
|
||||
ctrl->UpdateArea(w, r);
|
||||
}
|
||||
|
||||
static bool KeyEvent(Upp::Ctrl *ctrl, NSEvent *e, int up) {
|
||||
if(!ctrl)
|
||||
return false;
|
||||
Flags(e);
|
||||
if(!ctrl->IsEnabled())
|
||||
return false;
|
||||
|
|
@ -232,11 +240,13 @@ struct MMImp {
|
|||
ctrl->DispatchKey(k, 1);
|
||||
if(!up && !(k & (K_CTRL|K_ALT))) {
|
||||
WString x = ToWString((CFStringRef)(e.characters));
|
||||
#if 0 // this is now done by NSTextInputClient
|
||||
for(wchar c : x) {
|
||||
if(c < 0xF700 &&
|
||||
(c > 32 && c != 127 || /*c == 9 && !GetOption() || */c == 32 && !GetShift()))
|
||||
ctrl->DispatchKey(c, 1);
|
||||
}
|
||||
#endif
|
||||
if(e.keyCode == kVK_ANSI_KeypadEnter && *x != 13)
|
||||
ctrl->DispatchKey(13, 1);
|
||||
}
|
||||
|
|
@ -245,6 +255,8 @@ struct MMImp {
|
|||
|
||||
static void BecomeKey(Upp::Ctrl *ctrl)
|
||||
{
|
||||
if(!ctrl)
|
||||
return;
|
||||
LLOG("Become key " << Upp::Name(ctrl));
|
||||
Upp::Ctrl::lastActive = ctrl;
|
||||
ctrl->ActivateWnd();
|
||||
|
|
@ -260,6 +272,8 @@ struct MMImp {
|
|||
|
||||
static void ResignKey(Upp::Ctrl *ctrl)
|
||||
{
|
||||
if(!ctrl)
|
||||
return;
|
||||
LLOG("Resign key " << Upp::Name(ctrl));
|
||||
ctrl->KillFocusWnd();
|
||||
Upp::Ctrl::ReleaseCtrlCapture();
|
||||
|
|
@ -267,12 +281,16 @@ struct MMImp {
|
|||
|
||||
static void DoClose(Upp::Ctrl *ctrl)
|
||||
{
|
||||
if(!ctrl)
|
||||
return;
|
||||
ctrl->MMClose();
|
||||
Upp::Ctrl::ReleaseCtrlCapture();
|
||||
}
|
||||
|
||||
static int DnD(Upp::Ctrl *ctrl, id<NSDraggingInfo> info, bool paste = false)
|
||||
{
|
||||
if(!ctrl)
|
||||
return false;
|
||||
NSView *nsview = (NSView *)ctrl->GetNSView();
|
||||
PasteClip clip;
|
||||
clip.nspasteboard = info.draggingPasteboard;
|
||||
|
|
@ -299,6 +317,31 @@ struct MMImp {
|
|||
{
|
||||
Ctrl::DoCursorShape();
|
||||
}
|
||||
|
||||
static void ShowPreedit(Ctrl *ctrl, const WString& text)
|
||||
{
|
||||
if(ctrl)
|
||||
ctrl->GetTopCtrl()->ShowPreedit(text, INT_MAX);
|
||||
}
|
||||
|
||||
static NSRect PreeditRect(Ctrl *ctrl)
|
||||
{
|
||||
if(ctrl)
|
||||
return DesktopRect(ctrl->GetTopCtrl()->GetPreeditScreenRect());
|
||||
return NSRect();
|
||||
}
|
||||
|
||||
static void PreeditText(Ctrl *ctrl, const WString& s)
|
||||
{
|
||||
if(ctrl)
|
||||
for(Upp::wchar ch : s)
|
||||
ctrl->DispatchKey(ch, 1);
|
||||
}
|
||||
|
||||
static void CancelPreedit()
|
||||
{
|
||||
Ctrl::HidePreedit();
|
||||
}
|
||||
};
|
||||
|
||||
};
|
||||
|
|
@ -357,6 +400,7 @@ struct MMImp {
|
|||
}
|
||||
|
||||
- (void)keyDown:(NSEvent *)e {
|
||||
[self interpretKeyEvents: [NSArray arrayWithObject: e]];
|
||||
if(!Upp::MMImp::KeyEvent(ctrl, e, 0))
|
||||
[super keyDown:e];
|
||||
}
|
||||
|
|
@ -447,6 +491,69 @@ struct MMImp {
|
|||
[ta release];
|
||||
}
|
||||
|
||||
// NSTextInputClient methods
|
||||
|
||||
-(void)insertText:(id)aString replacementRange:(NSRange)replacementRange
|
||||
{
|
||||
(void) replacementRange;
|
||||
|
||||
NSString* pInsert = [aString isMemberOfClass: [NSAttributedString class]] ? [aString string] : aString;
|
||||
|
||||
if(pInsert)
|
||||
Upp::MMImp::PreeditText(ctrl, Upp::ToWString(pInsert));
|
||||
}
|
||||
|
||||
- (NSRange)markedRange
|
||||
{
|
||||
return NSMakeRange( NSNotFound, 0 );
|
||||
}
|
||||
|
||||
- (NSRange)selectedRange
|
||||
{
|
||||
return NSMakeRange( NSNotFound, 0 );
|
||||
}
|
||||
|
||||
- (NSRect)firstRectForCharacterRange:(NSRange)aRange actualRange:(NSRangePointer)actualRange
|
||||
{
|
||||
return Upp::MMImp::PreeditRect(ctrl);
|
||||
}
|
||||
|
||||
- (void)setMarkedText:(id)aString selectedRange:(NSRange)selRange replacementRange:(NSRange)replacementRange
|
||||
{
|
||||
if(![aString isKindOfClass:[NSAttributedString class]] )
|
||||
aString = [[[NSAttributedString alloc] initWithString:aString] autorelease];
|
||||
|
||||
Upp::MMImp::ShowPreedit(ctrl, Upp::ToWString([aString string]));
|
||||
}
|
||||
|
||||
- (BOOL)hasMarkedText
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
- (void)unmarkText
|
||||
{
|
||||
Upp::MMImp::CancelPreedit();
|
||||
}
|
||||
|
||||
- (NSArray *)validAttributesForMarkedText
|
||||
{
|
||||
return [NSArray arrayWithObjects:NSUnderlineStyleAttributeName, nil];
|
||||
}
|
||||
|
||||
- (NSAttributedString *)attributedSubstringForProposedRange:(NSRange)aRange actualRange:(NSRangePointer)actualRange
|
||||
{
|
||||
(void) aRange;
|
||||
(void) actualRange;
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (NSUInteger)characterIndexForPoint:(NSPoint)thePoint
|
||||
{
|
||||
(void)thePoint;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -97,8 +97,15 @@ void *Ctrl::GetNSView() const
|
|||
return top && top->coco ? top->coco->view : NULL;
|
||||
}
|
||||
|
||||
void Ctrl::DoCancelPreedit()
|
||||
{
|
||||
[[NSTextInputContext currentInputContext] discardMarkedText];
|
||||
}
|
||||
|
||||
void Ctrl::Create(Ctrl *owner, dword style, bool active)
|
||||
{
|
||||
cancel_preedit = DoCancelPreedit; // We really need this just once, but whatever..
|
||||
|
||||
if(owner)
|
||||
owner = owner->GetTopCtrl();
|
||||
|
||||
|
|
|
|||
|
|
@ -339,12 +339,14 @@ void Ctrl::SetModify()
|
|||
{
|
||||
GuiLock __;
|
||||
modify = true;
|
||||
CancelMyPreedit();
|
||||
}
|
||||
|
||||
void Ctrl::ClearModify()
|
||||
{
|
||||
GuiLock __;
|
||||
modify = false;
|
||||
CancelMyPreedit();
|
||||
}
|
||||
|
||||
void Ctrl::ClearModifyDeep()
|
||||
|
|
|
|||
|
|
@ -642,6 +642,12 @@ private:
|
|||
void SetInfoPart(int i, const char *txt);
|
||||
String GetInfoPart(int i) const;
|
||||
|
||||
Rect GetPreeditScreenRect();
|
||||
void SyncPreedit();
|
||||
void ShowPreedit(const WString& text, int cursor = INT_MAX);
|
||||
static void HidePreedit();
|
||||
static void PreeditSync(void (*enable_preedit)(Ctrl *top, bool enable));
|
||||
|
||||
// System window interface...
|
||||
void WndShow(bool b);
|
||||
void WndSetPos(const Rect& rect);
|
||||
|
|
@ -695,6 +701,8 @@ private:
|
|||
static bool IsNoLayoutZoom;
|
||||
static void Csizeinit();
|
||||
static void (*skin)();
|
||||
|
||||
static void (*cancel_preedit)();
|
||||
|
||||
friend void InitRichTextZoom();
|
||||
friend void AvoidPaintingCheck__();
|
||||
|
|
@ -875,6 +883,9 @@ public:
|
|||
virtual void MouseLeave();
|
||||
|
||||
virtual void Pen(Point p, const PenInfo& pen, dword keyflags);
|
||||
|
||||
virtual Point GetPreedit();
|
||||
virtual Font GetPreeditFont();
|
||||
|
||||
virtual void DragAndDrop(Point p, PasteClip& d);
|
||||
virtual void FrameDragAndDrop(Point p, PasteClip& d);
|
||||
|
|
@ -1122,6 +1133,10 @@ public:
|
|||
void SetCaret(const Rect& r);
|
||||
Rect GetCaret() const;
|
||||
void KillCaret();
|
||||
|
||||
static void CancelPreedit();
|
||||
|
||||
void CancelMyPreedit() { if(HasFocus()) CancelPreedit(); }
|
||||
|
||||
static Ctrl *GetFocusCtrl() { return FocusCtrl(); }
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ uses
|
|||
RichText,
|
||||
Painter;
|
||||
|
||||
library(WIN32) "advapi32 comdlg32 comctl32";
|
||||
library(WIN32) "advapi32 comdlg32 comctl32 Imm32 user32 gdi32";
|
||||
|
||||
pkg_config(POSIX !OSX !VIRTUALGUI) "freetype2 x11 xinerama xrender xft xdmcp fontconfig xcb xext";
|
||||
|
||||
|
|
@ -29,6 +29,7 @@ file
|
|||
CtrlTimer.cpp,
|
||||
CtrlClip.cpp,
|
||||
LocalLoop.cpp,
|
||||
Preedit.cpp,
|
||||
CtrlCoreInit.cpp,
|
||||
TopWindow.h,
|
||||
TopWindow.cpp,
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ bool Ctrl::DispatchKey(dword keycode, int count)
|
|||
return true;
|
||||
dword k = keycode;
|
||||
word l = LOWORD(keycode);
|
||||
if(!(k & K_DELTA) && l >= 32 && l != 127 && GetDefaultCharset() != CHARSET_UTF8)
|
||||
if(GetDefaultCharset() != CHARSET_UTF8 && !(k & K_DELTA) && l >= 32 && l != 127)
|
||||
k = MAKELONG((word)FromUnicode(l, CHARSET_DEFAULT), HIWORD(keycode));
|
||||
if(!focusCtrl)
|
||||
return false;
|
||||
|
|
@ -306,6 +306,7 @@ void Ctrl::KillFocusWnd()
|
|||
focusCtrl = focusCtrlWnd = NULL;
|
||||
DoKillFocus(pfocusCtrl, NULL);
|
||||
}
|
||||
CancelPreedit();
|
||||
}
|
||||
|
||||
void Ctrl::ClickActivateWnd()
|
||||
|
|
|
|||
|
|
@ -183,6 +183,8 @@ Vector<int> GetPropertyInts(GdkWindow *w, const char *property);
|
|||
#define GUIPLATFORM_CTRL_TOP_DECLS \
|
||||
GtkWidget *window; \
|
||||
GtkIMContext *im_context; \
|
||||
GtkIMContext *im_context_simple; \
|
||||
GtkIMContext *im_context_multi; \
|
||||
int64 cursor_id; \
|
||||
int id; \
|
||||
//$ }
|
||||
|
|
|
|||
|
|
@ -55,6 +55,7 @@ int Ctrl::scale;
|
|||
void InitGtkApp(int argc, char **argv, const char **envptr)
|
||||
{
|
||||
LLOG(rmsecs() << " InitGtkApp");
|
||||
|
||||
#if GTK_CHECK_VERSION(3, 10, 0)
|
||||
gdk_set_allowed_backends("x11"); // this fixes wayland issues
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ void Ctrl::Create(Ctrl *owner, bool popup)
|
|||
top = new Top;
|
||||
top->window = gtk_window_new(popup && owner ? GTK_WINDOW_POPUP : GTK_WINDOW_TOPLEVEL);
|
||||
top->owner = owner;
|
||||
|
||||
|
||||
static int id;
|
||||
top->id = ++id;
|
||||
|
||||
|
|
@ -57,7 +57,7 @@ void Ctrl::Create(Ctrl *owner, bool popup)
|
|||
gtk_window_resize(gtk(), LSC(r.GetWidth()), LSC(r.GetHeight()));
|
||||
|
||||
gtk_widget_realize(top->window);
|
||||
|
||||
|
||||
w.gdk = gtk_widget_get_window(top->window);
|
||||
|
||||
if(owner && owner->top)
|
||||
|
|
@ -68,20 +68,23 @@ void Ctrl::Create(Ctrl *owner, bool popup)
|
|||
|
||||
top->im_context = gtk_im_multicontext_new();
|
||||
gtk_im_context_set_client_window(top->im_context, gdk());
|
||||
gtk_im_context_set_use_preedit(top->im_context, false);
|
||||
gtk_im_context_set_use_preedit(top->im_context, true);
|
||||
g_signal_connect(top->im_context, "preedit-changed", G_CALLBACK(IMPreedit), (gpointer)(uintptr_t)top->id);
|
||||
g_signal_connect(top->im_context, "preedit-start", G_CALLBACK(IMPreedit), (gpointer)(uintptr_t)top->id);
|
||||
g_signal_connect(top->im_context, "preedit-end", G_CALLBACK(IMPreeditEnd), (gpointer)(uintptr_t)top->id);
|
||||
g_signal_connect(top->im_context, "commit", G_CALLBACK(IMCommit), (gpointer)(uintptr_t)top->id);
|
||||
|
||||
WndShow(IsShown());
|
||||
|
||||
|
||||
SweepConfigure(true);
|
||||
FocusSync();
|
||||
if(!popup)
|
||||
SetWndFocus();
|
||||
|
||||
activeCtrl = this;
|
||||
|
||||
|
||||
DndInit();
|
||||
|
||||
|
||||
StateH(OPEN);
|
||||
|
||||
GdkModifierType mod;
|
||||
|
|
@ -89,7 +92,7 @@ void Ctrl::Create(Ctrl *owner, bool popup)
|
|||
r = GetWndScreenRect().GetSize();
|
||||
if(r.Contains(m))
|
||||
DispatchMouse(MOUSEMOVE, m);
|
||||
|
||||
|
||||
RefreshLayoutDeep();
|
||||
}
|
||||
|
||||
|
|
@ -108,7 +111,8 @@ void Ctrl::WndDestroy()
|
|||
if(HasFocusDeep() || !GetFocusCtrl())
|
||||
activeCtrl = owner;
|
||||
}
|
||||
g_object_unref(top->im_context);
|
||||
if(top->im_context)
|
||||
g_object_unref(top->im_context);
|
||||
gtk_widget_destroy(top->window);
|
||||
isopen = false;
|
||||
popup = false;
|
||||
|
|
@ -167,4 +171,4 @@ void Ctrl::PopUp(Ctrl *owner, bool savebits, bool activate, bool, bool)
|
|||
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
|
@ -4,6 +4,9 @@
|
|||
|
||||
static gboolean GtkProc(GtkWidget *widget, GdkEvent *event, gpointer user_data);
|
||||
static void IMCommit(GtkIMContext *context, gchar *str, gpointer user_data);
|
||||
static void IMPreedit(GtkIMContext *context, gpointer user_data);
|
||||
static void IMPreeditEnd(GtkIMContext *context, gpointer user_data);
|
||||
static void IMLocation(Ctrl *w);
|
||||
|
||||
static int DoButtonEvent(GdkEvent *event, bool press);
|
||||
static void AddEvent(gpointer user_data, int type, const Value& value, GdkEvent *event);
|
||||
|
|
@ -118,6 +121,7 @@ _DBG_
|
|||
static void StopGrabPopup();
|
||||
static void StartGrabPopup();
|
||||
static bool ReleaseWndCapture0();
|
||||
static void DoCancelPreedit();
|
||||
|
||||
static Rect frameMargins;
|
||||
static Rect GetFrameMargins();
|
||||
|
|
|
|||
|
|
@ -130,8 +130,10 @@ gboolean Ctrl::GtkEvent(GtkWidget *widget, GdkEvent *event, gpointer user_data)
|
|||
|
||||
switch(event->type) {
|
||||
case GDK_DELETE:
|
||||
p->CancelPreedit();
|
||||
break;
|
||||
case GDK_FOCUS_CHANGE:
|
||||
p->CancelPreedit();
|
||||
if(p) {
|
||||
if(((GdkEventFocus *)event)->in)
|
||||
gtk_im_context_focus_in(p->top->im_context);
|
||||
|
|
@ -144,16 +146,19 @@ gboolean Ctrl::GtkEvent(GtkWidget *widget, GdkEvent *event, gpointer user_data)
|
|||
case GDK_LEAVE_NOTIFY:
|
||||
break;
|
||||
case GDK_BUTTON_PRESS:
|
||||
p->CancelPreedit();
|
||||
value = DoButtonEvent(event, true);
|
||||
if(IsNull(value))
|
||||
return false;
|
||||
break;
|
||||
case GDK_2BUTTON_PRESS:
|
||||
p->CancelPreedit();
|
||||
value = DoButtonEvent(event, true);
|
||||
if(IsNull(value))
|
||||
return false;
|
||||
break;
|
||||
case GDK_BUTTON_RELEASE:
|
||||
p->CancelPreedit();
|
||||
value = DoButtonEvent(event, false);
|
||||
if(IsNull(value))
|
||||
return false;
|
||||
|
|
@ -288,7 +293,7 @@ void Ctrl::AddEvent(gpointer user_data, int type, const Value& value, GdkEvent *
|
|||
e.count = 1;
|
||||
e.event = NULL;
|
||||
#if GTK_CHECK_VERSION(3, 22, 0)
|
||||
GdkDevice *d = gdk_event_get_source_device(event);
|
||||
GdkDevice *d = event ? gdk_event_get_source_device(event) : NULL;
|
||||
if(d && findarg(gdk_device_get_source(d), GDK_SOURCE_PEN, GDK_SOURCE_TOUCHSCREEN) >= 0) {
|
||||
e.pen = true;
|
||||
e.pen_barrel = MouseState & GDK_BUTTON3_MASK;
|
||||
|
|
@ -328,6 +333,48 @@ void Ctrl::IMCommit(GtkIMContext *context, gchar *str, gpointer user_data)
|
|||
AddEvent(user_data, EVENT_TEXT, ToUtf32(str), NULL);
|
||||
}
|
||||
|
||||
void Ctrl::IMLocation(Ctrl *w)
|
||||
{
|
||||
if(w && w->HasFocusDeep() && focusCtrl && !IsNull(focusCtrl->GetPreedit())) {
|
||||
GdkRectangle r;
|
||||
Rect e = w->GetPreeditScreenRect();
|
||||
Rect q = w->GetScreenRect();
|
||||
GdkRectangle gr;
|
||||
gr.x = LSC(e.left - q.left);
|
||||
gr.y = LSC(e.top - q.top);
|
||||
gr.width = LSC(e.GetWidth());
|
||||
gr.height = LSC(e.GetHeight());
|
||||
gtk_im_context_set_cursor_location(w->top->im_context, &gr);
|
||||
}
|
||||
}
|
||||
|
||||
void Ctrl::IMPreedit(GtkIMContext *context, gpointer user_data)
|
||||
{
|
||||
GuiLock __;
|
||||
Ctrl *w = GetTopCtrlFromId((uint32)(uintptr_t)user_data);
|
||||
if(w && w->HasFocusDeep() && focusCtrl && !IsNull(focusCtrl->GetPreedit())) {
|
||||
PangoAttrList *attrs;
|
||||
gchar *str;
|
||||
gint cursor_pos;
|
||||
gtk_im_context_get_preedit_string(context, &str, &attrs, &cursor_pos);
|
||||
WString text = ToUtf32(str);
|
||||
g_free(str);
|
||||
pango_attr_list_unref(attrs);
|
||||
w->ShowPreedit(text, cursor_pos);
|
||||
IMLocation(w);
|
||||
}
|
||||
else
|
||||
CancelPreedit();
|
||||
}
|
||||
|
||||
void Ctrl::IMPreeditEnd(GtkIMContext *context, gpointer user_data)
|
||||
{
|
||||
GuiLock __;
|
||||
Ctrl *w = GetTopCtrlFromId((uint32)(uintptr_t)user_data);
|
||||
if(w && w->HasFocusDeep() && focusCtrl && !IsNull(focusCtrl->GetPreedit()))
|
||||
w->HidePreedit();
|
||||
}
|
||||
|
||||
bool Ctrl::ProcessInvalids()
|
||||
{
|
||||
GuiLock __;
|
||||
|
|
@ -367,7 +414,7 @@ bool Ctrl::IsWaitingEvent()
|
|||
struct ProcStop {
|
||||
TimeStop tm;
|
||||
String ev;
|
||||
|
||||
|
||||
~ProcStop() { LOG("* " << ev << " elapsed " << tm); }
|
||||
};
|
||||
|
||||
|
|
@ -439,7 +486,7 @@ void Ctrl::Proc()
|
|||
pen.pressure = CurrentEvent.pen_pressure;
|
||||
pen.rotation = CurrentEvent.pen_rotation;
|
||||
pen.tilt = CurrentEvent.pen_tilt;
|
||||
|
||||
|
||||
is_pen_event = CurrentEvent.pen;
|
||||
|
||||
auto DoPen = [&](Point p) {
|
||||
|
|
@ -452,7 +499,7 @@ void Ctrl::Proc()
|
|||
}
|
||||
else
|
||||
for(Ctrl *t = q; t; t=q->ChildFromPoint(p)) q = t;
|
||||
|
||||
|
||||
q->Pen(p, pen, GetMouseFlags());
|
||||
SyncCaret();
|
||||
Image m = CursorOverride();
|
||||
|
|
@ -464,7 +511,7 @@ void Ctrl::Proc()
|
|||
findarg(CurrentEvent.type, GDK_MOTION_NOTIFY, GDK_BUTTON_PRESS, GDK_BUTTON_RELEASE) >= 0)
|
||||
{
|
||||
pen.action = decode(CurrentEvent.type, GDK_BUTTON_PRESS, PEN_DOWN, GDK_BUTTON_RELEASE, PEN_UP, 0);
|
||||
|
||||
|
||||
DoPen(GetMousePos() - GetScreenRect().TopLeft());
|
||||
}
|
||||
#endif
|
||||
|
|
@ -490,7 +537,7 @@ void Ctrl::Proc()
|
|||
ignoreclick = false;
|
||||
ignoremouseup = false;
|
||||
}
|
||||
|
||||
|
||||
if(!ignoreclick) {
|
||||
bool dbl = msecs(clicktime) < 250;
|
||||
clicktime = dbl ? clicktime - 1000 : msecs();
|
||||
|
|
@ -609,7 +656,7 @@ void Ctrl::Proc()
|
|||
kv |= K_CTRL;
|
||||
if(GetAlt() && kv != K_ALT_KEY)
|
||||
kv |= K_ALT;
|
||||
LLOG(GetKeyDesc(kv) << ", pressed: " << pressed << ", count: " << CurrentEvent.count);
|
||||
DLOG(GetKeyDesc(kv) << ", pressed: " << pressed << ", count: " << CurrentEvent.count);
|
||||
#ifdef GDK_WINDOWING_X11
|
||||
if(pressed)
|
||||
for(int i = 0; i < hotkey.GetCount(); i++) {
|
||||
|
|
@ -619,6 +666,7 @@ void Ctrl::Proc()
|
|||
}
|
||||
}
|
||||
#endif
|
||||
DDUMPHEX(kv);
|
||||
DispatchKey(!pressed * K_KEYUP + kv, CurrentEvent.count);
|
||||
}
|
||||
break;
|
||||
|
|
@ -693,8 +741,10 @@ bool Ctrl::ProcessEvent0(bool *quit, bool fetch)
|
|||
Ctrl *w = GetTopCtrlFromId(e.windowid);
|
||||
FocusSync();
|
||||
CaptureSync();
|
||||
if(w)
|
||||
if(w) {
|
||||
IMLocation(w);
|
||||
w->Proc();
|
||||
}
|
||||
r = true;
|
||||
}
|
||||
if(quit)
|
||||
|
|
@ -752,6 +802,9 @@ void WakeUpGuiThread()
|
|||
void Ctrl::EventLoop(Ctrl *ctrl)
|
||||
{
|
||||
GuiLock __;
|
||||
|
||||
cancel_preedit = DoCancelPreedit; // We really need this just once, but whatever..
|
||||
|
||||
ASSERT_(IsMainThread(), "EventLoop can only run in the main thread");
|
||||
ASSERT(LoopLevel == 0 || ctrl);
|
||||
LoopLevel++;
|
||||
|
|
@ -793,4 +846,4 @@ void Ctrl::GuiSleep(int ms)
|
|||
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
|
@ -396,6 +396,19 @@ bool Ctrl::SetWndFocus()
|
|||
return true;
|
||||
}
|
||||
|
||||
void Ctrl::DoCancelPreedit()
|
||||
{
|
||||
if(!focusCtrl)
|
||||
return;
|
||||
if(focusCtrl->top)
|
||||
focusCtrl->HidePreedit();
|
||||
if(focusCtrl->top) {
|
||||
gtk_im_context_reset(focusCtrl->top->im_context);
|
||||
gtk_im_context_focus_out(focusCtrl->top->im_context);
|
||||
gtk_im_context_focus_in(focusCtrl->top->im_context);
|
||||
}
|
||||
}
|
||||
|
||||
void WakeUpGuiThread();
|
||||
|
||||
void Ctrl::WndInvalidateRect(const Rect& r)
|
||||
|
|
|
|||
131
uppsrc/CtrlCore/Preedit.cpp
Normal file
131
uppsrc/CtrlCore/Preedit.cpp
Normal file
|
|
@ -0,0 +1,131 @@
|
|||
#include "CtrlCore.h"
|
||||
|
||||
#define LLOG(x) DLOG(x)
|
||||
|
||||
namespace Upp {
|
||||
|
||||
void (*Ctrl::cancel_preedit)(); // hook for implementation to hide cancel host preedit
|
||||
|
||||
void Ctrl::CancelPreedit()
|
||||
{
|
||||
HidePreedit();
|
||||
if(cancel_preedit)
|
||||
cancel_preedit();
|
||||
}
|
||||
|
||||
struct PreeditCtrl : Ctrl {
|
||||
WString text;
|
||||
Font font;
|
||||
Ctrl *owner = NULL;
|
||||
int cursor = INT_MAX;
|
||||
|
||||
virtual void Paint(Draw& w) {
|
||||
Size sz = GetSize();
|
||||
w.DrawRect(GetSize(), SWhite());
|
||||
w.DrawText(DPI(2), sz.cy - font.GetCy(), text, font, SBlack());
|
||||
if(cursor < text.GetCount())
|
||||
w.DrawRect(DPI(2) + GetTextSize(text.Mid(0, cursor), font).cx, 0, DPI(1), sz.cy, InvertColor);
|
||||
}
|
||||
|
||||
PreeditCtrl() { SetFrame(BlackFrame()); }
|
||||
};
|
||||
|
||||
Rect Ctrl::GetPreeditScreenRect()
|
||||
{ // preedit position in screen coordinates, zero width
|
||||
if(HasFocusDeep()) {
|
||||
Point p = focusCtrl->GetPreedit();
|
||||
if(!IsNull(p)) {
|
||||
p += focusCtrl->GetScreenView().TopLeft();
|
||||
return RectC(p.x, p.y - 1, 0, focusCtrl->GetPreeditFont().GetCy() + 1);
|
||||
}
|
||||
}
|
||||
return Null;
|
||||
}
|
||||
|
||||
Point Ctrl::GetPreedit()
|
||||
{
|
||||
if(HasFocus()) {
|
||||
Rect r = GetCaret();
|
||||
if(r.GetHeight() > 0)
|
||||
return r.TopRight();
|
||||
}
|
||||
return Null;
|
||||
}
|
||||
|
||||
Font Ctrl::GetPreeditFont()
|
||||
{
|
||||
static int pheight = -1;
|
||||
static Font pfont;
|
||||
if(!focusCtrl)
|
||||
return StdFont();
|
||||
int height = max(focusCtrl->GetCaret().GetHeight(), DPI(7));
|
||||
if(height != pheight) {
|
||||
pheight = height;
|
||||
while(pheight > 0) {
|
||||
pfont = StdFont(height);
|
||||
if(pfont.GetCy() < pheight)
|
||||
break;
|
||||
height--;
|
||||
}
|
||||
if(height == 0)
|
||||
pfont = StdFont();
|
||||
}
|
||||
return pfont;
|
||||
}
|
||||
|
||||
void Ctrl::SyncPreedit()
|
||||
{
|
||||
PreeditCtrl& p = Single<PreeditCtrl>();
|
||||
if(p.owner == this && focusCtrl) {
|
||||
Rect r = GetPreeditScreenRect();
|
||||
p.font = focusCtrl->GetPreeditFont();
|
||||
r.right = r.left + GetTextSize(p.text, p.font).cx + DPI(4);
|
||||
int wr = GetWorkArea().right;
|
||||
if(r.right > wr) {
|
||||
int w = r.GetWidth();
|
||||
r.right = min(wr, r.left - DPI(2));
|
||||
r.left = r.right - w;
|
||||
}
|
||||
p.SetRect(r);
|
||||
}
|
||||
}
|
||||
|
||||
void Ctrl::ShowPreedit(const WString& text, int cursor)
|
||||
{
|
||||
if(text.GetCount() == 0) {
|
||||
HidePreedit();
|
||||
return;
|
||||
}
|
||||
PreeditCtrl& p = Single<PreeditCtrl>();
|
||||
p.text = text;
|
||||
p.cursor = cursor;
|
||||
p.owner = this;
|
||||
SyncPreedit();
|
||||
if(!p.IsOpen())
|
||||
p.PopUp(this, true, false, true);
|
||||
p.Refresh();
|
||||
}
|
||||
|
||||
void Ctrl::HidePreedit()
|
||||
{
|
||||
PreeditCtrl& p = Single<PreeditCtrl>();
|
||||
if(p.IsOpen()) {
|
||||
p.Close();
|
||||
p.owner = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void Ctrl::PreeditSync(void (*enable_preedit)(Ctrl *top, bool enable))
|
||||
{ // enables / disables preedit
|
||||
static Ptr<Ctrl> preedit;
|
||||
Ctrl *fw = focusCtrl && !IsNull(focusCtrl->GetPreedit()) ? focusCtrl->GetTopCtrl() : nullptr;
|
||||
if(fw != preedit) {
|
||||
if(preedit)
|
||||
enable_preedit(preedit, false);
|
||||
if(fw)
|
||||
enable_preedit(fw, true);
|
||||
}
|
||||
preedit = fw;
|
||||
}
|
||||
|
||||
};
|
||||
|
|
@ -21,6 +21,7 @@ private:
|
|||
static void RenderFormat(int format);
|
||||
static void RenderAllFormats();
|
||||
static void DestroyClipboard();
|
||||
static void DoCancelPreedit();
|
||||
|
||||
void UpdateDHCtrls();
|
||||
|
||||
|
|
|
|||
|
|
@ -64,6 +64,21 @@ Point GetMousePos() {
|
|||
|
||||
bool PassWindowsKey(int wParam);
|
||||
|
||||
void Ctrl::DoCancelPreedit()
|
||||
{
|
||||
if(!focusCtrlWnd)
|
||||
return;
|
||||
if(focusCtrlWnd->top)
|
||||
focusCtrl->HidePreedit();
|
||||
if(focusCtrlWnd->top && focusCtrlWnd->top->hwnd) {
|
||||
HIMC himc = ImmGetContext(focusCtrlWnd->top->hwnd);
|
||||
if(himc && ImmGetOpenStatus(himc)) {
|
||||
ImmNotifyIME(himc, NI_COMPOSITIONSTR, CPS_CANCEL, 0);
|
||||
ImmReleaseContext(focusCtrlWnd->top->hwnd, himc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LRESULT Ctrl::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) {
|
||||
GuiLock __;
|
||||
eventid++;
|
||||
|
|
@ -71,6 +86,8 @@ LRESULT Ctrl::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) {
|
|||
Ptr<Ctrl> _this = this;
|
||||
HWND hwnd = GetHWND();
|
||||
|
||||
cancel_preedit = DoCancelPreedit; // We really need this just once, but whatever..
|
||||
|
||||
is_pen_event = (GetMessageExtraInfo() & 0xFFFFFF00) == 0xFF515700;
|
||||
|
||||
POINT p;
|
||||
|
|
@ -83,6 +100,19 @@ LRESULT Ctrl::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) {
|
|||
::ClientToScreen(hwnd, CurrentMousePos);
|
||||
return p;
|
||||
};
|
||||
|
||||
bool has_preedit = HasFocusDeep() && focusCtrl && !IsNull(focusCtrl->GetPreedit());
|
||||
|
||||
auto StopPreedit = [&] {
|
||||
HidePreedit();
|
||||
if(HasFocusDeep())
|
||||
CancelPreedit();
|
||||
};
|
||||
|
||||
auto ClickActivate = [&] {
|
||||
ClickActivateWnd();
|
||||
StopPreedit();
|
||||
};
|
||||
|
||||
switch(message) {
|
||||
case WM_POINTERDOWN:
|
||||
|
|
@ -174,7 +204,7 @@ LRESULT Ctrl::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) {
|
|||
case WM_POINTERDOWN:
|
||||
pendown=true;
|
||||
pen.action = PEN_DOWN;
|
||||
ClickActivateWnd();
|
||||
ClickActivate();
|
||||
break;
|
||||
case WM_POINTERUP:
|
||||
pendown=false;
|
||||
|
|
@ -235,7 +265,7 @@ LRESULT Ctrl::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) {
|
|||
if(ignoremouse) return HTTRANSPARENT;
|
||||
break;
|
||||
case WM_LBUTTONDOWN:
|
||||
ClickActivateWnd();
|
||||
ClickActivate();
|
||||
if(ignoreclick) return 0L;
|
||||
DoMouse(LEFTDOWN, MousePos(), 0);
|
||||
if(_this) PostInput();
|
||||
|
|
@ -248,13 +278,13 @@ LRESULT Ctrl::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) {
|
|||
if(_this) PostInput();
|
||||
return 0L;
|
||||
case WM_LBUTTONDBLCLK:
|
||||
ClickActivateWnd();
|
||||
ClickActivate();
|
||||
if(ignoreclick) return 0L;
|
||||
DoMouse(LEFTDOUBLE, MousePos(), 0);
|
||||
if(_this) PostInput();
|
||||
return 0L;
|
||||
case WM_RBUTTONDOWN:
|
||||
ClickActivateWnd();
|
||||
ClickActivate();
|
||||
if(ignoreclick) return 0L;
|
||||
DoMouse(RIGHTDOWN, MousePos());
|
||||
if(_this) PostInput();
|
||||
|
|
@ -267,13 +297,13 @@ LRESULT Ctrl::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) {
|
|||
if(_this) PostInput();
|
||||
return 0L;
|
||||
case WM_RBUTTONDBLCLK:
|
||||
ClickActivateWnd();
|
||||
ClickActivate();
|
||||
if(ignoreclick) return 0L;
|
||||
DoMouse(RIGHTDOUBLE, MousePos());
|
||||
if(_this) PostInput();
|
||||
return 0L;
|
||||
case WM_MBUTTONDOWN:
|
||||
ClickActivateWnd();
|
||||
ClickActivate();
|
||||
if(ignoreclick) return 0L;
|
||||
DoMouse(MIDDLEDOWN, MousePos());
|
||||
if(_this) PostInput();
|
||||
|
|
@ -286,7 +316,7 @@ LRESULT Ctrl::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) {
|
|||
if(_this) PostInput();
|
||||
return 0L;
|
||||
case WM_MBUTTONDBLCLK:
|
||||
ClickActivateWnd();
|
||||
ClickActivate();
|
||||
if(ignoreclick) return 0L;
|
||||
DoMouse(MIDDLEDOUBLE, MousePos());
|
||||
if(_this) PostInput();
|
||||
|
|
@ -294,7 +324,7 @@ LRESULT Ctrl::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) {
|
|||
case WM_NCLBUTTONDOWN:
|
||||
case WM_NCRBUTTONDOWN:
|
||||
case WM_NCMBUTTONDOWN:
|
||||
ClickActivateWnd();
|
||||
ClickActivate();
|
||||
IgnoreMouseUp();
|
||||
break;
|
||||
case WM_MOUSEMOVE:
|
||||
|
|
@ -409,6 +439,59 @@ LRESULT Ctrl::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) {
|
|||
break;
|
||||
// case WM_GETDLGCODE:
|
||||
// return wantfocus ? 0 : DLGC_STATIC;
|
||||
case WM_IME_STARTCOMPOSITION:
|
||||
case WM_IME_COMPOSITION:
|
||||
if(has_preedit) {
|
||||
HIMC himc = ImmGetContext(GetHWND());
|
||||
if(!himc)
|
||||
break;
|
||||
Rect pr = GetPreeditScreenRect();
|
||||
Point p = pr.TopLeft() - GetScreenRect().TopLeft();
|
||||
CANDIDATEFORM cf;
|
||||
cf.dwIndex = 0;
|
||||
cf.dwStyle = CFS_EXCLUDE;
|
||||
cf.ptCurrentPos.x = p.x;
|
||||
cf.ptCurrentPos.y = p.y;
|
||||
cf.rcArea.left = p.x;
|
||||
cf.rcArea.top = p.y;
|
||||
cf.rcArea.right = p.x + DPI(20); // DPI(20) is sort of hack, but candidate windows are above or bellow anyway...
|
||||
cf.rcArea.bottom = p.y + pr.GetHeight();
|
||||
ImmSetCandidateWindow(himc, &cf);
|
||||
/* // todo: SetCaretPos too
|
||||
Rect r;
|
||||
::CreateCaret(hwnd, NULL, 1, pr.Height());
|
||||
::ShowCaret(hwnd);
|
||||
::SetCaretPos(p.x, p.y);
|
||||
*/
|
||||
auto ReadString = [&](int type) -> WString {
|
||||
int len = ImmGetCompositionStringW (himc, type, NULL, 0);
|
||||
if(len > 0) {
|
||||
Buffer<char16> sw(len / 2);
|
||||
ImmGetCompositionStringW(himc, type, sw, len);
|
||||
return ToUtf32(sw, len / 2);
|
||||
}
|
||||
return Null;
|
||||
};
|
||||
if(lParam & GCS_COMPSTR) {
|
||||
ShowPreedit(ReadString(GCS_COMPSTR), ImmGetCompositionString(himc, GCS_CURSORPOS, 0, 0));
|
||||
}
|
||||
if(lParam & GCS_RESULTSTR) {
|
||||
WString h = ReadString(GCS_RESULTSTR);
|
||||
for(wchar c : h)
|
||||
DispatchKey(c, 1);
|
||||
HidePreedit();
|
||||
SyncCaret();
|
||||
}
|
||||
ImmReleaseContext(GetHWND(), himc);
|
||||
return 0L;
|
||||
}
|
||||
break;
|
||||
case WM_IME_ENDCOMPOSITION:
|
||||
if(has_preedit) {
|
||||
HidePreedit();
|
||||
return 0L;
|
||||
}
|
||||
break;
|
||||
case WM_XBUTTONDOWN: {
|
||||
UINT button = GET_XBUTTON_WPARAM(wParam);
|
||||
if(button == XBUTTON2)
|
||||
|
|
@ -463,7 +546,8 @@ LRESULT Ctrl::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) {
|
|||
if(!IsEnabled()) {
|
||||
if(lastActiveWnd && lastActiveWnd->IsEnabled()) {
|
||||
if(focusCtrl) { // this closes popup
|
||||
LLOG("WM_MOUSEACTIVATE -> ClickActivateWnd for " << UPP::Name(lastActiveWnd));
|
||||
LLOG("WM_MOUSEACTIVATE -> ClickActivate for " << UPP::Name(lastActiveWnd));
|
||||
StopPreedit();
|
||||
lastActiveWnd->ClickActivateWnd();
|
||||
}
|
||||
else { // this makes child dialog active when clicked on disabled parent
|
||||
|
|
@ -497,6 +581,7 @@ LRESULT Ctrl::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) {
|
|||
caretCtrl = NULL;
|
||||
SyncCaret();
|
||||
#endif
|
||||
SyncPreedit();
|
||||
}
|
||||
return 0L;
|
||||
case WM_HELP:
|
||||
|
|
@ -541,6 +626,7 @@ LRESULT Ctrl::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) {
|
|||
KillFocusWnd();
|
||||
}
|
||||
LLOG("//WM_KILLFOCUS " << (void *)(HWND)wParam << ", focusCtrlWnd = " << UPP::Name(focusCtrlWnd) << ", raw = " << (void *)::GetFocus());
|
||||
StopPreedit();
|
||||
return 0L;
|
||||
case WM_ENABLE:
|
||||
if(!!wParam != enabled) {
|
||||
|
|
|
|||
|
|
@ -489,6 +489,7 @@ void Ctrl::Create(HWND parent, DWORD style, DWORD exstyle, bool savebits, int sh
|
|||
StateH(OPEN);
|
||||
LLOG(LOG_END << "//Ctrl::Create in " <<UPP::Name(this));
|
||||
RegisterDragDrop(top->hwnd, (LPDROPTARGET) (top->dndtgt = NewUDropTarget(this)));
|
||||
::ImmAssociateContextEx(top->hwnd, NULL, 0);
|
||||
CancelMode();
|
||||
RefreshLayoutDeep();
|
||||
}
|
||||
|
|
@ -755,6 +756,10 @@ bool Ctrl::ProcessEvent(bool *quit)
|
|||
// LLOG(GetSysTime() << " % " << (unsigned)msecs() % 10000 << ": //sProcessMSG " << FormatIntHex(msg.message));
|
||||
DefferedFocusSync();
|
||||
SyncCaret();
|
||||
PreeditSync([](Ctrl *top, bool enable) {
|
||||
if(HWND hwnd = top->GetHWND())
|
||||
::ImmAssociateContextEx(hwnd, NULL, enable * IACE_DEFAULT);
|
||||
});
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -254,6 +254,7 @@ void DocEdit::PlaceCaret(int64 newpos, bool select) {
|
|||
SelectionChanged();
|
||||
if(IsSelection())
|
||||
SetSelectionSource(ClipFmtsText());
|
||||
CancelMyPreedit();
|
||||
}
|
||||
|
||||
int DocEdit::GetMousePos(Point p)
|
||||
|
|
|
|||
|
|
@ -427,6 +427,7 @@ void EditField::SelSource()
|
|||
SetSelectionSource(ClipFmtsText());
|
||||
else
|
||||
fsell = fselh = -1;
|
||||
CancelMyPreedit();
|
||||
}
|
||||
|
||||
void EditField::GotFocus()
|
||||
|
|
|
|||
|
|
@ -32,6 +32,11 @@ LineEdit::LineEdit() {
|
|||
|
||||
LineEdit::~LineEdit() {}
|
||||
|
||||
Font LineEdit::GetPreeditFont()
|
||||
{
|
||||
return font;
|
||||
}
|
||||
|
||||
void LineEdit::MouseWheel(Point, int zdelta, dword keyflags) {
|
||||
if(keyflags & K_SHIFT)
|
||||
sb.WheelX(zdelta);
|
||||
|
|
|
|||
|
|
@ -298,6 +298,7 @@ public:
|
|||
virtual void DragLeave();
|
||||
virtual void Layout();
|
||||
virtual void RefreshLine(int i);
|
||||
virtual Font GetPreeditFont();
|
||||
|
||||
protected:
|
||||
virtual void SetSb();
|
||||
|
|
|
|||
|
|
@ -364,7 +364,6 @@ void PdfDraw::DrawTextOp(int x, int y, int angle, const wchar *s, Font fnt,
|
|||
auto Fmt = [](double x) { return FormatF(x, 5); };
|
||||
|
||||
if(fnt.GetFaceInfo() & Font::COLORIMG) {
|
||||
int fi = -1;
|
||||
Pointf prev(0, 0);
|
||||
for(int i = 0; i < n; i++) {
|
||||
CGlyph cg = ColorGlyph(fnt, s[i]);
|
||||
|
|
|
|||
|
|
@ -107,6 +107,7 @@ void RichEdit::MoveNG(int newpos, bool select)
|
|||
if(select)
|
||||
SetSelectionSource(String().Cat() << "text/QTF;Rich Text Format;text/rtf;application/rtf;"
|
||||
<< ClipFmtsText());
|
||||
CancelMyPreedit();
|
||||
}
|
||||
|
||||
void RichEdit::Move(int newpos, bool select)
|
||||
|
|
|
|||
|
|
@ -2,6 +2,26 @@
|
|||
|
||||
namespace Upp {
|
||||
|
||||
Point RichEdit::GetPreedit()
|
||||
{
|
||||
Rect r = GetCaretRect();
|
||||
if(formatinfo.sscript == 2) {
|
||||
Point p = r.BottomRight();
|
||||
p.y -= 3 * r.GetHeight() / 5;
|
||||
return p;
|
||||
}
|
||||
return r.TopRight();
|
||||
}
|
||||
|
||||
Font RichEdit::GetPreeditFont()
|
||||
{
|
||||
Font fnt = formatinfo;
|
||||
int h = abs(fnt.GetHeight());
|
||||
if(formatinfo.sscript)
|
||||
h = 3 * h / 5;
|
||||
return fnt(max(GetZoom() * abs(h), 1));
|
||||
}
|
||||
|
||||
void RichEdit::ApplyFormat(dword charvalid, dword paravalid)
|
||||
{
|
||||
if(IsReadOnly())
|
||||
|
|
|
|||
|
|
@ -223,7 +223,8 @@ public:
|
|||
virtual void DragRepeat(Point p);
|
||||
virtual void DragLeave();
|
||||
virtual String GetSelectionData(const String& fmt) const;
|
||||
|
||||
virtual Point GetPreedit();
|
||||
virtual Font GetPreeditFont();
|
||||
|
||||
private:
|
||||
virtual int GetCharAt(int64 i) const { return GetChar((int)i); }
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue