123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226 |
- package choose_fonts
- import (
- "fmt"
- "os"
- "strconv"
- "sync"
- "kitty/tools/tui"
- "kitty/tools/tui/graphics"
- "kitty/tools/tui/loop"
- "kitty/tools/utils"
- )
- var _ = fmt.Print
- type State int
- const (
- SCANNING_FAMILIES State = iota
- LISTING_FAMILIES
- CHOOSING_FACES
- )
- type TextStyle struct {
- Font_sz float64 `json:"font_size"`
- Dpi_x float64 `json:"dpi_x"`
- Dpi_y float64 `json:"dpi_y"`
- Foreground string `json:"foreground"`
- Background string `json:"background"`
- }
- type pane interface {
- initialize(*handler) error
- draw_screen() error
- on_wakeup() error
- on_key_event(event *loop.KeyEvent) error
- on_text(text string, from_key_event bool, in_bracketed_paste bool) error
- on_click(id string) error
- }
- type handler struct {
- opts *Options
- lp *loop.Loop
- state State
- err_mutex sync.Mutex
- err_in_worker_thread error
- mouse_state tui.MouseState
- render_count uint
- render_lines tui.RenderLines
- text_style TextStyle
- graphics_manager graphics_manager
- temp_dir string
- listing FontList
- faces faces
- face_pane face_panel
- if_pane if_panel
- final_pane final_pane
- panes []pane
- current_pane pane
- }
- func (h *handler) set_worker_error(err error) {
- h.err_mutex.Lock()
- defer h.err_mutex.Unlock()
- h.err_in_worker_thread = err
- }
- func (h *handler) get_worker_error() error {
- h.err_mutex.Lock()
- defer h.err_mutex.Unlock()
- return h.err_in_worker_thread
- }
- // Events {{{
- func (h *handler) initialize() (err error) {
- h.lp.SetCursorVisible(false)
- h.lp.OnQueryResponse = h.on_query_response
- h.lp.QueryTerminal("font_size", "dpi_x", "dpi_y", "foreground", "background")
- h.panes = []pane{&h.listing, &h.faces, &h.face_pane, &h.if_pane, &h.final_pane}
- for _, pane := range h.panes {
- if err = pane.initialize(h); err != nil {
- return err
- }
- }
- // dont use /tmp as it may be mounted in RAM, Le Sigh
- if h.temp_dir, err = os.MkdirTemp(utils.CacheDir(), "kitten-choose-fonts-*"); err != nil {
- return
- }
- initialize_variable_data_cache()
- h.graphics_manager.initialize(h.lp)
- go func() {
- var r ListResult
- h.set_worker_error(kitty_font_backend.query("list_monospaced_fonts", nil, &r))
- h.listing.fonts = r.Fonts
- h.listing.resolved_faces_from_kitty_conf = r.Resolved_faces
- h.lp.WakeupMainThread()
- }()
- h.draw_screen()
- return
- }
- func (h *handler) finalize() {
- if h.temp_dir != "" {
- os.RemoveAll(h.temp_dir)
- h.temp_dir = ""
- }
- h.lp.SetCursorVisible(true)
- h.lp.SetCursorShape(loop.BLOCK_CURSOR, true)
- h.graphics_manager.finalize()
- }
- func (h *handler) on_query_response(key, val string, valid bool) error {
- if !valid {
- return fmt.Errorf("Terminal does not support querying the: %s", key)
- }
- set_float := func(k, v string, dest *float64) error {
- if fs, err := strconv.ParseFloat(v, 64); err == nil {
- *dest = fs
- } else {
- return fmt.Errorf("Invalid response from terminal to %s query: %#v", k, v)
- }
- return nil
- }
- switch key {
- case "font_size":
- if err := set_float(key, val, &h.text_style.Font_sz); err != nil {
- return err
- }
- case "dpi_x":
- if err := set_float(key, val, &h.text_style.Dpi_x); err != nil {
- return err
- }
- case "dpi_y":
- if err := set_float(key, val, &h.text_style.Dpi_y); err != nil {
- return err
- }
- case "foreground":
- h.text_style.Foreground = val
- case "background":
- h.text_style.Background = val
- return h.draw_screen()
- }
- return nil
- }
- func (h *handler) draw_screen() (err error) {
- h.render_count++
- h.lp.StartAtomicUpdate()
- defer func() {
- h.mouse_state.UpdateHoveredIds()
- h.mouse_state.ApplyHoverStyles(h.lp)
- h.lp.EndAtomicUpdate()
- }()
- h.graphics_manager.clear_placements()
- h.lp.ClearScreenButNotGraphics()
- h.lp.AllowLineWrapping(false)
- h.mouse_state.ClearCellRegions()
- if h.current_pane == nil {
- h.lp.Println("Scanning system for fonts, please wait...")
- } else {
- return h.current_pane.draw_screen()
- }
- return
- }
- func (h *handler) on_wakeup() (err error) {
- if err = h.get_worker_error(); err != nil {
- return
- }
- if h.current_pane == nil {
- h.current_pane = &h.listing
- }
- return h.listing.on_wakeup()
- }
- func (h *handler) on_mouse_event(event *loop.MouseEvent) (err error) {
- rc := h.render_count
- redraw_needed := false
- if h.mouse_state.UpdateState(event) {
- redraw_needed = true
- }
- if event.Event_type == loop.MOUSE_CLICK && event.Buttons&loop.LEFT_MOUSE_BUTTON != 0 {
- if err = h.mouse_state.ClickHoveredRegions(); err != nil {
- return
- }
- }
- if redraw_needed && rc == h.render_count {
- err = h.draw_screen()
- }
- return
- }
- func (h *handler) on_key_event(event *loop.KeyEvent) (err error) {
- if event.MatchesPressOrRepeat("ctrl+c") {
- event.Handled = true
- return fmt.Errorf("canceled by user")
- }
- if h.current_pane != nil {
- err = h.current_pane.on_key_event(event)
- }
- return
- }
- func (h *handler) on_text(text string, from_key_event bool, in_bracketed_paste bool) (err error) {
- if h.current_pane != nil {
- err = h.current_pane.on_text(text, from_key_event, in_bracketed_paste)
- }
- return
- }
- func (h *handler) on_escape_code(etype loop.EscapeCodeType, payload []byte) error {
- switch etype {
- case loop.APC:
- gc := graphics.GraphicsCommandFromAPC(payload)
- if gc != nil {
- return h.graphics_manager.on_response(gc)
- }
- }
- return nil
- }
- // }}}
|