File: common\editpal.c
1 /*
2 * editpal.c
3 *
4 * Edits VGA 256-color palettes.
5 *
6 * Key to initials:
7 *
8 * EAN - Ethan Nagel [70022,2552]
9 *
10 * JJB - Juan J. Buhler [jbuhler@gidef.edu.ar]
11 *
12 * TIW - Tim Wegner
13 *
14 * AMC - Andrew McCarthy [andrewmc@netsoc.ucd.ie]
15 *
16 * Revision History:
17 *
18 * 10-22-90 EAN Initial release.
19 *
20 * 10-23-90 EAN "Discovered" get_line/put_line functions, integrated
21 * them in (instead of only getcolor/putcolor). Much
22 * faster!
23 * Redesigned color editors (now at top of palette) and
24 * re-assigned some keys.
25 * Added (A)uto option.
26 * Fixed memory allocation problem. Now uses shared
27 * FRACTINT data area (strlocn). Uses 6 bytes DS.
28 *
29 * 10-27-90 EAN Added save to memory option - will save screen image to
30 * memory, if enough mem avail. (disk otherwise).
31 * Added s(T)ripe mode - works like (S)hade except only
32 * changes every n'th entry.
33 * Added temporary palette save/restore. (Can work like
34 * an undo feature.) Thanks to Pieter Branderhorst for
35 * idea.
36 *
37 * 10-28-90 EAN The (H)ide function now makes the palette invisible,
38 * while allowing any other operations (except '\\' -
39 * move/resize) to continue.
40 *
41 * 10-29-90 PB (in EAN's absence, <grin>)
42 * Change 'c' to 'd' and 's' to '=' for below.
43 * Add 'l' to load palette from .map, 's' to store .map.
44 * Add 'c' to invoke color cycling.
45 * Change cursor to use whatever colors it can from
46 * the palette (not fixed 0 and 255).
47 * Restore colors 0 and 255 to real values whenever
48 * palette is not on display.
49 * Rotate 255 colors instead of 254.
50 * Reduce cursor blink rate.
51 *
52 * 11-15-90 EAN Minor "bug" fixes. Continuous rotation now at a fixed
53 * rate - once every timer tick (18.2 sec); Blanks out
54 * color samples when rotating; Editors no longer rotate
55 * with the colors in color rotation mode; Eliminated
56 * (Z)oom mode; other minor fixes.
57 *
58 * 01-05-91 PB Add 'w' function to convert to greyscale.
59 *
60 * 01-16-91 PB Change rotate function to use new cyclerange stuff.
61 *
62 * 01-29-91 EAN Made all colors editable. The two reserved colors are
63 * X'ed out. They can be edited but the color is not
64 * visible. (There is an X over the sample instead.)
65 * Changed default reserved colors to 254 & 255.
66 * Added 'v' command to set the reserved colors to those
67 * under the editors.
68 * Added 'o' command to set the rotate range to between
69 * the two editors.
70 * Modified 'w' function:
71 * uses internal function to do conversion (not BIOS)
72 * will convert only current color if in 'x' mode or
73 * range between editors in 'y' mode or entire palette
74 * if in "normal" mode.
75 *
76 * 02-08-91 EAN Improved 16 color support. In 16 color mode, colors
77 * 16-255 have a dot over them and are editable but not
78 * visible (like the two reserved colors).
79 *
80 * 09-08-91 SWT Added 'n' command to make a negative color palette:
81 * will convert only current color if in 'x' mode or
82 * range between editors in 'y' mode or entire palette
83 * if in "normal" mode.
84 *
85 * 03-03-92 JJB Added '!', '@' and '#' commands to swap RG, GB and
86 * RB columns (sorry, I didn't find better keys)
87 *
88 * 10-03-92 TIW Minor changes for Jiim support, primarily changing
89 * variables from static to global.
90 *
91 * 2-11-93 EAN Added full Undo ('U' key) and Redo ('E' key)
92 * capability. Works pretty much as you'd expect
93 * it to.
94 *
95 * 3-6-93 EAN Modified "freestyle" mode, written by RB, to integrate
96 * into palette editor more completely and work with
97 * undo logic.
98 * Added status area under the "fractint" message to
99 * display current state of editor. A = Auto mode,
100 * X, Y = exclusion modes, F = freesyle mode, T = stripe
101 * mode is waiting for #.
102 *
103 * 03-21-97 AMC Made '"' work the same as '@' and made 'œ' work like
104 * '#' for those of us on this side of the Atlantic!
105 * The original palette is now stored in the other slots
106 * on startup, so you can 'undo all' if you haven't
107 * overwritten them already. Undo could do this, but
108 * this is handy.
109 * 05-22-97 TIW Replaced movedata with far_memcopy()
110 */
111
112 #ifdef DEBUG_UNDO
113 #include "mdisp.h" /* EAN 930211 *** Debug Only *** */ 114 #endif
115
116 #include <string.h>
117
118 #ifndef USE_VARARGS
119 #include <stdarg.h>
120 #else
121 #include <varargs.h> 122 #endif
123
124 #ifdef __TURBOC__
125 # include <mem.h> /* to get mem...() declarations */ 126 #endif
127
128 /* see Fractint.c for a description of the "include" hierarchy */
129 #include "port.h"
130 #include "prototyp.h"
131
132 /*
133 * misc. #defines
134 */
135
136 #define FONT_DEPTH 8 /* font size */
137
138 #define CSIZE_MIN 8 /* csize cannot be smaller than this */
139
140 #define CURSOR_SIZE 5 /* length of one side of the x-hair cursor */
141
142 #ifndef XFRACT
143 #define CURSOR_BLINK_RATE 3 /* timer ticks between cursor blinks */
146 #endif
147
148 #define FAR_RESERVE 8192L /* amount of far mem we will leave avail. */
149
150 #define MAX_WIDTH 1024 /* palette editor cannot be wider than this */
151
152 char scrnfile[] = "FRACTINT.$$1"; /* file where screen portion is */
153 /* stored */
154 char undofile[] = "FRACTINT.$$2"; /* file where undo list is stored */
155 #define TITLE "FRACTINT"
156
157 #define TITLE_LEN (8)
158
159
160 #define newx(size) mem_alloc(size)
161 #define new(class) (class *)(mem_alloc(sizeof(class)))
162 #define delete(block) block=NULL /* just for warning */
163
164 #ifdef XFRACT
165 int editpal_cursor = 0; 166 #endif
167
168
169 /*
170 * Stuff from fractint
171 */
172
173 #if 0
188 #endif
189 int using_jiim = 0;
190
191 /*
192 * basic data types
193 */
194
195
196 typedef struct
197 {
198 BYTE red,
199 green,
200 blue;
201 } PALENTRY;
202
203
204
205 /*
206 * static data
207 */
208
209
210 static BYTE far *font8x8 = NULL;
211 BYTE *line_buff; /* must be alloced!!! */
212 static BYTE fg_color,
213 bg_color;
214 static BOOLEAN reserve_colors;
215 static BOOLEAN inverse;
216
217 static float gamma_val = 1;
218
219
220 /*
221 * Interface to FRACTINT's graphics stuff
222 */
223
224
225 static void setpal(int pal, int r, int g, int b)
226 {
227 dacbox[pal][0] = (BYTE)r;
228 dacbox[pal][1] = (BYTE)g;
229 dacbox[pal][2] = (BYTE)b;
230 spindac(0,1);
231 }
232
233
234 static void setpalrange(int first, int how_many, PALENTRY *pal)
235 {
236 memmove(dacbox+first, pal, how_many*3);
237 spindac(0,1);
238 }
239
240
241 static void getpalrange(int first, int how_many, PALENTRY *pal)
242 {
243 memmove(pal, dacbox+first, how_many*3);
244 }
245
246
247 static void rotatepal(PALENTRY *pal, int dir, int lo, int hi)
248 { /* rotate in either direction */
249 PALENTRY hold;
250 int size;
251
252 size = 1 + (hi-lo);
253
254 if ( dir > 0 )
255 {
256 while ( dir-- > 0 )
257 {
258 memmove(&hold, &pal[hi], 3);
259 memmove(&pal[lo+1], &pal[lo], 3*(size-1));
260 memmove(&pal[lo], &hold, 3);
261 }
262 }
263
264 else if ( dir < 0 )
265 {
266 while ( dir++ < 0 )
267 {
268 memmove(&hold, &pal[lo], 3);
269 memmove(&pal[lo], &pal[lo+1], 3*(size-1));
270 memmove(&pal[hi], &hold, 3);
271 }
272 }
273 }
274
275
276 static void clip_put_line(int row, int start, int stop, BYTE *pixels)
277 {
278 if ( row < 0 || row >= sydots || start > sxdots || stop < 0 )
279 return ;
280
281 if ( start < 0 )
282 {
283 pixels += -start;
284 start = 0;
285 }
286
287 if ( stop >= sxdots )
288 stop = sxdots - 1;
289
290 if ( start > stop )
291 return ;
292
293 put_line(row, start, stop, pixels);
294 }
295
296
297 static void clip_get_line(int row, int start, int stop, BYTE *pixels)
298 {
299 if ( row < 0 || row >= sydots || start > sxdots || stop < 0 )
300 return ;
301
302 if ( start < 0 )
303 {
304 pixels += -start;
305 start = 0;
306 }
307
308 if ( stop >= sxdots )
309 stop = sxdots - 1;
310
311 if ( start > stop )
312 return ;
313
314 get_line(row, start, stop, pixels);
315 }
316
317
318 void clip_putcolor(int x, int y, int color)
319 {
320 if ( x < 0 || y < 0 || x >= sxdots || y >= sydots )
321 return ;
322
323 putcolor(x, y, color);
324 }
325
326
327 int clip_getcolor(int x, int y)
328 {
329 if ( x < 0 || y < 0 || x >= sxdots || y >= sydots )
330 return (0);
331
332 return ( getcolor(x, y) );
333 }
334
335
336 static void hline(int x, int y, int width, int color)
337 {
338 memset(line_buff, color, width);
339 clip_put_line(y, x, x+width-1, line_buff);
340 }
341
342
343 static void vline(int x, int y, int depth, int color)
344 {
345 while (depth-- > 0)
346 clip_putcolor(x, y++, color);
347 }
348
349
350 void getrow(int x, int y, int width, char *buff)
351 {
352 clip_get_line(y, x, x+width-1, (BYTE *)buff);
353 }
354
355
356 void putrow(int x, int y, int width, char *buff)
357 {
358 clip_put_line(y, x, x+width-1, (BYTE *)buff);
359 }
360
361
362 static void vgetrow(int x, int y, int depth, char *buff)
363 {
364 while (depth-- > 0)
365 *buff++ = (char)clip_getcolor(x, y++);
366 }
367
368
369 static void vputrow(int x, int y, int depth, char *buff)
370 {
371 while (depth-- > 0)
372 clip_putcolor(x, y++, (BYTE)(*buff++));
373 }
374
375
376 static void fillrect(int x, int y, int width, int depth, int color)
377 {
378 while (depth-- > 0)
379 hline(x, y++, width, color);
380 }
381
382
383 static void rect(int x, int y, int width, int depth, int color)
384 {
385 hline(x, y, width, color);
386 hline(x, y+depth-1, width, color);
387
388 vline(x, y, depth, color);
389 vline(x+width-1, y, depth, color);
390 }
391
392
393 void displayc(int x, int y, int fg, int bg, int ch)
394 {
395 int xc, yc;
396 BYTE t;
397 BYTE far *ptr;
398
399 if( font8x8 == NULL)
400 if ( (font8x8 = findfont(0)) == NULL )
401 return ;
402
403 ptr = ((BYTE far *)font8x8) + ch*FONT_DEPTH;
404
405 for (yc=0; yc<FONT_DEPTH; yc++, y++, ++ptr)
406 {
407 for (xc=0, t= *ptr; xc<8; xc++, t<<=1)
408 line_buff[xc] = (BYTE)((t&0x80) ? fg : bg);
409 putrow(x, y, 8, (char *)line_buff);
410 }
411 }
412
413
414 #ifndef USE_VARARGS
415 static void displayf(int x, int y, int fg, int bg, char *format, ...)
419 #endif
420 {
421 char buff[81];
422 int ctr;
423
424 va_list arg_list;
425
426 #ifndef USE_VARARGS
427 va_start(arg_list, format);
438 #endif
439 vsprintf(buff, format, arg_list);
440 va_end(arg_list);
441
442 for(ctr=0; buff[ctr]!='\0'; ctr++, x+=8)
443 displayc(x, y, fg, bg, buff[ctr]);
444 }
445
446
447 /*
448 * create smooth shades between two colors
449 */
450
451
452 static void mkpalrange(PALENTRY *p1, PALENTRY *p2, PALENTRY pal[], int num, int skip)
453 {
454 int curr;
455 double rm = (double)((int) p2->red - (int) p1->red ) / num,
456 gm = (double)((int) p2->green - (int) p1->green) / num,
457 bm = (double)((int) p2->blue - (int) p1->blue ) / num;
458
459 for (curr=0; curr<num; curr+=skip)
460 {
461 if (gamma_val == 1)
462 {
463 pal[curr].red = (BYTE)((p1->red == p2->red ) ? p1->red :
464 (int) p1->red + (int) ( rm * curr ));
465 pal[curr].green = (BYTE)((p1->green == p2->green) ? p1->green :
466 (int) p1->green + (int) ( gm * curr ));
467 pal[curr].blue = (BYTE)((p1->blue == p2->blue ) ? p1->blue :
468 (int) p1->blue + (int) ( bm * curr ));
469 }
470 else
471 {
472 pal[curr].red = (BYTE)((p1->red == p2->red ) ? p1->red :
473 (int) (p1->red + pow(curr/(double)(num-1),gamma_val)*num*rm));
474 pal[curr].green = (BYTE)((p1->green == p2->green) ? p1->green :
475 (int) (p1->green + pow(curr/(double)(num-1),gamma_val)*num*gm));
476 pal[curr].blue = (BYTE)((p1->blue == p2->blue ) ? p1->blue :
477 (int) (p1->blue + pow(curr/(double)(num-1),gamma_val)*num*bm));
478 }
479 }
480 }
481
482
483
484 /* Swap RG GB & RB columns */
485
486 static void rotcolrg(PALENTRY pal[], int num)
487 {
488 int curr;
489 int dummy;
490
491 for (curr=0; curr<=num; curr++)
492 {
493 dummy = pal[curr].red;
494 pal[curr].red = pal[curr].green;
495 pal[curr].green = (BYTE)dummy;
496 }
497 }
498
499
500 static void rotcolgb(PALENTRY pal[], int num)
501 {
502 int curr;
503 int dummy;
504
505 for (curr=0; curr<=num; curr++)
506 {
507 dummy = pal[curr].green;
508 pal[curr].green = pal[curr].blue;
509 pal[curr].blue = (BYTE)dummy;
510 }
511 }
512
513 static void rotcolbr(PALENTRY pal[], int num)
514 {
515 int curr;
516 int dummy;
517
518 for (curr=0; curr<=num; curr++)
519 {
520 dummy = pal[curr].red;
521 pal[curr].red = pal[curr].blue;
522 pal[curr].blue = (BYTE)dummy;
523 }
524 }
525
526
527 /*
528 * convert a range of colors to grey scale
529 */
530
531
532 static void palrangetogrey(PALENTRY pal[], int first, int how_many)
533 {
534 PALENTRY *curr;
535 BYTE val;
536
537
538 for (curr = &pal[first]; how_many>0; how_many--, curr++)
539 {
540 val = (BYTE) ( ((int)curr->red*30 + (int)curr->green*59 + (int)curr->blue*11) / 100 );
541 curr->red = curr->green = curr->blue = (BYTE)val;
542 }
543 }
544
545 /*
546 * convert a range of colors to their inverse
547 */
548
549
550 static void palrangetonegative(PALENTRY pal[], int first, int how_many)
551 {
552 PALENTRY *curr;
553
554 for (curr = &pal[first]; how_many>0; how_many--, curr++)
555 {
556 curr->red = (BYTE)(63 - curr->red);
557 curr->green = (BYTE)(63 - curr->green);
558 curr->blue = (BYTE)(63 - curr->blue);
559 }
560 }
561
562
563 /*
564 * draw and horizontal/vertical dotted lines
565 */
566
567
568 static void hdline(int x, int y, int width)
569 {
570 int ctr;
571 BYTE *ptr;
572
573 for (ctr=0, ptr=line_buff; ctr<width; ctr++, ptr++)
574 *ptr = (BYTE)((ctr&2) ? bg_color : fg_color);
575
576 putrow(x, y, width, (char *)line_buff);
577 }
578
579
580 static void vdline(int x, int y, int depth)
581 {
582 int ctr;
583
584 for (ctr=0; ctr<depth; ctr++, y++)
585 clip_putcolor(x, y, (ctr&2) ? bg_color : fg_color);
586 }
587
588
589 static void drect(int x, int y, int width, int depth)
590 {
591 hdline(x, y, width);
592 hdline(x, y+depth-1, width);
593
594 vdline(x, y, depth);
595 vdline(x+width-1, y, depth);
596 }
597
598
599 /*
600 * A very simple memory "allocator".
601 *
602 * Each call to mem_alloc() returns size bytes from the array mem_block.
603 *
604 * Be sure to call mem_init() before using mem_alloc()!
605 *
606 */
607
608 static char *mem_block;
609 static unsigned mem_avail;
610
611
612 void mem_init(VOIDPTR block, unsigned size)
613 {
614 mem_block = (char *)block;
615 mem_avail = size;
616 }
617
618
619 VOIDPTR mem_alloc(unsigned size)
620 {
621 VOIDPTR block;
622
623 #ifndef XFRACT
624 if (size & 1)
625 ++size; /* allocate even sizes */
628 #endif
629
630 if (mem_avail < size) /* don't let this happen! */
631 {
632 static FCODE msg[] = "editpal.c: Out of memory!\n";
633
634 stopmsg(0, msg);
635 exit(1);
636 }
637
638 block = mem_block;
639 mem_avail -= size;
640 mem_block += size;
641
642 return(block);
643 }
644
645
646
647 /*
648 * misc. routines
649 *
650 */
651
652
653 static BOOLEAN is_reserved(int color)
654 {
655 return ((BOOLEAN) ((reserve_colors && (color==(int)fg_color || color==(int)bg_color) ) ? TRUE : FALSE) );
656 }
657
658
659
660 static BOOLEAN is_in_box(int x, int y, int bx, int by, int bw, int bd)
661 {
662 return ((BOOLEAN) ((x >= bx) && (y >= by) && (x < bx+bw) && (y < by+bd)) );
663 }
664
665
666
667 static void draw_diamond(int x, int y, int color)
668 {
669 putcolor (x+2, y+0, color);
670 hline (x+1, y+1, 3, color);
671 hline (x+0, y+2, 5, color);
672 hline (x+1, y+3, 3, color);
673 putcolor (x+2, y+4, color);
674 }
675
676
677
678 /*
679 * Class: Cursor
680 *
681 * Purpose: Draw the blinking cross-hair cursor.
682 *
683 * Note: Only one Cursor can exist (referenced through the_cursor).
684 * IMPORTANT: Call Cursor_Construct before you use any other
685 * Cursor_ function! Call Cursor_Destroy before exiting to
686 * deallocate memory.
687 */
688
689 struct _Cursor
690 {
691
692 int x, y;
693 int hidden; /* >0 if mouse hidden */
694 long last_blink;
695 BOOLEAN blink;
696 #if 0
701 #endif
702 char t[CURSOR_SIZE]; /* save line segments here */
703 char b[CURSOR_SIZE];
704 char l[CURSOR_SIZE];
705 char r[CURSOR_SIZE];
706 } ;
707
708 #define Cursor struct _Cursor
709
710 /* private: */
711
712 static void Cursor__Draw (void);
713 static void Cursor__Save (void);
714 static void Cursor__Restore (void);
715
716 /* public: */
717 #ifdef NOT_USED
719 #endif
720
721
722
723 static Cursor *the_cursor = NULL;
724
725
726 BOOLEAN Cursor_Construct(void)
727 {
728 if (the_cursor != NULL)
729 return(FALSE);
730
731 the_cursor = new(Cursor);
732
733 the_cursor->x = sxdots/2;
734 the_cursor->y = sydots/2;
735 the_cursor->hidden = 1;
736 the_cursor->blink = FALSE;
737 the_cursor->last_blink = 0;
738
739 return (TRUE);
740 }
741
742
743 void Cursor_Destroy(void)
744 {
745 if (the_cursor != NULL)
746 delete(the_cursor);
747
748 the_cursor = NULL;
749 }
750
751
752
753 static void Cursor__Draw(void)
754 {
755 int color;
756
757 find_special_colors();
758 color = (the_cursor->blink) ? color_medium : color_dark;
759
760 vline(the_cursor->x, the_cursor->y-CURSOR_SIZE-1, CURSOR_SIZE, color);
761 vline(the_cursor->x, the_cursor->y+2, CURSOR_SIZE, color);
762
763 hline(the_cursor->x-CURSOR_SIZE-1, the_cursor->y, CURSOR_SIZE, color);
764 hline(the_cursor->x+2, the_cursor->y, CURSOR_SIZE, color);
765 }
766
767
768 static void Cursor__Save(void)
769 {
770 vgetrow(the_cursor->x, the_cursor->y-CURSOR_SIZE-1, CURSOR_SIZE, the_cursor->t);
771 vgetrow(the_cursor->x, the_cursor->y+2, CURSOR_SIZE, the_cursor->b);
772
773 getrow(the_cursor->x-CURSOR_SIZE-1, the_cursor->y, CURSOR_SIZE, the_cursor->l);
774 getrow(the_cursor->x+2, the_cursor->y, CURSOR_SIZE, the_cursor->r);
775 }
776
777
778 static void Cursor__Restore(void)
779 {
780 vputrow(the_cursor->x, the_cursor->y-CURSOR_SIZE-1, CURSOR_SIZE, the_cursor->t);
781 vputrow(the_cursor->x, the_cursor->y+2, CURSOR_SIZE, the_cursor->b);
782
783 putrow(the_cursor->x-CURSOR_SIZE-1, the_cursor->y, CURSOR_SIZE, the_cursor->l);
784 putrow(the_cursor->x+2, the_cursor->y, CURSOR_SIZE, the_cursor->r);
785 }
786
787
788
789 void Cursor_SetPos(int x, int y)
790 {
791 if (!the_cursor->hidden)
792 Cursor__Restore();
793
794 the_cursor->x = x;
795 the_cursor->y = y;
796
797 if (!the_cursor->hidden)
798 {
799 Cursor__Save();
800 Cursor__Draw();
801 }
802 }
803
804 #ifdef NOT_USED
812 #endif
813
814
815 void Cursor_Move(int xoff, int yoff)
816 {
817 if ( !the_cursor->hidden )
818 Cursor__Restore();
819
820 the_cursor->x += xoff;
821 the_cursor->y += yoff;
822
823 if (the_cursor->x < 0) the_cursor->x = 0;
824 if (the_cursor->y < 0) the_cursor->y = 0;
825 if (the_cursor->x >= sxdots) the_cursor->x = sxdots-1;
826 if (the_cursor->y >= sydots) the_cursor->y = sydots-1;
827
828 if ( !the_cursor->hidden )
829 {
830 Cursor__Save();
831 Cursor__Draw();
832 }
833 }
834
835
836 int Cursor_GetX(void) { return(the_cursor->x); }
837
838 int Cursor_GetY(void) { return(the_cursor->y); }
839
840
841 void Cursor_Hide(void)
842 {
843 if ( the_cursor->hidden++ == 0 )
844 Cursor__Restore();
845 }
846
847
848 void Cursor_Show(void)
849 {
850 if ( --the_cursor->hidden == 0)
851 {
852 Cursor__Save();
853 Cursor__Draw();
854 }
855 }
856
857 #ifdef XFRACT
858 void Cursor_StartMouseTracking()
859 {
860 editpal_cursor = 1;
861 }
862
863 void Cursor_EndMouseTracking()
864 {
865 editpal_cursor = 0;
866 } 867 #endif
868
869 /* See if the cursor should blink yet, and blink it if so */
870 void Cursor_CheckBlink(void)
871 {
872 long tick;
873 tick = readticker();
874
875 if ( (tick - the_cursor->last_blink) > CURSOR_BLINK_RATE )
876 {
877 the_cursor->blink = (BOOLEAN)((the_cursor->blink) ? FALSE : TRUE);
878 the_cursor->last_blink = tick;
879 if ( !the_cursor->hidden )
880 Cursor__Draw();
881 }
882 else if ( tick < the_cursor->last_blink )
883 the_cursor->last_blink = tick;
884 }
885
886 int Cursor_WaitKey(void) /* blink cursor while waiting for a key */
887 {
888
889 #ifndef XFRACT
890 while ( !keypressed() ) {
891 Cursor_CheckBlink();
892 }
897 #endif
898
899 return( keypressed() );
900 }
901
902
903
904 /*
905 * Class: MoveBox
906 *
907 * Purpose: Handles the rectangular move/resize box.
908 */
909
910 struct _MoveBox
911 {
912 int x, y;
913 int base_width,
914 base_depth;
915 int csize;
916 BOOLEAN moved;
917 BOOLEAN should_hide;
918 char *t, *b,
919 *l, *r;
920 } ;
921
922 #define MoveBox struct _MoveBox
923
924 /* private: */
925
926 static void MoveBox__Draw (MoveBox *this);
927 static void MoveBox__Erase (MoveBox *this);
928 static void MoveBox__Move (MoveBox *this, int key);
929
930 /* public: */
931
932 static MoveBox *MoveBox_Construct (int x, int y, int csize, int base_width,
933 int base_depth);
934 static void MoveBox_Destroy (MoveBox *this);
935 static BOOLEAN MoveBox_Process (MoveBox *this); /* returns FALSE if ESCAPED */
936 static BOOLEAN MoveBox_Moved (MoveBox *this);
937 static BOOLEAN MoveBox_ShouldHide (MoveBox *this);
938 static int MoveBox_X (MoveBox *this);
939 static int MoveBox_Y (MoveBox *this);
940 static int MoveBox_CSize (MoveBox *this);
941
942 static void MoveBox_SetPos (MoveBox *this, int x, int y);
943 static void MoveBox_SetCSize (MoveBox *this, int csize);
944
945
946
947 static MoveBox *MoveBox_Construct(int x, int y, int csize, int base_width, int base_depth)
948 {
949 MoveBox *this = new(MoveBox);
950
951 this->x = x;
952 this->y = y;
953 this->csize = csize;
954 this->base_width = base_width;
955 this->base_depth = base_depth;
956 this->moved = FALSE;
957 this->should_hide = FALSE;
958 this->t = newx(sxdots);
959 this->b = newx(sxdots);
960 this->l = newx(sydots);
961 this->r = newx(sydots);
962
963 return(this);
964 }
965
966
967 static void MoveBox_Destroy(MoveBox *this)
968 {
969 delete(this->t);
970 delete(this->b);
971 delete(this->l);
972 delete(this->r);
973 delete(this);
974 }
975
976
977 static BOOLEAN MoveBox_Moved(MoveBox *this) { return(this->moved); }
978
979 static BOOLEAN MoveBox_ShouldHide(MoveBox *this) { return(this->should_hide); }
980
981 static int MoveBox_X(MoveBox *this) { return(this->x); }
982
983 static int MoveBox_Y(MoveBox *this) { return(this->y); }
984
985 static int MoveBox_CSize(MoveBox *this) { return(this->csize); }
986
987
988 static void MoveBox_SetPos(MoveBox *this, int x, int y)
989 {
990 this->x = x;
991 this->y = y;
992 }
993
994
995 static void MoveBox_SetCSize(MoveBox *this, int csize)
996 {
997 this->csize = csize;
998 }
999
1000
1001 static void MoveBox__Draw(MoveBox *this) /* private */
1002 {
1003 int width = this->base_width + this->csize*16+1,
1004 depth = this->base_depth + this->csize*16+1;
1005 int x = this->x,
1006 y = this->y;
1007
1008
1009 getrow (x, y, width, this->t);
1010 getrow (x, y+depth-1, width, this->b);
1011
1012 vgetrow(x, y, depth, this->l);
1013 vgetrow(x+width-1, y, depth, this->r);
1014
1015 hdline(x, y, width);
1016 hdline(x, y+depth-1, width);
1017
1018 vdline(x, y, depth);
1019 vdline(x+width-1, y, depth);
1020 }
1021
1022
1023 static void MoveBox__Erase(MoveBox *this) /* private */
1024 {
1025 int width = this->base_width + this->csize*16+1,
1026 depth = this->base_depth + this->csize*16+1;
1027
1028 vputrow(this->x, this->y, depth, this->l);
1029 vputrow(this->x+width-1, this->y, depth, this->r);
1030
1031 putrow(this->x, this->y, width, this->t);
1032 putrow(this->x, this->y+depth-1, width, this->b);
1033 }
1034
1035
1036 #define BOX_INC 1
1037 #define CSIZE_INC 2
1038
1039 static void MoveBox__Move(MoveBox *this, int key)
1040 {
1041 BOOLEAN done = FALSE;
1042 BOOLEAN first = TRUE;
1043 int xoff = 0,
1044 yoff = 0;
1045
1046 while ( !done )
1047 {
1048 switch(key)
1049 {
1050 case RIGHT_ARROW_2: xoff += BOX_INC*4; break;
1051 case RIGHT_ARROW: xoff += BOX_INC; break;
1052 case LEFT_ARROW_2: xoff -= BOX_INC*4; break;
1053 case LEFT_ARROW: xoff -= BOX_INC; break;
1054 case DOWN_ARROW_2: yoff += BOX_INC*4; break;
1055 case DOWN_ARROW: yoff += BOX_INC; break;
1056 case UP_ARROW_2: yoff -= BOX_INC*4; break;
1057 case UP_ARROW: yoff -= BOX_INC; break;
1058
1059 default:
1060 done = TRUE;
1061 }
1062
1063 if (!done)
1064 {
1065 if (!first)
1066 getakey(); /* delete key from buffer */
1067 else
1068 first = FALSE;
1069 key = keypressed(); /* peek at the next one... */
1070 }
1071 }
1072
1073 xoff += this->x;
1074 yoff += this->y; /* (xoff,yoff) = new position */
1075
1076 if (xoff < 0) xoff = 0;
1077 if (yoff < 0) yoff = 0;
1078
1079 if (xoff+this->base_width+this->csize*16+1 > sxdots)
1080 xoff = sxdots - (this->base_width+this->csize*16+1);
1081
1082 if (yoff+this->base_depth+this->csize*16+1 > sydots)
1083 yoff = sydots - (this->base_depth+this->csize*16+1);
1084
1085 if ( xoff!=this->x || yoff!=this->y )
1086 {
1087 MoveBox__Erase(this);
1088 this->y = yoff;
1089 this->x = xoff;
1090 MoveBox__Draw(this);
1091 }
1092 }
1093
1094
1095 static BOOLEAN MoveBox_Process(MoveBox *this)
1096 {
1097 int key;
1098 int orig_x = this->x,
1099 orig_y = this->y,
1100 orig_csize = this->csize;
1101
1102 MoveBox__Draw(this);
1103
1104 #ifdef XFRACT
1105 Cursor_StartMouseTracking(); 1106 #endif
1107 for(;;)
1108 {
1109 Cursor_WaitKey();
1110 key = getakey();
1111
1112 if (key==ENTER || key==ENTER_2 || key==ESC || key=='H' || key=='h')
1113 {
1114 if (this->x != orig_x || this->y != orig_y || this->csize != orig_csize)
1115 this->moved = TRUE;
1116 else
1117 this->moved = FALSE;
1118 break;
1119 }
1120
1121 switch(key)
1122 {
1123 case UP_ARROW:
1124 case DOWN_ARROW:
1125 case LEFT_ARROW:
1126 case RIGHT_ARROW:
1127 case UP_ARROW_2:
1128 case DOWN_ARROW_2:
1129 case LEFT_ARROW_2:
1130 case RIGHT_ARROW_2:
1131 MoveBox__Move(this, key);
1132 break;
1133
1134 case PAGE_UP: /* shrink */
1135 if (this->csize > CSIZE_MIN)
1136 {
1137 int t = this->csize - CSIZE_INC;
1138 int change;
1139
1140 if (t < CSIZE_MIN)
1141 t = CSIZE_MIN;
1142
1143 MoveBox__Erase(this);
1144
1145 change = this->csize - t;
1146 this->csize = t;
1147 this->x += (change*16) / 2;
1148 this->y += (change*16) / 2;
1149 MoveBox__Draw(this);
1150 }
1151 break;
1152
1153 case PAGE_DOWN: /* grow */
1154 {
1155 int max_width = min(sxdots, MAX_WIDTH);
1156
1157 if (this->base_depth+(this->csize+CSIZE_INC)*16+1 < sydots &&
1158 this->base_width+(this->csize+CSIZE_INC)*16+1 < max_width )
1159 {
1160 MoveBox__Erase(this);
1161 this->x -= (CSIZE_INC*16) / 2;
1162 this->y -= (CSIZE_INC*16) / 2;
1163 this->csize += CSIZE_INC;
1164 if (this->y+this->base_depth+this->csize*16+1 > sydots)
1165 this->y = sydots - (this->base_depth+this->csize*16+1);
1166 if (this->x+this->base_width+this->csize*16+1 > max_width)
1167 this->x = max_width - (this->base_width+this->csize*16+1);
1168 if (this->y < 0)
1169 this->y = 0;
1170 if (this->x < 0)
1171 this->x = 0;
1172 MoveBox__Draw(this);
1173 }
1174 }
1175 break;
1176 }
1177 }
1178
1179 #ifdef XFRACT
1180 Cursor_EndMouseTracking(); 1181 #endif
1182
1183 MoveBox__Erase(this);
1184
1185 this->should_hide = (BOOLEAN)((key == 'H' || key == 'h') ? TRUE : FALSE);
1186
1187 return( (BOOLEAN)((key==ESC) ? FALSE : TRUE) );
1188 }
1189
1190
1191
1192 /*
1193 * Class: CEditor
1194 *
1195 * Purpose: Edits a single color component (R, G or B)
1196 *
1197 * Note: Calls the "other_key" function to process keys it doesn't use.
1198 * The "change" function is called whenever the value is changed
1199 * by the CEditor.
1200 */
1201
1202 struct _CEditor
1203 {
1204 int x, y;
1205 char letter;
1206 int val;
1207 BOOLEAN done;
1208 BOOLEAN hidden;
1209 #ifndef XFRACT
1210 void (*other_key)(int key, struct _CEditor *ce, VOIDPTR info);
1211 void (*change)(struct _CEditor *ce, VOIDPTR info);
1215 #endif
1216 void *info;
1217
1218 } ;
1219
1220 #define CEditor struct _CEditor
1221
1222 /* public: */
1223
1224 #ifndef XFRACT
1225 static CEditor *CEditor_Construct( int x, int y, char letter,
1226 void (*other_key)(int,CEditor*,void*),
1227 void (*change)(CEditor*,void*), VOIDPTR info);
1228 static void CEditor_Destroy (CEditor *this);
1229 static void CEditor_Draw (CEditor *this);
1230 static void CEditor_SetPos (CEditor *this, int x, int y);
1231 static void CEditor_SetVal (CEditor *this, int val);
1232 static int CEditor_GetVal (CEditor *this);
1233 static void CEditor_SetDone (CEditor *this, BOOLEAN done);
1234 static void CEditor_SetHidden (CEditor *this, BOOLEAN hidden);
1235 static int CEditor_Edit (CEditor *this);
1236 #else
1237 static CEditor *CEditor_Construct( int , int , char ,
1238 void (*other_key)(),
1239 void (*change)(), VOIDPTR );
1240 static void CEditor_Destroy (CEditor *);
1241 static void CEditor_Draw (CEditor *);
1242 static void CEditor_SetPos (CEditor *, int , int );
1243 static void CEditor_SetVal (CEditor *, int );
1244 static int CEditor_GetVal (CEditor *);
1245 static void CEditor_SetDone (CEditor *, BOOLEAN );
1246 static void CEditor_SetHidden (CEditor *, BOOLEAN );
1247 static int CEditor_Edit (CEditor *); 1248 #endif
1249
1250 #define CEditor_WIDTH (8*3+4)
1251 #define CEditor_DEPTH (8+4)
1252
1253
1254
1255 #ifndef XFRACT
1256 static CEditor *CEditor_Construct( int x, int y, char letter,
1257 void (*other_key)(int,CEditor*,VOIDPTR),
1258 void (*change)(CEditor*, VOIDPTR), VOIDPTR info)
1263 #endif
1264 {
1265 CEditor *this = new(CEditor);
1266
1267 this->x = x;
1268 this->y = y;
1269 this->letter = letter;
1270 this->val = 0;
1271 this->other_key = other_key;
1272 this->hidden = FALSE;
1273 this->change = change;
1274 this->info = info;
1275
1276 return(this);
1277 }
1278
1279 #ifdef __TURBOC__
1280 # pragma argsused /* kills "arg not used" warning */ 1281 #endif
1282 #ifdef __CLINT__
1283 # pragma argsused /* kills "arg not used" warning */ 1284 #endif
1285
1286 static void CEditor_Destroy(CEditor *this)
1287 {
1288 delete(this);
1289 }
1290
1291
1292 static void CEditor_Draw(CEditor *this)
1293 {
1294 if (this->hidden)
1295 return;
1296
1297 Cursor_Hide();
1298 displayf(this->x+2, this->y+2, fg_color, bg_color, "%c%02d", this->letter, this->val);
1299 Cursor_Show();
1300 }
1301
1302
1303 static void CEditor_SetPos(CEditor *this, int x, int y)
1304 {
1305 this->x = x;
1306 this->y = y;
1307 }
1308
1309
1310 static void CEditor_SetVal(CEditor *this, int val)
1311 {
1312 this->val = val;
1313 }
1314
1315
1316 static int CEditor_GetVal(CEditor *this)
1317 {
1318 return(this->val);
1319 }
1320
1321
1322 static void CEditor_SetDone(CEditor *this, BOOLEAN done)
1323 {
1324 this->done = done;
1325 }
1326
1327
1328 static void CEditor_SetHidden(CEditor *this, BOOLEAN hidden)
1329 {
1330 this->hidden = hidden;
1331 }
1332
1333
1334 static int CEditor_Edit(CEditor *this)
1335 {
1336 int key = 0;
1337 int diff;
1338
1339 this->done = FALSE;
1340
1341 if (!this->hidden)
1342 {
1343 Cursor_Hide();
1344 rect(this->x, this->y, CEditor_WIDTH, CEditor_DEPTH, fg_color);
1345 Cursor_Show();
1346 }
1347
1348 #ifdef XFRACT
1349 Cursor_StartMouseTracking(); 1350 #endif
1351 while ( !this->done )
1352 {
1353 Cursor_WaitKey();
1354 key = getakey();
1355
1356 switch( key )
1357 {
1358 case PAGE_UP:
1359 if (this->val < 63)
1360 {
1361 this->val += 5;
1362 if (this->val > 63)
1363 this->val = 63;
1364 CEditor_Draw(this);
1365 this->change(this, this->info);
1366 }
1367 break;
1368
1369 case '+':
1370 case CTL_PLUS: /*RB*/
1371 diff = 1;
1372 while ( keypressed() == key )
1373 {
1374 getakey();
1375 ++diff;
1376 }
1377 if (this->val < 63)
1378 {
1379 this->val += diff;
1380 if (this->val > 63)
1381 this->val = 63;
1382 CEditor_Draw(this);
1383 this->change(this, this->info);
1384 }
1385 break;
1386
1387 case PAGE_DOWN:
1388 if (this->val > 0)
1389 {
1390 this->val -= 5;
1391 if (this->val < 0)
1392 this->val = 0;
1393 CEditor_Draw(this);
1394 this->change(this, this->info);
1395 } break;
1396
1397 case '-':
1398 case CTL_MINUS: /*RB*/
1399 diff = 1;
1400 while ( keypressed() == key )
1401 {
1402 getakey();
1403 ++diff;
1404 }
1405 if (this->val > 0)
1406 {
1407 this->val -= diff;
1408 if (this->val < 0)
1409 this->val = 0;
1410 CEditor_Draw(this);
1411 this->change(this, this->info);
1412 }
1413 break;
1414
1415 case '0':
1416 case '1':
1417 case '2':
1418 case '3':
1419 case '4':
1420 case '5':
1421 case '6':
1422 case '7':
1423 case '8':
1424 case '9':
1425 this->val = (key - '0') * 10;
1426 if (this->val > 63)
1427 this->val = 63;
1428 CEditor_Draw(this);
1429 this->change(this, this->info);
1430 break;
1431
1432 default:
1433 this->other_key(key, this, this->info);
1434 break;
1435 } /* switch */
1436 } /* while */
1437 #ifdef XFRACT
1438 Cursor_EndMouseTracking(); 1439 #endif
1440
1441 if (!this->hidden)
1442 {
1443 Cursor_Hide();
1444 rect(this->x, this->y, CEditor_WIDTH, CEditor_DEPTH, bg_color);
1445 Cursor_Show();
1446 }
1447
1448 return(key);
1449 }
1450
1451
1452
1453 /*
1454 * Class: RGBEditor
1455 *
1456 * Purpose: Edits a complete color using three CEditors for R, G and B
1457 */
1458
1459 struct _RGBEditor
1460 {
1461 int x, y; /* position */
1462 int curr; /* 0=r, 1=g, 2=b */
1463 int pal; /* palette number */
1464 BOOLEAN done;
1465 BOOLEAN hidden;
1466 CEditor *color[3]; /* color editors 0=r, 1=g, 2=b */
1467 #ifndef XFRACT
1468 void (*other_key)(int key, struct _RGBEditor *e, VOIDPTR info);
1469 void (*change)(struct _RGBEditor *e, VOIDPTR info);
1473 #endif
1474 void *info;
1475 } ;
1476
1477 #define RGBEditor struct _RGBEditor
1478
1479 /* private: */
1480
1481 static void RGBEditor__other_key (int key, CEditor *ceditor, VOIDPTR info);
1482 static void RGBEditor__change (CEditor *ceditor, VOIDPTR info);
1483
1484 /* public: */
1485
1486 #ifndef XFRACT
1487 static RGBEditor *RGBEditor_Construct(int x, int y,
1488 void (*other_key)(int,RGBEditor*,void*),
1489 void (*change)(RGBEditor*,void*), VOIDPTR info);
1494 #endif
1495
1496 static void RGBEditor_Destroy (RGBEditor *this);
1497 static void RGBEditor_SetPos (RGBEditor *this, int x, int y);
1498 static void RGBEditor_SetDone (RGBEditor *this, BOOLEAN done);
1499 static void RGBEditor_SetHidden(RGBEditor *this, BOOLEAN hidden);
1500 static void RGBEditor_BlankSampleBox(RGBEditor *this);
1501 static void RGBEditor_Update (RGBEditor *this);
1502 static void RGBEditor_Draw (RGBEditor *this);
1503 static int RGBEditor_Edit (RGBEditor *this);
1504 static void RGBEditor_SetRGB (RGBEditor *this, int pal, PALENTRY *rgb);
1505 static PALENTRY RGBEditor_GetRGB (RGBEditor *this);
1506
1507 #define RGBEditor_WIDTH 62
1508 #define RGBEditor_DEPTH (1+1+CEditor_DEPTH*3-2+2)
1509
1510 #define RGBEditor_BWIDTH ( RGBEditor_WIDTH - (2+CEditor_WIDTH+1 + 2) )
1511 #define RGBEditor_BDEPTH ( RGBEditor_DEPTH - 4 )
1512
1513
1514
1515 #ifndef XFRACT
1516 static RGBEditor *RGBEditor_Construct(int x, int y, void (*other_key)(int,RGBEditor*,void*),
1517 void (*change)(RGBEditor*,void*), VOIDPTR info)
1521 #endif
1522 {
1523 RGBEditor *this = new(RGBEditor);
1524 static FCODE letter[] = "RGB";
1525 int ctr;
1526
1527 for (ctr=0; ctr<3; ctr++)
1528 this->color[ctr] = CEditor_Construct(0, 0, letter[ctr], RGBEditor__other_key,
1529 RGBEditor__change, this);
1530
1531 RGBEditor_SetPos(this, x, y);
1532 this->curr = 0;
1533 this->pal = 1;
1534 this->hidden = FALSE;
1535 this->other_key = other_key;
1536 this->change = change;
1537 this->info = info;
1538
1539 return(this);
1540 }
1541
1542
1543 static void RGBEditor_Destroy(RGBEditor *this)
1544 {
1545 CEditor_Destroy(this->color[0]);
1546 CEditor_Destroy(this->color[1]);
1547 CEditor_Destroy(this->color[2]);
1548 delete(this);
1549 }
1550
1551
1552 static void RGBEditor_SetDone(RGBEditor *this, BOOLEAN done)
1553 {
1554 this->done = done;
1555 }
1556
1557
1558 static void RGBEditor_SetHidden(RGBEditor *this, BOOLEAN hidden)
1559 {
1560 this->hidden = hidden;
1561 CEditor_SetHidden(this->color[0], hidden);
1562 CEditor_SetHidden(this->color[1], hidden);
1563 CEditor_SetHidden(this->color[2], hidden);
1564 }
1565
1566
1567 static void RGBEditor__other_key(int key, CEditor *ceditor, VOIDPTR info) /* private */
1568 {
1569 RGBEditor *this = (RGBEditor *)info;
1570
1571 switch( key )
1572 {
1573 case 'R':
1574 case 'r':
1575 if (this->curr != 0)
1576 {
1577 this->curr = 0;
1578 CEditor_SetDone(ceditor, TRUE);
1579 }
1580 break;
1581
1582 case 'G':
1583 case 'g':
1584 if (this->curr != 1)
1585 {
1586 this->curr = 1;
1587 CEditor_SetDone(ceditor, TRUE);
1588 }
1589 break;
1590
1591 case 'B':
1592 case 'b':
1593 if (this->curr != 2)
1594 {
1595 this->curr = 2;
1596 CEditor_SetDone(ceditor, TRUE);
1597 }
1598 break;
1599
1600 case DELETE: /* move to next CEditor */
1601 case CTL_ENTER_2: /*double click rt mouse also! */
1602 if ( ++this->curr > 2)
1603 this->curr = 0;
1604 CEditor_SetDone(ceditor, TRUE);
1605 break;
1606
1607 case INSERT: /* move to prev CEditor */
1608 if ( --this->curr < 0)
1609 this->curr = 2;
1610 CEditor_SetDone(ceditor, TRUE);
1611 break;
1612
1613 default:
1614 this->other_key(key, this, this->info);
1615 if (this->done)
1616 CEditor_SetDone(ceditor, TRUE);
1617 break;
1618 }
1619 }
1620
1621 #ifdef __TURBOC__
1622 # pragma argsused /* kills "arg not used" warning */ 1623 #endif
1624 #ifdef __CLINT__
1625 # pragma argsused /* kills "arg not used" warning */ 1626 #endif
1627
1628 static void RGBEditor__change(CEditor *ceditor, VOIDPTR info) /* private */
1629 {
1630 RGBEditor *this = (RGBEditor *)info;
1631
1632 ceditor = NULL; /* just for warning */
1633 if ( this->pal < colors && !is_reserved(this->pal) )
1634 setpal(this->pal, CEditor_GetVal(this->color[0]),
1635 CEditor_GetVal(this->color[1]), CEditor_GetVal(this->color[2]));
1636
1637 this->change(this, this->info);
1638 }
1639
1640
1641 static void RGBEditor_SetPos(RGBEditor *this, int x, int y)
1642 {
1643 this->x = x;
1644 this->y = y;
1645
1646 CEditor_SetPos(this->color[0], x+2, y+2);
1647 CEditor_SetPos(this->color[1], x+2, y+2+CEditor_DEPTH-1);
1648 CEditor_SetPos(this->color[2], x+2, y+2+CEditor_DEPTH-1+CEditor_DEPTH-1);
1649 }
1650
1651
1652 static void RGBEditor_BlankSampleBox(RGBEditor *this)
1653 {
1654 if (this->hidden)
1655 return ;
1656
1657 Cursor_Hide();
1658 fillrect(this->x+2+CEditor_WIDTH+1+1, this->y+2+1, RGBEditor_BWIDTH-2, RGBEditor_BDEPTH-2, bg_color);
1659 Cursor_Show();
1660 }
1661
1662
1663 static void RGBEditor_Update(RGBEditor *this)
1664 {
1665 int x1 = this->x+2+CEditor_WIDTH+1+1,
1666 y1 = this->y+2+1;
1667
1668 if (this->hidden)
1669 return ;
1670
1671 Cursor_Hide();
1672
1673 if ( this->pal >= colors )
1674 {
1675 fillrect(x1, y1, RGBEditor_BWIDTH-2, RGBEditor_BDEPTH-2, bg_color);
1676 draw_diamond(x1+(RGBEditor_BWIDTH-5)/2, y1+(RGBEditor_BDEPTH-5)/2, fg_color);
1677 }
1678
1679 else if ( is_reserved(this->pal) )
1680 {
1681 int x2 = x1+RGBEditor_BWIDTH-3,
1682 y2 = y1+RGBEditor_BDEPTH-3;
1683
1684 fillrect(x1, y1, RGBEditor_BWIDTH-2, RGBEditor_BDEPTH-2, bg_color);
1685 draw_line(x1, y1, x2, y2, fg_color);
1686 draw_line(x1, y2, x2, y1, fg_color);
1687 }
1688 else
1689 fillrect(x1, y1, RGBEditor_BWIDTH-2, RGBEditor_BDEPTH-2, this->pal);
1690
1691 CEditor_Draw(this->color[0]);
1692 CEditor_Draw(this->color[1]);
1693 CEditor_Draw(this->color[2]);
1694 Cursor_Show();
1695 }
1696
1697
1698 static void RGBEditor_Draw(RGBEditor *this)
1699 {
1700 if (this->hidden)
1701 return ;
1702
1703 Cursor_Hide();
1704 drect(this->x, this->y, RGBEditor_WIDTH, RGBEditor_DEPTH);
1705 fillrect(this->x+1, this->y+1, RGBEditor_WIDTH-2, RGBEditor_DEPTH-2, bg_color);
1706 rect(this->x+1+CEditor_WIDTH+2, this->y+2, RGBEditor_BWIDTH, RGBEditor_BDEPTH, fg_color);
1707 RGBEditor_Update(this);
1708 Cursor_Show();
1709 }
1710
1711
1712 static int RGBEditor_Edit(RGBEditor *this)
1713 {
1714 int key = 0;
1715
1716 this->done = FALSE;
1717
1718 if (!this->hidden)
1719 {
1720 Cursor_Hide();
1721 rect(this->x, this->y, RGBEditor_WIDTH, RGBEditor_DEPTH, fg_color);
1722 Cursor_Show();
1723 }
1724
1725 while ( !this->done )
1726 key = CEditor_Edit( this->color[this->curr] );
1727
1728 if (!this->hidden)
1729 {
1730 Cursor_Hide();
1731 drect(this->x, this->y, RGBEditor_WIDTH, RGBEditor_DEPTH);
1732 Cursor_Show();
1733 }
1734
1735 return (key);
1736 }
1737
1738
1739 static void RGBEditor_SetRGB(RGBEditor *this, int pal, PALENTRY *rgb)
1740 {
1741 this->pal = pal;
1742 CEditor_SetVal(this->color[0], rgb->red);
1743 CEditor_SetVal(this->color[1], rgb->green);
1744 CEditor_SetVal(this->color[2], rgb->blue);
1745 }
1746
1747
1748 static PALENTRY RGBEditor_GetRGB(RGBEditor *this)
1749 {
1750 PALENTRY pal;
1751
1752 pal.red = (BYTE)CEditor_GetVal(this->color[0]);
1753 pal.green = (BYTE)CEditor_GetVal(this->color[1]);
1754 pal.blue = (BYTE)CEditor_GetVal(this->color[2]);
1755
1756 return(pal);
1757 }
1758
1759
1760
1761 /*
1762 * Class: PalTable
1763 *
1764 * Purpose: This is where it all comes together. Creates the two RGBEditors
1765 * and the palette. Moves the cursor, hides/restores the screen,
1766 * handles (S)hading, (C)opying, e(X)clude mode, the "Y" exclusion
1767 * mode, (Z)oom option, (H)ide palette, rotation, etc.
1768 *
1769 */
1770
1771 /*
1772 enum stored_at_values
1773 {
1774 NOWHERE,
1775 DISK,
1776 MEMORY
1777 } ;
1778 */
1779
1780 /*
1781
1782 Modes:
1783 Auto: "A", " "
1784 Exclusion: "X", "Y", " "
1785 Freestyle: "F", " "
1786 S(t)ripe mode: "T", " "
1787
1788 */
1789
1790
1791
1792 struct _PalTable
1793 {
1794 int x, y;
1795 int csize;
1796 int active; /* which RGBEditor is active (0,1) */
1797 int curr[2];
1798 RGBEditor *rgb[2];
1799 MoveBox *movebox;
1800 BOOLEAN done;
1801 BOOLEAN exclude;
1802 BOOLEAN auto_select;
1803 PALENTRY pal[256];
1804 FILE *undo_file;
1805 BOOLEAN curr_changed;
1806 int num_redo;
1807 int hidden;
1808 int stored_at;
1809 FILE *file;
1810 char far *memory;
1811
1812 PALENTRY far *save_pal[8];
1813
1814
1815 PALENTRY fs_color;
1816 int top,bottom; /* top and bottom colours of freestyle band */
1817 int bandwidth; /*size of freestyle colour band */
1818 BOOLEAN freestyle;
1819 } ;
1820
1821 #define PalTable struct _PalTable
1822
1823 /* private: */
1824
1825 static void PalTable__DrawStatus (PalTable *this, BOOLEAN stripe_mode);
1826 static void PalTable__HlPal (PalTable *this, int pnum, int color);
1827 static void PalTable__Draw (PalTable *this);
1828 static BOOLEAN PalTable__SetCurr (PalTable *this, int which, int curr);
1829 static BOOLEAN PalTable__MemoryAlloc (PalTable *this, long size);
1830 static void PalTable__SaveRect (PalTable *this);
1831 static void PalTable__RestoreRect (PalTable *this);
1832 static void PalTable__SetPos (PalTable *this, int x, int y);
1833 static void PalTable__SetCSize (PalTable *this, int csize);
1834 static int PalTable__GetCursorColor(PalTable *this);
1835 static void PalTable__DoCurs (PalTable *this, int key);
1836 static void PalTable__Rotate (PalTable *this, int dir, int lo, int hi);
1837 static void PalTable__UpdateDAC (PalTable *this);
1838 static void PalTable__other_key (int key, RGBEditor *rgb, VOIDPTR info);
1839 static void PalTable__SaveUndoData(PalTable *this, int first, int last);
1840 static void PalTable__SaveUndoRotate(PalTable *this, int dir, int first, int last);
1841 static void PalTable__UndoProcess (PalTable *this, int delta);
1842 static void PalTable__Undo (PalTable *this);
1843 static void PalTable__Redo (PalTable *this);
1844 static void PalTable__change (RGBEditor *rgb, VOIDPTR info);
1845
1846 /* public: */
1847
1848 static PalTable *PalTable_Construct (void);
1849 static void PalTable_Destroy (PalTable *this);
1850 static void PalTable_Process (PalTable *this);
1851 static void PalTable_SetHidden (PalTable *this, BOOLEAN hidden);
1852 static void PalTable_Hide (PalTable *this, RGBEditor *rgb, BOOLEAN hidden);
1853
1854
1855 #define PalTable_PALX (1)
1856 #define PalTable_PALY (2+RGBEditor_DEPTH+2)
1857
1858 #define UNDO_DATA (1)
1859 #define UNDO_DATA_SINGLE (2)
1860 #define UNDO_ROTATE (3)
1861
1862 /* - Freestyle code - */
1863
1864 static void PalTable__CalcTopBottom(PalTable *this)
1865 {
1866 if (this->curr[this->active] < this->bandwidth )
1867 this->bottom = 0;
1868 else
1869 this->bottom = (this->curr[this->active]) - this->bandwidth;
1870
1871 if (this->curr[this->active] > (255-this->bandwidth) )
1872 this->top = 255;
1873 else
1874 this->top = (this->curr[this->active]) + this->bandwidth;
1875 }
1876
1877 static void PalTable__PutBand(PalTable *this, PALENTRY *pal)
1878 {
1879 int r,b,a;
1880
1881 /* clip top and bottom values to stop them running off the end of the DAC */
1882
1883 PalTable__CalcTopBottom(this);
1884
1885 /* put bands either side of current colour */
1886
1887 a = this->curr[this->active];
1888 b = this->bottom;
1889 r = this->top;
1890
1891 pal[a] = this->fs_color;
1892
1893 if (r != a && a != b)
1894 {
1895 mkpalrange(&pal[a], &pal[r], &pal[a], r-a, 1);
1896 mkpalrange(&pal[b], &pal[a], &pal[b], a-b, 1);
1897 }
1898
1899 }
1900
1901
1902 /* - Undo.Redo code - */
1903
1904
1905 static void PalTable__SaveUndoData(PalTable *this, int first, int last)
1906 {
1907 int num;
1908
1909 if ( this->undo_file == NULL )
1910 return ;
1911
1912 num = (last - first) + 1;
1913
1914 #ifdef DEBUG_UNDO
1916 #endif
1917
1918 fseek(this->undo_file, 0, SEEK_CUR);
1919 if ( num == 1 )
1920 {
1921 putc(UNDO_DATA_SINGLE, this->undo_file);
1922 putc(first, this->undo_file);
1923 fwrite(this->pal+first, 3, 1, this->undo_file);
1924 putw( 1 + 1 + 3 + sizeof(int), this->undo_file);
1925 }
1926 else
1927 {
1928 putc(UNDO_DATA, this->undo_file);
1929 putc(first, this->undo_file);
1930 putc(last, this->undo_file);
1931 fwrite(this->pal+first, 3, num, this->undo_file);
1932 putw(1 + 2 + (num*3) + sizeof(int), this->undo_file);
1933 }
1934
1935 this->num_redo = 0;
1936 }
1937
1938
1939 static void PalTable__SaveUndoRotate(PalTable *this, int dir, int first, int last)
1940 {
1941 if ( this->undo_file == NULL )
1942 return ;
1943
1944 #ifdef DEBUG_UNDO
1946 #endif
1947
1948 fseek(this->undo_file, 0, SEEK_CUR);
1949 putc(UNDO_ROTATE, this->undo_file);
1950 putc(first, this->undo_file);
1951 putc(last, this->undo_file);
1952 putw(dir, this->undo_file);
1953 putw(1 + 2 + sizeof(int), this->undo_file);
1954
1955 this->num_redo = 0;
1956 }
1957
1958
1959 static void PalTable__UndoProcess(PalTable *this, int delta) /* undo/redo common code */
1960 { /* delta = -1 for undo, +1 for redo */
1961 int cmd = getc(this->undo_file);
1962
1963 switch( cmd )
1964 {
1965 case UNDO_DATA:
1966 case UNDO_DATA_SINGLE:
1967 {
1968 int first, last, num;
1969 PALENTRY temp[256];
1970
1971 if ( cmd == UNDO_DATA )
1972 {
1973 first = (unsigned char)getc(this->undo_file);
1974 last = (unsigned char)getc(this->undo_file);
1975 }
1976 else /* UNDO_DATA_SINGLE */
1977 first = last = (unsigned char)getc(this->undo_file);
1978
1979 num = (last - first) + 1;
1980
1981 #ifdef DEBUG_UNDO
1982 mprintf(" Reading DATA from %d to %d", first, last); 1983 #endif
1984
1985 fread(temp, 3, num, this->undo_file);
1986
1987 fseek(this->undo_file, -(num*3), SEEK_CUR); /* go to start of undo/redo data */
1988 fwrite(this->pal+first, 3, num, this->undo_file); /* write redo/undo data */
1989
1990 memmove(this->pal+first, temp, num*3);
1991
1992 PalTable__UpdateDAC(this);
1993
1994 RGBEditor_SetRGB(this->rgb[0], this->curr[0], &(this->pal[this->curr[0]]));
1995 RGBEditor_SetRGB(this->rgb[1], this->curr[1], &(this->pal[this->curr[1]]));
1996 RGBEditor_Update(this->rgb[0]);
1997 RGBEditor_Update(this->rgb[1]);
1998 break;
1999 }
2000
2001 case UNDO_ROTATE:
2002 {
2003 int first = (unsigned char)getc(this->undo_file);
2004 int last = (unsigned char)getc(this->undo_file);
2005 int dir = getw(this->undo_file);
2006
2007 #ifdef DEBUG_UNDO
2008 mprintf(" Reading ROTATE of %d from %d to %d", dir, first, last); 2009 #endif
2010 PalTable__Rotate(this, delta*dir, first, last);
2011 break;
2012 }
2013
2014 default:
2015 #ifdef DEBUG_UNDO
2016 mprintf(" Unknown command: %d", cmd); 2017 #endif
2018 break;
2019 }
2020
2021 fseek(this->undo_file, 0, SEEK_CUR); /* to put us in read mode */
2022 getw(this->undo_file); /* read size */
2023 }
2024
2025
2026 static void PalTable__Undo(PalTable *this)
2027 {
2028 int size;
2029 long pos;
2030
2031 if ( ftell(this->undo_file) <= 0 ) /* at beginning of file? */
2032 { /* nothing to undo -- exit */
2033 return ;
2034 }
2035
2036 fseek(this->undo_file, -(int)sizeof(int), SEEK_CUR); /* go back to get size */
2037
2038 size = getw(this->undo_file);
2039 fseek(this->undo_file, -size, SEEK_CUR); /* go to start of undo */
2040
2041 #ifdef DEBUG_UNDO
2043 #endif
2044
2045 pos = ftell(this->undo_file);
2046
2047 PalTable__UndoProcess(this, -1);
2048
2049 fseek(this->undo_file, pos, SEEK_SET); /* go to start of this block */
2050
2051 ++this->num_redo;
2052 }
2053
2054
2055 static void PalTable__Redo(PalTable *this)
2056 {
2057 if ( this->num_redo <= 0 )
2058 return ;
2059
2060 #ifdef DEBUG_UNDO
2062 #endif
2063
2064 fseek(this->undo_file, 0, SEEK_CUR); /* to make sure we are in "read" mode */
2065 PalTable__UndoProcess(this, 1);
2066
2067 --this->num_redo;
2068 }
2069
2070
2071 /* - everything else - */
2072
2073
2074 #define STATUS_LEN (4)
2075
2076 static void PalTable__DrawStatus(PalTable *this, BOOLEAN stripe_mode)
2077 {
2078 int color, hunds, tens, ones;
2079 int width = 1+(this->csize*16)+1+1;
2080
2081 if ( !this->hidden && ( width - (RGBEditor_WIDTH*2+4) >= STATUS_LEN*8 ) )
2082 {
2083 int x = this->x + 2 + RGBEditor_WIDTH,
2084 y = this->y + PalTable_PALY - 10;
2085 color = PalTable__GetCursorColor(this);
2086 if (color < 0 || color >= colors) /* hmm, the border returns -1 */
2087 color = 0;
2088 Cursor_Hide();
2089
2090 displayc(x+(0*8), y, fg_color, bg_color, (this->auto_select) ? 'A' : 254);
2091 displayc(x+(1*8), y, fg_color, bg_color, (this->exclude==1) ? 'X' :
2092 (this->exclude==2) ? 'Y' : 254);
2093 displayc(x+(2*8), y, fg_color, bg_color, (this->freestyle) ? 'F' : 254);
2094 displayc(x+(3*8), y, fg_color, bg_color, (stripe_mode) ? 'T' : 254);
2095
2096 y = y - 10;
2097 hunds = (int)(color/100);
2098 displayc(x+(0*8), y, fg_color, bg_color, (char)(hunds) + '0' );
2099 tens = (int)((color - (hunds * 100)) / 10);
2100 displayc(x+(1*8), y, fg_color, bg_color, (char)(tens) + '0' );
2101 ones = (int)(color - (hunds * 100) - (tens * 10));
2102 displayc(x+(2*8), y, fg_color, bg_color, (char)(ones) + '0' );
2103
2104 Cursor_Show();
2105 }
2106 }
2107
2108
2109 static void PalTable__HlPal(PalTable *this, int pnum, int color)
2110 {
2111 int x = this->x + PalTable_PALX + (pnum%16)*this->csize,
2112 y = this->y + PalTable_PALY + (pnum/16)*this->csize,
2113 size = this->csize;
2114
2115 if (this->hidden)
2116 return ;
2117
2118 Cursor_Hide();
2119
2120 if (color < 0)
2121 drect(x, y, size+1, size+1);
2122 else
2123 rect(x, y, size+1, size+1, color);
2124
2125 Cursor_Show();
2126 }
2127
2128
2129 static void PalTable__Draw(PalTable *this)
2130 {
2131 int pal;
2132 int xoff, yoff;
2133 int width;
2134
2135 if (this->hidden)
2136 return ;
2137
2138 Cursor_Hide();
2139
2140 width = 1+(this->csize*16)+1+1;
2141
2142 rect(this->x, this->y, width, 2+RGBEditor_DEPTH+2+(this->csize*16)+1+1, fg_color);
2143
2144 fillrect(this->x+1, this->y+1, width-2, 2+RGBEditor_DEPTH+2+(this->csize*16)+1+1-2, bg_color);
2145
2146 hline(this->x, this->y+PalTable_PALY-1, width, fg_color);
2147
2148 if ( width - (RGBEditor_WIDTH*2+4) >= TITLE_LEN*8 )
2149 {
2150 int center = (width - TITLE_LEN*8) / 2;
2151
2152 displayf(this->x+center, this->y+RGBEditor_DEPTH/2-6, fg_color, bg_color, TITLE);
2153 }
2154
2155 RGBEditor_Draw(this->rgb[0]);
2156 RGBEditor_Draw(this->rgb[1]);
2157
2158 for (pal=0; pal<256; pal++)
2159 {
2160 xoff = PalTable_PALX + (pal%16) * this->csize;
2161 yoff = PalTable_PALY + (pal/16) * this->csize;
2162
2163 if ( pal >= colors )
2164 {
2165 fillrect(this->x + xoff + 1, this->y + yoff + 1, this->csize-1, this->csize-1, bg_color);
2166 draw_diamond(this->x + xoff + this->csize/2 - 1, this->y + yoff + this->csize/2 - 1, fg_color);
2167 }
2168
2169 else if ( is_reserved(pal) )
2170 {
2171 int x1 = this->x + xoff + 1,
2172 y1 = this->y + yoff + 1,
2173 x2 = x1 + this->csize - 2,
2174 y2 = y1 + this->csize - 2;
2175 fillrect(this->x + xoff + 1, this->y + yoff + 1, this->csize-1, this->csize-1, bg_color);
2176 draw_line(x1, y1, x2, y2, fg_color);
2177 draw_line(x1, y2, x2, y1, fg_color);
2178 }
2179 else
2180 fillrect(this->x + xoff + 1, this->y + yoff + 1, this->csize-1, this->csize-1, pal);
2181
2182 }
2183
2184 if (this->active == 0)
2185 {
2186 PalTable__HlPal(this, this->curr[1], -1);
2187 PalTable__HlPal(this, this->curr[0], fg_color);
2188 }
2189 else
2190 {
2191 PalTable__HlPal(this, this->curr[0], -1);
2192 PalTable__HlPal(this, this->curr[1], fg_color);
2193 }
2194
2195 PalTable__DrawStatus(this, FALSE);
2196
2197 Cursor_Show();
2198 }
2199
2200
2201
2202 static BOOLEAN PalTable__SetCurr(PalTable *this, int which, int curr)
2203 {
2204 BOOLEAN redraw = (BOOLEAN)((which < 0) ? TRUE : FALSE);
2205
2206 if ( redraw )
2207 {
2208 which = this->active;
2209 curr = this->curr[which];
2210 }
2211 else
2212 if ( curr == this->curr[which] || curr < 0 )
2213 return (FALSE);
2214
2215 Cursor_Hide();
2216
2217 PalTable__HlPal(this, this->curr[0], bg_color);
2218 PalTable__HlPal(this, this->curr[1], bg_color);
2219 PalTable__HlPal(this, this->top, bg_color);
2220 PalTable__HlPal(this, this->bottom, bg_color);
2221
2222 if ( this->freestyle )
2223 {
2224 this->curr[which] = curr;
2225
2226 PalTable__CalcTopBottom(this);
2227
2228 PalTable__HlPal(this, this->top, -1);
2229 PalTable__HlPal(this, this->bottom, -1);
2230 PalTable__HlPal(this, this->curr[this->active], fg_color);
2231
2232 RGBEditor_SetRGB(this->rgb[which], this->curr[which], &this->fs_color);
2233 RGBEditor_Update(this->rgb[which]);
2234
2235 PalTable__UpdateDAC(this);
2236
2237 Cursor_Show();
2238
2239 return (TRUE);
2240 }
2241
2242 this->curr[which] = curr;
2243
2244 if (this->curr[0] != this->curr[1])
2245 PalTable__HlPal(this, this->curr[this->active==0?1:0], -1);
2246 PalTable__HlPal(this, this->curr[this->active], fg_color);
2247
2248 RGBEditor_SetRGB(this->rgb[which], this->curr[which], &(this->pal[this->curr[which]]));
2249
2250 if (redraw)
2251 {
2252 int other = (which==0) ? 1 : 0;
2253 RGBEditor_SetRGB(this->rgb[other], this->curr[other], &(this->pal[this->curr[other]]));
2254 RGBEditor_Update(this->rgb[0]);
2255 RGBEditor_Update(this->rgb[1]);
2256 }
2257 else
2258 RGBEditor_Update(this->rgb[which]);
2259
2260 if (this->exclude)
2261 PalTable__UpdateDAC(this);
2262
2263 Cursor_Show();
2264
2265 this->curr_changed = FALSE;
2266
2267 return(TRUE);
2268 }
2269
2270
2271 static BOOLEAN PalTable__MemoryAlloc(PalTable *this, long size)
2272 {
2273 char far *temp;
2274
2275 if (debugflag == 420)
2276 {
2277 this->stored_at = NOWHERE;
2278 return (FALSE); /* can't do it */
2279 }
2280 temp = (char far *)farmemalloc(FAR_RESERVE); /* minimum free space */
2281
2282 if (temp == NULL)
2283 {
2284 this->stored_at = NOWHERE;
2285 return (FALSE); /* can't do it */
2286 }
2287
2288 this->memory = (char far *)farmemalloc( size );
2289
2290 farmemfree(temp);
2291
2292 if ( this->memory == NULL )
2293 {
2294 this->stored_at = NOWHERE;
2295 return (FALSE);
2296 }
2297 else
2298 {
2299 this->stored_at = FARMEM;
2300 return (TRUE);
2301 }
2302 }
2303
2304
2305 static void PalTable__SaveRect(PalTable *this)
2306 {
2307 char buff[MAX_WIDTH];
2308 int width = PalTable_PALX + this->csize*16 + 1 + 1,
2309 depth = PalTable_PALY + this->csize*16 + 1 + 1;
2310 int yoff;
2311
2312
2313 /* first, do any de-allocationg */
2314
2315 switch( this->stored_at )
2316 {
2317 case NOWHERE:
2318 break;
2319
2320 case DISK:
2321 break;
2322
2323 case FARMEM:
2324 if (this->memory != NULL)
2325 farmemfree(this->memory);
2326 this->memory = NULL;
2327 break;
2328 } ;
2329
2330 /* allocate space and store the rect */
2331
2332 if ( PalTable__MemoryAlloc(this, (long)width*depth) )
2333 {
2334 char far *ptr = this->memory;
2335 char far *bufptr = buff; /* MSC needs this indirection to get it right */
2336
2337 Cursor_Hide();
2338 for (yoff=0; yoff<depth; yoff++)
2339 {
2340 getrow(this->x, this->y+yoff, width, buff);
2341 hline (this->x, this->y+yoff, width, bg_color);
2342 far_memcpy(ptr,bufptr, width);
2343 ptr = (char far *)normalize(ptr+width);
2344 }
2345 Cursor_Show();
2346 }
2347
2348 else /* to disk */
2349 {
2350 this->stored_at = DISK;
2351
2352 if ( this->file == NULL )
2353 {
2354 this->file = dir_fopen(tempdir,scrnfile, "w+b");
2355 if (this->file == NULL)
2356 {
2357 this->stored_at = NOWHERE;
2358 buzzer(3);
2359 return ;
2360 }
2361 }
2362
2363 rewind(this->file);
2364 Cursor_Hide();
2365 for (yoff=0; yoff<depth; yoff++)
2366 {
2367 getrow(this->x, this->y+yoff, width, buff);
2368 hline (this->x, this->y+yoff, width, bg_color);
2369 if ( fwrite(buff, width, 1, this->file) != 1 )
2370 {
2371 buzzer(3);
2372 break;
2373 }
2374 }
2375 Cursor_Show();
2376 }
2377
2378 }
2379
2380
2381 static void PalTable__RestoreRect(PalTable *this)
2382 {
2383 char buff[MAX_WIDTH];
2384 int width = PalTable_PALX + this->csize*16 + 1 + 1,
2385 depth = PalTable_PALY + this->csize*16 + 1 + 1;
2386 int yoff;
2387
2388 if (this->hidden)
2389 return;
2390
2391 switch ( this->stored_at )
2392 {
2393 case DISK:
2394 rewind(this->file);
2395 Cursor_Hide();
2396 for (yoff=0; yoff<depth; yoff++)
2397 {
2398 if ( fread(buff, width, 1, this->file) != 1 )
2399 {
2400 buzzer(3);
2401 break;
2402 }
2403 putrow(this->x, this->y+yoff, width, buff);
2404 }
2405 Cursor_Show();
2406 break;
2407
2408 case FARMEM:
2409 {
2410 char far *ptr = this->memory;
2411 char far *bufptr = buff; /* MSC needs this indirection to get it right */
2412
2413 Cursor_Hide();
2414 for (yoff=0; yoff<depth; yoff++)
2415 {
2416 far_memcpy(bufptr, ptr, width);
2417 putrow(this->x, this->y+yoff, width, buff);
2418 ptr = (char far *)normalize(ptr+width);
2419 }
2420 Cursor_Show();
2421 break;
2422 }
2423
2424 case NOWHERE:
2425 break;
2426 } /* switch */
2427 }
2428
2429
2430 static void PalTable__SetPos(PalTable *this, int x, int y)
2431 {
2432 int width = PalTable_PALX + this->csize*16 + 1 + 1;
2433
2434 this->x = x;
2435 this->y = y;
2436
2437 RGBEditor_SetPos(this->rgb[0], x+2, y+2);
2438 RGBEditor_SetPos(this->rgb[1], x+width-2-RGBEditor_WIDTH, y+2);
2439 }
2440
2441
2442 static void PalTable__SetCSize(PalTable *this, int csize)
2443 {
2444 this->csize = csize;
2445 PalTable__SetPos(this, this->x, this->y);
2446 }
2447
2448
2449 static int PalTable__GetCursorColor(PalTable *this)
2450 {
2451 int x = Cursor_GetX(),
2452 y = Cursor_GetY(),
2453 size;
2454 int color = getcolor(x, y);
2455
2456 if ( is_reserved(color) )
2457 {
2458 if ( is_in_box(x, y, this->x, this->y, 1+(this->csize*16)+1+1, 2+RGBEditor_DEPTH+2+(this->csize*16)+1+1) )
2459 { /* is the cursor over the editor? */
2460 x -= this->x + PalTable_PALX;
2461 y -= this->y + PalTable_PALY;
2462 size = this->csize;
2463
2464 if (x < 0 || y < 0 || x > size*16 || y > size*16)
2465 return (-1);
2466
2467 if ( x == size*16 )
2468 --x;
2469 if ( y == size*16 )
2470 --y;
2471
2472 return ( (y/size)*16 + x/size );
2473 }
2474 else
2475 return (color);
2476 }
2477
2478 return (color);
2479 }
2480
2481
2482
2483 #define CURS_INC 1
2484
2485 static void PalTable__DoCurs(PalTable *this, int key)
2486 {
2487 BOOLEAN done = FALSE;
2488 BOOLEAN first = TRUE;
2489 int xoff = 0,
2490 yoff = 0;
2491
2492 while ( !done )
2493 {
2494 switch(key)
2495 {
2496 case RIGHT_ARROW_2: xoff += CURS_INC*4; break;
2497 case RIGHT_ARROW: xoff += CURS_INC; break;
2498 case LEFT_ARROW_2: xoff -= CURS_INC*4; break;
2499 case LEFT_ARROW: xoff -= CURS_INC; break;
2500 case DOWN_ARROW_2: yoff += CURS_INC*4; break;
2501 case DOWN_ARROW: yoff += CURS_INC; break;
2502 case UP_ARROW_2: yoff -= CURS_INC*4; break;
2503 case UP_ARROW: yoff -= CURS_INC; break;
2504
2505 default:
2506 done = TRUE;
2507 }
2508
2509 if (!done)
2510 {
2511 if (!first)
2512 getakey(); /* delete key from buffer */
2513 else
2514 first = FALSE;
2515 key = keypressed(); /* peek at the next one... */
2516 }
2517 }
2518
2519 Cursor_Move(xoff, yoff);
2520
2521 if (this->auto_select)
2522 PalTable__SetCurr(this, this->active, PalTable__GetCursorColor(this));
2523 }
2524
2525
2526 #ifdef __TURBOC__
2528 #endif
2529 #ifdef __CLINT__
2531 #endif
2532
2533 static void PalTable__change(RGBEditor *rgb, VOIDPTR info)
2534 {
2535 PalTable *this = (PalTable *)info;
2536 int pnum = this->curr[this->active];
2537
2538 if ( this->freestyle )
2539 {
2540 this->fs_color = RGBEditor_GetRGB(rgb);
2541 PalTable__UpdateDAC(this);
2542 return ;
2543 }
2544
2545 if ( !this->curr_changed )
2546 {
2547 PalTable__SaveUndoData(this, pnum, pnum);
2548 this->curr_changed = TRUE;
2549 }
2550
2551 this->pal[pnum] = RGBEditor_GetRGB(rgb);
2552
2553 if (this->curr[0] == this->curr[1])
2554 {
2555 int other = this->active==0 ? 1 : 0;
2556 PALENTRY color;
2557
2558 color = RGBEditor_GetRGB(this->rgb[this->active]);
2559 RGBEditor_SetRGB(this->rgb[other], this->curr[other], &color);
2560
2561 Cursor_Hide();
2562 RGBEditor_Update(this->rgb[other]);
2563 Cursor_Show();
2564 }
2565
2566 }
2567
2568
2569 static void PalTable__UpdateDAC(PalTable *this)
2570 {
2571 if ( this->exclude )
2572 {
2573 memset(dacbox, 0, 256*3);
2574 if (this->exclude == 1)
2575 {
2576 int a = this->curr[this->active];
2577 memmove(dacbox[a], &this->pal[a], 3);
2578 }
2579 else
2580 {
2581 int a = this->curr[0],
2582 b = this->curr[1];
2583
2584 if (a>b)
2585 {
2586 int t=a;
2587 a=b;
2588 b=t;
2589 }
2590
2591 memmove(dacbox[a], &this->pal[a], 3*(1+(b-a)));
2592 }
2593 }
2594 else
2595 {
2596 memmove(dacbox[0], this->pal, 3*colors);
2597
2598 if ( this->freestyle )
2599 PalTable__PutBand(this, (PALENTRY *)dacbox); /* apply band to dacbox */
2600 }
2601
2602 if ( !this->hidden )
2603 {
2604 if (inverse)
2605 {
2606 memset(dacbox[fg_color], 0, 3); /* dacbox[fg] = (0,0,0) */
2607 memset(dacbox[bg_color], 48, 3); /* dacbox[bg] = (48,48,48) */
2608 }
2609 else
2610 {
2611 memset(dacbox[bg_color], 0, 3); /* dacbox[bg] = (0,0,0) */
2612 memset(dacbox[fg_color], 48, 3); /* dacbox[fg] = (48,48,48) */
2613 }
2614 }
2615
2616 spindac(0,1);
2617 }
2618
2619
2620 static void PalTable__Rotate(PalTable *this, int dir, int lo, int hi)
2621 {
2622
2623 rotatepal(this->pal, dir, lo, hi);
2624
2625 Cursor_Hide();
2626
2627 /* update the DAC. */
2628
2629 PalTable__UpdateDAC(this);
2630
2631 /* update the editors. */
2632
2633 RGBEditor_SetRGB(this->rgb[0], this->curr[0], &(this->pal[this->curr[0]]));
2634 RGBEditor_SetRGB(this->rgb[1], this->curr[1], &(this->pal[this->curr[1]]));
2635 RGBEditor_Update(this->rgb[0]);
2636 RGBEditor_Update(this->rgb[1]);
2637
2638 Cursor_Show();
2639 }
2640
2641
2642 static void PalTable__other_key(int key, RGBEditor *rgb, VOIDPTR info)
2643 {
2644 PalTable *this = (PalTable *)info;
2645
2646 switch(key)
2647 {
2648 case '\\': /* move/resize */
2649 {
2650 if (this->hidden)
2651 break; /* cannot move a hidden pal */
2652 Cursor_Hide();
2653 PalTable__RestoreRect(this);
2654 MoveBox_SetPos(this->movebox, this->x, this->y);
2655 MoveBox_SetCSize(this->movebox, this->csize);
2656 if ( MoveBox_Process(this->movebox) )
2657 {
2658 if ( MoveBox_ShouldHide(this->movebox) )
2659 PalTable_SetHidden(this, TRUE);
2660 else if ( MoveBox_Moved(this->movebox) )
2661 {
2662 PalTable__SetPos(this, MoveBox_X(this->movebox), MoveBox_Y(this->movebox));
2663 PalTable__SetCSize(this, MoveBox_CSize(this->movebox));
2664 PalTable__SaveRect(this);
2665 }
2666 }
2667 PalTable__Draw(this);
2668 Cursor_Show();
2669
2670 RGBEditor_SetDone(this->rgb[this->active], TRUE);
2671
2672 if (this->auto_select)
2673 PalTable__SetCurr(this, this->active, PalTable__GetCursorColor(this));
2674 break;
2675 }
2676
2677 case 'Y': /* exclude range */
2678 case 'y':
2679 if ( this->exclude==2 )
2680 this->exclude = 0;
2681 else
2682 this->exclude = 2;
2683 PalTable__UpdateDAC(this);
2684 break;
2685
2686 case 'X':
2687 case 'x': /* exclude current entry */
2688 if ( this->exclude==1 )
2689 this->exclude = 0;
2690 else
2691 this->exclude = 1;
2692 PalTable__UpdateDAC(this);
2693 break;
2694
2695 case RIGHT_ARROW:
2696 case LEFT_ARROW:
2697 case UP_ARROW:
2698 case DOWN_ARROW:
2699 case RIGHT_ARROW_2:
2700 case LEFT_ARROW_2:
2701 case UP_ARROW_2:
2702 case DOWN_ARROW_2:
2703 PalTable__DoCurs(this, key);
2704 break;
2705
2706 case ESC:
2707 this->done = TRUE;
2708 RGBEditor_SetDone(rgb, TRUE);
2709 break;
2710
2711 case ' ': /* select the other palette register */
2712 this->active = (this->active==0) ? 1 : 0;
2713 if (this->auto_select)
2714 PalTable__SetCurr(this, this->active, PalTable__GetCursorColor(this));
2715 else
2716 PalTable__SetCurr(this, -1, 0);
2717
2718 if (this->exclude || this->freestyle)
2719 PalTable__UpdateDAC(this);
2720
2721 RGBEditor_SetDone(rgb, TRUE);
2722 break;
2723
2724 case ENTER: /* set register to color under cursor. useful when not */
2725 case ENTER_2: /* in auto_select mode */
2726
2727 if ( this->freestyle )
2728 {
2729 PalTable__SaveUndoData(this, this->bottom, this->top);
2730 PalTable__PutBand(this, this->pal);
2731 }
2732
2733 PalTable__SetCurr(this, this->active, PalTable__GetCursorColor(this));
2734
2735 if (this->exclude || this->freestyle )
2736 PalTable__UpdateDAC(this);
2737
2738 RGBEditor_SetDone(rgb, TRUE);
2739 break;
2740
2741 case 'D': /* copy (Duplicate?) color in inactive to color in active */
2742 case 'd':
2743 {
2744 int a = this->active,
2745 b = (a==0) ? 1 : 0;
2746 PALENTRY t;
2747
2748 t = RGBEditor_GetRGB(this->rgb[b]);
2749 Cursor_Hide();
2750
2751 RGBEditor_SetRGB(this->rgb[a], this->curr[a], &t);
2752 RGBEditor_Update(this->rgb[a]);
2753 PalTable__change(this->rgb[a], this);
2754 PalTable__UpdateDAC(this);
2755
2756 Cursor_Show();
2757 break;
2758 }
2759
2760 case '=': /* create a shade range between the two entries */
2761 {
2762 int a = this->curr[0],
2763 b = this->curr[1];
2764
2765 if (a > b)
2766 {
2767 int t = a;
2768 a = b;
2769 b = t;
2770 }
2771
2772 PalTable__SaveUndoData(this, a, b);
2773
2774 if (a != b)
2775 {
2776 mkpalrange(&this->pal[a], &this->pal[b], &this->pal[a], b-a, 1);
2777 PalTable__UpdateDAC(this);
2778 }
2779
2780 break;
2781 }
2782
2783 case '!': /* swap r<->g */
2784 {
2785 int a = this->curr[0],
2786 b = this->curr[1];
2787
2788 if (a > b)
2789 {
2790 int t = a;
2791 a = b;
2792 b = t;
2793 }
2794
2795 PalTable__SaveUndoData(this, a, b);
2796
2797 if (a != b)
2798 {
2799 rotcolrg(&this->pal[a], b-a);
2800 PalTable__UpdateDAC(this);
2801 }
2802
2803
2804 break;
2805 }
2806
2807 case '@': /* swap g<->b */
2808 case '"': /* UK keyboards */
2809 case 151: /* French keyboards */
2810 {
2811 int a = this->curr[0],
2812 b = this->curr[1];
2813
2814 if (a > b)
2815 {
2816 int t = a;
2817 a = b;
2818 b = t;
2819 }
2820
2821 PalTable__SaveUndoData(this, a, b);
2822
2823 if (a != b)
2824 {
2825 rotcolgb(&this->pal[a], b-a);
2826 PalTable__UpdateDAC(this);
2827 }
2828
2829 break;
2830 }
2831
2832 case '#': /* swap r<->b */
2833 case 156: /* UK keyboards (pound sign) */
2834 case '$': /* For French keyboards */
2835 {
2836 int a = this->curr[0],
2837 b = this->curr[1];
2838
2839 if (a > b)
2840 {
2841 int t = a;
2842 a = b;
2843 b = t;
2844 }
2845
2846 PalTable__SaveUndoData(this, a, b);
2847
2848 if (a != b)
2849 {
2850 rotcolbr(&this->pal[a], b-a);
2851 PalTable__UpdateDAC(this);
2852 }
2853
2854 break;
2855 }
2856
2857
2858 case 'T':
2859 case 't': /* s(T)ripe mode */
2860 {
2861 int key;
2862
2863 Cursor_Hide();
2864 PalTable__DrawStatus(this, TRUE);
2865 key = getakeynohelp();
2866 Cursor_Show();
2867
2868 if (key >= '1' && key <= '9')
2869 {
2870 int a = this->curr[0],
2871 b = this->curr[1];
2872
2873 if (a > b)
2874 {
2875 int t = a;
2876 a = b;
2877 b = t;
2878 }
2879
2880 PalTable__SaveUndoData(this, a, b);
2881
2882 if (a != b)
2883 {
2884 mkpalrange(&this->pal[a], &this->pal[b], &this->pal[a], b-a, key-'0');
2885 PalTable__UpdateDAC(this);
2886 }
2887 }
2888
2889 break;
2890 }
2891
2892 case 'M': /* set gamma */
2893 case 'm':
2894 {
2895 static FCODE o_msg[] = {"Enter gamma value"};
2896 char msg[sizeof(o_msg)];
2897 int i;
2898 char buf[20];
2899 far_strcpy(msg,o_msg);
2900 sprintf(buf,"%.3f",1./gamma_val);
2901 stackscreen();
2902 i = field_prompt(0,msg,NULL,buf,20,NULL);
2903 unstackscreen();
2904 if (i != -1) {
2905 sscanf(buf,"%f",&gamma_val);
2906 if (gamma_val==0) {
2907 gamma_val = (float)0.0000000001;
2908 }
2909 gamma_val = (float)(1./gamma_val);
2910 }
2911 }
2912 break;
2913 case 'A': /* toggle auto-select mode */
2914 case 'a':
2915 this->auto_select = (BOOLEAN)((this->auto_select) ? FALSE : TRUE);
2916 if (this->auto_select)
2917 {
2918 PalTable__SetCurr(this, this->active, PalTable__GetCursorColor(this));
2919 if (this->exclude)
2920 PalTable__UpdateDAC(this);
2921 }
2922 break;
2923
2924 case 'H':
2925 case 'h': /* toggle hide/display of palette editor */
2926 Cursor_Hide();
2927 PalTable_Hide(this, rgb, (BOOLEAN)((this->hidden) ? FALSE : TRUE));
2928 Cursor_Show();
2929 break;
2930
2931 case '.': /* rotate once */
2932 case ',':
2933 {
2934 int dir = (key=='.') ? 1 : -1;
2935
2936 PalTable__SaveUndoRotate(this, dir, rotate_lo, rotate_hi);
2937 PalTable__Rotate(this, dir, rotate_lo, rotate_hi);
2938 break;
2939 }
2940
2941 case '>': /* continuous rotation (until a key is pressed) */
2942 case '<':
2943 {
2944 int dir;
2945 long tick;
2946 int diff = 0;
2947
2948 Cursor_Hide();
2949
2950 if ( !this->hidden )
2951 {
2952 RGBEditor_BlankSampleBox(this->rgb[0]);
2953 RGBEditor_BlankSampleBox(this->rgb[1]);
2954 RGBEditor_SetHidden(this->rgb[0], TRUE);
2955 RGBEditor_SetHidden(this->rgb[1], TRUE);
2956 }
2957
2958 do
2959 {
2960 dir = (key=='>') ? 1 : -1;
2961
2962 while ( !keypressed() )
2963 {
2964 tick = readticker();
2965 PalTable__Rotate(this, dir, rotate_lo, rotate_hi);
2966 diff += dir;
2967 while (readticker() == tick) ; /* wait until a tick passes */
2968 }
2969
2970 key = getakey();
2971 }
2972 while (key=='<' || key=='>');
2973
2974 if ( !this->hidden )
2975 {
2976 RGBEditor_SetHidden(this->rgb[0], FALSE);
2977 RGBEditor_SetHidden(this->rgb[1], FALSE);
2978 RGBEditor_Update(this->rgb[0]);
2979 RGBEditor_Update(this->rgb[1]);
2980 }
2981
2982 if ( diff != 0 )
2983 PalTable__SaveUndoRotate(this, diff, rotate_lo, rotate_hi);
2984
2985 Cursor_Show();
2986 break;
2987 }
2988
2989 case 'I': /* invert the fg & bg colors */
2990 case 'i':
2991 inverse = (BOOLEAN)!inverse;
2992 PalTable__UpdateDAC(this);
2993 break;
2994
2995 case 'V':
2996 case 'v': /* set the reserved colors to the editor colors */
2997 if ( this->curr[0] >= colors || this->curr[1] >= colors ||
2998 this->curr[0] == this->curr[1] )
2999 {
3000 buzzer(2);
3001 break;
3002 }
3003
3004 fg_color = (BYTE)this->curr[0];
3005 bg_color = (BYTE)this->curr[1];
3006
3007 if ( !this->hidden )
3008 {
3009 Cursor_Hide();
3010 PalTable__UpdateDAC(this);
3011 PalTable__Draw(this);
3012 Cursor_Show();
3013 }
3014
3015 RGBEditor_SetDone(this->rgb[this->active], TRUE);
3016 break;
3017
3018 case 'O': /* set rotate_lo and rotate_hi to editors */
3019 case 'o':
3020 if (this->curr[0] > this->curr[1])
3021 {
3022 rotate_lo = this->curr[1];
3023 rotate_hi = this->curr[0];
3024 }
3025 else
3026 {
3027 rotate_lo = this->curr[0];
3028 rotate_hi = this->curr[1];
3029 }
3030 break;
3031
3032 case F2: /* restore a palette */
3033 case F3:
3034 case F4:
3035 case F5:
3036 case F6:
3037 case F7:
3038 case F8:
3039 case F9:
3040 {
3041 int which = key - F2;
3042
3043 if ( this->save_pal[which] != NULL )
3044 {
3045 Cursor_Hide();
3046
3047 PalTable__SaveUndoData(this, 0, 255);
3048 far_memcpy(this->pal,this->save_pal[which],256*3);
3049 PalTable__UpdateDAC(this);
3050
3051 PalTable__SetCurr(this, -1, 0);
3052 Cursor_Show();
3053 RGBEditor_SetDone(this->rgb[this->active], TRUE);
3054 }
3055 else
3056 buzzer(3); /* error buzz */
3057 break;
3058 }
3059
3060 case SF2: /* save a palette */
3061 case SF3:
3062 case SF4:
3063 case SF5:
3064 case SF6:
3065 case SF7:
3066 case SF8:
3067 case SF9:
3068 {
3069 int which = key - SF2;
3070
3071 if ( this->save_pal[which] != NULL )
3072 {
3073 far_memcpy(this->save_pal[which],this->pal,256*3);
3074 }
3075 else
3076 buzzer(3); /* oops! short on memory! */
3077 break;
3078 }
3079
3080 case 'L': /* load a .map palette */
3081 case 'l':
3082 {
3083 PalTable__SaveUndoData(this, 0, 255);
3084
3085 load_palette();
3086 #ifndef XFRACT
3087 getpalrange(0, colors, this->pal);
3090 #endif
3091 PalTable__UpdateDAC(this);
3092 RGBEditor_SetRGB(this->rgb[0], this->curr[0], &(this->pal[this->curr[0]]));
3093 RGBEditor_Update(this->rgb[0]);
3094 RGBEditor_SetRGB(this->rgb[1], this->curr[1], &(this->pal[this->curr[1]]));
3095 RGBEditor_Update(this->rgb[1]);
3096 break;
3097 }
3098
3099 case 'S': /* save a .map palette */
3100 case 's':
3101 {
3102 #ifndef XFRACT
3103 setpalrange(0, colors, this->pal);
3106 #endif
3107 save_palette();
3108 PalTable__UpdateDAC(this);
3109 break;
3110 }
3111
3112 case 'C': /* color cycling sub-mode */
3113 case 'c':
3114 {
3115 BOOLEAN oldhidden = (BOOLEAN)this->hidden;
3116
3117 PalTable__SaveUndoData(this, 0, 255);
3118
3119 Cursor_Hide();
3120 if ( !oldhidden )
3121 PalTable_Hide(this, rgb, TRUE);
3122 setpalrange(0, colors, this->pal);
3123 rotate(0);
3124 getpalrange(0, colors, this->pal);
3125 PalTable__UpdateDAC(this);
3126 if ( !oldhidden )
3127 {
3128 RGBEditor_SetRGB(this->rgb[0], this->curr[0], &(this->pal[this->curr[0]]));
3129 RGBEditor_SetRGB(this->rgb[1], this->curr[1], &(this->pal[this->curr[1]]));
3130 PalTable_Hide(this, rgb, FALSE);
3131 }
3132 Cursor_Show();
3133 break;
3134 }
3135
3136 case 'F':
3137 case 'f': /* toggle freestyle palette edit mode */
3138 this->freestyle= (BOOLEAN)((this->freestyle) ? FALSE :TRUE);
3139
3140 PalTable__SetCurr(this, -1, 0);
3141
3142 if ( !this->freestyle ) /* if turning off... */
3143 PalTable__UpdateDAC(this);
3144
3145 break;
3146
3147 case CTL_DEL: /* rt plus down */
3148 if (this->bandwidth >0 )
3149 this->bandwidth --;
3150 else
3151 this->bandwidth=0;
3152 PalTable__SetCurr(this, -1, 0);
3153 break;
3154
3155 case CTL_INSERT: /* rt plus up */
3156 if (this->bandwidth <255 )
3157 this->bandwidth ++;
3158 else
3159 this->bandwidth = 255;
3160 PalTable__SetCurr(this, -1, 0);
3161 break;
3162
3163 case 'W': /* convert to greyscale */
3164 case 'w':
3165 {
3166 switch ( this->exclude )
3167 {
3168 case 0: /* normal mode. convert all colors to grey scale */
3169 PalTable__SaveUndoData(this, 0, 255);
3170 palrangetogrey(this->pal, 0, 256);
3171 break;
3172
3173 case 1: /* 'x' mode. convert current color to grey scale. */
3174 PalTable__SaveUndoData(this, this->curr[this->active], this->curr[this->active]);
3175 palrangetogrey(this->pal, this->curr[this->active], 1);
3176 break;
3177
3178 case 2: /* 'y' mode. convert range between editors to grey. */
3179 {
3180 int a = this->curr[0],
3181 b = this->curr[1];
3182
3183 if (a > b)
3184 {
3185 int t = a;
3186 a = b;
3187 b = t;
3188 }
3189
3190 PalTable__SaveUndoData(this, a, b);
3191 palrangetogrey(this->pal, a, 1+(b-a));
3192 break;
3193 }
3194 }
3195
3196 PalTable__UpdateDAC(this);
3197 RGBEditor_SetRGB(this->rgb[0], this->curr[0], &(this->pal[this->curr[0]]));
3198 RGBEditor_Update(this->rgb[0]);
3199 RGBEditor_SetRGB(this->rgb[1], this->curr[1], &(this->pal[this->curr[1]]));
3200 RGBEditor_Update(this->rgb[1]);
3201 break;
3202 }
3203
3204 case 'N': /* convert to negative color */
3205 case 'n':
3206 {
3207 switch ( this->exclude )
3208 {
3209 case 0: /* normal mode. convert all colors to grey scale */
3210 PalTable__SaveUndoData(this, 0, 255);
3211 palrangetonegative(this->pal, 0, 256);
3212 break;
3213
3214 case 1: /* 'x' mode. convert current color to grey scale. */
3215 PalTable__SaveUndoData(this, this->curr[this->active], this->curr[this->active]);
3216 palrangetonegative(this->pal, this->curr[this->active], 1);
3217 break;
3218
3219 case 2: /* 'y' mode. convert range between editors to grey. */
3220 {
3221 int a = this->curr[0],
3222 b = this->curr[1];
3223
3224 if (a > b)
3225 {
3226 int t = a;
3227 a = b;
3228 b = t;
3229 }
3230
3231 PalTable__SaveUndoData(this, a, b);
3232 palrangetonegative(this->pal, a, 1+(b-a));
3233 break;
3234 }
3235 }
3236
3237 PalTable__UpdateDAC(this);
3238 RGBEditor_SetRGB(this->rgb[0], this->curr[0], &(this->pal[this->curr[0]]));
3239 RGBEditor_Update(this->rgb[0]);
3240 RGBEditor_SetRGB(this->rgb[1], this->curr[1], &(this->pal[this->curr[1]]));
3241 RGBEditor_Update(this->rgb[1]);
3242 break;
3243 }
3244
3245 case 'U': /* Undo */
3246 case 'u':
3247 PalTable__Undo(this);
3248 break;
3249
3250 case 'e': /* Redo */
3251 case 'E':
3252 PalTable__Redo(this);
3253 break;
3254
3255 } /* switch */
3256 PalTable__DrawStatus(this, FALSE);
3257 }
3258
3259 static void PalTable__MkDefaultPalettes(PalTable *this) /* creates default Fkey palettes */
3260 {
3261 int i;
3262 for(i=0; i<8; i++) /* copy original palette to save areas */
3263 {
3264 if (this->save_pal[i] != NULL)
3265 {
3266 far_memcpy(this->save_pal[i], this->pal, 256*3);
3267 }
3268 }
3269 }
3270
3271
3272
3273 static PalTable *PalTable_Construct(void)
3274 {
3275 PalTable *this = new(PalTable);
3276 int csize;
3277 int ctr;
3278 PALENTRY far *mem_block;
3279 void far *temp;
3280
3281 temp = (void far *)farmemalloc(FAR_RESERVE);
3282
3283 if ( temp != NULL )
3284 {
3285 mem_block = (PALENTRY far *)farmemalloc(256L*3 * 8);
3286
3287 if ( mem_block == NULL )
3288 {
3289 for (ctr=0; ctr<8; ctr++)
3290 this->save_pal[ctr] = NULL;
3291 }
3292 else
3293 {
3294 for (ctr=0; ctr<8; ctr++)
3295 this->save_pal[ctr] = mem_block + (256*ctr);
3296 }
3297 farmemfree(temp);
3298 }
3299
3300 this->rgb[0] = RGBEditor_Construct(0, 0, PalTable__other_key,
3301 PalTable__change, this);
3302 this->rgb[1] = RGBEditor_Construct(0, 0, PalTable__other_key,
3303 PalTable__change, this);
3304
3305 this->movebox = MoveBox_Construct(0,0,0, PalTable_PALX+1, PalTable_PALY+1);
3306
3307 this->active = 0;
3308 this->curr[0] = 1;
3309 this->curr[1] = 1;
3310 this->auto_select = TRUE;
3311 this->exclude = FALSE;
3312 this->hidden = FALSE;
3313 this->stored_at = NOWHERE;
3314 this->file = NULL;
3315 this->memory = NULL;
3316
3317 this->fs_color.red = 42;
3318 this->fs_color.green = 42;
3319 this->fs_color.blue = 42;
3320 this->freestyle = FALSE;
3321 this->bandwidth = 15;
3322 this->top = 255;
3323 this->bottom = 0 ;
3324
3325 this->undo_file = dir_fopen(tempdir,undofile, "w+b");
3326 this->curr_changed = FALSE;
3327 this->num_redo = 0;
3328
3329 RGBEditor_SetRGB(this->rgb[0], this->curr[0], &this->pal[this->curr[0]]);
3330 RGBEditor_SetRGB(this->rgb[1], this->curr[1], &this->pal[this->curr[0]]);
3331
3332 if (video_scroll) {
3333 PalTable__SetPos(this, video_startx, video_starty);
3334 csize = ( (vesa_yres-(PalTable_PALY+1+1)) / 2 ) / 16;
3335 } else {
3336 PalTable__SetPos(this, 0, 0);
3337 csize = ( (sydots-(PalTable_PALY+1+1)) / 2 ) / 16;
3338 }
3339
3340 if (csize<CSIZE_MIN)
3341 csize = CSIZE_MIN;
3342 PalTable__SetCSize(this, csize);
3343
3344 return(this);
3345 }
3346
3347
3348 static void PalTable_SetHidden(PalTable *this, BOOLEAN hidden)
3349 {
3350 this->hidden = hidden;
3351 RGBEditor_SetHidden(this->rgb[0], hidden);
3352 RGBEditor_SetHidden(this->rgb[1], hidden);
3353 PalTable__UpdateDAC(this);
3354 }
3355
3356
3357
3358 static void PalTable_Hide(PalTable *this, RGBEditor *rgb, BOOLEAN hidden)
3359 {
3360 if (hidden)
3361 {
3362 PalTable__RestoreRect(this);
3363 PalTable_SetHidden(this, TRUE);
3364 reserve_colors = FALSE;
3365 if (this->auto_select)
3366 PalTable__SetCurr(this, this->active, PalTable__GetCursorColor(this));
3367 }
3368 else
3369 {
3370 PalTable_SetHidden(this, FALSE);
3371 reserve_colors = TRUE;
3372 if (this->stored_at == NOWHERE) /* do we need to save screen? */
3373 PalTable__SaveRect(this);
3374 PalTable__Draw(this);
3375 if (this->auto_select)
3376 PalTable__SetCurr(this, this->active, PalTable__GetCursorColor(this));
3377 RGBEditor_SetDone(rgb, TRUE);
3378 }
3379 }
3380
3381
3382 static void PalTable_Destroy(PalTable *this)
3383 {
3384
3385 if (this->file != NULL)
3386 {
3387 fclose(this->file);
3388 dir_remove(tempdir,scrnfile);
3389 }
3390
3391 if (this->undo_file != NULL)
3392 {
3393 fclose(this->undo_file);
3394 dir_remove(tempdir,undofile);
3395 }
3396
3397 if (this->memory != NULL)
3398 farmemfree(this->memory);
3399
3400 if (this->save_pal[0] != NULL)
3401 farmemfree((BYTE far *)this->save_pal[0]);
3402
3403 RGBEditor_Destroy(this->rgb[0]);
3404 RGBEditor_Destroy(this->rgb[1]);
3405 MoveBox_Destroy(this->movebox);
3406 delete(this);
3407 }
3408
3409
3410 static void PalTable_Process(PalTable *this)
3411 {
3412 int ctr;
3413
3414 getpalrange(0, colors, this->pal);
3415
3416 /* Make sure all palette entries are 0-63 */
3417
3418 for(ctr=0; ctr<768; ctr++)
3419 ((char *)this->pal)[ctr] &= 63;
3420
3421 PalTable__UpdateDAC(this);
3422
3423 RGBEditor_SetRGB(this->rgb[0], this->curr[0], &this->pal[this->curr[0]]);
3424 RGBEditor_SetRGB(this->rgb[1], this->curr[1], &this->pal[this->curr[0]]);
3425
3426 if (!this->hidden)
3427 {
3428 MoveBox_SetPos(this->movebox, this->x, this->y);
3429 MoveBox_SetCSize(this->movebox, this->csize);
3430 if ( !MoveBox_Process(this->movebox) )
3431 {
3432 setpalrange(0, colors, this->pal);
3433 return ;
3434 }
3435
3436 PalTable__SetPos(this, MoveBox_X(this->movebox), MoveBox_Y(this->movebox));
3437 PalTable__SetCSize(this, MoveBox_CSize(this->movebox));
3438
3439 if ( MoveBox_ShouldHide(this->movebox) )
3440 {
3441 PalTable_SetHidden(this, TRUE);
3442 reserve_colors = FALSE; /* <EAN> */
3443 }
3444 else
3445 {
3446 reserve_colors = TRUE; /* <EAN> */
3447 PalTable__SaveRect(this);
3448 PalTable__Draw(this);
3449 }
3450 }
3451
3452 PalTable__SetCurr(this, this->active, PalTable__GetCursorColor(this));
3453 PalTable__SetCurr(this, (this->active==1)?0:1, PalTable__GetCursorColor(this));
3454 Cursor_Show();
3455 PalTable__MkDefaultPalettes(this);
3456 this->done = FALSE;
3457
3458 while ( !this->done )
3459 RGBEditor_Edit(this->rgb[this->active]);
3460
3461 Cursor_Hide();
3462 PalTable__RestoreRect(this);
3463 setpalrange(0, colors, this->pal);
3464 }
3465
3466
3467 /*
3468 * interface to FRACTINT
3469 */
3470
3471
3472
3473 void EditPalette(void) /* called by fractint */
3474 {
3475 int oldlookatmouse = lookatmouse;
3476 int oldsxoffs = sxoffs;
3477 int oldsyoffs = syoffs;
3478 PalTable *pt;
3479
3480 mem_init(strlocn, 10*1024);
3481
3482 if ( (font8x8 = findfont(0)) == NULL )
3483 return ;
3484
3485 if (sxdots < 133 || sydots < 174)
3486 return; /* prevents crash when physical screen is too small */
3487
3488 plot = putcolor;
3489
3490 line_buff = newx(max(sxdots,sydots));
3491
3492 lookatmouse = 3;
3493 sxoffs = syoffs = 0;
3494
3495 reserve_colors = TRUE;
3496 inverse = FALSE;
3497 fg_color = (BYTE)(255%colors);
3498 bg_color = (BYTE)(fg_color-1);
3499
3500 Cursor_Construct();
3501 pt = PalTable_Construct();
3502 PalTable_Process(pt);
3503 PalTable_Destroy(pt);
3504 Cursor_Destroy();
3505
3506 lookatmouse = oldlookatmouse;
3507 sxoffs = oldsxoffs;
3508 syoffs = oldsyoffs;
3509 delete(line_buff);
3510 }
3511