|
diff --git a/tdbg.cpp b/tdbg.cpp
|
| ... |
| 22 |
const int BREAKPOINTS_WINDOW_HEIGHT = 10; |
22 |
const int BREAKPOINTS_WINDOW_HEIGHT = 10; |
| 23 |
const int SIDEBAR_WIDTH = 40; |
23 |
const int SIDEBAR_WIDTH = 40; |
| 24 |
|
24 |
|
|
|
25 |
// https://unicodeplus.com/U+2593 |
|
|
26 |
const uint32_t SCROLLBAR_THUMB = 0x2593; // Dark shade |
|
|
27 |
const uint32_t SCROLLBAR_LINE = 0x2502; // Vertical line |
|
|
28 |
|
| 25 |
struct LLDBGuard { |
29 |
struct LLDBGuard { |
| 26 |
LLDBGuard() { SBDebugger::Initialize(); } |
30 |
LLDBGuard() { SBDebugger::Initialize(); } |
| 27 |
~LLDBGuard() { SBDebugger::Terminate(); } |
31 |
~LLDBGuard() { SBDebugger::Terminate(); } |
| ... |
| 54 |
MODE_NORMAL, |
58 |
MODE_NORMAL, |
| 55 |
MODE_INPUT_BREAKPOINT, |
59 |
MODE_INPUT_BREAKPOINT, |
| 56 |
MODE_INPUT_VARIABLE |
60 |
MODE_INPUT_VARIABLE |
|
|
61 |
}; |
|
|
62 |
|
|
|
63 |
struct VarLine { |
|
|
64 |
std::string text; |
|
|
65 |
int indent; |
|
|
66 |
int prefix_start; |
|
|
67 |
int prefix_end; |
| 57 |
}; |
68 |
}; |
| 58 |
|
69 |
|
| 59 |
std::string get_timestamp() { |
70 |
std::string get_timestamp() { |
| ... |
| 145 |
return '?'; |
156 |
return '?'; |
| 146 |
} |
157 |
} |
| 147 |
|
158 |
|
| 148 |
void draw_variable_recursive(SBValue val, int indent, int x, int start_y, int ¤t_offset, int max_height, int width) { |
159 |
void collect_variables_recursive(SBValue val, int indent, std::vector<VarLine>& lines, int width) { |
| 149 |
if (current_offset >= max_height || indent > 3) return; |
160 |
if (indent > 3) return; |
| 150 |
|
161 |
|
| 151 |
std::string original_name = val.GetName() ? val.GetName() : ""; |
162 |
std::string original_name = val.GetName() ? val.GetName() : ""; |
| 152 |
char type_char = get_type_char(val.GetType()); |
163 |
char type_char = get_type_char(val.GetType()); |
| ... |
| 161 |
std::string content = original_name; |
172 |
std::string content = original_name; |
| 162 |
if (!value.empty()) content += " = " + value; |
173 |
if (!value.empty()) content += " = " + value; |
| 163 |
|
174 |
|
| 164 |
std::string line = indent_str + prefix + content; |
175 |
std::string line_text = indent_str + prefix + content; |
| 165 |
if ((int)line.length() > width) line = line.substr(0, width - 3) + "..."; |
176 |
if ((int)line_text.length() > width) line_text = line_text.substr(0, width - 3) + "..."; |
| 166 |
|
177 |
|
| 167 |
int prefix_start = indent * 2; |
178 |
VarLine vl; |
| 168 |
int prefix_end = prefix_start + 4; // length of "(x) " |
179 |
vl.text = line_text; |
| 169 |
|
180 |
vl.indent = indent; |
| 170 |
for (int i = 0; i < (int)line.length(); ++i) { |
181 |
vl.prefix_start = indent * 2; |
| 171 |
uint16_t fg = TB_DEFAULT; |
182 |
vl.prefix_end = vl.prefix_start + 4; // length of "(x) " |
| 172 |
if (i >= prefix_start && i < prefix_end) { |
183 |
lines.push_back(vl); |
| 173 |
fg = TB_BLACK | TB_BOLD; |
|
|
| 174 |
} |
|
|
| 175 |
tb_set_cell(x + i, start_y + current_offset, line[i], fg, TB_DEFAULT); |
|
|
| 176 |
} |
|
|
| 177 |
|
|
|
| 178 |
current_offset++; |
|
|
| 179 |
|
184 |
|
| 180 |
if (val.GetNumChildren() > 0) { |
185 |
if (val.GetNumChildren() > 0) { |
| 181 |
uint32_t n = val.GetNumChildren(); |
186 |
uint32_t n = val.GetNumChildren(); |
| 182 |
for (uint32_t i = 0; i < n; ++i) { |
187 |
for (uint32_t i = 0; i < n; ++i) { |
| 183 |
draw_variable_recursive(val.GetChildAtIndex(i), indent + 1, x, start_y, current_offset, max_height, width); |
188 |
collect_variables_recursive(val.GetChildAtIndex(i), indent + 1, lines, width); |
| 184 |
} |
189 |
} |
| 185 |
} |
190 |
} |
| 186 |
} |
191 |
} |
| ... |
| 210 |
} |
215 |
} |
| 211 |
} |
216 |
} |
| 212 |
|
217 |
|
| 213 |
void draw_variables_view(SBFrame &frame, int x, int y, int w, int h) { |
218 |
void draw_variables_view(SBFrame &frame, int x, int y, int w, int h, int scroll_offset) { |
| 214 |
draw_box(x, y, w, h, "Locals"); |
219 |
draw_box(x, y, w, h, "Locals"); |
| 215 |
|
220 |
|
| 216 |
// Content area |
221 |
// Content area |
| ... |
| 224 |
return; |
229 |
return; |
| 225 |
} |
230 |
} |
| 226 |
|
231 |
|
|
|
232 |
std::vector<VarLine> lines; |
| 227 |
SBValueList vars = frame.GetVariables(true, true, false, true); |
233 |
SBValueList vars = frame.GetVariables(true, true, false, true); |
| 228 |
int current_offset = 0; |
234 |
for (uint32_t i = 0; i < vars.GetSize(); ++i) { |
|
|
235 |
collect_variables_recursive(vars.GetValueAtIndex(i), 0, lines, cw); |
|
|
236 |
} |
|
|
237 |
|
|
|
238 |
int total_lines = (int)lines.size(); |
|
|
239 |
int display_count = std::min(total_lines, ch); |
| 229 |
|
240 |
|
| 230 |
for (uint32_t i = 0; i < vars.GetSize(); ++i) { |
241 |
for (int i = 0; i < display_count; ++i) { |
| 231 |
draw_variable_recursive(vars.GetValueAtIndex(i), 0, cx, cy, current_offset, ch, cw); |
242 |
int line_idx = scroll_offset + i; |
|
|
243 |
if (line_idx < 0 || line_idx >= total_lines) continue; |
|
|
244 |
|
|
|
245 |
const VarLine& vl = lines[line_idx]; |
|
|
246 |
for (int j = 0; j < (int)vl.text.length() && j < cw; ++j) { |
|
|
247 |
uint16_t fg = TB_DEFAULT; |
|
|
248 |
if (j >= vl.prefix_start && j < vl.prefix_end) { |
|
|
249 |
fg = TB_BLACK | TB_BOLD; |
|
|
250 |
} |
|
|
251 |
tb_set_cell(cx + j, cy + i, vl.text[j], fg, TB_DEFAULT); |
|
|
252 |
} |
|
|
253 |
} |
|
|
254 |
|
|
|
255 |
// Draw scrollbar |
|
|
256 |
if (total_lines > ch) { |
|
|
257 |
int thumb_height = std::max(1, (ch * ch) / total_lines); |
|
|
258 |
int max_scroll = total_lines - ch; |
|
|
259 |
double scroll_percent = (double)scroll_offset / (double)max_scroll; |
|
|
260 |
int thumb_pos = (ch - thumb_height) * scroll_percent; |
|
|
261 |
|
|
|
262 |
for (int i = 0; i < ch; ++i) { |
|
|
263 |
uint32_t cell_char = SCROLLBAR_LINE; |
|
|
264 |
uint16_t fg = TB_DEFAULT; |
|
|
265 |
if (i >= thumb_pos && i < thumb_pos + thumb_height) { |
|
|
266 |
cell_char = SCROLLBAR_THUMB; |
|
|
267 |
fg = TB_WHITE; |
|
|
268 |
} |
|
|
269 |
tb_set_cell(x + w - 1, cy + i, cell_char, fg, TB_DEFAULT); |
|
|
270 |
} |
| 232 |
} |
271 |
} |
| 233 |
} |
272 |
} |
| 234 |
|
273 |
|
| ... |
| 268 |
return name; |
307 |
return name; |
| 269 |
} |
308 |
} |
| 270 |
|
309 |
|
| 271 |
void draw_source_view(SBFrame &frame, int x, int y, int w, int h, SourceCache& cache) { |
310 |
void draw_source_view(SBFrame &frame, int x, int y, int w, int h, SourceCache& cache, int scroll_offset) { |
| 272 |
draw_box(x, y, w, h, "Source"); |
311 |
draw_box(x, y, w, h, "Source"); |
| 273 |
|
312 |
|
| 274 |
int cx = x + 1; |
313 |
int cx = x + 1; |
| ... |
| 336 |
return; |
375 |
return; |
| 337 |
} |
376 |
} |
| 338 |
|
377 |
|
|
|
378 |
int total_lines = (int)lines.size(); |
| 339 |
int current_line = line_entry.GetLine(); |
379 |
int current_line = line_entry.GetLine(); |
| 340 |
int half_height = ch / 2; |
|
|
| 341 |
int start_line = std::max(1, current_line - half_height); |
|
|
| 342 |
int end_line = std::min((int)lines.size(), start_line + ch - 1); |
|
|
| 343 |
if (end_line - start_line + 1 < ch) { |
|
|
| 344 |
start_line = std::max(1, end_line - ch + 1); |
|
|
| 345 |
} |
|
|
| 346 |
|
|
|
| 347 |
for (int i = 0; i < ch; ++i) { |
380 |
for (int i = 0; i < ch; ++i) { |
| 348 |
int line_idx = start_line + i; |
381 |
int line_idx = scroll_offset + i + 1; |
| 349 |
if (line_idx > end_line) break; |
382 |
if (line_idx > total_lines) break; |
| 350 |
|
383 |
|
| 351 |
std::string src = lines[line_idx - 1]; |
384 |
std::string src = lines[line_idx - 1]; |
| 352 |
// Handle basic tab expansion (simple version) |
385 |
// Handle basic tab expansion (simple version) |
| ... |
| 380 |
} |
413 |
} |
| 381 |
} |
414 |
} |
| 382 |
} |
415 |
} |
|
|
416 |
|
|
|
417 |
// Draw scrollbar |
|
|
418 |
if (total_lines > ch) { |
|
|
419 |
int thumb_height = std::max(1, (ch * ch) / total_lines); |
|
|
420 |
int max_scroll = total_lines - ch; |
|
|
421 |
double scroll_percent = (double)scroll_offset / (double)max_scroll; |
|
|
422 |
int thumb_pos = (ch - thumb_height) * scroll_percent; |
|
|
423 |
|
|
|
424 |
for (int i = 0; i < ch; ++i) { |
|
|
425 |
uint32_t cell_char = SCROLLBAR_LINE; |
|
|
426 |
uint16_t fg = TB_DEFAULT; |
|
|
427 |
if (i >= thumb_pos && i < thumb_pos + thumb_height) { |
|
|
428 |
cell_char = SCROLLBAR_THUMB; |
|
|
429 |
fg = TB_WHITE; |
|
|
430 |
} |
|
|
431 |
tb_set_cell(x + w - 1, cy + i, cell_char, fg, TB_DEFAULT); |
|
|
432 |
} |
|
|
433 |
} |
| 383 |
} |
434 |
} |
| 384 |
|
435 |
|
| 385 |
void draw_breakpoints_view(SBTarget& target, int x, int y, int w, int h) { |
436 |
void draw_breakpoints_view(SBTarget& target, int x, int y, int w, int h) { |
| ... |
| 421 |
return target.BreakpointCreateByName(input.c_str()); |
472 |
return target.BreakpointCreateByName(input.c_str()); |
| 422 |
} |
473 |
} |
| 423 |
|
474 |
|
| 424 |
void draw_log_view(int x, int y, int w, int h, const std::vector<std::string>& log_buffer, AppMode mode, const std::string& input_buffer) { |
475 |
void draw_log_view(int x, int y, int w, int h, const std::vector<std::string>& log_buffer, AppMode mode, const std::string& input_buffer, int scroll_offset) { |
| 425 |
bool input_mode = (mode == MODE_INPUT_BREAKPOINT || mode == MODE_INPUT_VARIABLE); |
476 |
bool input_mode = (mode == MODE_INPUT_BREAKPOINT || mode == MODE_INPUT_VARIABLE); |
| 426 |
std::string title = input_mode ? "Input (Esc to Cancel)" : "Command & Log"; |
477 |
std::string title = input_mode ? "Input (Esc to Cancel)" : "Logs"; |
|
|
478 |
if (!input_mode && scroll_offset > 0) { |
|
|
479 |
title += " (Scrolled up: " + std::to_string(scroll_offset) + ")"; |
|
|
480 |
} |
| 427 |
draw_box(x, y, w, h, title); |
481 |
draw_box(x, y, w, h, title); |
| 428 |
|
482 |
|
| 429 |
int cx = x + 1; |
483 |
int cx = x + 1; |
| ... |
| 441 |
draw_text(cx, cy, TB_WHITE | TB_BOLD, TB_DEFAULT, prompt); |
495 |
draw_text(cx, cy, TB_WHITE | TB_BOLD, TB_DEFAULT, prompt); |
| 442 |
tb_set_cell(cx + prompt.length(), cy, '_', TB_WHITE | TB_BOLD | TB_REVERSE, TB_DEFAULT); |
496 |
tb_set_cell(cx + prompt.length(), cy, '_', TB_WHITE | TB_BOLD | TB_REVERSE, TB_DEFAULT); |
| 443 |
} else { |
497 |
} else { |
| 444 |
int log_lines_count = std::min((int)log_buffer.size(), ch); |
498 |
int total_logs = log_buffer.size(); |
| 445 |
for (int i = 0; i < log_lines_count; ++i) { |
499 |
int display_count = std::min(total_logs, ch); |
| 446 |
const std::string& msg = log_buffer[log_buffer.size() - log_lines_count + i]; |
500 |
|
|
|
501 |
for (int i = 0; i < display_count; ++i) { |
|
|
502 |
int log_idx = total_logs - display_count - scroll_offset + i; |
|
|
503 |
if (log_idx < 0 || log_idx >= total_logs) continue; |
|
|
504 |
|
|
|
505 |
const std::string& msg = log_buffer[log_idx]; |
| 447 |
std::string disp = msg; |
506 |
std::string disp = msg; |
| 448 |
if ((int)disp.length() > cw) disp = disp.substr(0, cw); |
507 |
if ((int)disp.length() > cw) disp = disp.substr(0, cw); |
| 449 |
draw_text(cx, cy + i, TB_DEFAULT, TB_DEFAULT, disp); |
508 |
draw_text(cx, cy + i, TB_DEFAULT, TB_DEFAULT, disp); |
|
|
509 |
} |
|
|
510 |
|
|
|
511 |
// Draw scrollbar |
|
|
512 |
if (total_logs > ch) { |
|
|
513 |
int thumb_height = std::max(1, (ch * ch) / total_logs); |
|
|
514 |
int max_scroll = total_logs - ch; |
|
|
515 |
double scroll_percent = (double)scroll_offset / (double)max_scroll; |
|
|
516 |
int thumb_pos = (ch - thumb_height) * (1.0 - scroll_percent); |
|
|
517 |
|
|
|
518 |
for (int i = 0; i < ch; ++i) { |
|
|
519 |
uint32_t cell_char = SCROLLBAR_LINE; |
|
|
520 |
uint16_t fg = TB_DEFAULT; |
|
|
521 |
if (i >= thumb_pos && i < thumb_pos + thumb_height) { |
|
|
522 |
cell_char = SCROLLBAR_THUMB; |
|
|
523 |
fg = TB_WHITE; |
|
|
524 |
} |
|
|
525 |
tb_set_cell(x + w - 1, cy + i, cell_char, fg, TB_DEFAULT); |
|
|
526 |
} |
| 450 |
} |
527 |
} |
| 451 |
} |
528 |
} |
| 452 |
} |
529 |
} |
| ... |
| 507 |
AppMode mode = MODE_NORMAL; |
584 |
AppMode mode = MODE_NORMAL; |
| 508 |
std::string input_buffer; |
585 |
std::string input_buffer; |
| 509 |
std::vector<std::string> log_buffer; |
586 |
std::vector<std::string> log_buffer; |
|
|
587 |
int log_scroll_offset = 0; |
|
|
588 |
int locals_scroll_offset = 0; |
|
|
589 |
int source_scroll_offset = 0; |
|
|
590 |
uint64_t last_pc = 0; |
| 510 |
SourceCache source_cache; |
591 |
SourceCache source_cache; |
| 511 |
log_buffer.push_back("Debugger started. Press 'b' to add breakpoint, 'r' to run."); |
592 |
log_buffer.push_back("Debugger started. Press 'b' to add breakpoint, 'r' to run."); |
|
|
593 |
|
|
|
594 |
tb_set_input_mode(TB_INPUT_ESC | TB_INPUT_MOUSE); |
| 512 |
|
595 |
|
| 513 |
while (running) { |
596 |
while (running) { |
| 514 |
tb_clear(); |
597 |
tb_clear(); |
| ... |
| 524 |
thread = process.GetSelectedThread(); |
607 |
thread = process.GetSelectedThread(); |
| 525 |
if (thread.IsValid()) { |
608 |
if (thread.IsValid()) { |
| 526 |
frame = thread.GetSelectedFrame(); |
609 |
frame = thread.GetSelectedFrame(); |
|
|
610 |
if (frame.IsValid()) { |
|
|
611 |
uint64_t current_pc = frame.GetPC(); |
|
|
612 |
if (current_pc != last_pc) { |
|
|
613 |
last_pc = current_pc; |
|
|
614 |
SBLineEntry le = frame.GetLineEntry(); |
|
|
615 |
if (le.IsValid()) { |
|
|
616 |
std::string fullpath; |
|
|
617 |
if (le.GetFileSpec().GetDirectory()) { |
|
|
618 |
fullpath = std::string(le.GetFileSpec().GetDirectory()) + "/" + le.GetFileSpec().GetFilename(); |
|
|
619 |
} else { |
|
|
620 |
fullpath = le.GetFileSpec().GetFilename(); |
|
|
621 |
} |
|
|
622 |
const std::vector<std::string>& lines = source_cache.get_lines(fullpath); |
|
|
623 |
int total_lines = (int)lines.size(); |
|
|
624 |
int ch = main_window_height - 2; |
|
|
625 |
source_scroll_offset = std::max(0, (int)le.GetLine() - ch / 2 - 1); |
|
|
626 |
if (source_scroll_offset + ch > total_lines) { |
|
|
627 |
source_scroll_offset = std::max(0, total_lines - ch); |
|
|
628 |
} |
|
|
629 |
} |
|
|
630 |
} |
|
|
631 |
} |
| 527 |
} |
632 |
} |
| 528 |
} |
633 |
} |
| 529 |
|
634 |
|
| 530 |
draw_source_view(frame, 0, 0, split_x, main_window_height, source_cache); |
635 |
draw_source_view(frame, 0, 0, split_x, main_window_height, source_cache, source_scroll_offset); |
| 531 |
draw_variables_view(frame, split_x, 0, SIDEBAR_WIDTH, locals_window_height); |
636 |
draw_variables_view(frame, split_x, 0, SIDEBAR_WIDTH, locals_window_height, locals_scroll_offset); |
| 532 |
draw_breakpoints_view(target, split_x, locals_window_height, SIDEBAR_WIDTH, BREAKPOINTS_WINDOW_HEIGHT); |
637 |
draw_breakpoints_view(target, split_x, locals_window_height, SIDEBAR_WIDTH, BREAKPOINTS_WINDOW_HEIGHT); |
| 533 |
draw_log_view(0, main_window_height, width, LOG_WINDOW_HEIGHT, log_buffer, mode, input_buffer); |
638 |
draw_log_view(0, main_window_height, width, LOG_WINDOW_HEIGHT, log_buffer, mode, input_buffer, log_scroll_offset); |
| 534 |
draw_status_bar(process, mode, width, height); |
639 |
draw_status_bar(process, mode, width, height); |
| 535 |
|
640 |
|
| 536 |
tb_present(); |
641 |
tb_present(); |
| ... |
| 611 |
if (!input_buffer.empty()) input_buffer.pop_back(); |
716 |
if (!input_buffer.empty()) input_buffer.pop_back(); |
| 612 |
} else if (ev.ch != 0) { |
717 |
} else if (ev.ch != 0) { |
| 613 |
input_buffer += (char)ev.ch; |
718 |
input_buffer += (char)ev.ch; |
|
|
719 |
} |
|
|
720 |
} |
|
|
721 |
} else if (ev.type == TB_EVENT_MOUSE) { |
|
|
722 |
int main_window_height = tb_height() - LOG_WINDOW_HEIGHT - STATUS_WINDOW_HEIGHT; |
|
|
723 |
int log_start_y = main_window_height; |
|
|
724 |
int log_end_y = tb_height() - STATUS_WINDOW_HEIGHT; |
|
|
725 |
|
|
|
726 |
if (ev.y >= log_start_y && ev.y < log_end_y) { |
|
|
727 |
if (ev.key == TB_KEY_MOUSE_WHEEL_UP) { |
|
|
728 |
int max_scroll = std::max(0, (int)log_buffer.size() - (LOG_WINDOW_HEIGHT - 2)); |
|
|
729 |
if (log_scroll_offset < max_scroll) { |
|
|
730 |
log_scroll_offset++; |
|
|
731 |
} |
|
|
732 |
} else if (ev.key == TB_KEY_MOUSE_WHEEL_DOWN) { |
|
|
733 |
if (log_scroll_offset > 0) { |
|
|
734 |
log_scroll_offset--; |
|
|
735 |
} |
|
|
736 |
} |
|
|
737 |
} |
|
|
738 |
|
|
|
739 |
// Source window scrolling |
|
|
740 |
if (ev.x < split_x && ev.y < main_window_height) { |
|
|
741 |
SBLineEntry le = frame.GetLineEntry(); |
|
|
742 |
if (le.IsValid()) { |
|
|
743 |
std::string fullpath; |
|
|
744 |
if (le.GetFileSpec().GetDirectory()) { |
|
|
745 |
fullpath = std::string(le.GetFileSpec().GetDirectory()) + "/" + le.GetFileSpec().GetFilename(); |
|
|
746 |
} else { |
|
|
747 |
fullpath = le.GetFileSpec().GetFilename(); |
|
|
748 |
} |
|
|
749 |
const std::vector<std::string>& lines = source_cache.get_lines(fullpath); |
|
|
750 |
int total_lines = (int)lines.size(); |
|
|
751 |
int ch = main_window_height - 2; |
|
|
752 |
int max_scroll = std::max(0, total_lines - ch); |
|
|
753 |
|
|
|
754 |
if (ev.key == TB_KEY_MOUSE_WHEEL_UP) { |
|
|
755 |
if (source_scroll_offset > 0) { |
|
|
756 |
source_scroll_offset--; |
|
|
757 |
} |
|
|
758 |
} else if (ev.key == TB_KEY_MOUSE_WHEEL_DOWN) { |
|
|
759 |
if (source_scroll_offset < max_scroll) { |
|
|
760 |
source_scroll_offset++; |
|
|
761 |
} |
|
|
762 |
} |
|
|
763 |
} |
|
|
764 |
} |
|
|
765 |
|
|
|
766 |
// Locals window scrolling |
|
|
767 |
int split_x = tb_width() - SIDEBAR_WIDTH; |
|
|
768 |
int locals_window_height = main_window_height - BREAKPOINTS_WINDOW_HEIGHT; |
|
|
769 |
if (ev.x >= split_x && ev.y < locals_window_height) { |
|
|
770 |
std::vector<VarLine> lines; |
|
|
771 |
if (frame.IsValid()) { |
|
|
772 |
SBValueList vars = frame.GetVariables(true, true, false, true); |
|
|
773 |
for (uint32_t i = 0; i < vars.GetSize(); ++i) { |
|
|
774 |
collect_variables_recursive(vars.GetValueAtIndex(i), 0, lines, SIDEBAR_WIDTH - 2); |
|
|
775 |
} |
|
|
776 |
} |
|
|
777 |
int max_scroll = std::max(0, (int)lines.size() - (locals_window_height - 2)); |
|
|
778 |
|
|
|
779 |
if (ev.key == TB_KEY_MOUSE_WHEEL_UP) { |
|
|
780 |
if (locals_scroll_offset > 0) { |
|
|
781 |
locals_scroll_offset--; |
|
|
782 |
} |
|
|
783 |
} else if (ev.key == TB_KEY_MOUSE_WHEEL_DOWN) { |
|
|
784 |
if (locals_scroll_offset < max_scroll) { |
|
|
785 |
locals_scroll_offset++; |
|
|
786 |
} |
| 614 |
} |
787 |
} |
| 615 |
} |
788 |
} |
| 616 |
} |
789 |
} |
| ... |