/////////////////////////////////////////////////////////////////////////////
// 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();
}