summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu
diff options
context:
space:
mode:
authorGravatarGravatar Vas Crabb <vas@vastheman.com>2019-11-21 03:36:19 +1100
committerGravatarGravatar Vas Crabb <vas@vastheman.com>2019-11-21 03:36:19 +1100
commit6c61aa61d280acd2e45f2456413603231e91063e (patch)
tree85d0cc18436e0eb17dbb92c5bd4170ac69cbc05e /src/emu
parentf5d23f7036650e2ca3d68779a60fc9018ec79692 (diff)
UI input mapping menu updates:
* When a switch-type input is selected, show feedback when it's pressed * If an invalid code is entered (e.g. only negatives) abandon the change rather than cycling default/none * If an invalid code is entered display a message until the user takes some other action input.cpp updates: * constexpr crusade on input_code and input_seq and some very slight optimisation to input_seq * seq_poll* is a frontend function and had no business being in the core, so it's a utility class now * seq_poll* now exposes a bit more detail, enabling improved interaction on the UI inputs menu * global state is reduced a little, but the poll_* functions are still members of the input manager with global state (nw) The Lua engine has been updated in a way that maintains source compatibility with existing Lua scripts. This is less than ideal, but it minimises impact. Ideally someone (possibly me) will be able to expose the input sequence poller helper properly. I tested the changes with the cheat and autofire plugins and I was able to assign sequences. However I found two issues: it's seems impossible to assign a more complex sequence than a single key/button in the autofire plugin (i.e. no AND or NOT conditions, I confirmed this is pre-existing, not a regression), and in both the cheat and autofire plugins I found it a bit unwieldy trying to enter a complex sequence without live feedback of the sequence as it's built (this was also applicable to MAME's own input mapping menu until I added the live display yesterday).
Diffstat (limited to 'src/emu')
-rw-r--r--src/emu/input.cpp214
-rw-r--r--src/emu/input.h131
-rw-r--r--src/emu/ioport.cpp2
3 files changed, 122 insertions, 225 deletions
diff --git a/src/emu/input.cpp b/src/emu/input.cpp
index 64aa4382c97..0d829b84bc5 100644
--- a/src/emu/input.cpp
+++ b/src/emu/input.cpp
@@ -30,10 +30,10 @@
const s32 INVALID_AXIS_VALUE = 0x7fffffff;
// additional expanded input codes for sequences
-const input_code input_seq::end_code(DEVICE_CLASS_INTERNAL, 0, ITEM_CLASS_INVALID, ITEM_MODIFIER_NONE, ITEM_ID_SEQ_END);
-const input_code input_seq::default_code(DEVICE_CLASS_INTERNAL, 0, ITEM_CLASS_INVALID, ITEM_MODIFIER_NONE, ITEM_ID_SEQ_DEFAULT);
-const input_code input_seq::not_code(DEVICE_CLASS_INTERNAL, 0, ITEM_CLASS_INVALID, ITEM_MODIFIER_NONE, ITEM_ID_SEQ_NOT);
-const input_code input_seq::or_code(DEVICE_CLASS_INTERNAL, 0, ITEM_CLASS_INVALID, ITEM_MODIFIER_NONE, ITEM_ID_SEQ_OR);
+constexpr input_code input_seq::end_code;
+constexpr input_code input_seq::default_code;
+constexpr input_code input_seq::not_code;
+constexpr input_code input_seq::or_code;
// constant sequences
const input_seq input_seq::empty_seq;
@@ -377,14 +377,15 @@ static const code_string_table itemid_token_table[] =
// input sequence
//-------------------------------------------------
-input_seq &input_seq::operator+=(input_code code)
+input_seq &input_seq::operator+=(input_code code) noexcept
{
// if not enough room, return false
- int curlength = length();
- if (curlength < ARRAY_LENGTH(m_code) - 1)
+ const int curlength = length();
+ if (curlength < m_code.size())
{
- m_code[curlength++] = code;
- m_code[curlength] = end_code;
+ m_code[curlength] = code;
+ if ((curlength + 1) < m_code.size())
+ m_code[curlength + 1] = end_code;
}
return *this;
}
@@ -396,17 +397,25 @@ input_seq &input_seq::operator+=(input_code code)
// before the new code
//-------------------------------------------------
-input_seq &input_seq::operator|=(input_code code)
+input_seq &input_seq::operator|=(input_code code) noexcept
{
// overwrite end/default with the new code
- if (m_code[0] == end_code || m_code[0] == default_code)
+ if (m_code[0] == default_code)
+ {
m_code[0] = code;
-
- // otherwise, append an OR token and then the new code
+ m_code[1] = end_code;
+ }
else
{
- *this += or_code;
- *this += code;
+ // otherwise, append an OR token and then the new code
+ const int curlength = length();
+ if ((curlength + 1) < m_code.size())
+ {
+ m_code[curlength] = or_code;
+ m_code[curlength + 1] = code;
+ if ((curlength + 2) < m_code.size())
+ m_code[curlength + 2] = end_code;
+ }
}
return *this;
}
@@ -416,13 +425,13 @@ input_seq &input_seq::operator|=(input_code code)
// length - return the length of the sequence
//-------------------------------------------------
-int input_seq::length() const
+int input_seq::length() const noexcept
{
// find the end token; error if none found
- for (int seqnum = 0; seqnum < ARRAY_LENGTH(m_code); seqnum++)
+ for (int seqnum = 0; seqnum < m_code.size(); seqnum++)
if (m_code[seqnum] == end_code)
return seqnum;
- return ARRAY_LENGTH(m_code);
+ return m_code.size();
}
@@ -431,17 +440,17 @@ int input_seq::length() const
// valid
//-------------------------------------------------
-bool input_seq::is_valid() const
+bool input_seq::is_valid() const noexcept
{
// "default" can only be of length 1
if (m_code[0] == default_code)
- return (length() == 1);
+ return m_code[1] == end_code;
// scan the sequence for valid codes
input_item_class lastclass = ITEM_CLASS_INVALID;
input_code lastcode = INPUT_CODE_INVALID;
int positive_code_count = 0;
- for (auto code : m_code)
+ for (input_code code : m_code)
{
// invalid codes are never permitted
if (code == INPUT_CODE_INVALID)
@@ -451,7 +460,7 @@ bool input_seq::is_valid() const
if (code == or_code || code == end_code)
{
// must be at least one positive code
- if (positive_code_count == 0)
+ if (!positive_code_count)
return false;
// last code must not have been an internal code
@@ -466,15 +475,12 @@ bool input_seq::is_valid() const
positive_code_count = 0;
lastclass = ITEM_CLASS_INVALID;
}
-
- // if we hit a NOT, make sure we don't have a double
else if (code == not_code)
{
+ // if we hit a NOT, make sure we don't have a double
if (lastcode == not_code)
return false;
}
-
- // anything else
else
{
// count positive codes
@@ -502,32 +508,14 @@ bool input_seq::is_valid() const
//-------------------------------------------------
-// set - directly set up to the first 7 codes
-//-------------------------------------------------
-
-void input_seq::set(input_code code0, input_code code1, input_code code2, input_code code3, input_code code4, input_code code5, input_code code6)
-{
- m_code[0] = code0;
- m_code[1] = code1;
- m_code[2] = code2;
- m_code[3] = code3;
- m_code[4] = code4;
- m_code[5] = code5;
- m_code[6] = code6;
- for (int codenum = 7; codenum < ARRAY_LENGTH(m_code); codenum++)
- m_code[codenum] = end_code;
-}
-
-
-//-------------------------------------------------
// backspace - "backspace" over the last entry in
// a sequence
//-------------------------------------------------
-void input_seq::backspace()
+void input_seq::backspace() noexcept
{
// if we have at least one entry, remove it
- int curlength = length();
+ const int curlength = length();
if (curlength > 0)
m_code[curlength - 1] = end_code;
}
@@ -538,9 +526,9 @@ void input_seq::backspace()
// with newcode in a sequence
//-------------------------------------------------
-void input_seq::replace(input_code oldcode, input_code newcode)
+void input_seq::replace(input_code oldcode, input_code newcode) noexcept
{
- for (auto & elem : m_code)
+ for (input_code &elem : m_code)
if (elem == oldcode)
elem = newcode;
}
@@ -555,10 +543,7 @@ void input_seq::replace(input_code oldcode, input_code newcode)
// input_manager - constructor
//-------------------------------------------------
-input_manager::input_manager(running_machine &machine)
- : m_machine(machine),
- m_poll_seq_last_ticks(0),
- m_poll_seq_class(ITEM_CLASS_SWITCH)
+input_manager::input_manager(running_machine &machine) : m_machine(machine)
{
// reset code memory
reset_memory();
@@ -1339,129 +1324,6 @@ s32 input_manager::seq_axis_value(const input_seq &seq, input_item_class &itemcl
//-------------------------------------------------
-// seq_poll_start - begin polling for a new
-// sequence of the given itemclass
-//-------------------------------------------------
-
-void input_manager::seq_poll_start(input_item_class itemclass, const input_seq *startseq)
-{
- assert(itemclass == ITEM_CLASS_SWITCH || itemclass == ITEM_CLASS_ABSOLUTE || itemclass == ITEM_CLASS_RELATIVE);
-
- // reset the recording count and the clock
- m_poll_seq_last_ticks = 0;
- m_poll_seq_class = itemclass;
- m_poll_seq.reset();
-
- // grab the starting sequence to append to, and append an OR
- if (startseq != nullptr)
- {
- m_poll_seq = *startseq;
- if (m_poll_seq.length() > 0)
- m_poll_seq += input_seq::or_code;
- }
-
- // flush out any goobers
- reset_polling();
- input_code dummycode = KEYCODE_ENTER;
- while (dummycode != INPUT_CODE_INVALID)
- dummycode = (m_poll_seq_class == ITEM_CLASS_SWITCH) ? poll_switches() : poll_axes();
-}
-
-
-//-------------------------------------------------
-// input_seq_poll - continue polling
-//-------------------------------------------------
-
-bool input_manager::seq_poll()
-{
- const int curlen = m_poll_seq.length();
- input_code lastcode = m_poll_seq[curlen - 1];
-
- input_code newcode;
- if (m_poll_seq_class == ITEM_CLASS_SWITCH)
- {
- // switch case: see if we have a new code to process
- newcode = poll_switches();
- if (newcode != INPUT_CODE_INVALID)
- {
- // if code is duplicate, toggle the NOT state on the code
- if (curlen > 0 && newcode == lastcode)
- {
- // back up over the existing code
- m_poll_seq.backspace();
-
- // if there was a NOT preceding it, delete it as well, otherwise append a fresh one
- if (m_poll_seq[curlen - 2] == input_seq::not_code)
- m_poll_seq.backspace();
- else
- m_poll_seq += input_seq::not_code;
- }
- }
- }
- else
- {
- // absolute/relative case: see if we have an analog change of sufficient amount
- bool has_or = false;
- if (lastcode == input_seq::or_code)
- {
- lastcode = m_poll_seq[curlen - 2];
- has_or = true;
- }
- newcode = poll_axes();
-
- // if the last code doesn't match absolute/relative of this code, ignore the new one
- if ((lastcode.item_class() == ITEM_CLASS_ABSOLUTE && newcode.item_class() != ITEM_CLASS_ABSOLUTE) ||
- (lastcode.item_class() == ITEM_CLASS_RELATIVE && newcode.item_class() != ITEM_CLASS_RELATIVE))
- newcode = INPUT_CODE_INVALID;
-
- // if the new code is valid, check for half-axis toggles on absolute controls
- if (newcode != INPUT_CODE_INVALID && curlen > 0 && newcode.item_class() == ITEM_CLASS_ABSOLUTE)
- {
- input_code last_nomodifier = lastcode;
- last_nomodifier.set_item_modifier(ITEM_MODIFIER_NONE);
- if (newcode == last_nomodifier)
- {
- // increment the modifier, wrapping back to none
- switch (lastcode.item_modifier())
- {
- case ITEM_MODIFIER_NONE: newcode.set_item_modifier(ITEM_MODIFIER_POS); break;
- case ITEM_MODIFIER_POS: newcode.set_item_modifier(ITEM_MODIFIER_NEG); break;
- default:
- case ITEM_MODIFIER_NEG: newcode.set_item_modifier(ITEM_MODIFIER_NONE); break;
- }
-
- // back up over the previous code so we can re-append
- if (has_or)
- m_poll_seq.backspace();
- m_poll_seq.backspace();
- }
- }
- }
-
- // if we got a new code to append it, append it and reset the timer
- if (newcode != INPUT_CODE_INVALID)
- {
- m_poll_seq += newcode;
- m_poll_seq_last_ticks = osd_ticks();
- }
-
- // if we're recorded at least one item and 2/3 of a second has passed, we're done
- if (m_poll_seq_last_ticks != 0 && osd_ticks() > m_poll_seq_last_ticks + osd_ticks_per_second() * 2 / 3)
- {
- // if the final result is invalid, reset to nothing
- if (!m_poll_seq.is_valid())
- m_poll_seq.reset();
-
- // return true to indicate that we are finished
- return true;
- }
-
- // return false to indicate we are still polling
- return false;
-}
-
-
-//-------------------------------------------------
// seq_clean - clean the sequence, removing
// any invalid bits
//-------------------------------------------------
@@ -1505,7 +1367,7 @@ std::string input_manager::seq_name(const input_seq &seq) const
// special case: empty
if (cleaned_seq[0] == input_seq::end_code)
- return std::string((seq.length() == 0) ? "None" : "n/a");
+ return std::string(seq.empty() ? "None" : "n/a");
// start with an empty buffer
std::string str;
diff --git a/src/emu/input.h b/src/emu/input.h
index 3ca97ae1e99..24b6dd062d2 100644
--- a/src/emu/input.h
+++ b/src/emu/input.h
@@ -17,6 +17,10 @@
#ifndef MAME_EMU_INPUT_H
#define MAME_EMU_INPUT_H
+#include <algorithm>
+#include <array>
+#include <iterator>
+
//**************************************************************************
// CONSTANTS
@@ -358,7 +362,12 @@ class input_code
{
public:
// construction/destruction
- input_code(input_device_class devclass = DEVICE_CLASS_INVALID, int devindex = 0, input_item_class itemclass = ITEM_CLASS_INVALID, input_item_modifier modifier = ITEM_MODIFIER_NONE, input_item_id itemid = ITEM_ID_INVALID)
+ constexpr input_code(
+ input_device_class devclass = DEVICE_CLASS_INVALID,
+ int devindex = 0,
+ input_item_class itemclass = ITEM_CLASS_INVALID,
+ input_item_modifier modifier = ITEM_MODIFIER_NONE,
+ input_item_id itemid = ITEM_ID_INVALID) noexcept
: m_internal(((devclass & 0xf) << 28) | ((devindex & 0xff) << 20) | ((itemclass & 0xf) << 16) | ((modifier & 0xf) << 12) | (itemid & 0xfff))
{
assert(devclass >= 0 && devclass < DEVICE_CLASS_MAXIMUM);
@@ -367,30 +376,48 @@ public:
assert(modifier >= 0 && modifier < ITEM_MODIFIER_MAXIMUM);
assert(itemid >= 0 && itemid < ITEM_ID_ABSOLUTE_MAXIMUM);
}
- input_code(const input_code &src)
- : m_internal(src.m_internal) { }
+ constexpr input_code(const input_code &src) noexcept = default;
// operators
- bool operator==(const input_code &rhs) const { return m_internal == rhs.m_internal; }
- bool operator!=(const input_code &rhs) const { return m_internal != rhs.m_internal; }
+ constexpr bool operator==(const input_code &rhs) const noexcept { return m_internal == rhs.m_internal; }
+ constexpr bool operator!=(const input_code &rhs) const noexcept { return m_internal != rhs.m_internal; }
// getters
- bool internal() const { return device_class() == DEVICE_CLASS_INTERNAL; }
- input_device_class device_class() const { return input_device_class((m_internal >> 28) & 0xf); }
- int device_index() const { return ((m_internal >> 20) & 0xff); }
- input_item_class item_class() const { return input_item_class((m_internal >> 16) & 0xf); }
- input_item_modifier item_modifier() const { return input_item_modifier((m_internal >> 12) & 0xf); }
- input_item_id item_id() const { return input_item_id(m_internal & 0xfff); }
+ constexpr bool internal() const noexcept { return device_class() == DEVICE_CLASS_INTERNAL; }
+ constexpr input_device_class device_class() const noexcept { return input_device_class((m_internal >> 28) & 0xf); }
+ constexpr int device_index() const noexcept { return ((m_internal >> 20) & 0xff); }
+ constexpr input_item_class item_class() const noexcept { return input_item_class((m_internal >> 16) & 0xf); }
+ constexpr input_item_modifier item_modifier() const noexcept { return input_item_modifier((m_internal >> 12) & 0xf); }
+ constexpr input_item_id item_id() const noexcept { return input_item_id(m_internal & 0xfff); }
// setters
- void set_device_class(input_device_class devclass) { assert(devclass >= 0 && devclass <= 0xf); m_internal = (m_internal & ~(0xf << 28)) | ((devclass & 0xf) << 28); }
- void set_device_index(int devindex) { assert(devindex >= 0 && devindex <= 0xff); m_internal = (m_internal & ~(0xff << 20)) | ((devindex & 0xff) << 20); }
- void set_item_class(input_item_class itemclass) { assert(itemclass >= 0 && itemclass <= 0xf); m_internal = (m_internal & ~(0xf << 16)) | ((itemclass & 0xf) << 16); }
- void set_item_modifier(input_item_modifier modifier) { assert(modifier >= 0 && modifier <= 0xf); m_internal = (m_internal & ~(0xf << 12)) | ((modifier & 0xf) << 12); }
- void set_item_id(input_item_id itemid) { assert(itemid >= 0 && itemid <= 0xfff); m_internal = (m_internal & ~0xfff) | (itemid & 0xfff); }
+ void set_device_class(input_device_class devclass) noexcept
+ {
+ assert(devclass >= 0 && devclass <= 0xf);
+ m_internal = (m_internal & ~(0xf << 28)) | ((devclass & 0xf) << 28);
+ }
+ void set_device_index(int devindex) noexcept
+ {
+ assert(devindex >= 0 && devindex <= 0xff);
+ m_internal = (m_internal & ~(0xff << 20)) | ((devindex & 0xff) << 20);
+ }
+ void set_item_class(input_item_class itemclass) noexcept
+ {
+ assert(itemclass >= 0 && itemclass <= 0xf);
+ m_internal = (m_internal & ~(0xf << 16)) | ((itemclass & 0xf) << 16);
+ }
+ void set_item_modifier(input_item_modifier modifier) noexcept
+ {
+ assert(modifier >= 0 && modifier <= 0xf);
+ m_internal = (m_internal & ~(0xf << 12)) | ((modifier & 0xf) << 12);
+ }
+ void set_item_id(input_item_id itemid) noexcept
+ {
+ assert(itemid >= 0 && itemid <= 0xfff);
+ m_internal = (m_internal & ~0xfff) | (itemid & 0xfff);
+ }
private:
- // internal state
u32 m_internal;
};
@@ -402,41 +429,59 @@ class input_seq
{
public:
// construction/destruction
- input_seq(input_code code0 = input_seq::end_code, input_code code1 = input_seq::end_code, input_code code2 = input_seq::end_code, input_code code3 = input_seq::end_code, input_code code4 = input_seq::end_code, input_code code5 = input_seq::end_code, input_code code6 = input_seq::end_code)
- { set(code0, code1, code2, code3, code4, code5, code6); }
- input_seq(const input_seq &rhs) { memcpy(m_code, rhs.m_code, sizeof(m_code)); }
+ template <typename... T> constexpr input_seq(input_code code_0 = end_code, T... code_n) noexcept
+ {
+ set(code_0, code_n...);
+ }
+ constexpr input_seq(const input_seq &rhs) noexcept = default;
// operators
- bool operator==(const input_seq &rhs) const { return (memcmp(m_code, rhs.m_code, sizeof(m_code)) == 0); }
- bool operator!=(const input_seq &rhs) const { return (memcmp(m_code, rhs.m_code, sizeof(m_code)) != 0); }
- input_code operator[](int index) const { return (index >= 0 && index < ARRAY_LENGTH(m_code)) ? m_code[index] : input_seq::end_code; }
- input_seq &operator+=(input_code code);
- input_seq &operator|=(input_code code);
+ bool operator==(const input_seq &rhs) const noexcept { return m_code == rhs.m_code; }
+ bool operator!=(const input_seq &rhs) const noexcept { return m_code != rhs.m_code; }
+ constexpr input_code operator[](int index) const noexcept { return (index >= 0 && index < m_code.size()) ? m_code[index] : end_code; }
+ input_seq &operator+=(input_code code) noexcept;
+ input_seq &operator|=(input_code code) noexcept;
// getters
- int length() const;
- bool is_valid() const;
- bool is_default() const { return m_code[0] == default_code; }
+ constexpr bool empty() const noexcept { return m_code[0] == end_code; }
+ constexpr int max_size() const noexcept { return std::tuple_size<decltype(m_code)>::value; }
+ int length() const noexcept;
+ bool is_valid() const noexcept;
+ constexpr bool is_default() const noexcept { return m_code[0] == default_code; }
// setters
- void set(input_code code0 = input_seq::end_code, input_code code1 = input_seq::end_code, input_code code2 = input_seq::end_code, input_code code3 = input_seq::end_code, input_code code4 = input_seq::end_code, input_code code5 = input_seq::end_code, input_code code6 = input_seq::end_code);
- void reset() { set(); }
- void set_default() { set(default_code); }
- void backspace();
- void replace(input_code oldcode, input_code newcode);
+ template <typename... T> void set(input_code code_0, T... code_n) noexcept
+ {
+ static_assert(sizeof...(T) < std::tuple_size<decltype(m_code)>::value, "too many codes for input_seq");
+ set<0>(code_0, code_n...);
+ }
+ void reset() noexcept { set(end_code); }
+ void set_default() noexcept { set(default_code); }
+ void backspace() noexcept;
+ void replace(input_code oldcode, input_code newcode) noexcept;
// constant codes used in sequences
- static const input_code end_code;
- static const input_code default_code;
- static const input_code not_code;
- static const input_code or_code;
+ static constexpr input_code end_code { DEVICE_CLASS_INTERNAL, 0, ITEM_CLASS_INVALID, ITEM_MODIFIER_NONE, ITEM_ID_SEQ_END };
+ static constexpr input_code default_code { DEVICE_CLASS_INTERNAL, 0, ITEM_CLASS_INVALID, ITEM_MODIFIER_NONE, ITEM_ID_SEQ_DEFAULT };
+ static constexpr input_code not_code { DEVICE_CLASS_INTERNAL, 0, ITEM_CLASS_INVALID, ITEM_MODIFIER_NONE, ITEM_ID_SEQ_NOT };
+ static constexpr input_code or_code { DEVICE_CLASS_INTERNAL, 0, ITEM_CLASS_INVALID, ITEM_MODIFIER_NONE, ITEM_ID_SEQ_OR };
// constant sequences
static const input_seq empty_seq;
private:
+ template <unsigned N> void set() noexcept
+ {
+ std::fill(std::next(m_code.begin(), N), m_code.end(), end_code);
+ }
+ template <unsigned N, typename... T> void set(input_code code_0, T... code_n) noexcept
+ {
+ m_code[N] = code_0;
+ set<N + 1>(code_n...);
+ }
+
// internal state
- input_code m_code[16];
+ std::array<input_code, 16> m_code;
};
@@ -478,11 +523,6 @@ public:
bool seq_pressed(const input_seq &seq);
s32 seq_axis_value(const input_seq &seq, input_item_class &itemclass);
- // input sequence polling
- void seq_poll_start(input_item_class itemclass, const input_seq *startseq = nullptr);
- bool seq_poll();
- const input_seq &seq_poll_final() const { return m_poll_seq; }
-
// input sequence helpers
input_seq seq_clean(const input_seq &seq) const;
std::string seq_name(const input_seq &seq) const;
@@ -503,11 +543,6 @@ private:
// classes
std::array<std::unique_ptr<input_class>, DEVICE_CLASS_MAXIMUM> m_class;
-
- // sequence polling state
- input_seq m_poll_seq;
- osd_ticks_t m_poll_seq_last_ticks;
- input_item_class m_poll_seq_class;
};
diff --git a/src/emu/ioport.cpp b/src/emu/ioport.cpp
index 0d7fe96e5b5..6b75a1289f4 100644
--- a/src/emu/ioport.cpp
+++ b/src/emu/ioport.cpp
@@ -2133,7 +2133,7 @@ void ioport_manager::load_config(config_type cfg_type, util::xml::data_node cons
if (seqtype != -1 && seqnode->get_value() != nullptr)
{
if (strcmp(seqnode->get_value(), "NONE") == 0)
- newseq[seqtype].set();
+ newseq[seqtype].reset();
else
machine().input().seq_from_tokens(newseq[seqtype], seqnode->get_value());
}