New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Debugger: MemoryWidget: add float and integer input types. Add input preview. #10528
Debugger: MemoryWidget: add float and integer input types. Add input preview. #10528
Conversation
Something is broken here in the hex view if you have leading zeroes and go over 16 characters. Spaces in the input box also seem to parse as leading zeroes. |
Seems like an improvement other than that though! |
Thanks for finding these edge cases! Spaces are now removed unless using ascii. |
Squash the fixup and I'm okay with this. |
Apologies for the conflicts, hope that's not too bad to fix. |
0ced546
to
2b4b172
Compare
np, I should probably look at this one more time later to make sure I didn't break anything. |
2b4b172
to
d4d7f30
Compare
When using Input Type == Hex and Data Type == ASCII, it pads the entered hex value to multiples of 4 bytes. While it's not exactly clear what the padding should be in that case, I think no padding (same as Data Type == U8) makes more sense for that. (For Data Type == Float, the 4 byte padding makes sense to keep, IMO, since floats are 4 bytes long.) |
Ohh, you're right. I didn't consider that case. |
d4d7f30
to
4833afc
Compare
4833afc
to
489a583
Compare
hex_string = QStringLiteral("%1").arg(hex_out, padding, hex, QLatin1Char('0')).toUpper(); | ||
} | ||
} | ||
else if (m_input_integer->isChecked()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I really think the logic is overkill. What about using a dropdown menu with the proper input type (u8, s8, u16, s16, u32, s32, u64, s64, float, double, hex, ascii, ...)?
Moreover, I think the m_type_*
members are misused. IIRC, they were only used to specify the representation of the memory view, not the input type. This use would be counterintuitive.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
6 different options for something that can be done with 1 option and some logic seems like overkill to me. Is it really unreasonable to expect someone to choose u8 view if they want to input a u8? The view doesn't determine type, only padding/length ( I guess you could call that type tho).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I find this actually pretty intuitive for integers and floats, though ymmv of course. For a hex string, less so, maybe that one should never be padded?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
6 different options for something that can be done with 1 option and some logic seems like overkill to me.
"Can be done with 1 option" and tons of branching is IMHO clearly overkill. On top of that, checking the first character each time to see if its signed or not is redundant and way harder to read.
The same goes for the padding heuristic which is everywhere. Whereas knowing the exact type gives you the appropriate padding without having to compute it.
Is it really unreasonable to expect someone to choose u8 view if they want to input a u8? The view doesn't determine type, only padding/length ( I guess you could call that type tho).
Yes it is, if it was not for the hex string preview, I don't think many people would have understood it. Especially, since there is an ASCII type and a float type in both group. So that's extremely confusing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How would you turn -20 from a QString into an 8 bit hexadecimal and a 16 bit hexadecimal QString? I'm more than happy to improve upon it, with a bit of guidance.
My basic goal is adding integer + float. Allowing the option to input 1 -> 00000001. Add a spaced out preview to easily see what you're inputting and how many bytes it is.
Should input and view be combined into one thing? Is there any time that'd be annoying?
I could also make it so if input size > intended size it defaults to string of bytes instead of continued padding.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How would you turn -20 from a QString into an 8 bit hexadecimal and a 16 bit hexadecimal QString? I'm more than happy to improve upon it, with a bit of guidance.
A QComboBox
can be used with the proper input type (u8, s8, u16, s16, u32, s32, u64, s64, float, double, hex, ascii, ...). Sticking to radio button sounds like a bad design choice to me. With the QComboBox
index, the validation/preview can be simplified and will boil down to a switch and an enum class like this and picking the right QString method (toShort, toInt, ...)
.
For instance:
switch (combo_id)
{
case InputComboId::S16:
{
short value = input_text.toShort(&good, 10);
if (good)
hex_string = QStringLiteral("%1").arg(value, 4, 16, QLatin1Char('0')).toUpper();
break;
}
case InputComboId::S32:
{
int value = input_text.toInt(&good, 10);
if (good)
hex_string = QStringLiteral("%1").arg(value, 8, 16, QLatin1Char('0')).toUpper();
break;
}
// Etc. (...)
}
Should input and view be combined into one thing? Is there any time that'd be annoying?
I could also make it so if input size > intended size it defaults to string of bytes instead of continued padding.
I think changing the view behaviour is out of scope of the PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That code doesn't give the correct output and the fix is the same padding convolution that's trying to be avoided.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought that it would have behaved like libfmt's format or printf but I was wrong.
Here is an alternative using libfmt sprintf:
case InputComboId::S16:
{
short value = input_text.toShort(&good, 10);
if (good)
hex_string = QString::fromStdString(fmt::sprintf("%04hX", value));
break;
}
Using fmt::format
follows python's format and doesn't print the intended number:
// Code testing
short value = -42;
qDebug() << QStringLiteral("%1").arg(value, 4, 16, QLatin1Char('0')).toUpper();
qDebug() << QString::fromStdString(fmt::format("{:04X}", value));
// You'll need to use printf specifiers and length modifiers here
qDebug() << QString::fromStdString(fmt::sprintf("%04hX", value));
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you! I knew fmt was incorrect, but didn't know about fmt sprintf.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't find a simpler method for float than BitCast, but everything else seems improved.
One problem I have with making 12 different input types, is all the red you will see if you go out of range. With just the integer type, at least you see an output and can adjust it rather than just getting hit with an invalid s8/s16/u8/whatever input that's out of range.
80e2abe
to
ad85548
Compare
Reimplemented original behavior for long hex strings. You can use any length hex, but hex must have whole bytes when using a long hex string. |
ad85548
to
16c8253
Compare
a61806d
to
72cc5bd
Compare
I improved the logic thanks to fmt::sprintf being pointed out. The remaining convoluted line is for a string of u16's being padded with zeroes. Do we want to allow a string of u16 or to just let it fall back to u8's? I could add 3 extra radio buttons for input length, to divorce it from the view type. |
As explained in my previous comment, I really think the input type's radio buttons are a very bad design choice and it should be switched to a Using the view's data type doesn't sound fine to me since it's inconsistent with the input type's radio buttons and incoherent like |
The only implementations I can think up involving a QComboBox with s8, s16, s32, u8, u16, u32, hex string, float, double, ascii would feel clunky to actually use. Also, if you input a "-2" s8 while looking at "12345678" in a U32 data view, do you expect to get 000000FE or 123456FE? Connecting the data view to input length avoids the question. QString doesn't have a direct s8/signed char conversion that I know of, so I think you still need to check it as an int for size/sign. Wouldn't it be more accurate to rename view data type to byte lengths rather than U's, regardless? |
What do you feel clunky about it? Using radio buttons is as much clunky if not clunkier especially if it's tight to other radio buttons of the view format (no hex editor I've used so far have this behaviour). Using a combo box is straightforward and explicit about what it will be doing (i.e. set a value of a specific data type at the specified address+offset). BTW, I think there is a misconception with your approach between padding/alignment and endianness. Using big-endian is fine as it's what the Wii/GC are using but magically deducing a "padding" for the radio button
I'm strongly opposed to connect it to the data view. I don't think people expect implicit stuff to happen like padding based on type and alignment. What would make the most sense is when you input "-2" (no matter what the view type is, even ASCII or Float), it writes "-2" at the specified address+offset, that's all. The answer would (in big endian):
I think using // For s8
short value = input_text.toShort(&good, 10);
good &= std::numeric_limits<signed char>::min() <= value && value <= std::numeric_limits<signed char>::max() |
To be clear, I'm not strongly for or against any of this; heck I was fine with the initial implementation of this PR. I think the memory window has too many big usability issues to start caring about (imo) small stuff like this. |
Sorry, I use the old WX style inputs in my personal builds, so I guess it was confusing for me to mention. Integers were an afterthought for this PR, because we can't even view things as integers. So heavily focusing on integers is weird for me. Your checkbox idea is good, since we already use it and it's consistent with other programs. |
6decd9d
to
dafdda2
Compare
I can't say I've ever seen any UI element like that, and I question how often one actually needs octal (I never do), but yeah, I suppose this works. @sepalani thoughts on this? |
Yeah looking at it again, just using the checkbox would be better It should only be active for unsigned right? With the setup you can still prepend 0 for octal. |
Technically there's nothing wrong with writing a signed -1 as 0xffffffff or whatever. It doesn't encode differently if it's signed, but I see no reason to not allow it. |
Hmm toShort(&good, 0) sees 0xffff as outside the limits of a signed short. It judges it as an unsigned. Not sure of a simple fix. |
fb75e00
to
1932249
Compare
Alright, played around with this a bit. There's a few minor weird quirks (eg. octal with prefixed 0 works on unsigned but not on signed, if you're in hex mode you can't prefix a 0x manually, hex byte string doesn't allow spaces but int/float does) but I'd be fine with just merging this as-is and tweaking the details later, because this is still a massive improvement over the previous state. Depends on how much you still want to work on this here. |
Oh, one thing that you should probably fix though: If you enter a long Hex Byte String (eg. |
I fixed everything except octal for signed, because it needs to work with hexadecimal too, and doesn't. My solutions to getting signed to work with hex would backslide into messy code. Like changing the signed enum to unsigned when validating or using a different switch set just for hex. I still need to merge the commits. I will wait awhile longer to see if anyone else has anything more for me. |
1932249
to
8ee3835
Compare
I'm fine with the combo box, or the checkbox for hex. The checkbox for hex feels less awkward and I haven't needed the use for octal yet.
That's the intended behaviour, 0xFFFF (aka 65535) is an invalid signed short (s16) but a valid unsigned short (u16, see |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Beside these nitpicks I'm fine with the current state of this PR.
search_type_group->addButton(m_find_hex); | ||
auto* input_layout = new QHBoxLayout; | ||
m_data_edit = new QLineEdit; | ||
m_base_check = new QCheckBox(tr("Hex")); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Parse as Hex
to be consistent with the Cheat Search feature.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wanted to allow as much space for the input box as possible. I could put it on the same line as the input combobox?
Thanks for the great suggestions. Should it be InputID or InputId for the enum? |
|
std::isprint(c, std::locale::classic()); Do I need to check this when processing ascii? I just noticed it in memoryviewwidget. Otherwise, ascii auto-trusts any input. |
8ee3835
to
1998b18
Compare
I don't think that's necessary, if the user enters a non-printable character in the textbox they can probably deal with the aftermath. |
Can you squish the commits now? I think we're finally done here. |
…w. Change input logic. Use combobox for options.
1998b18
to
ed96b8e
Compare
Data preview has automatic spacing per byte.
Float is only for singles.
Integer can accept both unsigned and signed numbers up to 4 bytes.
Hex is right aligned and based on the view type. Leading zeroes are always filled automatically.
View-based input:
Fixed a bug where an empty address offset would throw an error.
Loses the ability for infinite length hex string input, but still has it for ascii. Hex max length is 8 bytes. I could go back and redo it if people actually slam massive hex strings in there.
Not sure if anyone is against right-aligned. For me, when inputting 4 byte numbers, I'm either filling all 4 bytes or just operating on the right hand side, like inputting "1e" -> 00 00 00 1E. Also, inputting just one digit when needed is more comfortable "1" -> 01. Plus the input preview clearly shows what will be entered.
/edit Given that more and more types may be added, converted to a combo list. Made types more explicit.