1 | ;============================================================================= |
---|
2 | ;+ |
---|
3 | ; Finds and returns the value of a widget (or, for a button widget, |
---|
4 | ; whether it is set), given the uname of the widget. |
---|
5 | ; |
---|
6 | ; @returns The value of the widget, or for a button, 1 if set, 0 if |
---|
7 | ; not set. |
---|
8 | ; @param uname {in}{required}{type=string} The user value of the |
---|
9 | ; widget being manipulated. |
---|
10 | ;- |
---|
11 | function xidldoc::get_value, uname |
---|
12 | compile_opt idl2, hidden |
---|
13 | |
---|
14 | if n_params() ne 1 then begin |
---|
15 | message, 'Need widget user name.', /continue |
---|
16 | return, 0 |
---|
17 | endif |
---|
18 | |
---|
19 | id = widget_info(self.top, find_by_uname=uname) |
---|
20 | name = strlowcase(widget_info(id, /name)) |
---|
21 | if name eq 'button' then begin |
---|
22 | value = widget_info(id, /button_set) |
---|
23 | endif else begin |
---|
24 | widget_control, id, get_value=value |
---|
25 | endelse |
---|
26 | return, value |
---|
27 | end |
---|
28 | |
---|
29 | |
---|
30 | |
---|
31 | ;============================================================================= |
---|
32 | ;+ |
---|
33 | ; Finds and sets the value of a widget, given the uname of the widget |
---|
34 | ; and the value to set. |
---|
35 | ; |
---|
36 | ; @param uname {in}{required}{type=string} The user value of the |
---|
37 | ; widget being manipulated. |
---|
38 | ; @param value {in}{required} The value to assign the widget. |
---|
39 | ;- |
---|
40 | pro xidldoc::set_value, uname, value |
---|
41 | compile_opt idl2, hidden |
---|
42 | |
---|
43 | if n_params() ne 2 then begin |
---|
44 | message, 'Need widget user name and value.', /continue |
---|
45 | return |
---|
46 | endif |
---|
47 | |
---|
48 | id = widget_info(self.top, find_by_uname=uname) |
---|
49 | widget_control, id, set_value=value |
---|
50 | end |
---|
51 | |
---|
52 | |
---|
53 | |
---|
54 | ;============================================================================= |
---|
55 | ;+ |
---|
56 | ; Runs IDLdoc, given the parameters set in the xIDLdoc UI. IDLdoc |
---|
57 | ; messages, warnings and errors are displayed in the IDL output |
---|
58 | ; log. It is assumed that the user has IDLdoc installed, either in |
---|
59 | ; their path, or already compiled in memory. |
---|
60 | ;- |
---|
61 | pro xidldoc::run |
---|
62 | compile_opt idl2, hidden |
---|
63 | |
---|
64 | ;; Get widget values. |
---|
65 | root = self->get_value('root') |
---|
66 | overview = self->get_value('overview') |
---|
67 | output = self->get_value('output') |
---|
68 | title = self->get_value('title') |
---|
69 | subtitle = self->get_value('subtitle') |
---|
70 | footer = self->get_value('footer') |
---|
71 | user = self->get_value('user') |
---|
72 | embed = self->get_value('embed') |
---|
73 | stats = self->get_value('stats') |
---|
74 | quiet = self->get_value('quiet') |
---|
75 | silent = self->get_value('silent') |
---|
76 | navbar = self->get_value('navbar') |
---|
77 | browse = self->get_value('browse') |
---|
78 | |
---|
79 | ;; Do more parameter checking here? |
---|
80 | |
---|
81 | ;; Set up the call to IDLdoc. |
---|
82 | keys = create_struct('root', root, 'title', title, 'subtitle', subtitle, $ |
---|
83 | 'user', user, 'embed', embed, 'statistics', stats, $ |
---|
84 | 'quiet', quiet, 'silent', silent, $ |
---|
85 | 'nonavbar', ~navbar, 'browse_routines', browse) |
---|
86 | if overview ne '' then keys = create_struct(keys, 'overview', overview) |
---|
87 | if output ne '' then keys = create_struct(keys, 'output', output) |
---|
88 | if footer ne '' then keys = create_struct(keys, 'footer', footer) |
---|
89 | idldoc, _extra=keys |
---|
90 | end |
---|
91 | |
---|
92 | |
---|
93 | |
---|
94 | ;============================================================================= |
---|
95 | ;+ |
---|
96 | ; Handles events in the xIDLdoc UI. All events generated in the UI |
---|
97 | ; pass through the wrapper routine HANDLE_EVENTS and arrive here, |
---|
98 | ; where the event is parsed based on the generating widget's user |
---|
99 | ; name. |
---|
100 | ; |
---|
101 | ; @param event {in}{required}{type=structure} The event structure |
---|
102 | ; passed from XMANAGER. |
---|
103 | ;- |
---|
104 | pro xidldoc::handle_events, event |
---|
105 | compile_opt idl2, hidden |
---|
106 | |
---|
107 | uname = widget_info(event.id, /uname) |
---|
108 | case uname of |
---|
109 | 'run': self->run |
---|
110 | 'cancel': widget_control, self.top, /destroy |
---|
111 | 'draw': self->display |
---|
112 | 'root_browse': begin |
---|
113 | dir = dialog_pickfile(/directory, dialog_parent=self.top, $ |
---|
114 | title='Select IDLdoc Root Directory') |
---|
115 | if ~dir then return |
---|
116 | self->set_value, 'root', dir |
---|
117 | output = self->get_value('output') |
---|
118 | if ~output then self->set_value, 'output', dir |
---|
119 | end |
---|
120 | 'overview_browse': begin |
---|
121 | root = self->get_value('root') |
---|
122 | file = dialog_pickfile(dialog_parent=self.top, /must_exist, $ |
---|
123 | path=root, title='Select Overview File') |
---|
124 | if ~file then return |
---|
125 | self->set_value, 'overview', file |
---|
126 | end |
---|
127 | 'output_browse': begin |
---|
128 | root = self->get_value('root') |
---|
129 | dir = dialog_pickfile(/directory, dialog_parent=self.top, $ |
---|
130 | title='Select IDLdoc Output Directory', $ |
---|
131 | path=root) |
---|
132 | if ~dir then return |
---|
133 | self->set_value, 'output', dir |
---|
134 | end |
---|
135 | 'footer_browse': begin |
---|
136 | root = self->get_value('root') |
---|
137 | file = dialog_pickfile(dialog_parent=self.top, /must_exist, $ |
---|
138 | path=root, title='Select Footer File') |
---|
139 | if ~file then return |
---|
140 | self->set_value, 'footer', file |
---|
141 | end |
---|
142 | else: |
---|
143 | endcase |
---|
144 | end |
---|
145 | |
---|
146 | |
---|
147 | |
---|
148 | ;============================================================================= |
---|
149 | ;+ |
---|
150 | ; Destroys the UI and cleans up any resources associated with it. |
---|
151 | ; Destroys the object in this case, as well. |
---|
152 | ; |
---|
153 | ; <p> This method is called by XMANAGER through the widget cleanup routine |
---|
154 | ; CLEANUP_WIDGETS. |
---|
155 | ; |
---|
156 | ; @param top {in}{type=long} The top-level base widget identifier, |
---|
157 | ; required in the call by XMANAGER. |
---|
158 | ;- |
---|
159 | pro xidldoc::cleanup_widgets, top |
---|
160 | compile_opt idl2, hidden |
---|
161 | |
---|
162 | obj_destroy, self |
---|
163 | end |
---|
164 | |
---|
165 | |
---|
166 | |
---|
167 | ;============================================================================= |
---|
168 | ;+ |
---|
169 | ; Calls XMANAGER to register xIDLdoc's widget interface. Events are |
---|
170 | ; passed through the wrapper routine HANDLE_EVENTS. The kill_notify |
---|
171 | ; signal is passed through CLEANUP_WIDGETS. |
---|
172 | ; |
---|
173 | ; <p> Note that the NO_BLOCK keyword is ignored by IDL Runtime/Virtual |
---|
174 | ; Machine for IDL < 6.0. |
---|
175 | ; |
---|
176 | ; @uses HANDLE_EVENTS, CLEANUP_WIDGETS |
---|
177 | ;- |
---|
178 | pro xidldoc::start_xmanager |
---|
179 | compile_opt idl2, hidden |
---|
180 | |
---|
181 | xmanager, obj_class(self), self.top, $ |
---|
182 | /no_block, $ |
---|
183 | event_handler='handle_events', $ |
---|
184 | cleanup='cleanup_widgets' |
---|
185 | end |
---|
186 | |
---|
187 | |
---|
188 | |
---|
189 | ;============================================================================= |
---|
190 | ;+ |
---|
191 | ; Displays the header image in the draw window, if present. |
---|
192 | ;- |
---|
193 | pro xidldoc::display |
---|
194 | compile_opt idl2, hidden |
---|
195 | |
---|
196 | device, get_decomposed=odec |
---|
197 | if odec eq 0 then begin |
---|
198 | tvlct, r, g, b, /get |
---|
199 | loadct, 0, /silent |
---|
200 | endif |
---|
201 | if self.has_image then tv, *self.image, true=1 |
---|
202 | if odec eq 0 then tvlct, r, g, b |
---|
203 | end |
---|
204 | |
---|
205 | |
---|
206 | |
---|
207 | ;============================================================================= |
---|
208 | ;+ |
---|
209 | ; Realizes the widget hierarchy. |
---|
210 | ;- |
---|
211 | pro xidldoc::realize |
---|
212 | compile_opt idl2, hidden |
---|
213 | |
---|
214 | widget_control, self.top, /realize |
---|
215 | if self.has_image then begin |
---|
216 | widget_control, self.draw, get_value=window_id |
---|
217 | self.win_id = window_id |
---|
218 | endif |
---|
219 | end |
---|
220 | |
---|
221 | |
---|
222 | |
---|
223 | ;============================================================================= |
---|
224 | ;+ |
---|
225 | ; Centers the UI on the display. |
---|
226 | ;- |
---|
227 | pro xidldoc::center_ui |
---|
228 | compile_opt idl2, hidden |
---|
229 | |
---|
230 | geom = widget_info(self.top, /geometry) |
---|
231 | ss = get_screen_size() |
---|
232 | xoffset = ((ss[0] - geom.scr_xsize)/2) > 0 |
---|
233 | yoffset = ((ss[1] - geom.scr_ysize)/2) > 0 |
---|
234 | widget_control, self.top, xoffset=xoffset, yoffset=yoffset |
---|
235 | end |
---|
236 | |
---|
237 | |
---|
238 | |
---|
239 | ;============================================================================= |
---|
240 | ;+ |
---|
241 | ; Makes a UI element consisting of a label, a text field and a |
---|
242 | ; "Browse" button. |
---|
243 | ; |
---|
244 | ; @todo Make this into a compound widget. |
---|
245 | ; |
---|
246 | ; @param parent {in}{required}{type=long} The widget identifier |
---|
247 | ; of the parent base of this group of widgets. |
---|
248 | ; @param label {in}{required}{type=string} The text to display in |
---|
249 | ; the label widget. |
---|
250 | ; @param text {in}{required}{type=string} The text to display in |
---|
251 | ; the text widget. |
---|
252 | ; @keyword no_button {in}{optional}{type=boolean} Set to not |
---|
253 | ; display the "Browse" button. |
---|
254 | ;- |
---|
255 | pro xidldoc::make_input_row, parent, label, text, no_button=no_button |
---|
256 | compile_opt idl2, hidden |
---|
257 | |
---|
258 | under_base = widget_base(parent, /row) |
---|
259 | base = widget_base(under_base, /row, space=5) |
---|
260 | labl = widget_label(base, value=label+':', $ |
---|
261 | font=self->select_font(/bold)) |
---|
262 | text = widget_text(base, value=text, xsize=40, /editable, $ |
---|
263 | uname=strlowcase(label)) |
---|
264 | button_base = widget_base(under_base, /row, map=~keyword_set(no_button)) |
---|
265 | butn = widget_button(button_base, value='Browse', $ |
---|
266 | uname=strlowcase(label)+'_browse') |
---|
267 | end |
---|
268 | |
---|
269 | |
---|
270 | |
---|
271 | ;============================================================================= |
---|
272 | ;+ |
---|
273 | ; Returns a string containing the name of a font that can be used in a |
---|
274 | ; label or text widget. |
---|
275 | ; |
---|
276 | ; @todo Make this into an independent function outside this class |
---|
277 | ; definition. |
---|
278 | ; |
---|
279 | ; @keyword big {in}{optional}{type=boolean} Set this keyword to get |
---|
280 | ; a larger font. |
---|
281 | ; @keyword bold {in}{optional}{type=boolean} Set this keyword to get |
---|
282 | ; a bold font. |
---|
283 | ; @returns A string giving the name of the font. |
---|
284 | ;- |
---|
285 | function xidldoc::select_font, big=big, bold=bold |
---|
286 | compile_opt idl2, hidden |
---|
287 | |
---|
288 | case self.os of |
---|
289 | 'windows' : begin |
---|
290 | font = 'Helvetica' |
---|
291 | if keyword_set(big) then font += '*36' else font += '*14' |
---|
292 | if keyword_set(bold) then font += '*Bold' |
---|
293 | return, font |
---|
294 | end |
---|
295 | 'unix' : begin |
---|
296 | if keyword_set(big) then font = '9x15' else font = '6x13' |
---|
297 | if keyword_set(bold) then font += 'bold' |
---|
298 | return, font |
---|
299 | end |
---|
300 | else: |
---|
301 | endcase |
---|
302 | end |
---|
303 | |
---|
304 | |
---|
305 | |
---|
306 | ;============================================================================= |
---|
307 | ;+ |
---|
308 | ; Builds the widget hierarchy. Lots of buttons and fields. |
---|
309 | ;- |
---|
310 | pro xidldoc::build_widgets |
---|
311 | compile_opt idl2, hidden |
---|
312 | |
---|
313 | self.top = widget_base(title='IDLdoc', /column, base_align_right=0, $ |
---|
314 | xpad=10, ypad=10) |
---|
315 | widget_control, self.top, set_uvalue=self |
---|
316 | |
---|
317 | if self.has_image then begin |
---|
318 | self.draw = widget_draw(self.top, xsize=self.image_xs, $ |
---|
319 | ysize=self.image_ys, graphics_level=0, $ |
---|
320 | retain=0, /expose_events, uname='draw') |
---|
321 | endif else begin |
---|
322 | self.draw = -1 |
---|
323 | label = widget_label(self.top, value=' ') |
---|
324 | label_row = widget_base(self.top, /row, /align_left, space=15) |
---|
325 | label = widget_label(label_row, value='IDLdoc', $ |
---|
326 | font=self->select_font(/big, /bold)) |
---|
327 | label_col = widget_base(label_row, /column, /align_bottom, ypad=5) |
---|
328 | label = widget_label(label_col, $ |
---|
329 | value='An IDL documentation system.', $ |
---|
330 | font=self->select_font()) |
---|
331 | label = widget_label(self.top, value=' ') |
---|
332 | endelse |
---|
333 | |
---|
334 | base = widget_base(self.top, /column, /base_align_right) |
---|
335 | |
---|
336 | self->make_input_row, base, 'Root', '.' |
---|
337 | self->make_input_row, base, 'Overview', '' |
---|
338 | self->make_input_row, base, 'Output', '' |
---|
339 | self->make_input_row, base, 'Title', 'Research Systems, Inc.', $ |
---|
340 | /no_button |
---|
341 | self->make_input_row, base, 'Subtitle', 'IDL ' + !version.release, $ |
---|
342 | /no_button |
---|
343 | self->make_input_row, base, 'Footer', '' |
---|
344 | |
---|
345 | doc_level_base = widget_base(self.top, /row) |
---|
346 | label = widget_label(doc_level_base, value='Documentation level:', $ |
---|
347 | font=self->select_font(/bold)) |
---|
348 | |
---|
349 | butn_base = widget_base(doc_level_base, /row, /exclusive) |
---|
350 | butn = widget_button(butn_base, value='User', uname='user') |
---|
351 | butn = widget_button(butn_base, value='Developer', uname='developer') |
---|
352 | widget_control, butn, set_button=1 |
---|
353 | |
---|
354 | options_base = widget_base(self.top, /row, space=5) |
---|
355 | label = widget_label(options_base, value='Options: ', $ |
---|
356 | font=self->select_font(/bold)) |
---|
357 | |
---|
358 | check_base1 = widget_base(options_base, /column, /nonexclusive) |
---|
359 | butn = widget_button(check_base1, value='Embed', uname='embed') |
---|
360 | butn = widget_button(check_base1, value='Statistics', uname='stats', $ |
---|
361 | sensitive=0s) |
---|
362 | |
---|
363 | check_base2 = widget_base(options_base, /column, /nonexclusive) |
---|
364 | butn = widget_button(check_base2, value='Quiet', uname='quiet') |
---|
365 | butn = widget_button(check_base2, value='Silent', uname='silent') |
---|
366 | |
---|
367 | check_base3 = widget_base(options_base, /column, /nonexclusive) |
---|
368 | butn = widget_button(check_base3, value='Navigation Bar', uname='navbar') |
---|
369 | widget_control, butn, set_button=1 |
---|
370 | butn = widget_button(check_base3, value='Browse Window', uname='browse') |
---|
371 | |
---|
372 | choice = widget_base(self.top, /row, frame=0, /align_right) |
---|
373 | run = widget_button(choice, value='Run IDLdoc...', uname='run', xsize=100) |
---|
374 | cancel = widget_button(choice, value='Cancel', uname='cancel', xsize=100) |
---|
375 | end |
---|
376 | |
---|
377 | |
---|
378 | |
---|
379 | ;============================================================================= |
---|
380 | ;+ |
---|
381 | ; The actual class destructor. All cleanup code goes here, since it |
---|
382 | ; can be called directly. |
---|
383 | ;- |
---|
384 | pro xidldoc::destruct |
---|
385 | compile_opt idl2, hidden |
---|
386 | |
---|
387 | if ptr_valid(self.image) then ptr_free, self.image |
---|
388 | end |
---|
389 | |
---|
390 | |
---|
391 | |
---|
392 | ;============================================================================= |
---|
393 | ;+ |
---|
394 | ; The official class destructor. This method can't be called |
---|
395 | ; directly, however, so all code is placed in the |
---|
396 | ; <code>destruct</code> method instead. |
---|
397 | ;- |
---|
398 | pro xidldoc::cleanup |
---|
399 | compile_opt idl2, hidden |
---|
400 | |
---|
401 | self->destruct |
---|
402 | end |
---|
403 | |
---|
404 | |
---|
405 | |
---|
406 | ;============================================================================= |
---|
407 | ;+ |
---|
408 | ; Class constructor, used to load class data. Only one instance of |
---|
409 | ; xIDLdoc can run at any time. |
---|
410 | ; |
---|
411 | ; <p> Note that only a pixel-interleaved RGB image can be displayed at |
---|
412 | ; the top of the interface. |
---|
413 | ; |
---|
414 | ; @keyword header_image {in}{optional}{type=RGB image} A |
---|
415 | ; pixel-interleaved RGB image to be displayed at the top of the |
---|
416 | ; xIDLdoc interface. |
---|
417 | ; @returns 1 on success, 0 on failure. |
---|
418 | ;- |
---|
419 | function xidldoc::init, header_image=image |
---|
420 | compile_opt idl2, hidden |
---|
421 | |
---|
422 | if xregistered(obj_class(self)) then return, 0 |
---|
423 | |
---|
424 | self.os = strlowcase(!version.os_family) ;; 'windows' or 'unix' |
---|
425 | |
---|
426 | if n_elements(image) ne 0 then begin |
---|
427 | info = size(image, /structure) |
---|
428 | fail = 0 |
---|
429 | if info.dimensions[0] ne 3 then ++fail |
---|
430 | if info.n_dimensions ne 3 then ++fail |
---|
431 | if fail eq 0 then begin |
---|
432 | self.has_image = 1 |
---|
433 | self.image = ptr_new(image) |
---|
434 | self.image_xs = info.dimensions[1] |
---|
435 | self.image_ys = info.dimensions[2] |
---|
436 | endif |
---|
437 | endif |
---|
438 | |
---|
439 | self->build_widgets |
---|
440 | self->center_ui |
---|
441 | self->realize |
---|
442 | self->display |
---|
443 | if ~(lmgr(/vm) || lmgr(/runtime)) then self->start_xmanager |
---|
444 | return, 1 |
---|
445 | end |
---|
446 | |
---|
447 | |
---|
448 | |
---|
449 | ;============================================================================= |
---|
450 | ;+ |
---|
451 | ; The xIDLdoc class data definition routine. |
---|
452 | ; |
---|
453 | ; @field top The top-level base widget identifier. |
---|
454 | ; @field draw The draw widget identifier. Only present if an image is |
---|
455 | ; to be displayed at the top of the xIDLdoc interface. |
---|
456 | ; @field win_id The window index of the draw widget, if present. |
---|
457 | ; @field has_image 1 if an image is present, 0 otherwise. |
---|
458 | ; @field image A pointer to the image data. |
---|
459 | ; @field image_xs The xsize of the image. |
---|
460 | ; @field image_ys The ysize of the image. |
---|
461 | ; @field os The operating system IDL is running on. |
---|
462 | ;- |
---|
463 | pro xidldoc__define |
---|
464 | compile_opt idl2, hidden |
---|
465 | |
---|
466 | a = { xidldoc, $ |
---|
467 | top : 0, $ |
---|
468 | draw : 0, $ |
---|
469 | win_id : 0, $ |
---|
470 | has_image : 0, $ |
---|
471 | image : ptr_new(), $ |
---|
472 | image_xs : 0, $ |
---|
473 | image_ys : 0, $ |
---|
474 | os : '' $ |
---|
475 | } |
---|
476 | end |
---|
477 | |
---|
478 | |
---|
479 | |
---|
480 | ;============================================================================= |
---|
481 | ;+ |
---|
482 | ; This is a wrapper for simplifying the creation and use of an |
---|
483 | ; <code>xIDLdoc</code> object. |
---|
484 | ; |
---|
485 | ; @file_comments xIDLdoc is a graphical front-end for IDLdoc, the IDL |
---|
486 | ; documentation system developed by Mike Galloy of RSI. |
---|
487 | ; |
---|
488 | ; <p> To use xIDLdoc, IDLdoc should already be installed in a user's |
---|
489 | ; path or compiled in memory. IDLdoc messages, warnings and errors are |
---|
490 | ; displayed in the IDL output log. |
---|
491 | ; |
---|
492 | ; @keyword no_image {in}{optional}{type=boolean} Set this keyword so |
---|
493 | ; that no image is displayed at the top of the xIDLdoc interface. |
---|
494 | ; @examples |
---|
495 | ; <pre> |
---|
496 | ; IDL> xidldoc |
---|
497 | ; </pre> |
---|
498 | ; |
---|
499 | ; @pre IDLdoc must be in the user's path or already compiled in the |
---|
500 | ; user's IDL session. |
---|
501 | ; @uses Michael D. Galloy's IDLdoc. IDLdoc can be downloaded for free |
---|
502 | ; from the RSI codebank: <code>(www.rsinc.com/codebank)</code>. |
---|
503 | ; @requires IDL 6.0 |
---|
504 | ; @author Mark Piper, RSI, 2004 |
---|
505 | ;- |
---|
506 | pro xidldoc, no_image=no_image |
---|
507 | compile_opt idl2, logical_predicate |
---|
508 | |
---|
509 | home = sourceroot() |
---|
510 | |
---|
511 | if ~keyword_set(no_image) then begin |
---|
512 | file = home + 'idldoc_splash1.png' |
---|
513 | if file_test(file) then begin |
---|
514 | splash_color = read_image(file) |
---|
515 | odoc = obj_new('xidldoc', header_image=splash_color) |
---|
516 | endif |
---|
517 | endif else $ |
---|
518 | odoc = obj_new('xidldoc') |
---|
519 | |
---|
520 | if ~obj_valid(odoc) then return |
---|
521 | |
---|
522 | ;; Start XMANAGER last in runtime/vm mode for IDL < 6.1. |
---|
523 | if lmgr(/vm) || lmgr(/runtime) then odoc->start_xmanager |
---|
524 | end |
---|