campo-sirio/xvaga/xvtwin.cpp

1228 lines
28 KiB
C++
Raw Normal View History

#include "wxinc.h"
#define XTWIN_CPP 1
#include "xvt.h"
#include "xvtwin.h"
#include <wx/aui/aui.h>
#include <wx/dcbuffer.h>
#include <wx/notebook.h>
#include <wx/taskbar.h>
#include <wx/treectrl.h>
#include <wx/vlbox.h>
///////////////////////////////////////////////////////////
// Utilities
///////////////////////////////////////////////////////////
wxHashTable _nice_windows;
wxFrame* _task_win = NULL;
EVENT_HANDLER _task_win_handler = NULL;
wxRect NormalizeRCT(const RCT* prct)
{
wxRect rct;
if (prct != NULL)
{
rct.x = min(prct->left, prct->right);
rct.y = min(prct->top, prct->bottom);
rct.width = abs(prct->right - prct->left);
rct.height = abs(prct->bottom - prct->top);
}
return rct;
}
///////////////////////////////////////////////////////////
// Caret emulation
///////////////////////////////////////////////////////////
class TwxCaret : private wxTimer
{
WINDOW _owner;
PNT _pos;
wxSize _size;
bool _visible;
bool _drawn;
protected:
void Toggle();
virtual void Notify() { Toggle(); }
public:
void SetPos(int x, int y);
void SetSize(int x, int y) { _size.x = x; _size.y = y; }
void Show(WINDOW w, bool on = true);
void Hide() { Show(NULL_WIN, false); }
bool IsVisible() const { return _visible; }
WINDOW Owner() const { return _owner; }
void Kill();
TwxCaret() : _owner(NULL_WIN), _visible(false) { }
virtual ~TwxCaret() { Kill(); }
} _TheCaret;
void TwxCaret::Kill()
{ _owner = NULL_WIN; }
void TwxCaret::SetPos(int x, int y)
{
if (_visible && _drawn) // Lo cancella se necessario
Toggle();
_pos.h = x; _pos.v = y;
}
void TwxCaret::Show(WINDOW w, bool on)
{
if (_visible && _drawn)
Toggle(); // Lo cancella
_visible = on;
if (on)
{
_owner = w;
Toggle();
wxTimer::Start(500); // Lampeggia ogni mezzo secondo
}
else
{
if (w == _owner || w == NULL_WIN)
Kill();
}
}
void TwxCaret::Toggle()
{
if (!_visible || _owner == NULL_WIN)
return;
_drawn = !_drawn;
DRAW_CTOOLS dct;
xvt_dwin_get_draw_ctools(_owner, &dct);
CPEN pen;
pen.width = _size.x;
pen.pat = PAT_SOLID;
pen.style = P_SOLID;
pen.color = dct.fore_color;
xvt_dwin_set_draw_mode(_owner, M_NOT_XOR);
xvt_dwin_set_cpen(_owner, &pen);
xvt_dwin_draw_set_pos(_owner, _pos);
PNT p = _pos; p.v -= _size.y-1;
xvt_dwin_set_clip(_owner, NULL); // Non si sa mai!
xvt_dwin_draw_line(_owner, p);
xvt_dwin_set_draw_ctools(_owner, &dct);
}
void xvt_win_set_caret_size(WINDOW win, int width, int height)
{
_TheCaret.SetSize(width, height);
}
void xvt_win_set_caret_pos(WINDOW win, PNT p)
{
_TheCaret.SetPos(p.h, p.v-1);
}
void xvt_win_set_caret_visible(WINDOW win, BOOLEAN on)
{
_TheCaret.Show(win, on != 0);
}
///////////////////////////////////////////////////////////
// Generic Display context
///////////////////////////////////////////////////////////
TDC::TDC(wxWindow* owner) : _dc(NULL)
{
_owner = owner;
memset(&_dct, 0, sizeof(_dct));
_dct.pen.width = 0;
_dct.pen.pat = PAT_SOLID;
_dct.pen.style = P_SOLID;
_dct.pen.color = COLOR_BLACK;
_dct.brush.pat = PAT_HOLLOW;
_dct.brush.color = COLOR_WHITE;
_dct.mode = M_COPY;
_dct.fore_color = COLOR_BLACK;
_dct.back_color = COLOR_WHITE;
_dct.opaque_text = FALSE;
_font.SetPointSize(9); // Default font
_deltaf = 0;
// Reset clip area
SetClippingBox(NULL);
_real_clip = _clip;
_dirty = -1; // Absolutely force setting
}
TDC::~TDC()
{
KillDC();
}
void TDC::SetDirty(int d)
{
if (_dirty >= 0)
_dirty = d;
}
static int PatternToStyle(PAT_STYLE pat)
{
int style = wxSOLID;
switch (pat)
{
case PAT_NONE:
case PAT_HOLLOW: style = wxTRANSPARENT; break;
case PAT_SOLID: style = wxSOLID; break;
case PAT_HORZ: style = wxHORIZONTAL_HATCH; break;
case PAT_VERT: style = wxVERTICAL_HATCH; break;
case PAT_FDIAG: style = wxFDIAGONAL_HATCH; break;
case PAT_BDIAG: style = wxBDIAGONAL_HATCH; break;
case PAT_CROSS: style = wxCROSS_HATCH; break;
case PAT_DIAGCROSS: style = wxCROSSDIAG_HATCH; break;
case PAT_RUBBER:
case PAT_SPECIAL:
default: SORRY_BOX(); break;
}
return style;
}
static int PenStyleToStyle(PEN_STYLE s, PAT_STYLE p)
{
int style = wxSOLID;
if (p != PAT_HOLLOW)
{
switch (s)
{
case P_DOT : style = wxDOT; break;
case P_DASH: style = wxSHORT_DASH; break;
default: break;
}
}
else
style = wxTRANSPARENT;
return style;
}
bool TDC::PenChanged() const
{
const int diff = memcmp(&_dct.pen, &_real_dct.pen, sizeof(_dct.pen));
return diff != 0;
}
bool TDC::BrushChanged() const
{
const int diff = memcmp(&_dct.brush, &_real_dct.brush, sizeof(_dct.brush));
return diff != 0;
}
bool TDC::FontChanged() const
{
return _font != _real_font;
}
bool TDC::ClipChanged() const
{
const int diff = memcmp(&_clip, &_real_clip, sizeof(_clip));
return diff != 0;
}
#ifdef LINUX
bool is_printer_dc(wxDC * dc)
{
return wxDynamicCast(dc, wxPostScriptDC) != NULL;
}
#endif
wxDC& TDC::GetDC(bool bPaint)
{
if (bPaint)
{
KillDC();
//_dc = new wxAutoBufferedPaintDC(_owner); // Funziona ma si vedono cose strane temporanee
_dc = new wxPaintDC(_owner);
_dirty = -1;
}
else
{
if (_dc == NULL)
{
if (_owner == NULL || (unsigned long)_owner == SCREEN_WIN)
_dc = new wxScreenDC();
else
_dc = new wxClientDC(_owner);
_dirty = -1;
}
}
if (_dirty)
{
if (_dirty < 0 || PenChanged())
{
CAST_COLOR(_dct.pen.color, pen_color);
wxPen* pen = wxThePenList->FindOrCreatePen(pen_color, _dct.pen.width, PenStyleToStyle(_dct.pen.style, _dct.pen.pat));
_dc->SetPen(*pen);
_real_dct.pen = _dct.pen;
}
if (_dirty < 0 || BrushChanged())
{
CAST_COLOR(_dct.brush.color, brush_color);
wxBrush* brush = wxTheBrushList->FindOrCreateBrush(brush_color, PatternToStyle(_dct.brush.pat));
_dc->SetBrush(*brush);
_real_dct.brush = _dct.brush;
}
if (_dirty < 0 || _dct.mode != _real_dct.mode)
{
#ifdef LINUX
if(!is_printer_dc(_dc))
{
#endif
switch(_dct.mode)
{
case M_COPY: _dc->SetLogicalFunction(wxCOPY); break;
case M_OR: _dc->SetLogicalFunction(wxOR); break;
case M_XOR: _dc->SetLogicalFunction(wxXOR); break;
case M_CLEAR: _dc->SetLogicalFunction(wxCLEAR); break;
case M_NOT_COPY: _dc->SetLogicalFunction(wxSRC_INVERT); break;
case M_NOT_OR: _dc->SetLogicalFunction(wxNOR); break;
case M_NOT_XOR: _dc->SetLogicalFunction(wxEQUIV); break;
case M_NOT_CLEAR:_dc->SetLogicalFunction(wxSET); break;
default: SORRY_BOX();
}
#ifdef LINUX
}
#endif
_real_dct.mode = _dct.mode;
}
if (_dirty < 0 || _dct.fore_color != _real_dct.fore_color)
{
CAST_COLOR(_dct.fore_color, fore_color);
_dc->SetTextForeground(fore_color);
_real_dct.fore_color = _dct.fore_color;
}
if (_dirty < 0 || _dct.back_color != _real_dct.back_color)
{
CAST_COLOR(_dct.back_color, back_color);
_dc->SetTextBackground(back_color);
_real_dct.back_color = _dct.back_color;
}
if (_dirty < 0 || _dct.opaque_text != _real_dct.opaque_text)
{
_dc->SetBackgroundMode(_dct.opaque_text ? wxSOLID : wxTRANSPARENT);
_real_dct.opaque_text = _dct.opaque_text;
}
if (_dirty < 0 || FontChanged())
{
const wxFont& f = _font.Font(_dc, (WINDOW)_owner);
_dc->SetFont(f);
_real_font = _font;
int height, desc, lead;
_dc->GetTextExtent("Campo", NULL, &height, &desc, &lead);
_deltaf = height-desc;
}
if (_dirty < 0 || ClipChanged())
{
_dc->DestroyClippingRegion();
if (_clip.bottom < 4096)
_dc->SetClippingRegion(NormalizeRCT(&_clip));
_real_clip = _clip;
}
_dirty = false;
}
return *_dc;
}
void TDC::KillDC()
{
if (_dc != NULL)
{
SetClippingBox(NULL);
_real_clip = _clip;
delete _dc;
_dc = NULL;
}
}
void TDC::SetClippingBox(const RCT* pRct)
{
if (pRct != NULL)
{
const wxRect rct = NormalizeRCT(pRct);
_clip.left = rct.x; _clip.top = rct.y;
_clip.right = rct.GetRight(); _clip.bottom = rct.GetBottom();
}
else
{
_clip.left = _clip.top = 0;
_clip.right = _clip.bottom = 32000; // 32000 serve per i TDC di stampa (aumentare quando possibile) per il video basterebbe 4096
}
}
bool TDC::GetClippingBox(RCT* pRct) const
{
*pRct = _clip;
return _clip.right > _clip.left;
}
TDCMapper& GetTDCMapper()
{
static TDCMapper* _dc_map = NULL;
if (_dc_map == NULL)
_dc_map = new TDCMapper;
return *_dc_map;
}
void TDCMapper::DestroyDC(WINDOW owner)
{
if (owner)
{
TDC* pTDC = (*this)[owner];
if (pTDC)
pTDC->KillDC();
}
else
{
for (TDCMapper::iterator it = begin(); it != end(); ++it)
{
TDC* pTDC = it->second;
if (pTDC)
pTDC->KillDC();
}
}
}
void TDCMapper::DestroyTDC(WINDOW owner)
{
if (owner != NULL_WIN)
{
TDC* pTDC = (*this)[owner];
if (pTDC)
delete pTDC;
erase(owner);
}
else
{
TDCMapper::iterator it;
for (it = begin(); it != end(); ++it)
{
TDC* pTDC = it->second;
if (pTDC)
delete pTDC;
}
clear();
}
_pLastOwner = NULL_WIN;
}
TDC& TDCMapper::GetTDC(WINDOW owner)
{
if (owner != _pLastOwner)
{
wxASSERT(owner != NULL_WIN);
TDC* pTDC = (*this)[owner];
if (pTDC == NULL)
{
if (owner == PRINTER_WIN)
pTDC = new TPrintDC((wxWindow*)owner);
else
pTDC = new TDC((wxWindow*)owner);
(*this)[owner] = pTDC;
}
_pLastOwner = owner;
_pLastTDC = pTDC;
}
return *_pLastTDC;
}
bool TDCMapper::HasValidDC(WINDOW owner) const
{
if (owner == NULL_WIN)
return false;
if (owner == (WINDOW)_pLastOwner)
return true;
TDC* pTDC = (*((TDCMapper *) this))[owner];
return pTDC != NULL;
}
///////////////////////////////////////////////////////////
// Generic window class
///////////////////////////////////////////////////////////
IMPLEMENT_DYNAMIC_CLASS(TwxWindowBase, wxWindow)
#ifdef WIN32
WXLRESULT TwxWindowBase::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam)
{
WXLRESULT rc = 0;
bool processed = false;
switch (nMsg)
{
case WM_CLOSE:
processed = !Close();
break;
default:
break;
}
if ( !processed )
rc = wxWindow::MSWWindowProc(nMsg, wParam, lParam);
return rc;
}
#endif
bool TwxWindowBase::CreateBase(wxWindow *parent, wxWindowID id, const wxString &title,
const wxPoint &pos, const wxSize &size, long style)
{
wxWindowBase::Show(false); // Evita inutili sfarfallamenti
return Create(parent, id, pos, size, style, title);
}
TwxWindowBase::TwxWindowBase(wxWindow *parent, wxWindowID id, const wxString &title,
const wxPoint &pos, const wxSize &size, long style)
{
CreateBase(parent, id, title, pos, size, style);
}
IMPLEMENT_DYNAMIC_CLASS(TwxWindow, TwxWindowBase)
BEGIN_EVENT_TABLE(TwxWindow, TwxWindowBase)
EVT_CHAR(TwxWindow::OnChar)
EVT_KEY_DOWN(TwxWindow::OnKeyDown)
EVT_CLOSE(TwxWindow::OnClose)
EVT_KILL_FOCUS(TwxWindow::OnKillFocus)
EVT_LEFT_DCLICK(TwxWindow::OnMouseDouble)
EVT_LEFT_DOWN(TwxWindow::OnMouseDown)
EVT_LEFT_UP(TwxWindow::OnMouseUp)
EVT_MENU_RANGE(1000, 32766, TwxWindow::OnMenu)
EVT_MIDDLE_DOWN(TwxWindow::OnMouseDown)
EVT_MIDDLE_UP(TwxWindow::OnMouseUp)
EVT_MOTION(TwxWindow::OnMouseMove)
EVT_MOUSE_CAPTURE_LOST(TwxWindow::OnMouseCaptureLost)
EVT_MOUSEWHEEL(TwxWindow::OnMouseWheel)
EVT_PAINT(TwxWindow::OnPaint)
EVT_RIGHT_DOWN(TwxWindow::OnMouseDown)
EVT_RIGHT_UP(TwxWindow::OnMouseUp)
EVT_SCROLL(TwxWindow::OnScroll)
EVT_SCROLLWIN(TwxWindow::OnScrollWin)
EVT_SET_FOCUS(TwxWindow::OnSetFocus)
EVT_SIZE(TwxWindow::OnSize)
EVT_TIMER(TIMER_ID, TwxWindow::OnTimer)
EVT_COMMAND(wxID_ANY, wxEVT_COMMAND_BUTTON_CLICKED, TwxWindow::OnButton)
EVT_COMMAND(wxID_ANY, wxEVT_COMMAND_CHECKBOX_CLICKED, TwxWindow::OnCheckBox)
EVT_COMMAND(wxID_ANY, wxEVT_COMMAND_RADIOBUTTON_SELECTED, TwxWindow::OnRadioButton)
END_EVENT_TABLE()
void TwxWindow::DoXvtEvent(EVENT& e)
{
if (this != NULL && _eh != NULL)
_eh((WINDOW)this, &e);
}
void TwxWindow::OnChar(wxKeyEvent& evt)
{
static int nSkipNextDotKey = -883; // Valore indefinito
if (nSkipNextDotKey == -883) // Devo stabilire se attivare la gestione o no
{
const char* campoini = xvt_fsys_get_campo_ini();
char str[2];
xvt_sys_get_profile_string(campoini, "Main", "Point2Comma", "1", str, sizeof(str));
nSkipNextDotKey = strchr("1XY", *str) != NULL ? 0 : -1; // Dis/Abilita conversione punto in virgola
}
EVENT e; memset(&e, 0, sizeof(EVENT));
e.type = E_CHAR;
int k = evt.GetKeyCode();
if (nSkipNextDotKey == 1)
{
nSkipNextDotKey = 0;
if (k == '.')
{
evt.Skip();
return;
}
}
switch (k)
{
case WXK_ALT:
case WXK_MENU:
case WXK_NUMPAD0:
case WXK_NUMPAD1:
case WXK_NUMPAD2:
case WXK_NUMPAD3:
case WXK_NUMPAD4:
case WXK_NUMPAD5:
case WXK_NUMPAD6:
case WXK_NUMPAD7:
case WXK_NUMPAD8:
case WXK_NUMPAD9:
evt.Skip();
return;
case WXK_NUMPAD_DECIMAL: // Arriva solo dalla 3.6.3 in poi
case WXK_DECIMAL: // ??? Arriva sia '.' sia WXK_DECIMAL=340
if (nSkipNextDotKey == 0)
{
k = ','; // Trasformo il punto in virgola
nSkipNextDotKey = 1;
}
break;
case WXK_NUMPAD_ADD: k = '+';break;
case WXK_DOWN : k = K_DOWN; break;
case WXK_END : k = K_LEND; break;
case WXK_HOME : k = K_LHOME; break;
case WXK_LEFT : k = K_LEFT; break;
case WXK_NEXT : k = K_NEXT; break;
case WXK_PRIOR: k = K_PREV; break;
case WXK_RIGHT: k = K_RIGHT; break;
case WXK_UP : k = K_UP; break;
case WXK_TAB:
if (evt.ShiftDown())
k = K_BTAB;
break;
default:
if (k >= WXK_F1 && k <= WXK_F24)
k = K_F1 + k - WXK_F1;
break;
}
e.v.chr.shift = evt.ShiftDown();
e.v.chr.control = evt.ControlDown();
if (evt.AltDown())
{
e.v.chr.control = TRUE;
if (xvt_chr_is_alnum(k))
k = toupper(k);
else
{
if (strchr("+-", k) == NULL) // Aggiungere qui vari testi eventuali
{
evt.Skip();
return;
}
}
}
e.v.chr.ch = k;
DoXvtEvent(e);
}
void TwxWindow::OnKeyDown(wxKeyEvent& e)
{
#ifdef WIN32
// Triste necessita' per gestire corretamente Alt+'+' del tasterino
const int k = e.GetKeyCode();
if (k == WXK_NUMPAD_ADD)
{
if (e.AltDown())
{
OnChar(e);
return;
}
}
#else
if (e.AltDown() || e.ControlDown())
{
OnChar(event);
return;
}
#endif
e.Skip();
}
void TwxWindow::OnClose(wxCloseEvent& WXUNUSED(e))
{
EVENT e; memset(&e, 0, sizeof(EVENT));
e.type = E_CLOSE;
DoXvtEvent(e);
}
void TwxWindow::OnKillFocus(wxFocusEvent& WXUNUSED(e))
{
if (_TheCaret.Owner() == (WINDOW)this)
_TheCaret.Hide();
EVENT e; memset(&e, 0, sizeof(EVENT));
e.type = E_FOCUS;
e.v.active = 0;
DoXvtEvent(e);
}
void TwxWindow::OnMenu(wxCommandEvent& evt)
{
EVENT e; memset(&e, 0, sizeof(EVENT));
e.type = E_COMMAND;
e.v.cmd.control = 0; e.v.cmd.shift = 0;
e.v.cmd.tag = evt.GetId();
DoXvtEvent(e);
}
void TwxWindow::OnMouseCaptureLost(wxMouseCaptureLostEvent& WXUNUSED(e))
{
xvt_win_release_pointer();
}
void TwxWindow::OnMouseDouble(wxMouseEvent& evt)
{
EVENT e; memset(&e, 0, sizeof(EVENT));
e.type = E_MOUSE_DBL;
e.v.mouse.button = (evt.RightDown() ? 1 : 0) + (evt.MiddleDown() ? 2 : 0);
e.v.mouse.control = evt.ControlDown();
e.v.mouse.shift = evt.ShiftDown();
e.v.mouse.where.h = evt.GetX();
e.v.mouse.where.v = evt.GetY();
DoXvtEvent(e);
}
void TwxWindow::OnMouseDown(wxMouseEvent& evt)
{
EVENT e; memset(&e, 0, sizeof(EVENT));
e.type = E_MOUSE_DOWN;
e.v.mouse.button = (evt.RightDown() ? 1 : 0) + (evt.MiddleDown() ? 2 : 0);
e.v.mouse.control = evt.ControlDown();
e.v.mouse.shift = evt.ShiftDown();
e.v.mouse.where.h = evt.GetX();
e.v.mouse.where.v = evt.GetY();
DoXvtEvent(e);
SetFocus(); // Triste necessita'
}
void TwxWindow::OnMouseMove(wxMouseEvent& evt)
{
EVENT e; memset(&e, 0, sizeof(EVENT));
e.type = E_MOUSE_MOVE;
e.v.mouse.button = (evt.RightIsDown() ? 1 : 0) + (evt.MiddleIsDown() ? 2 : 0);
e.v.mouse.control = evt.ControlDown();
e.v.mouse.shift = evt.m_shiftDown;
e.v.mouse.where.h = evt.GetX();
e.v.mouse.where.v = evt.GetY();
DoXvtEvent(e);
}
void TwxWindow::OnMouseUp(wxMouseEvent& evt)
{
EVENT e; memset(&e, 0, sizeof(EVENT));
e.type = E_MOUSE_UP;
e.v.mouse.button = (evt.RightUp() ? 1 : 0) + (evt.MiddleUp() ? 2 : 0);
e.v.mouse.control = evt.ControlDown();
e.v.mouse.shift = evt.ShiftDown();
e.v.mouse.where.h = evt.GetX();
e.v.mouse.where.v = evt.GetY();
DoXvtEvent(e);
}
void TwxWindow::OnMouseWheel(wxMouseEvent& evt)
{
const int nRot = evt.GetWheelRotation();
if (nRot != 0)
{
EVENT e; memset(&e, 0, sizeof(EVENT));
e.type = E_VSCROLL;
e.v.scroll.pos = evt.GetY();
e.v.scroll.what = nRot > 0 ? SC_LINE_UP : SC_LINE_DOWN;
DoXvtEvent(e);
}
}
void TwxWindow::OnPaint(wxPaintEvent& WXUNUSED(evt))
{
const wxRect rctDamaged = GetUpdateRegion().GetBox();
EVENT e; memset(&e, 0, sizeof(EVENT));
e.type = E_UPDATE;
RCT& rct = e.v.update.rct;
//wxRect rctDamaged = GetUpdateRegion().GetBox();
rct.left = rctDamaged.x;
rct.top = rctDamaged.y;
rct.right = rctDamaged.GetRight()+1;
rct.bottom = rctDamaged.GetBottom()+1;
TDC& tdc = GetTDCMapper().GetTDC((WINDOW)this);
tdc.GetDC(true); // Forza la creazione di un wxPaintDC
DoXvtEvent(e);
tdc.KillDC(); // Distrugge il wxPaintDC
GetTDCMapper().DestroyDC(NULL_WIN); // Distrugge davvero tutti i wxClientDC residui (risolve molte "porcate" del video)
}
static SCROLL_CONTROL ConvertScrollToXVT(wxEventType et)
{
if (et == wxEVT_SCROLL_TOP)
return SC_THUMB; // Meglio di niente
if (et == wxEVT_SCROLL_BOTTOM)
return SC_THUMB; // Meglio di niente
if (et == wxEVT_SCROLL_LINEUP)
return SC_LINE_UP;
if (et == wxEVT_SCROLL_LINEDOWN)
return SC_LINE_DOWN;
if (et == wxEVT_SCROLL_PAGEUP)
return SC_PAGE_UP;
if (et == wxEVT_SCROLL_PAGEDOWN)
return SC_PAGE_DOWN;
if (et == wxEVT_SCROLL_THUMBTRACK)
return SC_THUMBTRACK;
if (et == wxEVT_SCROLL_THUMBRELEASE)
return SC_THUMB;
return SC_NONE;
}
void TwxWindow::OnScroll(wxScrollEvent& evt)
{
SCROLL_CONTROL sc = ConvertScrollToXVT(evt.GetEventType());
if (sc != SC_NONE)
{
EVENT e; memset(&e, 0, sizeof(EVENT));
e.type = E_CONTROL;
e.v.ctl.id = evt.GetId();
e.v.ctl.ci.type = evt.GetOrientation()==wxHORIZONTAL ? WC_HSCROLL : WC_VSCROLL;
e.v.ctl.ci.win = (WINDOW)evt.GetEventObject();
e.v.ctl.ci.v.scroll.pos = evt.GetPosition();
e.v.ctl.ci.v.scroll.what = sc;
DoXvtEvent(e);
}
}
void TwxWindow::OnScrollWin(wxScrollWinEvent& evt)
{
wxEventType et = evt.GetEventType();
et -= (wxEVT_SCROLLWIN_TOP - wxEVT_SCROLL_TOP);
const SCROLL_CONTROL sc = ConvertScrollToXVT(et);
if (sc != SC_NONE)
{
EVENT e; memset(&e, 0, sizeof(EVENT));
e.type = evt.GetOrientation() == wxHORIZONTAL ? E_HSCROLL : E_VSCROLL;
e.v.scroll.pos = evt.GetPosition();
e.v.scroll.what = sc;
DoXvtEvent(e);
}
}
void TwxWindow::OnSetFocus(wxFocusEvent& WXUNUSED(e))
{
EVENT e; memset(&e, 0, sizeof(EVENT));
e.type = E_FOCUS;
e.v.active = 1;
DoXvtEvent(e);
}
void TwxWindow::OnSize(wxSizeEvent& evt)
{
EVENT e; memset(&e, 0, sizeof(EVENT));
e.type = E_SIZE;
e.v.size.width = evt.GetSize().x;
e.v.size.height = evt.GetSize().y;
DoXvtEvent(e);
}
void TwxWindow::OnTimer(wxTimerEvent& WXUNUSED(evt))
{
EVENT e; memset(&e, 0, sizeof(EVENT));
e.type = E_TIMER;
e.v.timer.id = (WINDOW)this;
DoXvtEvent(e);
}
void TwxWindow::OnButton(wxCommandEvent& evt)
{
EVENT e; memset(&e, 0, sizeof(EVENT));
e.type = E_CONTROL;
e.v.ctl.id = evt.GetId();
e.v.ctl.ci.type = WC_PUSHBUTTON;
DoXvtEvent(e);
}
void TwxWindow::OnCheckBox(wxCommandEvent& evt)
{
EVENT e; memset(&e, 0, sizeof(EVENT));
e.type = E_CONTROL;
e.v.ctl.id = evt.GetId();
e.v.ctl.ci.type = WC_CHECKBOX;
DoXvtEvent(e);
}
void TwxWindow::OnRadioButton(wxCommandEvent& evt)
{
EVENT e; memset(&e, 0, sizeof(EVENT));
e.type = E_CONTROL;
e.v.ctl.id = evt.GetId();
e.v.ctl.ci.type = WC_RADIOBUTTON;
DoXvtEvent(e);
}
void TwxWindow::SetMenuTree(const MENU_ITEM* tree)
{
wxASSERT(tree != NULL);
if (tree != NULL)
{
if (m_menu)
xvt_res_free_menu_tree(m_menu);
m_menu = xvt_menu_duplicate_tree(tree);
TTaskWin* tw = wxStaticCast(_task_win, TTaskWin);
tw->PushMenuTree(tree, this);
}
}
BOOLEAN TwxWindow::AddPane(wxWindow* wnd, const char* caption, int nDock, int nFlags)
{
BOOLEAN ok = wnd != NULL;
if (ok)
{
if (m_pManager == NULL)
m_pManager = new wxAuiManager(this);
wxAuiPaneInfo pane;
pane.DefaultPane(); pane.Dockable(false);
const wxSize sz = wnd->GetSize();
switch (nDock)
{
case 1: // Left
pane.Left().Floatable(true).LeftDockable().RightDockable();
pane.MinSize(sz.x/2, -1).BestSize(sz.x, -1).MaxSize(3*sz.x/2, -1);
break;
case 2: // Top
pane.Top().Floatable(true).TopDockable().BottomDockable().MinSize(-1, sz.y/2);
break;
case 3: // Right
pane.Right().Floatable(true).LeftDockable().RightDockable();
pane.MinSize(sz.x/2, -1).BestSize(sz.x, -1).MaxSize(3*sz.x/2, -1);
break;
case 4: // Bottom
pane.Bottom().Floatable(true).TopDockable().BottomDockable().MinSize(-1, sz.y/2);
break;
case 52: // Center Top
pane.CentrePane().CaptionVisible(true).TopDockable();
break;
case 54: // Center Bottom
pane.CentrePane().CaptionVisible(true).BottomDockable();
break;
case 62: // Top toolbar
pane.ToolbarPane().Top().MinSize(wxSize(-1,sz.y));
break;
default: // Center
pane.CentrePane().Floatable(false);
break;
}
pane.CloseButton(false);
if (caption && *caption)
{
pane.Caption(caption);
pane.Name(caption);
}
if (nFlags)
pane.SetFlag(nFlags, true);
ok = m_pManager->AddPane(wnd, pane);
if (ok)
m_pManager->Update();
}
return ok;
}
TwxWindow::TwxWindow()
: m_menu(NULL), _type(W_DOC), _eh(NULL), _app_data(0L),
_timer(NULL), m_pManager(NULL)
{ }
TwxWindow::TwxWindow(wxWindow *parent, wxWindowID id, const wxString& title,
const wxPoint& pos, const wxSize& size, long style)
: TwxWindowBase(parent, id, title, pos, size, style),
m_menu(NULL), _eh(NULL), _app_data(0L), _timer(NULL),
m_pManager(NULL), m_bInDestroy(false)
{
_nice_windows.Put((WINDOW)this, this);
}
TwxWindow::~TwxWindow()
{
if (!m_bInDestroy) // Controllo di non essere RIchiamato dalla gestione di E_DESTROY
{
m_bInDestroy = true;
EVENT e; memset(&e, 0, sizeof(EVENT));
e.type = E_DESTROY;
DoXvtEvent(e);
// Rendo praticamente impossibile risalire a questo oggetto d'ora in poi
_nice_windows.Delete((WINDOW)this);
_eh = NULL;
_app_data = 0L;
if (HasCapture())
{
ReleaseMouse();
xvt_win_release_pointer(); // Paranoid?
}
if (_timer != NULL)
delete _timer;
if (m_pManager != NULL)
{
m_pManager->UnInit(); // Obbligatorio ma, chissa' perche', non gestito dal distruttore!
delete m_pManager;
}
if (m_menu)
{
xvt_res_free_menu_tree(m_menu);
m_menu = NULL;
((TTaskWin*)_task_win)->PopMenuTree();
}
}
}
///////////////////////////////////////////////////////////
// Main application = TASK_WIN functions
///////////////////////////////////////////////////////////
IMPLEMENT_DYNAMIC_CLASS(TTaskWin, wxFrame)
BEGIN_EVENT_TABLE(TTaskWin, wxFrame)
EVT_CLOSE(TTaskWin::OnClose)
EVT_MENU_RANGE(1000, 32766, TTaskWin::OnMenu)
EVT_PAINT(TTaskWin::OnPaint)
EVT_SIZE(TTaskWin::OnSize)
END_EVENT_TABLE()
void TTaskWin::OnClose(wxCloseEvent& evt)
{
if (evt.CanVeto())
{
EVENT e; memset(&e, 0, sizeof(EVENT));
e.type = E_CLOSE;
int veto = _task_win_handler((WINDOW)this, &e);
evt.Veto(veto != 0);
}
else
evt.Skip();
}
void TTaskWin::OnMenu(wxCommandEvent& evt)
{
EVENT e; memset(&e, 0, sizeof(EVENT));
e.type = E_COMMAND;
e.v.cmd.control = 0; e.v.cmd.shift = 0;
e.v.cmd.tag = evt.GetId();
if (m_MenuOwner == NULL || m_MenuOwner == this)
_task_win_handler((WINDOW)this, &e);
else
{
TwxWindow* w = wxDynamicCast(m_MenuOwner, TwxWindow);
if (w != NULL)
w->_eh((WINDOW)m_MenuOwner, &e);
}
}
void TTaskWin::OnPaint(wxPaintEvent& WXUNUSED(evt))
{
const wxRect rctDamaged = GetUpdateRegion().GetBox();
EVENT e; memset(&e, 0, sizeof(EVENT));
e.type = E_UPDATE;
RCT& rct = e.v.update.rct;
rct.left = rctDamaged.x;
rct.top = rctDamaged.y;
rct.right = rctDamaged.GetRight()+1;
rct.bottom = rctDamaged.GetBottom()+1;
TDC& dc = GetTDCMapper().GetTDC((WINDOW)this);
dc.GetDC(true); // Forza la creazione di un wxPaintDC
_task_win_handler((WINDOW)this, &e);
dc.KillDC();
}
void TTaskWin::OnSize(wxSizeEvent& evt)
{
EVENT e; memset(&e, 0, sizeof(EVENT));
e.type = E_SIZE;
e.v.size.width = evt.GetSize().x;
e.v.size.height = evt.GetSize().y;
_task_win_handler((WINDOW)this, &e);
}
void TTaskWin::SetMenuTree(const MENU_ITEM* tree)
{
wxMenuBar* bar = GetMenuBar();
if (bar != NULL && tree != NULL)
{
if (m_menu)
xvt_res_free_menu_tree(m_menu);
m_menu = xvt_menu_duplicate_tree(tree);
for ( ; tree != NULL && tree->tag != 0; tree++)
{
wxMenu* pMenu = new wxMenu;
for (MENU_ITEM* mi = tree->child; mi != NULL && mi->tag != 0; mi++)
{
wxMenuItem* item = NULL;
if (mi->separator)
item = new wxMenuItem(pMenu, wxID_SEPARATOR);
else
item = new wxMenuItem(pMenu, mi->tag, mi->text, wxEmptyString, mi->checkable);
pMenu->Append(item);
}
const int nLast = bar->GetMenuCount()-1;
int m;
for (m = 2; m < nLast; m++)
{
wxMenu* pMenu = bar->GetMenu(m);
if (pMenu->FindItem(tree->child->tag))
{
bar->Remove(m);
// delete pMenu;
break;
}
}
bar->Insert(m, pMenu, tree->text);
}
}
}
void TTaskWin::PushMenuTree(const MENU_ITEM* tree, wxWindow* owner)
{
if(m_pOldBar != NULL)
PopMenuTree();
m_pOldBar = GetMenuBar();
wxMenuBar* pBar = new wxMenuBar;
for (; tree && tree->tag != 0; tree++)
{
wxMenu* pMenu = new wxMenu;
for (MENU_ITEM* mi = tree->child; mi != NULL && mi->tag != 0; mi++)
{
wxMenuItem* item = NULL;
if (mi->separator)
item = new wxMenuItem(pMenu, wxID_SEPARATOR);
else
item = new wxMenuItem(pMenu, mi->tag, mi->text, wxEmptyString, mi->checkable);
pMenu->Append(item);
}
pBar->Append(pMenu, tree->text);
}
SetMenuBar(pBar);
m_MenuOwner = owner;
}
void TTaskWin::PopMenuTree()
{
wxASSERT(m_pOldBar != NULL);
wxMenuBar* pBar = GetMenuBar();
SetMenuBar(m_pOldBar);
delete pBar;
m_pOldBar = NULL;
m_MenuOwner = NULL; // = this;
}
TTaskWin::TTaskWin(wxWindowID id, const wxString& title,
const wxPoint& pos, const wxSize& size, long style)
: wxFrame(NULL, id, title, pos, size, style), m_menu(NULL), m_pOldBar(NULL), m_MenuOwner(NULL)
{
const wxIcon& ico = _GetIconResource(ICON_RSRC);
SetIcon(ico);
_nice_windows.Put((WINDOW)this, this);
}
TTaskWin::~TTaskWin()
{
_task_win = NULL;
_nice_windows.Delete((WINDOW)this);
if (m_menu)
{
xvt_res_free_menu_tree(m_menu);
m_menu = NULL;
}
}
///////////////////////////////////////////////////////////
// TwxTaskBarIcon
///////////////////////////////////////////////////////////
class TwxTaskBarIcon : public wxTaskBarIcon
{
wxWindow* _owned;
DECLARE_EVENT_TABLE();
protected:
void OnClick(wxTaskBarIconEvent& e);
public:
TwxTaskBarIcon(wxWindow* owned, short icon, wxString strTip);
};
BEGIN_EVENT_TABLE(TwxTaskBarIcon, wxTaskBarIcon)
EVT_TASKBAR_LEFT_DOWN(OnClick)
EVT_TASKBAR_RIGHT_DOWN(OnClick)
END_EVENT_TABLE()
void TwxTaskBarIcon::OnClick(wxTaskBarIconEvent& WXUNUSED(e))
{
if (_owned != NULL)
{
if (_owned->IsShown())
_owned->Show(false);
else
{
_owned->Show();
_owned->Raise();
}
}
}
TwxTaskBarIcon::TwxTaskBarIcon(wxWindow* owned, short icon, wxString strTip)
: _owned(owned)
{
const wxIcon* pIcon = NULL;
if (icon <= 0)
{
const wxFrame* pFrame = wxDynamicCast(_owned, wxFrame);
if (pFrame != NULL)
pIcon = &pFrame->GetIcon();
}
if (pIcon == NULL)
{
if (icon <= 0)
icon = ICON_RSRC;
pIcon = &_GetIconResource(icon);
}
if (strTip.IsEmpty())
strTip = _owned->GetLabel();
SetIcon(*pIcon, strTip);
}
WINDOW xvt_trayicon_create(WINDOW owned, short icon, const char* tooltip)
{
WINDOW ti = NULL_WIN;
if (owned != NULL_WIN)
ti = (WINDOW)new TwxTaskBarIcon((wxWindow*)owned, icon, tooltip);
return ti;
}
void xvt_trayicon_destroy(WINDOW tray)
{
wxTaskBarIcon* pTray = wxDynamicCast((wxObject*)tray, wxTaskBarIcon);
if (pTray != NULL)
delete pTray;
}