425 lines
12 KiB
C++
425 lines
12 KiB
C++
#ifndef WX_VIEWSUPT_H
|
|
#define WX_VIEWSUPT_H
|
|
|
|
#include <wx/wx.h>
|
|
#include <wx/window.h>
|
|
#include <wx/image.h>
|
|
#include <wx/caret.h>
|
|
#include <wx/spinctrl.h>
|
|
#include <wx/dialog.h>
|
|
#include <wx/panel.h>
|
|
#include <wx/dialog.h>
|
|
#include <wx/textctrl.h>
|
|
#include <wx/scrolbar.h>
|
|
#include <wx/stattext.h>
|
|
#include <wx/checkbox.h>
|
|
|
|
#include <stdint.h> // for uint32_t
|
|
|
|
// avoid exporting too much stuff
|
|
namespace Viewers {
|
|
// common to all viewers:
|
|
// - track in MainFrame::popups
|
|
// - wxID_CLOSE button closes window
|
|
// - AutoUpdate checkbox toggles calling Update() every screen refresh
|
|
class Viewer : public wxDialog {
|
|
public:
|
|
void CloseDlg(wxCloseEvent& ev);
|
|
Viewer(const wxString& name);
|
|
virtual ~Viewer()
|
|
{
|
|
}
|
|
virtual void Update() = 0;
|
|
bool auto_update;
|
|
|
|
// A lot of viewers have GUI elements to set parameters. Almost all
|
|
// of them just read back the value and update the display. This
|
|
// event handler does that with validators.
|
|
void ActiveCtrl(wxCommandEvent& ev);
|
|
void ActiveCtrlScr(wxScrollEvent& ev)
|
|
{
|
|
ActiveCtrl(ev);
|
|
}
|
|
void ActiveCtrlSpin(wxSpinEvent& ev)
|
|
{
|
|
ActiveCtrl(ev);
|
|
}
|
|
|
|
protected:
|
|
wxString dname;
|
|
void SetAutoUpdate(wxCommandEvent& ev)
|
|
{
|
|
auto_update = ev.IsChecked();
|
|
}
|
|
|
|
DECLARE_EVENT_TABLE()
|
|
};
|
|
|
|
// on errors, abort program
|
|
#define baddialog() \
|
|
do { \
|
|
wxLogError(_("Unable to load dialog %s from resources"), dname.c_str()); \
|
|
wxGetApp().frame->Close(true); \
|
|
return; \
|
|
} while (0)
|
|
|
|
// widgets to use with auto validator
|
|
#define getvfld(sv, n, t, v) \
|
|
do { \
|
|
t* _w = sv XRCCTRL(*this, n, t); \
|
|
if (!_w) \
|
|
baddialog(); \
|
|
_w->SetValidator(v); \
|
|
} while (0)
|
|
#define getradio(sv, n, var, val) getvfld(sv, n, wxRadioButton, wxBoolIntValidator(&var, val))
|
|
#define getslider(sv, n, var) getvfld(sv, n, wxSlider, wxGenericValidator(&var))
|
|
#define getspin(sv, n, var) getvfld(sv, n, wxSpinCtrl, wxGenericValidator(&var))
|
|
|
|
#define LoadXRCViewer(t) \
|
|
do { \
|
|
wxDialog* d = new Viewers::t##Viewer; \
|
|
if (d) { \
|
|
d->SetWindowStyle(wxCAPTION | wxRESIZE_BORDER); \
|
|
d->Show(); \
|
|
} \
|
|
} while (0)
|
|
|
|
// a list box with no horizontal scrollbar and a funky vertical scrollbar:
|
|
// range = 1 - 500
|
|
// but/pagesz = # of lines shown/# of lines shown - 1
|
|
// 1-100 = normal
|
|
// 101-200 = 10x semi-stationary
|
|
// 201-300 = stationary @ center
|
|
// 301-400 = 10x semi-stationary
|
|
// 401-500 = normal
|
|
|
|
// note that since listboxes' size is impossible to control correctly (at
|
|
// least with wxGTK), this uses a textctrl to display the items.
|
|
|
|
class DisList : public wxPanel {
|
|
public:
|
|
DisList();
|
|
// called after init to create subcontrols and size panel
|
|
void Refit(int cols);
|
|
void MoveSB();
|
|
void MoveView(wxScrollEvent& ev);
|
|
|
|
private:
|
|
void RefillNeeded();
|
|
|
|
public:
|
|
// called by parent's refill handler or any other time strings have
|
|
// changed
|
|
void Refill();
|
|
|
|
private:
|
|
void Resize(wxSizeEvent& ev);
|
|
void SetSel();
|
|
|
|
public:
|
|
// make addr visible and then select it
|
|
void SetSel(uint32_t addr);
|
|
void UnSel()
|
|
{
|
|
issel = false;
|
|
}
|
|
|
|
// currently visible lines
|
|
int nlines;
|
|
// at least nlines strings to display
|
|
wxArrayString strings;
|
|
// and their starting addrs (mostly for scrollbar)
|
|
wxArrayInt addrs;
|
|
// how far back to scroll for single line
|
|
int back_size;
|
|
// address of top line
|
|
uint32_t topaddr;
|
|
// max address for scrollbar
|
|
uint32_t maxaddr;
|
|
|
|
protected:
|
|
// assigned to textctrl to avoid mouse input
|
|
void MouseEvent(wxMouseEvent& ev)
|
|
{
|
|
(void)ev; // unused param
|
|
}
|
|
// the subwidgets
|
|
wxTextCtrl tc;
|
|
wxScrollBar sb;
|
|
// cached computed line tc size
|
|
int lineheight, extraheight;
|
|
// need to know if tc/sb have been Create()d yet
|
|
bool didinit;
|
|
// selection info
|
|
uint32_t seladdr;
|
|
bool issel;
|
|
|
|
DECLARE_DYNAMIC_CLASS(DisList) // for xrc
|
|
DECLARE_EVENT_TABLE()
|
|
};
|
|
|
|
BEGIN_DECLARE_EVENT_TYPES()
|
|
// event generated when fewer lines available than needed
|
|
DECLARE_LOCAL_EVENT_TYPE(EVT_REFILL_NEEDED, 0)
|
|
END_DECLARE_EVENT_TYPES()
|
|
|
|
// a hex editor with a funky scrollbar like above
|
|
|
|
// since it's impossible to exercise this much control over a text
|
|
// control, it uses a panel into which text is drawn.
|
|
// Maybe some day the above will be changed to do that as well, since
|
|
// it allows better mouse control as well.
|
|
|
|
class MemView : public wxPanel {
|
|
public:
|
|
MemView();
|
|
// called after init to create subcontrols and size panel
|
|
void Refit();
|
|
void MoveSB();
|
|
void MoveView(wxScrollEvent& ev);
|
|
|
|
private:
|
|
void RefillNeeded();
|
|
|
|
public:
|
|
// called by parent's refill handler or any other time strings have
|
|
// changed
|
|
void Refill();
|
|
|
|
private:
|
|
void Refill(wxDC& dc);
|
|
void RepaintEv(wxPaintEvent& ev);
|
|
void Repaint();
|
|
void Resize(wxSizeEvent& ev);
|
|
|
|
public:
|
|
// make addr visible
|
|
void ShowAddr(uint32_t addr, bool force_update = false);
|
|
|
|
// current selection, or topaddr if none
|
|
uint32_t GetAddr();
|
|
// currently visible lines
|
|
int nlines;
|
|
// at least nlines * 4 words to display
|
|
wxArrayInt words;
|
|
// address of top line
|
|
uint32_t topaddr;
|
|
// max address for scrollbar
|
|
uint32_t maxaddr;
|
|
// bytes per word == (1 << fmt)
|
|
int fmt;
|
|
// after write, these contain write addr and val
|
|
uint32_t writeaddr, writeval;
|
|
// when selection is made, this widget is updated w/ addr
|
|
wxControl* addrlab;
|
|
|
|
protected:
|
|
// easier than checking maxaddr
|
|
int addrlen;
|
|
|
|
void MouseEvent(wxMouseEvent& ev);
|
|
void KeyEvent(wxKeyEvent& ev);
|
|
// the subwidgets
|
|
wxPanel disp;
|
|
wxScrollBar sb;
|
|
wxCaret* caret;
|
|
// cached text size
|
|
int charheight, charwidth;
|
|
// need to know if tc/sb have been Create()d yet
|
|
bool didinit;
|
|
// selection info
|
|
int selnib, seladdr;
|
|
bool isasc;
|
|
void ShowCaret();
|
|
|
|
DECLARE_DYNAMIC_CLASS(MemView) // for xrc
|
|
DECLARE_EVENT_TABLE()
|
|
};
|
|
|
|
BEGIN_DECLARE_EVENT_TYPES()
|
|
// event generated when write occurs
|
|
// check writeaddr/writeval/fmt
|
|
DECLARE_LOCAL_EVENT_TYPE(EVT_WRITEVAL, 0)
|
|
END_DECLARE_EVENT_TYPES()
|
|
|
|
// Display a color in a square, with the RGB value to its right.
|
|
|
|
// this is too hard to integrate into xrc (impossible to initialize
|
|
// correctly) so no accomodations are made for this
|
|
|
|
class ColorView : public wxControl {
|
|
public:
|
|
ColorView(wxWindow* parent, wxWindowID id);
|
|
void SetRGB(int r, int g, int b);
|
|
void GetRGB(int& _r, int& _g, int& _b)
|
|
{
|
|
_r = r;
|
|
_g = g;
|
|
_b = b;
|
|
}
|
|
|
|
protected:
|
|
int r, g, b;
|
|
wxPanel* cp;
|
|
wxStaticText *rt, *gt, *bt;
|
|
};
|
|
#define unkctrl(n, v) \
|
|
do { \
|
|
if (!wxXmlResource::Get()->AttachUnknownControl(wxT(n), v, this)) \
|
|
baddialog(); \
|
|
} while (0)
|
|
#define colorctrl(v, n) \
|
|
do { \
|
|
v = new ColorView(this, XRCID(n)); \
|
|
if (!v) \
|
|
baddialog(); \
|
|
unkctrl(n, v); \
|
|
} while (0)
|
|
|
|
// Display a small bitmap in jumbopixel style. If a pixel is selected, it
|
|
// is highlighted with a border. For wxvbam, no event is generated.
|
|
// Instead, a ColorView can be assigned to it, and on selection, that
|
|
// widget will be updated to the selected color.
|
|
// The whole class can also be derived to add more functionality to the
|
|
// button click.
|
|
|
|
// It must be intialized in 3 phases: 2-phase xrc-style (new + Create()),
|
|
// and then InitBMP()
|
|
|
|
class PixView : public wxPanel {
|
|
public:
|
|
PixView()
|
|
: wxPanel()
|
|
, bm(0)
|
|
{
|
|
}
|
|
bool InitBMP(int w = 8, int h = 8, ColorView* cv = NULL);
|
|
// stride is in pixels
|
|
// format is rgb24 (aka wxImage format)
|
|
// x/y is added to data and returned coords
|
|
// if data == NULL, bitmap will be reset to default (all-black)
|
|
virtual void SetData(const unsigned char* data, int stride, int x = 0, int y = 0);
|
|
// desel if out of displayed range
|
|
void SetSel(int x, int y, bool dsel_cview_update = true);
|
|
// -1, -1 = no sel
|
|
void GetSel(int& x, int& y)
|
|
{
|
|
x = selx < 0 ? -1 : ox + selx;
|
|
y = sely < 0 ? -1 : oy + sely;
|
|
}
|
|
ColorView* cview;
|
|
|
|
protected:
|
|
wxImage im;
|
|
wxBitmap* bm;
|
|
void Redraw(wxPaintEvent& ev);
|
|
virtual void SelPoint(wxMouseEvent& ev);
|
|
int ox, oy, selx, sely;
|
|
|
|
DECLARE_EVENT_TABLE()
|
|
DECLARE_DYNAMIC_CLASS(PixView)
|
|
};
|
|
#define pixview(v, n, w, h, cv) \
|
|
do { \
|
|
v = XRCCTRL(*this, n, PixView); \
|
|
if (!v) \
|
|
baddialog(); \
|
|
v->InitBMP(w, h, cv); \
|
|
} while (0)
|
|
|
|
// a graphics viewer panel; expected to be inside of a wxScrollWindow
|
|
class GfxPanel : public wxPanel {
|
|
public:
|
|
GfxPanel()
|
|
: wxPanel()
|
|
, bm(0)
|
|
, selx(-1)
|
|
, sely(-1)
|
|
{
|
|
}
|
|
int bmw, bmh;
|
|
wxBitmap* bm;
|
|
wxImage* im;
|
|
PixView* pv;
|
|
|
|
protected:
|
|
void DrawBitmap(wxPaintEvent& ev);
|
|
void Click(wxMouseEvent& ev);
|
|
void MouseMove(wxMouseEvent& ev);
|
|
void DoSel(wxMouseEvent& ev, bool force = false);
|
|
|
|
private:
|
|
int selx, sely;
|
|
|
|
DECLARE_DYNAMIC_CLASS(GfxPanel)
|
|
DECLARE_EVENT_TABLE()
|
|
};
|
|
|
|
BEGIN_DECLARE_EVENT_TYPES()
|
|
// event generated on mouse click
|
|
// generates wxMouseEvent with coords adjusted to original bitmap
|
|
// size regardless of scaling
|
|
DECLARE_LOCAL_EVENT_TYPE(EVT_COMMAND_GFX_CLICK, 0)
|
|
END_DECLARE_EVENT_TYPES()
|
|
#define EVT_GFX_CLICK(id, fun) \
|
|
DECLARE_EVENT_TABLE_ENTRY(EVT_COMMAND_GFX_CLICK, \
|
|
id, \
|
|
wxID_ANY, \
|
|
wxMouseEventHandler(fun), \
|
|
NULL) \
|
|
,
|
|
|
|
// like Viewer, common stuff to all gfx viewers
|
|
// this is what actually manages the GfxPanel
|
|
class GfxViewer : public Viewer {
|
|
public:
|
|
GfxViewer(const wxString& dname, int maxw, int maxh);
|
|
void ChangeBMP();
|
|
void BMPSize(int w, int h);
|
|
|
|
protected:
|
|
void StretchTog(wxCommandEvent& ev);
|
|
void RefreshEv(wxCommandEvent& ev);
|
|
void SaveBMP(wxCommandEvent& ev);
|
|
wxImage image;
|
|
GfxPanel* gv;
|
|
|
|
private:
|
|
static wxString bmp_save_dir;
|
|
wxScrolledWindow* gvs;
|
|
wxCheckBox* str;
|
|
|
|
DECLARE_EVENT_TABLE()
|
|
};
|
|
|
|
// if the jumbopixel view is all there is, maybe send a GFX_CLICK..
|
|
class PixViewEvt : public PixView {
|
|
// generates a GFX_CLICK if a point is selected
|
|
void SetData(const unsigned char* data, int stride, int x = 0, int y = 0);
|
|
|
|
protected:
|
|
// always generates a GFX_CLICK
|
|
void SelPoint(wxMouseEvent& ev);
|
|
void click();
|
|
DECLARE_DYNAMIC_CLASS(PixViewEvt)
|
|
};
|
|
|
|
// a display-only checkbox which does not look like it's disabled
|
|
class DispCheckBox : public wxCheckBox {
|
|
public:
|
|
bool AcceptsFocus() const
|
|
{
|
|
return false;
|
|
}
|
|
void MouseEvent(wxMouseEvent& ev)
|
|
{
|
|
(void)ev; // unused param
|
|
}
|
|
DECLARE_EVENT_TABLE()
|
|
DECLARE_DYNAMIC_CLASS(DispCheckBox)
|
|
};
|
|
|
|
// standard widgets in graphical viewers
|
|
}
|
|
#endif /* WX_VIEWSUPT_H */
|