grub2: bring back build of aros-side grub2 tools
[AROS.git] / rom / devs / console / charmapconclass.c
bloba5ab0791709058d961af432295fd6cc0d2dbbc64
1 /*
2 Copyright © 1995-2014, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: Code for CONU_CHARMAP console units.
6 Lang: english
7 */
9 #include <string.h>
11 #include <exec/ports.h>
12 #include <proto/graphics.h>
13 #include <proto/intuition.h>
14 #include <proto/alib.h>
15 #include <intuition/intuition.h>
17 #include <intuition/imageclass.h>
18 #include <intuition/gadgetclass.h>
19 #include <intuition/sghooks.h>
20 #include <libraries/gadtools.h>
22 #include <graphics/rastport.h>
23 #include <aros/asmcall.h>
25 #include <stdlib.h>
27 #define SDEBUG 0
28 //#define DEBUG 1
29 #define DEBUG 0
30 #include <aros/debug.h>
32 #include "console_gcc.h"
33 #include "consoleif.h"
35 #include "charmap.h"
37 #define PROP_FLAGS \
38 AUTOKNOB | FREEVERT | PROPNEWLOOK | PROPBORDERLESS
40 #define CODE_COPY 'C'
41 #define CODE_PASTE 'V'
43 struct MyEditHookMsg
45 struct Message msg;
46 struct SGWork *sgw;
47 WORD code;
50 static const STRPTR CONCLIP_PORTNAME = "ConClip.rendezvous";
51 struct Scroll
53 struct Gadget scroller; /* proportionnal gadget */
54 struct Gadget down; /* down gadget */
55 struct Gadget up; /* up gadget */
56 struct PropInfo pinfo; /* PropInfo for scroller */
57 struct Image simage; /* image for scroller */
58 struct Image *upimage; /* Boopsi image for up arrow */
59 struct Image *downimage; /* ditto for down arrow */
62 // FIXME: Abstract out the non-GUI aspects
63 struct charmapcondata
65 /* Start of the scrollback buffer */
66 struct charmap_line *top_of_scrollback;
67 /* The line currently displayed at the top of the screen */
68 struct charmap_line *top_of_window;
69 /* Saved position for the top of the screen at the end of
70 the buffer; where the buffer is reset to if there is
71 output while scrolling */
72 struct charmap_line *saved_top_of_window;
73 ULONG saved_scrollback_pos;
75 ULONG scrollback_size; /* Total size of the scrollback buffer */
76 ULONG scrollback_pos; /* Position of the top of the window */
78 ULONG scrollback_max; /* Maximum number of lines in scrollback
79 buffer on top of CHAR_YMAX(o) */
81 BOOL unrendered; /* Unrendered cursor while scrolled back? */
83 /* FIXME: Belongs in snipmap class */
84 /* Current selection */
85 LONG select_x_min;
86 LONG select_y_min;
87 struct charmap_line *select_line_min;
88 LONG select_x_max;
89 LONG select_y_max;
90 struct charmap_line *select_line_max;
91 BOOL active_selection; /* If true, mouse move will affect the selection */
92 BOOL ignore_drag;
95 UBYTE boopsigad; /* Type of right prop gadget of window */
96 struct Scroll *prop;
98 /* Active gadget */
99 APTR activeGad;
101 /* Libraries */
102 struct Library *ccd_GfxBase;
106 /* Template used to quickly fill constant fields */
107 CONST struct Scroll ScrollBar = {
109 /* PropGadget */
110 NULL, 0, 0, 0, 0,
111 GFLG_RELRIGHT | GFLG_RELHEIGHT,
112 GACT_RIGHTBORDER | GACT_FOLLOWMOUSE | GACT_IMMEDIATE |
113 GACT_RELVERIFY,
114 GTYP_PROPGADGET,
115 NULL, NULL, NULL, 0, NULL,
116 0, NULL
119 /* Up-gadget */
120 NULL, 0, 0, 0, 0,
121 GFLG_RELRIGHT | GFLG_RELBOTTOM | GFLG_GADGHIMAGE |
122 GFLG_GADGIMAGE,
123 GACT_RIGHTBORDER | GACT_RELVERIFY | GACT_IMMEDIATE,
124 GTYP_BOOLGADGET,
125 NULL, NULL, NULL, 0, NULL,
126 1, NULL
129 /* Down-Gadget */
130 NULL, 0, 0, 0, 0,
131 GFLG_RELRIGHT | GFLG_RELBOTTOM | GFLG_GADGHIMAGE |
132 GFLG_GADGIMAGE,
133 GACT_RIGHTBORDER | GACT_RELVERIFY | GACT_IMMEDIATE,
134 GTYP_BOOLGADGET,
135 NULL, NULL, NULL, 0, NULL,
136 2, NULL
139 /* PropInfo */
140 PROP_FLAGS,
141 MAXPOT, MAXPOT,
142 MAXBODY, MAXBODY
144 /* Other values may be NULL */
148 #ifdef ConsoleDevice
149 #undef ConsoleDevice
150 #endif
152 #ifdef GfxBase
153 #undef GfxBase
154 #endif
155 //#define GfxBase (((struct charmapcondata *)INST_DATA(cl, o))->ccd_GfxBase)
157 static VOID charmapcon_refresh(Class *cl, Object *o, LONG off);
159 /*** Allocate and attach a prop gadget to the window ***/
160 static VOID charmapcon_add_prop(Class *cl, Object *o)
162 struct charmapcondata *data = INST_DATA(cl, o);
163 struct ConsoleBase *ConsoleDevice = (struct ConsoleBase *)cl->cl_UserData;
164 struct Scroll *pg;
165 struct Image *dummy;
166 struct Window *win = CU(o)->cu_Window;
168 UWORD height, size_width, size_height;
170 /* If the window is a backdrop'ed one, use a simplified BOOPSI propgadget
171 * because the next propgadget aspect depends on window activated state */
172 if (win->Flags & WFLG_BACKDROP)
174 /* Yes this is actually a (struct Gadget *)... */
175 if ((data->prop = pg =
176 (struct Scroll *)NewObject(NULL, "propgclass", GA_Top, 0,
177 GA_Left, win->Width - 10, GA_Width, 10, GA_Height,
178 win->Height, GA_RelVerify, TRUE, GA_FollowMouse, TRUE,
179 GA_Immediate, TRUE, PGA_VertPot, MAXPOT, PGA_VertBody,
180 MAXBODY, PGA_Freedom, FREEVERT, PGA_NewLook, TRUE,
181 TAG_END)))
183 /* And finally, add it to the window */
184 AddGList(win, (struct Gadget *)pg, 0, 1, NULL);
185 RefreshGList((struct Gadget *)pg, win, NULL, 1);
188 data->boopsigad = TRUE;
189 return;
191 data->boopsigad = FALSE;
193 /* Get memory */
194 if ((data->prop = pg = (void *)AllocMem(sizeof(*pg), MEMF_PUBLIC)))
196 /* Copy default flags/modes/etc. */
197 CopyMem(&ScrollBar, pg, sizeof(*pg));
198 pg->pinfo.Flags = PROP_FLAGS;
199 struct DrawInfo *di;
201 di = (void *)GetScreenDrawInfo(win->WScreen);
203 /* We need to get size-gadget height, to adjust properly arrows */
204 if ((dummy = (struct Image *)NewObject(NULL, "sysiclass",
205 SYSIA_Which, SIZEIMAGE,
206 SYSIA_DrawInfo, (IPTR) di, TAG_END)))
208 size_width = dummy->Width; /* width of up/down-gadgets */
209 size_height = dummy->Height; /* bottom offset */
211 /* We don't need the image anymore */
212 DisposeObject(dummy);
214 /* Get the boopsi image of the up and down arrow */
215 if ((pg->upimage = (struct Image *)NewObject(NULL, "sysiclass",
216 SYSIA_Which, UPIMAGE,
217 SYSIA_DrawInfo, (IPTR) di, TAG_END)))
219 pg->up.GadgetRender = pg->up.SelectRender =
220 (APTR) pg->upimage;
221 height = pg->upimage->Height;
223 if ((pg->downimage =
224 (struct Image *)NewObject(NULL, "sysiclass",
225 SYSIA_Which, DOWNIMAGE, SYSIA_DrawInfo,
226 (IPTR) di, TAG_END)))
228 struct Gadget *G = (void *)pg;
229 WORD hoffset = size_width / 4;
231 pg->down.GadgetRender = pg->down.SelectRender =
232 (APTR) pg->downimage;
234 /* Release drawinfo */
235 FreeScreenDrawInfo(win->WScreen, di);
237 /* Now init all sizes/positions relative to window's
238 * borders */
239 G->Height =
240 -(win->BorderTop + size_height + 2 * height + 2);
241 G->TopEdge = win->BorderTop + 1;
242 G->Width = size_width - hoffset * 2 + 2;
243 G->LeftEdge = -(size_width - hoffset);
244 G++;
245 pg->up.LeftEdge = G->LeftEdge = -(size_width - 1);
246 G->Width = pg->up.Width = size_width;
247 G->Height = pg->up.Height = height;
248 G->TopEdge = -(size_height + height - 1);
249 pg->up.TopEdge = G->TopEdge - height;
251 /* Other fields */
252 pg->scroller.GadgetRender = (APTR) &pg->simage;
253 pg->scroller.SpecialInfo = (APTR) &pg->pinfo;
255 /* Link gadgets */
256 pg->scroller.NextGadget = &pg->up;
257 pg->up.NextGadget = &pg->down;
259 /* And finally, add them to the window */
260 AddGList(win, &pg->scroller, 0, 3, NULL);
261 RefreshGList(&pg->scroller, win, NULL, 3);
263 return;
265 DisposeObject(pg->upimage);
268 FreeMem(pg, sizeof(*pg));
269 FreeScreenDrawInfo(win->WScreen, di);
271 return;
274 static VOID charmapcon_adj_prop(Class *cl, Object *o)
276 struct charmapcondata *data = INST_DATA(cl, o);
277 struct ConsoleBase *ConsoleDevice = (struct ConsoleBase *)cl->cl_UserData;
278 struct Window *w = CU(o)->cu_Window;
279 ULONG VertBody, VertPot;
281 ULONG hidden =
282 data->scrollback_size >
283 CHAR_YMAX(o) ? data->scrollback_size - CHAR_YMAX(o) - 1 : 0;
285 if (hidden > 0)
287 VertPot = (data->scrollback_pos) * MAXPOT / hidden;
288 VertBody = CHAR_YMAX(o) * MAXBODY / data->scrollback_size;
290 else
292 VertPot = 0;
293 VertBody = MAXBODY;
296 if (VertPot > MAXPOT)
298 VertPot = MAXPOT;
299 D(bug("VERTPOT SET TOO HIGH. Adjusted\n"));
302 NewModifyProp((struct Gadget *)&(data->prop->scroller), w, NULL,
303 ((struct PropInfo *)data->prop->scroller.SpecialInfo)->Flags,
304 MAXPOT, VertPot, MAXBODY, VertBody, 1);
307 /*** Free resources allocated for scroller ***/
308 void charmapcon_free_prop(Class *cl, Object *o)
310 struct charmapcondata *data = INST_DATA(cl, o);
311 struct ConsoleBase *ConsoleDevice = (struct ConsoleBase *)cl->cl_UserData;
312 struct Window *win = CU(o)->cu_Window;
314 if (data->prop)
316 if (win)
318 if (data->boopsigad)
319 RemoveGadget(win, (struct Gadget *)data->prop);
320 else
321 RemoveGList(win, &data->prop->scroller, 3);
323 if (data->boopsigad)
324 DisposeObject(data->prop);
325 else
327 /* Free elements */
328 DisposeObject(data->prop->upimage);
329 DisposeObject(data->prop->downimage);
331 /* Free struct */
332 FreeMem(data->prop, sizeof(*data->prop));
339 /*********** CharMapCon::New() **********************/
341 static Object *charmapcon_new(Class *cl, Object *o, struct opSet *msg)
343 EnterFunc(bug("CharMapCon::New()\n"));
344 APTR newGfxBase = TaggedOpenLibrary(TAGGEDOPEN_GRAPHICS);
345 if (newGfxBase == NULL)
346 return NULL;
348 o = (Object *) DoSuperMethodA(cl, o, (Msg) msg);
349 if (o)
351 struct charmapcondata *data = INST_DATA(cl, o);
353 /* Clear for checking inside dispose() whether stuff was allocated.
354 Basically this is bug-prevention.
356 memset(data, 0, sizeof(struct charmapcondata));
358 data->scrollback_max = 500; /* FIXME: Don't hardcode it */
359 data->ccd_GfxBase = newGfxBase;
360 charmapcon_add_prop(cl, o);
362 ReturnPtr("CharMapCon::New", Object *, o);
365 CloseLibrary(newGfxBase);
366 ReturnPtr("CharMapCon::New", Object *, NULL);
370 /*********** CharMapCon::Dispose() **************************/
372 static VOID charmapcon_dispose(Class *cl, Object *o, Msg msg)
374 struct charmapcondata *data = INST_DATA(cl, o);
376 charmap_dispose_lines(data->top_of_scrollback);
377 charmapcon_free_prop(cl, o);
379 CloseLibrary(data->ccd_GfxBase);
381 DoSuperMethodA(cl, o, msg);
384 /********* CharMapCon::DoCommand() ****************************/
386 static struct charmap_line *charmapcon_find_line(Class *cl, Object *o,
387 ULONG ycp)
389 struct charmapcondata *data = INST_DATA(cl, o);
391 // Find the line. This is inefficient but the number of lines on screen
392 // should never be very high.
393 // FIXME: Optimizing the case of appending to the end (e.g. know what line
394 // is on the last line of the buffer).
396 struct charmap_line *line = data->top_of_window;
397 if (!line)
399 D(bug("Initializing charmap\n"));
400 data->top_of_window = data->top_of_scrollback = line =
401 charmap_newline(0, 0);
402 data->scrollback_size = 1;
405 D(bug("Finding line %ld\n", ycp));
406 while (ycp > 0)
408 if (!line->next)
410 charmap_newline(0, line);
411 data->scrollback_size += 1;
413 line = line->next;
414 ycp -= 1;
417 while (data->scrollback_size > data->scrollback_max + CHAR_YMAX(o) &&
418 data->top_of_window != data->top_of_scrollback)
420 data->scrollback_size -= 1;
421 data->scrollback_pos -= 1;
423 /* FIXME: Needs testing... */
424 if (data->select_line_max == data->select_line_min &&
425 data->select_line_min == data->top_of_scrollback)
427 /* The entire selection has scrolled out, but we keep it in case
428 it is still active
430 data->select_line_min = data->select_line_min->next;
431 data->select_line_max = data->select_line_min;
432 data->select_x_min = 0;
433 data->select_x_max = 0;
434 data->select_y_min += 1;
435 data->select_y_max += 1;
437 else if (data->top_of_scrollback == data->select_line_min)
439 data->select_line_min = data->select_line_min->next;
440 data->select_y_min += 1;
441 data->select_x_min = 0;
443 else if (data->top_of_scrollback == data->select_line_max)
445 /* "Reversed" selection */
446 data->select_line_max = data->select_line_max->next;
447 data->select_y_max += 1;
448 data->select_x_max = 0;
451 data->top_of_scrollback =
452 charmap_dispose_line(data->top_of_scrollback);
455 return line;
458 static VOID charmap_ascii(Class *cl, Object *o, ULONG xcp, ULONG ycp,
459 char *str, ULONG len)
461 struct charmap_line *line = charmapcon_find_line(cl, o, ycp);
462 ULONG oldsize = line->size;
464 // Ensure the line has sufficient capacity.
465 if (line->size < xcp + len)
466 charmap_resize(line, xcp + len);
468 // .. copy the required data
469 memset(line->fgpen + xcp, CU(o)->cu_FgPen, len);
470 memset(line->bgpen + xcp, CU(o)->cu_BgPen, len);
471 memset(line->flags + xcp, CU(o)->cu_TxFlags, len);
472 memcpy(line->text + xcp, str, len);
474 // If cursor output is moved further right on the screen than
475 // the last output, we need to fill the line
476 if (oldsize < xcp)
478 memset(line->fgpen + oldsize, CU(o)->cu_FgPen, xcp - oldsize);
479 memset(line->bgpen + oldsize, CU(o)->cu_BgPen, xcp - oldsize);
480 memset(line->flags + oldsize, CU(o)->cu_TxFlags, xcp - oldsize);
481 memset(line->text + oldsize, ' ', xcp - oldsize);
485 static VOID charmap_scroll_up(Class *cl, Object *o, ULONG y)
487 struct charmapcondata *data = INST_DATA(cl, o);
489 if (!data->top_of_window)
490 return;
492 while (y--)
494 if (!data->top_of_window->next)
496 charmap_newline(0, data->top_of_window);
497 data->scrollback_size += 1;
499 data->top_of_window = data->top_of_window->next;
500 data->scrollback_pos += 1;
501 data->select_y_max -= 1;
502 data->select_y_min -= 1;
505 if (data->scrollback_size - CHAR_YMAX(o) - 1 <= data->scrollback_pos &&
506 data->unrendered)
508 Console_RenderCursor(o);
509 data->unrendered = 0;
512 while (data->scrollback_size > data->scrollback_max + CHAR_YMAX(o) &&
513 data->top_of_window != data->top_of_scrollback)
515 data->scrollback_size -= 1;
516 data->scrollback_pos -= 1;
517 data->top_of_scrollback =
518 charmap_dispose_line(data->top_of_scrollback);
522 static VOID charmap_scroll_down(Class *cl, Object *o, ULONG y)
524 // FIXME: Need to adjust cursor position or reset to bottom when editing.
525 struct charmapcondata *data = INST_DATA(cl, o);
526 if (!data->unrendered)
528 Console_UnRenderCursor(o);
529 data->unrendered = 1;
530 data->saved_scrollback_pos = data->scrollback_pos;
531 data->saved_top_of_window = data->top_of_window;
533 // FIXME: Select position.
535 if (data->top_of_window)
537 while (y-- && data->top_of_window->prev)
539 data->top_of_window = data->top_of_window->prev;
540 data->scrollback_pos -= 1;
541 data->select_y_max += 1;
542 data->select_y_min += 1;
547 static VOID charmapcon_scroll_to(Class *cl, Object *o, ULONG y)
549 struct charmapcondata *data = INST_DATA(cl, o);
550 struct Library *GfxBase = data->ccd_GfxBase;
551 struct Window *w = CU(o)->cu_Window;
552 struct RastPort *rp = w->RPort;
553 LONG off = data->scrollback_pos - y;
554 LONG old_pos = data->scrollback_pos;
556 if (off == 0)
557 return;
559 Console_UnRenderCursor(o);
561 if (off > 0)
562 charmap_scroll_down(cl, o, off);
563 else
564 charmap_scroll_up(cl, o, -off);
566 /* Correct offset to account for the fact we might reach the
567 * top or bottom of the buffer:
569 off = old_pos - data->scrollback_pos;
571 /* A whole screenful? If so we have no choice but a full refresh
572 * (though we could double buffer... Not sure that's worth the
573 * memory cost)
575 if (abs(off) > CHAR_YMAX(o))
577 charmapcon_refresh(cl, o, 0);
578 Console_RenderCursor(o);
579 return;
582 /* Avoid a full refresh by scrolling the rastport.
583 * Use "standard" background to reduce flicker
585 SetBPen(rp, CU(o)->cu_BgPen);
586 if (off > 0)
588 ScrollRaster(rp,
590 -YRSIZE * off,
591 GFX_XMIN(o), GFX_YMIN(o), GFX_XMAX(o), GFX_YMAX(o));
593 else
595 ScrollRaster(rp,
597 -YRSIZE * off,
598 GFX_XMIN(o), GFX_YMIN(o), GFX_XMAX(o), GFX_YMAX(o));
602 /* Partial refresh */
603 charmapcon_refresh(cl, o, off);
605 Console_RenderCursor(o);
609 static VOID charmap_delete_char(Class *cl, Object *o, ULONG x, ULONG y)
611 struct charmap_line *line = charmapcon_find_line(cl, o, y);
613 if (!line || x >= line->size)
614 return;
616 // FIXME: Shrink the buffer, or keep track of capacity separately.
617 if (x + 1 >= line->size)
619 line->text[x] = 0;
620 return;
623 memmove(line->fgpen + x, line->fgpen + x + 1, 1);
624 memmove(line->bgpen + x, line->bgpen + x + 1, 1);
625 memmove(line->flags + x, line->flags + x + 1, 1);
626 memmove(line->text + x, line->text + x + 1, 1);
629 static VOID charmap_insert_char(Class *cl, Object *o, ULONG x, ULONG y)
631 struct charmap_line *line = charmapcon_find_line(cl, o, y);
633 if (x >= line->size)
634 return;
636 /* FIXME: This is wasteful, since it copies the buffers straight over,
637 * so we have to do memmove's further down. */
638 charmap_resize(line, line->size + 1);
640 memmove(line->fgpen + x + 1, line->fgpen + x, line->size - x - 1);
641 memmove(line->bgpen + x + 1, line->bgpen + x, line->size - x - 1);
642 memmove(line->flags + x + 1, line->flags + x, line->size - x - 1);
643 memmove(line->text + x + 1, line->text + x, line->size - x - 1);
645 line->fgpen[x] = CU(o)->cu_FgPen;
646 line->bgpen[x] = CU(o)->cu_BgPen;
647 line->flags[x] = CU(o)->cu_TxFlags;
648 line->text[x] = ' ';
651 static VOID charmap_formfeed(Class *cl, Object *o)
653 struct charmapcondata *data = INST_DATA(cl, o);
654 struct charmap_line *line = data->top_of_window;
656 while (line)
658 charmap_resize(line, 0);
659 line = line->next;
663 static VOID charmapcon_docommand(Class *cl, Object *o,
664 struct P_Console_DoCommand *msg)
666 IPTR *params = msg->Params;
667 struct charmapcondata *data = INST_DATA(cl, o);
669 EnterFunc(bug
670 ("CharMapCon::DoCommand(o=%p, cmd=%d, params=%p) x=%d, y=%d, ymax=%d\n",
671 o, msg->Command, params, XCP, YCP, CHAR_YMAX(o)));
673 // This is a bit of a hack: Set position to bottom in order to prevent
674 // output while scrolled.
676 ULONG old_scrollback_size = data->scrollback_size;
677 ULONG old_scrollback_pos = data->scrollback_pos;
679 if (data->unrendered)
681 data->unrendered = 0;
682 data->scrollback_pos = data->saved_scrollback_pos;
683 data->select_y_min += old_scrollback_pos - data->scrollback_pos;
684 data->select_y_max += old_scrollback_pos - data->scrollback_pos;
685 data->top_of_window = data->saved_top_of_window;
686 charmapcon_refresh(cl, o, 0);
687 Console_RenderCursor(o);
690 switch (msg->Command)
692 case C_ASCII:
693 charmap_ascii(cl, o, XCP, YCP, (char *)&params[0], 1);
694 DoSuperMethodA(cl, o, (Msg) msg);
695 break;
697 case C_ASCII_STRING:
698 charmap_ascii(cl, o, XCP, YCP, (char *)params[0], (int)params[1]);
699 DoSuperMethodA(cl, o, (Msg) msg);
700 break;
702 case C_FORMFEED:
703 charmap_formfeed(cl, o);
704 DoSuperMethodA(cl, o, (Msg) msg);
705 break;
707 case C_DELETE_CHAR: /* FIXME: can it have params!? */
708 charmap_delete_char(cl, o, XCP, YCP);
709 DoSuperMethodA(cl, o, (Msg) msg);
710 break;
712 case C_INSERT_CHAR:
713 charmap_insert_char(cl, o, XCP, YCP);
714 DoSuperMethodA(cl, o, (Msg) msg);
715 break;
717 case C_SCROLL_UP:
719 D(bug("C_SCROLL_UP area (%d, %d) to (%d, %d), %d\n",
720 GFX_XMIN(o), GFX_YMIN(o), GFX_XMAX(o), GFX_YMAX(o),
721 YRSIZE * params[0]));
722 charmap_scroll_up(cl, o, params[0]);
723 DoSuperMethodA(cl, o, (Msg) msg);
724 break;
727 case C_SCROLL_DOWN:
729 D(bug("C_SCROLL_DOWN area (%d, %d) to (%d, %d), %d\n",
730 GFX_XMIN(o), GFX_YMIN(o), GFX_XMAX(o), GFX_YMAX(o),
731 YRSIZE * params[0]));
732 charmap_scroll_down(cl, o, params[0]);
733 DoSuperMethodA(cl, o, (Msg) msg);
734 break;
737 default:
738 DoSuperMethodA(cl, o, (Msg) msg);
739 break;
742 if (old_scrollback_size != data->scrollback_size ||
743 old_scrollback_pos != data->scrollback_pos)
744 charmapcon_adj_prop(cl, o);
746 ReturnVoid("CharMapCon::DoCommand");
749 /**************************
750 ** CharMapCon::ClearCell() **
751 **************************/
752 static VOID charmapcon_clearcell(Class *cl, Object *o,
753 struct P_Console_ClearCell *msg)
755 // FIXME, insert space.
756 DoSuperMethodA(cl, o, (Msg) msg);
759 static VOID charmapcon_refresh_lines(Class *cl, Object *o, LONG fromLine,
760 LONG toLine)
762 struct Window *w = CU(o)->cu_Window;
763 struct RastPort *rp = w->RPort;
764 struct charmapcondata *data = INST_DATA(cl, o);
765 struct Library *GfxBase = data->ccd_GfxBase;
767 if (fromLine < CHAR_YMIN(o))
768 fromLine = CHAR_YMIN(o);
769 if (toLine > CHAR_YMAX(o))
770 toLine = CHAR_YMAX(o);
772 D(bug("fromLine: %ld, toLine: %ld, char_ymax: %ld\n", fromLine, toLine,
773 CHAR_YMAX(o)));
775 if (toLine < fromLine)
776 return;
778 Console_UnRenderCursor(o);
780 D(bug("Rendering charmap\n"));
782 struct charmap_line *line = charmapcon_find_line(cl, o, fromLine);
783 ULONG y = GFX_YMIN(o) + fromLine * YRSIZE + rp->Font->tf_Baseline;
784 ULONG yc = fromLine;
785 UBYTE flags = 255;
787 LONG selectstart_x, selectstart_y, selectend_x, selectend_y;
788 if (data->select_y_min == data->select_y_max)
790 selectstart_y = selectend_y = data->select_y_min;
791 selectstart_x = MIN(data->select_x_min, data->select_x_max);
792 selectend_x = MAX(data->select_x_min, data->select_x_max);
794 else if (data->select_y_min < data->select_y_max)
796 selectstart_y = data->select_y_min;
797 selectstart_x = data->select_x_min;
798 selectend_y = data->select_y_max;
799 selectend_x = data->select_x_max;
801 else
803 selectstart_y = data->select_y_max;
804 selectstart_x = data->select_x_max;
805 selectend_y = data->select_y_min;
806 selectend_x = data->select_x_min;
809 while (line && yc <= toLine)
811 const char *str = line->text;
812 ULONG start = 0;
813 ULONG remaining_space = CHAR_XMAX(o) + 1;
814 Move(rp, GFX_XMIN(o), y);
815 while (line->size > start && remaining_space > 0 && str[start])
817 /* Identify a batch of characters with the same fgpen/bgpen
818 to avoid having to move/set pens and do Text() on single
819 characters */
821 UBYTE fgpen = line->fgpen[start];
822 UBYTE bgpen = line->bgpen[start];
824 /* Is any part of this line part of a selection?
825 * If so, we bake in a state transition on "stop".
826 * This code is messy - there must be a nicer way.
828 ULONG stop = 9999999;
829 BOOL in_selection = 0;
831 if (yc > selectstart_y && yc < selectend_y)
833 in_selection = 1;
835 else if (yc == selectstart_y)
837 if (yc == selectend_y)
839 if (start >= selectstart_x && start < selectend_x)
841 in_selection = 1;
842 stop = selectend_x;
844 else if (start < selectstart_x)
846 stop = selectstart_x;
849 else
851 if (start >= selectstart_x)
852 in_selection = 1;
853 else
854 stop = selectstart_x;
857 else if (yc == selectend_y)
859 /* In this case, the selection *ends* on selectend_x */
860 if (start < selectend_x)
862 in_selection = 1;
863 stop = selectend_x;
867 if (stop == start)
868 stop += 1;
870 if (in_selection)
872 fgpen = line->bgpen[start];
873 bgpen = line->fgpen[start];
876 ULONG len = 0;
877 while (line->size > start + len && str[start + len] &&
878 len < remaining_space &&
879 line->fgpen[start] == line->fgpen[start + len] &&
880 line->bgpen[start] == line->bgpen[start + len] &&
881 line->flags[start] == line->flags[start + len] &&
882 start + len < stop)
883 len += 1;
885 setabpen(GfxBase, rp, line->flags[start], fgpen, bgpen);
886 if ((line->flags[start] & CON_TXTFLAGS_MASK) !=
887 (flags & CON_TXTFLAGS_MASK))
889 SetSoftStyle(rp, line->flags[start], CON_TXTFLAGS_MASK);
891 flags = line->flags[start];
893 Text(rp, &str[start], len);
895 start += len;
896 remaining_space -= len;
899 /* Clear to EOL, without overwriting scroll bar (ClearEOL does) */
900 SetAPen(rp, CU(o)->cu_BgPen);
901 RectFill(rp,
902 GFX_X(o, start), GFX_Y(o, yc),
903 GFX_XMAX(o), GFX_Y(o, yc + 1) - 1);
904 y += YRSIZE;
905 yc++;
907 /* We want to make sure we have lines covering the window once
908 there's something to scroll back, as that simplies resize handling
909 etc.
911 if (!line->next && yc <= toLine)
913 line->next = charmap_newline(0, line);
914 data->scrollback_size += 1;
916 line = line->next;
919 if (yc < toLine)
921 SetAPen(rp, CU(o)->cu_BgPen);
922 RectFill(rp,
923 GFX_XMIN(o), GFX_Y(o, yc), GFX_XMAX(o), GFX_Y(o, toLine));
926 Console_RenderCursor(o);
931 * Refresh the full console unless "off" is provided.
932 * If off is set to a positive value, it indicates the
933 * number of rows from the top we start rendering.
934 * If off is set to a negative value, it indicates the
935 * number of rows from the top we stop rendering.
936 * This is used for partial refreshes when the screen is
937 * scrolled up/down.
939 static VOID charmapcon_refresh(Class *cl, Object *o, LONG off)
941 LONG fromLine = 0;
942 LONG toLine = CHAR_YMAX(o) - CHAR_YMIN(o);
944 if (off > 0)
945 toLine = off - 1;
946 if (off < 0)
947 fromLine = CHAR_YMAX(o) + off + 1;
949 charmapcon_refresh_lines(cl, o, fromLine, toLine);
953 static ULONG charmapcon_calc_selection_size(struct charmap_line *first,
954 struct charmap_line *last, ULONG minx, ULONG maxx)
956 struct charmap_line *cur = first;
957 ULONG size = 0;
958 while (cur)
960 if (cur->text)
962 if (cur == first)
964 if (cur == last)
965 size += abs(maxx - minx);
966 else
967 size += cur->size - minx;
969 else if (cur == last)
971 size += maxx;
973 else
975 size += cur->size;
978 if (cur != last || (cur == last && maxx == cur->size))
979 size += 1; /* line feed */
981 if (cur == last)
982 break;
983 cur = cur->next;
985 return size;
988 char *charmapcon_get_selection(ULONG size,
989 struct charmap_line *first,
990 struct charmap_line *last, ULONG minx, ULONG maxx)
992 char *buf = AllocMem(size, MEMF_ANY);
993 char *bufpos = buf;
994 struct charmap_line *cur = first;
996 if (!bufpos)
997 return 0;
999 while (cur)
1001 if (cur->text)
1003 /* empty lines may not have text ptrs */
1004 if (cur == first)
1006 if (cur == last)
1008 CopyMem(cur->text + MIN(minx, maxx), bufpos,
1009 abs(maxx - minx));
1010 bufpos += abs(maxx - minx);
1012 else
1014 CopyMem(cur->text + minx, bufpos, cur->size - minx);
1015 bufpos += cur->size - minx;
1018 else if (cur == last)
1020 CopyMem(cur->text, bufpos, maxx);
1021 bufpos += maxx;
1023 else
1025 CopyMem(cur->text, bufpos, cur->size);
1026 bufpos += cur->size;
1029 if (cur != last || (cur == last && maxx == cur->size)) /* line feed */
1031 *bufpos = '\r';
1032 bufpos += 1;
1034 if (cur == last)
1035 break;
1036 cur = cur->next;
1038 return buf;
1041 struct ConClipData
1043 ULONG flags; /* always zero? */
1044 ULONG size; /* does not include NUL termination */
1045 APTR buffer; /* NUL-terminated string! */
1048 /* FIXME: Belongs in snipmapcon - here temporarily until refactored out
1049 selection code */
1050 static VOID charmapcon_copy(Class *cl, Object *o, Msg copymsg)
1052 struct charmapcondata *data = INST_DATA(cl, o);
1053 struct ConsoleBase *ConsoleDevice = (struct ConsoleBase *)cl->cl_UserData;
1054 struct MsgPort replyport, *port;
1055 struct SGWork sgw;
1056 struct MyEditHookMsg msg;
1057 char *buf;
1059 struct charmap_line *first, *last;
1060 ULONG minx, maxx, size;
1062 /* Create a string from the contents of the scrollback buffer */
1063 if (data->select_y_min < data->select_y_max)
1065 first = data->select_line_min;
1066 last = data->select_line_max;
1067 minx = data->select_x_min;
1068 maxx = data->select_x_max;
1070 else
1072 first = data->select_line_max;
1073 last = data->select_line_min;
1074 minx = data->select_x_max;
1075 maxx = data->select_x_min;
1078 size = charmapcon_calc_selection_size(first, last, minx, maxx);
1079 buf = charmapcon_get_selection(size, first, last, minx, maxx);
1080 D(bug("%d bytes copied\n"));
1082 /* If Conclip is running, we prefer using that */
1083 if (IsListEmpty(&ConsoleDevice->sniphooks)
1084 && (port = FindPort(CONCLIP_PORTNAME)))
1086 /* AROS conclip format */
1087 D(bug("AROS conclip\n"));
1088 replyport.mp_Node.ln_Type = NT_MSGPORT;
1089 replyport.mp_Node.ln_Name = NULL;
1090 replyport.mp_Node.ln_Pri = 0;
1091 replyport.mp_Flags = PA_SIGNAL;
1092 replyport.mp_SigBit = SIGB_SINGLE;
1093 replyport.mp_SigTask = FindTask(NULL);
1094 NewList(&replyport.mp_MsgList);
1096 msg.msg.mn_Node.ln_Type = NT_MESSAGE;
1097 msg.msg.mn_ReplyPort = &replyport;
1098 msg.msg.mn_Length = sizeof(msg);
1100 msg.code = CODE_COPY;
1101 msg.sgw = &sgw;
1103 sgw.Gadget = 0;
1104 sgw.WorkBuffer = buf;
1105 sgw.PrevBuffer = 0;
1106 sgw.IEvent = 0;
1107 sgw.Code = CODE_COPY;
1108 sgw.Actions = 0;
1109 sgw.LongInt = 0;
1110 sgw.GadgetInfo = 0;
1111 sgw.EditOp = EO_BIGCHANGE;
1112 sgw.BufferPos = 0;
1113 sgw.NumChars = size;
1115 SetSignal(0, SIGF_SINGLE);
1116 PutMsg(port, &msg.msg);
1117 WaitPort(&replyport);
1119 FreeMem(buf, size);
1120 return;
1123 ObtainSemaphore(&ConsoleDevice->copyBufferLock);
1124 FreeMem((APTR) ConsoleDevice->copyBuffer,
1125 ConsoleDevice->copyBufferSize);
1127 ConsoleDevice->copyBuffer = buf;
1128 if (ConsoleDevice->copyBuffer)
1129 ConsoleDevice->copyBufferSize = size;
1130 else
1131 ConsoleDevice->copyBufferSize = 0;
1133 if (!IsListEmpty(&ConsoleDevice->sniphooks))
1135 /* OS2-3.x compatible conclip format */
1136 struct Hook *conhook;
1137 struct ConClipData ccd;
1139 D(bug("AOS conclip\n"));
1140 if (ConsoleDevice->copyBufferSize)
1142 ccd.flags = 0;
1143 ccd.size = ConsoleDevice->copyBufferSize;
1144 /* must be NUL-terminated */
1145 ccd.buffer = AllocVec(ccd.size + 1, MEMF_CLEAR);
1146 if (ccd.buffer)
1148 CopyMem(ConsoleDevice->copyBuffer, ccd.buffer, ccd.size);
1149 ForeachNode(&ConsoleDevice->sniphooks, conhook)
1151 D(bug("Calling AOS conclip hook %p\n", conhook));
1152 CALLHOOKPKT(conhook, NULL, &ccd);
1154 FreeVec(ccd.buffer);
1158 ReleaseSemaphore(&ConsoleDevice->copyBufferLock);
1162 /**********************************
1163 ** CharMapCon::NewWindowSize() **
1164 **********************************/
1165 static VOID charmapcon_newwindowsize(Class *cl, Object *o,
1166 struct P_Console_NewWindowSize *msg)
1168 struct charmapcondata *data = INST_DATA(cl, o);
1170 WORD old_ycp = YCP;
1172 DoSuperMethodA(cl, o, (Msg) msg);
1173 D(bug("CharMapCon::NewWindowSize(o=%p) x=%d, y=%d, ymax=%d\n",
1174 o, XCP, YCP, CHAR_YMAX(o)));
1176 // Is console empty? Unlikely, but anyway.
1177 if (!data->top_of_window)
1178 return;
1180 // Scroll up if new window size has forced the cursor up
1181 if (old_ycp > CHAR_YMAX(o))
1183 charmap_scroll_up(cl, o, old_ycp - CHAR_YMAX(o));
1186 charmapcon_refresh(cl, o, 0);
1189 static VOID charmapcon_handlemouse(Class *cl, Object *o,
1190 struct P_Console_HandleGadgets *msg)
1192 struct charmapcondata *data = INST_DATA(cl, o);
1193 struct Window *w = CU(o)->cu_Window;
1194 struct InputEvent *e = msg->Event;
1196 /* We have the following states:
1197 * - No active selection and no mouse button => ignore
1198 * - No active selection and left mouse button => Start selection
1199 * - Active selection and no mouse button => End selection
1200 * - Active selection and left mouse button => Update selection
1203 LONG x, y;
1206 * Take window-relative mouse position.
1207 * The original code here failed when the screen was moved away from (0, 0)
1208 * position. x and y were unaware of shifted display (ie_X and ie_Y are
1209 * raw physical coordinates, and w->LeftEdge and w->TopEdge are screen-
1210 * relative), and this caused lockups here.
1211 * TODO: Verify this intuition's behavior with AmigaOS3.1 using screentest
1212 * program. (sonic)
1214 x = e->ie_X - w->LeftEdge;
1215 y = e->ie_Y - w->TopEdge;
1217 x = w->MouseX;
1218 y = w->MouseY;
1220 /* Active selection */
1222 if (!(e->ie_Qualifier & IEQUALIFIER_LEFTBUTTON))
1224 /* End selection */
1225 data->active_selection = 0;
1226 data->ignore_drag = 0;
1227 return;
1230 if (!data->active_selection)
1232 if (e->ie_Qualifier & IEQUALIFIER_LEFTBUTTON && !data->ignore_drag)
1234 /* Inside the console area? */
1235 if (x >= GFX_XMIN(o) && x <= GFX_XMAX(o) &&
1236 y >= GFX_YMIN(o) && y <= GFX_YMAX(o))
1238 D(bug("activated selection with x: %ld, y: %ld,"
1239 " xmin: %ld, ymin: %Ld, xmax: %ld, ymax: %ld\n",
1240 x, y, GFX_XMIN(o), GFX_YMIN(o), GFX_XMAX(o),
1241 GFX_YMAX(o)));
1243 /* We need to clear these lines
1245 LONG old_min_y =
1246 MIN(data->select_y_min, data->select_y_max);
1247 LONG old_max_y =
1248 MAX(data->select_y_min, data->select_y_max);
1250 /* Yes, so start selection */
1251 data->active_selection = 1;
1252 data->ignore_drag = 0;
1253 data->select_x_min = (x - GFX_XMIN(o)) / XRSIZE;
1254 data->select_y_min = (y - GFX_YMIN(o)) / YRSIZE;
1255 data->select_line_min =
1256 charmapcon_find_line(cl, o, data->select_y_min);
1258 data->select_x_max = data->select_x_min;
1259 data->select_y_max = data->select_y_min;
1261 /* Clear */
1263 /* FIXME: Determine exactly which lines are affected, as
1264 follows:
1266 - If max_y has increased, render from old_max_y to new
1267 - If min_y has decreased, refresh from new min y to old
1268 - If both have changed, refresh in two batches.
1269 - If there's been a reversal of the relative positions of
1270 y_min/y_max, refresh the entire range.
1272 charmapcon_refresh_lines(cl, o, old_min_y, old_max_y);
1275 else
1276 data->ignore_drag = 1;
1278 return;
1281 /* Update selection. */
1282 if (x >= GFX_XMIN(o) && x <= GFX_XMAX(o) &&
1283 y >= GFX_YMIN(o) && y <= GFX_YMAX(o))
1286 LONG xmax, ymax;
1287 xmax = data->select_x_max;
1288 ymax = data->select_y_max;
1289 data->select_x_max = (x - GFX_XMIN(o)) / XRSIZE;
1290 data->select_y_max = (y - GFX_YMIN(o)) / YRSIZE;
1291 data->select_line_max =
1292 charmapcon_find_line(cl, o, data->select_y_max);
1293 /* FIXME: More intelligent refresh */
1294 if (xmax != data->select_x_max || ymax != data->select_y_max)
1296 charmapcon_refresh_lines(cl, o, MIN(ymax,
1297 MIN(data->select_y_min, data->select_y_max)), MAX(ymax,
1298 MAX(data->select_y_min, data->select_y_max)));
1301 else
1303 /* FIXME: Outside the console area, we need to scroll the window
1304 and just update the selection based on that */
1309 static VOID charmapcon_handlegadgets(Class *cl, Object *o,
1310 struct P_Console_HandleGadgets *msg)
1312 struct InputEvent *e = msg->Event;
1314 if (e->ie_Class == IECLASS_RAWMOUSE)
1316 charmapcon_handlemouse(cl, o, msg);
1317 return;
1320 struct charmapcondata *data = INST_DATA(cl, o);
1322 if (e->ie_Class == IECLASS_GADGETUP)
1324 data->activeGad = 0;
1325 return;
1328 if (e->ie_Class == IECLASS_GADGETDOWN)
1330 /* We pass 0 from consoletask if the mouse wheel is being used */
1331 if ((IPTR) e->ie_EventAddress == 1)
1332 data->activeGad = (APTR) &(data->prop->up);
1333 else if ((IPTR) e->ie_EventAddress == 2)
1334 data->activeGad = (APTR) &(data->prop->down);
1335 else
1336 data->activeGad = e->ie_EventAddress;
1339 if (data->activeGad == (APTR) &(data->prop->scroller))
1341 ULONG hidden =
1342 data->scrollback_size >
1343 CHAR_YMAX(o) ? data->scrollback_size - CHAR_YMAX(o) - 1 : 0;
1344 ULONG pos =
1345 (((struct PropInfo *)((struct Gadget *)&(data->prop->
1346 scroller))->SpecialInfo)->VertPot * hidden +
1347 (MAXPOT / 2)) / MAXPOT;
1349 if (pos != data->scrollback_pos)
1350 charmapcon_scroll_to(cl, o, pos);
1352 else if (data->activeGad == (APTR) &(data->prop->down))
1354 if (data->scrollback_pos + CHAR_YMAX(o) < data->scrollback_size - 1)
1356 charmap_scroll_up(cl, o, 1);
1357 charmapcon_refresh(cl, o, 0);
1358 charmapcon_adj_prop(cl, o);
1361 else if (data->activeGad == (APTR) &(data->prop->up))
1363 if (data->top_of_window != data->top_of_scrollback)
1365 charmap_scroll_down(cl, o, 1);
1366 charmapcon_refresh(cl, o, 0);
1367 charmapcon_adj_prop(cl, o);
1374 AROS_UFH3S(IPTR, dispatch_charmapconclass,
1375 AROS_UFHA(Class *, cl, A0),
1376 AROS_UFHA(Object *, o, A2), AROS_UFHA(Msg, msg, A1))
1378 AROS_USERFUNC_INIT
1380 IPTR retval = 0UL;
1382 switch (msg->MethodID)
1384 case OM_NEW:
1385 retval = (IPTR) charmapcon_new(cl, o, (struct opSet *)msg);
1386 break;
1388 case OM_DISPOSE:
1389 charmapcon_dispose(cl, o, msg);
1390 break;
1392 case M_Console_DoCommand:
1393 charmapcon_docommand(cl, o, (struct P_Console_DoCommand *)msg);
1394 break;
1396 case M_Console_ClearCell:
1397 // FIXME: scroll down to end here if it's not there already.
1398 charmapcon_clearcell(cl, o, (struct P_Console_ClearCell *)msg);
1399 break;
1401 case M_Console_NewWindowSize:
1402 charmapcon_newwindowsize(cl, o,
1403 (struct P_Console_NewWindowSize *)msg);
1404 break;
1406 case M_Console_HandleGadgets:
1407 //D(bug("CharMapCon::HandleGadgets\n"));
1408 charmapcon_handlegadgets(cl, o,
1409 (struct P_Console_HandleGadgets *)msg);
1410 break;
1412 /* FIXME: Belongs in snimapcon - here temporarily until refactored out
1413 selection code */
1414 case M_Console_Copy:
1415 charmapcon_copy(cl, o, msg);
1416 break;
1418 default:
1419 retval = DoSuperMethodA(cl, o, msg);
1420 break;
1423 return retval;
1425 AROS_USERFUNC_EXIT
1428 #undef ConsoleDevice
1430 Class *makeCharMapConClass(struct ConsoleBase *ConsoleDevice)
1433 Class *cl;
1435 cl = MakeClass(NULL, NULL, STDCONCLASSPTR,
1436 sizeof(struct charmapcondata), 0UL);
1437 if (cl)
1439 cl->cl_Dispatcher.h_Entry = (APTR) dispatch_charmapconclass;
1440 cl->cl_Dispatcher.h_SubEntry = NULL;
1442 cl->cl_UserData = (IPTR) ConsoleDevice;
1444 return (cl);
1446 return (NULL);