'OHRRPGCE CUSTOM - Font editor
'(C) Copyright 1997-2020 James Paige, Ralph Versteegen, and the OHRRPGCE Developers
'Dual licensed under the GNU GPL v2+ and MIT Licenses. Read LICENSE.txt for terms and disclaimer of liability.

#include "config.bi"
#include "allmodex.bi"
#include "common.bi"
#include "loading.bi"
#include "const.bi"
#include "cglobals.bi"
#include "custom.bi"
#include "customsubs.bi"


'Subs and functions only used here
DECLARE FUNCTION edit_font_picker_point(byval pixelpos as XYPair) as integer
DECLARE FUNCTION edit_font_draw_point(byval pixelpos as XYPair) as XYPair
DECLARE SUB fontedit_export_font(fnt() as integer)
DECLARE SUB fontedit_import_font(fnt() as integer)



SUB font_test_menu
 DIM menu(...) as string = {"Font 0", "Font 1", "Font 2", "Font 3"}
 DIM st as MenuState
 st.last = UBOUND(menu)
 st.size = 22

 DIM controls as string = "1: import from 'fonttests/testfont/', 2: import from bmp, 3: create edged font, 4: create shadow font"

 DO
  setwait 55
  setkeys
  IF keyval(ccCancel) > 1 THEN EXIT DO
  IF keyval(sc1) > 1 THEN
   DIM fallback as Font ptr = fonts(st.pt)
   IF fallback = 0 THEN fallback = fonts(0)
   DIM newfont as Font ptr = font_loadbmps("fonttests/testfont", fallback)
   font_unload @fonts(st.pt)
   fonts(st.pt) = newfont
  END IF
  IF keyval(sc2) > 1 THEN
   DIM filen as string
   filen = browse(browsePalettedImage, "")
   IF LEN(filen) THEN
    font_unload @fonts(st.pt)
    fonts(st.pt) = font_load_16x16(filen)
   END IF
  END IF
  IF keyval(sc3) > 1 THEN
   DIM choice as integer
   choice = multichoice("Create an edged font from which font?", menu())
   IF choice > -1 THEN
    DIM newfont as Font ptr = font_create_edged(fonts(choice))
    font_unload @fonts(st.pt)
    fonts(st.pt) = newfont
   END IF
  END IF
  IF keyval(sc4) > 1 THEN
   DIM choice as integer
   choice = multichoice("Create a drop-shadow font from which font?", menu())
   IF choice > -1 THEN
    DIM newfont as Font ptr = font_create_shadowed(fonts(choice), 2, 2)
    font_unload @fonts(st.pt)
    fonts(st.pt) = newfont
   END IF
  END IF

  usemenu st

  clearpage vpage, findrgb(80,80,80)
  'edgeboxstyle 10, 10, 300, 185, 0, vpage
  standardmenu menu(), st, , , vpage
  textcolor uilook(uiText), 0
  wrapprint controls, pInfoX, pInfoY, , vpage

  FOR i as integer = 0 TO 15
   DIM row as string
   FOR j as integer = i * 16 TO i * 16 + 15
    row &= CHR(j)
   NEXT
   IF fonts(st.pt) THEN
    printstr row, 145, 0 + i * fonts(st.pt)->line_h, vpage, YES, st.pt
   END IF
  NEXT

  setvispage vpage
  dowait
 LOOP
END SUB

SUB font_editor (fnt() as integer)
 DIM f(255) as integer  'Contains the character indices which should be shown (always 32-255)
 DIM copybuf(4) as integer
 DIM menu(6) as string
 DIM selectable(6) as bool
 flusharray selectable(), , YES

 menu(0) = "Previous Menu"
 menu(1) = "Edit Font..."
 menu(2) = "Import Font..."
 menu(3) = "Export Font..."
 selectable(4) = NO
 menu(5) = ""  'Set below
 selectable(6) = NO

 DIM i as integer

 DIM last as integer = -1
 FOR i = 32 TO 255
  last += 1
  f(last) = i
 NEXT i

 'mode = -1: the menu
 'mode = 0:  select a character to edit
 'mode = 1:  editing a character
 DIM mode as integer = -1

 'This state is used for the menu, not the charpicker
 DIM state as MenuState
 WITH state
  .pt = 0
  .top = 0
  .last = UBOUND(menu)
  .size = 22
 END WITH

 DIM fonttype as fontTypeEnum = get_font_type(fnt())

 DIM linesize as integer = 14
 DIM pt as integer = -1 * linesize

 DIM x as integer
 DIM y as integer
 
 DIM xoff as integer
 DIM yoff as integer
 
 DIM c as integer
 DIM hover_char as integer
 DIM hover_draw as XYPair

 setkeys
 DO
  setwait 55
  setkeys
  IF keyval(scF1) > 1 THEN show_help "fontedit"
  hover_char = edit_font_picker_point(readmouse.pos)
  hover_draw = edit_font_draw_point(readmouse.pos)
  SELECT CASE mode
   CASE -1 ' Main font menu
    IF keyval(ccCancel) > 1 THEN EXIT DO
    usemenu state, selectable()
    IF enter_space_click(state) THEN
     IF state.pt = 0 THEN EXIT DO
     IF state.pt = 1 THEN
      mode = 0
      readmouse.clearclick(mouseLeft)
     END IF
     IF state.pt = 2 THEN
      fontedit_import_font fnt()
      fonttype = get_font_type(fnt())
      state.pt = 1
      mode = 0
     END IF
     IF state.pt = 3 THEN fontedit_export_font fnt()
    END IF
    IF state.pt = 5 THEN
     IF intgrabber(fonttype, ftypeASCII, ftypeLatin1) THEN
      set_font_type fnt(), fonttype
      xbsave game + ".fnt", fnt(), 2048
     END IF
    END IF
   CASE 0 'Picking a character to edit
    IF keyval(ccCancel) > 1 THEN mode = -1
    IF keyval(ccUp) > 1 THEN pt = large(pt - linesize, -1 * linesize)
    IF keyval(ccDown) > 1 THEN pt = small(pt + linesize, last)
    IF keyval(ccLeft) > 1 THEN pt = large(pt - 1, 0)
    IF keyval(ccRight) > 1 THEN pt = small(pt + 1, last)
    IF enter_or_space() THEN
     IF pt < 0 THEN
      mode = -1
     ELSE
      mode = 1
      x = 0
      y = 0
     END IF
    END IF
   CASE 1 ' Editing a character
    IF keyval(ccCancel) > 1 OR keyval(scAnyEnter) > 1 THEN mode = 0
    IF keyval(ccUp) > 1 THEN loopvar y, 0, 7, -1
    IF keyval(ccDown) > 1 THEN loopvar y, 0, 7, 1
    IF keyval(ccLeft) > 1 THEN loopvar x, 0, 7, -1
    IF keyval(ccRight) > 1 THEN loopvar x, 0, 7, 1
    IF keyval(scSpace) > 1 THEN
     setbit fnt(), 0, (f(pt) * 8 + x) * 8 + y, (readbit(fnt(), 0, (f(pt) * 8 + x) * 8 + y) XOR 1)
     setfont fnt()
     xbsave game + ".fnt", fnt(), 2048
    END IF
  END SELECT
  IF mode >= 0 THEN 'Stuff that happens in both picking and editing mode
   '--copy and paste support
   IF copy_keychord() THEN
    FOR i = 0 TO 63
     setbit copybuf(), 0, i, readbit(fnt(), 0, f(pt) * 64 + i)
    NEXT i
   END IF
   IF paste_keychord() THEN
    FOR i = 0 TO 63
     setbit fnt(), 0, f(pt) * 64 + i, readbit(copybuf(), 0, i)
    NEXT i
    setfont fnt()
    xbsave game + ".fnt", fnt(), 2048
   END IF
   '--clicking on the "Previous menu" label
   IF readmouse.release AND mouseLeft THEN
    IF rect_collide_point(str_rect(menu(0), 0, 0), readmouse.pos) THEN
     mode = -1
    END IF
   END IF
   '--Clicking on a character to edit
   IF readmouse.release AND (mouseLeft OR mouseRight) THEN
    IF hover_char >= 0 THEN
     pt = hover_char
     mode = 0
    END IF
   END IF
   '--Clicking on a pixel to draw
   IF readmouse.buttons AND (mouseLeft OR mouseRight) THEN
    IF pt >= 0 ANDALSO hover_draw.x >= 0 ANDALSO hover_draw.y >= 0 THEN
     mode = 1
     x = hover_draw.x
     y = hover_draw.y
     DIM setpix as integer = 0
     IF readmouse.buttons AND mouseLeft THEN setpix = 1
     setbit fnt(), 0, (f(pt) * 8 + x) * 8 + y, setpix
     setfont fnt()
     xbsave game + ".fnt", fnt(), 2048
    END IF
   END IF
  END IF

  '--Draw screen
  clearpage dpage

  IF mode = -1 THEN
   menu(5) = "Font type: "
   IF fonttype = ftypeASCII THEN
    menu(5) &= "ASCII"
    menu(6) = " (Characters 127-255 are icons)"
   ELSEIF fonttype = ftypeLatin1 THEN
    menu(5) &= "Latin1"
    menu(6) = " (Characters 127-160 are icons)"
   END IF

   standardmenu menu(), state, , , dpage
  END IF

  IF mode >= 0 THEN
   state.tog XOR= 1'keep state.tog going even though we don't call standardmenu
   xoff = 8
   yoff = 8
   FOR i = 0 TO last
    textcolor uilook(uiMenuItem), uilook(uiDisabledItem)
    DIM cpos as XYPair = XY(xoff + (i MOD linesize) * 9, yoff + (i \ linesize) * 9)
    IF pt >= 0 THEN
     IF mode = 0 THEN
      IF (i MOD linesize) = (pt MOD linesize) OR (i \ linesize) = (pt \ linesize) THEN textcolor uilook(uiMenuItem), uilook(uiHighlight)
     END IF
    END IF
    IF hover_char = i THEN textcolor uilook(uiMouseHoverItem), uilook(uiSelectedDisabled)
    IF pt = i THEN textcolor uilook(uiSelectedItem + state.tog), 0
    printstr CHR(f(i)), cpos.x, cpos.y, dpage
   NEXT i
   textcolor uilook(uiMenuItem), 0
   IF rect_collide_point(str_rect(menu(0), 0, 0), readmouse.pos) THEN
    textcolor uilook(uiMouseHoverItem), 0
   END IF
   IF pt < 0 THEN textcolor uilook(uiSelectedItem + state.tog), 0
   printstr menu(0), 8, 0, dpage

   IF pt >= 0 THEN
    xoff = 150
    yoff = 4
    rectangle xoff, yoff, 160, 160, uilook(uiDisabledItem), dpage
    FOR i = 0 TO 7
     FOR j as integer = 0 TO 7
      IF readbit(fnt(), 0, (f(pt) * 8 + i) * 8 + j) THEN
       c = uilook(uiMenuItem)
       rectangle xoff + i * 20, yoff + j * 20, 20, 20, c, dpage
      END IF
     NEXT j
    NEXT i
    IF mode = 1 THEN
     IF readbit(fnt(), 0, (f(pt) * 8 + x) * 8 + y) THEN
      c = uilook(uiSelectedItem2)
     ELSE
      c = uilook(uiSelectedDisabled)
     END IF
     rectangle xoff + x * 20, yoff + y * 20, 20, 20, c, dpage
    END IF
    IF hover_draw.x >= 0 ANDALSO hover_draw.y >= 0 THEN
     edgebox xoff + hover_draw.x * 20, yoff + hover_draw.y * 20, 20, 20, uilook(uiMouseHoverItem), uilook(uiSelectedItem) + state.tog, dpage, transHollow
    END IF
    textcolor uilook(uiText), 0
    DIM tmp as string = "CHAR " & f(pt)
    'Show the \x## code recognised by HSpeak (must be two characters)
    'Only characters past &hA1 are Unicode characters
    IF f(pt) >= 127 THEN tmp &= "  \x" & HEX(f(pt))
    printstr tmp, 12, 190, dpage
    IF f(pt) < 32 THEN
     printstr "RESERVED", 160, 190, dpage
    ELSE
     FOR i = 2 TO 53
      IF f(pt) = ASC(key2text(2, i)) THEN printstr "ALT+" + UCASE(key2text(0, i)), 160, 190, dpage
      IF f(pt) = ASC(key2text(3, i)) THEN printstr "ALT+SHIFT+" + UCASE(key2text(0, i)), 160, 190, dpage
     NEXT i
     IF f(pt) = 32 THEN printstr "SPACE", 160, 190, dpage
    END IF
   END IF
  END IF

  SWAP vpage, dpage
  setvispage vpage
  dowait
 LOOP
END SUB

FUNCTION edit_font_draw_point(byval pixelpos as XYPair) as XYPair
 'Return the font drawing x,y pos that the pixelpos (mouse cursor) is over
 DIM offset as XYPair = XY(150, 4)
 DIM rows as integer = 8
 DIM cols as integer = 8
 DIM tilesize as integer = 20
 DIM areasize as RectType
 corners_to_rect offset, offset + XY(cols, rows) * tilesize, areasize
 IF NOT rect_collide_point(areasize, pixelpos) THEN RETURN XY(-1, -1)
 DIM drawpos as XYPair
 drawpos = pixelpos - offset
 drawpos = drawpos \ tilesize
 RETURN drawpos
END FUNCTION

FUNCTION edit_font_picker_point(byval pixelpos as XYPair) as integer
 'Return the character id that the pixelpos (mouse cursor) collides with or -1 if none
 DIM offset as XYPair = XY(8,8)
 DIM rows as integer = 16
 DIM cols as integer = 14
 DIM tilesize as integer = 9
 DIM areasize as RectType
 corners_to_rect offset, offset + XY(cols, rows) * tilesize, areasize
 IF NOT rect_collide_point(areasize, pixelpos) THEN RETURN -1
 DIM charpos as XYPair
 charpos = pixelpos - offset
 charpos = charpos \ tilesize
 RETURN charpos.y * cols + charpos.x
END FUNCTION

SUB fontedit_export_font(fnt() as integer)

 DIM newfont as string = "newfont"
 newfont = inputfilename("Input a filename to save to", ".ohf", "", "input_file_export_font") 

 IF newfont <> "" THEN
  xbsave game & ".fnt", fnt(), 2048
  copyfile game & ".fnt", newfont & ".ohf"
 END IF

END SUB

SUB fontedit_import_font(fnt() as integer)

 STATIC default as string
 DIM newfont as string
 newfont = browse(browseAny, default, "*.ohf", "browse_font")
 
 IF newfont <> "" THEN
  writeablecopyfile newfont, game & ".fnt"

  DIM i as integer
  DIM font_tmp(1023) as integer

  '--character 0 (actually fnt(0)) contains metadata (marks as ASCII or Latin-1)
  '--character 1 to 31 are internal icons and should never be overwritten
  FOR i = 1 * 4 TO 32 * 4 - 1
   font_tmp(i) = fnt(i)
  NEXT i

  '--Reload the font
  xbload game + ".fnt", fnt(), "Can't load font"
  setfont fnt()

  '--write back the old 1-31 characters
  FOR i = 1 * 4 TO 32 * 4 - 1
   fnt(i) = font_tmp(i)
  NEXT i

 END IF
END SUB
