///////////////////////////////////////////////////////////////////////////// // Name: clickwindowcontroller.cpp // Purpose: // Author: Cesar Mauri Loba (cesar at crea-si dot com) // Modified by: // Created: // Copyright: (C) 2008-18 Cesar Mauri Loba - CREA Software Systems // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . ///////////////////////////////////////////////////////////////////////////// #include "clickwindowtext.h" #include "clickwindowbitmap.h" #include "wviacam.h" #include "clickwindowcontroller.h" #include "viacamcontroller.h" #include "simplelog.h" #include #include // Class to notify actions executed on a certain point of the screen class ActionDoneEvent; wxDEFINE_EVENT(ACTION_DONE_EVENT, ActionDoneEvent); class ActionDoneEvent: public wxCommandEvent { public: ActionDoneEvent(wxEventType commandType = ACTION_DONE_EVENT, int id = 0) : wxCommandEvent(commandType, id) { } ActionDoneEvent(const ActionDoneEvent& event) : wxCommandEvent(event) { this->SetPoint(event.GetPoint()); } wxEvent* Clone() const { return new ActionDoneEvent(*this); } wxPoint GetPoint() const { return m_Point; } void SetPoint(const wxPoint& rp) { m_Point = rp; } private: wxPoint m_Point; }; // Constructor CClickWindowController::CClickWindowController(CViacamController & pViacamController) { m_pViacamController= &pViacamController; // Create text window m_pWindowText= new CClickWindowText (NULL, CLICK_WINDOW_TEXT); m_pWindowText->SetController (*this); // Create bitmap window m_pWindowBitmap = new CClickWindowBitmap(NULL, CLICK_WINDOW_BITMAP); m_pWindowBitmap->SetController (*this); // Create bitmap vertical window m_pWindowBitmapVertical= new CClickWindowBitmap(NULL, CLICK_WINDOW_BITMAP_VERTICAL); m_pWindowBitmapVertical->SetController (*this); // Create text vertical window m_pWindowTextVertical= new CClickWindowText (NULL, CLICK_WINDOW_TEXT_VERTICAL); m_pWindowTextVertical->SetController (*this); // Set current window m_pWindow= m_pWindowBitmap; Bind(ACTION_DONE_EVENT, &CClickWindowController::OnActionDoneEvent, this); // FIXME: implement this using the observer pattern m_pViacamController->GetMainWindow()->Connect (ID_WVIACAM, wxEVT_SHOW, wxShowEventHandler(CClickWindow::OnMainWindowShow), NULL, m_pWindow); Reset(); InitDefaults(); } CClickWindowController::~CClickWindowController() { Finalize(); } void CClickWindowController::Finalize () { Unbind(ACTION_DONE_EVENT, &CClickWindowController::OnActionDoneEvent, this); DeletePendingEvents(); if (m_pViacamController->GetMainWindow()) { m_pViacamController->GetMainWindow()->Disconnect (ID_WVIACAM, wxEVT_SHOW, wxShowEventHandler(CClickWindow::OnMainWindowShow), NULL, m_pWindowText); m_pViacamController->GetMainWindow()->Disconnect (ID_WVIACAM, wxEVT_SHOW, wxShowEventHandler(CClickWindow::OnMainWindowShow), NULL, m_pWindowBitmap); m_pViacamController->GetMainWindow()->Disconnect (ID_WVIACAM, wxEVT_SHOW, wxShowEventHandler(CClickWindow::OnMainWindowShow), NULL, m_pWindowBitmapVertical); m_pViacamController->GetMainWindow()->Disconnect (ID_WVIACAM, wxEVT_SHOW, wxShowEventHandler(CClickWindow::OnMainWindowShow), NULL, m_pWindowTextVertical); } if (m_pWindow) { m_pWindowText->Show(false); m_pWindowText->Destroy (); m_pWindowText= NULL; m_pWindowBitmap->Show(false); m_pWindowBitmap->Destroy (); m_pWindowBitmap= NULL; m_pWindowBitmapVertical->Show(false); m_pWindowBitmapVertical->Destroy (); m_pWindowBitmapVertical= NULL; m_pWindowTextVertical->Show(false); m_pWindowTextVertical->Destroy (); m_pWindowTextVertical= NULL; m_pWindow= NULL; } } void CClickWindowController::Show(bool show) { if (show!= m_pWindow->IsShown()) { /* if (m_autohide) m_pWindow->SetClickWindowStyle((CClickWindow::EClickWindowStatus)m_status, (CClickWindow::EDocking)m_dockingMode, show); else m_pWindow->SetClickWindowStyle(CClickWindow::DOCKED, (CClickWindow::EDocking)m_dockingMode, show); */ m_pWindow->Show(show); if (show) m_pWindow->UpdateButtons(GetEnabled(),GetCurrentButton(), GetLockedButton()); } } //Return to default state void CClickWindowController::Reset() { m_enabled= true; m_currentButton= LEFT; m_lockedButton= LEFT; m_halfDragClick= false; } inline bool CClickWindowController::IsCursorOverWindow(long x, long y) { wxRect pos= m_pWindow->GetRect(); wxRect parentPos= m_pWindow->GetNoClickButton()->GetScreenRect(); pos.Offset(0, parentPos.GetY() - pos.GetY()); int top= pos.GetTop(); int bottom= pos.GetBottom(); int left= pos.GetLeft(); int right= pos.GetRight(); if (top < 0) top= 0; if (bottom < 0) bottom= 0; if (left < 0) left= 0; if (right < 0) right= 0; if (y<= bottom && y>= top && x>= left && x<= right) return true; else return false; } mousecmd::mousecmd CClickWindowController::GetAction(long x, long y) { mousecmd::mousecmd retval= mousecmd::CMD_NO_CLICK; //wxMutexGuiEnter(); if (m_enabled) { if (IsCursorOverWindow(x,y)) { #if defined(__WXMSW__) retval= mousecmd::CMD_LEFT_UP; #else retval= mousecmd::CMD_LEFT_CLICK; #endif } else { switch (m_currentButton) { case CClickWindowController::LEFT: retval= mousecmd::CMD_LEFT_CLICK; break; case CClickWindowController::MIDDLE: retval= mousecmd::CMD_MIDDLE_CLICK; break; case CClickWindowController::RIGHT: retval= mousecmd::CMD_RIGHT_CLICK; break; case CClickWindowController::DRAG: if (!m_halfDragClick) retval= mousecmd::CMD_LEFT_DOWN; else retval= mousecmd::CMD_LEFT_UP; break; case CClickWindowController::DBLCLICK: retval= mousecmd::CMD_DOUBLE_CLICK; break; default: assert (false); } } } else { if (IsCursorOverNoClickButton(x, y)) #if defined(__WXMSW__) retval= mousecmd::CMD_LEFT_UP; #else retval= mousecmd::CMD_LEFT_CLICK; #endif } //wxMutexGuiLeave(); return retval; } // Select appropriate window taking into account design and location void CClickWindowController::SelectAppropriateWindow (EDesign design, ELocation location) { bool isAutohide= m_autohide; bool isHorizontal= (location == FLOATING_HORIZONTAL || location == TOP_DOCKED || location == BOTTOM_DOCKED); WXAppBar::EDocking oldDocking= m_pWindow->GetDockingMode(); if (design == CClickWindowController::NORMAL) { if (isHorizontal) m_pWindow= m_pWindowBitmap; else m_pWindow= m_pWindowBitmapVertical; } else { if (isHorizontal) m_pWindow= m_pWindowText; else m_pWindow= m_pWindowTextVertical; } // FIXME: implement this using the observer pattern m_pViacamController->GetMainWindow()->Connect (ID_WVIACAM, wxEVT_SHOW, wxShowEventHandler(CClickWindow::OnMainWindowShow), NULL, m_pWindow); m_pWindow->SetDockingMode(oldDocking); SetAutohide(isAutohide); } void CClickWindowController::SetDesign(CClickWindowController::EDesign design) { if (m_design== design) return; // Sanity check if (design != CClickWindowController::NORMAL && design != CClickWindowController::THIN) { SetDesign(CClickWindowController::NORMAL); return; } bool wasShown= IsShown(); if (wasShown) Show(false); SelectAppropriateWindow (design, m_location); if (wasShown) Show(true); m_design= design; } void CClickWindowController::SetLocation(CClickWindowController::ELocation location) { if (m_location== location) return; // Sanity check if (location< FLOATING_HORIZONTAL || location> RIGHT_DOCKED) { SetLocation(TOP_DOCKED); return; } bool isShown= IsShown(); if (isShown) Show(false); SelectAppropriateWindow (m_design, location); switch(location) { case FLOATING_HORIZONTAL: case FLOATING_VERTICAL: m_pWindow->SetDockingMode(WXAppBar::NON_DOCKED); break; case TOP_DOCKED: m_pWindow->SetDockingMode(WXAppBar::TOP_DOCKED); break; case BOTTOM_DOCKED: m_pWindow->SetDockingMode(WXAppBar::BOTTOM_DOCKED); break; case LEFT_DOCKED: m_pWindow->SetDockingMode(WXAppBar::LEFT_DOCKED); break; case RIGHT_DOCKED: m_pWindow->SetDockingMode(WXAppBar::RIGHT_DOCKED); break; default: assert (false); } if (isShown) Show(true); m_location= location; } void CClickWindowController::ActionDone(long x, long y) { // Run UI code in the main thread ActionDoneEvent event; wxPoint point(x, y); event.SetPoint(point); wxPostEvent(this, event); } void CClickWindowController::OnActionDoneEvent(const ActionDoneEvent& event) { long x= event.GetPoint().x; long y= event.GetPoint().y; // If cursor is over click window the notification takes place when // mouse event is received otherwise update internal state if (!IsCursorOverWindow(x,y)) { if (m_currentButton== CClickWindowController::DRAG) { if (!m_halfDragClick) m_halfDragClick= true; else { m_halfDragClick= false; m_currentButton= m_lockedButton; } } else m_currentButton= m_lockedButton; m_pWindow->UpdateButtons(GetEnabled(),GetCurrentButton(), GetLockedButton()); } } // Called from window. Notifies that button has been clicked. void CClickWindowController::NotifyButtonClick (CClickWindowController::EButton button) { if (m_enabled) { if (button== CClickWindowController::NO_CLICK) // Disable click m_enabled= false; else { if (m_fastMode || (m_currentButton!= m_lockedButton && button== m_currentButton)) m_lockedButton= button; m_currentButton= button; } m_pWindow->UpdateButtons(GetEnabled(),GetCurrentButton(), GetLockedButton()); } else { // Disabled state. Only handle NO_CLICK button if (button== CClickWindowController::NO_CLICK) { m_enabled= true; m_pWindow->UpdateButtons(GetEnabled(),GetCurrentButton(), GetLockedButton()); } } } // Called from window. Notifies that button has been entered void CClickWindowController::NotifyButtonEnter (CClickWindowController::EButton button) { if (m_enabled && m_fastMode) { if (button!= CClickWindowController::NO_CLICK && button!= m_currentButton) { m_currentButton= button; m_pWindow->UpdateButtons(GetEnabled(),GetCurrentButton(), GetLockedButton()); } } } void CClickWindowController::SetFastMode(bool enable) { m_fastMode= enable; } void CClickWindowController::SetAutohide(bool enable) { // TODO // bool isShown= IsShown(); // if (isShown) Show (false); m_autohide= enable; m_pWindow->SetAutohideMode(m_autohide); // if (m_autohide) m_status= CClickWindowController::HIDDEN; // else m_status= CClickWindowController::DOCKED; // if (isShown) Show (true); } inline bool CClickWindowController::IsCursorOverNoClickButton(long x, long y) { wxRect pos= m_pWindow->GetNoClickButton()->GetScreenRect(); if (y<= pos.GetBottom() && y>= pos.GetTop() && x>= pos.GetLeft() && x<= pos.GetRight()) return true; else return false; } void CClickWindowController::NotifyShowMainWindowClick () { m_pViacamController->GetMainWindow()->Show (!m_pViacamController->GetMainWindow()->IsShown()); } void CClickWindowController::SetWarnBarOverlap (bool value) { m_pWindow->SetWarnBarOverlap(value); } // Configuration methods void CClickWindowController::InitDefaults() { SetFastMode (false); SetDesign (CClickWindowController::NORMAL); //SetDockingMode(CClickWindowController::TOP_DOCKING); SetLocation (CClickWindowController::TOP_DOCKED); SetAutohide(false); //m_status= CClickWindowController::HIDDEN; } void CClickWindowController::WriteProfileData(wxConfigBase* pConfObj) { pConfObj->SetPath (_T("clickWindow")); pConfObj->Write(_T("fastMode"), m_fastMode); pConfObj->Write(_T("design"), (long) m_design); pConfObj->Write(_T("location"), (long) m_location); pConfObj->Write(_T("autohide"), m_autohide); pConfObj->Write(_T("warnBarOverlap"), m_pWindow->GetWarnBarOverlap()); pConfObj->SetPath (_T("..")); } void CClickWindowController::ReadProfileData(wxConfigBase* pConfObj) { pConfObj->SetPath (_T("clickWindow")); long design, location; bool warnBarOverlap= true; pConfObj->Read(_T("fastMode"), &m_fastMode); if (pConfObj->Read(_T("design"), &design)) SetDesign ((CClickWindowController::EDesign) design); if (pConfObj->Read(_T("location"), &location)) SetLocation (static_cast(location)); pConfObj->Read(_T("autohide"), &m_autohide); SetAutohide(m_autohide); pConfObj->Read(_T("warnBarOverlap"), &warnBarOverlap); m_pWindow->SetWarnBarOverlap(warnBarOverlap); pConfObj->SetPath (_T("..")); } const bool CClickWindowController::IsShown () const { return m_pWindow->IsShown(); }