-
Notifications
You must be signed in to change notification settings - Fork 62
/
notebook_widgets.hpp
117 lines (96 loc) · 4.24 KB
/
notebook_widgets.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
namespace widgets {
/* ** Widget API **
* in: nb: Pointer to notebook to add widget to.
* in: start, end: Iterators bracketing the textual representation of the widget.
* The first character will be a special code representing the anchor at which the
* widget lands in the buffer. The actual textual representation begins at start+1.
* return: Pointer to an unowned Gtk::Widget, or NULL. The caller will call Gtk::manage on it.
*
* You may not modify the buffer in the widget API. However, you can apply and remove tags, such
* as baseline modifiers, and signal callbacks you hook up to your widgets may modify the buffer contents.
* */
Gtk::Widget *RenderCheckbox(CNotebook *nb, Gtk::TextBuffer::iterator start, Gtk::TextBuffer::iterator end)
{
Glib::RefPtr<Gtk::TextMark> mstart = nb->sbuffer->create_mark(start,true);
Gtk::TextIter i=start;
++i;
if(i.get_char()=='[') ++i;
bool is_checked = (i.get_char()=='x'||i.get_char()=='X');
auto j = start; ++j;
// shift baseline for gtk checkbox widget
nb->sbuffer->apply_tag(nb->GetBaselineTag(2),start,j);
Gtk::CheckButton *b = new Gtk::CheckButton();
if(is_checked) b->set_active(true);
b->property_can_focus().set_value(false);
b->property_active().signal_changed().connect(sigc::slot<void>( [b,mstart,nb]() {
Gtk::TextIter i = nb->sbuffer->get_iter_at_mark(mstart);
++i; ++i;
if(b->get_active())
i=nb->sbuffer->insert(i,"x");
else
i=nb->sbuffer->insert(i," ");
Gtk::TextIter j=i; ++j;
nb->sbuffer->erase(i,j);
} ));
/* set appropriate cursor when checkbox hovered */
b->signal_enter().connect(sigc::slot<void>( [mstart,nb]() { nb->SetCursor(nb->pointer_cursor); } ));
b->signal_leave().connect(sigc::slot<void>( [mstart,nb]() { nb->update_cursor = true; } ));
/* destroy the mark when the widget is unmapped */
b->signal_unmap().connect(sigc::slot<void>( [mstart,nb]() {
/* need to defer the destruction due to mysterious interactions with signal chain */
auto s = Glib::IdleSource::create();
s->connect(sigc::slot<bool>( [mstart,nb]() {
nb->sbuffer->delete_mark(mstart);
return false;
}));
s->attach();
}));
return b;
}
std::string urldecode(std::string in)
{
std::size_t len = in.length(), p=0, nextp;
std::string out;
out.reserve(len); // reserve space to prevent costly reallocs on +=
char hexcode[3]={0}; // memory to hold extracted hex codes without allocations
while(p<len && (nextp = in.find("%",p))!=std::string::npos) {
out += std::string(in, p, nextp-p); // copy in everything up to the %
strncpy(hexcode, in.c_str()+nextp+1, 2); // get the hex code
int cc, nread=0;
if(sscanf(hexcode, "%02X%n", &cc, &nread) && nread>0 && (unsigned char)cc)
out += (unsigned char)cc; // seems like we got a hex code, append
p=nextp+nread+1; // skip the % and however many characters we successfully read as hex
}
out += std::string(in, p); // copy in the rest of the string
printf("'%s'\n",out.c_str()); fflush(stdout);
return out;
}
Gtk::Widget *RenderImage(CNotebook *nb, Gtk::TextBuffer::iterator start, Gtk::TextBuffer::iterator end)
{
/* the worst thing that could happen is that we go to the end and URL becomes empty */
auto urlstart = start;
nb->sbuffer->iter_forward_to_context_class_toggle(urlstart,"url");
if(urlstart < end) {
auto urlend = urlstart;
nb->sbuffer->iter_forward_to_context_class_toggle(urlend,"url");
// workaround for canonicalize_filename not being supported in glibmm<2.64
Glib::RefPtr<Gio::File> file = Glib::wrap(g_file_new_for_commandline_arg_and_cwd(urldecode(urlstart.get_text(urlend)).c_str(), nb->document_path.c_str()));
Gtk::Image *d = new Gtk::Image(file->get_path());
return d;
} else {
// condition fails if url was empty, vis. ()
Gtk::Image *d = new Gtk::Image();
d->set_from_icon_name("action-unavailable",Gtk::ICON_SIZE_BUTTON);
return d;
}
}
#if defined (HAVE_LASEM) || defined (HAVE_CLATEXMATH)
Gtk::Widget *RenderLatex(CNotebook *nb, Gtk::TextBuffer::iterator start, Gtk::TextBuffer::iterator end)
{
CLatexWidget *d = new CLatexWidget(nb->get_window(Gtk::TEXT_WINDOW_TEXT),nb->sbuffer->get_text(start,end,true),nb->get_style_context()->get_color());
auto j = start; ++j;
nb->sbuffer->apply_tag(nb->GetBaselineTag(d->GetBaseline()),start,j);
return d;
}
#endif
}