# jedit_tags.tcl - text tag-manipulation routines for jedit, a tk-based editor
#
######################################################################
# Copyright 1992-1999 by Jay Sekora.  This file may be freely        #
# distributed, modified or unmodified, for any purpose, provided     #
# that this copyright notice is retained verbatim in all copies and  #
# no attempt is made to obscure the authorship of this file.  If you #
# distribute any modified versions, I ask, but do not require, that  #
# you clearly mark any changes you make as such and that you provide #
# your users with instructions for getting the original sources.     #
######################################################################

######################################################################
# font commands - these set the font (tag list) for typing.
#   also, if there is a selection, and the insertion point is in it
#   or abuts it, the selection is set to the specified font.
# NOTE: fonts are registered in jedit_cmds.tcl
######################################################################

######################################################################
# jedit:set_tags t tags - general routine to do the above for any tag
######################################################################

proc jedit:set_tags { t args } {
  foreach tag $args {
    ::aq::tag::set_tag $t $tag
  }
  if [j:text:insert_touches_selection $t] {
    foreach tag $args {
      ::aq::tag::tag_text $t $tag sel.first sel.last
    }
  }
}

######################################################################
# jedit:clear_tags t patterns - 
#   remove tags matching any pattern from tag list, and if appropriate,
#   from selection
######################################################################

proc jedit:clear_tags { t args } {
  foreach pattern $args {
    ::aq::tag::clear_tag $t $pattern
  }
  if [j:text:insert_touches_selection $t] {
    foreach pattern $args {
      ::aq::tag::untag_text $t $pattern sel.first sel.last
    }
  }
}

######################################################################
# font procedures
######################################################################

proc jedit:font:roman { t } {
  jedit:set_tags $t richtext:font:roman
}

proc jedit:font:italic { t } {
  jedit:set_tags $t richtext:font:italic
}

proc jedit:font:bold { t } {
  jedit:set_tags $t richtext:font:bold
}

proc jedit:font:bolditalic { t } {
  jedit:set_tags $t richtext:font:bolditalic
}

proc jedit:font:typewriter { t } {
  jedit:set_tags $t richtext:font:typewriter
}

proc jedit:font:heading0 { t } {
  jedit:set_tags $t richtext:font:heading0
}

proc jedit:font:heading1 { t } {
  jedit:set_tags $t richtext:font:heading1
}

proc jedit:font:heading2 { t } {
  jedit:set_tags $t richtext:font:heading2
}

proc jedit:font:heading3 { t } {
  jedit:set_tags $t richtext:font:heading3
}

proc jedit:font:heading4 { t } {
  jedit:set_tags $t richtext:font:heading4
}

proc jedit:font:heading5 { t } {
  jedit:set_tags $t richtext:font:heading5
}

proc jedit:font:plain { t } {
  jedit:clear_tags $t richtext:font:*
}

######################################################################
# logical fonts for HTML
######################################################################

proc jedit:font:l_em { t } {
  jedit:set_tags $t richtext:font:l_em
}

proc jedit:font:l_cite { t } {
  jedit:set_tags $t richtext:font:l_cite
}

proc jedit:font:l_var { t } {
  jedit:set_tags $t richtext:font:l_var
}

proc jedit:font:l_dfn { t } {
  jedit:set_tags $t richtext:font:l_dfn
}

proc jedit:font:l_strong { t } {
  jedit:set_tags $t richtext:font:l_strong
}

proc jedit:font:l_kbd { t } {
  jedit:set_tags $t richtext:font:l_kbd
}

proc jedit:font:l_code { t } {
  jedit:set_tags $t richtext:font:l_code
}

proc jedit:font:l_samp { t } {
  jedit:set_tags $t richtext:font:l_samp
}

######################################################################
# list procedures
######################################################################

# make sure tags for a particular list level are configured properly

proc jedit:format:configure_list_tags { t level } {
  $t tag configure list:level:$level -relief raised -borderwidth $level
  $t tag configure special:list_item:$level -font {Symbol 12}
  set textmargin [expr {$level * 8}]
  set itemmargin [expr {$textmargin - 4}]
  catch {
    $t tag configure special:list_item:$level \
      -lmargin1 ${itemmargin}m -lmargin2 ${itemmargin}m
    $t tag configure list:level:$level \
      -lmargin1 ${textmargin}m -lmargin2 ${textmargin}m
  }
  # keep list-item tags high
  $t tag raise special:list_item:$level
  # but keep list tags themselves low, so other tags (like sel) override them
  #   (this might mean the margins will be wrong, though, *sigh*)
  $t tag lower list:level:$level
}

# make sure tags for all list levels in the widget are configured properly
#   (useful after loading text)
# this should be moved to text-loading procedures in jtexttags.tcl

proc jedit:format:configure_all_list_tags { t } {
  foreach tag [$t tag names] {
    if {[string match list:level:* $tag]} {
      set level [lindex [split $tag :] 2]
      jedit:format:configure_list_tags $t $level
    }
  }
}
# make the current line a list item (insert a bullet at the beginning of it)

proc jedit:format:list_item { t args } {
  global j_tag
  
  # first see if we're already in a list, and if so at what level
  set tags $j_tag(tags,$t)
  $t mark set insert_save insert
  set leveltagindex [lsearch -glob $tags list:level:*]
  if {$leveltagindex < 0} {
    # not already in a list; default to level 1
    jedit:set_tags $t list:1:ul		;# force being in a list
    jedit:set_tags $t list:level:1
    set level 1
    # and make sure level 1 is configured
    jedit:format:configure_list_tags $t 1
  } else {
    # already in a list; use existing level
    set leveltag [lindex $tags $leveltagindex]
    set level [lindex [split $leveltag :] 2]
  }
  
  # find the beginning of the line
  set start "[$t index insert] linestart"
  
  # only makes sense to insert at the beginning of a line,
  # so if we're not already there...
  
  if {[$t compare $start != insert]} {
    # make sure everything between the start of line and the insert point
    # is part of an appropriate list.
    ::aq::tag::tag_text $t list:$level:ul $start insert_save
    ::aq::tag::tag_text $t list:level:$level $start insert_save
    
    # move to beginning of line
    j:text:move $t $start
  }
  # set appropriate list tags (changed by move)
  ::aq::tag::set_tag $t list:$level:ul
  ::aq::tag::set_tag $t list:level:$level
  ::aq::tag::set_tag $t richtext:font:roman
  
  # insert bullet (tagged appropriately)
  j:text:insert_string $t "\xb7 "	;# 0xb7 is bullet in symbol font
  $t tag add special:list_item:$level $start
  
  if {[$t compare insert != insert_save]} {
    j:text:move $t insert_save
  }
  
  # restore tags in effect before bullet inserted
  eval ::aq::tag::set_tags [list $t] $tags
  # but make sure we're still in the right kind of list
  jedit:set_tags $t list:$level:ul
  jedit:set_tags $t list:level:$level
}

proc jedit:format:nest_list { t } {
  global j_tag
  
  # first see if we're already in a list, and if so at what level
  set tags $j_tag(tags,$t)
  set leveltagindex [lsearch -glob $tags list:level:*]
  if {$leveltagindex < 0} {
    # not already in a list; default to level 1
    jedit:set_tags $t list:1:ul		;# force being in a list
    jedit:set_tags $t list:level:1
    set level 1
  } else {
    # already in a list; find and increment existing level
    set leveltag [lindex $tags $leveltagindex]
    set level [lindex [split $leveltag :] 2]
    incr level
  }
  # apply appropriate tags for new list level
  jedit:set_tags $t list:$level:ul
  jedit:set_tags $t list:level:$level
  # and make sure tags are configured
  jedit:format:configure_list_tags $t $level
}

proc jedit:format:unnest_list { t } {
  global j_tag
  
  # do nothing if _not_ already in a list
  set tags $j_tag(tags,$t)
  set leveltagindex [lsearch -glob $tags list:level:*]
  if {$leveltagindex < 0} {
    # not already in a list; default to level 0
    set level 0
  } else {
    # already in a list; find and decrement existing level
    set leveltag [lindex $tags $leveltagindex]
    set level [lindex [split $leveltag :] 2]
    incr level -1
  }
  # if level is 0, clear all current list tags
  if {$level == 0} {
    jedit:clear_tags $t list:*
  } else {
    # apply appropriate tags for new list level
    jedit:set_tags $t list:$level:ul
    jedit:set_tags $t list:level:$level
  }
}

######################################################################
# other procedures
######################################################################

proc jedit:format:background { t colour } {
  jedit:set_tags $t display:background:$colour
}

proc jedit:format:foreground { t colour } {
  jedit:set_tags $t display:foreground:$colour
}

proc jedit:format:underline { t state } {
  if $state {
    jedit:set_tags $t display:underline:1
  } else {
    jedit:clear_tags $t display:underline:*
  }
}

proc jedit:format:background:clear { t } {
  jedit:clear_tags $t display:background:*
}

proc jedit:format:foreground:clear { t } {
  jedit:clear_tags $t display:foreground:*
}
