fortrangoingonforty/fortty / eb8c212

Browse files

Add dynamic font size adjustment with Ctrl/Cmd +/-

Implement real-time font size changes via keyboard shortcuts:
- Ctrl/Cmd + = (or +): Increase font size by 2px
- Ctrl/Cmd + -: Decrease font size by 2px
- Ctrl/Cmd + 0: Reset to config default

Font size is clamped to 8-72px range. Terminal dimensions
automatically recalculate and PTY is resized accordingly.
Fallback font path is saved at startup and reloaded on size
change to preserve Unicode glyphs (fish chevron, icons, etc).
Authored by espadonne
SHA
eb8c212af9c52ea1d8181a433a153c978088cdfe
Parents
9d9074d
Tree
ca74ef1

4 changed files

StatusFile+-
M src/fortty.f90 67 1
M src/text/renderer.f90 32 1
M src/window/glfw_bindings.f90 11 0
M src/window/window.f90 39 0
src/fortty.f90modified
@@ -37,6 +37,8 @@ program fortty
3737
   real(8) :: current_time, last_time, blink_timer
3838
   logical :: cursor_blink_visible
3939
   type(selection_t) :: sel
40
+  integer :: font_delta, new_font_size, base_font_size
41
+  character(len=256) :: font_path_saved, fallback_path_saved
4042
 
4143
   ! Load configuration (uses defaults if no config file found)
4244
   cfg = config_load('')
@@ -92,6 +94,11 @@ program fortty
9294
   ! After assignment, we need to update it to point to ren%font
9395
   ren%atlas%font => ren%font
9496
 
97
+  ! Save font path and base size for runtime font size changes
98
+  font_path_saved = font_path
99
+  base_font_size = cfg%font_size
100
+  fallback_path_saved = ''  ! Will be set when fallback is loaded
101
+
95102
   ! Load fallback font for missing glyphs (icons, symbols, etc.)
96103
   ! Use config fallback if specified, otherwise auto-detect via fontconfig
97104
   if (len_trim(cfg%font_fallback) > 0) then
@@ -162,7 +169,13 @@ program fortty
162169
   end if
163170
 
164171
   if (ren%font%has_fallback) then
165
-    print *, "Fallback font loaded: ", trim(fallback_path)
172
+    ! Save the successful fallback path for font size changes
173
+    if (len_trim(cfg%font_fallback) > 0) then
174
+      fallback_path_saved = cfg%font_fallback
175
+    else
176
+      fallback_path_saved = fallback_path
177
+    end if
178
+    print *, "Fallback font loaded: ", trim(fallback_path_saved)
166179
   else
167180
     print *, "Warning: No fallback font loaded - some icons may not display"
168181
   end if
@@ -227,6 +240,59 @@ program fortty
227240
       blink_timer = 0.0d0
228241
     end if
229242
 
243
+    ! Check for font size change request (Ctrl/Cmd +/-)
244
+    font_delta = window_get_font_delta()
245
+    if (font_delta /= 0) then
246
+      call window_clear_font_delta()
247
+
248
+      if (font_delta == -999) then
249
+        ! Reset to default
250
+        new_font_size = base_font_size
251
+      else
252
+        new_font_size = ren%font%size_px + font_delta
253
+      end if
254
+
255
+      ! Clamp to reasonable range (8px to 72px)
256
+      new_font_size = max(8, min(72, new_font_size))
257
+
258
+      if (new_font_size /= ren%font%size_px) then
259
+        ! Reload font with new size
260
+        call renderer_change_font_size(ren, trim(font_path_saved), new_font_size)
261
+
262
+        ! Fix atlas font pointer after reload
263
+        ren%atlas%font => ren%font
264
+
265
+        ! Reload fallback font (using saved path from startup)
266
+        if (len_trim(fallback_path_saved) > 0) then
267
+          call renderer_load_fallback_font(ren, trim(fallback_path_saved))
268
+        end if
269
+
270
+        ! Update cell dimensions from new font
271
+        cell_width = ren%font%cell_width
272
+        cell_height = ren%font%cell_height
273
+        ascender = ren%font%ascender
274
+        if (cell_width < 1) cell_width = 10
275
+        if (cell_height < 1) cell_height = 18
276
+        if (ascender < 1) ascender = cell_height - 4
277
+
278
+        ! Update window module's cell size for mouse coords
279
+        call window_set_cell_size(cell_width, cell_height)
280
+
281
+        ! Recalculate terminal dimensions
282
+        new_cols = win_width / cell_width
283
+        new_rows = win_height / cell_height
284
+        if (new_cols /= term_cols .or. new_rows /= term_rows) then
285
+          term_cols = new_cols
286
+          term_rows = new_rows
287
+          call pty_resize(pty, term_rows, term_cols)
288
+          call terminal_resize(term, term_rows, term_cols)
289
+        end if
290
+
291
+        call window_set_font_size(new_font_size)
292
+        print *, "Font size:", new_font_size, "px (", term_cols, "x", term_rows, ")"
293
+      end if
294
+    end if
295
+
230296
     ! Check for window resize
231297
     call window_get_size(win, win_width, win_height)
232298
     if (win_width /= prev_width .or. win_height /= prev_height) then
src/text/renderer.f90modified
@@ -12,7 +12,7 @@ module renderer_mod
1212
   public :: renderer_create, renderer_destroy
1313
   public :: renderer_begin, renderer_draw_char, renderer_draw_string, renderer_flush
1414
   public :: renderer_set_projection, renderer_load_fallback_font
15
-  public :: renderer_draw_rect
15
+  public :: renderer_draw_rect, renderer_change_font_size
1616
 
1717
   ! Vertex format: position(2) + texcoord(2) + color(4) = 8 floats per vertex
1818
   integer, parameter :: FLOATS_PER_VERTEX = 8
@@ -404,4 +404,35 @@ contains
404404
 
405405
   end subroutine renderer_draw_rect
406406
 
407
+  ! Change font size at runtime (destroys old font/atlas, creates new ones)
408
+  subroutine renderer_change_font_size(r, font_path, new_size)
409
+    type(renderer_t), intent(inout) :: r
410
+    character(len=*), intent(in) :: font_path
411
+    integer, intent(in) :: new_size
412
+
413
+    if (.not. r%initialized) return
414
+
415
+    ! Destroy old atlas and font
416
+    call atlas_destroy(r%atlas)
417
+    call font_destroy(r%font)
418
+
419
+    ! Load font with new size
420
+    r%font = font_load(font_path, new_size)
421
+    if (.not. r%font%loaded) then
422
+      print *, "Error: Failed to reload font at size", new_size
423
+      r%initialized = .false.
424
+      return
425
+    end if
426
+
427
+    ! Recreate atlas with new font
428
+    r%atlas = atlas_create(r%font)
429
+    if (.not. r%atlas%initialized) then
430
+      print *, "Error: Failed to recreate atlas"
431
+      call font_destroy(r%font)
432
+      r%initialized = .false.
433
+      return
434
+    end if
435
+
436
+  end subroutine renderer_change_font_size
437
+
407438
 end module renderer_mod
src/window/glfw_bindings.f90modified
@@ -74,6 +74,17 @@ module glfw_bindings
7474
   integer(c_int), parameter :: GLFW_KEY_Y = 89
7575
   integer(c_int), parameter :: GLFW_KEY_Z = 90
7676
 
77
+  ! Number keys
78
+  integer(c_int), parameter :: GLFW_KEY_0 = 48
79
+
80
+  ! Symbol keys (for font size adjustment)
81
+  integer(c_int), parameter :: GLFW_KEY_MINUS = 45       ! '-' key
82
+  integer(c_int), parameter :: GLFW_KEY_EQUAL = 61       ! '=' key
83
+
84
+  ! Numpad keys
85
+  integer(c_int), parameter :: GLFW_KEY_KP_SUBTRACT = 333
86
+  integer(c_int), parameter :: GLFW_KEY_KP_ADD = 334
87
+
7788
   ! Modifier masks
7889
   integer(c_int), parameter :: GLFW_MOD_SHIFT = 1
7990
   integer(c_int), parameter :: GLFW_MOD_CONTROL = 2
src/window/window.f90modified
@@ -15,6 +15,7 @@ module window_mod
1515
   public :: window_get_size, window_set_pty, window_set_terminal
1616
   public :: window_set_title, window_set_cell_size, window_set_blur
1717
   public :: window_get_selection, window_clipboard_set, window_clipboard_get
18
+  public :: window_get_font_delta, window_clear_font_delta, window_set_font_size
1819
 
1920
   type :: window_t
2021
     type(c_ptr) :: handle = c_null_ptr
@@ -40,6 +41,10 @@ module window_mod
4041
   integer, save :: cell_width = 10
4142
   integer, save :: cell_height = 18
4243
 
44
+  ! Font size adjustment state
45
+  integer, save :: pending_font_delta = 0   ! +2, -2, or -999 for reset
46
+  integer, save :: current_font_size = 16   ! Track current size
47
+
4348
   ! Interface to C helper for loading OpenGL
4449
   interface
4550
     integer(c_int) function fortty_load_gl() bind(C, name="fortty_load_gl")
@@ -233,6 +238,23 @@ contains
233238
       end if
234239
     end if
235240
 
241
+    ! Handle font size adjustment: Ctrl/Cmd + Plus/Minus/0
242
+    if (iand(mods, GLFW_MOD_CONTROL) /= 0 .or. iand(mods, GLFW_MOD_SUPER) /= 0) then
243
+      if (key == GLFW_KEY_EQUAL .or. key == GLFW_KEY_KP_ADD) then
244
+        ! Ctrl/Cmd + = or numpad + (increase font size)
245
+        pending_font_delta = 2
246
+        return
247
+      else if (key == GLFW_KEY_MINUS .or. key == GLFW_KEY_KP_SUBTRACT) then
248
+        ! Ctrl/Cmd + - (decrease font size)
249
+        pending_font_delta = -2
250
+        return
251
+      else if (key == GLFW_KEY_0) then
252
+        ! Ctrl/Cmd + 0 (reset font size)
253
+        pending_font_delta = -999
254
+        return
255
+      end if
256
+    end if
257
+
236258
     ! Handle Ctrl combinations (these don't trigger char_callback)
237259
     if (iand(mods, GLFW_MOD_CONTROL) /= 0) then
238260
       if (key >= GLFW_KEY_A .and. key <= GLFW_KEY_Z) then
@@ -704,4 +726,21 @@ contains
704726
     end if
705727
   end subroutine handle_paste
706728
 
729
+  ! Get pending font size delta (returns 0 if none)
730
+  function window_get_font_delta() result(delta)
731
+    integer :: delta
732
+    delta = pending_font_delta
733
+  end function window_get_font_delta
734
+
735
+  ! Clear pending font size delta
736
+  subroutine window_clear_font_delta()
737
+    pending_font_delta = 0
738
+  end subroutine window_clear_font_delta
739
+
740
+  ! Set current font size (for tracking)
741
+  subroutine window_set_font_size(size)
742
+    integer, intent(in) :: size
743
+    current_font_size = size
744
+  end subroutine window_set_font_size
745
+
707746
 end module window_mod