Skip to content

Commit

Permalink
[WIP] byte colouring
Browse files Browse the repository at this point in the history
  • Loading branch information
solemnwarning committed Apr 20, 2024
1 parent 35cad11 commit c66e6a6
Show file tree
Hide file tree
Showing 8 changed files with 735 additions and 33 deletions.
4 changes: 4 additions & 0 deletions Makefile
Expand Up @@ -351,6 +351,7 @@ APP_OBJS := \
src/BitmapTool.$(BUILD_TYPE).o \
src/buffer.$(BUILD_TYPE).o \
src/BytesPerLineDialog.$(BUILD_TYPE).o \
src/ByteColourMap.$(BUILD_TYPE).o \
src/ByteRangeSet.$(BUILD_TYPE).o \
src/CharacterEncoder.$(BUILD_TYPE).o \
src/CharacterFinder.$(BUILD_TYPE).o \
Expand Down Expand Up @@ -396,6 +397,7 @@ APP_OBJS := \
src/RangeProcessor.$(BUILD_TYPE).o \
src/search.$(BUILD_TYPE).o \
src/SettingsDialog.$(BUILD_TYPE).o \
src/SettingsDialogByteColour.$(BUILD_TYPE).o \
src/SettingsDialogHighlights.$(BUILD_TYPE).o \
src/StringPanel.$(BUILD_TYPE).o \
src/textentrydialog.$(BUILD_TYPE).o \
Expand Down Expand Up @@ -451,6 +453,7 @@ TEST_OBJS := \
src/BitOffset.$(BUILD_TYPE).o \
src/BitmapTool.$(BUILD_TYPE).o \
src/buffer.$(BUILD_TYPE).o \
src/ByteColourMap.$(BUILD_TYPE).o \
src/ByteRangeSet.$(BUILD_TYPE).o \
src/BytesPerLineDialog.$(BUILD_TYPE).o \
src/CharacterEncoder.$(BUILD_TYPE).o \
Expand Down Expand Up @@ -488,6 +491,7 @@ TEST_OBJS := \
src/RangeProcessor.$(BUILD_TYPE).o \
src/search.$(BUILD_TYPE).o \
src/SettingsDialog.$(BUILD_TYPE).o \
src/SettingsDialogByteColour.$(BUILD_TYPE).o \
src/SettingsDialogHighlights.$(BUILD_TYPE).o \
src/StringPanel.$(BUILD_TYPE).o \
src/Tab.$(BUILD_TYPE).o \
Expand Down
108 changes: 108 additions & 0 deletions src/ByteColourMap.cpp
@@ -0,0 +1,108 @@
/* Reverse Engineer's Hex Editor
* Copyright (C) 2024 Daniel Collins <solemnwarning@solemnwarning.net>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

#include "App.hpp"
#include "ByteColourMap.hpp"

REHex::ByteColourMap::ByteColourMap() {}

// REHex::ByteColourMap::ByteColourMap(const wxConfigBase *config)

void REHex::ByteColourMap::set_colour(unsigned char byte, int colour1, int colour2, int colour_delta_steps, int colour_delta_pos)
{
auto &elem = bytes[byte];

assert(colour_delta_steps >= colour_delta_pos);

elem.colour1 = colour1;
elem.colour2 = colour2;
elem.colour_delta_steps = colour_delta_steps;
elem.colour_delta_pos = colour_delta_pos;
}

wxColour REHex::ByteColourMap::get_colour(unsigned char byte) const
{
auto &elem = bytes[byte];

return elem.get_colour();
}

const REHex::ByteColourMap::Value &REHex::ByteColourMap::get_value(unsigned char byte) const
{
return bytes[byte];
}

bool REHex::ByteColourMap::Value::is_single() const
{
return colour_delta_steps == 0;
}

bool REHex::ByteColourMap::Value::is_start() const
{
return colour_delta_pos == 0 && colour_delta_steps > 0;
}

bool REHex::ByteColourMap::Value::is_end() const
{
return colour_delta_pos == colour_delta_steps && colour_delta_steps > 0;
}

wxColour REHex::ByteColourMap::Value::get_colour() const
{
wxColour c1, c2;

if(colour1 >= 0 && colour1 <= Palette::PAL_MAX)
{
c1 = (*active_palette)[colour1];
}
else if(colour1 >= Palette::PAL_INVALID && colour2 < (Palette::PAL_INVALID + HighlightColourMap::MAX_NUM))
{
HighlightColourMap highlight_colours = wxGetApp().settings->get_highlight_colours();
c1 = highlight_colours[colour1 - Palette::PAL_INVALID].primary_colour;
}
else{
c1 = (*active_palette)[Palette::PAL_NORMAL_TEXT_FG];
}

if(colour_delta_steps == 0)
{
return c1;
}

if(colour2 >= 0 && colour2 <= Palette::PAL_MAX)
{
c2 = (*active_palette)[colour2];
}
else if(colour2 >= Palette::PAL_INVALID && colour2 < (Palette::PAL_INVALID + HighlightColourMap::MAX_NUM))
{
HighlightColourMap highlight_colours = wxGetApp().settings->get_highlight_colours();
c2 = highlight_colours[colour2 - Palette::PAL_INVALID].primary_colour;
}
else{
c2 = (*active_palette)[Palette::PAL_NORMAL_TEXT_FG];
}

float alpha = (float)(colour_delta_pos) / (float)(colour_delta_steps);

unsigned char r = wxColour::AlphaBlend(c2.Red(), c1.Red(), alpha);
unsigned char g = wxColour::AlphaBlend(c2.Green(), c1.Green(), alpha);
unsigned char b = wxColour::AlphaBlend(c2.Blue(), c1.Blue(), alpha);

return wxColour(r, g, b);
}

// void REHex::ByteColourMap::save(wxConfigBase *config);
69 changes: 69 additions & 0 deletions src/ByteColourMap.hpp
@@ -0,0 +1,69 @@
/* Reverse Engineer's Hex Editor
* Copyright (C) 2024 Daniel Collins <solemnwarning@solemnwarning.net>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

#ifndef REHEX_BYTECOLOURMAP_HPP
#define REHEX_BYTECOLOURMAP_HPP

#include <wx/colour.h>
#include <wx/config.h>

#include "Palette.hpp"

namespace REHex
{
class ByteColourMap
{
public:
struct Value
{
int colour1; /**< 0..PAL_MAX = palette colour, PAL_INVALID+n = highlight colour n */
int colour2; /**< 0..PAL_MAX = palette colour, PAL_INVALID+n = highlight colour n */

int colour_delta_steps;
int colour_delta_pos;

Value():
colour1(Palette::PAL_NORMAL_TEXT_FG),
colour2(Palette::PAL_NORMAL_TEXT_FG),
colour_delta_steps(0),
colour_delta_pos(0) {}

bool is_single() const;
bool is_start() const;
bool is_end() const;

wxColour get_colour() const;
};

private:
Value bytes[256];

public:
ByteColourMap();
ByteColourMap(const wxConfigBase *config);

void set_colour(unsigned char byte, int colour1, int colour2, int colour_delta_steps, int colour_delta_pos);

wxColour get_colour(unsigned char byte) const;

const Value &get_value(unsigned char byte) const;

void save(wxConfigBase *config);
};
}

#endif /* !REHEX_BYTECOLOURMAP_HPP */
104 changes: 72 additions & 32 deletions src/DocumentCtrl.cpp
Expand Up @@ -76,7 +76,7 @@ static unsigned int pack_colour(const wxColour &colour)
return (unsigned int)(colour.Red()) | ((unsigned int)(colour.Blue()) << 8) | ((unsigned int)(colour.Green()) << 16);
}

REHex::DocumentCtrl::DocumentCtrl(wxWindow *parent, SharedDocumentPointer &doc):
REHex::DocumentCtrl::DocumentCtrl(wxWindow *parent, SharedDocumentPointer &doc, long style):
wxControl(),
doc(doc),
hex_font(wxFontInfo().FaceName(wxGetApp().get_font_name())),
Expand Down Expand Up @@ -108,7 +108,7 @@ REHex::DocumentCtrl::DocumentCtrl(wxWindow *parent, SharedDocumentPointer &doc):
/* The background style MUST be set before the control is created. */
SetBackgroundStyle(wxBG_STYLE_PAINT);
Create(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize,
(wxVSCROLL | wxHSCROLL | wxWANTS_CHARS));
(wxVSCROLL | wxHSCROLL | wxWANTS_CHARS | style));

client_width = 0;
client_height = 0;
Expand Down Expand Up @@ -937,7 +937,14 @@ void REHex::DocumentCtrl::_handle_width_change()
}

/* TODO: Preserve/scale the position as the window size changes. */
SetScrollbar(wxHORIZONTAL, 0, client_width, virtual_width);

if((GetWindowStyle() & DCTRL_LOCK_SCROLL) == 0)
{
SetScrollbar(wxHORIZONTAL, 0, client_width, virtual_width);
}
else{
SetScrollbar(wxHORIZONTAL, 0, 0, 0);
}

/* Update vertical scrollbar, since we just recalculated the height of the document. */
_update_vscroll();
Expand Down Expand Up @@ -1031,6 +1038,11 @@ void REHex::DocumentCtrl::_update_vscroll()
scroll_yoff_max = 0;
}

if((GetWindowStyle() & DCTRL_LOCK_SCROLL) != 0)
{
SetScrollbar(wxVERTICAL, 0, 0, 0);
}

linked_scroll_visit_others([this](DocumentCtrl *other)
{
other->scroll_yoff = scroll_yoff;
Expand All @@ -1047,6 +1059,11 @@ void REHex::DocumentCtrl::_update_vscroll()

void REHex::DocumentCtrl::_update_vscroll_pos(bool update_linked_scroll_others)
{
if((GetWindowStyle() & DCTRL_LOCK_SCROLL) != 0)
{
return;
}

int range = GetScrollRange(wxVERTICAL);
int thumb = GetScrollThumb(wxVERTICAL);

Expand Down Expand Up @@ -1207,6 +1224,11 @@ void REHex::DocumentCtrl::restore_scroll_position()

void REHex::DocumentCtrl::OnScroll(wxScrollWinEvent &event)
{
if((GetWindowStyle() & DCTRL_LOCK_SCROLL) != 0)
{
return;
}

wxEventType type = event.GetEventType();
int orientation = event.GetOrientation();

Expand Down Expand Up @@ -1307,6 +1329,11 @@ void REHex::DocumentCtrl::OnScroll(wxScrollWinEvent &event)

void REHex::DocumentCtrl::OnWheel(wxMouseEvent &event)
{
if((GetWindowStyle() & DCTRL_LOCK_SCROLL) != 0)
{
return;
}

wxMouseWheelAxis axis = event.GetWheelAxis();
int delta = event.GetWheelDelta();
int ticks_per_delta = event.GetLinesPerAction();
Expand Down Expand Up @@ -1618,7 +1645,7 @@ void REHex::DocumentCtrl::OnChar(wxKeyEvent &event)

_set_cursor_position(new_cursor_pos, Document::CSTATE_GOTO);

if (update_scrollpos)
if (update_scrollpos && (GetWindowStyle() & DCTRL_LOCK_SCROLL) == 0)
{
scroll_yoff = new_scroll_yoff;
_update_vscroll_pos();
Expand Down Expand Up @@ -1988,40 +2015,43 @@ void REHex::DocumentCtrl::OnMotionTick(int mouse_x, int mouse_y)

wxClientDC dc(this);

int scroll_xoff_max = GetScrollRange(wxHORIZONTAL) - GetScrollThumb(wxHORIZONTAL);

if(mouse_x < 0)
{
scroll_xoff -= std::min(abs(mouse_x), scroll_xoff);
SetScrollPos(wxHORIZONTAL, scroll_xoff);

mouse_x = 0;
}
else if(mouse_x >= client_width)
if((GetWindowStyle() & DCTRL_LOCK_SCROLL) == 0)
{
scroll_xoff += std::min((int)(mouse_x - client_width), (scroll_xoff_max - scroll_xoff));
SetScrollPos(wxHORIZONTAL, scroll_xoff);
int scroll_xoff_max = GetScrollRange(wxHORIZONTAL) - GetScrollThumb(wxHORIZONTAL);

mouse_x = client_width - 1;
}

if(mouse_y < 0)
{
scroll_yoff -= std::min((int64_t)(abs(mouse_y) / hf_height + 1), scroll_yoff);
_update_vscroll_pos();
if(mouse_x < 0)
{
scroll_xoff -= std::min(abs(mouse_x), scroll_xoff);
SetScrollPos(wxHORIZONTAL, scroll_xoff);

mouse_x = 0;
}
else if(mouse_x >= client_width)
{
scroll_xoff += std::min((int)(mouse_x - client_width), (scroll_xoff_max - scroll_xoff));
SetScrollPos(wxHORIZONTAL, scroll_xoff);

mouse_x = client_width - 1;
}

mouse_y = 0;
}
else if(mouse_y >= client_height)
{
scroll_yoff += std::min((int64_t)((mouse_y - client_height) / hf_height + 1), (scroll_yoff_max - scroll_yoff));
_update_vscroll_pos();
if(mouse_y < 0)
{
scroll_yoff -= std::min((int64_t)(abs(mouse_y) / hf_height + 1), scroll_yoff);
_update_vscroll_pos();

mouse_y = 0;
}
else if(mouse_y >= client_height)
{
scroll_yoff += std::min((int64_t)((mouse_y - client_height) / hf_height + 1), (scroll_yoff_max - scroll_yoff));
_update_vscroll_pos();

mouse_y = client_height - 1;
}

mouse_y = client_height - 1;
save_scroll_position();
}

save_scroll_position();

int rel_x = mouse_x + scroll_xoff;

/* Find the region containing the first visible line. */
Expand Down Expand Up @@ -2685,6 +2715,11 @@ void REHex::DocumentCtrl::_make_x_visible(int x_px, int width_px)
*/
void REHex::DocumentCtrl::_make_byte_visible(BitOffset offset)
{
if((GetWindowStyle() & DCTRL_LOCK_SCROLL) != 0)
{
return;
}

auto dr = _data_region_by_offset(offset);
assert(dr != data_regions.end());

Expand Down Expand Up @@ -3199,6 +3234,11 @@ void REHex::DocumentCtrl::set_scroll_yoff(int64_t scroll_yoff, bool update_linke

void REHex::DocumentCtrl::set_scroll_yoff_clamped(int64_t scroll_yoff)
{
if((GetWindowStyle() & DCTRL_LOCK_SCROLL) != 0)
{
return;
}

if(scroll_yoff < 0)
{
scroll_yoff = 0;
Expand Down

0 comments on commit c66e6a6

Please sign in to comment.