/* * Descent 3 * Copyright (C) 2024 Parallax Software * * 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 . --- HISTORICAL COMMENTS FOLLOW --- * $Logfile: /DescentIII/Main/ui/UIButton.cpp $ * $Revision: 29 $ * $Date: 5/02/99 7:18p $ * $Author: Samir $ * * Button code. * * $Log: /DescentIII/Main/ui/UIButton.cpp $ * * 29 5/02/99 7:18p Samir * a little better error checking with mouse input. also with fix from * grtext.cpp, fixed phony button problem. * * 28 5/02/99 6:09p Samir * unlock focus for buttons when mouse goes up regardless of state. * * 27 5/02/99 2:08a Samir * added Enable and Disable and only accept locking of button if mouse is * inside the button. * * 26 5/01/99 1:14a Samir * fixed mouse sequencing probs with selections being canceled out by * UISystem. * * 25 4/17/99 5:59a Jeff * Linux wants m_ButtonFont defined * * 24 4/14/99 1:52a Jeff * fixed case mismatched #includes * * 23 3/09/99 12:21p Samir * only allow checking of boxes if mouse is in checkbox at all times, not * when clicked on once. * * 22 2/21/99 6:36p Samir * focusing changes and key input changes to ui., * * 21 2/16/99 11:58a Samir * format buttons to fit their state. * * 20 12/08/98 3:18p Samir * checking a check box calls OnSelect * * 19 9/30/98 4:33p Samir * disabled gadgets display dim text. * * 18 9/23/98 3:00p Samir * took out unnecessary code. * * 17 5/22/98 5:02p Jeff * Added a flag for radio buttons so the button part won't be drawn (just * the text) * * 16 5/22/98 1:31p Jeff * changed text saturation for radio button * * 15 5/01/98 6:23p Samir * darkened buttons a bit. * * 14 4/24/98 2:42a Samir * added UICheckBox * * 13 3/10/98 12:50p Samir * Added highlight to radio button. * * 12 3/05/98 6:40p Samir * Implemented radio buttons. * * 11 2/10/98 4:55p Samir * Added radio buttons. * * 10 1/30/98 7:05p Samir * Each gadget now has their own coordinate system. * * 9 1/23/98 5:34p Samir * Allow for nonpersistant UIItems. * * 8 1/18/98 4:22p Samir * Implemented new UIItem system. * * 7 1/13/98 4:29p Samir * Added gadget buttons. * * 6 1/08/98 12:18p Samir * Buttons draw text color based off of UITextItem color. * * 5 1/05/98 4:36p Samir * Moved centering and fittext control flags to UIGadget class. * * 4 1/05/98 3:48p Jason * added SetAllText function for buttons * * 3 1/05/98 3:18p Samir * Added some button flags. * * 2 1/02/98 12:43p Samir * New UIButton interface. * * 1 12/30/97 4:36p Samir * Initial revision * * $NoKeywords: $ */ #include #include "UIlib.h" #if defined(POSIX) int UIButton::m_ButtonFont; #endif // tUIButton // This is a simple 2 state button (push down or push up) // Buttons have properties of gadgets, plus bitmap information per state. UIButton::UIButton() { m_Items[UI_BTS_DISABLED] = NULL; m_Items[UI_BTS_INACTIVE] = NULL; m_Items[UI_BTS_HILITE] = NULL; m_Items[UI_BTS_ACTIVATED] = NULL; } UIButton::~UIButton() {} // if text = NULL, no text printed out. void UIButton::Create(UIWindow *parent, int id, UIItem *item, int x, int y, int w, int h, int flags) { if (item) { m_Items[UI_BTS_DISABLED] = item->CopyUIItem(); m_Items[UI_BTS_INACTIVE] = item->CopyUIItem(); m_Items[UI_BTS_HILITE] = item->CopyUIItem(); m_Items[UI_BTS_ACTIVATED] = item->CopyUIItem(); } SetColor(UI_BTS_DISABLED, GR_DARKGRAY); SetColor(UI_BTS_INACTIVE, GR_DARKGRAY); SetColor(UI_BTS_HILITE, GR_RGB(128, 128, 128)); SetColor(UI_BTS_ACTIVATED, GR_RGB(128, 128, 128)); m_State = UI_BTS_INACTIVE; // current state of button. UIGadget::Create(parent, id, x, y, w, h, flags); } // sets the background bitmap for a specified button state void UIButton::SetStateItem(int state, UIItem *item) { ASSERT(state < UI_BTS_NUM); if (m_Items[state]) { delete m_Items[state]; m_Items[state] = NULL; } if (item) m_Items[state] = item->CopyUIItem(); } // sets the background color for a specified button state void UIButton::SetColor(int state, ddgr_color col) { ASSERT(state < UI_BTS_NUM); m_Colors[state] = col; } // sets text for all states. void UIButton::SetAllStates(UIItem *item) { for (int i = 0; i < UI_BTS_NUM; i++) SetStateItem(i, item); } // Inheritable operations // override: behavior when gadget is destroyed. void UIButton::OnDestroy() { UIGadget::OnDestroy(); SetStateItem(UI_BTS_DISABLED, NULL); SetStateItem(UI_BTS_INACTIVE, NULL); SetStateItem(UI_BTS_HILITE, NULL); SetStateItem(UI_BTS_ACTIVATED, NULL); } // behavior when gadget loses input focus. void UIButton::OnLostFocus() { if (m_State == UI_BTS_HILITE) m_State = UI_BTS_INACTIVE; } // behavior when gadget gains input focus. void UIButton::OnGainFocus() { if (m_State != UI_BTS_ACTIVATED) m_State = UI_BTS_HILITE; } // override: called when resized or before drawing. void UIButton::OnFormat() { if (m_Flags & UIF_FIT) { m_W = m_Items[m_State]->width() + 20; m_H = m_Items[m_State]->height() + 8; } UIGadget::OnFormat(); } // behavior when gadget is being drawn. void UIButton::OnDraw() { // do state based drawing // determine colors here. if (IsDisabled()) m_State = UI_BTS_DISABLED; switch (m_State) { case UI_BTS_ACTIVATED: case UI_BTS_HILITE: ui_DrawLTBox(GR_BLACK, GR_LIGHTGRAY, 0, 0, m_W, m_H); break; case UI_BTS_INACTIVE: ui_DrawLTBox(GR_LIGHTGRAY, GR_BLACK, 0, 0, m_W, m_H); break; case UI_BTS_DISABLED: ui_DrawLTBox(GR_DARKGRAY, GR_DARKGRAY, 0, 0, m_W, m_H); break; default: Int3(); } ui_DrawRect(m_Colors[m_State], 1, 1, m_W - 1, m_H - 1); if (m_Items[m_State]) { int x = (m_W / 2 - m_Items[m_State]->width() / 2); int y = (m_H / 2 - m_Items[m_State]->height() / 2); m_Items[m_State]->draw(x, y, IsDisabled() ? uiDrawFaded : uiDrawNormal); } } // behavior when key is pressed. void UIButton::OnKeyDown(int key) {} // behavior when key is released. void UIButton::OnKeyUp(int key) {} // behavior when mouse button is pressed. void UIButton::OnMouseBtnDown(int btn) { if (btn == UILMSEBTN) { if (m_State != UI_BTS_ACTIVATED && PT_IN_GADGET(m_Wnd, this, UI_input.mx, UI_input.my)) { m_State = UI_BTS_ACTIVATED; LOCK_FOCUS(this); // mprintf(0, "Mouse down, locking gadget.\n"); } else if (m_State == UI_BTS_ACTIVATED && !PT_IN_GADGET(m_Wnd, this, UI_input.mx, UI_input.my)) { m_State = UI_BTS_HILITE; } } } // behavior when mouse button is released. void UIButton::OnMouseBtnUp(int btn) { if (btn == UILMSEBTN) { if (m_State == UI_BTS_ACTIVATED) { if (PT_IN_GADGET(UIGadget::m_Wnd, this, UI_input.mx, UI_input.my)) { OnSelect(); } m_State = UI_BTS_HILITE; } // mprintf(0, "Mouse up, unlocking gadget.\n"); UNLOCK_FOCUS(this); } } // this adds to the gadget equivalent void UIButton::Disable() { UIGadget::Disable(); m_State = UI_BTS_DISABLED; } // this adds to the gadget equivalent void UIButton::Enable() { UIGadget::Enable(); if (HasFocus()) { m_State = UI_BTS_HILITE; } else { m_State = UI_BTS_INACTIVE; } } // UIRadioButton // This is a simple 2 state button (push down or push up) // Buttons have properties of gadgets, plus bitmap information per state. UIRadioButton::UIRadioButton() { m_PrevRB = m_NextRB = NULL; } void UIRadioButton::Create(UIWindow *parent, UIRadioButton *prev_rb, int id, UIItem *title, int x, int y, int w, int h, int flags) { UIButton::Create(parent, id, title, x, y, w, h, flags); // create link in radio button chain. m_PrevRB = prev_rb; m_NextRB = NULL; if (m_PrevRB) { m_NextRB = m_PrevRB->m_NextRB; if (m_NextRB) { m_NextRB->m_PrevRB = this; } m_PrevRB->m_NextRB = this; } if (!m_PrevRB) { UIGadget::SetFlag(UIF_GROUP_START); } else { m_PrevRB->ClearFlag(UIF_GROUP_END); } if (!m_NextRB) { UIGadget::SetFlag(UIF_GROUP_END); } // THIS PROBLEM IS PROBABLY DUE TO THE CALLER'S FAULT! ASSERT(m_PrevRB != this); } // turns on button, turns off others in group. void UIRadioButton::Activate() { ActivateButton(); } // behavior when gadget is being drawn. void UIRadioButton::OnDraw() { char btnstr[3]; int iterations = 0; if (IsDisabled()) m_State = UI_BTS_DISABLED; switch (m_State) { case UI_BTS_HILITE: iterations = 1; case UI_BTS_INACTIVE: case UI_BTS_DISABLED: if (m_Flags & UIRB_NOBUTTON) strcpy(btnstr, " "); else snprintf(btnstr, sizeof(btnstr), "%c ", UI_RADIO_OFF_CHAR); break; case UI_BTS_ACTIVATED: iterations = 1; if (m_Flags & UIRB_NOBUTTON) strcpy(btnstr, " "); else snprintf(btnstr, sizeof(btnstr), "%c ", UI_RADIO_ON_CHAR); break; default: btnstr[0] = 0; } UITextItem btn(btnstr, GetStateItem(m_State)->get_color(), GetStateItem(m_State)->get_alpha()); btn.draw(0, 0, IsDisabled() ? uiDrawFaded : uiDrawNormal); GetStateItem(m_State)->draw(ui_GetTextWidth(btnstr), 0, IsDisabled() ? uiDrawFaded : uiDrawNormal); while (iterations--) { btn.draw(0, 0, uiDrawAlphaSaturate); GetStateItem(m_State)->draw(ui_GetTextWidth(btnstr), 0, uiDrawAlphaSaturate); } } // override: called when resized or before drawing. void UIRadioButton::OnFormat() { if (m_Flags & UIF_FIT) { char btnstr[3]; if (m_Flags & UIRB_NOBUTTON) strcpy(btnstr, " "); else snprintf(btnstr, sizeof(btnstr), "%c ", UI_RADIO_OFF_CHAR); UITextItem btn(btnstr, GetStateItem(m_State)->get_color(), GetStateItem(m_State)->get_alpha()); m_W = GetStateItem(m_State)->width() + btn.width(); m_H = GetStateItem(m_State)->height() + 8; } UIGadget::OnFormat(); } // behavior when gadget loses input focus. void UIRadioButton::OnLostFocus() {} // behavior when gadget gains input focus. void UIRadioButton::OnGainFocus() {} // behavior when key is pressed. void UIRadioButton::OnKeyDown(int key) { if (key == KEY_SPACEBAR || key == KEY_ENTER) ActivateButton(); } // behavior when key is released. void UIRadioButton::OnKeyUp(int key) {} // behavior when mouse button is pressed. void UIRadioButton::OnMouseBtnDown(int btn) { if (btn == UILMSEBTN && !this->IsLocked()) { if (PT_IN_GADGET(m_Wnd, this, UI_input.mx, UI_input.my)) { ActivateButton(); LOCK_FOCUS(this); } } } // behavior when mouse button is released. void UIRadioButton::OnMouseBtnUp(int btn) { if (btn == UILMSEBTN) { UNLOCK_FOCUS(this); } } // activates this button, deactivating all others. void UIRadioButton::ActivateButton() { // okay, start through list UIRadioButton *radiolist = this; while (radiolist->m_PrevRB) radiolist = radiolist->m_PrevRB; // deactivate all buttons until we hit the current button, then activate it. while (radiolist) { if (radiolist == this) { radiolist->m_State = UI_BTS_ACTIVATED; OnSelect(); } else { radiolist->m_State = UI_BTS_INACTIVE; } radiolist = radiolist->m_NextRB; } } ////////////////////////////////////////////////////////////////////////////// // UICheckBox // This is a simple 2 state button (push down or push up) // Buttons have properties of gadgets, plus bitmap information per state. UICheckBox::UICheckBox() {} void UICheckBox::Create(UIWindow *parent, int id, UIItem *title, int x, int y, int w, int h, int flags) { UIButton::Create(parent, id, title, x, y, w, h, flags); SetCheck(false); } // turns on button, turns off others in group. void UICheckBox::SetCheck(bool state) { if (state) { m_State = UI_BTS_ACTIVATED; } else { m_State = UI_BTS_INACTIVE; } } // behavior when gadget is being drawn. void UICheckBox::OnDraw() { char btnstr[3]; int iterations = 1; ui_DrawSetTextType(UI_TEXTTYPE_SATURATE); if (IsDisabled()) m_State = UI_BTS_DISABLED; switch (m_State) { case UI_BTS_HILITE: iterations = 2; case UI_BTS_INACTIVE: case UI_BTS_DISABLED: snprintf(btnstr, sizeof(btnstr), "%c ", UI_CHECKBOX_OFF_CHAR); break; case UI_BTS_ACTIVATED: iterations = 2; snprintf(btnstr, sizeof(btnstr), "%c ", UI_CHECKBOX_ON_CHAR); break; default: btnstr[0] = 0; } UITextItem btn(btnstr, GetStateItem(m_State)->get_color(), GetStateItem(m_State)->get_alpha()); while (iterations--) { btn.draw(0, 0); GetStateItem(m_State)->draw(ui_GetTextWidth(btnstr), 0, IsDisabled() ? uiDrawFaded : uiDrawNormal); } ui_DrawSetTextType(0); } // override: called when resized or before drawing. void UICheckBox::OnFormat() { if (m_Flags & UIF_FIT) { char btnstr[3]; snprintf(btnstr, sizeof(btnstr), "%c ", UI_CHECKBOX_OFF_CHAR); UITextItem btn(btnstr, GetStateItem(m_State)->get_color(), GetStateItem(m_State)->get_alpha()); m_W = GetStateItem(m_State)->width() + btn.width(); m_H = GetStateItem(m_State)->height() + 8; } UIGadget::OnFormat(); } // behavior when gadget loses input focus. void UICheckBox::OnLostFocus() {} // behavior when gadget gains input focus. void UICheckBox::OnGainFocus() {} // behavior when key is pressed. void UICheckBox::OnKeyDown(int key) { if (key == KEY_SPACEBAR || key == KEY_ENTER) { SetCheck((m_State == UI_BTS_ACTIVATED) ? false : true); OnSelect(); } } // behavior when key is released. void UICheckBox::OnKeyUp(int key) {} // behavior when mouse button is pressed. void UICheckBox::OnMouseBtnDown(int btn) { if (btn == UILMSEBTN && !this->IsLocked()) { if (PT_IN_GADGET(m_Wnd, this, UI_input.mx, UI_input.my)) { SetCheck((m_State == UI_BTS_ACTIVATED) ? false : true); OnSelect(); LOCK_FOCUS(this); } } } // behavior when mouse button is released. void UICheckBox::OnMouseBtnUp(int btn) { if (btn == UILMSEBTN) { UNLOCK_FOCUS(this); } }