/* * This file is part of the planetblupi source code * Copyright (C) 1997, Daniel Roux & EPSITEC SA * Copyright (C) 2017-2019, Mathieu Schroeter * http://epsitec.ch; http://www.blupi.org; http://github.com/blupi-games * * 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 http://gnu.org/licenses */ #include #include #include "button.h" #include "decor.h" #include "def.h" #include "event.h" #include "gettext.h" #include "misc.h" #include "pixmap.h" #include "sound.h" CButton::CButton () { m_type = 0; m_bEnable = true; m_bHide = false; m_state = 0; m_mouseState = 0; m_nbMenu = 0; m_nbToolTips = 0; m_selMenu = 0; m_bMouseDown = false; m_message = static_cast (-1); m_pPixmap = nullptr; m_pDecor = nullptr; m_pSound = nullptr; m_toolTips = nullptr; } CButton::~CButton () {} // Crée un nouveau bouton. bool CButton::Create ( CPixmap * pPixmap, CSound * pSound, Point pos, Sint32 type, Sint32 * pMenu, Sint32 nbMenu, const char ** pToolTips, Sint32 region, Uint32 message, bool isRightReading) { Point iconDim; Sint32 i, icon; static Sint32 ttypes[] = { DIMBUTTONX, DIMBUTTONY, // button00.bmp }; if (type < 0 || type > 0) return false; iconDim.x = ttypes[type * 2 + 0]; iconDim.y = ttypes[type * 2 + 1]; m_pPixmap = pPixmap; m_pSound = pSound; m_type = type; m_bEnable = true; m_bHide = false; m_message = message; m_pos = pos; m_dim = iconDim; m_nbMenu = nbMenu; m_selMenu = 0; m_state = 0; m_mouseState = 0; m_bMouseDown = false; m_nbToolTips = 0; while (pToolTips[m_nbToolTips]) ++m_nbToolTips; for (i = 0; i < nbMenu; i++) { icon = pMenu[i]; if (isRightReading) { if (icon == 51) // right arrow icon = 50; else if (icon == 50) // left arrow icon = 51; else if (icon == 40) // stop icon = 109; } if (region == 1) // palmiers ? { if (icon == 0) icon = 90; // sol normal if (icon == 1) icon = 91; // sol inflammable if (icon == 2) icon = 92; // sol inculte if (icon == 7) icon = 9; // plante if (icon == 8) icon = 10; // arbre } if (region == 2) // hiver ? { if (icon == 0) icon = 96; // sol normal if (icon == 1) icon = 97; // sol inflammable if (icon == 2) icon = 98; // sol inculte if (icon == 8) icon = 99; // arbre } if (region == 3) // sapin ? { if (icon == 0) icon = 102; // sol normal if (icon == 1) icon = 103; // sol inflammable if (icon == 2) icon = 104; // sol inculte if (icon == 8) icon = 105; // arbre } m_iconMenu[i] = icon; } m_toolTips = pToolTips; return true; } // Dessine un bouton dans son état. void CButton::Draw () { Sint32 i; Point pos = this->m_pos; Rect rect; if (m_bHide) // bouton caché ? { rect.left = pos.x; rect.right = pos.x + m_dim.x; rect.top = pos.y; rect.bottom = pos.y + m_dim.y; m_pPixmap->DrawPart (-1, CHBACK, pos, rect); // dessine le fond return; } if (m_bEnable) // bouton actif ? m_pPixmap->DrawIcon (-1, CHBUTTON + m_type, m_mouseState, pos); else m_pPixmap->DrawIcon (-1, CHBUTTON + m_type, 4, pos); if (m_nbMenu == 0) return; if (m_nbMenu > 0) { m_pPixmap->DrawIcon (-1, CHBUTTON + m_type, m_iconMenu[m_selMenu] + 6, pos); } if (m_nbMenu == 1 || !m_bEnable || !m_bMouseDown) return; pos.x += IsRightReading () ? -m_dim.x - 2 : m_dim.x + 2; for (i = 0; i < m_nbMenu; i++) { m_pPixmap->DrawIcon (-1, CHBUTTON + m_type, i == m_selMenu ? 1 : 0, pos); m_pPixmap->DrawIcon (-1, CHBUTTON + m_type, m_iconMenu[i] + 6, pos); pos.x += IsRightReading () ? -m_dim.x - 1 : m_dim.x - 1; } } Sint32 CButton::GetState () { return m_state; } void CButton::SetState (Sint32 state) { m_state = state; m_mouseState = state; } Sint32 CButton::GetMenu () { return m_selMenu; } void CButton::SetMenu (Sint32 menu) { m_selMenu = menu; } bool CButton::GetEnable () { return m_bEnable; } void CButton::SetEnable (bool bEnable) { m_bEnable = bEnable; } bool CButton::GetHide () { return m_bHide; } void CButton::SetHide (bool bHide) { m_bHide = bHide; } // Traitement d'un événement. bool CButton::TreatEvent (const SDL_Event & event) { Point pos; if (m_bHide || !m_bEnable) return false; // pos = ConvLongToPos(lParam); switch (event.type) { case SDL_MOUSEBUTTONDOWN: if ( event.button.button != SDL_BUTTON_LEFT && event.button.button != SDL_BUTTON_RIGHT) break; pos.x = event.button.x; pos.y = event.button.y; if (MouseDown (pos)) return true; break; case SDL_MOUSEMOTION: pos.x = event.motion.x; pos.y = event.motion.y; if (MouseMove (pos)) return true; break; case SDL_MOUSEBUTTONUP: if ( event.button.button != SDL_BUTTON_LEFT && event.button.button != SDL_BUTTON_RIGHT) break; pos.x = event.button.x; pos.y = event.button.y; if (MouseUp (pos)) // (*) return false; break; } return false; } // (*) Tous les boutons doivent recevoir l'événement BUTTONUP ! // Indique si la souris est sur ce bouton. bool CButton::MouseOnButton (Point pos) { return Detect (pos); } bool CButton::IsInMenu (const Point & pos) { Sint32 width = m_dim.x; if (m_nbMenu > 1 && m_bMouseDown) // submenu expanded ? width += 2 + (m_dim.x + (IsRightReading () ? 1 : -1)) * m_nbMenu; if (IsRightReading () && m_nbMenu > 1 && m_bMouseDown) { if (pos.x > m_pos.x + m_dim.x || pos.x < m_pos.x - width + m_dim.x) return false; } else { if (pos.x < m_pos.x || pos.x > m_pos.x + width) return false; } if (pos.y < m_pos.y || pos.y > m_pos.y + m_dim.y) return false; return true; } // Retourne le tooltips pour un bouton, en fonction // de la position de la souris. const char * CButton::GetToolTips (Point pos) { Sint32 rank; if (m_bHide || !m_bEnable) return nullptr; if (!this->IsInMenu (pos)) return nullptr; rank = (pos.x - (m_pos.x + 2 + 1)) / (m_dim.x - 1); if (rank < 0) rank = 0; if (rank > m_nbToolTips) return nullptr; if (m_nbMenu > 1) { if (m_bMouseDown && rank > 0) rank--; else rank = m_selMenu; } return gettext (m_toolTips[rank]); } // Détecte si la souris est dans le bouton. bool CButton::Detect (Point pos) { if (m_bHide || !m_bEnable) return false; return this->IsInMenu (pos); } // Bouton de la souris pressé. bool CButton::MouseDown (Point pos) { if (!Detect (pos)) return false; m_mouseState = 1; m_bMouseDown = true; CEvent::PushUserEvent (EV_UPDATE); m_pSound->PlayImage (SOUND_CLICK, pos); return true; } // Souris déplacés. bool CButton::MouseMove (Point pos) { bool bDetect; Sint32 iState, iMenu; iState = m_mouseState; iMenu = m_selMenu; bDetect = Detect (pos); if (m_bMouseDown) { if (bDetect) m_mouseState = 1; // pressé else m_mouseState = m_state; } else { if (bDetect) m_mouseState = m_state + 2; // survollé else m_mouseState = m_state; } if ( m_nbMenu > 1 && m_bMouseDown && (IsRightReading () ? pos.x < m_pos.x : pos.x > m_pos.x + m_dim.x + 2)) // in sub-menu ? { m_selMenu = IsRightReading () ? (m_pos.x - 2 - pos.x) / (m_dim.x + 1) : (pos.x - (m_pos.x + m_dim.x + 2)) / (m_dim.x - 1); if (m_selMenu >= m_nbMenu) m_selMenu = m_nbMenu - 1; } if (iState != m_mouseState || iMenu != m_selMenu) CEvent::PushUserEvent (EV_UPDATE); return m_bMouseDown; } // Bouton de la souris relâché. bool CButton::MouseUp (Point pos) { bool bDetect; bDetect = Detect (pos); m_mouseState = m_state; m_bMouseDown = false; if (!bDetect) return false; if (m_message != static_cast (-1)) CEvent::PushUserEvent (m_message); return true; }