From bce5e8a9363060b8dd23952c03e2c9656889b429 Mon Sep 17 00:00:00 2001 From: Ilari Liusvaara Date: Fri, 3 May 2013 15:39:27 +0300 Subject: [PATCH 1/2] Movie editor: Backport UTF-32 stuff from master Makes it easier to change the movie editor code by reducing incompatiblities between rr1 and rr2. --- include/library/string.hpp | 2 + include/library/utf8.hpp | 32 ++++++ include/platform/wxwidgets/platform.hpp | 1 + include/platform/wxwidgets/textrender.hpp | 1 + src/library/utf8.cpp | 29 +++++ src/platform/wxwidgets/editor-movie.cpp | 133 ++++++++-------------- src/platform/wxwidgets/main.cpp | 5 + src/platform/wxwidgets/textrender.cpp | 19 ++-- 8 files changed, 123 insertions(+), 99 deletions(-) diff --git a/include/library/string.hpp b/include/library/string.hpp index 403cf6e7..a70decee 100644 --- a/include/library/string.hpp +++ b/include/library/string.hpp @@ -6,6 +6,7 @@ #include #include #include +#include "utf8.hpp" /** * Strip trailing CR if any. @@ -30,6 +31,7 @@ class stringfmt public: stringfmt() {} std::string str() { return x.str(); } + std::u32string str32() { return to_u32string(x.str()); } template stringfmt& operator<<(const T& y) { x << y; return *this; } void throwex() { throw std::runtime_error(x.str()); } private: diff --git a/include/library/utf8.hpp b/include/library/utf8.hpp index fb718ccf..9c05a8a7 100644 --- a/include/library/utf8.hpp +++ b/include/library/utf8.hpp @@ -1,6 +1,7 @@ #ifndef _library__utf8__hpp__included__ #define _library__utf8__hpp__included__ +#include #include #include #include @@ -27,4 +28,35 @@ int32_t utf8_parse_byte(int ch, uint16_t& state) throw(); */ size_t utf8_strlen(const std::string& str) throw(); +/** + * Transform UTF-8 into UTF-32. + */ +std::u32string to_u32string(const std::string& utf8); + +/** + * Transform UTF-32 into UTF-8. + */ +std::string to_u8string(const std::u32string& utf32); + +/** + * Iterator copy from UTF-8 to UTF-32 + */ +template +inline void copy_from_utf8(srcitr begin, srcitr end, dstitr target) +{ + uint16_t state = utf8_initial_state; + for(srcitr i = begin; i != end; i++) { + int32_t x = utf8_parse_byte((unsigned char)*i, state); + if(x >= 0) { + *target = x; + ++target; + } + } + int32_t x = utf8_parse_byte(-1, state); + if(x >= 0) { + *target = x; + ++target; + } +} + #endif diff --git a/include/platform/wxwidgets/platform.hpp b/include/platform/wxwidgets/platform.hpp index 4af83564..03974a20 100644 --- a/include/platform/wxwidgets/platform.hpp +++ b/include/platform/wxwidgets/platform.hpp @@ -25,6 +25,7 @@ extern bool vflip_enabled; extern bool rotate_enabled; wxString towxstring(const std::string& str) throw(std::bad_alloc); +wxString towxstring(const std::u32string& str) throw(std::bad_alloc); std::string tostdstring(const wxString& str) throw(std::bad_alloc); void bring_app_foreground(); std::string pick_archive_member(wxWindow* parent, const std::string& filename) throw(std::bad_alloc); diff --git a/include/platform/wxwidgets/textrender.hpp b/include/platform/wxwidgets/textrender.hpp index ca81ccca..abcfcc11 100644 --- a/include/platform/wxwidgets/textrender.hpp +++ b/include/platform/wxwidgets/textrender.hpp @@ -29,6 +29,7 @@ struct text_framebuffer std::pair get_pixels(); void render(char* buffer); size_t write(const std::string& str, size_t w, size_t x, size_t y, uint32_t fg, uint32_t bg); + size_t write(const std::u32string& str, size_t w, size_t x, size_t y, uint32_t fg, uint32_t bg); static size_t text_width(const std::string& text); private: std::vector buffer; diff --git a/src/library/utf8.cpp b/src/library/utf8.cpp index 8239049c..2a9c28b7 100644 --- a/src/library/utf8.cpp +++ b/src/library/utf8.cpp @@ -1,3 +1,4 @@ +#include #include "utf8.hpp" namespace @@ -142,6 +143,7 @@ int32_t utf8_parse_byte(int ch, uint16_t& state) throw() return -1; } }; + return -1; } size_t utf8_strlen(const std::string& str) throw() @@ -156,6 +158,33 @@ size_t utf8_strlen(const std::string& str) throw() return r; } +std::u32string to_u32string(const std::string& utf8) +{ + std::u32string x; + x.resize(utf8_strlen(utf8)); + copy_from_utf8(utf8.begin(), utf8.end(), x.begin()); + return x; +} + +std::string to_u8string(const std::u32string& utf32) +{ + std::ostringstream s; + for(auto i : utf32) { + if(i < 0x80) + s << (unsigned char)i; + else if(i < 0x800) + s << (unsigned char)(0xC0 + (i >> 6)) << (unsigned char)(0x80 + (i & 0x3F)); + else if(i < 0x10000) + s << (unsigned char)(0xE0 + (i >> 12)) << (unsigned char)(0x80 + ((i >> 6) & 0x3F)) + << (unsigned char)(0x80 + (i & 0x3F)); + else if(i < 0x10FFFF) + s << (unsigned char)(0xF0 + (i >> 18)) << (unsigned char)(0x80 + ((i >> 12) & 0x3F)) + << (unsigned char)(0x80 + ((i >> 6) & 0x3F)) + << (unsigned char)(0x80 + (i & 0x3F)); + } + return s.str(); +} + #ifdef TEST_UTF8 #include char* format_dword(uint16_t s) diff --git a/src/platform/wxwidgets/editor-movie.cpp b/src/platform/wxwidgets/editor-movie.cpp index b9fdad71..96320269 100644 --- a/src/platform/wxwidgets/editor-movie.cpp +++ b/src/platform/wxwidgets/editor-movie.cpp @@ -11,6 +11,7 @@ #include "library/string.hpp" #include "library/utf8.hpp" +#include #include #include #include @@ -63,35 +64,35 @@ struct control_info unsigned index; //Index in poll vector. int type; //-2 => Port, -1 => Fixed, 0 => Button, 1 => axis. char ch; - std::string title; + std::u32string title; unsigned port; unsigned controller; static control_info portinfo(unsigned& p, unsigned port, unsigned controller); - static control_info fixedinfo(unsigned& p, const std::string& str); - static control_info buttoninfo(unsigned& p, char character, const std::string& title, unsigned idx); - static control_info axisinfo(unsigned& p, const std::string& title, unsigned idx); + static control_info fixedinfo(unsigned& p, const std::u32string& str); + static control_info buttoninfo(unsigned& p, char character, const std::u32string& title, unsigned idx); + static control_info axisinfo(unsigned& p, const std::u32string& title, unsigned idx); }; control_info control_info::portinfo(unsigned& p, unsigned port, unsigned controller) { control_info i; i.position_left = p; - i.reserved = utf8_strlen((stringfmt() << port << "-" << controller).str()); + i.reserved = (stringfmt() << port << "-" << controller).str32().length(); p += i.reserved; i.index = 0; i.type = -2; i.ch = 0; - i.title = ""; + i.title = U""; i.port = port; i.controller = controller; return i; } -control_info control_info::fixedinfo(unsigned& p, const std::string& str) +control_info control_info::fixedinfo(unsigned& p, const std::u32string& str) { control_info i; i.position_left = p; - i.reserved = utf8_strlen(str); + i.reserved = str.length(); p += i.reserved; i.index = 0; i.type = -1; @@ -102,7 +103,7 @@ control_info control_info::fixedinfo(unsigned& p, const std::string& str) return i; } -control_info control_info::buttoninfo(unsigned& p, char character, const std::string& title, unsigned idx) +control_info control_info::buttoninfo(unsigned& p, char character, const std::u32string& title, unsigned idx) { control_info i; i.position_left = p; @@ -117,11 +118,11 @@ control_info control_info::buttoninfo(unsigned& p, char character, const std::st return i; } -control_info control_info::axisinfo(unsigned& p, const std::string& title, unsigned idx) +control_info control_info::axisinfo(unsigned& p, const std::u32string& title, unsigned idx) { control_info i; i.position_left = p; - i.reserved = utf8_strlen(title); + i.reserved = title.length(); if(i.reserved < 6) i.reserved = 6; p += i.reserved; @@ -143,17 +144,15 @@ public: void write_index(controller_frame& f, unsigned idx, short value); uint32_t read_pollcount(pollcounter_vector& v, unsigned idx); const std::list& get_controlinfo() { return controlinfo; } - std::string line1() { return _line1; } - std::string line2() { return _line2; } + std::u32string line1() { return _line1; } + std::u32string line2() { return _line2; } size_t width() { return _width; } private: size_t _width; - std::string _line1; - std::string _line2; + std::u32string _line1; + std::u32string _line2; void format_lines(); void add_port(unsigned& c, unsigned pid, porttype_info& p); - std::string vector_to_string(const std::vector& cp); - std::vector string_to_vector(const std::string& str); std::list controlinfo; }; @@ -169,12 +168,12 @@ void frame_controls::set_types(controller_frame& f) unsigned nextc = 0; controlinfo.clear(); controlinfo.push_back(control_info::portinfo(nextp, 0, 0)); - controlinfo.push_back(control_info::buttoninfo(nextc, 'F', "Framesync", 0)); - controlinfo.push_back(control_info::buttoninfo(nextc, 'R', "Reset", 1)); + controlinfo.push_back(control_info::buttoninfo(nextc, 'F', U"Framesync", 0)); + controlinfo.push_back(control_info::buttoninfo(nextc, 'R', U"Reset", 1)); nextc++; - controlinfo.push_back(control_info::axisinfo(nextc, " rhigh", 2)); + controlinfo.push_back(control_info::axisinfo(nextc, U" rhigh", 2)); nextc++; - controlinfo.push_back(control_info::axisinfo(nextc, " rlow", 3)); + controlinfo.push_back(control_info::axisinfo(nextc, U" rlow", 3)); if(nextp > nextc) nextc = nextp; nextp = nextc; @@ -189,15 +188,15 @@ void frame_controls::add_port(unsigned& c, unsigned pid, porttype_info& p) unsigned ccount = MAX_CONTROLLERS_PER_PORT * MAX_CONTROLS_PER_CONTROLLER; auto limits = get_core_logical_controller_limits(); while(p.is_present(i)) { - controlinfo.push_back(control_info::fixedinfo(c, "│")); + controlinfo.push_back(control_info::fixedinfo(c, U"\u2502")); unsigned nextp = c; controlinfo.push_back(control_info::portinfo(nextp, pid, i + 1)); unsigned b = 0; if(p.is_analog(i)) { - controlinfo.push_back(control_info::axisinfo(c, " xaxis", 4 + ccount * pid + i * + controlinfo.push_back(control_info::axisinfo(c, U" xaxis", 4 + ccount * pid + i * MAX_CONTROLS_PER_CONTROLLER - ccount)); c++; - controlinfo.push_back(control_info::axisinfo(c, " yaxis", 5 + ccount * pid + i * + controlinfo.push_back(control_info::axisinfo(c, U" yaxis", 5 + ccount * pid + i * MAX_CONTROLS_PER_CONTROLLER - ccount)); if(p.button_symbols[0]) c++; @@ -210,7 +209,7 @@ void frame_controls::add_port(unsigned& c, unsigned pid, porttype_info& p) break; if(lbid == limits.second) lbid = 0; - std::string name = get_logical_button_name(lbid); + std::u32string name = to_u32string(get_logical_button_name(lbid)); controlinfo.push_back(control_info::buttoninfo(c, p.button_symbols[j], name, 4 + b + ccount * pid + i * MAX_CONTROLS_PER_CONTROLLER - ccount)); } @@ -255,43 +254,6 @@ uint32_t frame_controls::read_pollcount(pollcounter_vector& v, unsigned idx) return v.get_polls(idx - 4); } -std::string frame_controls::vector_to_string(const std::vector& cp) -{ - std::ostringstream s; - for(auto i : cp) { - if(i < 0x80) - s << (unsigned char)i; - else if(i < 0x800) - s << (unsigned char)(0xC0 + (i >> 6)) << (unsigned char)(0x80 + (i & 0x3F)); - else if(i < 0x10000) - s << (unsigned char)(0xE0 + (i >> 12)) << (unsigned char)(0x80 + ((i >> 6) & 0x3F)) - << (unsigned char)(0x80 + (i & 0x3F)); - else if(i < 0x10FFFF) - s << (unsigned char)(0xF0 + (i >> 18)) << (unsigned char)(0x80 + ((i >> 12) & 0x3F)) - << (unsigned char)(0x80 + ((i >> 6) & 0x3F)) - << (unsigned char)(0x80 + (i & 0x3F)); - } - return s.str(); -} - -std::vector frame_controls::string_to_vector(const std::string& str) -{ - std::vector cp; - size_t spos = 0; - size_t slen = str.length(); - uint16_t state = utf8_initial_state; - while(true) { - int ch = (spos < slen) ? (unsigned char)str[spos] : - 1; - int32_t u = utf8_parse_byte(ch, state); - if(u >= 0) - cp.push_back(u); - if(ch < 0) - break; - spos++; - } - return cp; -} - void frame_controls::format_lines() { _width = 0; @@ -299,8 +261,8 @@ void frame_controls::format_lines() if(i.position_left + i.reserved > _width) _width = i.position_left + i.reserved; } - std::vector cp1; - std::vector cp2; + std::u32string cp1; + std::u32string cp2; uint32_t off = divcnt + 1; cp1.resize(_width + divcnt + 1); cp2.resize(_width + divcnt + 1); @@ -312,23 +274,23 @@ void frame_controls::format_lines() //For every port-controller, find the least coordinate. for(auto i : controlinfo) { if(i.type == -1) { - auto _title = string_to_vector(i.title); + auto _title = i.title; std::copy(_title.begin(), _title.end(), &cp1[i.position_left + off]); } else if(i.type == -2) { - auto _title = string_to_vector((stringfmt() << i.port << "-" << i.controller).str()); + auto _title = (stringfmt() << i.port << "-" << i.controller).str32(); std::copy(_title.begin(), _title.end(), &cp1[i.position_left + off]); } } //Line2 for(auto i : controlinfo) { - auto _title = string_to_vector(i.title); + auto _title = i.title; if(i.type == -1 || i.type == 1) std::copy(_title.begin(), _title.end(), &cp2[i.position_left + off]); if(i.type == 0) cp2[i.position_left + off] = i.ch; } - _line1 = vector_to_string(cp1); - _line2 = vector_to_string(cp2); + _line1 = cp1; + _line2 = cp2; } @@ -376,8 +338,8 @@ private: uint64_t first_editable(unsigned index); uint64_t first_nextframe(); int width(controller_frame& f); - std::string render_line1(controller_frame& f); - std::string render_line2(controller_frame& f); + std::u32string render_line1(controller_frame& f); + std::u32string render_line2(controller_frame& f); void render_linen(text_framebuffer& fb, controller_frame& f, uint64_t sfn, int y); unsigned long long spos; void* prev_obj; @@ -389,8 +351,8 @@ private: wxeditor_movie* m; bool requested; text_framebuffer fb; - int movielines; - int moviepos; + uint64_t movielines; + uint64_t moviepos; unsigned new_width; unsigned new_height; std::vector pixels; @@ -461,7 +423,7 @@ wxeditor_movie::_moviepanel::~_moviepanel() throw() {} wxeditor_movie::~wxeditor_movie() throw() {} wxeditor_movie::_moviepanel::_moviepanel(wxeditor_movie* v) - : wxPanel(v, wxID_ANY, wxDefaultPosition, wxSize(100, 100)), + : wxPanel(v, wxID_ANY, wxDefaultPosition, wxSize(100, 100), wxWANTS_CHARS), information_dispatch("movieeditor-listener") { m = v; @@ -530,13 +492,13 @@ int wxeditor_movie::_moviepanel::width(controller_frame& f) return divcnt + 1 + fcontrols.width(); } -std::string wxeditor_movie::_moviepanel::render_line1(controller_frame& f) +std::u32string wxeditor_movie::_moviepanel::render_line1(controller_frame& f) { update_cache(); return fcontrols.line1(); } -std::string wxeditor_movie::_moviepanel::render_line2(controller_frame& f) +std::u32string wxeditor_movie::_moviepanel::render_line2(controller_frame& f) { update_cache(); return fcontrols.line2(); @@ -546,7 +508,6 @@ void wxeditor_movie::_moviepanel::render_linen(text_framebuffer& fb, controller_ { update_cache(); size_t fbstride = fb.get_stride(); - auto fbsize = fb.get_characters(); text_framebuffer::element* _fb = fb.get_buffer(); text_framebuffer::element e; e.bg = 0xFFFFFF; @@ -571,15 +532,13 @@ void wxeditor_movie::_moviepanel::render_linen(text_framebuffer& fb, controller_ else if(subframe_to_frame[sfn] > curframe) past = 0; bool now = (subframe_to_frame[sfn] == curframe); - int xcord = -32768; + unsigned xcord = 32768; if(pressed) xcord = press_x; for(auto i : ctrlinfo) { int rpast = past; unsigned off = divcnt + 1; - unsigned idx = i.index; - frame_controls* _fcontrols = &fcontrols; bool cselected = (xcord >= i.position_left + off && xcord < i.position_left + i.reserved + off); if(rpast == -1) { unsigned polls = fcontrols.read_pollcount(pv, i.index); @@ -950,7 +909,6 @@ void wxeditor_movie::_moviepanel::on_mouse0(unsigned x, unsigned y, bool polarit for(auto i : fcontrols.get_controlinfo()) { unsigned off = divcnt + 1; unsigned idx = i.index; - frame_controls* _fcontrols = &fcontrols; if((press_x >= i.position_left + off && press_x < i.position_left + i.reserved + off) && (x >= i.position_left + off && x < i.position_left + i.reserved + off)) { if(i.type == 0) @@ -1102,7 +1060,7 @@ void wxeditor_movie::_moviepanel::on_mouse2(unsigned x, unsigned y, bool polarit bool enable_insert_frame = false; bool enable_delete_frame = false; bool enable_delete_subframe = false; - std::string title; + std::u32string title; if(y < 3) goto outrange; if(!movb.get_movie().readonly_mode()) @@ -1133,11 +1091,11 @@ void wxeditor_movie::_moviepanel::on_mouse2(unsigned x, unsigned y, bool polarit if(press_line >= first_nextframe() && press_line < linecount) enable_delete_frame = true; if(enable_toggle_button) - menu.Append(wxID_TOGGLE, towxstring("Toggle " + title)); + menu.Append(wxID_TOGGLE, towxstring(U"Toggle " + title)); if(enable_change_axis) - menu.Append(wxID_CHANGE, towxstring("Change " + title)); + menu.Append(wxID_CHANGE, towxstring(U"Change " + title)); if(enable_change_axis && rpress_line != press_line) - menu.Append(wxID_SWEEP, towxstring("Sweep " + title)); + menu.Append(wxID_SWEEP, towxstring(U"Sweep " + title)); if(enable_toggle_button || enable_change_axis) menu.AppendSeparator(); menu.Append(wxID_INSERT_AFTER, wxT("Insert frame after"))->Enable(enable_insert_frame); @@ -1172,10 +1130,11 @@ void wxeditor_movie::_moviepanel::signal_repaint() return; auto s = m->get_scroll(); requested = true; - int lines, width, height; + uint32_t width, height; + uint64_t lines; wxeditor_movie* m2 = m; uint64_t old_cached_cffs = cached_cffs; - int prev_width, prev_height; + uint32_t prev_width, prev_height; bool done_again = false; do_again: runemufn([&lines, &width, &height, m2, this]() { diff --git a/src/platform/wxwidgets/main.cpp b/src/platform/wxwidgets/main.cpp index dee31fb3..a304d8ca 100644 --- a/src/platform/wxwidgets/main.cpp +++ b/src/platform/wxwidgets/main.cpp @@ -252,6 +252,11 @@ wxString towxstring(const std::string& str) throw(std::bad_alloc) return wxString(str.c_str(), wxConvUTF8); } +wxString towxstring(const std::u32string& str) throw(std::bad_alloc) +{ + return wxString(to_u8string(str).c_str(), wxConvUTF8); +} + std::string tostdstring(const wxString& str) throw(std::bad_alloc) { return std::string(str.mb_str(wxConvUTF8)); diff --git a/src/platform/wxwidgets/textrender.cpp b/src/platform/wxwidgets/textrender.cpp index e08c5e6e..47dc9bef 100644 --- a/src/platform/wxwidgets/textrender.cpp +++ b/src/platform/wxwidgets/textrender.cpp @@ -135,21 +135,17 @@ size_t text_framebuffer::text_width(const std::string& text) } size_t text_framebuffer::write(const std::string& str, size_t w, size_t x, size_t y, uint32_t fg, uint32_t bg) +{ + return this->write(to_u32string(str), w, x, y, fg, bg); +} + +size_t text_framebuffer::write(const std::u32string& str, size_t w, size_t x, size_t y, uint32_t fg, uint32_t bg) { size_t spos = 0; size_t slen = str.length(); size_t pused = 0; - uint16_t state = utf8_initial_state; - while(true) { - int ch = (spos < slen) ? (unsigned char)str[spos] : - 1; - int32_t u = utf8_parse_byte(ch, state); - if(u < 0) { - if(ch < 0) - break; - spos++; - continue; - } - //Okay, got u to write... + while(spos < slen) { + int32_t u = str[spos++]; const bitmap_font::glyph& g = main_font.get_glyph(u); if(x < width) { element& e = buffer[y * width + x]; @@ -159,7 +155,6 @@ size_t text_framebuffer::write(const std::string& str, size_t w, size_t x, size_ } x++; pused += (g.wide ? 2 : 1); - spos++; } while(pused < w) { //Pad with spaces. From f051aabb5792932cd8a7ce65561eac13f9b2733a Mon Sep 17 00:00:00 2001 From: Ilari Liusvaara Date: Fri, 3 May 2013 15:40:43 +0300 Subject: [PATCH 2/2] Fix compilation if size_t != uint64_t --- src/core/movie.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/movie.cpp b/src/core/movie.cpp index 97be6730..e0459b9e 100644 --- a/src/core/movie.cpp +++ b/src/core/movie.cpp @@ -574,7 +574,7 @@ void movie::adjust_frame_count(int64_t adjust) current_frame_first_subframe += count_changes(current_frame_first_subframe); } //Nobody is this stupid, right? - current_frame_first_subframe = min(current_frame_first_subframe, movie_data.size()); + current_frame_first_subframe = min(current_frame_first_subframe, static_cast(movie_data.size())); } unsigned extended_mode = 0;