telescope-term 0.7 → 1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. checksums.yaml +4 -4
  2. data/bin/telescope +479 -606
  3. metadata +13 -19
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 408d3c474e9618022c328cdf98a68d2c0d1922951ab422229158ed8ca882d022
4
- data.tar.gz: 84f8679e4d86425f948c0a314ab5e7a8bedef62af0c170dafe3370d3f0317551
3
+ metadata.gz: 6a927518be7d857221796c64555e4fec64668911d1279ac9f116ce7b53e17d7d
4
+ data.tar.gz: c5107d1239cde8bc48b26e7daefb13ed0d65f16e2fe2bbbde1567f96ac79656b
5
5
  SHA512:
6
- metadata.gz: 3f0150614eeb44975ea19fd3bd61a7caf43349f5d9c7de50e6d174780c589926476ad77408cfa1cb9a4ae873dcd832994a18725b252a7aee4b5f2f575a5ba5d7
7
- data.tar.gz: 3ed63758d445eeaf494c14ebdc13543c1c2060a798230f7b16e55101beb7c777187e29c8c0e17e3e5a0ddeefb3cc3d0ca4688b98b375fe1faecb9e7e67635cec
6
+ metadata.gz: 230a99f5e65020b070110bf2b234638a44fc47f0f9f799f7b7114f2f8b9bda342952d5e1d4a9257bfdff69bcc5404cac76923b823809245ee59cd885b9e70240
7
+ data.tar.gz: 9c2f836f026ca88f523cd296290a8f7ac64f3ed813002b6575732b7c5624060a6a9f3f053931cf706efbdc31d2e6328df99395c7671260994f3a09fb78370485
data/bin/telescope CHANGED
@@ -1,637 +1,510 @@
1
1
  #!/usr/bin/env ruby
2
2
  # encoding: utf-8
3
- @help = <<HELPTEXT
4
- WELCOME TO TELESCOPE - A TERMINAL/CONSOLE PROGRAM FOR THE AMATEUR ASTRONOMER.
5
- The top panel lists your telescopes with eyepieces in the lower panel. Add a telescope by pressing 't' and fill in the name, the
6
- apperature (APP) and the focal length (FL) in the "command line" at the bottom and press ENTER. Add an eyepiece with 'e' and enter
7
- a name, the focal length (FL) and apparent field of view (AFOV) and press ENTER. Select items by using the TAB/UP/DOWN cursor keys.
8
- Press ENTER on a selected item to change the values in the command line. Delete an item by pressing 'D'. Move an with PgUP/PgDown keys.
9
- Sort telescopes with 'T' (toggles sorting by the first thre columns; Name, APP, FL). Sort eyepieces in the same way with the 'E' key.
10
- Tag items with the SPACE key (untag all with 'u'), then press 'o' to create an observation log file (content shown in the lower panel).
11
- Refresh all panels with the 'r' key. Escape the selected panels or the command line by pressing 'Ctrl-G'. Quit via 'q' (or 'Q' if you
12
- don't want to save your edits since last session). Save a backup session with 'b' and load a saved backup session with the 'B' key.
13
- Telescope and eyepiece data is saved in the file '.telescope' in your home directory (backup file is '.telescope.bu').
14
-
15
- LIST OF TELESCOPE ABBREVIATIONS: LIST OF EYEPIECE ABBREVIATIONS:
16
- APP, FL, F/? = Apperature and Focal Length (millimeters) and F-ratio FL = Focal Length (in millimeters)
17
- <MAG = Maximum magnitude visible AFOV = Apparent Field Of View
18
- xEYE = Light gathering compared to the human eye xMAGN = Magnification (with that telescope)
19
- MINx, MAXx = Minimum and maximum usable magnification FOV = True Field Of View (deg/min/sec)
20
- XPUP = Exit pupil (in millimeters)
21
- Recommended magnifications for objects:
22
- *FIELD = star fields, GX/NEB = galaxies/nebulae, PL/GCL = planets/globular clusters
23
- PLd/2* = planet details/double stars, TGHT2* = tight double stars
24
- DL/RC-SEP = Minimum separation, Dawes limit and Rayleigh limit
25
- MOON, SUN = Minimum feature resolved on the Moon (meters) & Sun (kilometers)
26
- HELPTEXT
27
- begin # BASIC SETUP
28
- if `tput cols`.to_i < 140
29
- puts "You must run Telescope with a minimum tarminal width of 140 chracters."
3
+
4
+ # SCRIPT INFO {{{1
5
+ # Name: Telescope - a tool for amateur astronomers
6
+ # Language: Pure Ruby, best viewed in VIM
7
+ # Author: Geir Isene <g@isene.com>
8
+ # Web_site: http://isene.com/
9
+ # Github: https://github.com/isene/telescope
10
+ # License: I release all copyright claims. This code is in the public domain.
11
+ # Permission is granted to use, copy modify, distribute, and sell
12
+ # this software for any purpose. I make no guarantee about the
13
+ # suitability of this software for any purpose and I am not liable
14
+ # for any damages resulting from its use. Further, I am under no
15
+ # obligation to maintain or extend this software. It is provided
16
+ # on an 'as is' basis without any expressed or implied warranty.
17
+ # Docs: Apart from the extensive documentation found on Github, you can
18
+ # get a great understanding of the code itself by simply sending
19
+ # or pasting this whole file into you favorite AI for coding with
20
+ # a prompt like this: "Help me understand every part of this code".
21
+
22
+ # SETUP {{{1
23
+ begin
24
+ require 'rcurses'
25
+ class Object
26
+ include Rcurses
27
+ include Rcurses::Input
30
28
  end
31
- require 'io/console'
32
- require 'date'
33
- require 'curses'
34
- include Curses
35
-
36
- Curses.init_screen
37
- Curses.start_color
38
- Curses.curs_set(0)
39
- Curses.noecho
40
- Curses.cbreak
41
- Curses.stdscr.keypad = true
29
+ rescue StandardError => e
30
+ puts 'Telescope is built using rcurses (https://github.com/isene/rcurses). Install rcurses to run Telescope.'
31
+ exit 1
32
+ end
33
+ Pane = Rcurses::Pane
34
+ require 'date'
42
35
 
43
- @ts = []
44
- @ep = []
45
-
46
- @tsmark = false
47
- @epmark = false
36
+ # Persistence paths
37
+ SAVE = File.join(Dir.home, '.telescope')
38
+
39
+ # HELP TEXT {{{1
40
+ HELP1 = " WELCOME TO THE TERMINAL TELESCOPE APPLICATION\n".b + '
41
+ This can help structure your telescopes and eyepieces.
42
+ It will calculate properties of your scopes and EPs.
43
+ Scope+EP combination properties are also calculated.
44
+
45
+ Anything you like to have changed or bugs fixed,
46
+ create an issue: https://github.com/isene/telescope
47
+ ...or drop me an e-mail: g@isene.com.
48
+
49
+ Press any key to show more help text.
50
+ '
48
51
 
49
- @tstag = []
50
- @eptag = []
52
+ HELP2 = " TERMININAL TELESCOPE APPLICATION\n\n Keys and their actions\n".b + '
53
+ t Add telescope (name,app,fl)
54
+ e Add eyepiece (name,fl,afov)
55
+ ENTER Edit selected
56
+ TAB Switch panels
57
+ UP/DOWN Move cursor
58
+ Shift-UP Move item up
59
+ Shift-DOWN Move item down
60
+ HOME/END Jump to start/end
61
+ o Toggle order by Telescope APP and Eyepiece FL
62
+ SPACE Tag/untag
63
+ u Untag all
64
+ Ctrl-o Create observation log with tagged equipment
65
+ D Delete item
66
+ r Refresh all panes
67
+ q/Q Quit (save/no save)
68
+ ? Help'.fg(230)
51
69
 
52
- @t_sort = false
53
- @e_sort = false
70
+ HELP3 = " Abbreviations and their meaning\n".b + '
71
+ APP = Telescope apperature (in millimeters)
72
+ TFL = Telescope focal length (in millimeters)
73
+ F/? = Telescope focal ratio
74
+ <MGN = Magnitude limit (dimmest object visible)
75
+ xEYE = Times eye light gathering
76
+ MINx = Minimum magnification
77
+ MAXx = Maximum magnification
78
+ SEP-R = Rayleigh separation criterion
79
+ SEP-D = Dawes separation limit
80
+ *FLD = EP for star fields
81
+ GLXY = EP for galaxies & nebulae
82
+ PLNT = EP for planets, globular clusters
83
+ DBL* = EP for double stars & planetary details
84
+ >2*< = EP for tight double stars
85
+ MOON = Smallest detail visible on Moon
86
+ SUN = Smallest detail visible on Sun
87
+
88
+ FL = EP focal length (in millimeters)
89
+ AFOV = EP apparent field of view
90
+ MAGX = Magnification (w/selected telescope)
91
+ TFOV = True field of view (w/selected telescope)
92
+ PPL = Exit pupil (w/selected telescope)
93
+ 2BLW = With a 2xBarlow (magnification, then rest)'.fg(229)
94
+
95
+ # CLEAR CURSES ON EXIT {{{1
96
+ at_exit do
97
+ $stdin.cooked!
98
+ $stdin.echo = true
99
+ Rcurses.clear_screen
100
+ Cursor.show
54
101
  end
55
- if File.exist?(Dir.home+'/.telescope')
56
- load(Dir.home+'/.telescope')
102
+
103
+ # INITIALIZATION {{{1
104
+ # Data stores
105
+ @ts = [] # Telescopes: [name, app, fl]
106
+ @ep = [] # Eyepieces: [name, fl, afov]
107
+ @tstag = [] # Telescope tags
108
+ @eptag = [] # Eyepiece tags
109
+ @cursor_ts = 0 # Telescope cursor index
110
+ @cursor_ep = 0 # Eyepiece cursor index
111
+
112
+ # Load saved data if present
113
+ SAVE = File.join(Dir.home, '.telescope') # Persistence path
114
+
115
+ if File.exist?(SAVE)
116
+ load SAVE # expects plaintext: @ts = [...] and @ep = [...]
117
+ else
118
+ @ts = []
119
+ @ep = []
57
120
  end
58
- class Numeric # NUMERIC CLASS EXTENSION
59
- def deg
60
- self * Math::PI / 180
61
- end
62
- def rad
63
- self * 180 / Math::PI
64
- end
65
- def dec2
66
- "%.2f" % self
67
- end
121
+
122
+ @ts_unsorted = @ts.dup
123
+ @ep_unsorted = @ep.dup
124
+
125
+ # Initialize tag arrays to match loaded data
126
+ @tstag = Array.new(@ts.size, false)
127
+ @eptag = Array.new(@ep.size, false)
128
+
129
+ # CLASS EXTENSIONS {{{1
130
+ # Numeric formatting helper
131
+ class Numeric
132
+ def deg; self * Math::PI / 180; end
133
+ def rad; self * 180 / Math::PI; end
134
+ def rts(n); format("%.#{n}f", self) end
68
135
  end
69
- class Curses::Window # CLASS EXTENSION
70
- # General extensions (see https://github.com/isene/Ruby-Curses-Class-Extension)
71
- attr_accessor :color, :fg, :bg, :attr, :update
72
- # Set self.color for an already defined color pair such as: init_pair(1, 255, 3)
73
- # The color pair is defined like this: init_pair(index, foreground, background)
74
- # self.fg is set for the foreground color (and is used if self.color is not set)
75
- # self.bg is set for the background color (and is used if self.color is not set)
76
- # self.attr is set for text attributes like Curses::A_BOLD
77
- def clr # Clears the whole window
78
- self.setpos(0, 0)
79
- self.maxy.times {self.deleteln()}
80
- self.refresh
81
- self.setpos(0, 0)
82
- end
83
- def clr_to_cur_line
84
- l = self.cury
85
- self.setpos(0, 0)
86
- l.times {self.deleteln()}
87
- self.refresh
88
- end
89
- def clr_from_cur_line
90
- l = self.cury
91
- (self.maxy - l).times {self.deleteln()}
92
- self.refresh
93
- self.setpos(l, 0)
94
- end
95
- def fill # Fill window with color as set by self.color (or self.bg if not set)
96
- self.setpos(0, 0)
97
- self.fill_from_cur_pos
98
- end
99
- def fill_to_cur_pos # Fills the window up to current line
100
- x = self.curx
101
- y = self.cury
102
- self.setpos(0, 0)
103
- blank = " " * self.maxx
104
- if self.color == nil
105
- self.bg = 0 if self.bg == nil
106
- self.fg = 255 if self.fg == nil
107
- init_pair(self.fg, self.fg, self.bg)
108
- y.times {self.attron(color_pair(self.fg)) {self << blank}}
109
- else
110
- y.times {self.attron(color_pair(self.color)) {self << blank}}
111
- end
112
- self.refresh
113
- self.setpos(y, x)
114
- end
115
- def fill_from_cur_pos # Fills the rest of the window from current line
116
- x = self.curx
117
- y = self.cury
118
- self.setpos(y, 0)
119
- blank = " " * self.maxx
120
- if self.color == nil
121
- self.bg = 0 if self.bg == nil
122
- self.fg = 255 if self.fg == nil
123
- init_pair(self.fg, self.fg, self.bg)
124
- self.maxy.times {self.attron(color_pair(self.fg)) {self << blank}}
125
- else
126
- self.maxy.times {self.attron(color_pair(self.color)) {self << blank}}
127
- end
128
- self.refresh
129
- self.setpos(y, x)
130
- end
131
- def p(text) # Puts text to window
132
- self.attr = 0 if self.attr == nil
133
- if self.color == nil
134
- self.bg = 0 if self.bg == nil
135
- self.fg = 255 if self.fg == nil
136
- init_pair(self.fg, self.fg, self.bg)
137
- self.attron(color_pair(self.fg) | self.attr) { self << text }
138
- else
139
- self.attron(color_pair(self.color) | self.attr) { self << text }
140
- end
141
- self.refresh
142
- end
143
- def pclr(text) # Puts text to window and clears the rest of the window
144
- self.p(text)
145
- self.clr_from_cur_line
146
- end
147
- def paclr(fg, bg, attr, text) # Puts text to window with full set of attributes and clears rest of window
148
- self.paclr(fg, bg, attr, text)
149
- self.clr_from_cur_line
150
- end
151
- def pa(fg, bg, attr, text) # Puts text to window with full set of attributes
152
- self.fg = fg
153
- self.bg = bg
154
- self.attr = attr
155
- init_pair(self.fg, self.fg, self.bg)
156
- self.attron(color_pair(self.fg) | self.attr) { self << text }
157
- self.refresh
136
+
137
+ # Pane class extension
138
+ module Rcurses
139
+ class Pane
140
+ attr_accessor :index
158
141
  end
159
142
  end
160
- def getchr # PROCESS KEY PRESSES
161
- c = STDIN.getch(min: 0, time: 1)
162
- case c
163
- when "\e" # ANSI escape sequences
164
- case $stdin.getc
165
- when '[' # CSI
166
- case $stdin.getc
167
- when 'A' then chr = "UP"
168
- when 'B' then chr = "DOWN"
169
- when 'C' then chr = "RIGHT"
170
- when 'D' then chr = "LEFT"
171
- when 'Z' then chr = "S-TAB"
172
- when '2' then chr = "INS" ; STDIN.getc
173
- when '3' then chr = "DEL" ; STDIN.getc
174
- when '5' then chr = "PgUP" ; STDIN.getc
175
- when '6' then chr = "PgDOWN" ; STDIN.getc
176
- when '7' then chr = "HOME" ; STDIN.getc
177
- when '8' then chr = "END" ; STDIN.getc
178
- end
179
- end
180
- when "", "" then chr = "BACK"
181
- when "" then chr = "WBACK"
182
- when "" then chr = "LDEL"
183
- when "" then chr = "C-T"
184
- when "" then chr = "C-G"
185
- when "\r" then chr = "ENTER"
186
- when "\t" then chr = "TAB"
187
- when /./ then chr = c
188
- end
189
- return chr
143
+
144
+ # OPTICAL FORMULAS {{{1
145
+ def tfr(app, tfl); (tfl.to_f / app); end
146
+ def mlim(app); (5 * Math::log(app / 10, 10) + 7.5); end
147
+ def xeye(app); (app.to_f ** 2 / 49); end
148
+ def minx(app, tfl); (tfl / (7 * tfr(app, tfl))); end
149
+ def mine(app, tfl); (7 * tfr(app, tfl)); end
150
+ def maxx(app); (2 * app.to_f); end
151
+ def maxe(app, tfl); (tfl / maxx(app)); end
152
+ def sepr(app); (3600.0 * Math::asin(671E-6 / app).rad); end
153
+ def sepd(app); (115.824 / app); end
154
+ def e_st(app, tfl); (6.4 * tfl / app); end
155
+ def e_gx(app, tfl); (3.6 * tfl / app); end
156
+ def e_pl(app, tfl); (2.1 * tfl / app); end
157
+ def e_2s(app, tfl); (1.3 * tfl / app); end
158
+ def e_t2(app, tfl); (0.7 * tfl / app); end
159
+ def moon(tfl); (384E6*Math::tan((115.824.deg / tfl)/360)); end
160
+ def sun(tfl); (moon(tfl) / 2.5668); end
161
+ def tfov(tfl, epfl, afov); (afov.to_f / magx(tfl, epfl)); end
162
+ def pupl(app, tfl, epfl); (app.to_f / magx(tfl, epfl)); end
163
+ def magx(tfl, epfl); (tfl.to_f / epfl); end
164
+
165
+ # FUNCTIONS {{{1
166
+ def refresh_all #{{{2
167
+ Rcurses.clear_screen
168
+ @pTS.border = false
169
+ @pEP.border = false
170
+ @focus.border = true
171
+ @pTS.full_refresh
172
+ @pTSh.full_refresh
173
+ @pEP.full_refresh
174
+ @pEPh.full_refresh
175
+ @pST.refresh
190
176
  end
191
- def main_getkey # GET KEY FROM USER
192
- chr = getchr
193
- case chr
194
- when '?' # Show helptext in lower panel
195
- @w_ep.clr
196
- @w_ep.pa(249, 0, 0, @help)
197
- @w_ep.p("\n ...Press any key to continue")
198
- getch
199
- when 'TAB' # Move between the panels
200
- if @tsmark
201
- @tsmark = false
202
- @epmark = 0
203
- elsif @epmark
204
- @epmark = false
205
- @tsmark = false
206
- else
207
- @tsmark = 0
208
- @epmark = false
209
- end
210
- when 'C-G' # Escape from panel selections or command line
211
- @epmark = false
212
- @tsmark = false
213
- when 'ENTER' # Edit selected item in the command line (or refresh panels)
214
- if @tsmark
215
- out = "#{@ts[@tsmark][0]}, #{@ts[@tsmark][1]}, #{@ts[@tsmark][2]}"
216
- ret = w_cm_getstr("", out).split(",")
217
- return if ret.length != 3
218
- ret[1] = ret[1].to_i
219
- ret[2] = ret[2].to_i
220
- @ts[@tsmark] = ret
221
- elsif @epmark
222
- out = "#{@ep[@epmark][0]}, #{@ep[@epmark][1]}, #{@ep[@epmark][2]}"
223
- ret = w_cm_getstr("", out).split(",")
224
- return if ret.length != 3
225
- ret[1] = ret[1].to_f
226
- ret[2] = ret[2].to_i
227
- @ep[@epmark] = ret
228
- end
229
- when 't' # Add a telescope
230
- return if @ts.length == 5
231
- ret = w_cm_getstr("", "Telescope, App, FL").split(",")
232
- return if ret.length != 3
233
- ret[1] = ret[1].to_i
234
- ret[2] = ret[2].to_i
235
- ret[1] = 1 if ret[1] == 0
236
- ret[2] = 1 if ret[2] == 0
237
- @ts[@ts.length] = ret
238
- when 'e' # Add an eyepiece
239
- ret = w_cm_getstr("", "Eyepiece, FL, AFOV").split(",")
240
- return if ret.length != 3
241
- ret[1] = ret[1].to_f
242
- ret[2] = ret[2].to_i
243
- ret[1] = 1 if ret[1] == 0
244
- ret[2] = 1 if ret[2] == 0
245
- @ep[@ep.length] = ret
246
- when 'D' # Delete selected item (telescope or eyepiece)
247
- if @tsmark
248
- @ts.delete_at(@tsmark)
249
- @tsmark -= 1
250
- elsif @epmark
251
- @ep.delete_at(@epmark)
252
- @epmark -= 1
253
- end
254
- when 'T' # Sort telescopes by next column (Name, APP, FL)
255
- if @t_sort == false or @t_sort == 2
256
- @t_sort = 0
257
- else
258
- @t_sort += 1
259
- end
260
- @ts = @ts.sort {|a,b| b[@t_sort] <=> a[@t_sort]}
261
- when 'E' # Sort eyepiece by next column (Name, FL, AFOV)
262
- if @e_sort == false or @e_sort == 2
263
- @e_sort = 0
264
- else
265
- @e_sort += 1
266
- end
267
- @ep = @ep.sort {|a,b| b[@e_sort] <=> a[@e_sort]}
268
- when 'UP' # Move to one item up
269
- if @tsmark
270
- if @tsmark == 0
271
- @tsmark = false
272
- else
273
- @tsmark -= 1
274
- end
275
- elsif @epmark
276
- if @epmark == 0
277
- @epmark = false
278
- @tsmark = @ts.length - 1
279
- else
280
- @epmark -= 1
281
- end
282
- else
283
- @epmark = @ep.length - 1
284
- end
285
- when 'DOWN' # Move to one item down
286
- if @tsmark
287
- if @tsmark == @ts.length - 1
288
- @tsmark = false
289
- @epmark = 0
290
- else
291
- @tsmark += 1
292
- end
293
- elsif @epmark
294
- if @epmark == @ep.length - 1
295
- @epmark = false
296
- else
297
- @epmark += 1
298
- end
299
- else
300
- @tsmark = 0
301
- end
302
- when 'PgUP' # Move selected item up by one
303
- if @tsmark
304
- t = @ts.delete_at(@tsmark)
305
- @tsmark -= 1 unless @tsmark == 0
306
- @ts.insert(@tsmark, t)
307
- elsif @epmark
308
- e = @ep.delete_at(@epmark)
309
- @epmark -= 1 unless @epmark == 0
310
- @ep.insert(@epmark, e)
311
- end
312
- when 'PgDOWN' # Move selected item by one down
313
- if @tsmark
314
- t = @ts.delete_at(@tsmark)
315
- @tsmark += 1 unless @tsmark == @ts.length
316
- @ts.insert(@tsmark, t)
317
- elsif @epmark
318
- e = @ep.delete_at(@epmark)
319
- @epmark += 1 unless @epmark == @ep.length
320
- @ep.insert(@epmark, e)
321
- end
322
- when 'HOME' # Jump to first item in the panel
323
- if @tsmark
324
- @tsmark = 0
325
- elsif @epmark
326
- @epmark = 0
327
- end
328
- when 'END' # Move to last item in the panel
329
- if @tsmark
330
- @tsmark = @ts.length - 1
331
- elsif @epmark
332
- @epmark = @ep.length - 1
333
- end
334
- when ' ' # Tag selected item to be used in observation file/log
335
- if @tsmark
336
- @tstag.include?(@tsmark) ? @tstag.delete(@tsmark) : @tstag.push(@tsmark)
337
- @tsmark += 1 unless @tsmark == @ts.length - 1
338
- elsif @epmark
339
- @eptag.include?(@epmark) ? @eptag.delete(@epmark) : @eptag.push(@epmark)
340
- @epmark += 1 unless @epmark == @ep.length - 1
341
- end
342
- when 'u' # Untag all tagget items
343
- @tstag.clear
344
- @eptag.clear
345
- when 'o' # Create observation file/log and show content in lower panel
346
- observe
347
- when 'b' # Create backup file (~/.telescope.bu) with current items
348
- File.write(Dir.home+'/.telescope.bu',"@ts = #{@ts}\n@ep = #{@ep}")
349
- when 'B' # Read items from backup file
350
- if File.exist?(Dir.home+'/.telescope.bu')
351
- load(Dir.home+'/.telescope.bu')
352
- end
353
- when 'r' # Hard refres panels
354
- @break = true
355
- when 'q' # Exit after saving items to ~/.telescope
356
- File.write(Dir.home+'/.telescope',"@ts = #{@ts}\n@ep = #{@ep}")
357
- exit 0
358
- when 'Q' # Exit without saving items
359
- exit 0
360
- else
177
+
178
+ def render_ts #{{{2
179
+ @pTS.clear
180
+ @ts.each_with_index do |t, i|
181
+ @pTS.text += "\n"
182
+ name = t[0]
183
+ app = t[1].to_i
184
+ tfl = t[2].to_i
185
+ tag_ts = @tstag[i] ? ' ' + '▐'.b.fg(46) : ' '
186
+ txt = tag_ts
187
+ txt += name.to_s.ljust(18)
188
+ txt += app.to_s.rjust(7)
189
+ txt += tfl.to_s.rjust(8)
190
+ txt += tfr(app, tfl).rts(1).rjust(6)
191
+ txt += mlim(app).rts(1).rjust(6)
192
+ txt += xeye(app).rts(0).rjust(6)
193
+ min = mine(app, tfl).rts(0)
194
+ min += "(" + minx(app, tfl).rts(0) + "x)"
195
+ txt += min.rjust(10)
196
+ max = maxe(app, tfl).rts(0)
197
+ max += "(" + maxx(app).rts(0) + "x)"
198
+ txt += max.rjust(9)
199
+ txt += sepr(app).rts(2).rjust(7) + '"'
200
+ txt += sepd(app).rts(2).rjust(6) + '"'
201
+ txt += e_st(app, tfl).rts(0).rjust(7)
202
+ txt += e_gx(app, tfl).rts(0).rjust(6)
203
+ txt += e_pl(app, tfl).rts(0).rjust(6)
204
+ txt += e_2s(app, tfl).rts(0).rjust(6)
205
+ txt += e_t2(app, tfl).rts(0).rjust(6)
206
+ txt += moon(tfl).rts(0).rjust(7)
207
+ txt += sun(tfl).rts(0).rjust(6)
208
+ txt[0] = '→' if i == @pTS.index
209
+ # ANSI safe padding
210
+ pad = @pTS.w - Rcurses.display_width(txt.pure)
211
+ pad = 0 if pad.negative?
212
+ txt += ' ' * pad
213
+ txt = txt.bg(234) if i == @pTS.index
214
+ txt = txt.fg(248) if i != @pTS.index
215
+ @pTS.text += txt
361
216
  end
217
+ @pTS.refresh
218
+ @pTSh.full_refresh
362
219
  end
363
- def observe
364
- @tstag = @tstag.sort
365
- @eptag = @eptag.sort
366
- date = DateTime.now.strftime "%Y-%m-%d"
367
- file = Dir.home + "/" + date + "_observation.txt"
368
- obs = "Observation file: #{file}\n"
369
- obs += "Observation date:\n\n"
370
- obs += "This file lists the intended equipment for the observation date.\n"
371
- obs += "Reference observations with telescope letter and eyepiece numbers (like A2, B1, etc.)\n\n"
372
- obs += "─" * 100 + "\n"
373
- enum = "ABCDE"
374
- @tstag.each_with_index do |t, i|
375
- d = @ts[t][1]
376
- f = @ts[t][2]
377
- obs += "Telescope (#{enum[i]}): " + @ts[t][0].ljust(15) + " ("
378
- obs += d.to_s + "mm/" + f.to_s + "mm f/" + (f/d.to_f).truncate(1).to_s + ")"
379
- mag = (5 * Math::log(d/10, 10) + 7.5).truncate(1).to_s
380
- obs += " Max MAG: " + mag
381
- sepd = (115.824/d).truncate(2).to_s
382
- sepr = (3600*Math::asin(671E-6/d).rad).truncate(2).to_s
383
- obs += " Min SEP: " + sepd + "/" + sepr + "\n"
384
- end
385
- obs += "No telescope(s) chosen for the observation\n" if @tstag.empty?
386
- obs += "─" * 100 + "\n"
387
- @eptag.each_with_index do |e, i|
388
- m = @ep[e][1]
389
- a = @ep[e][2]
390
- obs += "Eyepiece (#{i+1}): " + @ep[e][0].ljust(15) + " ("
391
- obs += m.to_s.rjust(4) + "mm/" + a.to_s.rjust(3) + "°) "
392
- @tstag.each_with_index do |t, j|
393
- d = @ts[t][1]
394
- f = @ts[t][2]
395
- obs += enum[j] + ": "
396
- mag = (f.to_f/m)
397
- obs += mag.truncate(1).to_s.rjust(5) + "x ("
398
- fov = a/mag
399
- deg = fov.to_i
400
- mins = ((fov - fov.to_i) * 60)
401
- min = mins.to_i
402
- sec = ((mins - min) * 60).to_i
403
- deg == 0 ? dgo = " " : dgo = deg.to_s + "°"
404
- mno = min.to_s.rjust(2, " ") + "'"
405
- sco = sec.to_s.rjust(2, " ") + "\""
406
- obs += (dgo + mno + sco) + ") "
407
- end
408
- obs += "\n"
409
- end
410
- obs += "No eyepiece(s) chosen for the observation\n" if @eptag.empty?
411
- obs += "─" * 100 + "\n\n"
412
- obs += "Object: Equipment: Observation:\n" * 8
413
- @w_ep.clr
414
- @w_ep.pa(255, 0, 0, obs)
415
- @w_ep.p("\n...Press any key to continue")
416
- File.write(file, obs)
417
- getch
220
+
221
+ def ep_nice(app, tfl, e) #{{{2
222
+ r = (tfl / app)
223
+ out = ' '
224
+ out += (e/6 > r ? ' ✓'.fg(112) : ' ✗'.fg(208))
225
+ out += (e/3 > r && e/6 <= r ? ' ✓'.fg(112) : ' ✗'.fg(208))
226
+ out += (e/1.5 > r && e/3 <= r ? ' ✓'.fg(112) : ' ✗'.fg(208))
227
+ out += (e >= r && e/1.5 <= r ? ' ✓'.fg(112) : ' ✗'.fg(208))
228
+ out += (e < r ? ' ✓'.fg(112) : ' ✗'.fg(208))
229
+ out
418
230
  end
419
231
 
420
- # TELESCOPE FUNCTIONS (top window, w_ts)
421
- def w_ts_show
422
- @w_ts.setpos(0,0)
423
- heading = " TELESCOPES APP(mm) FL(mm) F/? <MAG xEYE MINx MAXx *FIELD GX/NEB PL/GCL PLd/2* TGHT2* DL-SEP RC-SEP MOON SUN"
424
- heading += " " * (@w_ts.maxx - heading.length).abs
425
- @w_ts.pa(255, 94, Curses::A_BOLD, heading)
426
- @w_ts.fg = 15
427
- @w_ts.bg = 0
428
- @ts.each_with_index do |scope, i|
429
- name = scope[0][0...18]
430
- d = scope[1]
431
- f = scope[2]
432
- out = " " + name.ljust(18)
433
- out += d.to_s.rjust(8)
434
- out += f.to_s.rjust(8)
435
- attr = Curses::A_BOLD
436
- attr = attr | Curses::A_REVERSE if @tsmark == i
437
- attr = attr | Curses::A_UNDERLINE if @tstag.include?(i)
438
- @w_ts.pa(254, 0, attr, out) # Basic info (Name, APP, FL)
439
- out = (f.to_f/d.to_f).truncate(1).to_s.rjust(6)
440
- @w_ts.pa(254, 0, attr, out) # F/?
441
- out = (5 * Math::log(d/10, 10) + 7.5).truncate(1).to_s.rjust(6)
442
- @w_ts.pa(229, 0, attr, out) # <MAG
443
- out = (d**2/49).to_i.to_s.rjust(6)
444
- @w_ts.pa(229, 0, attr, out) # xEYE
445
- out = magx(d, f, 1/7.to_f)
446
- @w_ts.pa(157, 0, attr, out) # MINx
447
- out = magx(d, f, 2)
448
- @w_ts.pa(157, 0, attr, out) # MAXx
449
- out = magx(d, f, 1/6.4)
450
- @w_ts.pa(195, 0, attr, out) # *FIELD
451
- out = magx(d, f, 1/3.6)
452
- @w_ts.pa(195, 0, attr, out) # GX/NEB
453
- out = magx(d, f, 1/2.1)
454
- @w_ts.pa(195, 0, attr, out) # PL/GCL
455
- out = magx(d, f, 1/1.3)
456
- @w_ts.pa(195, 0, attr, out) # PLd/2*
457
- out = magx(d, f, 1/0.7)
458
- @w_ts.pa(195, 0, attr, out) # TGHT2*
459
- out = (115.824/d).truncate(2).dec2.to_s.rjust(7)
460
- @w_ts.pa(219, 0, attr, out) # DL-SEP
461
- out = (3600*Math::asin(671E-6/d).rad).truncate(2).dec2.to_s.rjust(8)
462
- @w_ts.pa(219, 0, attr, out) # RC-SEP
463
- moon = (384E6*Math::tan((115.824.deg/d)/3600))
464
- out = moon.to_i.to_s.rjust(6) + "m"
465
- @w_ts.pa(225, 0, attr, out) # MOON
466
- out = (moon/2.5668).to_i.to_s.rjust(5) + "km"
467
- @w_ts.pa(225, 0, attr, out) # SUN
468
- @w_ts.p("\n")
232
+ def render_ep #{{{2
233
+ app = @ts[@pTS.index][1].to_f
234
+ tfl = @ts[@pTS.index][2].to_f
235
+ @pEP.text = "\n"
236
+ @ep.each_with_index do |e, i|
237
+ name = e[0]
238
+ epfl = e[1].to_f
239
+ afov = e[2].to_f
240
+ tag_ep = @eptag[i] ? ' ' + '▐'.b.fg(46) : ' '
241
+ txt = tag_ep
242
+ txt += name.to_s.ljust(18)
243
+ txt += epfl.to_s.rjust(7)
244
+ txt += afov.to_s.rjust(8)
245
+ txt += magx(tfl, epfl).rts(0).rjust(8) + 'x'
246
+ fov = tfov(tfl, epfl, afov)
247
+ deg = fov.to_i
248
+ min = ((fov - deg) * 60).to_i
249
+ sec = ((fov - deg - min/60.0) * 3600).to_i
250
+ min_s = format('%02d', min)
251
+ sec_s = format('%02d', sec)
252
+ dms = "#{deg}°#{min_s}'#{sec_s}\""
253
+ txt += dms.rjust(11)
254
+ txt += pupl(app, tfl, epfl).rts(1).rjust(6)
255
+ txt += (magx(tfl, epfl) * 2).rts(0).rjust(8) + 'x'
256
+ tfov2 = tfov(tfl, epfl, afov) / 2.0
257
+ deg2 = tfov2.to_i
258
+ min2 = ((tfov2 - deg2) * 60).to_i
259
+ sec2 = ((tfov2 - deg2 - min2/60.0) * 3600).to_i
260
+ min2_s = format('%02d', min2)
261
+ sec2_s = format('%02d', sec2)
262
+ dms2 = "#{deg2}°#{min2_s}'#{sec2_s}\""
263
+ txt += dms2.rjust(11)
264
+ txt += (pupl(app, tfl, epfl) / 2).rts(1).rjust(6)
265
+ txt = txt.fg(248) if i != @pEP.index
266
+ txt += ep_nice(app, tfl, epfl)
267
+ txt[0] = '→' if i == @pEP.index
268
+ # ANSI safe padding
269
+ pad = @pEP.w - Rcurses.display_width(txt.pure)
270
+ pad = 0 if pad.negative?
271
+ txt += ' ' * pad
272
+ txt = txt.bg(234) if i == @pEP.index
273
+ @pEP.text += txt
469
274
  end
470
- @w_ts.clr_from_cur_line
471
- end
472
- def magx(d, f, r)
473
- m = d * r
474
- e = f / m
475
- return (m.to_i.to_s + "(" + e.to_i.to_s + ")").rjust(8)
275
+ @pEP.refresh
276
+ @pEPh.full_refresh
476
277
  end
477
278
 
478
- # EYEPIECE FUNCTIONS (middle window, w_ep)
479
- def w_ep_show
480
- @w_ep.setpos(0,0)
481
- scopes = 5
482
- heading = " ".rjust(35)
483
- @w_ep.pa(231, 240, 0, heading)
484
- @ts.each do |scope|
485
- @w_ep.pa(231, 240, Curses::A_BOLD, " ")
486
- heading = scope[0].ljust(22)
487
- @w_ep.pa(172, 240, Curses::A_BOLD, heading)
488
- end
489
- heading = " " * (@w_ep.maxx - @w_ep.curx)
490
- @w_ep.p(heading)
491
- heading = " EYEPIECES FL(mm) AFOV "
492
- heading += "│ xMAGN FOV(dms) XPUP " * @ts.length
493
- heading += " " * (@w_ep.maxx - heading.length).abs
494
- @w_ep.pa(231, 240, Curses::A_BOLD, heading)
495
- @w_ep.fg = 15
496
- @w_ep.bg = 0
497
- @ep.each_with_index do |ep, i|
498
- name = ep[0][0...18]
499
- m = ep[1].truncate(1)
500
- a = ep[2]
501
- out = " " + name.ljust(18)
502
- out += m.to_s.rjust(8)
503
- out += a.to_s.rjust(6) + "°"
504
- attr = Curses::A_BOLD
505
- attr = attr | Curses::A_REVERSE if @epmark == i
506
- attr = attr | Curses::A_UNDERLINE if @eptag.include?(i)
507
- @w_ep.pa(253, 0, attr, out)
508
- @ts.each do |scope|
509
- d = scope[1]
510
- f = scope[2]
511
- mag = (f.to_f/m)
512
- @w_ep.pa(254, 0, attr, " │")
513
- out = mag.truncate(1).to_s.rjust(6)
514
- @w_ep.pa(156, 0, attr, out)
515
- fov = a/mag
516
- deg = fov.to_i
517
- mins = ((fov - fov.to_i) * 60)
518
- min = mins.to_i
519
- sec = ((mins - min) * 60).to_i
520
- deg == 0 ? dgo = " " : dgo = deg.to_s + "°"
521
- mno = min.to_s.rjust(2, " ") + "'"
522
- sco = sec.to_s.rjust(2, " ") + "\""
523
- out = (dgo + mno + sco).rjust(10)
524
- @w_ep.pa(222, 0, attr, out)
525
- out = (d/mag).truncate(1).to_s.rjust(6)
526
- @w_ep.pa(209, 0, attr, out)
279
+ def observe #{{{2
280
+ # Prepare file header
281
+ date = Date.today.iso8601
282
+ file = File.join(Dir.home, "#{date}_observation.txt")
283
+
284
+ obs = +"Observation file: #{file}\n"
285
+ obs << "Observation date: #{date}\n\n"
286
+ obs << "This file lists the intended equipment for the observation date.\n"
287
+ obs << "Reference observations with telescope letter and eyepiece numbers (like A2, B1, etc.)\n\n"
288
+ obs << ("─" * 100) << "\n"
289
+
290
+ enum = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
291
+
292
+ # Collect and print selected telescopes
293
+ sel_ts = @tstag.each_index.select { |i| @tstag[i] }
294
+ if sel_ts.empty?
295
+ obs << "No telescope(s) chosen for the observation\n"
296
+ else
297
+ sel_ts.each_with_index do |ts_idx, idx|
298
+ name, app_str, tfl_str = @ts[ts_idx]
299
+ app, tfl = app_str.to_f, tfl_str.to_f
300
+
301
+ obs << format(
302
+ "Telescope (%s): %-15s (%3.0fmm/%4.0fmm f/%.1f)",
303
+ enum[idx], name, app, tfl, tfr(app, tfl)
304
+ )
305
+ obs << format(" Max MAG: %.1f", mlim(app))
306
+ obs << format(" Min SEP: %.2f/%.2f\n", sepd(app), sepr(app))
527
307
  end
528
- @w_ep.p("\n")
529
308
  end
530
- @w_ep.clr_from_cur_line
531
- end
532
309
 
533
- # COMMAND FUNCTIONS (bottom window, w_cm)
534
- def w_cm_show
535
- @w_cm.fill
536
- @w_cm.p(" Telescope v0.2 - By Geir Isene (https://isene.com) - press '?' to display the help text")
537
- end
538
- def w_cm_getstr(pretext, text) # A SIMPLE READLINE-LIKE ROUTINE
539
- Curses.curs_set(1)
540
- Curses.echo
541
- pos = text.length
542
- chr = ""
543
- while chr != "ENTER"
544
- @w_cm.setpos(0,0)
545
- init_pair(250, 250, 238)
546
- text += " " * (@w_cm.maxx - text.length) if text.length < @w_cm.maxx
547
- @w_cm.attron(color_pair(250)) { @w_cm << pretext + text }
548
- @w_cm.setpos(0,pretext.length + pos)
549
- @w_cm.refresh
550
- chr = getchr
551
- if chr == "C-G"
552
- Curses.curs_set(0)
553
- Curses.noecho
554
- @w_cm.update = true
555
- return ""
556
- end
557
- case chr
558
- when 'RIGHT'
559
- pos += 1 unless pos > text.length
560
- when 'LEFT'
561
- pos -= 1 unless pos == 0
562
- when 'HOME'
563
- pos = 0
564
- when 'END'
565
- pos = text.length
566
- when 'DEL'
567
- text[pos] = ""
568
- when 'BACK'
569
- unless pos == 0
570
- pos -= 1
571
- text[pos] = ""
572
- end
573
- when 'WBACK'
574
- unless pos == 0
575
- until text[pos - 1] == " " or pos == 0
576
- pos -= 1
577
- text[pos] = ""
578
- end
579
- if text[pos - 1] == " "
580
- pos -= 1
581
- text[pos] = ""
582
- end
310
+ obs << ("─" * 100) << "\n"
311
+
312
+ # Collect and print selected eyepieces (with per‐telescope TFOV)
313
+ sel_ep = @eptag.each_index.select { |i| @eptag[i] }
314
+ if sel_ep.empty?
315
+ obs << "No eyepiece(s) chosen for the observation\n"
316
+ else
317
+ sel_ep.each_with_index do |ep_idx, ep_num|
318
+ name, epfl_str, afov_str = @ep[ep_idx]
319
+ epfl, afov = epfl_str.to_f, afov_str.to_f
320
+
321
+ obs << format(
322
+ "Eyepiece (%d): %-15s (%4.0fmm/%3.0f°) ",
323
+ ep_num+1, name, epfl, afov
324
+ )
325
+
326
+ sel_ts.each_with_index do |ts_idx, ts_num|
327
+ app, tfl = @ts[ts_idx][1].to_f, @ts[ts_idx][2].to_f
328
+ mag = magx(tfl, epfl)
329
+ tf = tfov(tfl, epfl, afov)
330
+
331
+ # Break TFOV into deg, min, sec
332
+ deg = tf.to_i
333
+ min = ((tf - deg)*60).to_i
334
+ sec = ((tf - deg - min/60.0)*3600).to_i
335
+ angle = format(
336
+ "%2s%2d'%2d\"",
337
+ (deg.zero? ? " " : "#{deg}°"),
338
+ min, sec
339
+ )
340
+ obs << format(
341
+ "%s:%5.1fx (%s) ",
342
+ enum[ts_num], mag, angle
343
+ )
583
344
  end
584
- when 'LDEL'
585
- text = ""
586
- pos = 0
587
- when /^.$/
588
- text.insert(pos,chr)
589
- pos += 1
345
+
346
+ obs << "\n"
590
347
  end
591
348
  end
592
- curstr = text
593
- Curses.curs_set(0)
594
- Curses.noecho
595
- return curstr
349
+
350
+ obs << ("─" * 100) << "\n\n"
351
+ obs << ("Object: Equipment: Observation:\n" * 8)
352
+ @pObs.clear
353
+ @pObs.say(obs)
354
+ @pST.say(" Press any key to continue")
355
+ File.write(file, obs)
356
+ getchr
596
357
  end
597
358
 
598
- # MAIN PROGRAM
599
- loop do # OUTER LOOP - (catching refreshes via 'r')
600
- @break = false # Initialize @break variable (set if user hits 'r')
601
- begin # Create the four windows/panels
602
- if Curses.stdscr.maxx < 140
603
- break
604
- end
605
- Curses.stdscr.bg = 236
606
- Curses.stdscr.fg = 236
607
- Curses.stdscr.fill
608
- maxx = Curses.cols
609
- maxy = Curses.lines
610
- # Curses::Window.new(h,w,y,x)
611
- @w_ts = Curses::Window.new(7, maxx - 2, 1, 1)
612
- @w_ep = Curses::Window.new(maxy - 10, maxx - 2, 8, 1)
613
- @w_cm = Curses::Window.new(1, maxx, maxy - 1, 0)
614
- @w_ts.fg, @w_ts.bg = 15, 0
615
- @w_ep.fg, @w_ep.bg = 255, 232
616
- @w_cm.fg, @w_cm.bg = 233, 246
617
- @w_ts.clr
618
- @w_ep.clr
619
- @w_cm.fill
620
- loop do # INNER, CORE LOOP
621
- w_ts_show
622
- w_ep_show
623
- w_cm_show
624
- main_getkey # Get key from user
625
- break if @break # Break to outer loop, redrawing windows, if user hit 'r'
626
- if Curses.cols != maxx or Curses.lines != maxy # break on terminal resize
627
- close_screen
628
- puts " You must run Telescope with a minimum tarminal width of 140 chracters."
629
- break
630
- end
359
+ # PANE SETUP {{{1
360
+ # Top telescopes, eyepieces below, status at bottom
361
+ @max_h, @max_w = IO.console.winsize
362
+ @pTS = Pane.new( 2, 2, @max_w - 2, 8, nil, nil)
363
+ @pTSh = Pane.new( 2, 2, @max_w - 2, 1, 255, "00524b")
364
+ @pTSa = Pane.new( 1, @max_h, @max_w, 1, 255, "00524b")
365
+ @pEP = Pane.new( 2, 11, @max_w - 2, @max_h - 12, nil, nil)
366
+ @pEPh = Pane.new( 2, 11, @max_w - 2, 1, 255, "4c3c1d")
367
+ @pEPa = Pane.new( 1, @max_h, @max_w, 1, 255, "4c3c1d")
368
+ @pST = Pane.new( 1, @max_h, @max_w, 1, 255, 236)
369
+
370
+ @pHlp = Pane.new( @max_w/2 - 30, @max_h/2 - 13, 60, 26, 252, 233)
371
+ @pObs = Pane.new( 8, 8, @max_w - 16, @max_h - 16, 231, 233)
372
+
373
+ @pTSh.text = ' TELESCOPES APP(mm) FL(mm) F/? <MGN xEYE MINx MAXx SEP-R SEP-D *FLD GLXY PLNT DBL* >2*< MOON SUN'.b
374
+ @pEPh.text = ' EYEPIECES FL(mm) AFOV'.b
375
+ @pEPh.text += ' MAGX TFOV PPL 2blw tfov ppl'.b.i.fg("00827b")
376
+ @pEPh.text += ' *FLD GLXY PLNT DBL* >2*<'.bg("4c3c1d")
377
+ @pST.text = ' t/e = Add telescope/eyepiece, ENTER = Edit item, q/Q = Quit, ? = Help'
378
+ @pHlp.border = true
379
+ @pObs.border = true
380
+
381
+ @pTSa.record = true
382
+ @pEPa.record = true
383
+ @pTS.index = 0
384
+ @pEP.index = 0
385
+ @sort_ts = false
386
+ @sort_ep = false
387
+ @ts_unsorted = @ts.dup
388
+ @ep_unsorted = @ep.dup
389
+ @focus = @pTS
390
+ @current = @ts
391
+
392
+ # TRAP WIN SIZE CHANGE {{{1
393
+ Signal.trap('WINCH') do
394
+ @h, @w = IO.console.winsize
395
+ refresh_all
396
+ end
397
+
398
+ # MAIN LOOP {{{1
399
+ refresh_all
400
+ loop do
401
+ render_ts
402
+ render_ep
403
+ @pST.text = ' t/e = Add telescope/eyepiece, ENTER = Edit item, q/Q = Quit, ? = Help'
404
+ @pST.full_refresh
405
+ ch = getchr
406
+ case ch
407
+ when 'q'
408
+ File.write(SAVE, "@ts = #{@ts.inspect}\n@ep = #{@ep.inspect}\n") && exit
409
+ when 'Q'; exit
410
+ when '?'
411
+ @pHlp.full_refresh
412
+ @pHlp.say(HELP1)
413
+ getchr
414
+ @pHlp.say(HELP2)
415
+ getchr
416
+ @pHlp.say(HELP3)
417
+ getchr
418
+ refresh_all
419
+ when 'r'
420
+ refresh_all
421
+ when 't'
422
+ inp=@pTSa.ask('name, app, fl: ','').split(', ')
423
+ next unless inp.size == 3
424
+ @ts<<inp
425
+ @tstag<<false
426
+ @ts_unsorted << inp # keep master list updated
427
+ @current = @ts
428
+ when 'e'
429
+ inp=@pEPa.ask('name, fl, afov: ','').split(', ')
430
+ next unless inp.size == 3
431
+ @ep<<inp
432
+ @eptag<<false
433
+ @ep_unsorted << inp # keep master list updated
434
+ @current = @ep
435
+ when 'ENTER'
436
+ val = @current[@focus.index].join(', ')
437
+ arr=@pST.ask('Edit: ', val).split(', '); next unless arr.size==3
438
+ @current[@focus.index] = arr
439
+ when 'D'
440
+ if @current.equal?(@ts)
441
+ removed = @ts.delete_at(@focus.index)
442
+ @ts_unsorted.delete(removed)
443
+ @tstag.delete_at(@focus.index)
444
+ else
445
+ removed = @ep.delete_at(@focus.index)
446
+ @ep_unsorted.delete(removed)
447
+ @eptag.delete_at(@focus.index)
448
+ end
449
+ when 'TAB'
450
+ @focus = (@focus == @pTS ? @pEP : @pTS)
451
+ @current = (@current == @ts ? @ep : @ts)
452
+ @pTS.border = false
453
+ @pEP.border = false
454
+ @focus.border = true
455
+ @pTS.border_refresh
456
+ @pEP.border_refresh
457
+ when 'UP'
458
+ @focus.index -= 1
459
+ @focus.index = @current.length - 1 if @focus.index < 0
460
+ when 'DOWN'
461
+ @focus.index += 1
462
+ @focus.index = 0 if @focus.index > @current.length - 1
463
+ @focus == :ts ? @cursor_ts = 0 : @cursor_ep = 0
464
+ when 'HOME'
465
+ @focus.index = 0
466
+ when 'END'
467
+ @focus.index = @current.length - 1
468
+ when 'S-UP'
469
+ @current.insert([@focus.index - 1, 0].max, @current.delete_at(@focus.index))
470
+ @focus.index -= 1 if @focus.index != 0
471
+ when 'S-DOWN'
472
+ @current.insert([@focus.index + 1, @current.size - 1].min, @current.delete_at(@focus.index))
473
+ @focus.index += 1 if @focus.index != @current.size - 1
474
+ when 'o' # Toggle-sort the currently focused list
475
+ if @current.equal?(@ts) # toggling telescopes
476
+ @sort_ts = !@sort_ts
477
+ @ts = if @sort_ts
478
+ @ts_unsorted.sort_by { |t| t[1].to_i }
479
+ else
480
+ @ts_unsorted.dup
481
+ end
482
+ @current = @ts
483
+ @pTS.index = [@pTS.index, @ts.size - 1].min
484
+ else # toggling eyepieces
485
+ @sort_ep = !@sort_ep
486
+ @ep = if @sort_ep
487
+ @ep_unsorted.sort_by { |e| e[1].to_i }
488
+ else
489
+ @ep_unsorted.dup
490
+ end
491
+ @current = @ep
492
+ @pEP.index = [@pEP.index, @ep.size - 1].min
631
493
  end
632
- ensure # On exit: close curses, clear terminal
633
- close_screen
494
+ when ' ' # SPACE: tag/untag current entry
495
+ if @current.equal?(@ts)
496
+ idx = @pTS.index
497
+ @tstag[idx] = !@tstag[idx]
498
+ else
499
+ idx = @pEP.index
500
+ @eptag[idx] = !@eptag[idx]
501
+ end
502
+ when 'u'
503
+ @tstag.fill(false)
504
+ @eptag.fill(false)
505
+ when 'C-O'
506
+ observe
634
507
  end
635
508
  end
636
509
 
637
- # vim: set sw=2 sts=2 et fdm=syntax fdn=2 fcs=fold\:\ :
510
+ # vim: set sw=2 sts=2 et filetype=ruby fdm=marker fdn=2 fcs=fold\:\ :
metadata CHANGED
@@ -1,40 +1,34 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: telescope-term
3
3
  version: !ruby/object:Gem::Version
4
- version: '0.7'
4
+ version: '1.0'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Geir Isene
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-02-05 00:00:00.000000000 Z
11
+ date: 2025-05-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: curses
14
+ name: rcurses
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '1.3'
20
- - - ">="
21
- - !ruby/object:Gem::Version
22
- version: 1.3.2
19
+ version: '3.5'
23
20
  type: :runtime
24
21
  prerelease: false
25
22
  version_requirements: !ruby/object:Gem::Requirement
26
23
  requirements:
27
24
  - - "~>"
28
25
  - !ruby/object:Gem::Version
29
- version: '1.3'
30
- - - ">="
31
- - !ruby/object:Gem::Version
32
- version: 1.3.2
26
+ version: '3.5'
33
27
  description: 'With this program you can list your telescopes and eyepieces and get
34
28
  a set of calculations done for each scope and for the combination of scope and eyepiece.
35
- Easy interface. Run the program, then hit ''?'' to show the help file. New in v0.6.0:
36
- Added sorting of telescopes (via ''T'') and eyepieces (''E''). New in 1.7: Highlighted
37
- all of current selection for better readability.'
29
+ Easy interface. Run the program, then hit ''?'' to show the help file. Version 1.0:
30
+ A full rewrite using the rcurses library (https://github.com/isene/rcurses) - lots
31
+ of improvements.'
38
32
  email: g@isene.com
39
33
  executables:
40
34
  - telescope
@@ -47,7 +41,7 @@ licenses:
47
41
  - Unlicense
48
42
  metadata:
49
43
  source_code_uri: https://github.com/isene/telescope
50
- post_install_message:
44
+ post_install_message:
51
45
  rdoc_options: []
52
46
  require_paths:
53
47
  - lib
@@ -62,8 +56,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
62
56
  - !ruby/object:Gem::Version
63
57
  version: '0'
64
58
  requirements: []
65
- rubygems_version: 3.1.2
66
- signing_key:
59
+ rubygems_version: 3.4.20
60
+ signing_key:
67
61
  specification_version: 4
68
- summary: Terminal program to aid the amateur astronomer.
62
+ summary: Terminal program for the amateur astronomer.
69
63
  test_files: []