pgadmin3/include/utils/popuphelp.h
lsv d47a0fb61c Support hotkey for context help window.
Улучшена поддержка клавиши для навигации в контекстной справке.
Краткий список:
PAGEDOWN,PAGEUP,UP,DOWN,HOME,END - скроллинг окна.
+ - увеличить размер окна.
S - screenshot контекстной справки.
C - копирование в html формате.
2026-04-13 15:03:25 +05:00

357 lines
13 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#ifndef POPUPHELP_H
#define POPUPHELP_H
#include "wx/popupwin.h"
#include <wx/html/htmlwin.h>
#include <wx/clipbrd.h>
#include "utils/FunctionPGHelper.h"
#include <wx/regex.h>
#include <map>
#include <vector>
#include "wx/display.h"
#include "frm/menuServerStatus.h"
class popuphelp :
public wxPopupTransientWindow
{
public:
~popuphelp() {
delete closeTimer;
}
//popuphelp(wxWindow* parent);
bool ProcessLeftDown(wxMouseEvent& event)
{
return false;
}
bool IsValid() {
return isvalid;
}
void SetSizePopup(const wxSize& sz) {
//wxPoint p=this->GetScreenPosition();
//p.x=p.x-50;
//p.y=p.y-50;
//SetSize(p.x,p.y, sz.x,sz.y,wxSIZE_FORCE);
SetSize(sz);
Layout();
Fit();
sizew = sz;
}
wxSize GetSizePopup() { return sizew; }
void keyProcessing(wxKeyEvent& event) {
if (event.GetKeyCode() == WXK_ESCAPE) {
Hide();
event.Skip();
return;
}
if (event.GetKeyCode() == WXK_NUMPAD_ADD) {
wxSize sz = this->GetSize();
wxSize szh = htmlWindow->GetSize();
int xx, yy;
htmlWindow->GetVirtualSize(&xx, &yy);
wxPoint p = GetScreenPosition();
wxSize sizeScreen = getScreenSizeForPoint(p);
if (yy > szh.y) {
if (p.y + sz.y + 50 < sizeScreen.y)
sz.y += 50;
else
if (p.y > 50) { p.y = p.y - 50; sz.y += 50; }
}
if (p.x + sz.x + 50 < sizeScreen.x)
sz.x += 50;
else
if (p.x > 50) { p.x = p.x - 50; sz.x += 50; }
SetSize(p.x, p.y, sz.x, sz.y, wxSIZE_USE_EXISTING);
Layout();
wxSize newsz = GetSize();
//std::cout << sz.GetWidth() << "," << sz.GetHeight() << " new: " << newsz.GetWidth() << "," << newsz.GetHeight() << std::endl;
}
if (event.GetKeyCode() == WXK_PAGEDOWN) htmlWindow->ScrollPages(1);
if (event.GetKeyCode() == WXK_PAGEUP) htmlWindow->ScrollPages(-1);
if (event.GetKeyCode() == WXK_DOWN) htmlWindow->ScrollLines(1);
if (event.GetKeyCode() == WXK_UP) htmlWindow->ScrollLines(-1);
if (event.GetKeyCode() == WXK_HOME) htmlWindow->ScrollPages(-1000);
if (event.GetKeyCode() == WXK_END) htmlWindow->ScrollPages(1000);
//std::cout << "key code " << event.GetKeyCode() << " " << std::endl;
if (event.GetKeyCode() == 'C' && hist.size() > 0) {
if (wxTheClipboard->Open())
{
wxString h = hist[hist.size() - 1];
// Добавляем данные (можно добавить несколько форматов, если нужно)
wxDataObjectComposite* dataobj = new wxDataObjectComposite();
dataobj->Add(new wxHTMLDataObject(h));
wxTheClipboard->SetData(dataobj);
// fix for linux app crush
wxSafeYield();
wxTheClipboard->Close(); // crush app without wxSafeYield();
}
else
{
wxLogError("No open clipboard.");
}
}
if (event.GetKeyCode() == 'S') {
wxSize clientSize = this->GetClientSize();
// Создаём битмап того же размера
wxBitmap bitmap(clientSize.x, clientSize.y, -1); // -1 — лучший формат для экрана
// Создаём DC для рисования в битмап
wxMemoryDC memDC;
memDC.SelectObject(bitmap);
// Очищаем фон (опционально, если окно не полностью перерисовано)
memDC.SetBackground(*wxWHITE_BRUSH);
memDC.Clear();
// Используем wxClientDC для чтения содержимого окна
wxClientDC clientDC(this);
// Переносим данные с clientDC в memDC (копируем прямоугольник)
// Важно: координаты — относительно окна!
memDC.Blit(0, 0, clientSize.x, clientSize.y, &clientDC, 0, 0);
// Освобождаем DC
memDC.SelectObject(wxNullBitmap);
// Открываем буфер обмена
if (wxTheClipboard->Open())
{
// Добавляем данные (можно добавить несколько форматов, если нужно)
wxTheClipboard->SetData(new wxBitmapDataObject(bitmap));
wxTheClipboard->Close();
}
else
{
wxLogError("No open clipboard.");
}
}
};
popuphelp(wxWindow* parent,wxString keyword, FunctionPGHelper *hhelper,wxPoint &posit,wxSize &newSz) : wxPopupTransientWindow(parent, wxPU_CONTAINS_CONTROLS| wxBORDER_NONE) {
wxSize top_sz(newSz);
sizew = top_sz;
//SetSize(top_sz);
this->hhelper = hhelper;
SetBackgroundColour(*wxBLACK);
extern sysSettings* settings;
wxFont fnt = settings->GetSQLFont();
int size = fnt.GetPointSize();
SetFont(fnt);
htmlWindow = new wxHtmlWindow(this, -1, wxDefaultPosition, sizew);
wxFont font(size, wxFontFamily::wxFONTFAMILY_MODERN, wxFontStyle::wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
wxString fixf = font.GetFaceName();
wxString scalf = fnt.GetFaceName();
int f_sizes[7];
f_sizes[0] = int(size -4);
f_sizes[1] = int(size -2);
f_sizes[2] = size;
f_sizes[3] = int(size +1);
f_sizes[4] = int(size +3);
f_sizes[5] = int(size +5);
f_sizes[6] = int(size +7);
htmlWindow->SetFonts(scalf, fixf, f_sizes);
htmlWindow->SetRelatedStatusBar(0);
//htmlWindow->SetPage("<html><body><h1>TEST</h1><span fgcolor=\"#332233\">Set Page Works</span></body></hmtl>");
wxString txt;
txt=hhelper->getDBinfoKeyword(keyword,true);
if (txt.IsEmpty()) {
txt = hhelper->getHelpString(keyword.Lower());
if (txt.empty()) {
txt = hhelper->getSqlCommandHelp(keyword.Lower());
if (txt.empty()) {
isvalid = false;
return;
}
}
}
SetPage(txt);
//htmlWindow->SetSize(htmlWindow->GetInternalRepresentation()->GetWidth(), htmlWindow->GetInternalRepresentation()->GetHeight());
//wxSize sz= htmlWindow->GetSize();
//sz = htmlWindow->GetBestSize();
//htmlWindow->SetHTMLBackgroundImage(wxBitmapBundle::FromSVGFile("data/bg.svg", wxSize(65, 45)));
wxBoxSizer* topsizer;
topsizer = new wxBoxSizer(wxVERTICAL);
//htmlWindow->SetInitialSize(wxSize(htmlWindow->GetInternalRepresentation()->GetWidth(), htmlWindow->GetInternalRepresentation()->GetHeight()));
//SetSize(wxSize(300,150));
topsizer->Add(htmlWindow, 1, wxEXPAND|wxALL, 1);
//wxButton* bu1 = new wxButton(this, wxID_OK, _("OK"));
//bu1->SetDefault();
//topsizer->Add(bu1, 0, wxALL | wxALIGN_RIGHT, 15);
SetSizer(topsizer);
topsizer->Fit(this);
int xx, yy;
htmlWindow->GetVirtualSize(&xx, &yy);
//wxSize sz = GetSize();
wxPoint posScreen;
wxSize sizeScreen;
const int displayNum = wxDisplay::GetFromPoint(posit);
if (displayNum != wxNOT_FOUND)
{
const wxRect rectScreen = wxDisplay(displayNum).GetGeometry();
posScreen = rectScreen.GetPosition();
sizeScreen = rectScreen.GetSize();
}
else // outside of any display?
{
// just use the primary one then
posScreen = wxPoint(0, 0);
sizeScreen = wxGetDisplaySize();
}
wxSize top_new(top_sz);
if (xx > sizeScreen.x) xx = sizeScreen.x - 120;
if (yy > sizeScreen.y) yy = sizeScreen.y - 120;
if (xx > top_sz.x || yy > top_sz.y) {
int dx = 0;
if (htmlWindow->IsScrollbarShown(wxHORIZONTAL)) dx=htmlWindow->GetScrollThumb(wxHORIZONTAL);
SetSizePopup(wxSize(xx+dx, yy+5));
}
//this->Bind(wxEVT_HTML_CELL_CLICKED, [&](wxHtmlCellEvent& event) {
// wxHtmlCell* c = event.GetCell();
//
// wxString ctext=c->ConvertToText(NULL);
// ctext=htmlWindow->SelectionToText();
// wxString s = wxString::Format("cell = %s",ctext.c_str());
// wxMessageBox(s, "cell", wxOK | wxICON_INFORMATION);
// });
this->Bind(wxEVT_HTML_LINK_CLICKED, [&](wxHtmlLinkEvent& event) {
wxHtmlLinkInfo i = event.GetLinkInfo();
wxString name = i.GetHref();
wxString body;
if (name.Len()>1 && name[0]=='#') {
body=this->hhelper->getTextForAnchor(name);
if (body.Len()>0) {
SetPage(body);
}
return;
}
body=this->hhelper->getDBinfoKeyword(name,false);
if (body.IsEmpty()) {
body=this->hhelper->getHelpString(name);
if (body.IsEmpty()) {
body = this->hhelper->getHelpFile(name);
}
}
SetPage(body);
//ctext=htmlWindow->SelectionToText();
//wxString s = wxString::Format("cell = %s",ctext.c_str());
});
Bind(wxEVT_CHAR_HOOK, &popuphelp::keyProcessing,this);
htmlWindow->Bind(wxEVT_RIGHT_UP, [&](wxMouseEvent& event) {
wxString name;
wxLongLong e = wxGetLocalTimeMillis();
if (e - startTimeWin < 150)
return;
//wxString body = this->hhelper->getHelpString(name);
wxString ctext = htmlWindow->SelectionToText();
if (!ctext.IsEmpty()) {
#ifdef __WXMSW__
if (wxTheClipboard->Open())
{
wxDataObjectComposite* dataobj = new wxDataObjectComposite();
dataobj->Add(new wxTextDataObject(ctext));
wxTheClipboard->SetData(dataobj);
wxTheClipboard->Close();
}
#endif
wxString wname = GetParent()->GetName();
if (wname == "frmStatus") {
//CMD_EVENT_FIND_STR
wxCommandEvent event(wxEVT_MENU, CMD_EVENT_FIND_STR);
event.SetEventObject(this);
// Give it some contents
event.SetString(ctext);
// Do send it
GetParent()->ProcessWindowEvent(event);
}
//statusBar->SetStatusText(wxString::Format(" TIMER COUNT %d x:%d,y:%d", count, m.x, m.y));
Hide();
return;
}
this->SetPage("", true);
//ctext=htmlWindow->SelectionToText();
//wxString s = wxString::Format("cell = %s",ctext.c_str());
});
startTimeWin = wxGetLocalTimeMillis();
int inter = hhelper->GetTimerClose();
if (inter != -1) {
closeTimer = new wxTimer(this);
Bind(wxEVT_TIMER, [&](wxTimerEvent& event) {
closeTimer->Stop();
wxPoint pm = this->GetScreenPosition();
wxRect rc = this->GetSize();
wxPoint m = wxGetMousePosition();
rc.x = pm.x;
rc.y = pm.y;
if (!rc.Contains(m)) {
Hide();
return;
}
});
closeTimer->StartOnce(inter);
}
}
private:
bool isvalid = true;
wxHtmlWindow* htmlWindow;
wxLongLong startTimeWin;
wxSize sizew;
FunctionPGHelper* hhelper;
std::vector<wxString> hist;
std::vector<wxPoint> hist_viewp;
void SetPage(wxString innerbody,bool gethistory=false) {
wxString h;
int p = innerbody.Find("<body>");
if (innerbody.Find("<html>")>=0) h = innerbody;
else
if (p > -1) {
innerbody.Replace("<body>", "<html><body TEXT=\"#000000\" BGCOLOR=\"#FFFFE0\" LINK=\"#0000FF\" VLINK=\"#FF0000\" ALINK=\"#000088\">", false);
h = "" + innerbody + "";
}
else
h = "<html><body TEXT=\"#000000\" BGCOLOR=\"#FFFFE0\" LINK=\"#0000FF\" VLINK=\"#FF0000\" ALINK=\"#000088\">" + innerbody + "</body></hmtl>";
if (gethistory) {
if (hist.size() < 2) {
Hide();
return;
}
hist.pop_back();
h = hist[hist.size()-1];
}
else {
if (hist.size()>0) {
wxPoint ps=htmlWindow->GetViewStart();
hist_viewp.push_back(ps);
}
hist.push_back(h);
}
htmlWindow->SetPage(h);
if (gethistory && hist_viewp.size()>0) {
wxPoint ps=hist_viewp[hist_viewp.size()-1];
hist_viewp.pop_back();
htmlWindow->Scroll(ps);
} else {
//
wxPoint ps(0,0);
htmlWindow->Scroll(ps);
}
}
private:
wxTimer *closeTimer=NULL;
};
#endif