Merge remote-tracking branch 'origin/rr1-maint' into rr1-maint

This commit is contained in:
Ilari Liusvaara 2013-01-25 12:35:01 +02:00
commit 1297f683e0
12 changed files with 649 additions and 100 deletions

View file

@ -1 +1 @@
1-Δ15ε3
1-Δ16

View file

@ -413,6 +413,27 @@ public:
* Call on_dumper_update on on all objects.
*/
static void do_dumper_update() throw();
/**
* Notify about changes to voice streams.
*
* Default implementation does nothing.
*/
virtual void on_voice_stream_change();
/**
* Call on_voice_stream_change on all objects.
*/
static void do_voice_stream_change() throw();
/**
* Notify about changes to subtitles.
*
* Default implementation does nothing.
*/
virtual void on_subtitle_change();
/**
* Call on_subtitle_change on all objects.
*/
static void do_subtitle_change() throw();
protected:
/**
* Call to indicate this target is interested in sound sample data.

View file

@ -2122,6 +2122,67 @@ Returns bitwise OR of 1 left shifted by bit1 places, 1 left shifted by bit2
As special value, nil argument is no-op.
\end_layout
\begin_layout Subsubsection
bit.test_any(number a, number b)
\end_layout
\begin_layout Standard
Is there a common set bit in a and b?
\end_layout
\begin_layout Subsubsection
bit.test_all(number a, number b)
\end_layout
\begin_layout Standard
Are all set bits in b also set in a?
\end_layout
\begin_layout Subsubsection
bit.popcount(number a)
\end_layout
\begin_layout Standard
Population count of a.
\end_layout
\begin_layout Subsubsection
bit.clshift(number a, number b, [number amount,[number bits]])
\end_layout
\begin_layout Standard
Does chained left shift on a, b by amount positions, assuming numbers to
be of specified number of bits.
\end_layout
\begin_layout Subsubsection
bit.crshift(number a, number b, [number amount,[number bits]])
\end_layout
\begin_layout Standard
Does chained right shift on a, b by amount positions, assuming numbers to
be of specified number of bits.
\end_layout
\begin_layout Subsubsection
bit.flagdecode(number a, number bits, [string on, [string off]])
\end_layout
\begin_layout Standard
Return string of length bits where ith character is ith character of on
if bit i is on, otherwise ith character of off.
Out of range reads give last character, or '*'/'-' if empty.
\end_layout
\begin_layout Subsubsection
bit.rflagdecode(number a, number bits, [string on, [string off]])
\end_layout
\begin_layout Standard
Like bit.flagdecode, but outputs the string in the opposite order (most significa
nt bit first).
\end_layout
\begin_layout Subsection
Table gui:
\end_layout
@ -7343,5 +7404,61 @@ Compensate for nuts bsnes superscope/justifier handling
Lua: Fix bit.extract boolean handling
\end_layout
\begin_layout Subsection
rr1-delta16
\end_layout
\begin_layout Itemize
Stop at movie end: Don't off-by-one
\end_layout
\begin_layout Itemize
Fix crash closing lsnes with voice playback active.
\end_layout
\begin_layout Itemize
Import/Export OggOpus for commentary tracks
\end_layout
\begin_layout Itemize
16-button controllers.
\end_layout
\begin_layout Itemize
Don't show nonexistent controllers in input display
\end_layout
\begin_layout Itemize
Set voice record/playback volume from UI
\end_layout
\begin_layout Itemize
Patches for gambatte SVN364.
\end_layout
\begin_layout Itemize
Load markup (if exists) even without gamepack file.
\end_layout
\begin_layout Itemize
Screen rotation & flipping
\end_layout
\begin_layout Itemize
Lua: Some new bit functions
\end_layout
\begin_layout Itemize
Auto-refresh voice streams on change.
\end_layout
\begin_layout Itemize
Auto-refresh subtitles on change & new subtitle editor.
\end_layout
\begin_layout Itemize
Fix music volume adjustment.
\end_layout
\end_body
\end_document

View file

@ -1047,6 +1047,43 @@ Returns bitwise OR of 1 left shifted by bit1 places, 1 left
shifted by bit2 places and so on. As special value, nil argument
is no-op.
8.2.12 bit.test_any(number a, number b)
Is there a common set bit in a and b?
8.2.13 bit.test_all(number a, number b)
Are all set bits in b also set in a?
8.2.14 bit.popcount(number a)
Population count of a.
8.2.15 bit.clshift(number a, number b, [number amount,[number
bits]])
Does chained left shift on a, b by amount positions, assuming
numbers to be of specified number of bits.
8.2.16 bit.crshift(number a, number b, [number amount,[number
bits]])
Does chained right shift on a, b by amount positions, assuming
numbers to be of specified number of bits.
8.2.17 bit.flagdecode(number a, number bits, [string on, [string
off]])
Return string of length bits where ith character is ith character
of on if bit i is on, otherwise ith character of off. Out of
range reads give last character, or '*'/'-' if empty.
8.2.18 bit.rflagdecode(number a, number bits, [string on, [string
off]])
Like bit.flagdecode, but outputs the string in the opposite order
(most significant bit first).
8.3 Table gui:
Most of these functions can only be called in on_paint and
@ -3616,3 +3653,31 @@ set-axis joystick0axis19 disabled
• Lua: Fix bit.extract boolean handling
18.76 rr1-delta16
• Stop at movie end: Don't off-by-one
• Fix crash closing lsnes with voice playback active.
• Import/Export OggOpus for commentary tracks
• 16-button controllers.
• Don't show nonexistent controllers in input display
• Set voice record/playback volume from UI
• Patches for gambatte SVN364.
• Load markup (if exists) even without gamepack file.
• Screen rotation & flipping
• Lua: Some new bit functions
• Auto-refresh voice streams on change.
• Auto-refresh subtitles on change & new subtitle editor.
• Fix music volume adjustment.

View file

@ -538,3 +538,35 @@ void information_dispatch::do_dumper_update() throw()
END_EH_BLOCK(i, "on_dumper_update");
}
}
void information_dispatch::on_voice_stream_change()
{
//Do nothing.
}
void information_dispatch::do_voice_stream_change() throw()
{
if(in_global_ctors())
return;
for(auto& i : dispatch()) {
START_EH_BLOCK
i->on_voice_stream_change();
END_EH_BLOCK(i, "on_voice_stream_change");
}
}
void information_dispatch::on_subtitle_change()
{
//Do nothing.
}
void information_dispatch::do_subtitle_change() throw()
{
if(in_global_ctors())
return;
for(auto& i : dispatch()) {
START_EH_BLOCK
i->on_subtitle_change();
END_EH_BLOCK(i, "on_subtitle_change");
}
}

View file

@ -9,6 +9,7 @@
#include "library/ogg.hpp"
#include "core/audioapi.hpp"
#include "core/command.hpp"
#include "core/dispatch.hpp"
#include "core/framerate.hpp"
#include "core/inthread.hpp"
#include "core/keymapper.hpp"
@ -1669,6 +1670,7 @@ out:
messages << "Can't add stream: " << e.what() << std::endl;
active_stream->put_ref();
}
information_dispatch::do_voice_stream_change();
} else
active_stream->put_ref();
active_stream = NULL;
@ -1872,6 +1874,7 @@ namespace
}
s->put_ref();
current_collection->delete_stream(id);
information_dispatch::do_voice_stream_change();
messages << "Deleted stream #" << id << "." << std::endl;
});
@ -1921,6 +1924,7 @@ namespace
}
s->put_ref();
current_collection->alter_stream_timebase(id, tbase);
information_dispatch::do_voice_stream_change();
messages << "Timebase of stream #" << id << " is now " << (tbase / 48000.0) << "s"
<< std::endl;
});
@ -1953,6 +1957,7 @@ namespace
throw;
}
st->unlock(); //Not locked.
information_dispatch::do_voice_stream_change();
messages << "Imported stream (" << st->length() / 48000.0 << "s) as ID #" << id << std::endl;
}
@ -2058,6 +2063,7 @@ namespace
if(current_collection)
delete current_collection;
current_collection = newc;
information_dispatch::do_voice_stream_change();
messages << "Loaded '" << x << "'" << std::endl;
});
@ -2068,6 +2074,7 @@ namespace
if(current_collection)
delete current_collection;
current_collection = NULL;
information_dispatch::do_voice_stream_change();
messages << "Collection unloaded" << std::endl;
});
@ -2160,6 +2167,7 @@ uint64_t voicesub_import_stream(uint64_t ts, const std::string& filename, extern
throw;
}
st->unlock(); //Not locked.
information_dispatch::do_voice_stream_change();
return id;
}
@ -2169,6 +2177,7 @@ void voicesub_delete_stream(uint64_t id)
if(!current_collection)
throw std::runtime_error("No collection loaded");
current_collection->delete_stream(id);
information_dispatch::do_voice_stream_change();
}
void voicesub_export_superstream(const std::string& filename)
@ -2192,6 +2201,7 @@ void voicesub_load_collection(const std::string& filename)
if(current_collection)
delete current_collection;
current_collection = newc;
information_dispatch::do_voice_stream_change();
}
void voicesub_unload_collection()
@ -2200,6 +2210,7 @@ void voicesub_unload_collection()
if(current_collection)
delete current_collection;
current_collection = NULL;
information_dispatch::do_voice_stream_change();
}
void voicesub_alter_timebase(uint64_t id, uint64_t ts)
@ -2208,6 +2219,7 @@ void voicesub_alter_timebase(uint64_t id, uint64_t ts)
if(!current_collection)
throw std::runtime_error("No collection loaded");
current_collection->alter_stream_timebase(id, ts);
information_dispatch::do_voice_stream_change();
}
double voicesub_ts_seconds(uint64_t ts)

View file

@ -1,4 +1,6 @@
#include "core/command.hpp"
#include "core/dispatch.hpp"
#include "core/framebuffer.hpp"
#include "core/moviedata.hpp"
#include "core/subtitles.hpp"
#include "core/window.hpp"
@ -109,6 +111,8 @@ namespace
our_movie.subtitles.erase(key);
else
our_movie.subtitles[key] = s_unescape(text);
information_dispatch::do_subtitle_change();
redraw_framebuffer();
});
function_ptr_command<> list_subtitle("list-subtitle", "List the subtitles",
@ -229,4 +233,6 @@ void set_subtitle_for(uint64_t f, uint64_t l, const std::string& x)
our_movie.subtitles.erase(key);
else
our_movie.subtitles[key] = s_unescape(x);
information_dispatch::do_subtitle_change();
redraw_framebuffer();
}

View file

@ -639,8 +639,6 @@ void platform::queue(const std::string& c) throw(std::bad_alloc)
void platform::queue(void (*f)(void* arg), void* arg, bool sync) throw(std::bad_alloc)
{
if(sync && queue_synchronous_fn_warning)
std::cerr << "WARNING: Synchronous queue in callback to UI, this may deadlock!" << std::endl;
init_threading();
mutex::holder h(*queue_lock);
++next_function;

View file

@ -1,4 +1,5 @@
#include "lua/internal.hpp"
#include "library/minmax.hpp"
#define BITWISE_BITS 48
#define BITWISE_MASK ((1ULL << (BITWISE_BITS)) - 1)
@ -133,6 +134,111 @@ namespace
return 1;
});
function_ptr_luafun lua_testany("bit.test_any", [](lua_State* LS, const std::string& fname) -> int {
uint64_t a = get_numeric_argument<uint64_t>(LS, 1, fname.c_str());
uint64_t b = get_numeric_argument<uint64_t>(LS, 2, fname.c_str());
lua_pushboolean(LS, (a & b) != 0);
return 1;
});
function_ptr_luafun lua_testall("bit.test_all", [](lua_State* LS, const std::string& fname) -> int {
uint64_t a = get_numeric_argument<uint64_t>(LS, 1, fname.c_str());
uint64_t b = get_numeric_argument<uint64_t>(LS, 2, fname.c_str());
lua_pushboolean(LS, (a & b) == b);
return 1;
});
int poptable[] = {0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4};
int popcount(uint64_t x)
{
int c = 0;
for(unsigned i = 0; i < 16; i++) {
c += poptable[x & 15];
x >>= 4;
}
return c;
}
function_ptr_luafun lua_popcount("bit.popcount", [](lua_State* LS, const std::string& fname) -> int {
uint64_t a = get_numeric_argument<uint64_t>(LS, 1, fname.c_str());
lua_pushnumber(LS,popcount(a));
return 1;
});
function_ptr_luafun lua_clshift("bit.clshift", [](lua_State* LS, const std::string& fname) -> int {
unsigned amount = 1;
unsigned bits = 48;
uint64_t a = get_numeric_argument<uint64_t>(LS, 1, fname.c_str());
uint64_t b = get_numeric_argument<uint64_t>(LS, 2, fname.c_str());
get_numeric_argument(LS, 3, amount, fname.c_str());
get_numeric_argument(LS, 4, bits, fname.c_str());
uint64_t mask = ((1ULL << bits) - 1);
a &= mask;
b &= mask;
a <<= amount;
a &= mask;
a |= (b >> (bits - amount));
b <<= amount;
b &= mask;
lua_pushnumber(LS, a);
lua_pushnumber(LS, b);
return 2;
});
function_ptr_luafun lua_crshift("bit.crshift", [](lua_State* LS, const std::string& fname) -> int {
unsigned amount = 1;
unsigned bits = 48;
uint64_t a = get_numeric_argument<uint64_t>(LS, 1, fname.c_str());
uint64_t b = get_numeric_argument<uint64_t>(LS, 2, fname.c_str());
get_numeric_argument(LS, 3, amount, fname.c_str());
get_numeric_argument(LS, 4, bits, fname.c_str());
uint64_t mask = ((1ULL << bits) - 1);
a &= mask;
b &= mask;
b >>= amount;
b |= (a << (bits - amount));
b &= mask;
a >>= amount;
lua_pushnumber(LS, a);
lua_pushnumber(LS, b);
return 2;
});
int flagdecode_core(lua_State* LS, const std::string& fname, bool reverse)
{
uint64_t a = get_numeric_argument<uint64_t>(LS, 1, fname.c_str());
uint64_t b = get_numeric_argument<uint64_t>(LS, 2, fname.c_str());
std::string on, off;
if(lua_type(LS, 3) == LUA_TSTRING)
on = get_string_argument(LS, 3, fname.c_str());
if(lua_type(LS, 4) == LUA_TSTRING)
off = get_string_argument(LS, 4, fname.c_str());
size_t onl = on.length();
size_t offl = off.length();
char onc = onl ? on[onl - 1] : '*';
char offc = offl ? off[offl - 1] : '-';
char buffer[65];
unsigned i;
size_t bias = min(b, (uint64_t)64) - 1;
for(i = 0; i < 64 && i < b; i++) {
char onc2 = (i < onl) ? on[i] : onc;
char offc2 = (i < offl) ? off[i] : offc;
buffer[reverse ? (bias - i) : i] = ((a >> i) & 1) ? onc2 : offc2;
}
buffer[i] = '\0';
lua_pushstring(LS, buffer);
return 1;
}
function_ptr_luafun lua_flagdecode("bit.flagdecode", [](lua_State* LS, const std::string& fname) -> int {
return flagdecode_core(LS, fname, false);
});
function_ptr_luafun lua_rflagdecode("bit.rflagdecode", [](lua_State* LS, const std::string& fname) -> int {
return flagdecode_core(LS, fname, true);
});
lua_symmetric_bitwise<combine_none, BITWISE_MASK> bit_none("bit.none");
lua_symmetric_bitwise<combine_none, BITWISE_MASK> bit_bnot("bit.bnot");
lua_symmetric_bitwise<combine_any, 0> bit_any("bit.any");

View file

@ -10,57 +10,204 @@
#include <wx/radiobut.h>
#include "library/string.hpp"
#include "core/dispatch.hpp"
#include "core/emucore.hpp"
#include "core/subtitles.hpp"
class wxeditor_subtitles : public wxDialog
namespace
{
struct subdata
{
uint64_t first;
uint64_t last;
std::string text;
};
}
class wxeditor_subtitles : public wxFrame
{
public:
wxeditor_subtitles(wxWindow* parent);
~wxeditor_subtitles() throw();
bool ShouldPreventAppExit() const;
void on_subtitles_change(wxCommandEvent& e);
void on_ok(wxCommandEvent& e);
void on_cancel(wxCommandEvent& e);
void on_change(wxCommandEvent& e);
void on_add(wxCommandEvent& e);
void on_edit(wxCommandEvent& e);
void on_delete(wxCommandEvent& e);
void on_close(wxCommandEvent& e);
void on_wclose(wxCloseEvent& e);
void refresh();
private:
wxTextCtrl* subs;
wxButton* ok;
wxButton* cancel;
struct refresh_listener : public information_dispatch
{
refresh_listener(wxeditor_subtitles* v)
: information_dispatch("subtitle-editor-change-listener")
{
obj = v;
}
void on_subtitle_change()
{
wxeditor_subtitles* _obj = obj;
runuifun([_obj]() -> void { _obj->refresh(); });
}
wxeditor_subtitles* obj;
};
bool closing;
wxListBox* subs;
wxTextCtrl* subtext;
wxButton* add;
wxButton* edit;
wxButton* _delete;
wxButton* close;
std::map<int, subdata> subtexts;
refresh_listener* rlistener;
};
namespace
{
class wxeditor_subtitles_subtitle : public wxDialog
{
public:
wxeditor_subtitles_subtitle(wxWindow* parent, subdata d);
void on_change(wxCommandEvent& e);
void on_cancel(wxCommandEvent& e);
void on_ok(wxCommandEvent& e);
subdata get_result();
private:
wxTextCtrl* first;
wxTextCtrl* last;
wxTextCtrl* text;
wxButton* ok;
wxButton* cancel;
};
wxeditor_subtitles_subtitle::wxeditor_subtitles_subtitle(wxWindow* parent, subdata d)
: wxDialog(parent, wxID_ANY, wxT("lsnes: Edit subtitle"), wxDefaultPosition, wxSize(-1, -1))
{
Centre();
wxFlexGridSizer* top_s = new wxFlexGridSizer(2, 1, 0, 0);
SetSizer(top_s);
wxFlexGridSizer* data_s = new wxFlexGridSizer(3, 2, 0, 0);
data_s->Add(new wxStaticText(this, wxID_ANY, wxT("First frame:")));
data_s->Add(first = new wxTextCtrl(this, wxID_ANY, wxT(""), wxDefaultPosition, wxSize(200, -1)));
data_s->Add(new wxStaticText(this, wxID_ANY, wxT("Last frame:")));
data_s->Add(last = new wxTextCtrl(this, wxID_ANY, wxT(""), wxDefaultPosition, wxSize(200, -1)));
data_s->Add(new wxStaticText(this, wxID_ANY, wxT("Text:")));
data_s->Add(text = new wxTextCtrl(this, wxID_ANY, wxT(""), wxDefaultPosition, wxSize(400, -1)));
top_s->Add(data_s, 1, wxGROW);
first->Connect(wxEVT_COMMAND_TEXT_UPDATED,
wxCommandEventHandler(wxeditor_subtitles_subtitle::on_change), NULL, this);
last->Connect(wxEVT_COMMAND_TEXT_UPDATED,
wxCommandEventHandler(wxeditor_subtitles_subtitle::on_change), NULL, this);
text->Connect(wxEVT_COMMAND_TEXT_UPDATED,
wxCommandEventHandler(wxeditor_subtitles_subtitle::on_change), NULL, this);
wxBoxSizer* pbutton_s = new wxBoxSizer(wxHORIZONTAL);
pbutton_s->AddStretchSpacer();
pbutton_s->Add(ok = new wxButton(this, wxID_ANY, wxT("OK")), 0, wxGROW);
pbutton_s->Add(cancel = new wxButton(this, wxID_ANY, wxT("Cancel")), 0, wxGROW);
ok->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(wxeditor_subtitles_subtitle::on_ok),
NULL, this);
cancel->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
wxCommandEventHandler(wxeditor_subtitles_subtitle::on_cancel), NULL, this);
top_s->Add(pbutton_s, 0, wxGROW);
pbutton_s->SetSizeHints(this);
top_s->SetSizeHints(this);
first->SetValue(towxstring((stringfmt() << d.first).str()));
last->SetValue(towxstring((stringfmt() << d.last).str()));
text->SetValue(towxstring(d.text));
Fit();
}
void wxeditor_subtitles_subtitle::on_change(wxCommandEvent& e)
{
bool valid = true;
std::string _first = tostdstring(first->GetValue());
std::string _last = tostdstring(last->GetValue());
std::string _text = tostdstring(text->GetValue());
valid = valid && regex_match("[0-9]{1,19}", _first);
valid = valid && regex_match("[0-9]{1,19}", _last);
valid = valid && (_text != "");
ok->Enable(valid);
}
void wxeditor_subtitles_subtitle::on_cancel(wxCommandEvent& e)
{
EndModal(wxID_CANCEL);
}
void wxeditor_subtitles_subtitle::on_ok(wxCommandEvent& e)
{
EndModal(wxID_OK);
}
subdata wxeditor_subtitles_subtitle::get_result()
{
subdata d;
d.first = parse_value<uint64_t>(tostdstring(first->GetValue()));
d.last = parse_value<uint64_t>(tostdstring(last->GetValue()));
d.text = tostdstring(text->GetValue());
return d;
}
bool edit_subtext(wxWindow* w, struct subdata& d)
{
wxeditor_subtitles_subtitle* editor = NULL;
try {
editor = new wxeditor_subtitles_subtitle(w, d);
int ret = editor->ShowModal();
if(ret == wxID_OK)
d = editor->get_result();
} catch(...) {
}
if(editor)
editor->Destroy();
}
}
wxeditor_subtitles::wxeditor_subtitles(wxWindow* parent)
: wxDialog(parent, wxID_ANY, wxT("lsnes: Edit subtitles"), wxDefaultPosition, wxSize(-1, -1))
: wxFrame(NULL, wxID_ANY, wxT("lsnes: Edit subtitles"), wxDefaultPosition, wxSize(-1, -1))
{
closing = false;
Centre();
wxFlexGridSizer* top_s = new wxFlexGridSizer(2, 1, 0, 0);
SetSizer(top_s);
top_s->Add(subs = new wxTextCtrl(this, wxID_ANY, wxT(""), wxDefaultPosition, wxSize(400, 300),
wxTE_MULTILINE), 1, wxGROW);
subs->Connect(wxEVT_COMMAND_TEXT_UPDATED,
wxCommandEventHandler(wxeditor_subtitles::on_subtitles_change), NULL, this);
//TODO: Apppropriate controls.
top_s->Add(subs = new wxListBox(this, wxID_ANY, wxDefaultPosition, wxSize(300, 400), 0, NULL,
wxLB_SINGLE), 1, wxGROW);
subs->Connect(wxEVT_COMMAND_LISTBOX_SELECTED,
wxCommandEventHandler(wxeditor_subtitles::on_change), NULL, this);
wxBoxSizer* pbutton_s = new wxBoxSizer(wxHORIZONTAL);
pbutton_s->AddStretchSpacer();
pbutton_s->Add(ok = new wxButton(this, wxID_ANY, wxT("OK")), 0, wxGROW);
pbutton_s->Add(cancel = new wxButton(this, wxID_ANY, wxT("Cancel")), 0, wxGROW);
ok->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(wxeditor_subtitles::on_ok), NULL, this);
cancel->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(wxeditor_subtitles::on_cancel), NULL,
pbutton_s->Add(add = new wxButton(this, wxID_ANY, wxT("Add")), 0, wxGROW);
pbutton_s->Add(edit = new wxButton(this, wxID_ANY, wxT("Edit")), 0, wxGROW);
pbutton_s->Add(_delete = new wxButton(this, wxID_ANY, wxT("Delete")), 0, wxGROW);
pbutton_s->Add(close = new wxButton(this, wxID_ANY, wxT("Close")), 0, wxGROW);
add->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(wxeditor_subtitles::on_add), NULL, this);
edit->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(wxeditor_subtitles::on_edit), NULL, this);
_delete->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(wxeditor_subtitles::on_delete), NULL,
this);
close->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(wxeditor_subtitles::on_close), NULL, this);
top_s->Add(pbutton_s, 0, wxGROW);
pbutton_s->SetSizeHints(this);
top_s->SetSizeHints(this);
Fit();
rlistener = new refresh_listener(this);
refresh();
}
std::string txt = "";
runemufn([&txt]() {
for(auto i : get_subtitles()) {
std::ostringstream line;
line << i.first << " " << i.second << " " << get_subtitle_for(i.first, i.second) << std::endl;
txt = txt + line.str();
}
});
subs->SetValue(towxstring(txt));
wxeditor_subtitles::~wxeditor_subtitles() throw()
{
delete rlistener;
}
bool wxeditor_subtitles::ShouldPreventAppExit() const
@ -68,76 +215,107 @@ bool wxeditor_subtitles::ShouldPreventAppExit() const
return false;
}
void wxeditor_subtitles::on_subtitles_change(wxCommandEvent& e)
void wxeditor_subtitles::on_close(wxCommandEvent& e)
{
std::string txt = tostdstring(subs->GetValue());
std::string line;
while(txt != "") {
extract_token(txt, line, "\n");
istrip_CR(line);
if(line == "")
continue;
auto r = regex("([0-9]+)[ \t]+([0-9]+)[ \t]+(.+)", line);
if(!r) {
ok->Disable();
return;
}
try {
parse_value<uint64_t>(r[1]);
parse_value<uint64_t>(r[2]);
} catch(...) {
ok->Disable();
return;
}
}
ok->Enable();
closing = true;
Destroy();
}
void wxeditor_subtitles::on_ok(wxCommandEvent& e)
void wxeditor_subtitles::on_wclose(wxCloseEvent& e)
{
std::map<std::pair<uint64_t, uint64_t>, std::string> data;
runemufn([&data]() {
for(auto i : get_subtitles())
data[std::make_pair(i.first, i.second)] = "";
});
std::string txt = tostdstring(subs->GetValue());
std::string line;
while(txt != "") {
extract_token(txt, line, "\n");
istrip_CR(line);
if(line == "")
continue;
auto r = regex("([0-9]+)[ \t]+([0-9]+)[ \t]+(.+)", line);
if(!r)
return;
try {
uint64_t f = parse_value<uint64_t>(r[1]);
uint64_t l = parse_value<uint64_t>(r[2]);
data[std::make_pair(f, l)] = r[3];
} catch(...) {
return;
}
}
runemufn([&data]() {
for(auto i : data)
set_subtitle_for(i.first.first, i.first.second, i.second);
});
EndModal(wxID_OK);
closing = true;
}
void wxeditor_subtitles::on_cancel(wxCommandEvent& e)
void wxeditor_subtitles::refresh()
{
EndModal(wxID_CANCEL);
if(closing)
return;
std::map<std::pair<uint64_t, uint64_t>, std::string> _subtitles;
runemufn([&_subtitles]() -> void {
auto keys = get_subtitles();
for(auto i : keys)
_subtitles[i] = get_subtitle_for(i.first, i.second);
});
int sel = subs->GetSelection();
bool found = (subtexts.count(sel) != 0);
subdata matching = subtexts[sel];
subs->Clear();
unsigned num = 0;
subtexts.clear();
for(auto i : _subtitles) {
subdata newdata;
newdata.first = i.first.first;
newdata.last = i.first.second;
newdata.text = i.second;
subtexts[num++] = newdata;
std::string s = (stringfmt() << i.first.first << "-" << i.first.second << ": " << i.second).str();
subs->Append(towxstring(s));
}
for(int i = 0; i < subs->GetCount(); i++)
if(subtexts[i].first == matching.first && subtexts[i].last == matching.last)
subs->SetSelection(i);
if(subs->GetSelection() == wxNOT_FOUND && sel < subs->GetCount())
subs->SetSelection(sel);
sel = subs->GetSelection();
found = (subtexts.count(sel) != 0);
edit->Enable(found);
_delete->Enable(found);
}
void wxeditor_subtitles::on_change(wxCommandEvent& e)
{
if(closing)
return;
int sel = subs->GetSelection();
bool found = (subtexts.count(sel) != 0);
edit->Enable(found);
_delete->Enable(found);
}
void wxeditor_subtitles::on_add(wxCommandEvent& e)
{
if(closing)
return;
subdata t;
t.first = 0;
t.last = 0;
t.text = "";
if(edit_subtext(this, t))
set_subtitle_for(t.first, t.last, t.text);
}
void wxeditor_subtitles::on_edit(wxCommandEvent& e)
{
if(closing)
return;
int sel = subs->GetSelection();
if(!subtexts.count(sel))
return;
auto t = subtexts[sel];
auto old = t;
if(edit_subtext(this, t)) {
set_subtitle_for(old.first, old.last, "");
set_subtitle_for(t.first, t.last, t.text);
}
}
void wxeditor_subtitles::on_delete(wxCommandEvent& e)
{
if(closing)
return;
int sel = subs->GetSelection();
if(!subtexts.count(sel))
return;
auto t = subtexts[sel];
set_subtitle_for(t.first, t.last, "");
}
void wxeditor_subtitles_display(wxWindow* parent)
{
modal_pause_holder hld;
wxDialog* editor;
wxFrame* editor;
try {
editor = new wxeditor_subtitles(parent);
editor->ShowModal();
editor->Show();
} catch(...) {
}
editor->Destroy();
}

View file

@ -9,6 +9,7 @@
#include <wx/control.h>
#include <wx/combobox.h>
#include "core/dispatch.hpp"
#include "library/string.hpp"
#define NOTHING 0xFFFFFFFFFFFFFFFFULL
@ -22,6 +23,7 @@ class wxeditor_voicesub : public wxDialog
{
public:
wxeditor_voicesub(wxWindow* parent);
~wxeditor_voicesub() throw();
bool ShouldPreventAppExit() const;
void on_select(wxCommandEvent& e);
void on_play(wxCommandEvent& e);
@ -39,9 +41,23 @@ public:
void on_refresh(wxCommandEvent& e);
void on_close(wxCommandEvent& e);
void on_wclose(wxCloseEvent& e);
private:
bool closing;
void refresh();
private:
struct refresh_listener : public information_dispatch
{
refresh_listener(wxeditor_voicesub* v)
: information_dispatch("voicesub-editor-change-listner")
{
obj = v;
}
void on_voice_stream_change()
{
wxeditor_voicesub* _obj = obj;
runuifun([_obj]() -> void { _obj->refresh(); });
}
wxeditor_voicesub* obj;
};
bool closing;
uint64_t get_id();
std::map<int, uint64_t> smap;
wxListBox* subtitles;
@ -59,6 +75,8 @@ private:
wxButton* unloadbutton;
wxButton* refreshbutton;
wxButton* closebutton;
refresh_listener* rlistener;
};
wxeditor_voicesub::wxeditor_voicesub(wxWindow* parent)
@ -150,9 +168,15 @@ wxeditor_voicesub::wxeditor_voicesub(wxWindow* parent)
top_s->SetSizeHints(this);
Fit();
rlistener = new refresh_listener(this);
refresh();
}
wxeditor_voicesub::~wxeditor_voicesub() throw()
{
delete rlistener;
}
void wxeditor_voicesub::on_select(wxCommandEvent& e)
{
if(closing)
@ -177,7 +201,6 @@ void wxeditor_voicesub::on_play(wxCommandEvent& e)
} catch(std::exception& e) {
show_message_ok(this, "Error playing", e.what(), wxICON_EXCLAMATION);
}
refresh();
}
void wxeditor_voicesub::on_delete(wxCommandEvent& e)
@ -190,7 +213,6 @@ void wxeditor_voicesub::on_delete(wxCommandEvent& e)
} catch(std::exception& e) {
show_message_ok(this, "Error deleting", e.what(), wxICON_EXCLAMATION);
}
refresh();
}
void wxeditor_voicesub::on_export_o(wxCommandEvent& e)
@ -209,7 +231,6 @@ void wxeditor_voicesub::on_export_o(wxCommandEvent& e)
} catch(std::exception& e) {
show_message_ok(this, "Error exporting", e.what(), wxICON_EXCLAMATION);
}
refresh();
}
void wxeditor_voicesub::on_export_p(wxCommandEvent& e)
@ -228,7 +249,6 @@ void wxeditor_voicesub::on_export_p(wxCommandEvent& e)
} catch(std::exception& e) {
show_message_ok(this, "Error exporting", e.what(), wxICON_EXCLAMATION);
}
refresh();
}
void wxeditor_voicesub::on_export_q(wxCommandEvent& e)
@ -247,7 +267,6 @@ void wxeditor_voicesub::on_export_q(wxCommandEvent& e)
} catch(std::exception& e) {
show_message_ok(this, "Error exporting", e.what(), wxICON_EXCLAMATION);
}
refresh();
}
void wxeditor_voicesub::on_export_s(wxCommandEvent& e)
@ -263,7 +282,6 @@ void wxeditor_voicesub::on_export_s(wxCommandEvent& e)
} catch(std::exception& e) {
show_message_ok(this, "Error exporting superstream", e.what(), wxICON_EXCLAMATION);
}
refresh();
}
void wxeditor_voicesub::on_import_o(wxCommandEvent& e)
@ -282,7 +300,6 @@ void wxeditor_voicesub::on_import_o(wxCommandEvent& e)
} catch(std::exception& e) {
show_message_ok(this, "Error importing", e.what(), wxICON_EXCLAMATION);
}
refresh();
}
void wxeditor_voicesub::on_import_p(wxCommandEvent& e)
@ -301,7 +318,6 @@ void wxeditor_voicesub::on_import_p(wxCommandEvent& e)
} catch(std::exception& e) {
show_message_ok(this, "Error importing", e.what(), wxICON_EXCLAMATION);
}
refresh();
}
void wxeditor_voicesub::on_import_q(wxCommandEvent& e)
@ -320,7 +336,6 @@ void wxeditor_voicesub::on_import_q(wxCommandEvent& e)
} catch(std::exception& e) {
show_message_ok(this, "Error importing", e.what(), wxICON_EXCLAMATION);
}
refresh();
}
void wxeditor_voicesub::on_change_ts(wxCommandEvent& e)
@ -340,7 +355,6 @@ void wxeditor_voicesub::on_change_ts(wxCommandEvent& e)
} catch(std::exception& e) {
show_message_ok(this, "Error changing timebase", e.what(), wxICON_EXCLAMATION);
}
refresh();
}
void wxeditor_voicesub::on_load(wxCommandEvent& e)
@ -356,13 +370,11 @@ void wxeditor_voicesub::on_load(wxCommandEvent& e)
} catch(std::exception& e) {
show_message_ok(this, "Error loading collection", e.what(), wxICON_EXCLAMATION);
}
refresh();
}
void wxeditor_voicesub::on_unload(wxCommandEvent& e)
{
voicesub_unload_collection();
refresh();
}
void wxeditor_voicesub::on_refresh(wxCommandEvent& e)
@ -378,6 +390,8 @@ void wxeditor_voicesub::on_close(wxCommandEvent& e)
void wxeditor_voicesub::refresh()
{
if(closing)
return;
bool cflag = voicesub_collection_loaded();
unloadbutton->Enable(cflag);
exportsbutton->Enable(cflag);

View file

@ -1229,7 +1229,7 @@ void wxwin_mainwindow::handle_menu_click_cancelable(wxCommandEvent& e)
case wxID_SET_VOLUME:
parsed = pick_volume(this, "Set volume", last_volume);
if(parsed >= -1e-10)
runemufn([parsed]() { platform::global_volume = parsed; });
runemufn([parsed]() { audioapi_music_volume(parsed); });
return;
case wxID_SET_VOLUME_RECORD:
parsed = pick_volume(this, "Set recording volume", last_volume_record);