2 Copyright © 1995-2014, The AROS Development Team. All rights reserved.
5 Desc: Code for CONU_CHARMAP console units.
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>
30 #include <aros/debug.h>
32 #include "console_gcc.h"
33 #include "consoleif.h"
38 AUTOKNOB | FREEVERT | PROPNEWLOOK | PROPBORDERLESS
41 #define CODE_PASTE 'V'
50 static const STRPTR CONCLIP_PORTNAME
= "ConClip.rendezvous";
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
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 */
87 struct charmap_line
*select_line_min
;
90 struct charmap_line
*select_line_max
;
91 BOOL active_selection
; /* If true, mouse move will affect the selection */
95 UBYTE boopsigad
; /* Type of right prop gadget of window */
102 struct Library
*ccd_GfxBase
;
106 /* Template used to quickly fill constant fields */
107 CONST
struct Scroll ScrollBar
= {
111 GFLG_RELRIGHT
| GFLG_RELHEIGHT
,
112 GACT_RIGHTBORDER
| GACT_FOLLOWMOUSE
| GACT_IMMEDIATE
|
115 NULL
, NULL
, NULL
, 0, NULL
,
121 GFLG_RELRIGHT
| GFLG_RELBOTTOM
| GFLG_GADGHIMAGE
|
123 GACT_RIGHTBORDER
| GACT_RELVERIFY
| GACT_IMMEDIATE
,
125 NULL
, NULL
, NULL
, 0, NULL
,
131 GFLG_RELRIGHT
| GFLG_RELBOTTOM
| GFLG_GADGHIMAGE
|
133 GACT_RIGHTBORDER
| GACT_RELVERIFY
| GACT_IMMEDIATE
,
135 NULL
, NULL
, NULL
, 0, NULL
,
144 /* Other values may be NULL */
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
;
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
,
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
;
191 data
->boopsigad
= FALSE
;
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
;
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
=
221 height
= pg
->upimage
->Height
;
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
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
);
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
;
252 pg
->scroller
.GadgetRender
= (APTR
) &pg
->simage
;
253 pg
->scroller
.SpecialInfo
= (APTR
) &pg
->pinfo
;
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);
265 DisposeObject(pg
->upimage
);
268 FreeMem(pg
, sizeof(*pg
));
269 FreeScreenDrawInfo(win
->WScreen
, di
);
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
;
282 data
->scrollback_size
>
283 CHAR_YMAX(o
) ? data
->scrollback_size
- CHAR_YMAX(o
) - 1 : 0;
287 VertPot
= (data
->scrollback_pos
) * MAXPOT
/ hidden
;
288 VertBody
= CHAR_YMAX(o
) * MAXBODY
/ data
->scrollback_size
;
296 if (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
;
319 RemoveGadget(win
, (struct Gadget
*)data
->prop
);
321 RemoveGList(win
, &data
->prop
->scroller
, 3);
324 DisposeObject(data
->prop
);
328 DisposeObject(data
->prop
->upimage
);
329 DisposeObject(data
->prop
->downimage
);
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
)
348 o
= (Object
*) DoSuperMethodA(cl
, o
, (Msg
) msg
);
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
,
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
;
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
));
410 charmap_newline(0, line
);
411 data
->scrollback_size
+= 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
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
);
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
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
)
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
&&
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
;
559 Console_UnRenderCursor(o
);
562 charmap_scroll_down(cl
, o
, off
);
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
575 if (abs(off
) > CHAR_YMAX(o
))
577 charmapcon_refresh(cl
, o
, 0);
578 Console_RenderCursor(o
);
582 /* Avoid a full refresh by scrolling the rastport.
583 * Use "standard" background to reduce flicker
585 SetBPen(rp
, CU(o
)->cu_BgPen
);
591 GFX_XMIN(o
), GFX_YMIN(o
), GFX_XMAX(o
), GFX_YMAX(o
));
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
)
616 // FIXME: Shrink the buffer, or keep track of capacity separately.
617 if (x
+ 1 >= line
->size
)
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
);
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
;
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
;
658 charmap_resize(line
, 0);
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
);
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
)
693 charmap_ascii(cl
, o
, XCP
, YCP
, (char *)¶ms
[0], 1);
694 DoSuperMethodA(cl
, o
, (Msg
) msg
);
698 charmap_ascii(cl
, o
, XCP
, YCP
, (char *)params
[0], (int)params
[1]);
699 DoSuperMethodA(cl
, o
, (Msg
) msg
);
703 charmap_formfeed(cl
, o
);
704 DoSuperMethodA(cl
, o
, (Msg
) msg
);
707 case C_DELETE_CHAR
: /* FIXME: can it have params!? */
708 charmap_delete_char(cl
, o
, XCP
, YCP
);
709 DoSuperMethodA(cl
, o
, (Msg
) msg
);
713 charmap_insert_char(cl
, o
, XCP
, YCP
);
714 DoSuperMethodA(cl
, o
, (Msg
) msg
);
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
);
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
);
738 DoSuperMethodA(cl
, o
, (Msg
) msg
);
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
,
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
,
775 if (toLine
< fromLine
)
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
;
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
;
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
;
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
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
)
835 else if (yc
== selectstart_y
)
837 if (yc
== selectend_y
)
839 if (start
>= selectstart_x
&& start
< selectend_x
)
844 else if (start
< selectstart_x
)
846 stop
= selectstart_x
;
851 if (start
>= selectstart_x
)
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
)
872 fgpen
= line
->bgpen
[start
];
873 bgpen
= line
->fgpen
[start
];
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
] &&
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
);
896 remaining_space
-= len
;
899 /* Clear to EOL, without overwriting scroll bar (ClearEOL does) */
900 SetAPen(rp
, CU(o
)->cu_BgPen
);
902 GFX_X(o
, start
), GFX_Y(o
, yc
),
903 GFX_XMAX(o
), GFX_Y(o
, yc
+ 1) - 1);
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
911 if (!line
->next
&& yc
<= toLine
)
913 line
->next
= charmap_newline(0, line
);
914 data
->scrollback_size
+= 1;
921 SetAPen(rp
, CU(o
)->cu_BgPen
);
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
939 static VOID
charmapcon_refresh(Class
*cl
, Object
*o
, LONG off
)
942 LONG toLine
= CHAR_YMAX(o
) - CHAR_YMIN(o
);
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
;
965 size
+= abs(maxx
- minx
);
967 size
+= cur
->size
- minx
;
969 else if (cur
== last
)
978 if (cur
!= last
|| (cur
== last
&& maxx
== cur
->size
))
979 size
+= 1; /* line feed */
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
);
994 struct charmap_line
*cur
= first
;
1003 /* empty lines may not have text ptrs */
1008 CopyMem(cur
->text
+ MIN(minx
, maxx
), bufpos
,
1010 bufpos
+= abs(maxx
- minx
);
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
);
1025 CopyMem(cur
->text
, bufpos
, cur
->size
);
1026 bufpos
+= cur
->size
;
1029 if (cur
!= last
|| (cur
== last
&& maxx
== cur
->size
)) /* line feed */
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
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
;
1056 struct MyEditHookMsg msg
;
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
;
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
;
1104 sgw
.WorkBuffer
= buf
;
1107 sgw
.Code
= CODE_COPY
;
1111 sgw
.EditOp
= EO_BIGCHANGE
;
1113 sgw
.NumChars
= size
;
1115 SetSignal(0, SIGF_SINGLE
);
1116 PutMsg(port
, &msg
.msg
);
1117 WaitPort(&replyport
);
1123 ObtainSemaphore(&ConsoleDevice
->copyBufferLock
);
1124 FreeMem((APTR
) ConsoleDevice
->copyBuffer
,
1125 ConsoleDevice
->copyBufferSize
);
1127 ConsoleDevice
->copyBuffer
= buf
;
1128 if (ConsoleDevice
->copyBuffer
)
1129 ConsoleDevice
->copyBufferSize
= size
;
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
)
1143 ccd
.size
= ConsoleDevice
->copyBufferSize
;
1144 /* must be NUL-terminated */
1145 ccd
.buffer
= AllocVec(ccd
.size
+ 1, MEMF_CLEAR
);
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
);
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
)
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
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
1214 x = e->ie_X - w->LeftEdge;
1215 y = e->ie_Y - w->TopEdge;
1220 /* Active selection */
1222 if (!(e
->ie_Qualifier
& IEQUALIFIER_LEFTBUTTON
))
1225 data
->active_selection
= 0;
1226 data
->ignore_drag
= 0;
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
),
1243 /* We need to clear these lines
1246 MIN(data
->select_y_min
, data
->select_y_max
);
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
;
1263 /* FIXME: Determine exactly which lines are affected, as
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
);
1276 data
->ignore_drag
= 1;
1281 /* Update selection. */
1282 if (x
>= GFX_XMIN(o
) && x
<= GFX_XMAX(o
) &&
1283 y
>= GFX_YMIN(o
) && y
<= GFX_YMAX(o
))
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
)));
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
);
1320 struct charmapcondata
*data
= INST_DATA(cl
, o
);
1322 if (e
->ie_Class
== IECLASS_GADGETUP
)
1324 data
->activeGad
= 0;
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
);
1336 data
->activeGad
= e
->ie_EventAddress
;
1339 if (data
->activeGad
== (APTR
) &(data
->prop
->scroller
))
1342 data
->scrollback_size
>
1343 CHAR_YMAX(o
) ? data
->scrollback_size
- CHAR_YMAX(o
) - 1 : 0;
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
))
1382 switch (msg
->MethodID
)
1385 retval
= (IPTR
) charmapcon_new(cl
, o
, (struct opSet
*)msg
);
1389 charmapcon_dispose(cl
, o
, msg
);
1392 case M_Console_DoCommand
:
1393 charmapcon_docommand(cl
, o
, (struct P_Console_DoCommand
*)msg
);
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
);
1401 case M_Console_NewWindowSize
:
1402 charmapcon_newwindowsize(cl
, o
,
1403 (struct P_Console_NewWindowSize
*)msg
);
1406 case M_Console_HandleGadgets
:
1407 //D(bug("CharMapCon::HandleGadgets\n"));
1408 charmapcon_handlegadgets(cl
, o
,
1409 (struct P_Console_HandleGadgets
*)msg
);
1412 /* FIXME: Belongs in snimapcon - here temporarily until refactored out
1414 case M_Console_Copy
:
1415 charmapcon_copy(cl
, o
, msg
);
1419 retval
= DoSuperMethodA(cl
, o
, msg
);
1428 #undef ConsoleDevice
1430 Class
*makeCharMapConClass(struct ConsoleBase
*ConsoleDevice
)
1435 cl
= MakeClass(NULL
, NULL
, STDCONCLASSPTR
,
1436 sizeof(struct charmapcondata
), 0UL);
1439 cl
->cl_Dispatcher
.h_Entry
= (APTR
) dispatch_charmapconclass
;
1440 cl
->cl_Dispatcher
.h_SubEntry
= NULL
;
1442 cl
->cl_UserData
= (IPTR
) ConsoleDevice
;