diff --git a/xvaga/xvtwin.cpp b/xvaga/xvtwin.cpp new file mode 100755 index 000000000..8385f6434 --- /dev/null +++ b/xvaga/xvtwin.cpp @@ -0,0 +1,1672 @@ +#include "wxinc.h" + +#define XTWIN_CPP 1 +#include "xvt.h" +#include "xvtwin.h" + +#include "wx/notebook.h" +#include "wx/treectrl.h" + +/////////////////////////////////////////////////////////// +// Utilities +/////////////////////////////////////////////////////////// + +wxHashTable _nice_windows; +wxWindow* _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 dc->IsKindOf(CLASSINFO(wxPostScriptDC)); +} +#endif + +wxDC& TDC::GetDC(bool bPaint) +{ + if (bPaint) + { + KillDC(); + _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 = 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) + { + 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) + +bool TwxWindowBase::CreateBase(wxWindow *parent, wxWindowID id, const wxString &title, + const wxPoint &pos, const wxSize &size, long style) +{ + // Evita inutili sfarfallamenti in quanto wxWidgets crea le finestre visibili per default + wxWindowBase::Show(false); + bool ok = Create(parent, id, pos, size, style, title); + if (ok) + { +#if wxCHECK_VERSION(2,8,0) +#else + SetTitle(title); // Triste necessita', la Create sembra ignorare il titolo +#endif + } + return ok; +} + +TwxWindowBase::TwxWindowBase(wxWindow *parent, wxWindowID id, const wxString &title, + const wxPoint &pos, const wxSize &size, long style) +{ + wxASSERT(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) +#if wxCHECK_VERSION(2,8,0) + EVT_MOUSE_CAPTURE_LOST(TwxWindow::OnMouseCaptureLost) +#endif + 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_RANGE(1, 9999, wxEVT_COMMAND_BUTTON_CLICKED, TwxWindow::OnButton) + EVT_COMMAND_RANGE(1, 9999, wxEVT_COMMAND_CHECKBOX_CLICKED, TwxWindow::OnCheckBox) + EVT_COMMAND_RANGE(1, 9999, 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_DESTROY; + DoXvtEvent(e); + Destroy(); +} + +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); +} + +#if wxCHECK_VERSION(2,8,0) +void TwxWindow::OnMouseCaptureLost(wxMouseCaptureLostEvent& WXUNUSED(e)) +{ + xvt_win_release_pointer(); +} +#endif + +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)) +{ + 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) + { + const wxScrollBar* sb = (wxScrollBar*)evt.GetEventObject(); + const wxSize sz = sb->GetSize(); + + EVENT e; memset(&e, 0, sizeof(EVENT)); + e.type = E_CONTROL; + e.v.ctl.id = evt.GetId(); + e.v.ctl.ci.type = sz.x > sz.y ? WC_HSCROLL : WC_VSCROLL; + e.v.ctl.ci.win = (WINDOW)sb; + 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.height = evt.GetSize().x; + e.v.size.width = 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*)_task_win)->PushMenuTree(tree, this); + } +} + +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), _timer(NULL) +{ + _nice_windows.Put((WINDOW)this, this); +} + +TwxWindow::~TwxWindow() +{ + if (_timer) + delete _timer; + if (m_menu) + { + xvt_res_free_menu_tree(m_menu); + ((TTaskWin*)_task_win)->PopMenuTree(); + } + + _nice_windows.Delete((WINDOW)this); +} + + +/////////////////////////////////////////////////////////// +// 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*)m_MenuOwner)->_eh((WINDOW)m_MenuOwner, &e); +} + +void TTaskWin::OnPaint(wxPaintEvent& WXUNUSED(evt)) +{ + 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& 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.height = evt.GetSize().x; + e.v.size.width = evt.GetSize().y; + _task_win_handler((WINDOW)this, &e); +} + +void TTaskWin::SetMenuTree(const MENU_ITEM* tree) +{ + if (m_menu) + xvt_res_free_menu_tree(m_menu); + m_menu = xvt_menu_duplicate_tree(tree); + + wxMenuBar* bar = GetMenuBar(); + 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(wxWindow *parent, wxWindowID id, + const wxString& title, const wxPoint& pos, + const wxSize& size, long style) + : wxFrame(parent, id, title, pos, size, style), m_menu(NULL), m_pOldBar(NULL), m_MenuOwner(NULL) +{ + wxIcon* ico = _GetIconResource(ICON_RSRC); + if (ico) + SetIcon(*ico); + _nice_windows.Put((WINDOW)this, this); +} + +TTaskWin::~TTaskWin() +{ + if (m_menu) + { + xvt_res_free_menu_tree(m_menu); + m_menu = NULL; + } + _nice_windows.Delete((WINDOW)this); +} + +/////////////////////////////////////////////////////////// +// Controls functions +/////////////////////////////////////////////////////////// + +class TwxScrollBar : public wxScrollBar +{ +protected: + virtual bool AcceptsFocus() const { return false; } // Altrimenti mette il flag wxTAB_TRAVERSAL + +public: + TwxScrollBar(wxWindow *parent, wxWindowID id, + const wxPoint& pos, const wxSize& size, long style) + { Create(parent, id, pos, size, style); } +}; + +class TwxNoteBook : public wxNotebook +{ +public: + wxNotebookPage* AddTab(int idx, const wxString text, wxBitmap* bmp); + TwxNoteBook(wxWindow *parent, wxWindowID id, const wxPoint& pos, const wxSize& size); +}; + +class TwxTreeCtrl : public wxTreeCtrl +{ + WX_DECLARE_VOIDPTR_HASH_MAP(int, XVT_IMAGE_Map); + XVT_IMAGE_Map m_img; + wxFont m_font; + int m_nFrozen; + +private: + int img2int(XVT_IMAGE img); // Store img into internal image list + void OnClick(wxTreeEvent& evt, bool bDouble); + +protected: + DECLARE_EVENT_TABLE(); + void OnExpanding(wxTreeEvent& e); // Called when node in about to be expanded + void OnCollapsed(wxTreeEvent& e); // Called when node is collapsed + void OnSelected(wxTreeEvent& e); // Calls OnClick(e, false) + void OnActivated(wxTreeEvent& e); // Calls OnClick(e, true) + +public: + void SetNodeImages(const wxTreeItemId& id, XVT_IMAGE item_image, + XVT_IMAGE collapsed_image, XVT_IMAGE expanded_image); + virtual bool SetFont(const wxFont& font) { m_font = font; return font.IsOk(); } + virtual wxFont GetFont() const; + + void Suspend(); + void Resume(); + TwxTreeCtrl(wxWindow *parent, wxWindowID id, const wxPoint& pos, const wxSize& size); +}; + +WINDOW xvt_ctl_create_def(WIN_DEF *win_def_p, WINDOW parent_win, long app_data) +{ + wxASSERT(win_def_p != NULL); + const wxRect rct = NormalizeRCT(&win_def_p->rct); + wxWindow* pParent = (wxWindow*)parent_win; + const wxWindowID id = win_def_p->v.ctl.ctrl_id; + + WINDOW win = NULL_WIN; + switch (win_def_p->wtype) + { + case WC_HSCROLL: /* horizontal scrollbar control */ + case WC_VSCROLL: /* vertical scrollbar control */ + { + const long style = win_def_p->wtype == WC_HSCROLL ? wxSB_HORIZONTAL : wxSB_VERTICAL; + TwxScrollBar* sb = new TwxScrollBar(pParent, id, rct.GetPosition(), rct.GetSize(), style); + win = (WINDOW)sb; + } + break; + case WC_HGAUGE: /* horizontal progress bar control */ + case WC_VGAUGE: /* vertical progress bar control */ + { + const long style = (win_def_p->wtype == WC_HGAUGE) ? wxGA_HORIZONTAL : wxGA_VERTICAL; + wxGauge* pg = new wxGauge(pParent, id, app_data, + rct.GetPosition(), rct.GetSize(), style); + win = (WINDOW)pg; + } + break; + case WC_PUSHBUTTON: /* bottone normale */ + { + wxButton* pb = NULL; + if (win_def_p->text && *win_def_p->text) // Bottone normale con label + { + pb = new wxButton(pParent, id, win_def_p->text, rct.GetPosition(), rct.GetSize()); + } + else + { // Bottone figo con immagini + wxBitmap bmp; + pb = new wxBitmapButton(pParent, id, bmp, rct.GetPosition(), rct.GetSize()); + } + win = (WINDOW)pb; + } + break; + case WC_CHECKBOX: /* check box */ + { + long style = wxCHK_2STATE | wxTRANSPARENT_WINDOW; + if (win_def_p->wtype == CTL_FLAG_RIGHT_JUST) + style |= wxALIGN_RIGHT; + wxCheckBox* cb = new wxCheckBox(pParent, id, win_def_p->text, + rct.GetPosition(), rct.GetSize(), style); + win = (WINDOW)cb; + } + break; + case WC_RADIOBUTTON: /* radio button */ + { + wxRadioButton* rb = new wxRadioButton(pParent, id, win_def_p->text, + rct.GetPosition(), rct.GetSize()); + win = (WINDOW)rb; + } + break; + case WC_NOTEBK: + { + TwxNoteBook* nb = new TwxNoteBook(pParent, id, rct.GetPosition(), rct.GetSize()); + win = (WINDOW)nb; + } + break; + case WC_TREE: + { + TwxTreeCtrl* tv = new TwxTreeCtrl(pParent, id, rct.GetPosition(), rct.GetSize()); + win = (WINDOW)tv; + XVT_FNTID font_id = win_def_p->v.ctl.font_id; + if (font_id == NULL) + font_id = xvt_dwin_get_font(parent_win); + if (font_id != NULL) + { + const wxFont& font = ((TFontId*)font_id)->Font(NULL, win); + tv->SetFont(font); + } + } + break; + default: + SORRY_BOX(); break; + } + + if (win != NULL) + { + wxWindow& w = *(wxWindow*)win; + const long flags = win_def_p->v.ctl.flags; + if (flags & CTL_FLAG_INVISIBLE) w.Hide(); + if (flags & CTL_FLAG_DISABLED) w.Disable(); + } + + return win; +} + +void xvt_ctl_check_radio_button(WINDOW win, WINDOW* wins, int NbrWindows) +{ + wxASSERT(NbrWindows >= 2); + for (int i = 0; i < NbrWindows; i++) + { + wxRadioButton* rb = (wxRadioButton*)wins[i]; + wxASSERT(rb != NULL && rb->IsKindOf(CLASSINFO(wxRadioButton))); + rb->SetValue(win == wins[i]); + } +} + +void xvt_ctl_set_checked(WINDOW win, BOOLEAN bCheck) +{ + wxCheckBox* cb = (wxCheckBox*)win; + wxASSERT(cb != NULL); + cb->SetValue(bCheck != 0); +} + +/////////////////////////////////////////////////////////// +// Notebook interface +/////////////////////////////////////////////////////////// + +#define CAST_NOTEBOOK(win, nb) wxASSERT(win); TwxNoteBook& nb = *(TwxNoteBook*)win; + +wxNotebookPage* TwxNoteBook::AddTab(int idx, const wxString text, wxBitmap* bmp) +{ + int imageId = -1; + if (bmp != NULL) + { + wxImageList* il = GetImageList(); + if (il == NULL) + AssignImageList(il = new wxImageList(16,16)); + imageId = il->Add(*bmp); + } + + wxNotebookPage* nbp = new TwxWindow(this, wxID_ANY, text, + wxDefaultPosition, wxDefaultSize, 0); + if (idx < 0 || idx >= (int)GetPageCount()) + AddPage(nbp, text, false, imageId); + else + InsertPage(idx, nbp, text, false, imageId); + + return nbp; +} + +TwxNoteBook::TwxNoteBook(wxWindow *parent, wxWindowID id, + const wxPoint& pos, const wxSize& size) + : wxNotebook(parent, id, pos, size) +{} + +void xvt_notebk_add_page(WINDOW notebk, short tab_no, short page_no, + const char* title, long page_data) +{ + wxASSERT(page_no == 0); + CAST_NOTEBOOK(notebk, nb); + if (tab_no < 0 || tab_no >= (int)nb.GetPageCount()) + { + tab_no = nb.GetPageCount(); + xvt_notebk_add_tab(notebk, tab_no, title, NULL); + } + + TwxWindow* nbp = (TwxWindow*)nb.GetPage(tab_no); + nbp->SetLabel(title); + nbp->_app_data = page_data; + nbp->SetBackgroundStyle(wxBG_STYLE_CUSTOM); // Lo sfondo viene disegnato nella OnPaint +} + +void xvt_notebk_add_tab(WINDOW notebk, short tab_no, const char* title, XVT_IMAGE image) +{ + CAST_NOTEBOOK(notebk, nb); + nb.AddTab(tab_no, title, NULL); +} + +WINDOW xvt_notebk_create_face(WINDOW notebk, short tab_no, short page_no, + EVENT_MASK mask, EVENT_HANDLER face_eh, long app_data) +{ + return xvt_notebk_create_face_def(notebk, tab_no, page_no, NULL, mask, face_eh, app_data); +} + +WINDOW xvt_notebk_create_face_def(WINDOW notebk, short tab_no, short WXUNUSED(page_no), + WIN_DEF* win_def_p, EVENT_MASK WXUNUSED(mask), + EVENT_HANDLER face_eh, long app_data) +{ + wxASSERT(tab_no >= 0 && tab_no < xvt_notebk_get_num_tabs(notebk)); + CAST_NOTEBOOK(notebk, nb); + TwxWindow* nbp = (TwxWindow*)nb.GetPage(tab_no); + + wxWindowID id = 10001+tab_no; + wxString text; + long style = 0; + if (win_def_p != NULL) + { + id = win_def_p->v.ctl.ctrl_id; + text = win_def_p->text; + style = win_def_p->v.ctl.flags; + } + if (!text.IsEmpty()) + nbp->SetLabel(text); + if (id > 0) + nbp->SetId(id); + nbp->_eh = face_eh; + nbp->_app_data = app_data; + + return (WINDOW)nbp; +} + +WINDOW xvt_notebk_get_face(WINDOW notebk, short tab_no, short page_no) +{ + wxASSERT(tab_no >= 0 && tab_no < xvt_notebk_get_num_tabs(notebk)); + wxASSERT(page_no == 0); + CAST_NOTEBOOK(notebk, nb); + return (WINDOW)nb.GetPage(tab_no); +} + +short xvt_notebk_get_num_tabs(WINDOW notebk) +{ + CAST_NOTEBOOK(notebk, nb); + return nb.GetPageCount(); +} + +void xvt_notebk_set_front_page(WINDOW notebk, short tab_no, short page_no) +{ + CAST_NOTEBOOK(notebk, nb); + nb.ChangeSelection(tab_no); // Non generare eventi di cambio pagina! +} + +void xvt_notebk_set_tab_title(WINDOW notebk, short tab_no, const char* title) +{ + CAST_NOTEBOOK(notebk, nb); + nb.SetPageText(tab_no, title); +} + +/////////////////////////////////////////////////////////// +// TreeCtrl interface +/////////////////////////////////////////////////////////// + +BEGIN_EVENT_TABLE(TwxTreeCtrl, wxTreeCtrl) + EVT_TREE_ITEM_EXPANDING(wxID_ANY, TwxTreeCtrl::OnExpanding) + EVT_TREE_ITEM_COLLAPSED(wxID_ANY, TwxTreeCtrl::OnCollapsed) + EVT_TREE_SEL_CHANGED(wxID_ANY, TwxTreeCtrl::OnSelected) + EVT_TREE_ITEM_ACTIVATED(wxID_ANY, TwxTreeCtrl::OnActivated) +END_EVENT_TABLE(); + +#define CAST_TREEVIEW(win, tv) wxASSERT(win); TwxTreeCtrl& tv = *(TwxTreeCtrl*)win; + +struct TwxTreeItemData : public wxTreeItemData +{ + wxString m_strData; // Assumo sempre una stringa come dati +}; + +void TwxTreeCtrl::OnExpanding(wxTreeEvent& evt) +{ + if (!m_nFrozen) + { + const wxTreeItemId id = evt.GetItem(); + EVENT e; memset(&e, 0, sizeof(EVENT)); + e.type = E_CONTROL; + e.v.ctl.id = evt.GetId(); + e.v.ctl.ci.type = WC_TREE; + e.v.ctl.ci.win = WINDOW(this); + e.v.ctl.ci.v.treeview.node = id.m_pItem; + e.v.ctl.ci.v.treeview.expanded = TRUE; + if (GetChildrenCount(id) == 0) // Trucco perfido ... + e.v.ctl.ci.v.treeview.collapsed = TRUE; // ... stato indeterminato = EXPANDING + TwxWindow* win = (TwxWindow*)GetParent(); + win->DoXvtEvent(e); + if (GetChildrenCount(id) == 0) // Allora e' proprio vero ... + SetItemHasChildren(id, false); + } +} + +void TwxTreeCtrl::OnCollapsed(wxTreeEvent& evt) +{ + if (!m_nFrozen) + { + Suspend(); + EVENT e; memset(&e, 0, sizeof(EVENT)); + e.type = E_CONTROL; + e.v.ctl.id = evt.GetId(); + e.v.ctl.ci.type = WC_TREE; + e.v.ctl.ci.win = WINDOW(this); + e.v.ctl.ci.v.treeview.node = evt.GetItem().m_pItem; + e.v.ctl.ci.v.treeview.collapsed = TRUE; + TwxWindow* win = (TwxWindow*)GetParent(); + win->DoXvtEvent(e); + Resume(); + } +} + +void TwxTreeCtrl::OnClick(wxTreeEvent& evt, bool bDouble) +{ + if (!m_nFrozen) + { + Suspend(); + EVENT e; memset(&e, 0, sizeof(EVENT)); + e.type = E_CONTROL; + e.v.ctl.id = evt.GetId(); + e.v.ctl.ci.type = WC_TREE; + e.v.ctl.ci.win = WINDOW(this); + e.v.ctl.ci.v.treeview.node = evt.GetItem().m_pItem; + if (bDouble) + e.v.ctl.ci.v.treeview.dbl_click = TRUE; + else + e.v.ctl.ci.v.treeview.sgl_click = TRUE; + TwxWindow* win = (TwxWindow*)GetParent(); + win->DoXvtEvent(e); + Resume(); + } +} + +void TwxTreeCtrl::OnSelected(wxTreeEvent& evt) +{ OnClick(evt, false); } + +void TwxTreeCtrl::OnActivated(wxTreeEvent& evt) +{ OnClick(evt, true); } + +int TwxTreeCtrl::img2int(XVT_IMAGE xvt_img) +{ + int i = -1; + if (xvt_img != NULL) + { + i = m_img[xvt_img] - 1; // Ho memorizzato indice+1 + if (i < 0) // Immagine sconosciuta + { + const wxImage& img = *(wxImage*)xvt_img; + wxImageList* il = GetImageList(); + if (il == NULL) // Lista non ancora creata + { + il = new wxImageList; + il->Create(img.GetWidth(), img.GetHeight(), true, 3); + AssignImageList(il); // DON'T CALL SetImageList! + } + i = il->Add(wxBitmap(img)); + m_img[xvt_img] = i+1; // Memorizzo indice+1 + } + if (i < 0) + SORRY_BOX(); + } + return i; +} + +void TwxTreeCtrl::SetNodeImages(const wxTreeItemId& id, XVT_IMAGE item_image, + XVT_IMAGE collapsed_image, XVT_IMAGE expanded_image) +{ + const int ii = img2int(item_image); + if (ii >= 0) + SetItemImage(id, ii); + else + { + const int ic = img2int(collapsed_image); + if (ic >= 0) + { + SetItemImage(id, ic); + const int ie = img2int(expanded_image); + if (ie >= 0) + SetItemImage(id, ie, wxTreeItemIcon_Selected); + } + } +} + +wxFont TwxTreeCtrl::GetFont() const +{ return m_font.IsOk() ? m_font : wxTreeCtrl::GetFont(); } + +void TwxTreeCtrl::Suspend() +{ m_nFrozen++; } + +void TwxTreeCtrl::Resume() +{ + wxASSERT(m_nFrozen > 0); + if (m_nFrozen > 0) + m_nFrozen--; +} + +TwxTreeCtrl::TwxTreeCtrl(wxWindow *parent, wxWindowID id, + const wxPoint& pos, const wxSize& size) + : wxTreeCtrl(parent, id, pos, size, wxTR_HAS_BUTTONS | wxTR_HIDE_ROOT), + m_nFrozen(0) +{ + AddRoot("Root"); +} + +WINDOW xvt_treeview_create(WINDOW parent_win, + RCT * rct_p, char * title, long ctl_flags, + long app_data, int ctl_id, XVT_IMAGE item_image, + XVT_IMAGE collapsed_image, XVT_IMAGE expanded_image, + long attrs, int line_height) +{ + WIN_DEF win_def; memset(&win_def, 0, sizeof(WIN_DEF)); + win_def.wtype = WC_TREE; + win_def.rct = *rct_p; + win_def.text = title; + win_def.v.ctl.ctrl_id = ctl_id; + win_def.v.ctl.flags = ctl_flags; + WINDOW win = xvt_ctl_create_def(&win_def, parent_win, app_data); + return win; +} + +XVT_TREEVIEW_NODE xvt_treeview_add_child_node(WINDOW win, + XVT_TREEVIEW_NODE parent, XVT_TREEVIEW_NODE_TYPE type, + XVT_IMAGE item_image, XVT_IMAGE collapsed_image, XVT_IMAGE expanded_image, + const char* string, XVT_TREEVIEW_CALLBACK callback, const char* data) +{ + XVT_TREEVIEW_NODE node = NULL; + if (win != NULL_WIN) + { + CAST_TREEVIEW(win, tv); + TwxTreeItemData* pData = new TwxTreeItemData; + pData->m_strData = data; + wxTreeItemId pa(parent); + if (!pa.IsOk()) + pa = tv.GetRootItem(); + wxTreeItemId id = tv.AppendItem(pa, string, -1, -1, pData); + if (id.IsOk()) + { + tv.SetItemHasChildren(pa, true); + tv.SetItemHasChildren(id, type == XVT_TREEVIEW_NODE_NONTERMINAL); + tv.SetNodeImages(id, item_image, collapsed_image, expanded_image); + tv.SetItemFont(id, tv.GetFont()); + node = id.m_pItem; + } + } + return node; +} + +XVT_TREEVIEW_NODE xvt_treeview_get_child_node(WINDOW win, XVT_TREEVIEW_NODE parent_node, + int position) +{ + XVT_TREEVIEW_NODE child_node = NULL; + if (win != NULL_WIN && position >= 0) + { + CAST_TREEVIEW(win, tv); + wxTreeItemId parent(parent_node); + if (!parent.IsOk()) + parent = tv.GetRootItem(); + + if (position < (int)tv.GetChildrenCount(parent)) + { + wxTreeItemIdValue cookie; + wxTreeItemId id; + int i = -1; + for (id = tv.GetFirstChild(parent, cookie), i = -1; + i < position && id.IsOk(); id = tv.GetNextChild(parent, cookie), i++); + child_node = id.m_pItem; + } + } + return child_node; +} + +const char* xvt_treeview_get_node_data(WINDOW win, XVT_TREEVIEW_NODE node) +{ + const char* data = NULL; + if (win != NULL_WIN && node != NULL) + { + CAST_TREEVIEW(win, tv); + const wxTreeItemId id(node); + TwxTreeItemData* pData = (TwxTreeItemData*)tv.GetItemData(id); + if (pData != NULL) + data = (const char*)pData->m_strData; + } + return data; +} + +void xvt_treeview_destroy_node(WINDOW win, XVT_TREEVIEW_NODE node) +{ + if (win != NULL_WIN && node != NULL) + { + CAST_TREEVIEW(win, tv); + wxTreeItemId id(node); + tv.Delete(id); + } +} + +BOOLEAN xvt_treeview_expand_node(WINDOW win, XVT_TREEVIEW_NODE node, BOOLEAN recurse) +{ + BOOLEAN ok = (win != NULL_WIN) && (node != NULL); + if (ok) + { + CAST_TREEVIEW(win, tv); + const wxTreeItemId id(node); + if (recurse) + tv.ExpandAllChildren(id); + else + tv.Expand(id); + } + return ok; +} + +XVT_TREEVIEW_NODE xvt_treeview_get_root_node(WINDOW win) +{ + XVT_TREEVIEW_NODE pRoot = NULL; + if (win != NULL_WIN) + { + CAST_TREEVIEW(win, tv); + const wxTreeItemId id = tv.GetRootItem(); + pRoot = id.m_pItem; + } + return pRoot; +} + +XVT_TREEVIEW_NODE xvt_treeview_get_selected_node(WINDOW win) +{ + CAST_TREEVIEW(win, tv); + const wxTreeItemId id = tv.GetSelection(); + return id.m_pItem; +} + +BOOLEAN xvt_treeview_remove_child_node(WINDOW win, XVT_TREEVIEW_NODE node) +{ + BOOLEAN ok = (win != NULL_WIN) && (node != NULL); + if (ok) + { + CAST_TREEVIEW(win, tv); + const wxTreeItemId id(node); + tv.Delete(id); + } + return ok; +} + +BOOLEAN xvt_treeview_remove_node_children(WINDOW win, XVT_TREEVIEW_NODE node) +{ + BOOLEAN ok = FALSE; + if (win != NULL_WIN) + { + CAST_TREEVIEW(win, tv); + wxTreeItemId id(node); + if (!id.IsOk()) + id = tv.GetRootItem(); + tv.DeleteChildren(id); + ok = TRUE; + } + return ok; +} + +void xvt_treeview_resume(WINDOW win) +{ + CAST_TREEVIEW(win, tv); + tv.Resume(); +} + +void xvt_treeview_select_node(WINDOW win, XVT_TREEVIEW_NODE node, BOOLEAN sel) +{ + if (win != NULL_WIN && node != NULL) + { + CAST_TREEVIEW(win, tv); + const wxTreeItemId id(node); + tv.SelectItem(id, sel != 0); + if (sel) + tv.EnsureVisible(id); + } +} + +void xvt_treeview_set_node_images(WINDOW win, XVT_TREEVIEW_NODE node, XVT_IMAGE item_image, + XVT_IMAGE collapsed_image, XVT_IMAGE expanded_image) +{ + if (win != NULL_WIN && node != NULL) + { + CAST_TREEVIEW(win, tv); + const wxTreeItemId id(node); + tv.SetNodeImages(id, item_image, collapsed_image, expanded_image); + } +} + +void xvt_treeview_set_node_string(WINDOW win, XVT_TREEVIEW_NODE node, const char* text) +{ + if (win != NULL_WIN && node != NULL) + { + CAST_TREEVIEW(win, tv); + const wxTreeItemId id(node); + tv.SetItemText(id, text); + } +} + +void xvt_treeview_suspend(WINDOW win) +{ + CAST_TREEVIEW(win, tv); + tv.Suspend(); +} diff --git a/xvaga/xvtwin.h b/xvaga/xvtwin.h new file mode 100755 index 000000000..805b6127e --- /dev/null +++ b/xvaga/xvtwin.h @@ -0,0 +1,229 @@ +#ifndef __XVTWIN_H +#define __XVTWIN_H + +class TFontId +{ + wxString m_strFace; + int m_nSize; + XVT_FONT_STYLE_MASK m_wMask; + WINDOW m_win; + +protected: + void Copy(const TFontId& pFont); + bool IsEqual(const TFontId& pFont) const; + +public: + void SetWin(WINDOW w) { m_win = w; } + WINDOW Win() const { return m_win; } + + void SetPointSize(int s) { m_nSize = s; } + int PointSize() const { return m_nSize; } + + void SetMask(XVT_FONT_STYLE_MASK mask) { m_wMask = mask; } + XVT_FONT_STYLE_MASK Mask() const { return m_wMask; } + int Style() const; + bool Underline() const; + int Weight() const; + + void SetFaceName(const char* f) { m_strFace = f; } + const char* FaceName() const; + int Family() const; + + void Copy(const wxFont& rFont); + wxFont& Font(wxDC* dc, WINDOW w) const; + + TFontId& operator=(const TFontId& f) { Copy(f); return *this; } + bool operator==(const TFontId& f) const { return IsEqual(f); } + bool operator!=(const TFontId& f) const { return !IsEqual(f); } + + TFontId() : m_nSize(0), m_wMask(0), m_win(NULL_WIN) { } + TFontId(const TFontId& f) : m_win(NULL_WIN) { Copy(f); } +}; + +class TDC : public wxObject +{ + wxWindow* _owner; + +protected: + wxDC* _dc; + RCT _clip; + int _dirty; // false = 0, true = 1, very_dirty = -1; + int _deltaf; + + DRAW_CTOOLS _real_dct; + TFontId _real_font; + RCT _real_clip; + + bool PenChanged() const; + bool BrushChanged() const; + bool FontChanged() const; + bool ClipChanged() const; + +public: + DRAW_CTOOLS _dct; + TFontId _font; + wxPoint _pnt; + + void SetClippingBox(const RCT* pRct); + bool GetClippingBox(RCT* pRct) const; + void SetDirty(int d = 1); + int GetFontDelta() const { return _deltaf; } + + virtual wxDC& GetDC(bool bPaint = false); + virtual void KillDC(); + TDC(wxWindow* owner); + virtual ~TDC(); +}; + +class TPrintDC : public TDC +{ + static bool _page_start; + +public: + static void SetPageStart(); + + virtual wxDC& GetDC(bool); + virtual void KillDC(); + TPrintDC(wxWindow* owner); + virtual ~TPrintDC(); +}; + +WX_DECLARE_HASH_MAP(WINDOW, TDC*, wxIntegerHash, wxIntegerEqual, wxTDCHashMap); + +class TDCMapper : public wxTDCHashMap +{ + WINDOW _pLastOwner; + TDC* _pLastTDC; + +public: + TDC& GetTDC(WINDOW owner); + wxDC& GetDC(WINDOW owner, bool bPaint = false) { return GetTDC(owner).GetDC(bPaint); } + void DestroyDC(WINDOW owner); + void DestroyTDC(WINDOW owner); + bool HasValidDC(WINDOW owner) const; + + TDCMapper() : _pLastOwner(NULL_WIN), _pLastTDC(NULL) { } + virtual ~TDCMapper() { DestroyTDC(NULL_WIN); } +}; + +TDCMapper& GetTDCMapper(); + +class TwxWindowBase : public wxWindow +{ +#ifdef LINUX +private: + wxString m_strTitle; + virtual void SetTitle(const wxString& title) { wxWindow::SetTitle(m_strTitle = title); } + virtual wxString GetTitle() const { return m_strTitle; } +#endif + +public: + bool CreateBase(wxWindow *parent, wxWindowID id, const wxString &title, + const wxPoint &pos, const wxSize &size, long style); + + TwxWindowBase() { } + TwxWindowBase(wxWindow *parent, wxWindowID id, const wxString &title, + const wxPoint & pos, const wxSize & size, long style); + + DECLARE_DYNAMIC_CLASS(TwxWindowBase) +}; + +class TwxWindow : public TwxWindowBase +{ +private: + MENU_ITEM* m_menu; + +protected: + virtual void OnChar(wxKeyEvent& e); + virtual void OnClose(wxCloseEvent& e); + virtual void OnKeyDown(wxKeyEvent& e); + virtual void OnKillFocus(wxFocusEvent& e); + virtual void OnMenu(wxCommandEvent& e); +#if wxCHECK_VERSION(2,8,0) + virtual void OnMouseCaptureLost(wxMouseCaptureLostEvent& e); +#endif + virtual void OnMouseDouble(wxMouseEvent& e); + virtual void OnMouseDown(wxMouseEvent& e); + virtual void OnMouseMove(wxMouseEvent& e); + virtual void OnMouseUp(wxMouseEvent& e); + virtual void OnMouseWheel(wxMouseEvent& e); + virtual void OnScroll(wxScrollEvent& e); + virtual void OnScrollWin(wxScrollWinEvent& e); + virtual void OnSetFocus(wxFocusEvent& e); + virtual void OnSize(wxSizeEvent& e); + virtual void OnTimer(wxTimerEvent& e); + virtual void OnButton(wxCommandEvent& e); + virtual void OnCheckBox(wxCommandEvent& e); + virtual void OnRadioButton(wxCommandEvent& e); + +public: + void DoXvtEvent(EVENT& e); + virtual void OnPaint(wxPaintEvent& e); + +public: + WIN_TYPE _type; + EVENT_HANDLER _eh; + long _app_data; + wxTimer* _timer; + + void SetMenuTree(const MENU_ITEM* menu); + MENU_ITEM* GetMenuTree() const { return m_menu; } + + TwxWindow() : m_menu(NULL), _type(W_DOC), _eh(NULL), _app_data(0L), _timer(NULL) { } + TwxWindow(wxWindow *parent, wxWindowID id, const wxString& title, + const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize, long style = 0); + virtual ~TwxWindow(); + + DECLARE_DYNAMIC_CLASS(TwxWindow); + DECLARE_EVENT_TABLE(); +}; + +class TTaskWin : public wxFrame +{ + MENU_ITEM* m_menu; + + wxMenuBar* m_pOldBar; + wxWindow* m_MenuOwner; + +protected: + virtual void OnClose(wxCloseEvent& e); + virtual void OnMenu(wxCommandEvent& e); + virtual void OnSize(wxSizeEvent& e); + +public: + virtual void OnPaint(wxPaintEvent& e); + +public: + void SetMenuTree(const MENU_ITEM* tree); + const MENU_ITEM* GetMenuTree() const { return m_menu; } + void PushMenuTree(const MENU_ITEM* tree, wxWindow* owner); + void PopMenuTree(); + + TTaskWin() : wxFrame(), m_menu(NULL), m_pOldBar(NULL) { } + TTaskWin(wxWindow *parent, wxWindowID id, const wxString& title, + const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, + long style = wxDEFAULT_FRAME_STYLE); + ~TTaskWin(); + + DECLARE_DYNAMIC_CLASS(TTaskWin); + DECLARE_EVENT_TABLE(); +}; + +#define TIMER_ID 1 +const wxString& _GetAppTitle(); +wxIcon* _GetIconResource(int rid); + +#define CAST_COLOR(xc, wc) wxColour wc((xc>>16)&0xFF, (xc>>8)&0xFF, xc&0xFF) +#define MAKE_XVT_COLOR(wc) MAKE_COLOR(wc.Red(), wc.Green(), wc.Blue()) +wxRect NormalizeRCT(const RCT* prct); + +#ifdef XVTWIN_CPP +#define extern +#endif + +extern wxHashTable _nice_windows; +extern wxWindow* _task_win; +extern EVENT_HANDLER _task_win_handler; + +#endif