Skip to content
Open
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
288d478
Basic AddressRangeScrollbar implementation
Anohkka May 23, 2025
1ff1fc0
Use AddressRangeScrollbar for the disassembly window scrollbar
Anohkka May 23, 2025
fa2d1ea
Move more code into AddressRangeScrollbar
Anohkka May 23, 2025
a773f8a
Add scroll bar to hex widget
Anohkka May 23, 2025
0eb474a
Use signals instead of return value for AddressRangeScrollbar::setPos…
Anohkka May 23, 2025
030f115
Format and rename
Anohkka May 23, 2025
a90caa2
Increase scrolling speed while hovering over hex widget scroll bar
Anohkka May 25, 2025
da46c4f
Fix missing includes
Anohkka May 26, 2025
0954551
Format HexWidget.h
Anohkka May 26, 2025
eca187e
Fix formatting yet again
Anohkka May 26, 2025
0ced237
Remove redundant connection to disassembly widget scroll bar
Anohkka May 27, 2025
31aa1df
Scroll line by line with hex widget scroll bar and make it not seek
Anohkka May 27, 2025
f8d939e
Use signals for disassembly window scroll bar
Anohkka May 27, 2025
7d47e00
Snap to addresses with the hex widget scroll bar like seeking does
Anohkka May 27, 2025
d889afa
Fix being able to scroll past the end with scroll buttons in hex widget
Anohkka May 27, 2025
226bc11
Fix formatting
Anohkka May 27, 2025
dfeddc6
Format HexWidget.cpp
Anohkka May 27, 2025
f6575a9
Fix a missing emit
Anohkka May 27, 2025
8403d70
Handle page step
Anohkka Jun 3, 2025
3e92ec4
Add HexWidget::showPosition function
Anohkka Jun 3, 2025
ba6f1ef
Update scroll bar with hex widget viewport
Anohkka Jun 3, 2025
be7ecdb
Fix page step up in hex widget causing an integer underflow
Anohkka Jun 7, 2025
68ca6cf
Prevent page step from scrolling out of range in hex widget
Anohkka Jun 7, 2025
cca76cb
Prevent page step from scrolling out of range in disassembly widget
Anohkka Jun 7, 2025
102d873
Merge branch 'dev' into address-range-scroll-bar
Anohkka Oct 16, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ set(SOURCES
tools/basefind/BaseFindDialog.cpp
tools/basefind/BaseFindSearchDialog.cpp
tools/basefind/BaseFindResultsDialog.cpp
widgets/AddressRangeScrollBar.cpp
)
set(HEADER_FILES
core/Cutter.h
Expand Down Expand Up @@ -319,6 +320,7 @@ set(HEADER_FILES
tools/basefind/BaseFindDialog.h
tools/basefind/BaseFindSearchDialog.h
tools/basefind/BaseFindResultsDialog.h
widgets/AddressRangeScrollBar.h
)
set(UI_FILES
dialogs/AboutDialog.ui
Expand Down Expand Up @@ -500,7 +502,7 @@ endif()

target_link_libraries(Cutter PUBLIC ${RIZIN_TARGET})
if(CUTTER_ENABLE_PYTHON)
if(CMAKE_VERSION VERSION_LESS "3.12.0")
if(CMAKE_VERSION VERSION_LESS "3.12.0")
# On windows some of the Python STABLE API functions are in seperate library
# which isn't added by CMake.
if (WIN32)
Expand Down
177 changes: 177 additions & 0 deletions src/widgets/AddressRangeScrollBar.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
#include "AddressRangeScrollBar.h"
#include "Cutter.h"

#include <QWheelEvent>

#include <algorithm>
#include <cstring>

AddressRangeScrollBar::AddressRangeScrollBar(QWidget *parent) : QScrollBar(parent)
{
setSingleStep(0);
connect(Core(), &CutterCore::refreshAll, this, &AddressRangeScrollBar::refreshRange);
connect(this, &AddressRangeScrollBar::actionTriggered, this, [this](int action) {
switch (action) {
// Due to the way the QScrollBar::actionTriggered signal works,
// setting the slider pos to its current value here
// prevents it from moving, allowing us to basically
// override behavior for specific actions
// See https://doc.qt.io/qt-6/qabstractslider.html#actionTriggered
// for more info.
case QAbstractSlider::SliderSingleStepAdd:
setSliderPosition(value());
if (value() == maximum())
return;
emit scrolled(-3);
return;
case QAbstractSlider::SliderSingleStepSub:
setSliderPosition(value());
if (value() == minimum())
return;
emit scrolled(3);
return;
default:
return;
}
});
}

void AddressRangeScrollBar::refreshRange()
{
beginOffset = RVA_MAX;
endOffset = 0;
if (!Core()->currentlyEmulating && Core()->currentlyDebugging) {
QString currentlyOpenFile = Core()->getConfig("file.path");
QList<MemoryMapDescription> memoryMaps = Core()->getMemoryMap();
for (const MemoryMapDescription &map : memoryMaps) {
if (map.fileName == currentlyOpenFile) {
if (map.addrStart < beginOffset) {
beginOffset = map.addrStart;
}
if (map.addrEnd > endOffset) {
endOffset = map.addrEnd;
}
}
}
} else {
RzCoreLocked core(Core());
RzPVector *mapsPtr = rz_io_maps(core->io);
if (!mapsPtr) {
emit hideScrollBar();
return;
}
CutterPVector<RzIOMap> maps { mapsPtr };
for (const RzIOMap *const map : maps) {
// Skip the ESIL memory stack region
if (Core()->currentlyEmulating && std::strncmp(rz_str_get(map->name), "mem.", 4) == 0) {
continue;
}
ut64 b = rz_itv_begin(map->itv);
ut64 e = rz_itv_end(map->itv);
if (b < beginOffset) {
beginOffset = b;
}
if (e > endOffset) {
endOffset = e;
}
}
}
if (endOffset) {
--endOffset;
}
if (endOffset == 0) {
beginOffset = 0;
}
setMinimum(0);
// Increasing this value increases scroll bar accuracy for small files but
// decreases it for large files
// Sufficiently below 2^32 to avoid causing problems in calculations done by QScrollbar,
// otherwise as high as possible to maximize range in which address map 1:1 to scrollbar pos.
const int rangeMax = 512 * 1024 * 1024;
if (rangeSize() > rangeMax) {
setMaximum(rangeMax);
} else {
setMaximum(rangeSize());
}
if (rangeSize()) {
emit showScrollBar();
return;
}
emit hideScrollBar();
return;
}

void AddressRangeScrollBar::setPosition(RVA address)
{
const QSignalBlocker blocker(this);
if (!maximum() || !rangeSize()) {
emit hideScrollBar();
return;
}
int scrollBarPos = 0;
if (address < beginOffset) {
setValue(scrollBarPos);
emit showScrollBar();
return;
}
if (address > endOffset) {
setValue(maximum());
emit showScrollBar();
return;
}
auto offset = address - beginOffset;
if ((RVA_MAX / maximum()) < rangeSize()) {
// Fallback formula for large files
uint64_t smallBox = rangeSize() / maximum();
uint64_t extra = rangeSize() % maximum();
auto bigBoxRange = (smallBox + 1) * extra;
if (offset < bigBoxRange) {
scrollBarPos = offset / (smallBox + 1);
} else {
scrollBarPos = extra + (offset - bigBoxRange) / smallBox;
}
} else {
scrollBarPos = (maximum() * offset) / rangeSize();
}
if (address != beginOffset && scrollBarPos == 0) {
scrollBarPos = 1;
}
setValue(scrollBarPos);
emit showScrollBar();
return;
}

RVA AddressRangeScrollBar::address()
{
if (!maximum() || !rangeSize()) {
return beginOffset;
}
// Fallback formula for large files
if ((RVA_MAX / maximum()) < rangeSize()) {
return value() * (rangeSize() / maximum()) + std::min<RVA>(value(), rangeSize() % maximum())
+ beginOffset;
}
return (value() * rangeSize()) / maximum() + beginOffset;
}

RVA AddressRangeScrollBar::rangeSize()
{
return endOffset - beginOffset;
}

void AddressRangeScrollBar::wheelEvent(QWheelEvent *event)
{
accumScrollWheelDeltaY += event->angleDelta().y();
// Delta is reported in 1/8 of a degree
// eg. 120 units * 1/8 = 15 degrees
// Typical scroll speed is 1 line per 5 degrees
const int lineDelta = 5 * 8;
if (accumScrollWheelDeltaY >= lineDelta || accumScrollWheelDeltaY <= -lineDelta) {
int lineCount = accumScrollWheelDeltaY / lineDelta;
accumScrollWheelDeltaY -= lineDelta * lineCount;
if ((lineCount < 0 && value() == maximum()) || (lineCount > 0 && value() == minimum())) {
return;
}
emit scrolled(lineCount);
}
}
30 changes: 30 additions & 0 deletions src/widgets/AddressRangeScrollBar.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#ifndef ADDRESS_RANGE_SCROLLBAR_H
#define ADDRESS_RANGE_SCROLLBAR_H

#include <QScrollBar>
#include "CutterCommon.h"

class AddressRangeScrollBar : public QScrollBar
{
Q_OBJECT
public:
AddressRangeScrollBar(QWidget *parent = nullptr);
void refreshRange();
void setPosition(RVA address);
RVA address();
RVA rangeSize();

signals:
void hideScrollBar();
void showScrollBar();
void scrolled(int lines);

protected:
void wheelEvent(QWheelEvent *event) override;

private:
RVA beginOffset = 0, endOffset = RVA_INVALID;
int accumScrollWheelDeltaY = 0;
};

#endif // ADDRESS_RANGE_SCROLLBAR_H
Loading
Loading