1 | ; $Id$ |
---|
2 | ; |
---|
3 | ; Copyright (c) 1992-2005, Research Systems, Inc. All rights reserved. |
---|
4 | ; Unauthorized reproduction prohibited. |
---|
5 | ;+ |
---|
6 | ; NAME: |
---|
7 | ; CW_BGROUP |
---|
8 | ; |
---|
9 | ; PURPOSE: |
---|
10 | ; CW_BGROUP is a compound widget that simplifies creating |
---|
11 | ; a base of buttons. It handles the details of creating the |
---|
12 | ; proper base (standard, exclusive, or non-exclusive) and filling |
---|
13 | ; in the desired buttons. Events for the individual buttons are |
---|
14 | ; handled transparently, and a CW_BGROUP event returned. This |
---|
15 | ; event can return any one of the following: |
---|
16 | ; - The Index of the button within the base. |
---|
17 | ; - The widget ID of the button. |
---|
18 | ; - The name of the button. |
---|
19 | ; - An arbitrary value taken from an array of User values. |
---|
20 | ; |
---|
21 | ; CATEGORY: |
---|
22 | ; Compound widgets. |
---|
23 | ; |
---|
24 | ; CALLING SEQUENCE: |
---|
25 | ; Widget = CW_BGROUP(Parent, Names) |
---|
26 | ; |
---|
27 | ; To get or set the value of a CW_BGROUP, use the GET_VALUE and |
---|
28 | ; SET_VALUE keywords to WIDGET_CONTROL. The value of a CW_BGROUP |
---|
29 | ; is: |
---|
30 | ; |
---|
31 | ; ----------------------------------------------- |
---|
32 | ; Type Value |
---|
33 | ; ----------------------------------------------- |
---|
34 | ; normal None |
---|
35 | ; exclusive Index of currently set button |
---|
36 | ; non-exclusive Vector indicating the position |
---|
37 | ; of each button (1-set, 0-unset) |
---|
38 | ; ----------------------------------------------- |
---|
39 | ; |
---|
40 | ; |
---|
41 | ; INPUTS: |
---|
42 | ; Parent: The ID of the parent widget. |
---|
43 | ; Names: A string array, containing one string per button, |
---|
44 | ; giving the name of each button. |
---|
45 | ; |
---|
46 | ; KEYWORD PARAMETERS: |
---|
47 | ; |
---|
48 | ; BUTTON_UVALUE: An array of user values to be associated with |
---|
49 | ; each button and returned in the event structure. |
---|
50 | ; COLUMN: Buttons will be arranged in the number of columns |
---|
51 | ; specified by this keyword. |
---|
52 | ; EVENT_FUNCT: The name of an optional user-supplied event function |
---|
53 | ; for buttons. This function is called with the return |
---|
54 | ; value structure whenever a button is pressed, and |
---|
55 | ; follows the conventions for user-written event |
---|
56 | ; functions. |
---|
57 | ; EXCLUSIVE: Buttons will be placed in an exclusive base, with |
---|
58 | ; only one button allowed to be selected at a time. |
---|
59 | ; FONT: The name of the font to be used for the button |
---|
60 | ; titles. If this keyword is not specified, the default |
---|
61 | ; font is used. |
---|
62 | ; FRAME: Specifies the width of the frame to be drawn around |
---|
63 | ; the base. |
---|
64 | ; IDS: A named variable into which the button IDs will be |
---|
65 | ; stored, as a longword vector. |
---|
66 | ; LABEL_LEFT: Creates a text label to the left of the buttons. |
---|
67 | ; LABEL_TOP: Creates a text label above the buttons. |
---|
68 | ; MAP: If set, the base will be mapped when the widget |
---|
69 | ; is realized (the default). |
---|
70 | ; NONEXCLUSIVE: Buttons will be placed in an non-exclusive base. |
---|
71 | ; The buttons will be independent. |
---|
72 | ; NO_RELEASE: If set, button release events will not be returned. |
---|
73 | ; RETURN_ID: If set, the VALUE field of returned events will be |
---|
74 | ; the widget ID of the button. |
---|
75 | ; RETURN_INDEX: If set, the VALUE field of returned events will be |
---|
76 | ; the zero-based index of the button within the base. |
---|
77 | ; THIS IS THE DEFAULT. |
---|
78 | ; RETURN_NAME: If set, the VALUE field of returned events will be |
---|
79 | ; the name of the button within the base. |
---|
80 | ; ROW: Buttons will be arranged in the number of rows |
---|
81 | ; specified by this keyword. |
---|
82 | ; SCROLL: If set, the base will include scroll bars to allow |
---|
83 | ; viewing a large base through a smaller viewport. |
---|
84 | ; SET_VALUE: The initial value of the buttons. This is equivalent |
---|
85 | ; to the later statement: |
---|
86 | ; |
---|
87 | ; WIDGET_CONTROL, widget, set_value=value |
---|
88 | ; |
---|
89 | ; SPACE: The space, in pixels, to be left around the edges |
---|
90 | ; of a row or column major base. This keyword is |
---|
91 | ; ignored if EXCLUSIVE or NONEXCLUSIVE are specified. |
---|
92 | ; UVALUE: The user value to be associated with the widget. |
---|
93 | ; UNAME: The user name to be associated with the widget. |
---|
94 | ; XOFFSET: The X offset of the widget relative to its parent. |
---|
95 | ; XPAD: The horizontal space, in pixels, between children |
---|
96 | ; of a row or column major base. Ignored if EXCLUSIVE |
---|
97 | ; or NONEXCLUSIVE are specified. |
---|
98 | ; XSIZE: The width of the base. |
---|
99 | ; X_SCROLL_SIZE: The width of the viewport if SCROLL is specified. |
---|
100 | ; YOFFSET: The Y offset of the widget relative to its parent. |
---|
101 | ; YPAD: The vertical space, in pixels, between children of |
---|
102 | ; a row or column major base. Ignored if EXCLUSIVE |
---|
103 | ; or NONEXCLUSIVE are specified. |
---|
104 | ; YSIZE: The height of the base. |
---|
105 | ; Y_SCROLL_SIZE: The height of the viewport if SCROLL is specified. |
---|
106 | ; |
---|
107 | ; OUTPUTS: |
---|
108 | ; The ID of the created widget is returned. |
---|
109 | ; |
---|
110 | ; SIDE EFFECTS: |
---|
111 | ; This widget generates event structures with the following definition: |
---|
112 | ; |
---|
113 | ; event = { ID:0L, TOP:0L, HANDLER:0L, SELECT:0, VALUE:0 } |
---|
114 | ; |
---|
115 | ; The SELECT field is passed through from the button event. VALUE is |
---|
116 | ; either the INDEX, ID, NAME, or BUTTON_UVALUE of the button, |
---|
117 | ; depending on how the widget was created. |
---|
118 | ; |
---|
119 | ; RESTRICTIONS: |
---|
120 | ; Only buttons with textual names are handled by this widget. |
---|
121 | ; Bitmaps are not understood. |
---|
122 | ; |
---|
123 | ; MODIFICATION HISTORY: |
---|
124 | ; 15 June 1992, AB |
---|
125 | ; 7 April 1993, AB, Removed state caching. |
---|
126 | ; 6 Oct. 1994, KDB, Font keyword is not applied to the label. |
---|
127 | ; 10 FEB 1995, DJC fixed bad bug in event procedure, getting |
---|
128 | ; id of stash widget. |
---|
129 | ; 11 April 1995, AB Removed Motif special cases. |
---|
130 | ;- |
---|
131 | |
---|
132 | |
---|
133 | pro CW_BGROUP_SETV, id, value |
---|
134 | compile_opt hidden, idl2, strictarrsubs |
---|
135 | |
---|
136 | ON_ERROR, 2 ;return to caller |
---|
137 | |
---|
138 | stash = WIDGET_INFO(id, /CHILD) |
---|
139 | WIDGET_CONTROL, stash, GET_UVALUE=state, /NO_COPY |
---|
140 | |
---|
141 | case state.type of |
---|
142 | 0: message,'unable to set plain button group value' |
---|
143 | 1: begin |
---|
144 | WIDGET_CONTROL, SET_BUTTON=0, state.ids[state.excl_pos] |
---|
145 | state.excl_pos = value |
---|
146 | WIDGET_CONTROL, /SET_BUTTON, state.ids[value] |
---|
147 | end |
---|
148 | 2: begin |
---|
149 | n = n_elements(value)-1 |
---|
150 | for i = 0, n do begin |
---|
151 | state.nonexcl_curpos[i] = value[i] |
---|
152 | WIDGET_CONTROL, state.ids[i], SET_BUTTON=value[i] |
---|
153 | endfor |
---|
154 | end |
---|
155 | endcase |
---|
156 | |
---|
157 | WIDGET_CONTROL, stash, SET_UVALUE=state, /NO_COPY |
---|
158 | end |
---|
159 | |
---|
160 | |
---|
161 | |
---|
162 | function CW_BGROUP_GETV, id, value |
---|
163 | |
---|
164 | compile_opt hidden, idl2, strictarrsubs |
---|
165 | ON_ERROR, 2 ;return to caller |
---|
166 | |
---|
167 | stash = WIDGET_INFO(id, /CHILD) |
---|
168 | WIDGET_CONTROL, stash, GET_UVALUE=state, /NO_COPY |
---|
169 | |
---|
170 | case state.type of |
---|
171 | 0: message, 'unable to get plain button group value' |
---|
172 | ; 1: ret = state.excl_pos |
---|
173 | 1: ret = state.ret_arr[state.excl_pos] |
---|
174 | ; 2: ret = state.nonexcl_curpos |
---|
175 | 2: BEGIN |
---|
176 | index = where(state.nonexcl_curpos NE 0) |
---|
177 | if index[0] EQ -1 then begin |
---|
178 | if size(state.ret_arr, /type) EQ 7 then ret = '' ELSE ret = -1 |
---|
179 | ENDIF ELSE ret = state.ret_arr[index] |
---|
180 | END |
---|
181 | endcase |
---|
182 | |
---|
183 | WIDGET_CONTROL, stash, SET_UVALUE=state, /NO_COPY |
---|
184 | |
---|
185 | return, ret |
---|
186 | |
---|
187 | end |
---|
188 | |
---|
189 | |
---|
190 | |
---|
191 | function CW_BGROUP_EVENT, ev |
---|
192 | compile_opt hidden, idl2, strictarrsubs |
---|
193 | WIDGET_CONTROL, ev.handler, GET_UVALUE=stash |
---|
194 | WIDGET_CONTROL, stash, GET_UVALUE=state, /NO_COPY |
---|
195 | WIDGET_CONTROL, ev.id, get_uvalue=uvalue |
---|
196 | |
---|
197 | ret = 1 ;Assume we return a struct |
---|
198 | case state.type of |
---|
199 | 0: |
---|
200 | 1: if (ev.select eq 1) then begin |
---|
201 | state.excl_pos = uvalue |
---|
202 | ENDIF else begin |
---|
203 | if (state.no_release ne 0) then ret = 0 |
---|
204 | ENDELSE |
---|
205 | 2: begin |
---|
206 | ; Keep track of the current state |
---|
207 | state.nonexcl_curpos[uvalue] = ev.select |
---|
208 | if (state.no_release ne 0) and (ev.select eq 0) then ret = 0 |
---|
209 | end |
---|
210 | endcase |
---|
211 | |
---|
212 | if ret then begin ;Return a struct? |
---|
213 | ret = { ID:state.base, TOP:ev.top, HANDLER:0L, SELECT:ev.select, $ |
---|
214 | VALUE:state.ret_arr[uvalue] } |
---|
215 | efun = state.efun |
---|
216 | WIDGET_CONTROL, stash, SET_UVALUE=state, /NO_COPY |
---|
217 | if efun ne '' then return, CALL_FUNCTION(efun, ret) $ |
---|
218 | else return, ret |
---|
219 | endif else begin ;Trash the event |
---|
220 | WIDGET_CONTROL, stash, SET_UVALUE=state, /NO_COPY |
---|
221 | return, 0 |
---|
222 | endelse |
---|
223 | end |
---|
224 | |
---|
225 | |
---|
226 | |
---|
227 | |
---|
228 | |
---|
229 | |
---|
230 | |
---|
231 | function CW_BGROUP, parent, names, $ |
---|
232 | BUTTON_UVALUE = button_uvalue, COLUMN=column, EVENT_FUNCT = efun, $ |
---|
233 | EXCLUSIVE=excl, FONT=font, FRAME=frame, IDS=ids, LABEL_TOP=label_top, $ |
---|
234 | LABEL_LEFT=label_left, MAP=map, $ |
---|
235 | NONEXCLUSIVE=nonexcl, NO_RELEASE=no_release, RETURN_ID=return_id, $ |
---|
236 | RETURN_INDEX=return_index, RETURN_NAME=return_name, $ |
---|
237 | ROW=row, SCROLL=scroll, SET_VALUE=sval, SPACE=space, $ |
---|
238 | TAB_MODE=tab_mode, UVALUE=uvalue, $ |
---|
239 | XOFFSET=xoffset, XPAD=xpad, XSIZE=xsize, X_SCROLL_SIZE=x_scroll_size,$ |
---|
240 | YOFFSET=yoffset, YPAD=ypad, YSIZE=ysize, Y_SCROLL_SIZE=y_scroll_size, $ |
---|
241 | UNAME=uname |
---|
242 | |
---|
243 | |
---|
244 | IF (N_PARAMS() ne 2) THEN MESSAGE, 'Incorrect number of arguments' |
---|
245 | |
---|
246 | ON_ERROR, 2 ;return to caller |
---|
247 | |
---|
248 | ; Set default values for the keywords |
---|
249 | version = WIDGET_INFO(/version) |
---|
250 | if (version.toolkit eq 'OLIT') then def_space_pad = 4 else def_space_pad = 3 |
---|
251 | IF (N_ELEMENTS(column) eq 0) then column = 0 |
---|
252 | IF (N_ELEMENTS(excl) eq 0) then excl = 0 |
---|
253 | IF (N_ELEMENTS(frame) eq 0) then frame = 0 |
---|
254 | IF (N_ELEMENTS(map) eq 0) then map=1 |
---|
255 | IF (N_ELEMENTS(nonexcl) eq 0) then nonexcl = 0 |
---|
256 | IF (N_ELEMENTS(no_release) eq 0) then no_release = 0 |
---|
257 | IF (N_ELEMENTS(row) eq 0) then row = 0 |
---|
258 | IF (N_ELEMENTS(scroll) eq 0) then scroll = 0 |
---|
259 | IF (N_ELEMENTS(space) eq 0) then space = def_space_pad |
---|
260 | IF (N_ELEMENTS(uname) eq 0) then uname = 'CW_BGROUP_UNAME' |
---|
261 | IF (N_ELEMENTS(uvalue) eq 0) then uvalue = 0 |
---|
262 | IF (N_ELEMENTS(xoffset) eq 0) then xoffset=0 |
---|
263 | IF (N_ELEMENTS(xpad) eq 0) then xpad = def_space_pad |
---|
264 | IF (N_ELEMENTS(xsize) eq 0) then xsize = 0 |
---|
265 | IF (N_ELEMENTS(x_scroll_size) eq 0) then x_scroll_size = 0 |
---|
266 | IF (N_ELEMENTS(yoffset) eq 0) then yoffset=0 |
---|
267 | IF (N_ELEMENTS(ypad) eq 0) then ypad = def_space_pad |
---|
268 | IF (N_ELEMENTS(ysize) eq 0) then ysize = 0 |
---|
269 | IF (N_ELEMENTS(y_scroll_size) eq 0) then y_scroll_size = 0 |
---|
270 | |
---|
271 | |
---|
272 | |
---|
273 | |
---|
274 | top_base = 0L |
---|
275 | if (n_elements(label_top) ne 0) then begin |
---|
276 | next_base = WIDGET_BASE(parent, XOFFSET=xoffset, YOFFSET=yoffset, /COLUMN) |
---|
277 | if(keyword_set(font))then $ |
---|
278 | junk = WIDGET_LABEL(next_base, value=label_top,font=font) $ |
---|
279 | else junk = WIDGET_LABEL(next_base, value=label_top) |
---|
280 | top_base = next_base |
---|
281 | endif else next_base = parent |
---|
282 | |
---|
283 | if (n_elements(label_left) ne 0) then begin |
---|
284 | next_base = WIDGET_BASE(next_base, XOFFSET=xoffset, YOFFSET=yoffset, /ROW) |
---|
285 | if(keyword_set(font))then $ |
---|
286 | junk = WIDGET_LABEL(next_base, value=label_left, font=font) $ |
---|
287 | else junk = WIDGET_LABEL(next_base, value=label_left) |
---|
288 | if (top_base eq 0L) then top_base = next_base |
---|
289 | endif |
---|
290 | ; We need some kind of outer base to hold the users UVALUE |
---|
291 | if (top_base eq 0L) then begin |
---|
292 | top_base = WIDGET_BASE(parent, XOFFSET=xoffset, YOFFSET=yoffset) |
---|
293 | next_base = top_base |
---|
294 | endif |
---|
295 | If (top_base EQ next_base) THEN $ |
---|
296 | next_base = WIDGET_BASE(top_base, Xpad=1, Ypad=1, Space=1) |
---|
297 | |
---|
298 | ; Set top level base attributes |
---|
299 | WIDGET_CONTROL, top_base, MAP=map, $ |
---|
300 | FUNC_GET_VALUE='CW_BGROUP_GETV', PRO_SET_VALUE='CW_BGROUP_SETV', $ |
---|
301 | SET_UVALUE=uvalue, SET_UNAME=uname |
---|
302 | |
---|
303 | ; Tabbing |
---|
304 | if (n_elements(tab_mode) ne 0) then begin |
---|
305 | WIDGET_CONTROL, top_base, TAB_MODE=tab_mode |
---|
306 | WIDGET_CONTROL, next_base, TAB_MODE=tab_mode |
---|
307 | end |
---|
308 | |
---|
309 | ; The actual button holding base |
---|
310 | base = WIDGET_BASE(next_base, COLUMN=column, EXCLUSIVE=excl, FRAME=frame, $ |
---|
311 | NONEXCLUSIVE=nonexcl, ROW=row, SCROLL=scroll, SPACE=space, $ |
---|
312 | XPAD=xpad, XSIZE=xsize, X_SCROLL_SIZE=x_scroll_size, $ |
---|
313 | YPAD=ypad, YSIZE=ysize, Y_SCROLL_SIZE=y_scroll_size, $ |
---|
314 | EVENT_FUNC='CW_BGROUP_EVENT', $ |
---|
315 | UVALUE=WIDGET_INFO(top_base, /child)) |
---|
316 | |
---|
317 | |
---|
318 | n = n_elements(names) |
---|
319 | ids = lonarr(n) |
---|
320 | for i = 0, n-1 do begin |
---|
321 | if (n_elements(font) eq 0) then begin |
---|
322 | ids[i] = WIDGET_BUTTON(base, value=names[i], UVALUE=i, $ |
---|
323 | UNAME=uname+'_BUTTON'+STRTRIM(i,2)) |
---|
324 | endif else begin |
---|
325 | ids[i] = WIDGET_BUTTON(base, value=names[i], FONT=font, $ |
---|
326 | UVALUE=i, UNAME=uname+'_BUTTON'+STRTRIM(i,2)) |
---|
327 | endelse |
---|
328 | endfor |
---|
329 | |
---|
330 | ; Keep the state info in the real (inner) base UVALUE. |
---|
331 | ; Pick an event value type: |
---|
332 | ; 0 - Return ID |
---|
333 | ; 1 - Return INDEX |
---|
334 | ; 2 - Return NAME |
---|
335 | ret_type = 1 |
---|
336 | if KEYWORD_SET(RETURN_ID) then ret_type = 0 |
---|
337 | if KEYWORD_SET(RETURN_NAME) then ret_type = 2 |
---|
338 | if KEYWORD_SET(BUTTON_UVALUE) then ret_type = 3 |
---|
339 | case ret_type of |
---|
340 | 0: ret_arr = ids |
---|
341 | 1: ret_arr = indgen(n) |
---|
342 | 2: ret_arr = names |
---|
343 | 3: ret_arr = button_uvalue |
---|
344 | endcase |
---|
345 | type = 0 |
---|
346 | if (excl ne 0) then type = 1 |
---|
347 | |
---|
348 | if (nonexcl ne 0) then type = 2 |
---|
349 | if n_elements(efun) le 0 then efun = '' |
---|
350 | state = { type:type, $ ; 0-Standard, 1-Exclusive, 2-Non-exclusive |
---|
351 | base: top_base, $ ; cw_bgroup base... |
---|
352 | ret_arr:ret_arr, $ ; Vector of event values |
---|
353 | efun : efun, $ ; Name of event fcn |
---|
354 | nonexcl_curpos:intarr(n), $ ; If non-exclus, tracks state |
---|
355 | excl_pos:0, $ ; If exclusive, current button |
---|
356 | ids:ids, $ ; Ids of buttons |
---|
357 | no_release:no_release } |
---|
358 | WIDGET_CONTROL, WIDGET_INFO(top_base, /CHILD), SET_UVALUE=state, /NO_COPY |
---|
359 | |
---|
360 | if (n_elements(sval) ne 0) then CW_BGROUP_SETV, top_base, sval |
---|
361 | |
---|
362 | return, top_base |
---|
363 | END |
---|