307 lines
8.8 KiB
C++
307 lines
8.8 KiB
C++
/*
|
|
* This plugin demonstrates how to use non modal forms.
|
|
* It creates 2 windows on the screen:
|
|
* - a window with 4 buttons: dock, undock, show, hide (CONTROL FORM)
|
|
* - a window with a text edit control and a list control (EDITOR FORM)
|
|
* The buttons of the first window can be used to manage the second window.
|
|
* We will call the first window 'CONTROL FORM' and the second window 'EDITOR
|
|
* FORM', just to be able to reference them easily.
|
|
*/
|
|
|
|
#include <ida.hpp>
|
|
#include <idp.hpp>
|
|
#include <loader.hpp>
|
|
#include <kernwin.hpp>
|
|
|
|
//---------------------------------------------------------------------------
|
|
// chooser (list view) items
|
|
static const char *const names[] =
|
|
{
|
|
"Item one",
|
|
"Item two",
|
|
"Item three"
|
|
};
|
|
|
|
//--------------------------------------------------------------------------
|
|
struct plugin_ctx_t : public plugmod_t
|
|
{
|
|
// the editor form
|
|
TWidget *editor_widget = nullptr;
|
|
|
|
// contents of the text field for each item
|
|
qstring txts[qnumber(names)] =
|
|
{
|
|
"Text one:\n This is text for item one",
|
|
"Text two:\n And this is text for item two",
|
|
"Text three:\n And finally text for the last item"
|
|
};
|
|
|
|
// Current index for chooser list view
|
|
size_t curidx = 0;
|
|
// Form actions for control dialog
|
|
form_actions_t *control_fa = nullptr;
|
|
// Defines where to place new/existing editor window
|
|
bool dock = false;
|
|
|
|
virtual bool idaapi run(size_t) override;
|
|
|
|
int editor_modcb(int fid, form_actions_t &fa);
|
|
void open_editor_form(int options = 0);
|
|
void close_editor_form();
|
|
int control_modcb(int fid, form_actions_t &fa);
|
|
void update_buttons(form_actions_t &fa);
|
|
};
|
|
|
|
//---------------------------------------------------------------------------
|
|
struct of_chooser_t : public chooser_t
|
|
{
|
|
public:
|
|
// this object must be allocated using `new`
|
|
// as it used in the non-modal form
|
|
of_chooser_t() : chooser_t()
|
|
{
|
|
columns = 1;
|
|
static const int widths_[] = { 12 };
|
|
static const char *const header_[] = { "Name" };
|
|
widths = widths_;
|
|
header = header_;
|
|
}
|
|
|
|
virtual size_t idaapi get_count() const override { return qnumber(names); }
|
|
virtual void idaapi get_row(
|
|
qstrvec_t *cols,
|
|
int *,
|
|
chooser_item_attrs_t *,
|
|
size_t n) const override
|
|
{
|
|
(*cols)[0] = names[n];
|
|
}
|
|
};
|
|
|
|
// Form actions for editor window
|
|
enum editor_form_actions
|
|
{
|
|
TEXT_CHANGED = 1,
|
|
ITEM_SELECTED = 2,
|
|
};
|
|
|
|
// Form actions for control window
|
|
enum control_form_actions
|
|
{
|
|
BTN_DOCK = 10,
|
|
BTN_UNDOCK = 11,
|
|
BTN_OPEN = 12,
|
|
BTN_CLOSE = 13,
|
|
};
|
|
|
|
//--------------------------------------------------------------------------
|
|
inline void enable_button(form_actions_t &fa, int fid, bool enabled)
|
|
{
|
|
fa.enable_field(fid, enabled);
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// Update control window buttons state
|
|
void plugin_ctx_t::update_buttons(form_actions_t &fa)
|
|
{
|
|
bool visible = editor_widget != NULL;
|
|
enable_button(fa, 10, !dock && visible);
|
|
enable_button(fa, 11, dock && visible);
|
|
enable_button(fa, 12, !visible);
|
|
enable_button(fa, 13, visible);
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// this callback is called when the user clicks on a button
|
|
static int idaapi btn_cb(int, form_actions_t &)
|
|
{
|
|
msg("button has been pressed -> \n");
|
|
return 0;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// this callback is called when something happens in our non-modal editor form
|
|
static int idaapi editor_modcb_(int fid, form_actions_t &fa)
|
|
{
|
|
plugin_ctx_t &ctx = *(plugin_ctx_t *)fa.get_ud();
|
|
return ctx.editor_modcb(fid, fa);
|
|
}
|
|
int plugin_ctx_t::editor_modcb(int fid, form_actions_t &fa)
|
|
{
|
|
switch ( fid )
|
|
{
|
|
case CB_INIT: // Initialization
|
|
msg("init editor form\n");
|
|
break;
|
|
case CB_CLOSE: // Closing the form
|
|
msg("closing editor form\n");
|
|
// mark the form as closed
|
|
editor_widget = nullptr;
|
|
// If control form exists then update buttons
|
|
if ( control_fa != nullptr )
|
|
update_buttons(*control_fa);
|
|
break;
|
|
case TEXT_CHANGED: // Text changed
|
|
{
|
|
textctrl_info_t ti;
|
|
fa.get_text_value(1, &ti);
|
|
txts[curidx] = ti.text;
|
|
}
|
|
msg("text has been changed\n");
|
|
break;
|
|
case ITEM_SELECTED: // list item selected
|
|
{
|
|
sizevec_t sel;
|
|
if ( fa.get_chooser_value(2, &sel) )
|
|
{
|
|
curidx = sel[0];
|
|
textctrl_info_t ti;
|
|
ti.cb = sizeof(textctrl_info_t);
|
|
ti.text = txts[curidx];
|
|
fa.set_text_value(1, &ti);
|
|
}
|
|
}
|
|
msg("selection has been changed\n");
|
|
break;
|
|
default:
|
|
msg("unknown id %d\n", fid);
|
|
break;
|
|
}
|
|
return 1;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
// create and open the editor form
|
|
void plugin_ctx_t::open_editor_form(int options)
|
|
{
|
|
static const char formdef[] =
|
|
"BUTTON NO NONE\n" // we do not want the standard buttons on the form
|
|
"BUTTON YES NONE\n"
|
|
"BUTTON CANCEL NONE\n"
|
|
"Editor form\n" // the form title. it is also used to refer to the form later
|
|
"\n"
|
|
"%/%*" // placeholder for the 'editor_modcb' callback
|
|
"\n"
|
|
"<List:E2:30:30:1::><|><Text:t1:30:40:::>\n" // text edit control and chooser control separated by splitter
|
|
"\n";
|
|
// structure for text edit control
|
|
textctrl_info_t ti;
|
|
ti.cb = sizeof(textctrl_info_t);
|
|
ti.text = txts[0];
|
|
// structure for chooser list view
|
|
of_chooser_t *ofch = new of_chooser_t();
|
|
// selection for chooser list view
|
|
sizevec_t selected;
|
|
selected.push_back(0); // first item by default
|
|
editor_widget = open_form(formdef,
|
|
options,
|
|
editor_modcb_, this,
|
|
ofch, &selected,
|
|
&ti);
|
|
} //lint !e429 custodial pointer 'ofch' likely not freed nor returned
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
void plugin_ctx_t::close_editor_form()
|
|
{
|
|
msg("closing editor widget\n");
|
|
close_widget(editor_widget, WCLS_CLOSE_LATER);
|
|
editor_widget = nullptr;
|
|
}
|
|
//--------------------------------------------------------------------------
|
|
inline void dock_form(bool _dock)
|
|
{
|
|
set_dock_pos("Editor form",
|
|
NULL,
|
|
_dock ? DP_INSIDE : DP_FLOATING);
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// this callback is called when something happens in our non-modal control form
|
|
static int idaapi control_modcb_(int fid, form_actions_t &fa)
|
|
{
|
|
plugin_ctx_t &ctx = *(plugin_ctx_t *)fa.get_ud();
|
|
return ctx.control_modcb(fid, fa);
|
|
}
|
|
int plugin_ctx_t::control_modcb(int fid, form_actions_t &fa)
|
|
{
|
|
switch ( fid )
|
|
{
|
|
case CB_INIT: // Initialization
|
|
msg("init control form\n");
|
|
dock = false;
|
|
control_fa = &fa; // remember the 'fa' for the future
|
|
update_buttons(fa);
|
|
break;
|
|
case CB_CLOSE: // Closing
|
|
msg("closing control form\n");
|
|
control_fa = NULL;
|
|
return 1;
|
|
case BTN_DOCK:
|
|
msg("dock editor form\n");
|
|
dock = true;
|
|
dock_form(dock);
|
|
break;
|
|
case BTN_UNDOCK:
|
|
msg("undock editor form\n");
|
|
dock = false;
|
|
dock_form(dock);
|
|
break;
|
|
case BTN_OPEN:
|
|
msg("open editor form\n");
|
|
open_editor_form(WOPN_DP_TAB|WOPN_RESTORE);
|
|
dock_form(dock);
|
|
break;
|
|
case BTN_CLOSE:
|
|
close_editor_form();
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
update_buttons(fa);
|
|
return 1;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// the main function of the plugin
|
|
bool idaapi plugin_ctx_t::run(size_t)
|
|
{
|
|
// first open the editor form
|
|
open_editor_form(WOPN_RESTORE);
|
|
|
|
static const char control_form[] =
|
|
"BUTTON NO NONE\n" // do not display standard buttons at the bottom
|
|
"BUTTON YES NONE\n"
|
|
"BUTTON CANCEL NONE\n"
|
|
"Control form\n" // the title. it is used to refer to the form later
|
|
"%/%*" // placeholder for control_modcb
|
|
"<Dock:B10:30:::><Undock:B11:30:::><Show:B12:30:::><Hide:B13:30:::>\n"; // Create control buttons
|
|
|
|
open_form(control_form,
|
|
WOPN_RESTORE,
|
|
control_modcb_, this,
|
|
btn_cb, btn_cb, btn_cb, btn_cb);
|
|
set_dock_pos("Control form", NULL, DP_FLOATING, 0, 0, 300, 100);
|
|
return true;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// initialize the plugin
|
|
static plugmod_t *idaapi init()
|
|
{
|
|
return new plugin_ctx_t;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
plugin_t PLUGIN =
|
|
{
|
|
IDP_INTERFACE_VERSION,
|
|
PLUGIN_MULTI, // The plugin can work with multiple idbs in parallel
|
|
init,
|
|
nullptr,
|
|
nullptr,
|
|
nullptr,
|
|
nullptr,
|
|
"Open non-modal form sample",// the preferred short name of the plugin
|
|
nullptr,
|
|
};
|