#include "wxinc.h" #define XTWIN_CPP 1 #include "xvt.h" #include "xvtart.h" #include "xvtwin.h" #include #include //#include #include #include #include #include /////////////////////////////////////////////////////////// // Utilities /////////////////////////////////////////////////////////// wxHashTable _nice_windows; wxFrame* _task_win = NULL; EVENT_HANDLER _task_win_handler = NULL; wxRect RCT2Rect(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; } void Rect2RCT(const wxRect& r, RCT* rct) { xvt_rect_set(rct, r.x, r.y, r.GetRight()+1, r.GetBottom()+1); } /////////////////////////////////////////////////////////// // 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) { if (win != NULL_WIN) _TheCaret.SetSize(width, height); } void xvt_win_set_caret_pos(WINDOW win, PNT p) { if (win != NULL_WIN) _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_SPECIAL: style = wxSOLID; break; // Used for gradient case PAT_RUBBER: default: style = wxSOLID; 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("Mg", NULL, &height, &desc, &lead); _deltaf = height-desc+1; } if (_dirty < 0 || ClipChanged()) { _dc->DestroyClippingRegion(); if (_clip.bottom < 4096) _dc->SetClippingRegion(RCT2Rect(&_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) { // Normalizza posizione e dimensioni invece di limitarsi a fare _clip=*pRct const wxRect rct = RCT2Rect(pRct); Rect2RCT(rct, &_clip); } 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 { if (pRct != NULL) *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() long TwxWindow::DoXvtEvent(EVENT& e) { long ret = 0; if (this != NULL && _eh != NULL) ret = _eh((WINDOW)this, &e); return ret; } 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 } XVT_EVENT e(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 2.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)) { XVT_EVENT e(E_CLOSE); DoXvtEvent(e); } void TwxWindow::OnKillFocus(wxFocusEvent& WXUNUSED(e)) { if (_TheCaret.Owner() == (WINDOW)this) _TheCaret.Hide(); XVT_EVENT e(E_FOCUS); e.v.active = 0; DoXvtEvent(e); } void TwxWindow::OnMenu(wxCommandEvent& evt) { XVT_EVENT e(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) { XVT_EVENT e(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) { XVT_EVENT e(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) { XVT_EVENT e(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) { XVT_EVENT e(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) { XVT_EVENT e(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(); XVT_EVENT e(E_UPDATE); Rect2RCT(rctDamaged, &e.v.update.rct); 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) { XVT_EVENT e(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) { XVT_EVENT e(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)) { XVT_EVENT e(E_FOCUS); e.v.active = TRUE; DoXvtEvent(e); } void TwxWindow::OnSize(wxSizeEvent& evt) { XVT_EVENT e(E_SIZE); e.v.size.width = evt.GetSize().x; e.v.size.height = evt.GetSize().y; DoXvtEvent(e); } void TwxWindow::OnTimer(wxTimerEvent& WXUNUSED(evt)) { XVT_EVENT e(E_TIMER); e.v.timer.id = (WINDOW)this; DoXvtEvent(e); } void TwxWindow::OnButton(wxCommandEvent& evt) { XVT_EVENT e(E_CONTROL); e.v.ctl.id = evt.GetId(); e.v.ctl.ci.type = WC_PUSHBUTTON; DoXvtEvent(e); } void TwxWindow::OnCheckBox(wxCommandEvent& evt) { XVT_EVENT e(E_CONTROL); e.v.ctl.id = evt.GetId(); e.v.ctl.ci.type = WC_CHECKBOX; DoXvtEvent(e); } void TwxWindow::OnRadioButton(wxCommandEvent& evt) { XVT_EVENT e(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; XVT_EVENT e(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; GetTDCMapper().DestroyTDC((WINDOW)this); // Elimina dalla lista dei display context 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) EVT_END_SESSION(TTaskWin::OnClose) EVT_END_PROCESS(wxID_ANY, TTaskWin::OnEndProcess) END_EVENT_TABLE() void TTaskWin::OnClose(wxCloseEvent& evt) { if (evt.CanVeto()) { XVT_EVENT e(E_CLOSE); const int veto = _task_win_handler((WINDOW)this, &e); evt.Veto(veto != 0); } else evt.Skip(); } void TTaskWin::OnMenu(wxCommandEvent& evt) { XVT_EVENT e(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(); XVT_EVENT e(E_UPDATE); Rect2RCT(rctDamaged, &e.v.update.rct); 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) { XVT_EVENT e(E_SIZE); e.v.size.width = evt.GetSize().x; e.v.size.height = evt.GetSize().y; _task_win_handler((WINDOW)this, &e); } void TTaskWin::OnEndProcess(wxProcessEvent& evt) { if (_task_win_handler != NULL) { XVT_EVENT e(E_PROCESS); e.v.process.msg_id = E_DESTROY; e.v.process.pid = evt.GetPid(); e.v.process.exit_code = evt.GetExitCode(); _task_win_handler((WINDOW)this, &e); delete evt.GetEventObject(); // delete wxProcess } } 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; } const XVT_COLOR_COMPONENT* TTaskWin::GetCtlColors() const { if (m_xcc == NULL) ((TTaskWin*)this)->m_xcc = (XVT_COLOR_COMPONENT*)xvt_vobj_get_attr(NULL_WIN, ATTR_APP_CTL_COLORS); return m_xcc; } COLOR TTaskWin::GetCtlColor(XVT_COLOR_TYPE ct) const { COLOR croma = COLOR_INVALID; const XVT_COLOR_COMPONENT* xcc = GetCtlColors(); for (int i = 0; i < 16 && xcc[i].type != XVT_COLOR_NULL; i++) { if (xcc[i].type == ct) { croma = xcc[i].color; break; } } return croma; } void TTaskWin::SetCtlColors(const XVT_COLOR_COMPONENT* colors) { GetCtlColors(); // Ensure m_xcc is not NULL for (int c = 0; colors[c].type != XVT_COLOR_NULL; c++) { int k = -1; for (k = 0; m_xcc[k].type != colors[c].type; k++); if (k < 15) { m_xcc[k].type = colors[c].type; m_xcc[k].color = colors[c].color; } } } 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), m_xcc(NULL) { SetIcon(xvtart_GetIconResource(ICON_RSRC)); _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; } if (m_xcc) { xvt_mem_free((DATA_PTR)m_xcc); m_xcc = NULL; } wxExit(); // Exits main loop in the "rare" case it's still running } /////////////////////////////////////////////////////////// // 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) { wxIcon ico; if (icon <= 0 && _owned != NULL) { const wxFrame* pFrame = wxDynamicCast(_owned, wxFrame); if (pFrame != NULL) ico = pFrame->GetIcon(); } else ico = xvtart_GetIconResource(icon); if (strTip.IsEmpty()) strTip = _owned->GetLabel(); SetIcon(ico, 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; }