|
|
nono 1.7.0
//
// nono
// Copyright (C) 2020 nono project
// Licensed under nono-license.txt
//
//
// ログモニター
//
#include "wxlogmonitor.h"
#include "logger.h"
#include "mainapp.h"
#include "monitor.h"
#include "sjis.h"
//#define WINDOW_DEBUG 1
#if defined(WINDOW_DEBUG)
#define DPRINTF(fmt...) printf(fmt)
#else
#define DPRINTF(fmt...) /**/
#endif
// コンストラクタ
WXLogMonitor::WXLogMonitor(wxWindow *parent)
: inherited(parent, wxID_ANY, _("Log"), DEFAULT_STYLE | wxRESIZE_BORDER)
{
DPRINTF("%s begin\n", __method__);
// +-----------------+---------+
// | LogMonitorPanel | VScroll |
// +-----------------+---------+
// モニタ
logger = gMainApp.GetLogger();
screen = new LogMonitorPanel(this, logger->GetMonitor());
// スクロールバー
vscroll = new WXScrollBar(this, wxID_ANY, wxSB_VERTICAL);
// 自前レイアウト。
SetMyLayout();
// ウィンドウサイズを確定させる
FontChanged();
// スクロールのために (パネル領域での) MouseWheel イベントもここで
// 受け取りたい。スクロールバー上のマウスホイール操作はスクロールバーが
// 処理しているので問題ないが、パネル領域でのマウスホイール操作はここ
// (wxFrame)ではなくパネルに対して飛んでくる。
// ここで一緒に処理したほうが楽なので、こちらに回す。
screen->Bind(wxEVT_MOUSEWHEEL, &WXLogMonitor::OnMouseWheel, this);
// スクロールバーからの位置変更通知イベントは表示パネルへ回す。
vscroll->Bind(NONO_EVT_SCROLL, &WXLogMonitor::OnScroll, this);
// XXX ログウィンドウのコピーはまだ動いてない
screen->DisconnectContextMenu();
DPRINTF("%s done\n", __method__);
}
// デストラクタ
WXLogMonitor::~WXLogMonitor()
{
}
void
WXLogMonitor::FontChanged()
{
screen->FontChanged();
vscroll->FontChanged();
DPRINTF("%s %d\n", __method__, screen->GetFontHeight());
Fit();
}
// 自前レイアウト方式のサイズに関する情報を返す。
bool
WXLogMonitor::GetMySizeHints(wxSize *newp, wxSize *minp, wxSize *maxp,
wxSize *incp)
{
auto ssize = screen->GetSize();
auto vsize = vscroll->GetSize();
int x = ssize.x + vsize.x;
int min_y = std::max(vscroll->GetMinSize().y, screen->GetScreenHeight(1));
int new_y = std::max(ssize.y, min_y);
wxSize newsize(x, new_y);
wxSize minsize(x, min_y);
wxSize maxsize(x, GetMaxClientSize().y);
wxSize incsize(0, screen->GetFontHeight());
if (newp) *newp = newsize;
if (minp) *minp = minsize;
if (maxp) *maxp = maxsize;
if (incp) *incp = incsize;
return true;
}
bool
WXLogMonitor::Layout()
{
if (MyLayout() == false) {
// コントロールを配置。
wxSize client = GetClientSize();
const wxSize vsize = vscroll->GetSize();
int panel_width = client.x - vsize.x;
int panel_height = client.y;
// 最低でも 1px ないと GTK とかに怒られる。今は起きないはず?
if (__predict_false(panel_width < 1)) {
panel_width = 1;
}
if (__predict_false(panel_height < 1)) {
panel_height = 1;
}
screen->SetSize(0, 0, panel_width, panel_height);
vscroll->SetSize(panel_width, 0, vsize.x, panel_height);
// スクロールバーを再設定
SetScroll();
}
return true;
}
// スクロールバーを再設定
void
WXLogMonitor::SetScroll()
{
int displines;
int row;
int pos;
int thumbsize;
int range;
int pagesize;
displines = logger->GetDispLines();
row = screen->GetRow();
if (displines <= row) {
pos = 0;
range = row;
} else {
pos = (displines - row) - screen->GetUserData();
range = displines;
}
thumbsize = row;
pagesize = thumbsize - 1;
vscroll->SetScrollParam(pos, thumbsize, range, pagesize);
}
// マウスホイールイベント (WXTextScreen 上で起きたやつをこっちに回してある)
void
WXLogMonitor::OnMouseWheel(wxMouseEvent& event)
{
// GetWheelRotation() は上(奥)向きに回すと +120、下(手前)に回すと -120。
// どこの決まりか知らんけど、スクロールバーのほうはホイール1段階で3行
// スクロールするのでそれに合わせる。
int pos = vscroll->GetThumbPosition();
pos = pos - event.GetWheelRotation() / 40;
int maxpos = vscroll->GetRange() - vscroll->GetThumbSize();
if (pos < 0)
pos = 0;
if (pos > maxpos)
pos = maxpos;
DoScroll(pos);
// スクロールバーの位置を追従
vscroll->SetThumbPosition(pos);
}
// スクロールバーからの通知イベント
void
WXLogMonitor::OnScroll(wxScrollEvent& event)
{
DoScroll(event.GetPosition());
}
// スクロール処理 (OnScroll() と OnMouseWheel() から呼ばれる)
void
WXLogMonitor::DoScroll(int pos)
{
// pos 即ちスクロールバーの Thumb の位置は上端の位置。
// 対してログウィンドウでは下端を基準にしたほうが処理しやすい。
// userdata = 0 だと Thumb が下に接していてパネルの最下行が最新行、
// userdata = 1 だと Thumb が下から1段階分上にありパネルの最下行は
// 最新行の一つ前の行、となる。
//
// Range=6 Range=6
// Pos=4 Pos=0
// ThumbSz=2 ThumbSz=2
// userdata=0 userdata=4
// △ △
// □ ■
// □ ■
// □ □
// □ □
// ■ □
// ■ □
// ▽ ▽
// パネル最下行に表示する行の最新行からのオフセット
// (0 なら Thumb が下端に接している)
int vpos = vscroll->GetRange() - vscroll->GetThumbSize() - pos;
screen->SetUserData(vpos);
}
//
// モニターオブジェクト
//
// コンストラクタ
LogMonitorPanel::LogMonitorPanel(WXLogMonitor *parent_, Monitor *monitor_)
: inherited(parent_, monitor_)
{
parent = parent_;
}
// デストラクタ
LogMonitorPanel::~LogMonitorPanel()
{
}
void
LogMonitorPanel::DoRefresh()
{
inherited::DoRefresh();
// スクロールバーを再設定。
parent->SetScroll();
}
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.