struct widget * widget_new_list(struct widget * parent, int x, int y, int width, int height, struct stack * items) { struct widget * rv; int scrollbar_width; int visible_items; { struct widget * tmp; tmp = widget_new_button(widget_root(), 0, 0, "x"); visible_items = (height - 2) / widget_height(tmp); widget_delete(tmp); int item_count; item_count = 0; for(unsigned int i = 0; i < items->size; i++) if(items->data[i] != NULL) item_count++; if(item_count <= visible_items) scrollbar_width = 0; else scrollbar_width = 20; } rv = widget_new_child(parent, x, y, width, height); widget_set_ulong(rv, "type", WT_LIST); struct stack * itemobjs; itemobjs = stack_new(); widget_set_pointer(rv, "items", 'P', itemobjs); struct widget * container, * frame; container = widget_new_child(rv, 0, 0, width - scrollbar_width, height); widget_add_flags(container, WF_CLIPPING); frame = widget_new_frame(container, 0, 0, width - scrollbar_width, height); frame->z_ = rv->z_; widget_delete_flags(frame, WF_CAST_SHADOW | WF_DRAW_BORDERS | WF_BACKGROUND); struct widget * prev; y = 0; prev = NULL; for(unsigned int i = 0; i < items->size; i++) if(items->data[i] != NULL) { struct widget * obj; obj = widget_new_button(frame, 0, y, items->data[i]); stack_push(itemobjs, obj); widget_delete_flags(obj, WF_DRAW_BORDERS | WF_ALIGN_CENTER); widget_set_ulong(obj, "alpha", 0x80); widget_set_width(obj, widget_width(frame)); widget_set_ulong(obj, "value", i); widget_set_widget_pointer(obj, "list_object", rv); widget_set_on_release(obj, on_item_release); widget_set_on_focus(obj, on_item_focus); y += widget_height(obj); if(prev != NULL) widget_set_navigation_updown(prev, obj); prev = obj; } widget_set_height(frame, y); widget_set_widget_pointer(rv, "focus_down_object", prev); if(scrollbar_width > 0) { struct widget * scrollbar, * scrollbar_button; int bheight; scrollbar = widget_new_frame(rv, width - scrollbar_width, 0, scrollbar_width, height); scrollbar->z_ = rv->z_; widget_delete_flags(scrollbar, WF_CAST_SHADOW); widget_set_on_activate_at(scrollbar, on_scrollbar_clicked); widget_set_enabled(scrollbar, true); widget_add_flags(scrollbar, WF_FOCUSABLE); scrollbar_button = widget_new_button(scrollbar, 1, 1, NULL); widget_set_width(scrollbar_button, scrollbar_width - 2); bheight = 0; if(items->size > 0) bheight += (height - 2) * visible_items / items->size; if(bheight > height - 2) bheight = height - 2; widget_set_height(scrollbar_button, bheight); widget_set_on_activate_at(scrollbar_button, on_scrollbar_button_clicked); widget_set_widget_pointer(scrollbar_button, "frame", frame); widget_set_widget_pointer(scrollbar, "scrollbar_button", scrollbar_button); widget_set_widget_pointer(rv, "scrollbar_button", scrollbar_button); } return rv; }
void TileViewer_Update(t_app_tile_viewer *app) { ALLEGRO_BITMAP *bmp = app->box->gfx_buffer; // Skip update if not active if (!app->active) return; // If skin has changed, redraw everything if (app->box->flags & GUI_BOX_FLAGS_DIRTY_REDRAW_ALL_LAYOUT) { TileViewer_Layout(app, FALSE); app->box->flags &= ~GUI_BOX_FLAGS_DIRTY_REDRAW_ALL_LAYOUT; app->dirty = TRUE; } bool dirty_all = app->dirty || Palette_EmulationDirtyAny; bool dirty = dirty_all; // Update hovered tile index { const int mx = app->tiles_display_zone->mouse_x; const int my = app->tiles_display_zone->mouse_y; // Msg(MSGT_USER, "mx = %d, my = %d", mx, my); if (app->tiles_display_zone->mouse_action & WIDGET_MOUSE_ACTION_HOVER) app->tile_hovered = ((my / 8) * 16) + mx / 8; else app->tile_hovered = -1; } // Compute the tile that is to display in the bottom info line int tile_current = (app->tile_hovered != -1) ? app->tile_hovered : app->tile_selected; bool tile_current_refresh = /*(tile_current == -1) ? FALSE : */ (((tile_current != app->tile_displayed) || dirty_all || tgfx.Tile_Dirty [tile_current])); int tile_current_addr = -1; const v2i tiles_frame_pos = app->tiles_display_frame.pos; const v2i tile_selected_pos = v2i(app->tile_selected_frame.pos.x + 2, app->tile_selected_frame.pos.y + 2); int vram_addr_min = 0x0000; int vram_addr_size = 0; int vram_tile_size = 1; // Then redraw all tiles ALLEGRO_LOCKED_REGION* locked_region = al_lock_bitmap(app->box->gfx_buffer, ALLEGRO_PIXEL_FORMAT_ANY, ALLEGRO_LOCK_READWRITE); switch (g_driver->vdp) { case VDP_SMSGG: { widget_set_enabled(app->vram_addr_tms9918_scrollbar, false); vram_addr_min = 0; vram_addr_size = 0x4000; vram_tile_size = 32; int n = 0; const u8 * nd = &tgfx.Tile_Decoded[0][0]; const u32 * palette_host = app->palette ? &Palette_EmulationToHostGui[16] : &Palette_EmulationToHostGui[0]; for (int y = 0; y != app->tiles_height; y++) { for (int x = 0; x != app->tiles_width; x++) { if (tgfx.Tile_Dirty [n] & TILE_DIRTY_DECODE) Decode_Tile (n); if (dirty_all || tgfx.Tile_Dirty [n]) { VDP_Mode4_DrawTile(app->box->gfx_buffer, locked_region, nd, palette_host, tiles_frame_pos.x+(x * 8), tiles_frame_pos.y+(y * 8), 0); tgfx.Tile_Dirty [n] = 0; dirty = TRUE; } if (n == tile_current) { tile_current_addr = vram_addr_min + (n * 32); VDP_Mode4_DrawTile(app->box->gfx_buffer, locked_region, nd, palette_host, tile_selected_pos.x, tile_selected_pos.y, 0); } n ++; nd += 64; } } break; } case VDP_TMS9918: { widget_set_enabled(app->vram_addr_tms9918_scrollbar, true); vram_addr_min = 0x0000 + app->vram_addr_tms9918_current*0x1000; vram_addr_size = 0x1000; vram_tile_size = 8; const int fg_color = Palette_EmulationToHostGui[app->palette + 1]; const int bg_color = Palette_EmulationToHostGui[(app->palette != 0) ? 1 : 15]; const u8 * addr = VRAM + vram_addr_min; //VRAM = g_machine.VDP.sg_pattern_gen_address; // addr = &VRAM[apps.opt.Tiles_Base]; int n = 0; for (int y = 0; y != app->tiles_height; y ++) { for (int x = 0; x != app->tiles_width; x ++) { if ((addr - VRAM) > 0x4000) break; VDP_Mode0123_DrawTile(bmp, locked_region, tiles_frame_pos.x+(x * 8), tiles_frame_pos.y+(y * 8), addr, fg_color, bg_color); if (n == tile_current) { tile_current_addr = vram_addr_min + (n * 8); VDP_Mode0123_DrawTile(bmp, locked_region, tile_selected_pos.x, tile_selected_pos.y, addr, fg_color, bg_color); } n++; addr += 8; } } dirty = TRUE; // to be replaced later break; } } al_unlock_bitmap(app->box->gfx_buffer); // Refresh top status line (address range) al_set_target_bitmap(bmp); { // FIXME-OPT const int y = -1; al_draw_filled_rectangle(0, y + 1, app->vram_addr_tms9918_scrollbar->enabled ? app->vram_addr_tms9918_scrollbar->frame.pos.x-1 : 128-1, y + 11+1, COLOR_SKIN_WINDOW_BACKGROUND); char buf[64]; sprintf(buf, "Range: $%04X-$%04X", vram_addr_min, vram_addr_min+vram_addr_size-1); Font_Print(FONTID_SMALL, buf, 0, y + 1, COLOR_SKIN_WINDOW_TEXT); dirty = true; } // Refresh bottom status line (selected tile) if (dirty_all || tile_current_refresh) { const int y = app->tiles_display_frame.GetMax().y; al_draw_filled_rectangle(16, y + 1, 127+1, y + 11+1, COLOR_SKIN_WINDOW_BACKGROUND); dirty = TRUE; if (tile_current != -1) { // Description char addr[16]; if (tile_current_addr != -1) sprintf(addr, "$%04X", tile_current_addr); else sprintf(addr, "????"); char buf[128]; const int tile_index = tile_current_addr / vram_tile_size; sprintf(buf, Msg_Get(MSG_TilesViewer_Tile), tile_index, tile_index, addr); Font_Print(FONTID_SMALL, buf, 16, y + 1, COLOR_SKIN_WINDOW_TEXT); app->tile_displayed = tile_current; } else { // Fill tile with black const t_frame* fr = &app->tile_selected_frame; al_draw_filled_rectangle(fr->pos.x+2, fr->pos.y+2, fr->pos.x+2+8, fr->pos.y+2+8, COLOR_BLACK); } } if (dirty_all || dirty) app->dirty = FALSE; }