1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
|
xgterm.NOTES -- Some random design notes made while writing this code. Not
intended to be useful to anyone reading this code.
To do:
Object manager
add bitmap support
add event handling support
Gterm widget
add cell array
pixrect operations?
minor odds and ends
Gtermio
modify to use object manager
add messaging capability
GIO
add messaging capability
modify cell array support as needed
Pixmaps
cache by name
new entry replaces old
entries are never freed unless overwritten
for lookup, check cache first then look for file (normal resource
translation)
typical bitmap:
#define opendot_width 16
#define opendot_height 16
#define opendot_x_hot 7
#define opendot_y_hot 7
static char opendot_bits[] = {
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x01,
0x60,0x03,0x20,0x02,0x60,0x03,0xc0,0x01,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
types of bitmaps - bitmap, pixmap, cursor
createBitmap name width height data
createPixmap name width height depth fg_color bg_color data
createCursor name source mask fg_color bg_color x_hot y_hot
Event handling
addEventHandler <procname> <event-mask> [<event-mask>...]
userEventHandler {widget event-type time wx wy rx ry other}
where "other" is a event-specific list of fields
Event structs
event masks, event names are numerous
most events have these fields:
type, time, x_win, y_win, x_root, y_root other
other fields:
key: state (key or button mask), keycode
button: state (key or button mask), button code
motion: state (key or button mask), is_hint
crossing: mode (normal, grab, ungrab)
focus: mode (normal, grab, ungrab)
visibility: state
error: error_code, request_code, minor_code
keycode|button|mode|state
Event masks
Button1MotionMask
Button2MotionMask
Button3MotionMask
Button4MotionMask
Button5MotionMask
ButtonMotionMask
ButtonPressMask
ButtonReleaseMask
ColormapChangeMask
EnterWindowMask
ExposureMask
FocusChangeMask
KeyPressMask
KeyReleaseMask
KeymapStateMask
LeaveWindowMask
NoEventMask
OwnerGrabButtonMask
PointerMotionHintMask
PointerMotionMask
PropertyChangeMask
ResizeRedirectMask
StructureNotifyMask
SubstructureNotifyMask
SubstructureRedirectMask
VisibilityChangeMask
Event names
ButtonPress
ButtonRelease
CirculateNotify
CirculateRequest
ClientMessage
ColormapNotify
ConfigureNotify
ConfigureRequest
CreateNotify
DestroyNotify
EnterNotify
Expose
FocusIn
FocusOut
GraphicsExpose
GravityNotify
KeyPress
KeyRelease
KeymapNotify
LeaveNotify
MapNotify
MapRequest
MappingNotify
MotionNotify
NoExpose
PropertyNotify
ReparentNotify
ResizeRequest
SelectionClear
SelectionNotify
SelectionRequest
UnmapNotify
VisibilityNotify
GTERM CELL ARRAY
Colormap
use pseudocolor visual if possible
a fixed number of well defined sharable, read-only cells
a variable number of private read-write cells
the private cells are allocated at runtime when the
application allocates a colormap
the graphcap entry specifies the maximum number of private
colormap cells that can be allocated
a private colormap is used if the requested cells cannot
be allocated
there is only one colormap per gterm widget (if there are
multiple cell arrays they share the same colormap)
Cell arrays (obsolete term?)
A cell array is mapping of an MxN array of 8 bit pixel values
to a region of the screen.
The pixel values in a cell array range from 0 to NC, and are
contiguous in that range. NC is the number of colors in
the gterm colormap. The first few values starting at 0
are statically allocated and cell array pixels will
normally start at the first dynamically allocated value.
The cell array mapping defines the transformation used to paint
a region of the Gterm window from the cell array pixels.
Scaling and axis flipping are possible.
Cell arrays are defined and written to in separate steps. A
given write operation may modify only part of the MxN pixels
of the cell array.
New operations
write colormap Writes N cells of the gterm colormap starting
at a given pixel value.
define cell array Define transformation for cell array N.
Several cell arrays may be active.
write cell array Write to a subregion of a cell array (operates
in cell array pixels, not screen pixels).
Arbitrary regions of the colormap or a cell array may be
modified, allowing for very interactive operations.
Binary pixel values must be encoded for transmission between the
client and server. The simplest encoding adds 040 to the value
of each pixel (byte), resulting in a printable byte stream.
Control codes may be used for compression schemes.
Alternative scheme
Store cell array in off screen buffer. This is the same as
above except that in the above scheme the pixels are not
saved.
Modifying any pixel data, or editing the mapping causes the
affected region of the screen to be rewritten.
The advantage of this approach is that operations such as zoom
and pan can be implemented merely by modifying the mapping.
Given multiple cell arrays, one can also do blink, split
screen, etc.
Perhaps mappings should be separate from cell arrays. The
same array may be mapped to more than one region of the
screen, or a mapping may map portions of more than one
array.
Fundamental items are pixel array, mapping, colormap
Pixmap operations
Create host or display pixmap
Destroy pixmap (or all such pixmaps)
Copy data to/from pixmap and screen
Read a file into a pixmap or series of pixmaps
Append pixmap to a file
Should be combined with Obm capabilities for creating and
referencing pixmaps.
Pixmap operations can be used for a number of purposes,
including movie making.
Imaging Procedures
Images (rasters) are implemented internally in Gterm using either
ximages or off screen pixmaps. Which format is used is decided at
raster create time and is controlled by a Gterm resource. This is
transparent to the client application. Currently only 8 bit rasters
are supported.
GtRasterInit (gt)
GtAssignRaster (gt, raster, drawable)
GtCreateRaster (gt, raster, type, width, height)
GtDestroyRaster (gt, raster)
exists = GtQueryRaster (gt, raster, &width, &height)
n = GtNRasters (gt)
GtWritePixels (gt, raster, pixels, x1, y1, nx, ny)
GtReadPixels (gt, raster, pixels, x1, y1, nx, ny)
pixmap = GtCreatePixmap (gt, src, x, y, width, height)
GtCopyPixmap (gt, pixmap, dst, x, y, width, height)
GtWriteColormap (gt, first, nelem, r, g, b)
GtReadColormap (gt, first, nelem, r, g, b)
GtInitMappings (gt)
GtCopyRaster (gt, rop, src,sx,sy,snx,sny, dst,dx,dy,dnx,dny)
GtSetMapping (gt, mapping, src,sx,sy,snx,sny, dst,dx,dy,dnx,dny)
GtGetMapping (gt, mapping, src,sx,sy,snx,sny, dst,dx,dy,dnx,dny)
GtEnableMapping (gt, mapping, enable)
GtRefreshMapping (gt, mapping)
For the widget class we can also have commands to operate upon
pixmaps created by or written into a gterm widget.
createPixmap name src [x y width height]
copyPixmap name dst [x y width height]
destroyPixmap name
There should also be commands to delete pixmaps, write pixmaps to
files, and read pixmaps from files.
The imaging routines operate in window or pixmap pixels. If a
window is resized, any mappings referencing the window are modified
to reflect the change in size. A query-size function is required
to pass the window size in pixels back to the client. A set-size
(resize window) procedure is also desirable to allow the client to
attempt to set the window to the optimum size for an image.
The client uses a special library of procedures for imaging. These
use GIO escapes to communicate with the stdgraph kernel. The
stdgraph kernel uses special ESC codes to communicate with the
server.
Applications which do only simple imaging will use GIO calls to
put a cell array and assign colors, using NDC coordinates for the
cell array mapping. More demanding applications that must operate
in pixel space, operate directly on image buffers, etc., will use
the GIO escapes directly. The stdgraph kernel will keep track of
the window size and perform NDC to pixel space conversions for the
put cell array call.
Implementation
Code structure
client
gio
gim
gki_escape
| (--IPC--)
stdgraph kernel
serial encoding
| (--IPC--)
gtermio
obm
gterm widget
Simple graphics applications use the high level GIO routines for
imaging. These include put/get cell array and put/get colors, with
gset being used to select colors for drawing.
A small library of routines are used in client programs that have
more demanding imaging requirements. These are implemented using
GIO escapes and operate in pixel space, providing direct access to
the gterm imaging functions.
The GIO escapes are processed by the stdgraph kernel. This uses ASCII
escape sequences defined in graphcap to communicate with the server.
The GIO escape codes are defined in lib$gescape.h.
The gtermio code in Xgterm processes these escape sequences and
converts them into calls to the imaging routines in the gterm widget.
The object manager also provides routines for calling the gterm
imaging routines from within UI code.
The actual Xlib based imaging code is in the gterm widget.
Complications
Cursor mode - wants to buffer all GKI instructions, including the
GIM escapes, some of which are voluminous. If any interactive image
editing, redrawing, etc. is done without initializing things, this
could be a lot of data. Would like cursor mode to work in the sense
that one can redraw the screen, zoom and pan.
Cursor readback - for a cursor read within a mapped region of the
screen, the logical thing is to return raster coordinates rather
than Tek window coordinates. The server should make the mapping
transparent, so that the client gets raster coordinates regardless
of the image offset, scale, any axis flip, and so on.
Cursor mode strategy - all GIM escapes issued by the client are
executed, but only setmapping instructions are buffered. During a
cursor mode redraw the setmapping instructions are edited to reflect
the cursor mode zoom/pan (this should be done by a GIM routine), and
retransimitted to the server at the time that they are encountered
in the display list. In most cases this will result in the image
data being redrawn at the appropriate time, e.g. after a frame draw
and area clear, and before any overlaid graphics is drawn.
This requires that the server not initialize the imaging system on
every frame clear (probably the imaging subsystem should be
initialized when the cursor mode frame buffer is cleared, rather
than when the server screen is cleared). The space required to
buffer setmapping instructions is mimimal. A disadvantage is that
:.write/read will not save or redisplay image data. The major
advantage is that this provides full cursor mode zoom/pan capability
and is time and space efficient.
To encapsulate manipulation of the GIM escapes in the cursor mode
code, a GIM (stdgraph kernel) routine should be called when a GIM
escape is executed to edit the instruction, if any, left behind in
the cursor mode buffer. This routine will have access to the
cursor mode frame buffer and will edit it as necessary, e.g.
deleting the instruction, replacing it, or editing earlier GIM
escapes in the same frame buffer.
Cursor readback strategy - to solve this problem it appears to be
necessary to have the server pass back the "cursor number" in a
cursor read. When a cursor read occurs there is no way the client
can predict which cursor will be read; the server selects the cursor
depending upon the pointer location. The cursor number is the Tek
cursor, a raster cursor, or a region of a window. The WCS number
in the cursor value struct passed back to the client indicates
which cursor was read.
Timings
Time to copy 631296 byte text file through a tty/pty
lepus 8-9sec 70 Kb/sec
tucana 2sec 300 Kb/sec
Cursor Handling
The general scheme is that when the cursor is read, the server
determines which raster the cursor is in and returns pixel
coordinates relative to this raster, regardless of how the raster is
mapped to the screen. The return cursor value includes the raster
number, pixel X and Y coordinates, and the keystroke (keycode) which
terminated the cursor read.
Since the Tek cursor value struct does not provide adequate
resolution or any provision for the raster number, a custom cursor
return value is required. gtermio will continue to support a Tek
cursor, using a special escape to initiate a custom cursor read.
gki_retcursor needs to be modified to provide more coordinate
resolution and to allow the "cursor" (raster) number to be returned.
In cursor mode, WCS selection will use the CN/raster number instead
of screen position to determine the WCS to be used. A WCS maps a
range of world coordinates (e.g. image pixel coordinates) to a
viewport in NDC space.
Current cursor mechanism
ESC SUB - initiate standard Tek cursor read
user types key to terminate graphics input mode
server returns cursor value encoded as
key
hix; lox
hiy; loy
trailer1; trailer2
x, y are encoded in Tek screen coordinates, 0-1023,0-779
gki_getcursor (fd, x, y, key, cursor)
stg_getcursor (cursor number)
call stg_readcursor to read cursor
returns GKI cursor value struct
cursor number, x, y, key
stg_readcursor (cursor, x, y, key)
stg_rdcursor (tty, cursor, x, y, key, output_rc)
set raw mode
getc until pattern is matched
clear raw mode
stg_encode to decode cursor value
return x, y, key
rcursor (fd, curval, maxch)
grc_cursor (rc, stream, x, y, key, ppos) (screen)
gtr_readcursor (stream, x, y, key) (screen)
gki_getcursor (fd, mx, my, key, 0) (GKI)
grc_scrtowcs (stream, x, y, xc, yc, wcs) (WCS)
grc_scrtondc (sx, sy, mx, my) (NDC)
wcs = grc_selectwcs (tr, mx, my)
grc_settran (w, ct)
grc_ndctowcs (ct, mx, my, wx, wy) (WCS)
format and return cursor value as a string (WCS)
screen coordinates - workstation screen/window
NDC coordinates - normalized screen coordinates (no zoom)
WCS coordinates - world coordinates in active WCS
WCS - max 16 per screen
wx1,wx2,wy1,wy2 range of world coordinates
sx1,sx2,sy1,sy2 viewport, NDC coordinates
xtran, ytran type of transformation in each axis
clip flag to clip at viewport boundary
WSTRAN - cursor mode ndc-to-screen
vx1,vx2,vy1,vy2 range of NDC coordinates
mx1,mx1,my1,my2 range of GKI coordinates
Cursor mechanism with rasters
The key concept underlying this scheme is that GKI (NDC) coordinates
refer to the "raster" the cursor is in, rather than to the screen,
hence are independent of the raster-to-screen mapping. One
logically draws into a raster, and any mappings defined on the
raster take care of rendering the graphics on the screen. A cursor
read returns both screen coordinates, used for cursor mode zoom/pan,
and image raster GKI/NDC coordinates. A special case is raster 0,
the screen (actually the drawing window), which is what GKI/NDC
coordinates always referred to in the past. When drawing into
raster 0 one is drawing directly to the screen. When drawing into a
raster, one is still drawing to the screen, but via any mapping or
mappings defined on the raster.
Each raster has zero or more WCS associated with it. The WCS
associated with the raster defines a mapping between some world
coordinate system, e.g., image pixel coordinates, and NDC or
normalized raster coordinates. To get from world coordinates to
pixels on the screen, one converts from world coordinates to NDC
coordinates via the WCS, then from NDC coordinates to raster pixels,
then from raster pixels to screen pixels via the mapping. To be
more precise, the full transformation is as follows:
GIO in the client:
world -> NDC
NDC -> GKI (clipped at viewport)
Cursor mode in the CL:
GKI to "screen" (zoomed/clipped-GKI) coordinates
zoomed-GKI to Tek coordinates for serial protocol
Gtermio code in the server:
Tek coordinates to raster pixel coordinates for current
drawing raster
Gterm widget code:
raster pixel coordinates to screen pixel coordinates
via a mapping defined on the raster
repeat for each mapping defined on the raster
Graphics drawing for raster overlays requires that the server treat
the input Tek encoded coordinates (1024x780) as normalized for the
current raster. If the raster number is zero the normal drawing
operation (into the display window) takes place. If the raster
number is nonzero any mappings defined on the referenced raster
define where the graphics is drawn on the screen. If a mapping is
disabled no drawing takes place. Graphics are automatically clipped
at the boundary of the destination rect defined by a mapping.
In a cursor read operation, the server determines which raster if
any is mapped to the region of the screen the cursor is in. Both
screen (raster 0) and raster coordinates are returned using a
special cursor value struct. The cursor value return by RCURSOR
(hence =gcur and clgcur) returns the world coordinates defined by
the selected WCS for the current raster. If no WCS is defined NDC
coordinates are returned. If multiple WCS are defined for a raster
cursor mode selects the "nearest" viewport as it has always done
for screen coordinates.
About the only alternative to the above scheme is to have the server
return raster pixel coordinates. The problem with this is that this
is inconsistent with the GIO graphics model, and the WCS cannot be
used to return world coordinates, or to draw graphics overlays.
A complication with this scheme is that normally WCS 1 is used for
the screen (raster 0). Sometimes more than one WCS is used. Hence
to make a strict association between WCS number and raster number
would require that raster numbers be allocated accordingly in the
client. Also it is not clear what happens if there is more than one
WCS defined for a raster. To get around this problem a way is
needed to define which raster a WCS refers to. This can be done
without a (significant) protocol change by encoding the frame number
in the existing, little used WCS_CLIP field of the existing WCS
structure.
Colormap Sharing
A gterm resource selects type of colormap: default, private, shared
default means default screen colormap, shared by all apps
private means colormap is used only by this gterm instance
shared means non-default colormap shared by multiple gterms
In the case of the default colormap, read-only or read-write cells
are allocated out of the screen default colormap. This guarantees
that the colors of non-gterm windows will not be affected when gterm
colors are allocated, but it may not be possible to allocate all
requested colors, or having allocated these colors to a gterm
widget it may not be possible to run other applications. Use of
the default colormap is appropriate for applications that do not
use many colors.
A private colormap is allocated and used by only a single gterm.
This guarantees that the expected number of colors will be available,
and prevents one gterm from changing another's colors. The main
disadvantage is that the window will go black (or whatever) when
the pointer is not in the window.
A shared colormap is a non-default (custom) colormap shared by
multiple gterms. Allocation of colors is guaranteed, but when one
gterm modifies the colormap all gterms using the shared colormap
are affected. They are however still visible and if they contain
similar data the display may still appear reasonable. There can
be multiple shared colormaps, each with a different name.
It is possible to use a trick to minimize colormap flashing when
private or shared colormaps are used. This works so long as the
default colormap has only a limited number of colors allocated,
and the gterm client needs only a limited number of colors (e.g.
200 or so out of 256). The trick is to allocate as many colors as
possible from the default colormap, assigning the same pixels for
colors in the custom colormap. The default colormap is then copied
to the private (or shared) colormap, and the new colors are stored
in both colormaps. The newly allocated colors are then freed in
the default colormap. The custom colormap will then inherit most
of the color assignments of the default colormap, and in turn the
default colormap may still have the initial color assignments from
the custom colormap.
Differences will appear as both colormaps change thereafter, but in
practice many color assignments are fairly static so colormap
flashing should be minimized. The default colormap can be updated
periodically by repeating the allocate, store, copy, and free
sequence, e.g., when the custom colormap is modified.
Custom gterm colormap allocation strategy: in the normal case reserve
216 colors for private use. The remaining cells are copied from the
default colormap to minimize colormap flashing. If the gterm client
requests more than 216 colors the full colormap is allocated.
0 - 37 copied from default colormap
38 - 253 reserved for gterm client
254 - 255 copied from default colormap
The point where the gterm colormap starts (e.g. 38) should be defined
by a resource as there is no guarantee which end of the default
colormap static colors will be allocated at.
if (use default colormap) {
allocate read-write cells
store colors
} else {
if (don't have colormap yet) {
map colormap name to atom
if (named gterm colormap not found) {
# Create gterm colormap.
open connection to display
create colormap, allocate all colors
call XSetRGBColormaps to set colormap property
call XSetCloseDownMode to make colormap permanent
close display
} else {
call XGetRGBColormaps to get colormap property
get colormap id
}
set colormap id for gterm window
call XSetWMColormapWindows to notify WM of custom colormap
}
store new colors in custom colormap
if (match colormaps) {
copy global cells from default colormap
attempt to allocate cells in default colormap
attempt to store new colors in default colormap
free cells allocated above
}
}
If the gterm widget has a private colormap different than that of
its top level window, XSetWMColormapWindows must be called for gterm
window focus in/out events to indicate to the WM that the colormap
for the gterm window is to be loaded.
Windowing the Display
Given a range of display pixel values and a normalized colormap,
apply a threshold/gain transformation to window the display (i.e.,
write new screen colormap). This needs to be done in the UI to
provide acceptable interactive response.
GtWindowDisplay (gw, offset, slope)
offset (0.5 +/- X) center of windowed region
slope (+/- X) slope of transfer function
The transfer function is applied to the normalized colormap
and the output colormap is written to the screen.
To window over a greater dynamic range one must regenerate the
display pixel values from the raster or image (this can be done by
the client). For example, the client application can display a
histogram and the user can mark the region to be written to the the
gterm raster pixels.
The marker facilities described in the next section can be used to
implement real-time display of the grayscale transfer function if
desired. The message facility could also be used to transfer the
image histogram and information about the histogram region loaded
into a raster, for use with the transfer function to generate a
full display of the grayscale mapping from disk image to screen.
Graphics Markers
A "marker" is a graphics object, defined on a raster, which can be
created or destroyed, which can draw itself, or which can modify
(move or resize) itself in response to pointer events. Markers have
attributes such as the marker type (text, line, circle, polygon,
etc.), color, line width, center, width, height, visibility, and
sensitivity. Markers can accept callbacks which are executed when
the object is interactively moved or resized.
Markers can be used to annotate a window, as if one were drawing
into a window. The chief difference between a marker and a simple
drawing operation (such as a polyline) is that markers are not just
lines on the screen, but actual objects capable of responding to
requests or taking independent action.
Generic functions
create
destroy
copy
set attribute
get attribute
raise, lower
Generic attributes
type
visibility
autoRedraw
sensitivity
foreground, background text markers
linecolor, linewidth
knotcolor, knotsize
fillcolor, fillstyle polygon markers
width, height
x, y
Marker types
text font, string
line vertices
box
rectangle
circle
ellipse
polyline vertices
polygon vertices
Procedures
gm = GmGreate (gt, type, interactive)
gm = GmCopy (gm)
GmDestroy (gm)
GmAddCallback (gm, func, client_data)
gm = GmSelect (gt, x, y, &what)
GmMarkpos (gm)
GmRedraw (gm, func, erase)
GmRaise (gm, ref_gm|NULL)
GmLower (gm, ref_gm|NULL)
GmNotify (gm, events)
GmAdd (gm, x, y)
GmDelete (gm, x, y)
GmMove (gm, x, y)
GmResize (gm, x, y)
GmRotate (gm, x, y)
GmSetAttribute (gm, attribute, value, type)
GmGetAttribute (gm, attribute, value, type)
GmSetVertices (gm, points, first, npts)
npts = GmGetVertices (gm, points, first, maxpts)
raster = GtSelectRaster (gt, st, sx, sy, rt, &rx, &ry, &mp)
GtMapVector (gt, mp, dir, st, sv, dt, dv, npts, clip)
Markers operate in screen coordinates (raster 0). The SelectRaster
and MapVector routines may be used to convert to and from raster
coordinates if desired.
Actions
create (type)
destroy marker
set (attr, value)
raise marker
lower marker
notify callback
markpos marker
markposAdd marker point button1-down
redraw marker button1-up
add point
delete point
deleteDestroy point or marker delete or backspace
move marker
resize marker
moveResize point or marker button1-motion
rotate marker shift-button1
Marker specific functions (internal)
bool = select (gm, x, y, &what)
classinit (gm)
markpos (gm, &rect)
redraw (gm, function)
add (gm, x, y)
delete (gm, x, y)
move (gm, x, y)
resize (gm, x, y)
rotate (gm, x, y)
The marker specific functions are the methods for each marker
class. The functions add, delete, move etc. merely edit the marker
descriptor. A separate call to redraw is required to redraw the
modified marker.
Actions such as deleteDestroy and moveResize will select one of the
listed actions based upon the pointer coordinates. For example with
moveResize, if the pointer is in the center of a marker the entire
marker is moved, and if the pointer is near a point the point is
moved or the marker resized depending upon the type of marker.
The default translations for these actions are shown at the right.
These translations are in effect only when the pointer is over a
marker that is sensitive and visible. The cursor will change to
indicate that the marker is active; the cursor type will indicate
whether the entire marker, a single point, or add-point will be
selected if button1 is pressed at that location. In addition, the
default translation for button1-down for the window is create
rectangle. Hence a rectangle object can be created and dragged out
with the left button at any time just using the default
translations. This can be used prior to executing a command to
indicate the region to be operated upon.
Actions such as move, resize, rotate, etc. do not redraw the object
(unless autoRedraw is set). Instead, these actions do a GXor redraw
of the marker at the old location, edit the marker according to its
type, and then do another GXor redraw at the new location. When
tracking the cursor this produces a rubber-band effect. When
tracking completes (e.g., button1-up) the screen is refreshed at the
markpos position, erasing the old marker, any affected markers are
redrawn at the markpos position, and the edited marker is redrawn at
the new location.
A Marker is created with GmCreate. If the interactive flag is set
a mode is entered where the mouse is used to set the initial
position and size of the object. The cursor changes to indicate
that the widget is waiting for input. The user moves the mouse to
the position on the screen where the object will go, clicks the left
pointer, and then does a drag to set the initial size and
orientation of the object. When the button is released the create
object operation is complete, unless the marker type is polygon in
which case multiple click-and-drag operations are required to
interactively define the polygon.
If the create is not interactive, the GmCreate returns immediately,
and SetAttribute calls are used to set the object attributes and
then display the object.
Once a marker has been created the sensitivity attribute controls
whether the object can be interactively moved or resized with the
mouse. If the marker is sensitive, when the pointer is placed
within the marker or near a vertex or edge the cursor will change to
indicate that the marker, vertex, or edge can be dragged to move or
resize the marker. Alternatively, the delete or backspace key can
be used to destroy the marker. This will not actually destroy the
marker, but will notify the client (via a callback) that the user
has requested that the marker be destroyed.
When the mouse is near a sensitive marker a special translation
table defines the key or pointer bindings associated with the drag,
delete, etc. marker actions. Typical bindings would be left pointer
for create and drag, middle pointer to terminate a sequence such as
when drawing a polygon or to abort a create object, shift left
pointer to add a point to an existing polygon, and delete or
backspace to delete an object, or in add-point mode, the last vertex
in a polygon.
All the gterm widget need do is, when there is one or more sensitive
marker in a window, track the cursor and load the marker translation
table when the pointer is over a marker which is sensitive. The
rest will be done by the marker actions.
Markers can be used in UI code to provide a more general method of
position input than a cursor read, which can only specify a single
point. For example to input a rectangular region, one would do the
following:
UI selects marker type rectangle
UI creates a rectangle marker in interactive mode
cursor changes to indicate create-object mode
user positions mouse and clicks left button
holding button down, user drags out the rectangle
button up terminates GmCreate
UI calls GetVertices and passes polygon back to client
UI destroys marker
If desired, the client application can draw the polygon again
using normal graphics drawing commands (i.e., not as a marker).
To mark a region on a raster in UI code:
UI creates rectangle object in noninteractive mode
visibility and autoredraw are initially false
UI calls SetAttribute to set rectangle position, size, etc.
UI sets visibility attribute to cause marker to be drawn
If the region is to be active, e.g. something should happen if the
user moves or resizes the region, then the sensitivity should be
set to true and a callback can be posted to take some action if the
region is changed. For example, this could be used to graphically
pan the image or adjust the colormap.
Markers are only drawn to the screen, never to the screen pixmap.
Hence they can be erased by copying from the screen pixmap. If the
screen needs to be refreshed the markers are redrawn from the object
list maintained internally by the gterm widget.
Display of Pixel Dependent Information
A common feature of image display UIs is the ability to display
information about the pixel under the cursor, either in sample mode
or continuously as the cursor is moved. For maximum flexibility
one must rely upon the client application to return information about
a pixel, since usually only the client has full access to the data,
and the significance of a pixel can be highly application specific.
An example of this is the display of the cursor position and pixel
intensity in user coordinates.
To implement this feature we need the following capabilities.
o The UI posts a callback procedure which is called whenever
the cursor moves, i.e., which receives pointer-moved events.
o The UI obtains information about the pixel under the pointer
from the client.
o The UI displays this information in a text object, either
overlaid on the image or in a separate text display area.
The WS already provides the ability to post a callback to receive
pointer-moved events. What we need is an efficient way to obtain
information about the pixel under the cursor. Due to the overhead
of the client-server architecture, it is undesirable to query the
client every time we need information about a pixel. Hence, we must
get information for a block of pixels in single query and cache this
information in the server, sending another query only when the
pointer moves to a different region of the screen.
This can be done by sending a request to the client to send a block
of information (text) for all the points in a grid in pixel space.
The client responds by generating the text as a message to a UI
parameter. The UI then needs a way to select text from the UI
parameter, and generate another query if the desired data is not
cached.
The cached text consists of a sequence of lines of the form
raster-x raster-y client-text
The server will need to cache several such blocks of data, each with
a header identifying the raster number and the region of the raster
covered by the cached data. The object code in the server will
provide convenience routines for managing and searching this data.
Text Display Facilities
Real-time display of pixel information requires some way of
displaying the text passed back by the client via the method
described in the last section. Text display can be done either
using a text widget ouside the gterm window, or using a text marker
if the text is to be overlaid on the image. An advantage of using a
marker for the text overlay is that since the marker is active, the
user can use the mouse to reposition the text on the screen.
Translations
The Widget specifies the default translations. The Widget
translations resource specifies replacement, augment, or override
translations. Additional augment or override translations may
be specified in a function call (e.g. to cause the widget to invoke
an application specified menu via a translation).
On a marker focusout, the widget must restore the gterm window
translations.
At initialize time:
if (translations resource defined) {
if (augment or override translations) {
defTranslations = compiled Gterm translations
compile auxiliary translations
set augment or override flag
} else
defTranslations = compiled translations resource
} else
defTranslations = compiled translations resource
At focusout time:
SetValues defTranslations
for (each auxiliary translation table)
augment or override widget translations
Additional auxiliary widget translations can be specified with
GtAugmentTranslations or GtOverrideTranslations.
oo
|