Repository navigation
Replies: 19 comments
|
So let's begin with what we've previously discussed about |
|
The last commit introduces some little breaking changes:
Here are more area of improvements:
|
As I mentioned earlier my intention for This is how I painted gradient before: virtual void MyDelegate::paint (QPainter* painter, const QHexView* hex_view) const override
{
QLinearGradient gradient (0, 0, 0, headerRect().height());
gradient.setColorAt (0.1, hex_view->palette().color (QPalette::Light));
gradient.setColorAt (1, hex_view->palette().color (QPalette::Midlight));
painter->fillRect (hex_view->headerRect(), gradient);
QHexDelegate::paint (painter, hex_view);
}This is how I setup gradient now: QHexOptions options;
QLinearGradient gradient;
gradient.setColorAt (0.1, hex_view->palette().color (QPalette::Light));
gradient.setColorAt (1, hex_view->palette().color (QPalette::Midlight));
options.headerformat.background = gradient;
hex_view->setOptions (options);The issue is with this line: QLinearGradient gradient (0, 0, 0, headerRect().height());In order to paint the gradient we need to know the start and stop points. The default-constructed The solution I came up with is adding a few lines of code to Lines 649 to 656 in 6ecffde Add this after: if (hcf.background.gradient())
{
QGradient* gradient = const_cast <QGradient*> (hcf.background.gradient());
if (gradient->type() == QGradient::LinearGradient)
{
QLinearGradient* linear_gradient = reinterpret_cast <QLinearGradient*> (gradient);
linear_gradient->setStart (0, 0);
linear_gradient->setFinalStop (0, headerRect().height());
} // Should something be done with other gradient types as well?
}This is a bit unpleasant as
As I have shown above I am using only
I haven't used
Can't say much about this, it fits great in Now, on to what to do with
Good point, a line is, well, a line, it doesn't seem much can be done with it. There is, nonetheless, one case that needs to be addressed should bool MyDelegate::paintSeparator (QPainter* painter, QLineF line, const QHexView* hex_view) const override
{
qDrawShadeLine (painter, line.p1().toPoint(), line.p2().toPoint(), hex_view->palette());
return true;
}To call As for
I wouldn't worry too much about that, I mentioned that one extremely unlikely case when user can mess things up simply because I try to take everything into account, no matter how insignificant it is, but how much attention should be paid for it is a whole different matter. And I think that issue can be taken out entirely if you use There is one more thing I am using virtual void paint (QPainter* painter, const QHexView* hex_view) const override
{
static bool old_windows = QOperatingSystemVersion::current().majorVersion() <
QOperatingSystemVersion::Windows10.majorVersion();
if (old_windows)
{
QStyleOptionHeader headerStyleOption;
headerStyleOption.rect = QRect (0, 0, hex_view->width(), QFontMetrics(hex_view->font()).height());
hex_view->style()->drawControl (QStyle::CE_HeaderSection, &headerStyleOption, painter, hex_view);
}
QHexDelegate::paint (painter, hex_view);
}This, however, can be added as another of If everything that I have mentioned above is implemented, I personally would have no need for neither And if you are concerned that with too much access the user might mess up something else, don't be. That's the whole point of delegates, to boldly override where no man has overriden before, isn't it? If I screw up there with delegate it's on me, I know the risks as a user. I personally take advantage of Qt's own delegates and I am probably wandering too much into the "what if" territory there, talking beyond the funcionality I already use the delegates for. When I am not sure whether to remove something or not, I usually leave everything as is. But I am talking from the user perspective here, for you probably the most important question would be "will it be much of a burden to maintain these two functions?" And finally, if you decide to keep hex_view->setDelegate (some_delegate_that_paints_header);
hex_view->setOptions (any_options_there); // This is what messes things up
This is the part of Lines 525 to 528 in 6ecffde If we pass Now background is no longer Lines 660 to 661 in 6ecffde |
if(m_options.headerformat.background == Qt::NoBrush) {
m_options.headerformat.background =
this->palette().brush(QPalette::Base);
}
|
Me too, every time this pops up in my code it likely means that something ain't right, I was hesitant myself but could not come up with any other solution. In this case, however, it looks like the issue is with Qt's own API, not much we can do about that. Normally I'd expect it to have two methods - As you have shown they tend to violate these principles even in their own code, and in the case of
Don't mind that large wall of text I have written, I just sometimes get carried away and go deep into details. I myself always have that nagging desire to remove various things, constantly questioning whether I should keep something or not. I mentioned I was using |
Probably it's a better idea to leave this part as it is: if someone wants to use |
|
Alright, things are pretty good as they are now. We've got It seems like we've covered everything mentioned before, shall we move on to the next batch of suggestions? Let's talk about the First things first, it seems there is a bug: Any byte before the value Now on to the extra features it could benefit from. When
Also I beleive And I suppose since we already have got the All that combined would make it possible to customise the copy output for any programming language, That's a rough outline of how these features could be implemented. I guess something could go into |
It seems that
I have extended it a bit further: instead of adding more hardcoded/opinionated copy flavours I have introduced this tiny struct: QHexView/include/QHexView/qhexview.h Lines 17 to 24 in b7831d0 which allows to copy bytes in any format you want, eg: // Copy as C hexadecimal string
QHexCopyFormat cf;
cf.prefix = "\"";
cf.suffix = "\"";
cf.byte_prefix = "\\x";
hexview->copyFormat(cf); // copies as "\xAA\xBB\xCC"
// Copy as Common Lisp expression
QHexCopyFormat cf;
cf.prefix = "#(";
cf.suffix = ")";
cf.byte_prefix = "#x";
cf.separator = " ";
hexview->copyFormat(cf); // copies as #(#xAA #xBB #xCC)So:
Also, there is a new method called |
|
Excellent, this is even better than what I suggested, works great. A few minor notes:
Changing this (and in a few other places):
to this:
fixed it, but this was just a quick patch to get things working immediately, I didn't put much thought into it, so something may probably be incorrect.
the output could look like this: or maybe even like this:
Good idea, this is much simpler than having to take a screenshot, using graphical editor to crop the image, etc. when there is a need to share hex output. Actually I recently came across a conversation where something like that could have been used. A person was explaining a particular point in file which needed to be edited in a hex editor, and his messages consisted of something along the lines of "you've got to reach this piece of text... skip a few rows... then find that byte..." and so on, a quick copy like you've implemented would have simplified things a lot for him. Now, moving on to the search dialogs. So, say, we are looking for a hex pattern. Like this:
So far so good. But what if the gap represented by wildcard characters is larger. 8 bytes? 16 bytes? A whole lot more? Would be very inconvenient to repeatedly write lots of question marks. And I guarantee somewhere in the middle of copy-pasting the user forgets something and ends up with the incorrect number of bytes to skip. This could be addressed with a relatively small change to the syntax:
We could write the skip keyword followed by a decimal number of bytes to skip and after that proceed as usual. Honestly, I am a bit conflicted about it. If a more sophisticated search like that is required it probably means that the user is better off using an actual scripting language rather than a domain-specific one. On the other hand it feels like a nice thing to have, still looks simple enough and if it doesn't require much effort to implement, then why not? And one wouldn't want to link to the whole Python runtime just to skip a few dozens of bytes in a hex editor, would he? I wonder, since hex editors certainly have been there for a long time, shouldn't there be some standard similar to the regular expressions, or at least some common practices regarding the syntax of hexadecimal search? |
I have fixed the one in I have opted for this formatting style, it's available when
I haven't checked this one yet, I will do in the following days. |
Not to worry, I'm sticking to Qt5 and don't have any plans to switch to the new version any time soon, so whatever compiler errors arise I can report instantly. Speaking of which, there are two more places to apply the fix at: Lines 396 to 397 in b241464 I had a quick glance at documentation, they've changed the subscript operator's argument from plain integer to Regarding the new formatting style you've opted to, a few small suggestions, not crucial, but if they won't complicate the code much:
This does not really bother me, just being a bit pedantic there.
That'll do, it is slightly less obvious than the 'skip' keyword, but on the other hand being two characters long it is more aesthetically pleasing in this context. The number representing the byte span to skip might need to be more than two characters long though, however unlikely it may be. I suppose you may implement the feature with this limitation first and then figure out what to do to bypass it. Is the two-character policy due to spaces between hex bytes within the pattern being optional? If separating the pattern's bytes with spaces was enforced adding any keywords or even new syntax constructs might not be much of a challenge. Frankly speaking, I am not really a proponent of enforcing something or removing features, but what is the hex pattern not separated by spaces good for? One case I can think of is quickly copying an integer value in hexadecimal form from a calculator. But other than that anything beyond eight bytes is likely to look as gobbledegook in that notation. Well, maybe one other case is copying a hash value I suppose. Albeit I am speaking from a personal narrow perspective, maybe there are much more use cases for it that I am simply not aware of. Maybe you can even go as far as having two notations - one for simpy copy-pasting values for the cases I outlined and the other for manually constructing the pattern with a more sophisticated syntax. |
Great, thanks!
I did some tests, in my case the trailing whitespace is added because it's part of the separator (it's just appended as-is), separators can be right-trimmed when it's added before line break, I can add it as option in
The last commit finally implements pattern search with a more flexible implementation, so as we planned before, it supports:
Also edge cases like
Probably there are more edge cases, I haven't tested all possible combinations. AFAIK whitespaces was optional even before, now I'm 100% sure: whitespaces are simply ignored. |
Yea, if it won't bloat the function too much that'd be a small nice thing to have, along with the ability to control indentation (tabs, spaces, their count, etc.)
Gave it a try, haven't noticed any issues, and that's even better than what I suggested, that is it does not require the exact number of bytes to skip. Nonetheless sometimes writing exactly how much bytes to skip might improve the pattern. Here's a somewhat contrived example: let's say we're looking for a local host source address within a set of IPv4 packets. The first byte is typically
That will work correctly in 99,9% of cases. But there will be that one 0,01%, however unlikely, where other IPv4 header fields are formed in such a way that the Note that I don't really have any practical application for such feature in mind at this time, just thought that it would be something useful for the pattern syntax to have. |
Done, QHexView/include/QHexView/qhexview.h Lines 17 to 27 in 2cfdfaa
We can keep this implementation for now, it can be always improved later. PS: there is also this new feature which highlights changes done by the user. |
Seems like
Of course, no need to rush it. Could be a goal for the next 5.2 version. You actually might be the pioneer with this particular pattern-searching syntax, as I don't think I have seen anyone go beyond the simple Just make sure to write it down in some "TO DO" comment, or make a "TO DO" And a few things to add to this potential "TO DO" list. As before I am not sure how they will be useful in practice, but we can never find out unless this is implemented, and this being worthy of being added depends on how much effort it will take to implement.
Good addition, I checked it out. Do not hesitate to point out here any other discussions popping up because I might miss them as my full attention is on this one. I have a suggestion regarding this new feature, will post it in that discussion. Something that caught my attention in the last post in that thread is that you create a whole new You've also mentioned that both Usually I prefer to have all the API within the main widget with the rest of implementation being hidden and inaccessible to user, but in this case calling The null pointer check for the |
It's implemented, now we have QHexView/include/QHexView/model/qhexoptions.h Lines 51 to 52 in 1a76eda Also the tracking algorithm is changed a bit, because an insertion is implemented as insert + replace (press
These functions are there for convenience, but they can be removed or, at least, we can keep the most common ones. QHexDocument
QHexCursor
QHexMetadata
There is also a subtle visual change: the hex area byte's background is now x-padded by These are single bytes highlighted invidividually, but the extra padding makes it looks like a single rectangle. |
|
Tracking seems fine, just one thing needs to be fixed: upon calling This got me thinking, since I am using this to view network packets and frequently switch between them, the tracking colors data would need to be saved somewhere and restored upon switching. It being gone is not really an issue though, and it is probably not worth the effort to implement the save/restore functionality, so I am just pointing out the current behavior. And I'd probably use the full "insert" and "overwrite" words for the
That is a very nice list of the major functions you've written there, great starting point giving a quick and clear overview of the most important features. Free self-documenting code right here. With how neatly the API is decoupled now, it seems to me that getting the grasp of it is better through examining these individual classes rather than looking at a blob of functions of the main So the convenience functions might be more of a hindrance to learning the API than the actual convenience at this point. We don't have convenience functions for the All this is mostly speculative of course, despite me leaning more toward the convenience functions removal I am still not fully certain, but the points above seem to be fairly solid nonetheless. Ideally it should be a few other folks dropping by telling what they think, but chances are it'll be just two of us here discussing that.
This is a fine change, but I'd say, just like back when we discussed the |
Fixed, I've forgot to clear the list of changes, thanks for spotting it!
That's how the widget now restores previous changes: I put a copy of However, changes are stored in
I also don't really know what to keep in
Implemented as |
I have just realized that I forgot that I think a non-const counterpart of
Yea, it's a tough question, I guess it'll be clearer by the time the development will have been reaching the conclusion. Meanwhile better just keep these things we are not completely sure about (this and the syntax of hex search pattern) in some list so we won't have to dig through this discussion again when working on the next versions.
Doesn't seem to make much difference, if any at all to me, but adjusting the divisor here seems to do the trick: Lines 80 to 84 in 628d248 Replacing the number 2 with not 4, not 8, but actually 16 (!) does bring back the old style. No idea why exactly this number, but it appears to work fine with this value, at least on my high DPI system. Now, moving on to a few bugs regarding incorrect rectangles returned for some areas. Note that there is a very small chance these might be outdated as I have prepared this text in advance and decided to wait till we finished with copy formats and change tracking, so the discussion does not become cluttered. So here the bugs are: The width of the address rectangle returned by the This is the calculation I came up with: constexpr unsigned int address_padding = 2;
qreal width = (this->addressWidth() + address_padding) * this->cellWidth();
return QRectF (0, y, width, this->height() - y);The width of this->endColumnX() - this->asciiColumnX()Add cellWidth() to it: this->endColumnX() - this->asciiColumnX() + this->cellWidth()Speaking of rectangles, since we have Having these three functions you can remove their counterparts in This is how my delegate paints the position of the selected byte after I experimented a bit: static const QString pos_string = QStringLiteral ("Pos:");
QHexPosition position = hex_view->hexCursor()->position();
QRectF rect = hex_view->headerAddressRect();
painter->save();
painter->setPen (hex_view->options().header_format.foreground);
painter->drawText (rect, pos_string);
rect.setLeft (hex_view->cellWidth() * pos_string.size() + hex_view->cellWidth() / 2);
painter->drawText (rect, QString::number (position.line * 16 + position.column).rightJustified (5, '0'));
painter->restore();
QHexDelegate::paint (painter, hex_view);This is how it looks: This is a bit more complex than simply using the And the more freedom I have in
Speaking of the latter, I turned And now here we arrive back at the dilemma of what to keep in the By the time the development is getting close to finish and things become much clearer a final assessment regarding what part of the |



Uh oh!
There was an error while loading. Please reload this page.
5.1 development topic
All reactions