norcal 1.4.0 → 1.5.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 (5) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE +21 -12
  3. data/README.md +7 -3
  4. data/bin/norcal +87 -27
  5. metadata +4 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9be7e8ddb9dd50827b5f06ebb3df0f77198839e50e243fe2a5afe2b9c3013de4
4
- data.tar.gz: f4c4991791a1cfffe455411d4c08534f4f65a60539cf9ee01dd43f1084ab70e0
3
+ metadata.gz: 1608e3179b744d9c6ace3748742e20a83b0b2991bf859613e84541514565a9b5
4
+ data.tar.gz: 246f277da99b0498f00a4056849c06bcc0c9ac2d3395728051a56d351c81ec46
5
5
  SHA512:
6
- metadata.gz: 39d0619b9c32fad49beeb6f720d7776c11e5238c4d85ac19d0a642aadf749b8196174b8e64be1bc5f37a585edb44a6db3369102e9f54a89be333593cc0694df9
7
- data.tar.gz: 7f4cc6f41397632c34854ecee9cbbe24eccde9bc0dc6ca3741891ba161c78af61968fcf286b3a1b9e9f32806bb0891b1f681e91085923fb499675d020fae6dcf
6
+ metadata.gz: 6baf6625c75e4e7d170a577be6cfbd8ba25be9a9db1654b45d03eeb4249adac817a6572c591d4b1275504446d4fbc31c1fb92b2ec5c2ab9f7b4f60fcb46d5182
7
+ data.tar.gz: 35f41710cd20ccd926d854ea21f2a599fc3ba779f85f8bf6ad32015ef4e63f79bf23247b8966f357f92f3e71d5421b177172862f2fe78f6eec13421345d611be
data/LICENSE CHANGED
@@ -1,15 +1,24 @@
1
- ISC License
1
+ This is free and unencumbered software released into the public domain.
2
2
 
3
- Copyright (c) 2026 baosen <chibaosen@gmail.com>
3
+ Anyone is free to copy, modify, publish, use, compile, sell, or
4
+ distribute this software, either in source code form or as a compiled
5
+ binary, for any purpose, commercial or non-commercial, and by any
6
+ means.
4
7
 
5
- Permission to use, copy, modify, and/or distribute this software for any
6
- purpose with or without fee is hereby granted, provided that the above
7
- copyright notice and this permission notice appear in all copies.
8
+ In jurisdictions that recognize copyright laws, the author or authors
9
+ of this software dedicate any and all copyright interest in the
10
+ software to the public domain. We make this dedication for the benefit
11
+ of the public at large and to the detriment of our heirs and
12
+ successors. We intend this dedication to be an overt act of
13
+ relinquishment in perpetuity of all present and future rights to this
14
+ software under copyright law.
8
15
 
9
- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10
- WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11
- MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12
- ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13
- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14
- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15
- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19
+ IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20
+ OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21
+ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22
+ OTHER DEALINGS IN THE SOFTWARE.
23
+
24
+ For more information, please refer to <https://unlicense.org/>
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # norcal
2
2
 
3
- A local Norwegian desktop calendar.
3
+ A local Norwegian calendar.
4
4
 
5
5
  ![norcal screenshot](screenshot.png)
6
6
 
@@ -31,7 +31,7 @@ gem install norcal
31
31
  git clone https://github.com/baosen/norcal.git
32
32
  cd norcal
33
33
  gem build norcal.gemspec
34
- gem install norcal-1.4.0.gem
34
+ gem install norcal-1.5.0.gem
35
35
  ```
36
36
 
37
37
  ## Usage
@@ -57,6 +57,10 @@ norcal --light 2026 # light mode, specific year
57
57
  - Auto-fit to screen height on startup, with `fit` button
58
58
  - Scrollbar for zoomed-in views
59
59
 
60
+ ## References
61
+
62
+ - Djupvik, Guro: [røde dager](https://lille.snl.no/r%C3%B8de_dager) i Lille norske leksikon på snl.no. Hentet 7. april 2026.
63
+
60
64
  ## License
61
65
 
62
- [ISC](LICENSE)
66
+ [Unlicense](LICENSE)
data/bin/norcal CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
- # norcal - Norwegian desktop calendar
2
+ # norcal - Norwegian calendar
3
3
 
4
4
  require 'date'
5
5
  require 'tk'
@@ -23,8 +23,9 @@ MONTHS_NO = %w[
23
23
  Juli August September Oktober November Desember
24
24
  ].freeze
25
25
 
26
- DAYS_NO = %w[Ma Ti On To Fr Lø Sø].freeze
27
- MABBR_NO = %w[jan feb mar apr mai jun jul aug sep okt nov des].freeze
26
+ DAYS_NO = %w[Ma Ti On To Fr Lø Sø].freeze
27
+ MABBR_NO = %w[jan feb mar apr mai jun jul aug sep okt nov des].freeze
28
+ QUARTERS = ['1. kvartal', '2. kvartal', '3. kvartal', '4. kvartal'].freeze
28
29
 
29
30
  # -- Date helpers --------------------------------------------------------------
30
31
 
@@ -62,13 +63,14 @@ def red_days(year)
62
63
  e = easter(year)
63
64
  {
64
65
  Date.new(year, 1, 1) => "Første nyttårsdag",
66
+ e - 7 => "Palmesøndag",
65
67
  e - 3 => "Skjærtorsdag",
66
68
  e - 2 => "Langfredag",
67
69
  e => "1. påskedag",
68
70
  e + 1 => "2. påskedag",
69
71
  Date.new(year, 5, 1) => "Arbeidernes dag",
70
72
  e + 39 => "Kristi himmelfartsdag",
71
- Date.new(year, 5, 17) => "Grunnlovsdagen",
73
+ Date.new(year, 5, 17) => "Grunnlovsdagen 1814",
72
74
  e + 49 => "1. pinsedag",
73
75
  e + 50 => "2. pinsedag",
74
76
  Date.new(year, 12, 25) => "1. juledag",
@@ -92,21 +94,8 @@ def notable_dates(year)
92
94
  nov27 = Date.new(year, 11, 27)
93
95
  advent1 = nov27 + ((7 - nov27.cwday) % 7)
94
96
 
95
- # Override display names for some red days in the notable list
96
- notable_names = {
97
- e + 39 => "Kristi himmelfartsdag",
98
- Date.new(year, 5, 17) => "Grunnlovsdagen 1814",
99
- }
100
-
101
97
  # Start with all red days
102
- entries = holidays.map { |date, name|
103
- [date, notable_names[date] || name, true]
104
- }
105
-
106
- # Red-in-list but not a public holiday
107
- entries += [
108
- [e - 7, "Palmesøndag", true],
109
- ]
98
+ entries = holidays.map { |date, name| [date, name, true] }
110
99
 
111
100
  # Non-red notable dates
112
101
  entries += [
@@ -195,6 +184,66 @@ $root = TkRoot.new do
195
184
  title "norcal"
196
185
  end
197
186
 
187
+ # -- Tooltip -------------------------------------------------------------------
188
+
189
+ $tooltip = TkToplevel.new($root) { withdraw; overrideredirect true }
190
+ $tooltip_label = TkLabel.new($tooltip) {
191
+ justify 'left'; padx 6; pady 3; borderwidth 1; relief 'solid'; wraplength 0
192
+ }
193
+ $tooltip_label.pack
194
+
195
+ # Make tooltip transparent to mouse events (X11 input passthrough)
196
+ begin
197
+ Tk.tk_call('wm', 'attributes', $tooltip, '-type', 'tooltip')
198
+ rescue; end
199
+
200
+ def tooltip_show(widget, text)
201
+ t = theme
202
+ f = make_fonts
203
+ $tooltip_label.configure(
204
+ text: text, font: f[:btn], background: t[:bg], foreground: t[:fg],
205
+ highlightbackground: t[:border]
206
+ )
207
+ $tooltip.configure(background: t[:border])
208
+
209
+ # Force geometry recalculation so tooltip is never cropped
210
+ $tooltip.geometry('')
211
+ Tk.update_idletasks
212
+
213
+ # Position below the widget
214
+ x = widget.winfo_rootx
215
+ y = widget.winfo_rooty + widget.winfo_height + 2
216
+ # Keep on screen
217
+ screen_w = $root.winfo_screenwidth
218
+ screen_h = $root.winfo_screenheight
219
+ tip_w = $tooltip.winfo_reqwidth
220
+ tip_h = $tooltip.winfo_reqheight
221
+ x = screen_w - tip_w if x + tip_w > screen_w
222
+ y = widget.winfo_rooty - tip_h - 2 if y + tip_h > screen_h
223
+ $tooltip.geometry("+#{x}+#{y}")
224
+ $tooltip.deiconify
225
+ $tooltip.raise
226
+ end
227
+
228
+ def tooltip_hide
229
+ $tooltip.withdraw
230
+ end
231
+
232
+ def bind_tooltip(widget, text)
233
+ widget.bind('Enter') { tooltip_show(widget, text) }
234
+ widget.bind('Leave') { tooltip_hide }
235
+ end
236
+
237
+ # Build a lookup: Date -> [name, ...] for tooltips.
238
+ # Uses red_days names directly (no overrides), plus non-red notable names.
239
+ def date_names(year)
240
+ names = Hash.new { |h, k| h[k] = [] }
241
+ notable_dates(year).each do |d, n, _|
242
+ names[d] << n unless names[d].include?(n)
243
+ end
244
+ names
245
+ end
246
+
198
247
  # -- Widget tracking for in-place updates --------------------------------------
199
248
 
200
249
  # All trackable widgets, grouped by update type.
@@ -238,7 +287,7 @@ end
238
287
 
239
288
  # -- Build calendar (one-time per year) ----------------------------------------
240
289
 
241
- def build_month(parent, year, month, holidays)
290
+ def build_month(parent, year, month, holidays, names)
242
291
  first = Date.new(year, month, 1)
243
292
  last_day = Date.new(year, month, -1)
244
293
  monday = first - (first.cwday - 1)
@@ -283,9 +332,10 @@ def build_month(parent, year, month, holidays)
283
332
  bg_key = is_today ? :today_bg : :bg
284
333
  font_key = is_today ? :cal_bold : :cal
285
334
 
286
- lbl = TkLabel.new(grid) { text day.day.to_s }
335
+ lbl = TkLabel.new(grid) { text day.day.to_s; anchor 'e' }
287
336
  $w[:labels] << { w: lbl, fg: fg_key, bg: bg_key, font: font_key }
288
- lbl.grid(row: row, column: i + 1, sticky: 'e')
337
+ lbl.grid(row: row, column: i + 1, sticky: 'nsew')
338
+ bind_tooltip(lbl, names[day].join("\n")) if names.key?(day)
289
339
  end
290
340
  end
291
341
  row += 1
@@ -350,14 +400,14 @@ end
350
400
  def rebuild_notable
351
401
  $notable_frame&.destroy
352
402
  $notable_frame = build_notable($notable_parent, $year)
353
- $notable_frame.grid(row: 4, column: 0, columnspan: 3, padx: 3, pady: [4, 0], sticky: 'ew')
403
+ $notable_frame.grid(row: 8, column: 0, columnspan: 3, padx: 3, pady: [4, 0], sticky: 'ew')
354
404
  restyle
355
405
  end
356
406
 
357
407
  def build_buttons(parent)
358
408
  btn_bar = TkFrame.new(parent)
359
409
  $w[:bg] << btn_bar
360
- btn_bar.grid(row: 5, column: 0, columnspan: 3, pady: [4, 0])
410
+ btn_bar.grid(row: 9, column: 0, columnspan: 3, pady: [4, 0])
361
411
 
362
412
  b1 = TkButton.new(btn_bar) { relief 'flat'; borderwidth 0; command { $dark = !$dark; restyle } }
363
413
  $w[:buttons] << { w: b1, fg: :dkgray, text_key: :toggle_label, text: nil }
@@ -392,6 +442,7 @@ def build_all(year)
392
442
  $inner_frame&.destroy
393
443
 
394
444
  holidays = red_days(year)
445
+ names = date_names(year)
395
446
 
396
447
  $inner_frame = TkFrame.new($canvas)
397
448
  $w[:bg] << $inner_frame
@@ -408,14 +459,23 @@ def build_all(year)
408
459
  $w[:bg] << grid_f
409
460
  grid_f.pack
410
461
 
411
- 12.times do |idx|
412
- build_month(grid_f, year, idx + 1, holidays)
413
- .grid(row: idx / 3, column: idx % 3, padx: 3, pady: 3, sticky: 'nsew')
462
+ 4.times do |q|
463
+ label_row = q * 2
464
+ month_row = q * 2 + 1
465
+
466
+ qlbl = TkLabel.new(grid_f) { text QUARTERS[q] }
467
+ $w[:labels] << { w: qlbl, fg: :dkgray, bg: :bg, font: :cal }
468
+ qlbl.grid(row: label_row, column: 0, columnspan: 3, pady: [4, 0], sticky: 'w')
469
+
470
+ 3.times do |col|
471
+ build_month(grid_f, year, q * 3 + col + 1, holidays, names)
472
+ .grid(row: month_row, column: col, padx: 3, pady: 3, sticky: 'nsew')
473
+ end
414
474
  end
415
475
 
416
476
  $notable_parent = grid_f
417
477
  $notable_frame = build_notable(grid_f, year)
418
- $notable_frame.grid(row: 4, column: 0, columnspan: 3, padx: 3, pady: [4, 0], sticky: 'ew')
478
+ $notable_frame.grid(row: 8, column: 0, columnspan: 3, padx: 3, pady: [4, 0], sticky: 'ew')
419
479
 
420
480
  build_buttons(grid_f)
421
481
  3.times { |c| grid_f.grid_columnconfigure(c, weight: 1) }
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: norcal
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.4.0
4
+ version: 1.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - baosen
@@ -23,7 +23,7 @@ dependencies:
23
23
  - - "~>"
24
24
  - !ruby/object:Gem::Version
25
25
  version: '0.6'
26
- description: A local Norwegian desktop calendar with Tk GUI
26
+ description: A local Norwegian calendar with Tk GUI
27
27
  email: chibaosen@gmail.com
28
28
  executables:
29
29
  - norcal
@@ -35,7 +35,7 @@ files:
35
35
  - bin/norcal
36
36
  homepage: https://github.com/baosen/norcal
37
37
  licenses:
38
- - ISC
38
+ - Unlicense
39
39
  metadata: {}
40
40
  rdoc_options: []
41
41
  require_paths:
@@ -53,5 +53,5 @@ required_rubygems_version: !ruby/object:Gem::Requirement
53
53
  requirements: []
54
54
  rubygems_version: 4.0.3
55
55
  specification_version: 4
56
- summary: Norwegian desktop calendar
56
+ summary: Norwegian calendar
57
57
  test_files: []