faces.go 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. package choose_fonts
  2. import (
  3. "fmt"
  4. "math"
  5. "sync"
  6. "kitty/tools/tui/loop"
  7. "kitty/tools/utils"
  8. )
  9. var _ = fmt.Print
  10. type faces_settings struct {
  11. font_family, bold_font, italic_font, bold_italic_font string
  12. }
  13. type faces_preview_key struct {
  14. settings faces_settings
  15. width, height int
  16. }
  17. type faces struct {
  18. handler *handler
  19. family string
  20. settings faces_settings
  21. preview_cache map[faces_preview_key]map[string]RenderedSampleTransmit
  22. preview_cache_mutex sync.Mutex
  23. }
  24. const highlight_key_style = "fg=magenta bold"
  25. func (self *faces) draw_screen() (err error) {
  26. lp := self.handler.lp
  27. lp.SetCursorVisible(false)
  28. sz, _ := lp.ScreenSize()
  29. styled := lp.SprintStyled
  30. lp.QueueWriteString(self.handler.format_title(self.family, 0))
  31. lines := []string{
  32. fmt.Sprintf("Press %s to select this font, %s to go back to the font list or any of the %s keys below to fine-tune the appearance of the individual font styles.", styled("fg=green", "Enter"), styled("fg=red", "Esc"), styled(highlight_key_style, "highlighted")), "",
  33. }
  34. _, y, str := self.handler.render_lines.InRectangle(lines, 0, 2, int(sz.WidthCells), int(sz.HeightCells), &self.handler.mouse_state, self.on_click)
  35. lp.QueueWriteString(str)
  36. num_lines_per_font := ((int(sz.HeightCells) - y - 1) / 4) - 2
  37. num_lines := max(1, num_lines_per_font)
  38. key := faces_preview_key{settings: self.settings, width: int(sz.WidthCells * sz.CellWidth), height: int(sz.CellHeight) * num_lines}
  39. self.preview_cache_mutex.Lock()
  40. defer self.preview_cache_mutex.Unlock()
  41. previews, found := self.preview_cache[key]
  42. if !found {
  43. self.preview_cache[key] = make(map[string]RenderedSampleTransmit)
  44. go func() {
  45. var r map[string]RenderedSampleTransmit
  46. s := key.settings
  47. self.handler.set_worker_error(kitty_font_backend.query("render_family_samples", map[string]any{
  48. "text_style": self.handler.text_style, "font_family": s.font_family,
  49. "bold_font": s.bold_font, "italic_font": s.italic_font, "bold_italic_font": s.bold_italic_font,
  50. "width": key.width, "height": key.height, "output_dir": self.handler.temp_dir,
  51. }, &r))
  52. self.preview_cache_mutex.Lock()
  53. defer self.preview_cache_mutex.Unlock()
  54. self.preview_cache[key] = r
  55. self.handler.lp.WakeupMainThread()
  56. }()
  57. return
  58. }
  59. if len(previews) < 4 {
  60. return
  61. }
  62. slot := 0
  63. d := func(setting, title string) {
  64. r := previews[setting]
  65. num_lines := int(math.Ceil(float64(r.Canvas_height) / float64(sz.CellHeight)))
  66. if int(sz.HeightCells)-y < num_lines+1 {
  67. return
  68. }
  69. lp.MoveCursorTo(1, y+1)
  70. _, y, str = self.handler.render_lines.InRectangle([]string{title + ": " + previews[setting].Psname}, 0, y, int(sz.WidthCells), int(sz.HeightCells), &self.handler.mouse_state, self.on_click)
  71. lp.QueueWriteString(str)
  72. if y+num_lines < int(sz.HeightCells) {
  73. lp.MoveCursorTo(1, y+1)
  74. self.handler.graphics_manager.display_image(slot, r.Path, r.Canvas_width, r.Canvas_height)
  75. slot++
  76. y += num_lines + 1
  77. }
  78. }
  79. d(`font_family`, styled(highlight_key_style, "R")+`egular`)
  80. d(`bold_font`, styled(highlight_key_style, "B")+`old`)
  81. d(`italic_font`, styled(highlight_key_style, "I")+`talic`)
  82. d(`bold_italic_font`, "B"+styled(highlight_key_style, "o")+`ld-Italic`)
  83. return
  84. }
  85. func (self *faces) initialize(h *handler) (err error) {
  86. self.handler = h
  87. self.preview_cache = make(map[faces_preview_key]map[string]RenderedSampleTransmit)
  88. return
  89. }
  90. func (self *faces) on_wakeup() error {
  91. return self.handler.draw_screen()
  92. }
  93. func (self *faces) on_click(id string) (err error) {
  94. return
  95. }
  96. func (self *faces) on_key_event(event *loop.KeyEvent) (err error) {
  97. if event.MatchesPressOrRepeat("esc") {
  98. event.Handled = true
  99. self.handler.current_pane = &self.handler.listing
  100. return self.handler.draw_screen()
  101. }
  102. if event.MatchesPressOrRepeat("enter") {
  103. event.Handled = true
  104. return self.handler.final_pane.on_enter(self.family, self.settings)
  105. }
  106. return
  107. }
  108. func (self *faces) on_text(text string, from_key_event bool, in_bracketed_paste bool) (err error) {
  109. if from_key_event {
  110. which := ""
  111. switch text {
  112. case "r", "R":
  113. which = "font_family"
  114. case "b", "B":
  115. which = "bold_font"
  116. case "i", "I":
  117. which = "italic_font"
  118. case "o", "O":
  119. which = "bold_italic_font"
  120. }
  121. if which != "" {
  122. return self.handler.face_pane.on_enter(self.family, which, self.settings)
  123. }
  124. }
  125. return
  126. }
  127. func (self *faces) on_enter(family string) error {
  128. if family != "" {
  129. self.family = family
  130. r := self.handler.listing.resolved_faces_from_kitty_conf
  131. d := func(conf ResolvedFace, setting *string, defval string) {
  132. s := utils.IfElse(conf.Setting == "auto", "auto", conf.Spec)
  133. *setting = utils.IfElse(family == conf.Family, s, defval)
  134. }
  135. d(r.Font_family, &self.settings.font_family, fmt.Sprintf(`family="%s"`, family))
  136. d(r.Bold_font, &self.settings.bold_font, "auto")
  137. d(r.Italic_font, &self.settings.italic_font, "auto")
  138. d(r.Bold_italic_font, &self.settings.bold_italic_font, "auto")
  139. }
  140. self.handler.current_pane = self
  141. return self.handler.draw_screen()
  142. }