1 // Copyright © 2008-2021 Pioneer Developers. See AUTHORS.txt for details 2 // Licensed under the terms of the GPL v3. See licenses/GPL-3.txt 3 4 #include "GuiContainer.h" 5 6 #include "Gui.h" 7 #include "graphics/Renderer.h" 8 9 #include <SDL_stdinc.h> 10 11 namespace Gui { 12 Container()13 Container::Container() 14 { 15 m_transparent = true; 16 SetBgColor(Theme::Colors::bg); 17 onMouseLeave.connect(sigc::mem_fun(this, &Container::_OnMouseLeave)); 18 onSetSize.connect(sigc::mem_fun(this, &Container::_OnSetSize)); 19 } 20 ~Container()21 Container::~Container() 22 { 23 DeleteAllChildren(); 24 } 25 _OnSetSize()26 void Container::_OnSetSize() 27 { 28 if (IsVisible()) UpdateAllChildSizes(); 29 } 30 _OnMouseLeave()31 void Container::_OnMouseLeave() 32 { 33 for (WidgetList::iterator i = m_children.begin(), itEnd = m_children.end(); i != itEnd; ++i) { 34 if ((*i).w->IsMouseOver() == true) 35 (*i).w->OnMouseLeave(); 36 } 37 } 38 OnMouseMotion(MouseMotionEvent * e)39 bool Container::OnMouseMotion(MouseMotionEvent *e) 40 { 41 float x = e->x; 42 float y = e->y; 43 for (WidgetList::iterator i = m_children.begin(), itEnd = m_children.end(); i != itEnd; ++i) { 44 float *pos, size[2]; 45 if (!(*i).w->IsVisible()) { 46 if ((*i).w->IsMouseOver() == true) 47 (*i).w->OnMouseLeave(); 48 continue; 49 } 50 int evmask = (*i).w->GetEventMask(); 51 if (!(evmask & Widget::EVENT_MOUSEMOTION)) continue; 52 53 pos = (*i).pos; 54 (*i).w->GetSize(size); 55 56 if ((x >= pos[0]) && (x < pos[0] + size[0]) && 57 (y >= pos[1]) && (y < pos[1] + size[1])) { 58 e->x = x - pos[0]; 59 e->y = y - pos[1]; 60 if ((*i).w->IsMouseOver() == false) { 61 (*i).w->OnMouseEnter(); 62 } 63 bool alive = (*i).w->OnMouseMotion(e); 64 if (!alive) return false; 65 } else { 66 if ((*i).w->IsMouseOver() == true) 67 (*i).w->OnMouseLeave(); 68 } 69 } 70 return true; 71 } 72 HandleMouseEvent(MouseButtonEvent * e)73 bool Container::HandleMouseEvent(MouseButtonEvent *e) 74 { 75 float x = e->x; 76 float y = e->y; 77 for (WidgetList::iterator i = m_children.begin(), itEnd = m_children.end(); i != itEnd; ++i) { 78 float *pos, size[2]; 79 if (!(*i).w->IsVisible()) continue; 80 if (!(*i).w->GetEnabled()) continue; 81 int evmask = (*i).w->GetEventMask(); 82 if (e->isdown) { 83 if (!(evmask & Widget::EVENT_MOUSEDOWN)) continue; 84 } else { 85 if (!(evmask & Widget::EVENT_MOUSEUP)) continue; 86 } 87 pos = (*i).pos; 88 (*i).w->GetSize(size); 89 90 if ((x >= pos[0]) && (x < pos[0] + size[0]) && 91 (y >= pos[1]) && (y < pos[1] + size[1])) { 92 e->x = x - pos[0]; 93 e->y = y - pos[1]; 94 bool alive; 95 if (e->isdown) { 96 alive = (*i).w->OnMouseDown(e); 97 } else { 98 alive = (*i).w->OnMouseUp(e); 99 } 100 if (!alive) return false; 101 } 102 } 103 onMouseButtonEvent.emit(e); 104 return true; 105 } 106 DeleteAllChildren()107 void Container::DeleteAllChildren() 108 { 109 PROFILE_SCOPED() 110 for (WidgetList::iterator i = m_children.begin(), itEnd = m_children.end(); i != itEnd; ++i) { 111 delete (*i).w; 112 } 113 m_children.clear(); 114 } 115 RemoveAllChildren()116 void Container::RemoveAllChildren() 117 { 118 PROFILE_SCOPED() 119 for (WidgetList::iterator i = m_children.begin(), itEnd = m_children.end(); i != itEnd; ++i) { 120 i->w->SetParent(0); 121 } 122 m_children.clear(); 123 } 124 PrependChild(Widget * child,float x,float y)125 void Container::PrependChild(Widget *child, float x, float y) 126 { 127 PROFILE_SCOPED() 128 assert(child->GetParent() == 0); 129 assert(FindChild(child) == m_children.end()); 130 131 widget_pos wp; 132 wp.w = child; 133 wp.pos[0] = x; 134 wp.pos[1] = y; 135 wp.flags = 0; 136 child->SetParent(this); 137 m_children.push_front(wp); 138 } 139 AppendChild(Widget * child,float x,float y)140 void Container::AppendChild(Widget *child, float x, float y) 141 { 142 PROFILE_SCOPED() 143 assert(child->GetParent() == 0); 144 assert(FindChild(child) == m_children.end()); 145 146 widget_pos wp; 147 wp.w = child; 148 wp.pos[0] = x; 149 wp.pos[1] = y; 150 wp.flags = 0; 151 child->SetParent(this); 152 m_children.push_back(wp); 153 } 154 MoveChild(Widget * child,float x,float y)155 void Container::MoveChild(Widget *child, float x, float y) 156 { 157 PROFILE_SCOPED() 158 WidgetList::iterator it = FindChild(child); 159 if (it != m_children.end()) { 160 it->pos[0] = x; 161 it->pos[1] = y; 162 } 163 } 164 RemoveChild(Widget * child)165 void Container::RemoveChild(Widget *child) 166 { 167 PROFILE_SCOPED() 168 WidgetList::iterator it = FindChild(child); 169 if (it != m_children.end()) { 170 it->w->SetParent(0); 171 m_children.erase(it); 172 } 173 } 174 FindChild(const Widget * w) const175 Container::WidgetList::const_iterator Container::FindChild(const Widget *w) const 176 { 177 PROFILE_SCOPED() 178 for (WidgetList::const_iterator i = m_children.begin(); i != m_children.end(); ++i) 179 if (i->w == w) return i; 180 return m_children.end(); 181 } 182 FindChild(const Widget * w)183 Container::WidgetList::iterator Container::FindChild(const Widget *w) 184 { 185 PROFILE_SCOPED() 186 for (WidgetList::iterator i = m_children.begin(), itEnd = m_children.end(); i != itEnd; ++i) 187 if (i->w == w) return i; 188 return m_children.end(); 189 } 190 Draw()191 void Container::Draw() 192 { 193 PROFILE_SCOPED() 194 195 Graphics::Renderer *r = Gui::Screen::GetRenderer(); 196 r->SetRenderState(Gui::Screen::alphaBlendState); 197 198 float size[2]; 199 GetSize(size); 200 if (!m_transparent) { 201 PROFILE_SCOPED_RAW("Container::Draw - !m_transparent") 202 if (!m_rect) { 203 m_rect.reset(new Graphics::Drawables::Rect(Screen::GetRenderer(), vector2f(0.f), vector2f(size[0], size[0]), m_bgcol, Screen::alphaBlendState, false)); 204 } else { 205 m_rect->Update(vector2f(0.f), vector2f(size[0], size[1]), m_bgcol); 206 } 207 m_rect->Draw(Screen::GetRenderer()); 208 } 209 210 for (WidgetList::iterator i = m_children.begin(), itEnd = m_children.end(); i != itEnd; ++i) { 211 PROFILE_SCOPED_RAW("Container::Draw - Child Loop") 212 if (!(*i).w->IsVisible()) 213 continue; 214 215 matrix4x4f modelView = r->GetTransform(); 216 modelView.Translate((*i).pos[0], (*i).pos[1], 0); 217 Graphics::Renderer::MatrixTicket ticket(r, modelView); 218 (*i).w->Draw(); 219 } 220 } 221 OnMouseDown(MouseButtonEvent * e)222 bool Container::OnMouseDown(MouseButtonEvent *e) 223 { 224 return HandleMouseEvent(e); 225 } 226 OnMouseUp(MouseButtonEvent * e)227 bool Container::OnMouseUp(MouseButtonEvent *e) 228 { 229 return HandleMouseEvent(e); 230 } 231 ShowChildren()232 void Container::ShowChildren() 233 { 234 PROFILE_SCOPED() 235 for (WidgetList::iterator i = m_children.begin(), itEnd = m_children.end(); i != itEnd; ++i) { 236 (*i).w->Show(); 237 } 238 } 239 HideChildren()240 void Container::HideChildren() 241 { 242 PROFILE_SCOPED() 243 for (WidgetList::iterator i = m_children.begin(), itEnd = m_children.end(); i != itEnd; ++i) { 244 (*i).w->Hide(); 245 } 246 } 247 GetChildPosition(const Widget * child,float outPos[2]) const248 void Container::GetChildPosition(const Widget *child, float outPos[2]) const 249 { 250 WidgetList::const_iterator it = FindChild(child); 251 assert(it != m_children.end()); 252 outPos[0] = it->pos[0]; 253 outPos[1] = it->pos[1]; 254 } 255 Show()256 void Container::Show() 257 { 258 PROFILE_SCOPED() 259 Widget::Show(); 260 if (IsVisible()) { 261 ResizeRequest(); 262 } 263 } 264 ShowAll()265 void Container::ShowAll() 266 { 267 PROFILE_SCOPED() 268 for (WidgetList::iterator i = m_children.begin(), itEnd = m_children.end(); i != itEnd; ++i) { 269 (*i).w->ShowAll(); 270 } 271 Show(); 272 } 273 HideAll()274 void Container::HideAll() 275 { 276 PROFILE_SCOPED() 277 HideChildren(); 278 Hide(); 279 } 280 SetBgColor(const Color & col)281 void Container::SetBgColor(const Color &col) 282 { 283 m_bgcol = col; 284 } 285 286 } // namespace Gui 287