void gui_widget_screen_rect(gui_widget_t* widget, rect_t* rect) { if(rect == NULL) return; rect_t widget_rect; gui_widget_rect(widget, &widget_rect); rect_t parent_rect; gui_object_t* parent = gui_object_parent(GUI_OBJECT(widget)); while(parent){ gui_widget_rect(GUI_WIDGET(parent), &parent_rect); widget_rect.left += parent_rect.left; widget_rect.top += parent_rect.top; widget_rect.right += parent_rect.left; widget_rect.bottom += parent_rect.top; //widget_rect.left = MAX(widget_rect.left, parent_rect.left); //widget_rect.top = MAX(widget_rect.top, parent_rect.top); //widget_rect.right = MIN(widget_rect.right, parent_rect.right); //widget_rect.bottom = MIN(widget_rect.bottom, parent_rect.bottom); parent = gui_object_parent(parent); } rect_copy(rect, &widget_rect); }
err_t gui_widget_begin_paint(gui_widget_t* widget, painter_t* painter, const rect_t* rect) { if(painter == NULL) return E_NULL_POINTER; RETURN_ERR_IF_FAIL(painter_init(painter, gui_graphics(gui_object_gui(GUI_OBJECT(widget))))); point_t widget_point; rect_t widget_rect; gui_widget_screen_visible_position(widget, &widget_point, &widget_rect); rect_t paint_rect; if(rect != NULL){ rect_copy(&paint_rect, rect); rect_clip(&paint_rect, &widget_rect); }else{ rect_copy(&paint_rect, &widget_rect); } painter_set_scissor_rect(painter, &paint_rect); painter_set_scissor_enabled(painter, true); painter_set_offset(painter, point_x(&widget_point), point_y(&widget_point)); painter_set_offset_enabled(painter, true); return E_NO_ERROR; }
void gui_widget_move(gui_widget_t* widget, graphics_pos_t x, graphics_pos_t y) { if(x == gui_widget_x(widget) && y == gui_widget_y(widget)) return; gui_object_t* parent = gui_object_parent(GUI_OBJECT(widget)); if(gui_widget_visible(widget)){ if(parent){ rect_t rect; gui_repaint_event_t event; gui_widget_screen_rect(widget, &rect); rect_set_x(&widget->rect, x); rect_set_y(&widget->rect, y); gui_repaint_event_init_rect(&event, &rect); gui_widget_repaint_event(GUI_WIDGET(parent), &event); } else { rect_set_x(&widget->rect, x); rect_set_y(&widget->rect, y); } gui_widget_repaint(widget, NULL); } else { rect_set_x(&widget->rect, x); rect_set_y(&widget->rect, y); } }
void gui_widget_resize(gui_widget_t* widget, graphics_size_t width, graphics_size_t height) { graphics_size_t old_width = gui_widget_width(widget); graphics_size_t old_height = gui_widget_height(widget); if(old_width == width && old_height == height) return; graphics_size_t paint_width = MAX(width, old_width); graphics_size_t paint_height = MAX(height, old_height); rect_set_width(&widget->rect, width); rect_set_height(&widget->rect, height); gui_resize_event_t event; gui_resize_event_init(&event, width, height); gui_widget_resize_event(widget, &event); gui_object_t* parent = gui_object_parent(GUI_OBJECT(widget)); if(parent){ point_t point; gui_repaint_event_t event; gui_widget_screen_position(widget, &point); gui_repaint_event_init(&event, point.x, point.y, paint_width, paint_height); gui_widget_repaint_event(GUI_WIDGET(parent), &event); } gui_widget_repaint(widget, NULL); }
err_t gui_widget_init_parent(gui_widget_t* widget, gui_t* gui, gui_widget_t* parent) { RETURN_ERR_IF_FAIL(gui_object_init_parent(GUI_OBJECT(widget), gui, GUI_OBJECT(parent))); widget->id = next_widget_id ++; widget->type_id = GUI_WIDGET_TYPE_ID; widget->visible = false; widget->focusable = false; rect_init(&widget->rect); widget->border = GUI_BORDER_NONE; widget->back_color = gui_theme(gui_object_gui(GUI_OBJECT(widget)))->panel_color; widget->on_resize = gui_widget_on_resize; widget->on_repaint = gui_widget_on_repaint; widget->on_key_press = gui_widget_on_key_press; widget->on_key_release = gui_widget_on_key_release; return E_NO_ERROR; }
void gui_object_set_displayed(gui_object_t *obj, int displayed) { obj->displayed = displayed; if (displayed) { gui_object_set_redraw(obj); } else if (obj->parent != NULL) { gui_object_set_redraw(GUI_OBJECT(obj->parent)); } }
void gui_widget_set_visible(gui_widget_t* widget, bool visible) { if(widget->visible == visible) return; widget->visible = visible; if(visible){ gui_widget_repaint(widget, NULL); }else{ gui_object_t* parent = gui_object_parent(GUI_OBJECT(widget)); if(parent){ rect_t rect; gui_widget_screen_rect(widget, &rect); gui_widget_repaint(GUI_WIDGET(parent), &rect); } if(gui_widget_has_focus(widget)){ gui_clear_focus_widget(gui_object_gui(GUI_OBJECT(widget))); } } }
bool gui_widget_visible_parents(gui_widget_t* widget) { if(!gui_widget_visible(widget)) return false; gui_object_t* parent = gui_object_parent(GUI_OBJECT(widget)); while(parent){ if(!gui_widget_visible(GUI_WIDGET(parent))) return false; parent = gui_object_parent(parent); } return true; }
graphics_pos_t gui_widget_screen_y(gui_widget_t* widget) { graphics_pos_t y = gui_widget_y(widget); gui_object_t* parent = gui_object_parent(GUI_OBJECT(widget)); while(parent){ y += gui_widget_y(GUI_WIDGET(parent)); parent = gui_object_parent(parent); } return y; }
graphics_pos_t gui_widget_screen_x(gui_widget_t* widget) { graphics_pos_t x = gui_widget_x(widget); gui_object_t* parent = gui_object_parent(GUI_OBJECT(widget)); while(parent){ x += gui_widget_x(GUI_WIDGET(parent)); parent = gui_object_parent(parent); } return x; }
void gui_widget_repaint_event(gui_widget_t* widget, gui_repaint_event_t* event) { if(!gui_widget_visible_parents(widget)) return; if(gui_widget_width(widget) == 0 || gui_widget_height(widget) == 0) return; rect_t* rect = NULL; if(event) rect = &event->rect; if(widget->on_repaint) widget->on_repaint(widget, rect); list_foreach2_second(&GUI_OBJECT(widget)->childs, gui_wdiget_foreach_childs_repaint, event); }
void gui_widget_screen_position(gui_widget_t* widget, point_t* point) { if(point == NULL) return; point->x = gui_widget_x(widget); point->y = gui_widget_y(widget); gui_object_t* parent = gui_object_parent(GUI_OBJECT(widget)); while(parent){ point->x += gui_widget_x(GUI_WIDGET(parent)); point->y += gui_widget_y(GUI_WIDGET(parent)); parent = gui_object_parent(parent); } }
void gui_widget_screen_visible_position(gui_widget_t* widget, point_t* point, rect_t* rect) { if(point == NULL && rect == NULL) return; point_t widget_point; gui_widget_position(widget, &widget_point); rect_t widget_rect; gui_widget_rect(widget, &widget_rect); rect_t parent_rect; gui_object_t* parent = gui_object_parent(GUI_OBJECT(widget)); while(parent){ gui_widget_rect(GUI_WIDGET(parent), &parent_rect); widget_point.x += rect_x(&parent_rect); widget_point.y += rect_y(&parent_rect); widget_rect.left += parent_rect.left; widget_rect.top += parent_rect.top; widget_rect.right += parent_rect.left; widget_rect.bottom += parent_rect.top; widget_rect.left = MAX(widget_rect.left, parent_rect.left); widget_rect.top = MAX(widget_rect.top, parent_rect.top); widget_rect.right = MIN(widget_rect.right, parent_rect.right); widget_rect.bottom = MIN(widget_rect.bottom, parent_rect.bottom); parent = gui_object_parent(parent); } if(point) point_copy(point, &widget_point); if(rect) rect_copy(rect, &widget_rect); }
void gui_widget_set_focus(gui_widget_t* widget) { gui_set_focus_widget(gui_object_gui(GUI_OBJECT(widget)), widget); }
void gui_container_init(gui_container_t *cont) { gui_object_init(GUI_OBJECT(cont)); cont->set_redraw_child = gui_container_set_redraw_child_default; }
static void gui_container_set_redraw_child_default(gui_container_t *cont, gui_object_t *child) { gui_object_set_redraw(GUI_OBJECT(cont)); }
/* game_loop() has been turned into a SDL based loop. The code for one iteration of the original game_loop is in game_loop_iter. */ static void game_loop() { /* FPS */ int fps = 0; float fps_ema = 0; int fps_target = 25; /* TODO: compute alpha dynamically based on frametime */ const float ema_alpha = 0.07; const int frametime_target = 1000 / fps_target; /* in milliseconds */ int last_frame = SDL_GetTicks(); int drag_button = 0; unsigned int last_down[3] = {0}; unsigned int last_click[3] = {0}; unsigned int current_ticks = SDL_GetTicks(); unsigned int accum = 0; SDL_Event event; gui_event_t ev; game_loop_run = 1; while (game_loop_run) { while (SDL_PollEvent(&event)) { switch (event.type) { case SDL_MOUSEBUTTONUP: if (drag_button == event.button.button) { ev.type = GUI_EVENT_TYPE_DRAG_END; ev.x = event.button.x; ev.y = event.button.y; ev.button = drag_button; gui_object_handle_event((gui_object_t *)&interface, &ev); drag_button = 0; } ev.type = GUI_EVENT_TYPE_BUTTON_UP; ev.x = event.button.x; ev.y = event.button.y; ev.button = event.button.button; gui_object_handle_event((gui_object_t *)&interface, &ev); if (event.button.button <= 3 && current_ticks - last_down[event.button.button-1] < MOUSE_SENSITIVITY) { ev.type = GUI_EVENT_TYPE_CLICK; ev.x = event.button.x; ev.y = event.button.y; ev.button = event.button.button; gui_object_handle_event((gui_object_t *)&interface, &ev); if (current_ticks - last_click[event.button.button-1] < MOUSE_SENSITIVITY) { ev.type = GUI_EVENT_TYPE_DBL_CLICK; ev.x = event.button.x; ev.y = event.button.y; ev.button = event.button.button; gui_object_handle_event((gui_object_t *)&interface, &ev); } last_click[event.button.button-1] = current_ticks; } break; case SDL_MOUSEBUTTONDOWN: ev.type = GUI_EVENT_TYPE_BUTTON_DOWN; ev.x = event.button.x; ev.y = event.button.y; ev.button = event.button.button; gui_object_handle_event((gui_object_t *)&interface, &ev); if (event.button.button <= 3) last_down[event.button.button-1] = current_ticks; break; case SDL_MOUSEMOTION: if (drag_button == 0) { /* Move pointer normally. */ interface_set_cursor(&interface, event.motion.x, event.motion.y); } for (int button = 1; button <= 3; button++) { if (event.motion.state & SDL_BUTTON(button)) { if (drag_button == 0) { drag_button = button; ev.type = GUI_EVENT_TYPE_DRAG_START; ev.x = event.motion.x; ev.y = event.motion.y; ev.button = drag_button; gui_object_handle_event((gui_object_t *)&interface, &ev); } ev.type = GUI_EVENT_TYPE_DRAG_MOVE; ev.x = event.motion.x; ev.y = event.motion.y; ev.button = drag_button; gui_object_handle_event((gui_object_t *)&interface, &ev); break; } } break; case SDL_KEYDOWN: if (event.key.keysym.sym == SDLK_q && (event.key.keysym.mod & KMOD_CTRL)) { game_loop_quit(); break; } switch (event.key.keysym.sym) { /* Map scroll */ case SDLK_UP: { viewport_t *viewport = interface_get_top_viewport(&interface); viewport_move_by_pixels(viewport, 0, -1); } break; case SDLK_DOWN: { viewport_t *viewport = interface_get_top_viewport(&interface); viewport_move_by_pixels(viewport, 0, 1); } break; case SDLK_LEFT: { viewport_t *viewport = interface_get_top_viewport(&interface); viewport_move_by_pixels(viewport, -1, 0); } break; case SDLK_RIGHT: { viewport_t *viewport = interface_get_top_viewport(&interface); viewport_move_by_pixels(viewport, 1, 0); } break; /* Panel click shortcuts */ case SDLK_1: { panel_bar_t *panel = interface_get_panel_bar(&interface); panel_bar_activate_button(panel, 0); } break; case SDLK_2: { panel_bar_t *panel = interface_get_panel_bar(&interface); panel_bar_activate_button(panel, 1); } break; case SDLK_3: { panel_bar_t *panel = interface_get_panel_bar(&interface); panel_bar_activate_button(panel, 2); } break; case SDLK_4: { panel_bar_t *panel = interface_get_panel_bar(&interface); panel_bar_activate_button(panel, 3); } break; case SDLK_5: { panel_bar_t *panel = interface_get_panel_bar(&interface); panel_bar_activate_button(panel, 4); } break; case SDLK_TAB: if (event.key.keysym.mod & KMOD_SHIFT) { interface_return_from_message(&interface); } else { interface_open_message(&interface); } break; /* Game speed */ case SDLK_PLUS: case SDLK_KP_PLUS: if (game.game_speed < 40) game.game_speed += 1; LOGI("main", "Game speed: %u", game.game_speed); break; case SDLK_MINUS: case SDLK_KP_MINUS: if (game.game_speed >= 1) game.game_speed -= 1; LOGI("main", "Game speed: %u", game.game_speed); break; case SDLK_0: game.game_speed = DEFAULT_GAME_SPEED; LOGI("main", "Game speed: %u", game.game_speed); break; case SDLK_p: if (game.game_speed == 0) game_pause(0); else game_pause(1); break; /* Audio */ case SDLK_s: sfx_enable(!sfx_is_enabled()); break; case SDLK_m: midi_enable(!midi_is_enabled()); break; /* Video */ case SDLK_f: if (event.key.keysym.mod & KMOD_CTRL) { sdl_set_fullscreen(!sdl_is_fullscreen()); } break; /* Misc */ case SDLK_ESCAPE: if (GUI_OBJECT(&interface.popup)->displayed) { interface_close_popup(&interface); } else if (interface.building_road) { interface_build_road_end(&interface); } break; /* Debug */ case SDLK_g: interface.viewport.layers ^= VIEWPORT_LAYER_GRID; break; case SDLK_b: interface.viewport.show_possible_build = !interface.viewport.show_possible_build; break; case SDLK_j: { int current = 0; for (int i = 0; i < 4; i++) { if (interface.player == game.player[i]) { current = i; break; } } for (int i = (current+1) % 4; i != current; i = (i+1) % 4) { if (PLAYER_IS_ACTIVE(game.player[i])) { interface.player = game.player[i]; LOGD("main", "Switched to player %i.", i); break; } } } break; case SDLK_z: if (event.key.keysym.mod & KMOD_CTRL) { save_game(0); } break; case SDLK_F10: interface_open_game_init(&interface); break; default: break; } break; case SDL_VIDEORESIZE: sdl_set_resolution(event.resize.w, event.resize.h, 0); frame_t *screen = sdl_get_screen_frame(); int width = sdl_frame_get_width(screen); int height = sdl_frame_get_height(screen); screen_frame.clip.w = width; screen_frame.clip.h = height; gui_object_set_size((gui_object_t *)&interface, width, height); break; case SDL_QUIT: game_loop_quit(); break; } } unsigned int new_ticks = SDL_GetTicks(); int delta_ticks = new_ticks - current_ticks; current_ticks = new_ticks; /* Update FPS EMA per frame */ fps = 1000*(1.0 / (float)delta_ticks); if (fps_ema > 0) fps_ema = ema_alpha*fps + (1-ema_alpha)*fps_ema; else if (fps > 0) fps_ema = fps; accum += delta_ticks; while (accum >= TICK_LENGTH) { game_update(); /* Autosave periodically */ if ((game.const_tick % AUTOSAVE_INTERVAL) == 0 && game.game_speed > 0) { int r = save_game(1); if (r < 0) LOGW("main", "Autosave failed."); } /* Print FPS */ if ((game.const_tick % (10*TICKS_PER_SEC)) == 0) { LOGV("main", "FPS: %i", (int)fps_ema); } accum -= TICK_LENGTH; } /* Update and draw interface */ interface_update(&interface); gui_object_redraw(GUI_OBJECT(&interface), game.frame); /* TODO very crude dirty marking algortihm: mark everything. */ sdl_mark_dirty(0, 0, sdl_frame_get_width(game.frame), sdl_frame_get_height(game.frame)); /* Swap video buffers */ sdl_swap_buffers(); /* Reduce framerate to target if we finished too fast */ int now = SDL_GetTicks(); int frametime_spent = now - last_frame; if (frametime_spent < frametime_target) { SDL_Delay(frametime_target - frametime_spent); } last_frame = SDL_GetTicks(); } }