mirror of
https://github.com/RPCS3/rpcs3.git
synced 2024-11-22 18:53:28 +01:00
overlays: move some code to cpp files
This commit is contained in:
parent
4037225e98
commit
32bdd8ef7b
@ -129,289 +129,15 @@ namespace rsx
|
||||
std::vector<u8> glyph_data;
|
||||
bool initialized = false;
|
||||
|
||||
font(const char *ttf_name, f32 size)
|
||||
{
|
||||
// Init glyph
|
||||
std::vector<u8> bytes;
|
||||
std::vector<std::string> font_dirs;
|
||||
std::vector<std::string> fallback_fonts;
|
||||
#ifdef _WIN32
|
||||
font_dirs.push_back("C:/Windows/Fonts/");
|
||||
fallback_fonts.push_back("C:/Windows/Fonts/Arial.ttf");
|
||||
#else
|
||||
char *home = getenv("HOME");
|
||||
if (home == nullptr)
|
||||
home = getpwuid(getuid())->pw_dir;
|
||||
font(const char* ttf_name, f32 size);
|
||||
|
||||
font_dirs.push_back(home);
|
||||
if (home[font_dirs[0].length() - 1] == '/')
|
||||
font_dirs[0] += ".fonts/";
|
||||
else
|
||||
font_dirs[0] += "/.fonts/";
|
||||
stbtt_aligned_quad get_char(char c, f32& x_advance, f32& y_advance);
|
||||
|
||||
fallback_fonts.push_back("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf"); //ubuntu
|
||||
fallback_fonts.push_back("/usr/share/fonts/TTF/DejaVuSans.ttf"); //arch
|
||||
#endif
|
||||
// Search dev_flash for the font too
|
||||
font_dirs.push_back(g_cfg.vfs.get_dev_flash() + "data/font/");
|
||||
font_dirs.push_back(g_cfg.vfs.get_dev_flash() + "data/font/SONY-CC/");
|
||||
void render_text_ex(std::vector<vertex>& result, f32& x_advance, f32& y_advance, const char* text, u32 char_limit, u16 max_width, bool wrap);
|
||||
|
||||
// Attempt to load a font from dev_flash as a last resort
|
||||
fallback_fonts.push_back(g_cfg.vfs.get_dev_flash() + "data/font/SCE-PS3-VR-R-LATIN.TTF");
|
||||
std::vector<vertex> render_text(const char* text, u16 max_width = UINT16_MAX, bool wrap = false);
|
||||
|
||||
// Attemt to load requested font
|
||||
std::string file_path;
|
||||
bool font_found = false;
|
||||
for (auto& font_dir : font_dirs)
|
||||
{
|
||||
std::string requested_file = font_dir + ttf_name;
|
||||
|
||||
// Append ".ttf" if not present
|
||||
std::string font_lower(requested_file);
|
||||
|
||||
std::transform(requested_file.begin(), requested_file.end(), font_lower.begin(), ::tolower);
|
||||
if (font_lower.substr(font_lower.size() - 4) != ".ttf")
|
||||
requested_file += ".ttf";
|
||||
|
||||
file_path = requested_file;
|
||||
|
||||
if (fs::is_file(requested_file))
|
||||
{
|
||||
font_found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Attemt to load a fallback if request font wasn't found
|
||||
if (!font_found)
|
||||
{
|
||||
for (auto &fallback_font : fallback_fonts)
|
||||
{
|
||||
if (fs::is_file(fallback_font))
|
||||
{
|
||||
file_path = fallback_font;
|
||||
font_found = true;
|
||||
|
||||
LOG_NOTICE(RSX, "Found font file '%s' as a replacement for '%s'", fallback_font.c_str(), ttf_name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Read font
|
||||
if (font_found)
|
||||
{
|
||||
fs::file f(file_path);
|
||||
f.read(bytes, f.size());
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_ERROR(RSX, "Failed to initialize font '%s.ttf'", ttf_name);
|
||||
return;
|
||||
}
|
||||
|
||||
glyph_data.resize(width * height);
|
||||
pack_info.resize(256);
|
||||
|
||||
stbtt_pack_context context;
|
||||
if (!stbtt_PackBegin(&context, glyph_data.data(), width, height, 0, 1, nullptr))
|
||||
{
|
||||
LOG_ERROR(RSX, "Font packing failed");
|
||||
return;
|
||||
}
|
||||
|
||||
stbtt_PackSetOversampling(&context, oversample, oversample);
|
||||
|
||||
// Convert pt to px
|
||||
size_px = ceilf((f32)size * 96.f / 72.f);
|
||||
size_pt = size;
|
||||
|
||||
if (!stbtt_PackFontRange(&context, bytes.data(), 0, size_px, 0, 256, pack_info.data()))
|
||||
{
|
||||
LOG_ERROR(RSX, "Font packing failed");
|
||||
stbtt_PackEnd(&context);
|
||||
return;
|
||||
}
|
||||
|
||||
stbtt_PackEnd(&context);
|
||||
|
||||
font_name = ttf_name;
|
||||
initialized = true;
|
||||
|
||||
f32 unused;
|
||||
get_char('m', em_size, unused);
|
||||
}
|
||||
|
||||
stbtt_aligned_quad get_char(char c, f32 &x_advance, f32 &y_advance)
|
||||
{
|
||||
if (!initialized)
|
||||
return{};
|
||||
|
||||
stbtt_aligned_quad quad;
|
||||
stbtt_GetPackedQuad(pack_info.data(), width, height, u8(c), &x_advance, &y_advance, &quad, false);
|
||||
return quad;
|
||||
}
|
||||
|
||||
void render_text_ex(std::vector<vertex>& result, f32& x_advance, f32& y_advance, const char* text, u32 char_limit, u16 max_width, bool wrap)
|
||||
{
|
||||
x_advance = 0.f;
|
||||
y_advance = 0.f;
|
||||
result.clear();
|
||||
|
||||
if (!initialized)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
u32 i = 0u;
|
||||
bool skip_whitespace = false;
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (char c = text[i++]; c && (i <= char_limit))
|
||||
{
|
||||
if (u8(c) >= char_count)
|
||||
{
|
||||
// Unsupported glyph, render null for now
|
||||
c = ' ';
|
||||
c = ' ';
|
||||
}
|
||||
|
||||
switch (c)
|
||||
{
|
||||
case '\n':
|
||||
{
|
||||
y_advance += size_px + 2.f;
|
||||
x_advance = 0.f;
|
||||
continue;
|
||||
}
|
||||
case '\r':
|
||||
{
|
||||
x_advance = 0.f;
|
||||
continue;
|
||||
}
|
||||
default:
|
||||
{
|
||||
stbtt_aligned_quad quad;
|
||||
if (skip_whitespace && text[i - 1] == ' ')
|
||||
{
|
||||
quad = {};
|
||||
}
|
||||
else
|
||||
{
|
||||
quad = get_char(c, x_advance, y_advance);
|
||||
skip_whitespace = false;
|
||||
}
|
||||
|
||||
if (quad.x1 > max_width)
|
||||
{
|
||||
bool wrapped = false;
|
||||
bool non_whitespace_break = false;
|
||||
|
||||
if (wrap)
|
||||
{
|
||||
// scan previous chars
|
||||
for (int j = i - 1, nb_chars = 0; j > 0; j--, nb_chars++)
|
||||
{
|
||||
if (text[j] == '\n')
|
||||
break;
|
||||
|
||||
if (text[j] == ' ')
|
||||
{
|
||||
non_whitespace_break = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (non_whitespace_break)
|
||||
{
|
||||
if (nb_chars > 1)
|
||||
{
|
||||
nb_chars--;
|
||||
|
||||
auto first_affected = result.size() - (nb_chars * 4);
|
||||
f32 base_x = result[first_affected].values[0];
|
||||
|
||||
for (size_t n = first_affected; n < result.size(); ++n)
|
||||
{
|
||||
auto char_index = n / 4;
|
||||
if (text[char_index] == ' ')
|
||||
{
|
||||
// Skip character
|
||||
result[n++].vec2(0.f, 0.f);
|
||||
result[n++].vec2(0.f, 0.f);
|
||||
result[n++].vec2(0.f, 0.f);
|
||||
result[n].vec2(0.f, 0.f);
|
||||
continue;
|
||||
}
|
||||
|
||||
result[n].values[0] -= base_x;
|
||||
result[n].values[1] += size_px + 2.f;
|
||||
}
|
||||
|
||||
x_advance = result.back().values[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
x_advance = 0.f;
|
||||
}
|
||||
|
||||
wrapped = true;
|
||||
y_advance += size_px + 2.f;
|
||||
|
||||
if (text[i - 1] == ' ')
|
||||
{
|
||||
quad = {};
|
||||
skip_whitespace = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
quad = get_char(c, x_advance, y_advance);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!wrapped)
|
||||
{
|
||||
// TODO: Ellipsize
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
result.push_back({ quad.x0, quad.y0, quad.s0, quad.t0 });
|
||||
result.push_back({ quad.x1, quad.y0, quad.s1, quad.t0 });
|
||||
result.push_back({ quad.x0, quad.y1, quad.s0, quad.t1 });
|
||||
result.push_back({ quad.x1, quad.y1, quad.s1, quad.t1 });
|
||||
break;
|
||||
}
|
||||
} // switch
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<vertex> render_text(const char *text, u16 max_width = UINT16_MAX, bool wrap = false)
|
||||
{
|
||||
std::vector<vertex> result;
|
||||
f32 unused_x, unused_y;
|
||||
|
||||
render_text_ex(result, unused_x, unused_y, text, UINT32_MAX, max_width, wrap);
|
||||
return result;
|
||||
}
|
||||
|
||||
std::pair<f32, f32> get_char_offset(const char *text, u16 max_length, u16 max_width = UINT16_MAX, bool wrap = false)
|
||||
{
|
||||
std::vector<vertex> unused;
|
||||
f32 loc_x, loc_y;
|
||||
|
||||
render_text_ex(unused, loc_x, loc_y, text, max_length, max_width, wrap);
|
||||
return { loc_x, loc_y };
|
||||
}
|
||||
std::pair<f32, f32> get_char_offset(const char* text, u16 max_length, u16 max_width = UINT16_MAX, bool wrap = false);
|
||||
};
|
||||
|
||||
// TODO: Singletons are cancer
|
||||
@ -1417,99 +1143,18 @@ namespace rsx
|
||||
f32 m_value = 0.f;
|
||||
|
||||
public:
|
||||
progress_bar()
|
||||
{
|
||||
text_view.back_color = { 0.f, 0.f, 0.f, 0.f };
|
||||
}
|
||||
progress_bar();
|
||||
void inc(f32 value);
|
||||
void dec(f32 value);
|
||||
void set_limit(f32 limit);
|
||||
void set_value(f32 value);
|
||||
void set_pos(u16 _x, u16 _y) override;
|
||||
void set_size(u16 _w, u16 _h) override;
|
||||
void translate(s16 dx, s16 dy) override;
|
||||
void set_text(const char* str) override;
|
||||
void set_text(const std::string& str) override;
|
||||
|
||||
void inc(f32 value)
|
||||
{
|
||||
set_value(m_value + value);
|
||||
}
|
||||
|
||||
void dec(f32 value)
|
||||
{
|
||||
set_value(m_value - value);
|
||||
}
|
||||
|
||||
void set_limit(f32 limit)
|
||||
{
|
||||
m_limit = limit;
|
||||
is_compiled = false;
|
||||
}
|
||||
|
||||
void set_value(f32 value)
|
||||
{
|
||||
m_value = std::clamp(value, 0.f, m_limit);
|
||||
|
||||
f32 indicator_width = (w * m_value) / m_limit;
|
||||
indicator.set_size((u16)indicator_width, h);
|
||||
is_compiled = false;
|
||||
}
|
||||
|
||||
void set_pos(u16 _x, u16 _y) override
|
||||
{
|
||||
u16 text_w, text_h;
|
||||
text_view.measure_text(text_w, text_h);
|
||||
text_h += 13;
|
||||
|
||||
overlay_element::set_pos(_x, _y + text_h);
|
||||
indicator.set_pos(_x, _y + text_h);
|
||||
text_view.set_pos(_x, _y);
|
||||
}
|
||||
|
||||
void set_size(u16 _w, u16 _h) override
|
||||
{
|
||||
overlay_element::set_size(_w, _h);
|
||||
text_view.set_size(_w, text_view.h);
|
||||
set_value(m_value);
|
||||
}
|
||||
|
||||
void translate(s16 dx, s16 dy) override
|
||||
{
|
||||
set_pos(x + dx, y + dy);
|
||||
}
|
||||
|
||||
void set_text(const char* str) override
|
||||
{
|
||||
text_view.set_text(str);
|
||||
text_view.align_text(text_align::center);
|
||||
|
||||
u16 text_w, text_h;
|
||||
text_view.measure_text(text_w, text_h);
|
||||
text_view.set_size(w, text_h);
|
||||
|
||||
set_pos(text_view.x, text_view.y);
|
||||
is_compiled = false;
|
||||
}
|
||||
|
||||
void set_text(const std::string& str) override
|
||||
{
|
||||
text_view.set_text(str);
|
||||
text_view.align_text(text_align::center);
|
||||
|
||||
u16 text_w, text_h;
|
||||
text_view.measure_text(text_w, text_h);
|
||||
text_view.set_size(w, text_h);
|
||||
|
||||
set_pos(text_view.x, text_view.y);
|
||||
is_compiled = false;
|
||||
}
|
||||
|
||||
compiled_resource& get_compiled() override
|
||||
{
|
||||
if (!is_compiled)
|
||||
{
|
||||
auto& compiled = overlay_element::get_compiled();
|
||||
compiled.add(text_view.get_compiled());
|
||||
|
||||
indicator.back_color = fore_color;
|
||||
indicator.refresh();
|
||||
compiled.add(indicator.get_compiled());
|
||||
}
|
||||
|
||||
return compiled_resources;
|
||||
}
|
||||
compiled_resource& get_compiled() override;
|
||||
};
|
||||
|
||||
struct list_view : public vertical_layout
|
||||
@ -1528,181 +1173,23 @@ namespace rsx
|
||||
bool m_cancel_only = false;
|
||||
|
||||
public:
|
||||
list_view(u16 width, u16 height)
|
||||
{
|
||||
w = width;
|
||||
h = height;
|
||||
list_view(u16 width, u16 height);
|
||||
|
||||
m_scroll_indicator_top = std::make_unique<image_view>(width, 5);
|
||||
m_scroll_indicator_bottom = std::make_unique<image_view>(width, 5);
|
||||
m_accept_btn = std::make_unique<image_button>(120, 20);
|
||||
m_cancel_btn = std::make_unique<image_button>(120, 20);
|
||||
m_highlight_box = std::make_unique<overlay_element>(width, 0);
|
||||
void update_selection();
|
||||
|
||||
m_scroll_indicator_top->set_size(width, 40);
|
||||
m_scroll_indicator_bottom->set_size(width, 40);
|
||||
m_accept_btn->set_size(120, 30);
|
||||
m_cancel_btn->set_size(120, 30);
|
||||
void select_next();
|
||||
void select_previous();
|
||||
|
||||
m_scroll_indicator_top->set_image_resource(resource_config::standard_image_resource::fade_top);
|
||||
m_scroll_indicator_bottom->set_image_resource(resource_config::standard_image_resource::fade_bottom);
|
||||
void add_entry(std::unique_ptr<overlay_element>& entry);
|
||||
|
||||
if (g_cfg.sys.enter_button_assignment == enter_button_assign::circle)
|
||||
{
|
||||
m_accept_btn->set_image_resource(resource_config::standard_image_resource::circle);
|
||||
m_cancel_btn->set_image_resource(resource_config::standard_image_resource::cross);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_accept_btn->set_image_resource(resource_config::standard_image_resource::cross);
|
||||
m_cancel_btn->set_image_resource(resource_config::standard_image_resource::circle);
|
||||
}
|
||||
int get_selected_index();
|
||||
|
||||
m_scroll_indicator_bottom->set_pos(0, height - 40);
|
||||
m_accept_btn->set_pos(30, height + 20);
|
||||
m_cancel_btn->set_pos(180, height + 20);
|
||||
std::string get_selected_item();
|
||||
|
||||
m_accept_btn->set_text("Select");
|
||||
m_cancel_btn->set_text("Cancel");
|
||||
void set_cancel_only(bool cancel_only);
|
||||
void translate(s16 _x, s16 _y) override;
|
||||
|
||||
m_accept_btn->set_font("Arial", 16);
|
||||
m_cancel_btn->set_font("Arial", 16);
|
||||
|
||||
auto_resize = false;
|
||||
back_color = { 0.15f, 0.15f, 0.15f, 0.8f };
|
||||
|
||||
m_highlight_box->back_color = { .5f, .5f, .8f, 0.2f };
|
||||
m_highlight_box->pulse_effect_enabled = true;
|
||||
m_scroll_indicator_top->fore_color.a = 0.f;
|
||||
m_scroll_indicator_bottom->fore_color.a = 0.f;
|
||||
}
|
||||
|
||||
void update_selection()
|
||||
{
|
||||
auto current_element = m_items[m_selected_entry * 2].get();
|
||||
|
||||
// Calculate bounds
|
||||
auto min_y = current_element->y - y;
|
||||
auto max_y = current_element->y + current_element->h + pack_padding + 2 - y;
|
||||
|
||||
if (min_y < scroll_offset_value)
|
||||
{
|
||||
scroll_offset_value = min_y;
|
||||
}
|
||||
else if (max_y > (h + scroll_offset_value))
|
||||
{
|
||||
scroll_offset_value = max_y - h - 2;
|
||||
}
|
||||
|
||||
if ((scroll_offset_value + h + 2) >= m_elements_height)
|
||||
m_scroll_indicator_bottom->fore_color.a = 0.f;
|
||||
else
|
||||
m_scroll_indicator_bottom->fore_color.a = 0.5f;
|
||||
|
||||
if (scroll_offset_value == 0)
|
||||
m_scroll_indicator_top->fore_color.a = 0.f;
|
||||
else
|
||||
m_scroll_indicator_top->fore_color.a = 0.5f;
|
||||
|
||||
m_highlight_box->set_pos(current_element->x, current_element->y);
|
||||
m_highlight_box->h = current_element->h + pack_padding;
|
||||
m_highlight_box->y -= scroll_offset_value;
|
||||
|
||||
m_highlight_box->refresh();
|
||||
m_scroll_indicator_top->refresh();
|
||||
m_scroll_indicator_bottom->refresh();
|
||||
refresh();
|
||||
}
|
||||
|
||||
void select_next()
|
||||
{
|
||||
if (m_selected_entry < (m_elements_count - 1))
|
||||
{
|
||||
m_selected_entry++;
|
||||
update_selection();
|
||||
}
|
||||
}
|
||||
|
||||
void select_previous()
|
||||
{
|
||||
if (m_selected_entry > 0)
|
||||
{
|
||||
m_selected_entry--;
|
||||
update_selection();
|
||||
}
|
||||
}
|
||||
|
||||
void add_entry(std::unique_ptr<overlay_element>& entry)
|
||||
{
|
||||
// Add entry view
|
||||
add_element(entry);
|
||||
m_elements_count++;
|
||||
|
||||
// Add separator
|
||||
auto separator = std::make_unique<overlay_element>();
|
||||
separator->back_color = fore_color;
|
||||
separator->w = w;
|
||||
separator->h = 2;
|
||||
add_element(separator);
|
||||
|
||||
if (m_selected_entry < 0)
|
||||
m_selected_entry = 0;
|
||||
|
||||
m_elements_height = advance_pos;
|
||||
update_selection();
|
||||
}
|
||||
|
||||
int get_selected_index()
|
||||
{
|
||||
return m_selected_entry;
|
||||
}
|
||||
|
||||
std::string get_selected_item()
|
||||
{
|
||||
if (m_selected_entry < 0)
|
||||
return{};
|
||||
|
||||
return m_items[m_selected_entry]->text;
|
||||
}
|
||||
|
||||
void set_cancel_only(bool cancel_only)
|
||||
{
|
||||
if (cancel_only)
|
||||
m_cancel_btn->set_pos(x + 30, y + h + 20);
|
||||
else
|
||||
m_cancel_btn->set_pos(x + 180, y + h + 20);
|
||||
|
||||
m_cancel_only = cancel_only;
|
||||
is_compiled = false;
|
||||
}
|
||||
|
||||
void translate(s16 _x, s16 _y) override
|
||||
{
|
||||
layout_container::translate(_x, _y);
|
||||
m_scroll_indicator_top->translate(_x, _y);
|
||||
m_scroll_indicator_bottom->translate(_x, _y);
|
||||
m_accept_btn->translate(_x, _y);
|
||||
m_cancel_btn->translate(_x, _y);
|
||||
}
|
||||
|
||||
compiled_resource& get_compiled() override
|
||||
{
|
||||
if (!is_compiled)
|
||||
{
|
||||
auto compiled = vertical_layout::get_compiled();
|
||||
compiled.add(m_highlight_box->get_compiled());
|
||||
compiled.add(m_scroll_indicator_top->get_compiled());
|
||||
compiled.add(m_scroll_indicator_bottom->get_compiled());
|
||||
compiled.add(m_cancel_btn->get_compiled());
|
||||
|
||||
if (!m_cancel_only)
|
||||
compiled.add(m_accept_btn->get_compiled());
|
||||
|
||||
compiled_resources = compiled;
|
||||
}
|
||||
|
||||
return compiled_resources;
|
||||
}
|
||||
compiled_resource& get_compiled() override;
|
||||
};
|
||||
|
||||
struct edit_text : public label
|
||||
@ -1720,112 +1207,11 @@ namespace rsx
|
||||
|
||||
using label::label;
|
||||
|
||||
void move_caret(direction dir)
|
||||
{
|
||||
switch (dir)
|
||||
{
|
||||
case left:
|
||||
{
|
||||
if (caret_position)
|
||||
{
|
||||
caret_position--;
|
||||
refresh();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case right:
|
||||
{
|
||||
if (caret_position < text.length())
|
||||
{
|
||||
caret_position++;
|
||||
refresh();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case up:
|
||||
case down:
|
||||
// TODO
|
||||
break;
|
||||
}
|
||||
}
|
||||
void move_caret(direction dir);
|
||||
void insert_text(const std::string& str);
|
||||
void erase();
|
||||
|
||||
void insert_text(const std::string& str)
|
||||
{
|
||||
if (caret_position == 0)
|
||||
{
|
||||
// Start
|
||||
text = str + text;
|
||||
}
|
||||
else if (caret_position == text.length())
|
||||
{
|
||||
// End
|
||||
text += str;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Middle
|
||||
text.insert(caret_position, str);
|
||||
}
|
||||
|
||||
caret_position += ::narrow<u16>(str.length());
|
||||
refresh();
|
||||
}
|
||||
|
||||
void erase()
|
||||
{
|
||||
if (!caret_position)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (caret_position == 1)
|
||||
{
|
||||
text = text.length() > 1? text.substr(1) : "";
|
||||
}
|
||||
else if (caret_position == text.length())
|
||||
{
|
||||
text = text.substr(0, caret_position - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
text = text.substr(0, caret_position - 1) + text.substr(caret_position);
|
||||
}
|
||||
|
||||
caret_position--;
|
||||
refresh();
|
||||
}
|
||||
|
||||
compiled_resource& get_compiled() override
|
||||
{
|
||||
if (!is_compiled)
|
||||
{
|
||||
auto& compiled = label::get_compiled();
|
||||
|
||||
overlay_element caret;
|
||||
auto renderer = get_font();
|
||||
const auto caret_loc = renderer->get_char_offset(text.c_str(), caret_position,
|
||||
clip_text ? w : UINT16_MAX, wrap_text);
|
||||
|
||||
caret.set_pos(u16(caret_loc.first + padding_left + x), u16(caret_loc.second + padding_top + y));
|
||||
caret.set_size(1, u16(renderer->size_px + 2));
|
||||
caret.fore_color = fore_color;
|
||||
caret.back_color = fore_color;
|
||||
caret.pulse_effect_enabled = true;
|
||||
|
||||
compiled.add(caret.get_compiled());
|
||||
|
||||
for (auto &cmd : compiled.draw_commands)
|
||||
{
|
||||
// TODO: Scrolling by using scroll offset
|
||||
cmd.config.clip_region = true;
|
||||
cmd.config.clip_rect = { f32(x), f32(y), f32(x + w), f32(y + h) };
|
||||
}
|
||||
|
||||
is_compiled = true;
|
||||
}
|
||||
|
||||
return compiled_resources;
|
||||
}
|
||||
compiled_resource& get_compiled() override;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
114
rpcs3/Emu/RSX/Overlays/overlay_edit_text.cpp
Normal file
114
rpcs3/Emu/RSX/Overlays/overlay_edit_text.cpp
Normal file
@ -0,0 +1,114 @@
|
||||
#include "stdafx.h"
|
||||
#include "overlay_controls.h"
|
||||
|
||||
namespace rsx
|
||||
{
|
||||
namespace overlays
|
||||
{
|
||||
void edit_text::move_caret(direction dir)
|
||||
{
|
||||
switch (dir)
|
||||
{
|
||||
case left:
|
||||
{
|
||||
if (caret_position)
|
||||
{
|
||||
caret_position--;
|
||||
refresh();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case right:
|
||||
{
|
||||
if (caret_position < text.length())
|
||||
{
|
||||
caret_position++;
|
||||
refresh();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case up:
|
||||
case down:
|
||||
// TODO
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void edit_text::insert_text(const std::string& str)
|
||||
{
|
||||
if (caret_position == 0)
|
||||
{
|
||||
// Start
|
||||
text = str + text;
|
||||
}
|
||||
else if (caret_position == text.length())
|
||||
{
|
||||
// End
|
||||
text += str;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Middle
|
||||
text.insert(caret_position, str);
|
||||
}
|
||||
|
||||
caret_position += ::narrow<u16>(str.length());
|
||||
refresh();
|
||||
}
|
||||
|
||||
void edit_text::erase()
|
||||
{
|
||||
if (!caret_position)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (caret_position == 1)
|
||||
{
|
||||
text = text.length() > 1 ? text.substr(1) : "";
|
||||
}
|
||||
else if (caret_position == text.length())
|
||||
{
|
||||
text = text.substr(0, caret_position - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
text = text.substr(0, caret_position - 1) + text.substr(caret_position);
|
||||
}
|
||||
|
||||
caret_position--;
|
||||
refresh();
|
||||
}
|
||||
|
||||
compiled_resource& edit_text::get_compiled()
|
||||
{
|
||||
if (!is_compiled)
|
||||
{
|
||||
auto& compiled = label::get_compiled();
|
||||
|
||||
overlay_element caret;
|
||||
auto renderer = get_font();
|
||||
const auto caret_loc = renderer->get_char_offset(text.c_str(), caret_position, clip_text ? w : UINT16_MAX, wrap_text);
|
||||
|
||||
caret.set_pos(u16(caret_loc.first + padding_left + x), u16(caret_loc.second + padding_top + y));
|
||||
caret.set_size(1, u16(renderer->size_px + 2));
|
||||
caret.fore_color = fore_color;
|
||||
caret.back_color = fore_color;
|
||||
caret.pulse_effect_enabled = true;
|
||||
|
||||
compiled.add(caret.get_compiled());
|
||||
|
||||
for (auto& cmd : compiled.draw_commands)
|
||||
{
|
||||
// TODO: Scrolling by using scroll offset
|
||||
cmd.config.clip_region = true;
|
||||
cmd.config.clip_rect = {f32(x), f32(y), f32(x + w), f32(y + h)};
|
||||
}
|
||||
|
||||
is_compiled = true;
|
||||
}
|
||||
|
||||
return compiled_resources;
|
||||
}
|
||||
} // namespace overlays
|
||||
} // namespace rsx
|
292
rpcs3/Emu/RSX/Overlays/overlay_font.cpp
Normal file
292
rpcs3/Emu/RSX/Overlays/overlay_font.cpp
Normal file
@ -0,0 +1,292 @@
|
||||
#include "stdafx.h"
|
||||
#include "overlay_controls.h"
|
||||
|
||||
namespace rsx
|
||||
{
|
||||
namespace overlays
|
||||
{
|
||||
font::font(const char* ttf_name, f32 size)
|
||||
{
|
||||
// Init glyph
|
||||
std::vector<u8> bytes;
|
||||
std::vector<std::string> font_dirs;
|
||||
std::vector<std::string> fallback_fonts;
|
||||
#ifdef _WIN32
|
||||
font_dirs.push_back("C:/Windows/Fonts/");
|
||||
fallback_fonts.push_back("C:/Windows/Fonts/Arial.ttf");
|
||||
#else
|
||||
char* home = getenv("HOME");
|
||||
if (home == nullptr)
|
||||
home = getpwuid(getuid())->pw_dir;
|
||||
|
||||
font_dirs.push_back(home);
|
||||
if (home[font_dirs[0].length() - 1] == '/')
|
||||
font_dirs[0] += ".fonts/";
|
||||
else
|
||||
font_dirs[0] += "/.fonts/";
|
||||
|
||||
fallback_fonts.push_back("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf"); // ubuntu
|
||||
fallback_fonts.push_back("/usr/share/fonts/TTF/DejaVuSans.ttf"); // arch
|
||||
#endif
|
||||
// Search dev_flash for the font too
|
||||
font_dirs.push_back(g_cfg.vfs.get_dev_flash() + "data/font/");
|
||||
font_dirs.push_back(g_cfg.vfs.get_dev_flash() + "data/font/SONY-CC/");
|
||||
|
||||
// Attempt to load a font from dev_flash as a last resort
|
||||
fallback_fonts.push_back(g_cfg.vfs.get_dev_flash() + "data/font/SCE-PS3-VR-R-LATIN.TTF");
|
||||
|
||||
// Attemt to load requested font
|
||||
std::string file_path;
|
||||
bool font_found = false;
|
||||
for (auto& font_dir : font_dirs)
|
||||
{
|
||||
std::string requested_file = font_dir + ttf_name;
|
||||
|
||||
// Append ".ttf" if not present
|
||||
std::string font_lower(requested_file);
|
||||
|
||||
std::transform(requested_file.begin(), requested_file.end(), font_lower.begin(), ::tolower);
|
||||
if (font_lower.substr(font_lower.size() - 4) != ".ttf")
|
||||
requested_file += ".ttf";
|
||||
|
||||
file_path = requested_file;
|
||||
|
||||
if (fs::is_file(requested_file))
|
||||
{
|
||||
font_found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Attemt to load a fallback if request font wasn't found
|
||||
if (!font_found)
|
||||
{
|
||||
for (auto& fallback_font : fallback_fonts)
|
||||
{
|
||||
if (fs::is_file(fallback_font))
|
||||
{
|
||||
file_path = fallback_font;
|
||||
font_found = true;
|
||||
|
||||
LOG_NOTICE(RSX, "Found font file '%s' as a replacement for '%s'", fallback_font.c_str(), ttf_name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Read font
|
||||
if (font_found)
|
||||
{
|
||||
fs::file f(file_path);
|
||||
f.read(bytes, f.size());
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_ERROR(RSX, "Failed to initialize font '%s.ttf'", ttf_name);
|
||||
return;
|
||||
}
|
||||
|
||||
glyph_data.resize(width * height);
|
||||
pack_info.resize(256);
|
||||
|
||||
stbtt_pack_context context;
|
||||
if (!stbtt_PackBegin(&context, glyph_data.data(), width, height, 0, 1, nullptr))
|
||||
{
|
||||
LOG_ERROR(RSX, "Font packing failed");
|
||||
return;
|
||||
}
|
||||
|
||||
stbtt_PackSetOversampling(&context, oversample, oversample);
|
||||
|
||||
// Convert pt to px
|
||||
size_px = ceilf((f32)size * 96.f / 72.f);
|
||||
size_pt = size;
|
||||
|
||||
if (!stbtt_PackFontRange(&context, bytes.data(), 0, size_px, 0, 256, pack_info.data()))
|
||||
{
|
||||
LOG_ERROR(RSX, "Font packing failed");
|
||||
stbtt_PackEnd(&context);
|
||||
return;
|
||||
}
|
||||
|
||||
stbtt_PackEnd(&context);
|
||||
|
||||
font_name = ttf_name;
|
||||
initialized = true;
|
||||
|
||||
f32 unused;
|
||||
get_char('m', em_size, unused);
|
||||
}
|
||||
|
||||
stbtt_aligned_quad font::get_char(char c, f32& x_advance, f32& y_advance)
|
||||
{
|
||||
if (!initialized)
|
||||
return {};
|
||||
|
||||
stbtt_aligned_quad quad;
|
||||
stbtt_GetPackedQuad(pack_info.data(), width, height, u8(c), &x_advance, &y_advance, &quad, false);
|
||||
return quad;
|
||||
}
|
||||
|
||||
void font::render_text_ex(std::vector<vertex>& result, f32& x_advance, f32& y_advance, const char* text, u32 char_limit, u16 max_width, bool wrap)
|
||||
{
|
||||
x_advance = 0.f;
|
||||
y_advance = 0.f;
|
||||
result.clear();
|
||||
|
||||
if (!initialized)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
u32 i = 0u;
|
||||
bool skip_whitespace = false;
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (char c = text[i++]; c && (i <= char_limit))
|
||||
{
|
||||
if (u8(c) >= char_count)
|
||||
{
|
||||
// Unsupported glyph, render null for now
|
||||
c = ' ';
|
||||
c = ' ';
|
||||
}
|
||||
|
||||
switch (c)
|
||||
{
|
||||
case '\n':
|
||||
{
|
||||
y_advance += size_px + 2.f;
|
||||
x_advance = 0.f;
|
||||
continue;
|
||||
}
|
||||
case '\r':
|
||||
{
|
||||
x_advance = 0.f;
|
||||
continue;
|
||||
}
|
||||
default:
|
||||
{
|
||||
stbtt_aligned_quad quad;
|
||||
if (skip_whitespace && text[i - 1] == ' ')
|
||||
{
|
||||
quad = {};
|
||||
}
|
||||
else
|
||||
{
|
||||
quad = get_char(c, x_advance, y_advance);
|
||||
skip_whitespace = false;
|
||||
}
|
||||
|
||||
if (quad.x1 > max_width)
|
||||
{
|
||||
bool wrapped = false;
|
||||
bool non_whitespace_break = false;
|
||||
|
||||
if (wrap)
|
||||
{
|
||||
// scan previous chars
|
||||
for (int j = i - 1, nb_chars = 0; j > 0; j--, nb_chars++)
|
||||
{
|
||||
if (text[j] == '\n')
|
||||
break;
|
||||
|
||||
if (text[j] == ' ')
|
||||
{
|
||||
non_whitespace_break = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (non_whitespace_break)
|
||||
{
|
||||
if (nb_chars > 1)
|
||||
{
|
||||
nb_chars--;
|
||||
|
||||
auto first_affected = result.size() - (nb_chars * 4);
|
||||
f32 base_x = result[first_affected].values[0];
|
||||
|
||||
for (size_t n = first_affected; n < result.size(); ++n)
|
||||
{
|
||||
auto char_index = n / 4;
|
||||
if (text[char_index] == ' ')
|
||||
{
|
||||
// Skip character
|
||||
result[n++].vec2(0.f, 0.f);
|
||||
result[n++].vec2(0.f, 0.f);
|
||||
result[n++].vec2(0.f, 0.f);
|
||||
result[n].vec2(0.f, 0.f);
|
||||
continue;
|
||||
}
|
||||
|
||||
result[n].values[0] -= base_x;
|
||||
result[n].values[1] += size_px + 2.f;
|
||||
}
|
||||
|
||||
x_advance = result.back().values[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
x_advance = 0.f;
|
||||
}
|
||||
|
||||
wrapped = true;
|
||||
y_advance += size_px + 2.f;
|
||||
|
||||
if (text[i - 1] == ' ')
|
||||
{
|
||||
quad = {};
|
||||
skip_whitespace = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
quad = get_char(c, x_advance, y_advance);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!wrapped)
|
||||
{
|
||||
// TODO: Ellipsize
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
result.push_back({quad.x0, quad.y0, quad.s0, quad.t0});
|
||||
result.push_back({quad.x1, quad.y0, quad.s1, quad.t0});
|
||||
result.push_back({quad.x0, quad.y1, quad.s0, quad.t1});
|
||||
result.push_back({quad.x1, quad.y1, quad.s1, quad.t1});
|
||||
break;
|
||||
}
|
||||
} // switch
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<vertex> font::render_text(const char* text, u16 max_width, bool wrap)
|
||||
{
|
||||
std::vector<vertex> result;
|
||||
f32 unused_x, unused_y;
|
||||
|
||||
render_text_ex(result, unused_x, unused_y, text, UINT32_MAX, max_width, wrap);
|
||||
return result;
|
||||
}
|
||||
|
||||
std::pair<f32, f32> font::get_char_offset(const char* text, u16 max_length, u16 max_width, bool wrap)
|
||||
{
|
||||
std::vector<vertex> unused;
|
||||
f32 loc_x, loc_y;
|
||||
|
||||
render_text_ex(unused, loc_x, loc_y, text, max_length, max_width, wrap);
|
||||
return {loc_x, loc_y};
|
||||
}
|
||||
} // namespace overlays
|
||||
} // namespace rsx
|
184
rpcs3/Emu/RSX/Overlays/overlay_list_view.cpp
Normal file
184
rpcs3/Emu/RSX/Overlays/overlay_list_view.cpp
Normal file
@ -0,0 +1,184 @@
|
||||
#include "stdafx.h"
|
||||
#include "overlay_controls.h"
|
||||
|
||||
namespace rsx
|
||||
{
|
||||
namespace overlays
|
||||
{
|
||||
list_view::list_view(u16 width, u16 height)
|
||||
{
|
||||
w = width;
|
||||
h = height;
|
||||
|
||||
m_scroll_indicator_top = std::make_unique<image_view>(width, 5);
|
||||
m_scroll_indicator_bottom = std::make_unique<image_view>(width, 5);
|
||||
m_accept_btn = std::make_unique<image_button>(120, 20);
|
||||
m_cancel_btn = std::make_unique<image_button>(120, 20);
|
||||
m_highlight_box = std::make_unique<overlay_element>(width, 0);
|
||||
|
||||
m_scroll_indicator_top->set_size(width, 40);
|
||||
m_scroll_indicator_bottom->set_size(width, 40);
|
||||
m_accept_btn->set_size(120, 30);
|
||||
m_cancel_btn->set_size(120, 30);
|
||||
|
||||
m_scroll_indicator_top->set_image_resource(resource_config::standard_image_resource::fade_top);
|
||||
m_scroll_indicator_bottom->set_image_resource(resource_config::standard_image_resource::fade_bottom);
|
||||
|
||||
if (g_cfg.sys.enter_button_assignment == enter_button_assign::circle)
|
||||
{
|
||||
m_accept_btn->set_image_resource(resource_config::standard_image_resource::circle);
|
||||
m_cancel_btn->set_image_resource(resource_config::standard_image_resource::cross);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_accept_btn->set_image_resource(resource_config::standard_image_resource::cross);
|
||||
m_cancel_btn->set_image_resource(resource_config::standard_image_resource::circle);
|
||||
}
|
||||
|
||||
m_scroll_indicator_bottom->set_pos(0, height - 40);
|
||||
m_accept_btn->set_pos(30, height + 20);
|
||||
m_cancel_btn->set_pos(180, height + 20);
|
||||
|
||||
m_accept_btn->set_text("Select");
|
||||
m_cancel_btn->set_text("Cancel");
|
||||
|
||||
m_accept_btn->set_font("Arial", 16);
|
||||
m_cancel_btn->set_font("Arial", 16);
|
||||
|
||||
auto_resize = false;
|
||||
back_color = {0.15f, 0.15f, 0.15f, 0.8f};
|
||||
|
||||
m_highlight_box->back_color = {.5f, .5f, .8f, 0.2f};
|
||||
m_highlight_box->pulse_effect_enabled = true;
|
||||
m_scroll_indicator_top->fore_color.a = 0.f;
|
||||
m_scroll_indicator_bottom->fore_color.a = 0.f;
|
||||
}
|
||||
|
||||
void list_view::update_selection()
|
||||
{
|
||||
auto current_element = m_items[m_selected_entry * 2].get();
|
||||
|
||||
// Calculate bounds
|
||||
auto min_y = current_element->y - y;
|
||||
auto max_y = current_element->y + current_element->h + pack_padding + 2 - y;
|
||||
|
||||
if (min_y < scroll_offset_value)
|
||||
{
|
||||
scroll_offset_value = min_y;
|
||||
}
|
||||
else if (max_y > (h + scroll_offset_value))
|
||||
{
|
||||
scroll_offset_value = max_y - h - 2;
|
||||
}
|
||||
|
||||
if ((scroll_offset_value + h + 2) >= m_elements_height)
|
||||
m_scroll_indicator_bottom->fore_color.a = 0.f;
|
||||
else
|
||||
m_scroll_indicator_bottom->fore_color.a = 0.5f;
|
||||
|
||||
if (scroll_offset_value == 0)
|
||||
m_scroll_indicator_top->fore_color.a = 0.f;
|
||||
else
|
||||
m_scroll_indicator_top->fore_color.a = 0.5f;
|
||||
|
||||
m_highlight_box->set_pos(current_element->x, current_element->y);
|
||||
m_highlight_box->h = current_element->h + pack_padding;
|
||||
m_highlight_box->y -= scroll_offset_value;
|
||||
|
||||
m_highlight_box->refresh();
|
||||
m_scroll_indicator_top->refresh();
|
||||
m_scroll_indicator_bottom->refresh();
|
||||
refresh();
|
||||
}
|
||||
|
||||
void list_view::select_next()
|
||||
{
|
||||
if (m_selected_entry < (m_elements_count - 1))
|
||||
{
|
||||
m_selected_entry++;
|
||||
update_selection();
|
||||
}
|
||||
}
|
||||
|
||||
void list_view::select_previous()
|
||||
{
|
||||
if (m_selected_entry > 0)
|
||||
{
|
||||
m_selected_entry--;
|
||||
update_selection();
|
||||
}
|
||||
}
|
||||
|
||||
void list_view::add_entry(std::unique_ptr<overlay_element>& entry)
|
||||
{
|
||||
// Add entry view
|
||||
add_element(entry);
|
||||
m_elements_count++;
|
||||
|
||||
// Add separator
|
||||
auto separator = std::make_unique<overlay_element>();
|
||||
separator->back_color = fore_color;
|
||||
separator->w = w;
|
||||
separator->h = 2;
|
||||
add_element(separator);
|
||||
|
||||
if (m_selected_entry < 0)
|
||||
m_selected_entry = 0;
|
||||
|
||||
m_elements_height = advance_pos;
|
||||
update_selection();
|
||||
}
|
||||
|
||||
int list_view::get_selected_index()
|
||||
{
|
||||
return m_selected_entry;
|
||||
}
|
||||
|
||||
std::string list_view::get_selected_item()
|
||||
{
|
||||
if (m_selected_entry < 0)
|
||||
return {};
|
||||
|
||||
return m_items[m_selected_entry]->text;
|
||||
}
|
||||
|
||||
void list_view::set_cancel_only(bool cancel_only)
|
||||
{
|
||||
if (cancel_only)
|
||||
m_cancel_btn->set_pos(x + 30, y + h + 20);
|
||||
else
|
||||
m_cancel_btn->set_pos(x + 180, y + h + 20);
|
||||
|
||||
m_cancel_only = cancel_only;
|
||||
is_compiled = false;
|
||||
}
|
||||
|
||||
void list_view::translate(s16 _x, s16 _y)
|
||||
{
|
||||
layout_container::translate(_x, _y);
|
||||
m_scroll_indicator_top->translate(_x, _y);
|
||||
m_scroll_indicator_bottom->translate(_x, _y);
|
||||
m_accept_btn->translate(_x, _y);
|
||||
m_cancel_btn->translate(_x, _y);
|
||||
}
|
||||
|
||||
compiled_resource& list_view::get_compiled()
|
||||
{
|
||||
if (!is_compiled)
|
||||
{
|
||||
auto compiled = vertical_layout::get_compiled();
|
||||
compiled.add(m_highlight_box->get_compiled());
|
||||
compiled.add(m_scroll_indicator_top->get_compiled());
|
||||
compiled.add(m_scroll_indicator_bottom->get_compiled());
|
||||
compiled.add(m_cancel_btn->get_compiled());
|
||||
|
||||
if (!m_cancel_only)
|
||||
compiled.add(m_accept_btn->get_compiled());
|
||||
|
||||
compiled_resources = compiled;
|
||||
}
|
||||
|
||||
return compiled_resources;
|
||||
}
|
||||
} // namespace overlays
|
||||
} // namespace rsx
|
299
rpcs3/Emu/RSX/Overlays/overlay_message_dialog.cpp
Normal file
299
rpcs3/Emu/RSX/Overlays/overlay_message_dialog.cpp
Normal file
@ -0,0 +1,299 @@
|
||||
#include "stdafx.h"
|
||||
#include "overlays.h"
|
||||
|
||||
namespace rsx
|
||||
{
|
||||
namespace overlays
|
||||
{
|
||||
message_dialog::message_dialog(bool use_custom_background)
|
||||
{
|
||||
background.set_size(1280, 720);
|
||||
background.back_color.a = 0.85f;
|
||||
|
||||
text_display.set_size(1100, 40);
|
||||
text_display.set_pos(90, 364);
|
||||
text_display.set_font("Arial", 16);
|
||||
text_display.align_text(overlay_element::text_align::center);
|
||||
text_display.set_wrap_text(true);
|
||||
text_display.back_color.a = 0.f;
|
||||
|
||||
bottom_bar.back_color = color4f(1.f, 1.f, 1.f, 1.f);
|
||||
bottom_bar.set_size(1200, 2);
|
||||
bottom_bar.set_pos(40, 400);
|
||||
|
||||
progress_1.set_size(800, 4);
|
||||
progress_2.set_size(800, 4);
|
||||
progress_1.back_color = color4f(0.25f, 0.f, 0.f, 0.85f);
|
||||
progress_2.back_color = color4f(0.25f, 0.f, 0.f, 0.85f);
|
||||
|
||||
btn_ok.set_text("Yes");
|
||||
btn_ok.set_size(140, 30);
|
||||
btn_ok.set_pos(545, 420);
|
||||
btn_ok.set_font("Arial", 16);
|
||||
|
||||
btn_cancel.set_text("No");
|
||||
btn_cancel.set_size(140, 30);
|
||||
btn_cancel.set_pos(685, 420);
|
||||
btn_cancel.set_font("Arial", 16);
|
||||
|
||||
if (g_cfg.sys.enter_button_assignment == enter_button_assign::circle)
|
||||
{
|
||||
btn_ok.set_image_resource(resource_config::standard_image_resource::circle);
|
||||
btn_cancel.set_image_resource(resource_config::standard_image_resource::cross);
|
||||
}
|
||||
else
|
||||
{
|
||||
btn_ok.set_image_resource(resource_config::standard_image_resource::cross);
|
||||
btn_cancel.set_image_resource(resource_config::standard_image_resource::circle);
|
||||
}
|
||||
|
||||
if (use_custom_background)
|
||||
{
|
||||
auto icon_path = Emu.GetSfoDir() + "/PIC1.PNG";
|
||||
if (!fs::exists(icon_path))
|
||||
{
|
||||
// Fallback path
|
||||
icon_path = Emu.GetSfoDir() + "/ICON0.PNG";
|
||||
}
|
||||
|
||||
if (fs::exists(icon_path))
|
||||
{
|
||||
background_image = std::make_unique<image_info>(icon_path.c_str());
|
||||
if (background_image->data)
|
||||
{
|
||||
f32 color = (100 - g_cfg.video.shader_preloading_dialog.darkening_strength) / 100.f;
|
||||
background_poster.fore_color = color4f(color, color, color, 1.);
|
||||
background.back_color.a = 0.f;
|
||||
|
||||
background_poster.set_size(1280, 720);
|
||||
background_poster.set_raw_image(background_image.get());
|
||||
background_poster.set_blur_strength((u8)g_cfg.video.shader_preloading_dialog.blur_strength);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return_code = CELL_MSGDIALOG_BUTTON_NONE;
|
||||
}
|
||||
|
||||
compiled_resource message_dialog::get_compiled()
|
||||
{
|
||||
compiled_resource result;
|
||||
|
||||
if (background_image && background_image->data)
|
||||
{
|
||||
result.add(background_poster.get_compiled());
|
||||
}
|
||||
|
||||
result.add(background.get_compiled());
|
||||
result.add(text_display.get_compiled());
|
||||
|
||||
if (num_progress_bars > 0)
|
||||
{
|
||||
result.add(progress_1.get_compiled());
|
||||
}
|
||||
|
||||
if (num_progress_bars > 1)
|
||||
{
|
||||
result.add(progress_2.get_compiled());
|
||||
}
|
||||
|
||||
if (interactive)
|
||||
{
|
||||
if (!num_progress_bars)
|
||||
result.add(bottom_bar.get_compiled());
|
||||
|
||||
if (!cancel_only)
|
||||
result.add(btn_ok.get_compiled());
|
||||
|
||||
if (!ok_only)
|
||||
result.add(btn_cancel.get_compiled());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void message_dialog::on_button_pressed(pad_button button_press)
|
||||
{
|
||||
switch (button_press)
|
||||
{
|
||||
case pad_button::cross:
|
||||
{
|
||||
if (ok_only)
|
||||
{
|
||||
return_code = CELL_MSGDIALOG_BUTTON_OK;
|
||||
}
|
||||
else if (cancel_only)
|
||||
{
|
||||
// Do not accept for cancel-only dialogs
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
return_code = CELL_MSGDIALOG_BUTTON_YES;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case pad_button::circle:
|
||||
{
|
||||
if (ok_only)
|
||||
{
|
||||
// Ignore cancel operation for Ok-only
|
||||
return;
|
||||
}
|
||||
else if (cancel_only)
|
||||
{
|
||||
return_code = CELL_MSGDIALOG_BUTTON_ESCAPE;
|
||||
}
|
||||
else
|
||||
{
|
||||
return_code = CELL_MSGDIALOG_BUTTON_NO;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default: return;
|
||||
}
|
||||
|
||||
close();
|
||||
}
|
||||
|
||||
error_code message_dialog::show(const std::string& text, const MsgDialogType& type, std::function<void(s32 status)> on_close)
|
||||
{
|
||||
num_progress_bars = type.progress_bar_count;
|
||||
if (num_progress_bars)
|
||||
{
|
||||
u16 offset = 58;
|
||||
progress_1.set_pos(240, 412);
|
||||
|
||||
if (num_progress_bars > 1)
|
||||
{
|
||||
progress_2.set_pos(240, 462);
|
||||
offset = 98;
|
||||
}
|
||||
|
||||
// Push the other stuff down
|
||||
bottom_bar.translate(0, offset);
|
||||
btn_ok.translate(0, offset);
|
||||
btn_cancel.translate(0, offset);
|
||||
}
|
||||
|
||||
text_display.set_text(utf8_to_ascii8(text));
|
||||
|
||||
u16 text_w, text_h;
|
||||
text_display.measure_text(text_w, text_h);
|
||||
text_display.translate(0, -(text_h - 16));
|
||||
|
||||
switch (type.button_type.unshifted())
|
||||
{
|
||||
case CELL_MSGDIALOG_TYPE_BUTTON_TYPE_NONE:
|
||||
interactive = !type.disable_cancel;
|
||||
if (interactive)
|
||||
{
|
||||
btn_cancel.set_pos(585, btn_cancel.y);
|
||||
btn_cancel.set_text("Cancel");
|
||||
cancel_only = true;
|
||||
}
|
||||
break;
|
||||
case CELL_MSGDIALOG_TYPE_BUTTON_TYPE_OK:
|
||||
btn_ok.set_pos(600, btn_ok.y);
|
||||
btn_ok.set_text("OK");
|
||||
interactive = true;
|
||||
ok_only = true;
|
||||
break;
|
||||
case CELL_MSGDIALOG_TYPE_BUTTON_TYPE_YESNO: interactive = true; break;
|
||||
}
|
||||
|
||||
this->on_close = on_close;
|
||||
if (interactive)
|
||||
{
|
||||
thread_ctrl::spawn("dialog input thread", [&] {
|
||||
if (auto error = run_input_loop())
|
||||
{
|
||||
LOG_ERROR(RSX, "Dialog input loop exited with error code=%d", error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
u32 message_dialog::progress_bar_count()
|
||||
{
|
||||
return num_progress_bars;
|
||||
}
|
||||
|
||||
void message_dialog::progress_bar_set_taskbar_index(s32 index)
|
||||
{
|
||||
taskbar_index = index;
|
||||
}
|
||||
|
||||
error_code message_dialog::progress_bar_set_message(u32 index, const std::string& msg)
|
||||
{
|
||||
if (index >= num_progress_bars)
|
||||
return CELL_MSGDIALOG_ERROR_PARAM;
|
||||
|
||||
if (index == 0)
|
||||
progress_1.set_text(msg);
|
||||
else
|
||||
progress_2.set_text(msg);
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code message_dialog::progress_bar_increment(u32 index, f32 value)
|
||||
{
|
||||
if (index >= num_progress_bars)
|
||||
return CELL_MSGDIALOG_ERROR_PARAM;
|
||||
|
||||
if (index == 0)
|
||||
progress_1.inc(value);
|
||||
else
|
||||
progress_2.inc(value);
|
||||
|
||||
if (index == taskbar_index || taskbar_index == -1)
|
||||
Emu.GetCallbacks().handle_taskbar_progress(1, (s32)value);
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code message_dialog::progress_bar_reset(u32 index)
|
||||
{
|
||||
if (index >= num_progress_bars)
|
||||
return CELL_MSGDIALOG_ERROR_PARAM;
|
||||
|
||||
if (index == 0)
|
||||
progress_1.set_value(0.f);
|
||||
else
|
||||
progress_2.set_value(0.f);
|
||||
|
||||
Emu.GetCallbacks().handle_taskbar_progress(0, 0);
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code message_dialog::progress_bar_set_limit(u32 index, u32 limit)
|
||||
{
|
||||
if (index >= num_progress_bars)
|
||||
return CELL_MSGDIALOG_ERROR_PARAM;
|
||||
|
||||
if (index == 0)
|
||||
progress_1.set_limit((float)limit);
|
||||
else
|
||||
progress_2.set_limit((float)limit);
|
||||
|
||||
if (index == taskbar_index)
|
||||
{
|
||||
taskbar_limit = limit;
|
||||
Emu.GetCallbacks().handle_taskbar_progress(2, taskbar_limit);
|
||||
}
|
||||
else if (taskbar_index == -1)
|
||||
{
|
||||
taskbar_limit += limit;
|
||||
Emu.GetCallbacks().handle_taskbar_progress(2, taskbar_limit);
|
||||
}
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
} // namespace overlays
|
||||
} // namespace rsx
|
102
rpcs3/Emu/RSX/Overlays/overlay_progress_bar.cpp
Normal file
102
rpcs3/Emu/RSX/Overlays/overlay_progress_bar.cpp
Normal file
@ -0,0 +1,102 @@
|
||||
#include "stdafx.h"
|
||||
#include "overlay_controls.h"
|
||||
|
||||
namespace rsx
|
||||
{
|
||||
namespace overlays
|
||||
{
|
||||
progress_bar::progress_bar()
|
||||
{
|
||||
text_view.back_color = {0.f, 0.f, 0.f, 0.f};
|
||||
}
|
||||
|
||||
void progress_bar::inc(f32 value)
|
||||
{
|
||||
set_value(m_value + value);
|
||||
}
|
||||
|
||||
void progress_bar::dec(f32 value)
|
||||
{
|
||||
set_value(m_value - value);
|
||||
}
|
||||
|
||||
void progress_bar::set_limit(f32 limit)
|
||||
{
|
||||
m_limit = limit;
|
||||
is_compiled = false;
|
||||
}
|
||||
|
||||
void progress_bar::set_value(f32 value)
|
||||
{
|
||||
m_value = std::clamp(value, 0.f, m_limit);
|
||||
|
||||
f32 indicator_width = (w * m_value) / m_limit;
|
||||
indicator.set_size((u16)indicator_width, h);
|
||||
is_compiled = false;
|
||||
}
|
||||
|
||||
void progress_bar::set_pos(u16 _x, u16 _y)
|
||||
{
|
||||
u16 text_w, text_h;
|
||||
text_view.measure_text(text_w, text_h);
|
||||
text_h += 13;
|
||||
|
||||
overlay_element::set_pos(_x, _y + text_h);
|
||||
indicator.set_pos(_x, _y + text_h);
|
||||
text_view.set_pos(_x, _y);
|
||||
}
|
||||
|
||||
void progress_bar::set_size(u16 _w, u16 _h)
|
||||
{
|
||||
overlay_element::set_size(_w, _h);
|
||||
text_view.set_size(_w, text_view.h);
|
||||
set_value(m_value);
|
||||
}
|
||||
|
||||
void progress_bar::translate(s16 dx, s16 dy)
|
||||
{
|
||||
set_pos(x + dx, y + dy);
|
||||
}
|
||||
|
||||
void progress_bar::set_text(const char* str)
|
||||
{
|
||||
text_view.set_text(str);
|
||||
text_view.align_text(text_align::center);
|
||||
|
||||
u16 text_w, text_h;
|
||||
text_view.measure_text(text_w, text_h);
|
||||
text_view.set_size(w, text_h);
|
||||
|
||||
set_pos(text_view.x, text_view.y);
|
||||
is_compiled = false;
|
||||
}
|
||||
|
||||
void progress_bar::set_text(const std::string& str)
|
||||
{
|
||||
text_view.set_text(str);
|
||||
text_view.align_text(text_align::center);
|
||||
|
||||
u16 text_w, text_h;
|
||||
text_view.measure_text(text_w, text_h);
|
||||
text_view.set_size(w, text_h);
|
||||
|
||||
set_pos(text_view.x, text_view.y);
|
||||
is_compiled = false;
|
||||
}
|
||||
|
||||
compiled_resource& progress_bar::get_compiled()
|
||||
{
|
||||
if (!is_compiled)
|
||||
{
|
||||
auto& compiled = overlay_element::get_compiled();
|
||||
compiled.add(text_view.get_compiled());
|
||||
|
||||
indicator.back_color = fore_color;
|
||||
indicator.refresh();
|
||||
compiled.add(indicator.get_compiled());
|
||||
}
|
||||
|
||||
return compiled_resources;
|
||||
}
|
||||
} // namespace overlays
|
||||
} // namespace rsx
|
251
rpcs3/Emu/RSX/Overlays/overlay_save_dialog.cpp
Normal file
251
rpcs3/Emu/RSX/Overlays/overlay_save_dialog.cpp
Normal file
@ -0,0 +1,251 @@
|
||||
#include "stdafx.h"
|
||||
#include "overlays.h"
|
||||
|
||||
namespace rsx
|
||||
{
|
||||
namespace overlays
|
||||
{
|
||||
save_dialog::save_dialog_entry::save_dialog_entry(const std::string& text1, const std::string& text2, const std::string& text3, u8 resource_id, const std::vector<u8>& icon_buf)
|
||||
{
|
||||
std::unique_ptr<overlay_element> image = std::make_unique<image_view>();
|
||||
image->set_size(160, 110);
|
||||
image->set_padding(36, 36, 11, 11); // Square image, 88x88
|
||||
|
||||
if (resource_id != image_resource_id::raw_image)
|
||||
{
|
||||
static_cast<image_view*>(image.get())->set_image_resource(resource_id);
|
||||
}
|
||||
else if (icon_buf.size())
|
||||
{
|
||||
image->set_padding(0, 0, 11, 11); // Half sized icon, 320x176->160x88
|
||||
icon_data = std::make_unique<image_info>(icon_buf);
|
||||
static_cast<image_view*>(image.get())->set_raw_image(icon_data.get());
|
||||
}
|
||||
else
|
||||
{
|
||||
// Fallback
|
||||
static_cast<image_view*>(image.get())->set_image_resource(resource_config::standard_image_resource::save);
|
||||
}
|
||||
|
||||
std::unique_ptr<overlay_element> text_stack = std::make_unique<vertical_layout>();
|
||||
std::unique_ptr<overlay_element> padding = std::make_unique<spacer>();
|
||||
std::unique_ptr<overlay_element> header_text = std::make_unique<label>(utf8_to_ascii8(text1));
|
||||
std::unique_ptr<overlay_element> subtext = std::make_unique<label>(utf8_to_ascii8(text2));
|
||||
|
||||
padding->set_size(1, 1);
|
||||
header_text->set_size(800, 40);
|
||||
header_text->set_font("Arial", 16);
|
||||
header_text->set_wrap_text(true);
|
||||
|
||||
subtext->set_size(800, 0);
|
||||
subtext->set_font("Arial", 14);
|
||||
subtext->set_wrap_text(true);
|
||||
static_cast<label*>(subtext.get())->auto_resize(true);
|
||||
|
||||
// Make back color transparent for text
|
||||
header_text->back_color.a = 0.f;
|
||||
subtext->back_color.a = 0.f;
|
||||
|
||||
static_cast<vertical_layout*>(text_stack.get())->pack_padding = 5;
|
||||
static_cast<vertical_layout*>(text_stack.get())->add_element(padding);
|
||||
static_cast<vertical_layout*>(text_stack.get())->add_element(header_text);
|
||||
static_cast<vertical_layout*>(text_stack.get())->add_element(subtext);
|
||||
|
||||
if (!text3.empty())
|
||||
{
|
||||
// Detail info actually exists
|
||||
std::unique_ptr<overlay_element> detail = std::make_unique<label>(utf8_to_ascii8(text3));
|
||||
detail->set_size(800, 0);
|
||||
detail->set_font("Arial", 12);
|
||||
detail->set_wrap_text(true);
|
||||
detail->back_color.a = 0.f;
|
||||
static_cast<label*>(detail.get())->auto_resize(true);
|
||||
static_cast<vertical_layout*>(text_stack.get())->add_element(detail);
|
||||
}
|
||||
|
||||
if (text_stack->h > image->h)
|
||||
{
|
||||
std::unique_ptr<overlay_element> padding2 = std::make_unique<spacer>();
|
||||
padding2->set_size(1, 5);
|
||||
static_cast<vertical_layout*>(text_stack.get())->add_element(padding2);
|
||||
}
|
||||
|
||||
// Pack
|
||||
this->pack_padding = 15;
|
||||
add_element(image);
|
||||
add_element(text_stack);
|
||||
}
|
||||
|
||||
save_dialog::save_dialog()
|
||||
{
|
||||
m_dim_background = std::make_unique<overlay_element>();
|
||||
m_dim_background->set_size(1280, 720);
|
||||
|
||||
m_list = std::make_unique<list_view>(1240, 540);
|
||||
m_description = std::make_unique<label>();
|
||||
m_time_thingy = std::make_unique<label>();
|
||||
|
||||
m_list->set_pos(20, 85);
|
||||
|
||||
m_description->set_font("Arial", 20);
|
||||
m_description->set_pos(20, 37);
|
||||
m_description->set_text("Save Dialog");
|
||||
|
||||
m_time_thingy->set_font("Arial", 14);
|
||||
m_time_thingy->set_pos(1000, 30);
|
||||
m_time_thingy->set_text(date_time::current_time());
|
||||
|
||||
static_cast<label*>(m_description.get())->auto_resize();
|
||||
static_cast<label*>(m_time_thingy.get())->auto_resize();
|
||||
|
||||
m_dim_background->back_color.a = 0.8f;
|
||||
m_description->back_color.a = 0.f;
|
||||
m_time_thingy->back_color.a = 0.f;
|
||||
|
||||
return_code = selection_code::canceled;
|
||||
}
|
||||
|
||||
void save_dialog::update()
|
||||
{
|
||||
m_time_thingy->set_text(date_time::current_time());
|
||||
static_cast<label*>(m_time_thingy.get())->auto_resize();
|
||||
}
|
||||
|
||||
void save_dialog::on_button_pressed(pad_button button_press)
|
||||
{
|
||||
switch (button_press)
|
||||
{
|
||||
case pad_button::cross:
|
||||
if (m_no_saves)
|
||||
break;
|
||||
return_code = m_list->get_selected_index();
|
||||
// Fall through
|
||||
case pad_button::circle:
|
||||
close();
|
||||
break;
|
||||
case pad_button::dpad_up:
|
||||
m_list->select_previous();
|
||||
break;
|
||||
case pad_button::dpad_down:
|
||||
m_list->select_next();
|
||||
break;
|
||||
default:
|
||||
LOG_TRACE(RSX, "[ui] Button %d pressed", (u8)button_press);
|
||||
}
|
||||
}
|
||||
|
||||
compiled_resource save_dialog::get_compiled()
|
||||
{
|
||||
compiled_resource result;
|
||||
result.add(m_dim_background->get_compiled());
|
||||
result.add(m_list->get_compiled());
|
||||
result.add(m_description->get_compiled());
|
||||
result.add(m_time_thingy->get_compiled());
|
||||
|
||||
if (m_no_saves)
|
||||
result.add(m_no_saves_text->get_compiled());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
s32 save_dialog::show(std::vector<SaveDataEntry>& save_entries, u32 op, vm::ptr<CellSaveDataListSet> listSet)
|
||||
{
|
||||
std::vector<u8> icon;
|
||||
std::vector<std::unique_ptr<overlay_element>> entries;
|
||||
|
||||
for (auto& entry : save_entries)
|
||||
{
|
||||
std::unique_ptr<overlay_element> e;
|
||||
e = std::make_unique<save_dialog_entry>(entry.title, entry.subtitle, entry.details, image_resource_id::raw_image, entry.iconBuf);
|
||||
entries.emplace_back(std::move(e));
|
||||
}
|
||||
|
||||
if (op >= 8)
|
||||
{
|
||||
m_description->set_text("Delete Save");
|
||||
}
|
||||
else if (op & 1)
|
||||
{
|
||||
m_description->set_text("Load Save");
|
||||
}
|
||||
else
|
||||
{
|
||||
m_description->set_text("Save");
|
||||
}
|
||||
|
||||
const bool newpos_head = listSet->newData && listSet->newData->iconPosition == CELL_SAVEDATA_ICONPOS_HEAD;
|
||||
|
||||
if (!newpos_head)
|
||||
{
|
||||
for (auto& entry : entries)
|
||||
{
|
||||
m_list->add_entry(entry);
|
||||
}
|
||||
}
|
||||
|
||||
if (listSet->newData)
|
||||
{
|
||||
std::unique_ptr<overlay_element> new_stub;
|
||||
|
||||
const char* title = "Create New";
|
||||
|
||||
int id = resource_config::standard_image_resource::new_entry;
|
||||
|
||||
if (auto picon = +listSet->newData->icon)
|
||||
{
|
||||
if (picon->title)
|
||||
title = picon->title.get_ptr();
|
||||
|
||||
if (picon->iconBuf && picon->iconBufSize && picon->iconBufSize <= 225280)
|
||||
{
|
||||
const auto iconBuf = static_cast<u8*>(picon->iconBuf.get_ptr());
|
||||
const auto iconEnd = iconBuf + picon->iconBufSize;
|
||||
icon.assign(iconBuf, iconEnd);
|
||||
}
|
||||
}
|
||||
|
||||
if (!icon.empty())
|
||||
{
|
||||
id = image_resource_id::raw_image;
|
||||
}
|
||||
|
||||
new_stub = std::make_unique<save_dialog_entry>(title, "Select to create a new entry", "", id, icon);
|
||||
|
||||
m_list->add_entry(new_stub);
|
||||
}
|
||||
|
||||
if (newpos_head)
|
||||
{
|
||||
for (auto& entry : entries)
|
||||
{
|
||||
m_list->add_entry(entry);
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_list->m_items.size())
|
||||
{
|
||||
m_no_saves_text = std::make_unique<label>("There is no saved data.");
|
||||
m_no_saves_text->set_font("Arial", 20);
|
||||
m_no_saves_text->align_text(overlay_element::text_align::center);
|
||||
m_no_saves_text->set_pos(m_list->x, m_list->y + m_list->h / 2);
|
||||
m_no_saves_text->set_size(m_list->w, 30);
|
||||
m_no_saves_text->back_color.a = 0;
|
||||
|
||||
m_no_saves = true;
|
||||
m_list->set_cancel_only(true);
|
||||
}
|
||||
|
||||
static_cast<label*>(m_description.get())->auto_resize();
|
||||
|
||||
if (auto err = run_input_loop())
|
||||
return err;
|
||||
|
||||
if (return_code == entries.size() && !newpos_head)
|
||||
return selection_code::new_save;
|
||||
if (return_code >= 0 && newpos_head)
|
||||
return return_code - 1;
|
||||
|
||||
return return_code;
|
||||
}
|
||||
} // namespace overlays
|
||||
} // namespace RSX
|
@ -0,0 +1,91 @@
|
||||
#include "stdafx.h"
|
||||
#include "overlays.h"
|
||||
|
||||
namespace rsx
|
||||
{
|
||||
namespace overlays
|
||||
{
|
||||
shader_compile_notification::shader_compile_notification()
|
||||
{
|
||||
const u16 pos_x = g_cfg.video.shader_compilation_hint.pos_x;
|
||||
const u16 pos_y = g_cfg.video.shader_compilation_hint.pos_y;
|
||||
|
||||
m_text.set_font("Arial", 16);
|
||||
m_text.set_text("Compiling shaders");
|
||||
m_text.auto_resize();
|
||||
m_text.set_pos(pos_x, pos_y);
|
||||
|
||||
m_text.back_color.a = 0.f;
|
||||
|
||||
for (int n = 0; n < 3; ++n)
|
||||
{
|
||||
dots[n].set_size(2, 2);
|
||||
dots[n].back_color = color4f(1.f, 1.f, 1.f, 1.f);
|
||||
dots[n].set_pos(m_text.w + pos_x + 5 + (6 * n), pos_y + 20);
|
||||
}
|
||||
|
||||
creation_time = get_system_time();
|
||||
expire_time = creation_time + 1000000;
|
||||
|
||||
// Disable forced refresh unless fps dips below 4
|
||||
min_refresh_duration_us = 250000;
|
||||
}
|
||||
|
||||
void shader_compile_notification::update_animation(u64 t)
|
||||
{
|
||||
// Update rate is twice per second
|
||||
auto elapsed = t - creation_time;
|
||||
elapsed /= 500000;
|
||||
|
||||
auto old_dot = current_dot;
|
||||
current_dot = elapsed % 3;
|
||||
|
||||
if (old_dot != current_dot)
|
||||
{
|
||||
if (old_dot != 255)
|
||||
{
|
||||
dots[old_dot].set_size(2, 2);
|
||||
dots[old_dot].translate(0, 1);
|
||||
}
|
||||
|
||||
dots[current_dot].translate(0, -1);
|
||||
dots[current_dot].set_size(3, 3);
|
||||
}
|
||||
}
|
||||
|
||||
// Extends visible time by half a second. Also updates the screen
|
||||
void shader_compile_notification::touch()
|
||||
{
|
||||
if (urgency_ctr == 0 || urgency_ctr > 8)
|
||||
{
|
||||
refresh();
|
||||
urgency_ctr = 0;
|
||||
}
|
||||
|
||||
expire_time = get_system_time() + 500000;
|
||||
urgency_ctr++;
|
||||
}
|
||||
|
||||
void shader_compile_notification::update()
|
||||
{
|
||||
auto current_time = get_system_time();
|
||||
if (current_time > expire_time)
|
||||
close();
|
||||
|
||||
update_animation(current_time);
|
||||
|
||||
// Usually this method is called during a draw-to-screen operation. Reset urgency ctr
|
||||
urgency_ctr = 1;
|
||||
}
|
||||
|
||||
compiled_resource shader_compile_notification::get_compiled()
|
||||
{
|
||||
auto compiled = m_text.get_compiled();
|
||||
compiled.add(dots[0].get_compiled());
|
||||
compiled.add(dots[1].get_compiled());
|
||||
compiled.add(dots[2].get_compiled());
|
||||
|
||||
return compiled;
|
||||
}
|
||||
} // namespace overlays
|
||||
} // namespace rsx
|
70
rpcs3/Emu/RSX/Overlays/overlay_trophy_notification.cpp
Normal file
70
rpcs3/Emu/RSX/Overlays/overlay_trophy_notification.cpp
Normal file
@ -0,0 +1,70 @@
|
||||
#include "stdafx.h"
|
||||
#include "overlays.h"
|
||||
|
||||
namespace rsx
|
||||
{
|
||||
namespace overlays
|
||||
{
|
||||
trophy_notification::trophy_notification()
|
||||
{
|
||||
frame.set_pos(0, 0);
|
||||
frame.set_size(260, 80);
|
||||
frame.back_color.a = 0.85f;
|
||||
|
||||
image.set_pos(8, 8);
|
||||
image.set_size(64, 64);
|
||||
image.back_color.a = 0.f;
|
||||
|
||||
text_view.set_pos(85, 0);
|
||||
text_view.set_padding(0, 0, 24, 0);
|
||||
text_view.set_font("Arial", 8);
|
||||
text_view.align_text(overlay_element::text_align::center);
|
||||
text_view.back_color.a = 0.f;
|
||||
}
|
||||
void trophy_notification::update()
|
||||
{
|
||||
u64 t = get_system_time();
|
||||
if (((t - creation_time) / 1000) > 7500)
|
||||
close();
|
||||
}
|
||||
|
||||
compiled_resource trophy_notification::get_compiled()
|
||||
{
|
||||
auto result = frame.get_compiled();
|
||||
result.add(image.get_compiled());
|
||||
result.add(text_view.get_compiled());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
s32 trophy_notification::show(const SceNpTrophyDetails& trophy, const std::vector<uchar>& trophy_icon_buffer)
|
||||
{
|
||||
if (trophy_icon_buffer.size())
|
||||
{
|
||||
icon_info = std::make_unique<image_info>(trophy_icon_buffer);
|
||||
image.set_raw_image(icon_info.get());
|
||||
}
|
||||
|
||||
std::string trophy_message;
|
||||
switch (trophy.trophyGrade)
|
||||
{
|
||||
case SCE_NP_TROPHY_GRADE_BRONZE: trophy_message = "bronze"; break;
|
||||
case SCE_NP_TROPHY_GRADE_SILVER: trophy_message = "silver"; break;
|
||||
case SCE_NP_TROPHY_GRADE_GOLD: trophy_message = "gold"; break;
|
||||
case SCE_NP_TROPHY_GRADE_PLATINUM: trophy_message = "platinum"; break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
trophy_message = "You have earned the " + trophy_message + " trophy\n" + utf8_to_ascii8(trophy.name);
|
||||
text_view.set_text(trophy_message);
|
||||
text_view.auto_resize();
|
||||
|
||||
// Resize background to cover the text
|
||||
u16 margin_sz = text_view.x - image.w - image.x;
|
||||
frame.w = text_view.x + text_view.w + margin_sz;
|
||||
|
||||
creation_time = get_system_time();
|
||||
return CELL_OK;
|
||||
}
|
||||
} // namespace overlays
|
||||
} // namespace rsx
|
@ -496,76 +496,7 @@ namespace rsx
|
||||
std::unique_ptr<image_info> icon_data;
|
||||
|
||||
public:
|
||||
save_dialog_entry(const std::string& text1, const std::string& text2, const std::string& text3, u8 resource_id, const std::vector<u8>& icon_buf)
|
||||
{
|
||||
std::unique_ptr<overlay_element> image = std::make_unique<image_view>();
|
||||
image->set_size(160, 110);
|
||||
image->set_padding(36, 36, 11, 11); // Square image, 88x88
|
||||
|
||||
if (resource_id != image_resource_id::raw_image)
|
||||
{
|
||||
static_cast<image_view*>(image.get())->set_image_resource(resource_id);
|
||||
}
|
||||
else if (icon_buf.size())
|
||||
{
|
||||
image->set_padding(0, 0, 11, 11); // Half sized icon, 320x176->160x88
|
||||
icon_data = std::make_unique<image_info>(icon_buf);
|
||||
static_cast<image_view*>(image.get())->set_raw_image(icon_data.get());
|
||||
}
|
||||
else
|
||||
{
|
||||
// Fallback
|
||||
static_cast<image_view*>(image.get())->set_image_resource(resource_config::standard_image_resource::save);
|
||||
}
|
||||
|
||||
std::unique_ptr<overlay_element> text_stack = std::make_unique<vertical_layout>();
|
||||
std::unique_ptr<overlay_element> padding = std::make_unique<spacer>();
|
||||
std::unique_ptr<overlay_element> header_text = std::make_unique<label>(utf8_to_ascii8(text1));
|
||||
std::unique_ptr<overlay_element> subtext = std::make_unique<label>(utf8_to_ascii8(text2));
|
||||
|
||||
padding->set_size(1, 1);
|
||||
header_text->set_size(800, 40);
|
||||
header_text->set_font("Arial", 16);
|
||||
header_text->set_wrap_text(true);
|
||||
|
||||
subtext->set_size(800, 0);
|
||||
subtext->set_font("Arial", 14);
|
||||
subtext->set_wrap_text(true);
|
||||
static_cast<label*>(subtext.get())->auto_resize(true);
|
||||
|
||||
// Make back color transparent for text
|
||||
header_text->back_color.a = 0.f;
|
||||
subtext->back_color.a = 0.f;
|
||||
|
||||
static_cast<vertical_layout*>(text_stack.get())->pack_padding = 5;
|
||||
static_cast<vertical_layout*>(text_stack.get())->add_element(padding);
|
||||
static_cast<vertical_layout*>(text_stack.get())->add_element(header_text);
|
||||
static_cast<vertical_layout*>(text_stack.get())->add_element(subtext);
|
||||
|
||||
if (!text3.empty())
|
||||
{
|
||||
// Detail info actually exists
|
||||
std::unique_ptr<overlay_element> detail = std::make_unique<label>(utf8_to_ascii8(text3));
|
||||
detail->set_size(800, 0);
|
||||
detail->set_font("Arial", 12);
|
||||
detail->set_wrap_text(true);
|
||||
detail->back_color.a = 0.f;
|
||||
static_cast<label*>(detail.get())->auto_resize(true);
|
||||
static_cast<vertical_layout*>(text_stack.get())->add_element(detail);
|
||||
}
|
||||
|
||||
if (text_stack->h > image->h)
|
||||
{
|
||||
std::unique_ptr<overlay_element> padding2 = std::make_unique<spacer>();
|
||||
padding2->set_size(1, 5);
|
||||
static_cast<vertical_layout*>(text_stack.get())->add_element(padding2);
|
||||
}
|
||||
|
||||
// Pack
|
||||
this->pack_padding = 15;
|
||||
add_element(image);
|
||||
add_element(text_stack);
|
||||
}
|
||||
save_dialog_entry(const std::string& text1, const std::string& text2, const std::string& text3, u8 resource_id, const std::vector<u8>& icon_buf);
|
||||
};
|
||||
|
||||
std::unique_ptr<overlay_element> m_dim_background;
|
||||
@ -577,177 +508,14 @@ namespace rsx
|
||||
bool m_no_saves = false;
|
||||
|
||||
public:
|
||||
save_dialog()
|
||||
{
|
||||
m_dim_background = std::make_unique<overlay_element>();
|
||||
m_dim_background->set_size(1280, 720);
|
||||
save_dialog();
|
||||
|
||||
m_list = std::make_unique<list_view>(1240, 540);
|
||||
m_description = std::make_unique<label>();
|
||||
m_time_thingy = std::make_unique<label>();
|
||||
void update() override;
|
||||
void on_button_pressed(pad_button button_press) override;
|
||||
|
||||
m_list->set_pos(20, 85);
|
||||
compiled_resource get_compiled() override;
|
||||
|
||||
m_description->set_font("Arial", 20);
|
||||
m_description->set_pos(20, 37);
|
||||
m_description->set_text("Save Dialog");
|
||||
|
||||
m_time_thingy->set_font("Arial", 14);
|
||||
m_time_thingy->set_pos(1000, 30);
|
||||
m_time_thingy->set_text(date_time::current_time());
|
||||
|
||||
static_cast<label*>(m_description.get())->auto_resize();
|
||||
static_cast<label*>(m_time_thingy.get())->auto_resize();
|
||||
|
||||
m_dim_background->back_color.a = 0.8f;
|
||||
m_description->back_color.a = 0.f;
|
||||
m_time_thingy->back_color.a = 0.f;
|
||||
|
||||
return_code = selection_code::canceled;
|
||||
}
|
||||
|
||||
void on_button_pressed(pad_button button_press) override
|
||||
{
|
||||
switch (button_press)
|
||||
{
|
||||
case pad_button::cross:
|
||||
if (m_no_saves)
|
||||
break;
|
||||
return_code = m_list->get_selected_index();
|
||||
// Fall through
|
||||
case pad_button::circle:
|
||||
close();
|
||||
break;
|
||||
case pad_button::dpad_up:
|
||||
m_list->select_previous();
|
||||
break;
|
||||
case pad_button::dpad_down:
|
||||
m_list->select_next();
|
||||
break;
|
||||
default:
|
||||
LOG_TRACE(RSX, "[ui] Button %d pressed", (u8)button_press);
|
||||
}
|
||||
}
|
||||
|
||||
compiled_resource get_compiled() override
|
||||
{
|
||||
compiled_resource result;
|
||||
result.add(m_dim_background->get_compiled());
|
||||
result.add(m_list->get_compiled());
|
||||
result.add(m_description->get_compiled());
|
||||
result.add(m_time_thingy->get_compiled());
|
||||
|
||||
if (m_no_saves)
|
||||
result.add(m_no_saves_text->get_compiled());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
s32 show(std::vector<SaveDataEntry>& save_entries, u32 op, vm::ptr<CellSaveDataListSet> listSet)
|
||||
{
|
||||
std::vector<u8> icon;
|
||||
std::vector<std::unique_ptr<overlay_element>> entries;
|
||||
|
||||
for (auto& entry : save_entries)
|
||||
{
|
||||
std::unique_ptr<overlay_element> e;
|
||||
e = std::make_unique<save_dialog_entry>(entry.title, entry.subtitle, entry.details, image_resource_id::raw_image, entry.iconBuf);
|
||||
entries.emplace_back(std::move(e));
|
||||
}
|
||||
|
||||
if (op >= 8)
|
||||
{
|
||||
m_description->set_text("Delete Save");
|
||||
}
|
||||
else if (op & 1)
|
||||
{
|
||||
m_description->set_text("Load Save");
|
||||
}
|
||||
else
|
||||
{
|
||||
m_description->set_text("Save");
|
||||
}
|
||||
|
||||
const bool newpos_head = listSet->newData && listSet->newData->iconPosition == CELL_SAVEDATA_ICONPOS_HEAD;
|
||||
|
||||
if (!newpos_head)
|
||||
{
|
||||
for (auto& entry : entries)
|
||||
{
|
||||
m_list->add_entry(entry);
|
||||
}
|
||||
}
|
||||
|
||||
if (listSet->newData)
|
||||
{
|
||||
std::unique_ptr<overlay_element> new_stub;
|
||||
|
||||
const char* title = "Create New";
|
||||
|
||||
int id = resource_config::standard_image_resource::new_entry;
|
||||
|
||||
if (auto picon = +listSet->newData->icon)
|
||||
{
|
||||
if (picon->title)
|
||||
title = picon->title.get_ptr();
|
||||
|
||||
if (picon->iconBuf && picon->iconBufSize && picon->iconBufSize <= 225280)
|
||||
{
|
||||
const auto iconBuf = static_cast<u8*>(picon->iconBuf.get_ptr());
|
||||
const auto iconEnd = iconBuf + picon->iconBufSize;
|
||||
icon.assign(iconBuf, iconEnd);
|
||||
}
|
||||
}
|
||||
|
||||
if (!icon.empty())
|
||||
{
|
||||
id = image_resource_id::raw_image;
|
||||
}
|
||||
|
||||
new_stub = std::make_unique<save_dialog_entry>(title, "Select to create a new entry", "", id, icon);
|
||||
|
||||
m_list->add_entry(new_stub);
|
||||
}
|
||||
|
||||
if (newpos_head)
|
||||
{
|
||||
for (auto& entry : entries)
|
||||
{
|
||||
m_list->add_entry(entry);
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_list->m_items.size())
|
||||
{
|
||||
m_no_saves_text = std::make_unique<label>("There is no saved data.");
|
||||
m_no_saves_text->set_font("Arial", 20);
|
||||
m_no_saves_text->align_text(overlay_element::text_align::center);
|
||||
m_no_saves_text->set_pos(m_list->x, m_list->y + m_list->h / 2);
|
||||
m_no_saves_text->set_size(m_list->w, 30);
|
||||
m_no_saves_text->back_color.a = 0;
|
||||
|
||||
m_no_saves = true;
|
||||
m_list->set_cancel_only(true);
|
||||
}
|
||||
|
||||
static_cast<label*>(m_description.get())->auto_resize();
|
||||
|
||||
if (auto err = run_input_loop())
|
||||
return err;
|
||||
|
||||
if (return_code == entries.size() && !newpos_head)
|
||||
return selection_code::new_save;
|
||||
if (return_code >= 0 && newpos_head)
|
||||
return return_code - 1;
|
||||
|
||||
return return_code;
|
||||
}
|
||||
|
||||
void update() override
|
||||
{
|
||||
m_time_thingy->set_text(date_time::current_time());
|
||||
static_cast<label*>(m_time_thingy.get())->auto_resize();
|
||||
}
|
||||
s32 show(std::vector<SaveDataEntry>& save_entries, u32 op, vm::ptr<CellSaveDataListSet> listSet);
|
||||
};
|
||||
|
||||
struct message_dialog : public user_interface
|
||||
@ -771,300 +539,20 @@ namespace rsx
|
||||
std::unique_ptr<image_info> background_image;
|
||||
|
||||
public:
|
||||
message_dialog(bool use_custom_background = false)
|
||||
{
|
||||
background.set_size(1280, 720);
|
||||
background.back_color.a = 0.85f;
|
||||
message_dialog(bool use_custom_background = false);
|
||||
|
||||
text_display.set_size(1100, 40);
|
||||
text_display.set_pos(90, 364);
|
||||
text_display.set_font("Arial", 16);
|
||||
text_display.align_text(overlay_element::text_align::center);
|
||||
text_display.set_wrap_text(true);
|
||||
text_display.back_color.a = 0.f;
|
||||
compiled_resource get_compiled() override;
|
||||
|
||||
bottom_bar.back_color = color4f(1.f, 1.f, 1.f, 1.f);
|
||||
bottom_bar.set_size(1200, 2);
|
||||
bottom_bar.set_pos(40, 400);
|
||||
void on_button_pressed(pad_button button_press) override;
|
||||
|
||||
progress_1.set_size(800, 4);
|
||||
progress_2.set_size(800, 4);
|
||||
progress_1.back_color = color4f(0.25f, 0.f, 0.f, 0.85f);
|
||||
progress_2.back_color = color4f(0.25f, 0.f, 0.f, 0.85f);
|
||||
error_code show(const std::string& text, const MsgDialogType& type, std::function<void(s32 status)> on_close);
|
||||
|
||||
btn_ok.set_text("Yes");
|
||||
btn_ok.set_size(140, 30);
|
||||
btn_ok.set_pos(545, 420);
|
||||
btn_ok.set_font("Arial", 16);
|
||||
|
||||
btn_cancel.set_text("No");
|
||||
btn_cancel.set_size(140, 30);
|
||||
btn_cancel.set_pos(685, 420);
|
||||
btn_cancel.set_font("Arial", 16);
|
||||
|
||||
if (g_cfg.sys.enter_button_assignment == enter_button_assign::circle)
|
||||
{
|
||||
btn_ok.set_image_resource(resource_config::standard_image_resource::circle);
|
||||
btn_cancel.set_image_resource(resource_config::standard_image_resource::cross);
|
||||
}
|
||||
else
|
||||
{
|
||||
btn_ok.set_image_resource(resource_config::standard_image_resource::cross);
|
||||
btn_cancel.set_image_resource(resource_config::standard_image_resource::circle);
|
||||
}
|
||||
|
||||
if (use_custom_background)
|
||||
{
|
||||
auto icon_path = Emu.GetSfoDir() + "/PIC1.PNG";
|
||||
if (!fs::exists(icon_path))
|
||||
{
|
||||
// Fallback path
|
||||
icon_path = Emu.GetSfoDir() + "/ICON0.PNG";
|
||||
}
|
||||
|
||||
if (fs::exists(icon_path))
|
||||
{
|
||||
background_image = std::make_unique<image_info>(icon_path.c_str());
|
||||
if (background_image->data)
|
||||
{
|
||||
f32 color = (100 - g_cfg.video.shader_preloading_dialog.darkening_strength) / 100.f;
|
||||
background_poster.fore_color = color4f(color, color, color, 1.);
|
||||
background.back_color.a = 0.f;
|
||||
|
||||
background_poster.set_size(1280, 720);
|
||||
background_poster.set_raw_image(background_image.get());
|
||||
background_poster.set_blur_strength((u8)g_cfg.video.shader_preloading_dialog.blur_strength);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return_code = CELL_MSGDIALOG_BUTTON_NONE;
|
||||
}
|
||||
|
||||
compiled_resource get_compiled() override
|
||||
{
|
||||
compiled_resource result;
|
||||
|
||||
if (background_image && background_image->data)
|
||||
{
|
||||
result.add(background_poster.get_compiled());
|
||||
}
|
||||
|
||||
result.add(background.get_compiled());
|
||||
result.add(text_display.get_compiled());
|
||||
|
||||
if (num_progress_bars > 0)
|
||||
{
|
||||
result.add(progress_1.get_compiled());
|
||||
}
|
||||
|
||||
if (num_progress_bars > 1)
|
||||
{
|
||||
result.add(progress_2.get_compiled());
|
||||
}
|
||||
|
||||
if (interactive)
|
||||
{
|
||||
if (!num_progress_bars)
|
||||
result.add(bottom_bar.get_compiled());
|
||||
|
||||
if (!cancel_only)
|
||||
result.add(btn_ok.get_compiled());
|
||||
|
||||
if (!ok_only)
|
||||
result.add(btn_cancel.get_compiled());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void on_button_pressed(pad_button button_press) override
|
||||
{
|
||||
switch (button_press)
|
||||
{
|
||||
case pad_button::cross:
|
||||
{
|
||||
if (ok_only)
|
||||
{
|
||||
return_code = CELL_MSGDIALOG_BUTTON_OK;
|
||||
}
|
||||
else if (cancel_only)
|
||||
{
|
||||
// Do not accept for cancel-only dialogs
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
return_code = CELL_MSGDIALOG_BUTTON_YES;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case pad_button::circle:
|
||||
{
|
||||
if (ok_only)
|
||||
{
|
||||
// Ignore cancel operation for Ok-only
|
||||
return;
|
||||
}
|
||||
else if (cancel_only)
|
||||
{
|
||||
return_code = CELL_MSGDIALOG_BUTTON_ESCAPE;
|
||||
}
|
||||
else
|
||||
{
|
||||
return_code = CELL_MSGDIALOG_BUTTON_NO;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
close();
|
||||
}
|
||||
|
||||
error_code show(const std::string& text, const MsgDialogType &type, std::function<void(s32 status)> on_close)
|
||||
{
|
||||
num_progress_bars = type.progress_bar_count;
|
||||
if (num_progress_bars)
|
||||
{
|
||||
u16 offset = 58;
|
||||
progress_1.set_pos(240, 412);
|
||||
|
||||
if (num_progress_bars > 1)
|
||||
{
|
||||
progress_2.set_pos(240, 462);
|
||||
offset = 98;
|
||||
}
|
||||
|
||||
// Push the other stuff down
|
||||
bottom_bar.translate(0, offset);
|
||||
btn_ok.translate(0, offset);
|
||||
btn_cancel.translate(0, offset);
|
||||
}
|
||||
|
||||
text_display.set_text(utf8_to_ascii8(text));
|
||||
|
||||
u16 text_w, text_h;
|
||||
text_display.measure_text(text_w, text_h);
|
||||
text_display.translate(0, -(text_h - 16));
|
||||
|
||||
switch (type.button_type.unshifted())
|
||||
{
|
||||
case CELL_MSGDIALOG_TYPE_BUTTON_TYPE_NONE:
|
||||
interactive = !type.disable_cancel;
|
||||
if (interactive)
|
||||
{
|
||||
btn_cancel.set_pos(585, btn_cancel.y);
|
||||
btn_cancel.set_text("Cancel");
|
||||
cancel_only = true;
|
||||
}
|
||||
break;
|
||||
case CELL_MSGDIALOG_TYPE_BUTTON_TYPE_OK:
|
||||
btn_ok.set_pos(600, btn_ok.y);
|
||||
btn_ok.set_text("OK");
|
||||
interactive = true;
|
||||
ok_only = true;
|
||||
break;
|
||||
case CELL_MSGDIALOG_TYPE_BUTTON_TYPE_YESNO:
|
||||
interactive = true;
|
||||
break;
|
||||
}
|
||||
|
||||
this->on_close = on_close;
|
||||
if (interactive)
|
||||
{
|
||||
thread_ctrl::spawn("dialog input thread", [&]
|
||||
{
|
||||
if (auto error = run_input_loop())
|
||||
{
|
||||
LOG_ERROR(RSX, "Dialog input loop exited with error code=%d", error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
u32 progress_bar_count()
|
||||
{
|
||||
return num_progress_bars;
|
||||
}
|
||||
|
||||
void progress_bar_set_taskbar_index(s32 index)
|
||||
{
|
||||
taskbar_index = index;
|
||||
}
|
||||
|
||||
error_code progress_bar_set_message(u32 index, const std::string& msg)
|
||||
{
|
||||
if (index >= num_progress_bars)
|
||||
return CELL_MSGDIALOG_ERROR_PARAM;
|
||||
|
||||
if (index == 0)
|
||||
progress_1.set_text(msg);
|
||||
else
|
||||
progress_2.set_text(msg);
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code progress_bar_increment(u32 index, f32 value)
|
||||
{
|
||||
if (index >= num_progress_bars)
|
||||
return CELL_MSGDIALOG_ERROR_PARAM;
|
||||
|
||||
if (index == 0)
|
||||
progress_1.inc(value);
|
||||
else
|
||||
progress_2.inc(value);
|
||||
|
||||
if (index == taskbar_index || taskbar_index == -1)
|
||||
Emu.GetCallbacks().handle_taskbar_progress(1, (s32)value);
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code progress_bar_reset(u32 index)
|
||||
{
|
||||
if (index >= num_progress_bars)
|
||||
return CELL_MSGDIALOG_ERROR_PARAM;
|
||||
|
||||
if (index == 0)
|
||||
progress_1.set_value(0.f);
|
||||
else
|
||||
progress_2.set_value(0.f);
|
||||
|
||||
Emu.GetCallbacks().handle_taskbar_progress(0, 0);
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code progress_bar_set_limit(u32 index, u32 limit)
|
||||
{
|
||||
if (index >= num_progress_bars)
|
||||
return CELL_MSGDIALOG_ERROR_PARAM;
|
||||
|
||||
if (index == 0)
|
||||
progress_1.set_limit((float)limit);
|
||||
else
|
||||
progress_2.set_limit((float)limit);
|
||||
|
||||
if (index == taskbar_index)
|
||||
{
|
||||
taskbar_limit = limit;
|
||||
Emu.GetCallbacks().handle_taskbar_progress(2, taskbar_limit);
|
||||
}
|
||||
else if (taskbar_index == -1)
|
||||
{
|
||||
taskbar_limit += limit;
|
||||
Emu.GetCallbacks().handle_taskbar_progress(2, taskbar_limit);
|
||||
}
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
u32 progress_bar_count();
|
||||
void progress_bar_set_taskbar_index(s32 index);
|
||||
error_code progress_bar_set_message(u32 index, const std::string& msg);
|
||||
error_code progress_bar_increment(u32 index, f32 value);
|
||||
error_code progress_bar_reset(u32 index);
|
||||
error_code progress_bar_set_limit(u32 index, u32 limit);
|
||||
};
|
||||
|
||||
struct trophy_notification : public user_interface
|
||||
@ -1078,68 +566,13 @@ namespace rsx
|
||||
std::unique_ptr<image_info> icon_info;
|
||||
|
||||
public:
|
||||
trophy_notification()
|
||||
{
|
||||
frame.set_pos(0, 0);
|
||||
frame.set_size(260, 80);
|
||||
frame.back_color.a = 0.85f;
|
||||
trophy_notification();
|
||||
|
||||
image.set_pos(8, 8);
|
||||
image.set_size(64, 64);
|
||||
image.back_color.a = 0.f;
|
||||
void update() override;
|
||||
|
||||
text_view.set_pos(85, 0);
|
||||
text_view.set_padding(0, 0, 24, 0);
|
||||
text_view.set_font("Arial", 8);
|
||||
text_view.align_text(overlay_element::text_align::center);
|
||||
text_view.back_color.a = 0.f;
|
||||
}
|
||||
compiled_resource get_compiled() override;
|
||||
|
||||
void update() override
|
||||
{
|
||||
u64 t = get_system_time();
|
||||
if (((t - creation_time) / 1000) > 7500)
|
||||
close();
|
||||
}
|
||||
|
||||
compiled_resource get_compiled() override
|
||||
{
|
||||
auto result = frame.get_compiled();
|
||||
result.add(image.get_compiled());
|
||||
result.add(text_view.get_compiled());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
s32 show(const SceNpTrophyDetails& trophy, const std::vector<uchar>& trophy_icon_buffer)
|
||||
{
|
||||
if (trophy_icon_buffer.size())
|
||||
{
|
||||
icon_info = std::make_unique<image_info>(trophy_icon_buffer);
|
||||
image.set_raw_image(icon_info.get());
|
||||
}
|
||||
|
||||
std::string trophy_message;
|
||||
switch (trophy.trophyGrade)
|
||||
{
|
||||
case SCE_NP_TROPHY_GRADE_BRONZE: trophy_message = "bronze"; break;
|
||||
case SCE_NP_TROPHY_GRADE_SILVER: trophy_message = "silver"; break;
|
||||
case SCE_NP_TROPHY_GRADE_GOLD: trophy_message = "gold"; break;
|
||||
case SCE_NP_TROPHY_GRADE_PLATINUM: trophy_message = "platinum"; break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
trophy_message = "You have earned the " + trophy_message + " trophy\n" + utf8_to_ascii8(trophy.name);
|
||||
text_view.set_text(trophy_message);
|
||||
text_view.auto_resize();
|
||||
|
||||
//Resize background to cover the text
|
||||
u16 margin_sz = text_view.x - image.w - image.x;
|
||||
frame.w = text_view.x + text_view.w + margin_sz;
|
||||
|
||||
creation_time = get_system_time();
|
||||
return CELL_OK;
|
||||
}
|
||||
s32 show(const SceNpTrophyDetails& trophy, const std::vector<uchar>& trophy_icon_buffer);
|
||||
};
|
||||
|
||||
struct shader_compile_notification : user_interface
|
||||
@ -1153,88 +586,13 @@ namespace rsx
|
||||
u64 expire_time = 0; // Time to end the prompt
|
||||
u64 urgency_ctr = 0; // How critical it is to show to the user
|
||||
|
||||
shader_compile_notification()
|
||||
{
|
||||
const u16 pos_x = g_cfg.video.shader_compilation_hint.pos_x;
|
||||
const u16 pos_y = g_cfg.video.shader_compilation_hint.pos_y;
|
||||
shader_compile_notification();
|
||||
|
||||
m_text.set_font("Arial", 16);
|
||||
m_text.set_text("Compiling shaders");
|
||||
m_text.auto_resize();
|
||||
m_text.set_pos(pos_x, pos_y);
|
||||
void update_animation(u64 t);
|
||||
void touch();
|
||||
void update() override;
|
||||
|
||||
m_text.back_color.a = 0.f;
|
||||
|
||||
for (int n = 0; n < 3; ++n)
|
||||
{
|
||||
dots[n].set_size(2, 2);
|
||||
dots[n].back_color = color4f(1.f, 1.f, 1.f, 1.f);
|
||||
dots[n].set_pos(m_text.w + pos_x + 5 + (6 * n), pos_y + 20);
|
||||
}
|
||||
|
||||
creation_time = get_system_time();
|
||||
expire_time = creation_time + 1000000;
|
||||
|
||||
// Disable forced refresh unless fps dips below 4
|
||||
min_refresh_duration_us = 250000;
|
||||
}
|
||||
|
||||
void update_animation(u64 t)
|
||||
{
|
||||
// Update rate is twice per second
|
||||
auto elapsed = t - creation_time;
|
||||
elapsed /= 500000;
|
||||
|
||||
auto old_dot = current_dot;
|
||||
current_dot = elapsed % 3;
|
||||
|
||||
if (old_dot != current_dot)
|
||||
{
|
||||
if (old_dot != 255)
|
||||
{
|
||||
dots[old_dot].set_size(2, 2);
|
||||
dots[old_dot].translate(0, 1);
|
||||
}
|
||||
|
||||
dots[current_dot].translate(0, -1);
|
||||
dots[current_dot].set_size(3, 3);
|
||||
}
|
||||
}
|
||||
|
||||
// Extends visible time by half a second. Also updates the screen
|
||||
void touch()
|
||||
{
|
||||
if (urgency_ctr == 0 || urgency_ctr > 8)
|
||||
{
|
||||
refresh();
|
||||
urgency_ctr = 0;
|
||||
}
|
||||
|
||||
expire_time = get_system_time() + 500000;
|
||||
urgency_ctr++;
|
||||
}
|
||||
|
||||
void update() override
|
||||
{
|
||||
auto current_time = get_system_time();
|
||||
if (current_time > expire_time)
|
||||
close();
|
||||
|
||||
update_animation(current_time);
|
||||
|
||||
// Usually this method is called during a draw-to-screen operation. Reset urgency ctr
|
||||
urgency_ctr = 1;
|
||||
}
|
||||
|
||||
compiled_resource get_compiled() override
|
||||
{
|
||||
auto compiled = m_text.get_compiled();
|
||||
compiled.add(dots[0].get_compiled());
|
||||
compiled.add(dots[1].get_compiled());
|
||||
compiled.add(dots[2].get_compiled());
|
||||
|
||||
return compiled;
|
||||
}
|
||||
compiled_resource get_compiled() override;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug - LLVM|x64">
|
||||
@ -304,8 +304,16 @@
|
||||
</ClCompile>
|
||||
<ClCompile Include="Emu\RSX\Null\NullGSRender.cpp" />
|
||||
<ClCompile Include="Emu\RSX\Overlays\overlays.cpp" />
|
||||
<ClCompile Include="Emu\RSX\Overlays\overlay_edit_text.cpp" />
|
||||
<ClCompile Include="Emu\RSX\Overlays\overlay_font.cpp" />
|
||||
<ClCompile Include="Emu\RSX\Overlays\overlay_list_view.cpp" />
|
||||
<ClCompile Include="Emu\RSX\Overlays\overlay_message_dialog.cpp" />
|
||||
<ClCompile Include="Emu\RSX\Overlays\overlay_osk.cpp" />
|
||||
<ClCompile Include="Emu\RSX\Overlays\overlay_perf_metrics.cpp" />
|
||||
<ClCompile Include="Emu\RSX\Overlays\overlay_progress_bar.cpp" />
|
||||
<ClCompile Include="Emu\RSX\Overlays\overlay_save_dialog.cpp" />
|
||||
<ClCompile Include="Emu\RSX\Overlays\overlay_shader_compile_notification.cpp" />
|
||||
<ClCompile Include="Emu\RSX\Overlays\overlay_trophy_notification.cpp" />
|
||||
<ClCompile Include="Emu\RSX\RSXFIFO.cpp" />
|
||||
<ClCompile Include="Emu\RSX\rsx_methods.cpp" />
|
||||
<ClCompile Include="Emu\RSX\rsx_utils.cpp" />
|
||||
|
@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
@ -782,6 +782,30 @@
|
||||
<ClCompile Include="Emu\Cell\lv2\sys_overlay.cpp">
|
||||
<Filter>Emu\Cell\lv2</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Emu\RSX\Overlays\overlay_save_dialog.cpp">
|
||||
<Filter>Emu\GPU\RSX\Overlays</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Emu\RSX\Overlays\overlay_message_dialog.cpp">
|
||||
<Filter>Emu\GPU\RSX\Overlays</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Emu\RSX\Overlays\overlay_shader_compile_notification.cpp">
|
||||
<Filter>Emu\GPU\RSX\Overlays</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Emu\RSX\Overlays\overlay_trophy_notification.cpp">
|
||||
<Filter>Emu\GPU\RSX\Overlays</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Emu\RSX\Overlays\overlay_font.cpp">
|
||||
<Filter>Emu\GPU\RSX\Overlays</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Emu\RSX\Overlays\overlay_list_view.cpp">
|
||||
<Filter>Emu\GPU\RSX\Overlays</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Emu\RSX\Overlays\overlay_edit_text.cpp">
|
||||
<Filter>Emu\GPU\RSX\Overlays</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Emu\RSX\Overlays\overlay_progress_bar.cpp">
|
||||
<Filter>Emu\GPU\RSX\Overlays</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="Crypto\aes.h">
|
||||
|
Loading…
Reference in New Issue
Block a user