ultimatepp/uppsrc/CtrlCore/Preedit.cpp
2022-02-26 18:31:33 +01:00

131 lines
No EOL
2.6 KiB
C++

#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;
}
};