nuclear@6: /* nuclear@6: GoatKit - a themable/animated widget toolkit for games nuclear@6: Copyright (C) 2014 John Tsiombikas nuclear@6: nuclear@6: This program is free software: you can redistribute it and/or modify nuclear@6: it under the terms of the GNU Lesser General Public License as published by nuclear@6: the Free Software Foundation, either version 3 of the License, or nuclear@6: (at your option) any later version. nuclear@6: nuclear@6: This program is distributed in the hope that it will be useful, nuclear@6: but WITHOUT ANY WARRANTY; without even the implied warranty of nuclear@6: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the nuclear@6: GNU Lesser General Public License for more details. nuclear@6: nuclear@6: You should have received a copy of the GNU Lesser General Public License nuclear@6: along with this program. If not, see . nuclear@6: */ nuclear@6: #include nuclear@6: #include nuclear@6: #include nuclear@6: #include nuclear@6: #include "screen.h" nuclear@6: #include "widget.h" nuclear@15: #include "boolanm.h" nuclear@6: nuclear@6: #define MAX_BUTTONS 16 nuclear@6: nuclear@6: namespace goatkit { nuclear@6: nuclear@6: struct ScreenImpl { nuclear@15: BoolAnim visible; nuclear@6: std::vector widgets; nuclear@6: BBox box; nuclear@6: nuclear@6: Widget *inp_focused, *over, *pressed[MAX_BUTTONS]; nuclear@6: Widget *mgrab; nuclear@6: }; nuclear@6: nuclear@6: static Vec2 world_to_scr(const ScreenImpl *scr, const Vec2 &v); nuclear@6: //static Vec2 scr_to_world(const ScreenImpl *scr, const Vec2 &v) nuclear@6: nuclear@6: Screen::Screen() nuclear@6: { nuclear@6: scr = new ScreenImpl; nuclear@6: nuclear@6: scr->box.bmin = Vec2(0, 0); nuclear@6: scr->box.bmax = Vec2(1, 1); nuclear@6: nuclear@6: scr->inp_focused = scr->over = 0; nuclear@6: for(int i=0; ipressed[i] = 0; nuclear@6: } nuclear@6: nuclear@6: scr->visible = true; nuclear@6: scr->mgrab = 0; nuclear@6: } nuclear@6: nuclear@6: Screen::~Screen() nuclear@6: { nuclear@6: delete scr; nuclear@6: } nuclear@6: nuclear@6: void Screen::set_position(float x, float y) nuclear@6: { nuclear@6: set_position(Vec2(x, y)); nuclear@6: } nuclear@6: nuclear@6: void Screen::set_position(const Vec2 &pos) nuclear@6: { nuclear@6: Vec2 sz = get_size(); nuclear@6: nuclear@6: scr->box.bmin = pos; nuclear@6: scr->box.bmax.x = pos.x + sz.x; nuclear@6: scr->box.bmax.y = pos.y + sz.y; nuclear@6: } nuclear@6: nuclear@6: const Vec2 &Screen::get_position() const nuclear@6: { nuclear@6: return scr->box.bmin; nuclear@6: } nuclear@6: nuclear@6: void Screen::set_size(float x, float y) nuclear@6: { nuclear@6: set_size(Vec2(x, y)); nuclear@6: } nuclear@6: nuclear@6: void Screen::set_size(const Vec2 &sz) nuclear@6: { nuclear@6: scr->box.bmax.x = scr->box.bmin.x + sz.x; nuclear@6: scr->box.bmax.y = scr->box.bmin.y + sz.y; nuclear@6: } nuclear@6: nuclear@6: const Vec2 Screen::get_size() const nuclear@6: { nuclear@6: return Vec2(scr->box.bmax.x - scr->box.bmin.x, nuclear@6: scr->box.bmax.y - scr->box.bmin.y); nuclear@6: } nuclear@6: nuclear@6: const BBox &Screen::get_box() const nuclear@6: { nuclear@6: return scr->box; nuclear@6: } nuclear@6: nuclear@6: void Screen::add_widget(Widget *w) nuclear@6: { nuclear@6: scr->widgets.push_back(w); nuclear@6: if(scr->visible) { nuclear@6: w->show(); nuclear@6: } else { nuclear@6: w->hide(); nuclear@6: } nuclear@6: nuclear@6: w->set_screen(this); nuclear@6: } nuclear@6: nuclear@6: int Screen::get_widget_count() const nuclear@6: { nuclear@6: return (int)scr->widgets.size(); nuclear@6: } nuclear@6: nuclear@6: Widget *Screen::get_widget(int idx) const nuclear@6: { nuclear@6: if(idx < 0 || idx >= (int)scr->widgets.size()) { nuclear@6: return 0; nuclear@6: } nuclear@6: return scr->widgets[idx]; nuclear@6: } nuclear@6: nuclear@6: Widget *Screen::get_widget(const char *name) const nuclear@6: { nuclear@6: for(size_t i=0; iwidgets.size(); i++) { nuclear@6: if(strcmp(scr->widgets[i]->get_name(), name) == 0) { nuclear@6: return scr->widgets[i]; nuclear@6: } nuclear@6: } nuclear@6: return 0; nuclear@6: } nuclear@6: nuclear@6: void Screen::show() nuclear@6: { nuclear@15: scr->visible.change(true); nuclear@6: nuclear@6: for(size_t i=0; iwidgets.size(); i++) { nuclear@6: scr->widgets[i]->show(); nuclear@6: } nuclear@6: } nuclear@6: nuclear@6: void Screen::hide() nuclear@6: { nuclear@15: scr->visible.change(false); nuclear@6: nuclear@6: for(size_t i=0; iwidgets.size(); i++) { nuclear@6: scr->widgets[i]->hide(); nuclear@6: } nuclear@6: } nuclear@6: nuclear@6: bool Screen::is_visible() const nuclear@6: { nuclear@6: return scr->visible; nuclear@6: } nuclear@6: nuclear@15: float Screen::get_visibility() const nuclear@15: { nuclear@15: return scr->visible.get_value(); nuclear@15: } nuclear@15: nuclear@15: void Screen::set_visibility_transition(long msec) nuclear@15: { nuclear@15: scr->visible.set_transition_duration(msec); nuclear@15: for(size_t i=0; iwidgets.size(); i++) { nuclear@15: scr->widgets[i]->set_visibility_transition(msec); nuclear@15: } nuclear@15: } nuclear@15: nuclear@15: long Screen::get_visibility_transition() const nuclear@15: { nuclear@15: return scr->visible.get_transition_duration(); nuclear@15: } nuclear@15: nuclear@6: bool Screen::grab_mouse(Widget *w) nuclear@6: { nuclear@6: if(!scr->mgrab || !w) { nuclear@6: scr->mgrab = w; nuclear@6: return true; nuclear@6: } nuclear@6: return false; nuclear@6: } nuclear@6: nuclear@6: void Screen::draw() const nuclear@6: { nuclear@6: for(size_t i=0; iwidgets.size(); i++) { nuclear@6: scr->widgets[i]->draw(); nuclear@6: } nuclear@6: } nuclear@6: nuclear@6: static Widget *find_widget_at(const ScreenImpl *scr, const Vec2 &pt) nuclear@6: { nuclear@6: for(size_t i=0; iwidgets.size(); i++) { nuclear@6: Widget *w = scr->widgets[i]; nuclear@6: nuclear@6: if(w->hit_test(pt)) { nuclear@6: return w; nuclear@6: } nuclear@6: } nuclear@6: return 0; nuclear@6: } nuclear@6: nuclear@6: void Screen::sysev_keyboard(int key, bool press) nuclear@6: { nuclear@6: Event ev; nuclear@6: nuclear@6: if(scr->inp_focused) { nuclear@6: ev.type = EV_KEY; nuclear@6: ev.key.key = key; nuclear@6: ev.key.press = press; nuclear@6: scr->inp_focused->handle_event(ev); nuclear@6: } nuclear@6: } nuclear@6: nuclear@6: void Screen::sysev_mouse_button(int bn, bool press, float x, float y) nuclear@6: { nuclear@6: Event ev; nuclear@6: Vec2 pt = world_to_scr(scr, Vec2(x, y)); nuclear@6: Widget *new_over = scr->mgrab ? scr->mgrab : find_widget_at(scr, pt); nuclear@6: nuclear@6: ev.type = EV_MOUSE_BUTTON; nuclear@6: ev.button.button = bn; nuclear@6: ev.button.pos = pt; nuclear@6: ev.button.press = press; nuclear@6: nuclear@6: if(press) { nuclear@6: if(bn == 0) { nuclear@6: // left click gives input focus nuclear@6: // TODO: add input focus event in widget nuclear@6: if(new_over && new_over != scr->inp_focused && new_over->can_focus()) { nuclear@6: printf("input focus %p -> %p\n", (void*)scr->inp_focused, (void*)new_over); nuclear@6: new_over->focusin(); nuclear@6: nuclear@6: if(scr->inp_focused) { nuclear@6: scr->inp_focused->focusout(); nuclear@6: } nuclear@6: scr->inp_focused = new_over; nuclear@6: } nuclear@6: } nuclear@6: nuclear@6: scr->pressed[bn] = new_over; nuclear@6: scr->over = new_over; nuclear@6: nuclear@6: if(new_over) { nuclear@6: new_over->handle_event(ev); nuclear@6: } nuclear@6: nuclear@6: } else { nuclear@6: // send the mouse release event to the widget that got the matching press nuclear@6: if(scr->pressed[bn]) { nuclear@6: scr->pressed[bn]->handle_event(ev); nuclear@6: scr->pressed[bn] = 0; nuclear@6: } nuclear@6: } nuclear@6: nuclear@6: // if we're not over the same widget any more send the leave/enter events nuclear@6: // TODO also add drag/drop events nuclear@6: if(scr->over != new_over) { nuclear@6: ev.type = EV_MOUSE_FOCUS; nuclear@6: if(scr->over) { nuclear@6: ev.focus.enter = false; nuclear@6: scr->over->handle_event(ev); nuclear@6: } nuclear@6: if(new_over) { nuclear@6: ev.focus.enter = true; nuclear@6: new_over->handle_event(ev); nuclear@6: } nuclear@6: scr->over = new_over; nuclear@6: } nuclear@6: } nuclear@6: nuclear@6: void Screen::sysev_mouse_motion(float x, float y) nuclear@6: { nuclear@6: Event ev; nuclear@6: Vec2 pt = world_to_scr(scr, Vec2(x, y)); nuclear@6: Widget *new_over = scr->mgrab ? scr->mgrab : find_widget_at(scr, pt); nuclear@6: nuclear@6: // if we're not over the same widget any more send the leave/enter events nuclear@6: if(scr->over != new_over) { nuclear@6: ev.type = EV_MOUSE_FOCUS; nuclear@6: if(scr->over) { nuclear@6: ev.focus.enter = false; nuclear@6: scr->over->handle_event(ev); nuclear@6: } nuclear@6: if(new_over) { nuclear@6: ev.focus.enter = true; nuclear@6: new_over->handle_event(ev); nuclear@6: } nuclear@6: scr->over = new_over; nuclear@6: } nuclear@6: nuclear@6: if(new_over) { nuclear@6: // send motion event nuclear@6: ev.type = EV_MOUSE_MOTION; nuclear@6: ev.motion.pos = pt; nuclear@6: new_over->handle_event(ev); nuclear@6: } nuclear@6: } nuclear@6: nuclear@6: static Vec2 world_to_scr(const ScreenImpl *scr, const Vec2 &v) nuclear@6: { nuclear@6: return Vec2(v.x - scr->box.bmin.x, v.y - scr->box.bmin.y); nuclear@6: } nuclear@6: nuclear@6: /* nuclear@6: static Vec2 scr_to_world(const ScreenImpl *scr, const Vec2 &v) nuclear@6: { nuclear@6: return Vec2(v.x + scr->box.bmin.x, v.y + scr->box.bmin.y); nuclear@6: } nuclear@6: */ nuclear@6: nuclear@6: nuclear@6: } // namespace goatkit