Posted by
| Nick Gammon
Australia (23,133 posts) Bio
Forum Administrator |
Message
| Well it is quite tricky to get perfect. This demo plugin should help. It simply catches all lines from the MUD and copies them to a miniwindow, keeping colours, and wrapping if the lines won't fit.
|
To save and install the Chat_Window_Demo plugin do this:
- Copy between the lines below (to the Clipboard)
- Open a text editor (such as Notepad) and paste the plugin into it
- Save to disk on your PC, preferably in your plugins directory, as Chat_Window_Demo.xml
- Go to the MUSHclient File menu -> Plugins
- Click "Add"
- Choose the file Chat_Window_Demo.xml (which you just saved in step 3) as a plugin
- Click "Close"
|
<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE muclient>
<muclient>
<plugin
name="Chat_Window_Demo"
author="Nick Gammon"
id="93068d80a35c123ed55376dc"
language="Lua"
purpose="Redirects all output to a miniwindow"
date_written="2010-01-11 10:04"
requires="4.37"
version="2.0"
>
</plugin>
<triggers>
<trigger
enabled="y"
match="*"
script="chat_handler"
sequence="100"
>
</trigger>
</triggers>
<!-- Script -->
<script>
<![CDATA[
require "copytable"
-- configuration
-- window size in pixels
WINDOW_WIDTH = 400
WINDOW_HEIGHT = 800
MAX_LINES = 1000 -- how many lines to store
-- font
FONT_NAME = "Dina"
FONT_SIZE = 8
-- where to put the window
WINDOW_POSITION = 6
-- colours
WINDOW_BACKGROUND_COLOUR = 0x111111
-- offset of text from edge
TEXT_INSET = 5
-- where to store the chat line
lines = {} -- table of recent chat lines
-- display one line
function Display_Line (line, styles)
local left = TEXT_INSET
local top = (line - 1) * font_height
for _, v in ipairs (styles) do
left = left + WindowText (win, "f", v.text, left, top, 0, 0, v.textcolour)
end -- for each style run
end -- Display_Line
-- here on chat line
function chat_handler (name, line, wildcards, styles)
-- blank existing window contents
WindowRectOp (win, 2, 0, 0, 0, 0, WINDOW_BACKGROUND_COLOUR)
WindowRectOp (win, 5, 0, 0, 0, 0, 5, 15)
local avail = 0
local line_styles
-- blank line? force one entry
if #styles == 0 then
-- remove first line if filled up
if #lines >= MAX_LINES then
table.remove (lines, 1)
end -- if
table.insert (lines, {})
end -- if
-- keep pulling out styles and trying to fit them on the current line
while #styles > 0 do
-- no room available? start new line
if avail <= 0 then
-- remove first line if filled up
if #lines >= MAX_LINES then
table.remove (lines, 1)
end -- if
avail = WINDOW_WIDTH - (TEXT_INSET * 2)
line_styles = {}
table.insert (lines, line_styles)
end -- line full
-- get first style, work out how long it is
local style = table.remove (styles, 1) -- pull out first style
local width = WindowTextWidth (win, "f", style.text) -- how long this style is
-- if it fits, copy whole style in
if width <= avail then
table.insert (line_styles, style)
avail = avail - width
else -- otherwise, have to split style
-- look for trailing space (work backwards)
-- remember where space is
local col = style.length - 1
local split_col
-- keep going until out of columns
while col > 1 do
width = WindowTextWidth (win, "f", style.text:sub (1, col))
if width <= avail then
if not split_col then
split_col = col -- in case no space found, this is where we can split
end -- if
-- see if space here
if style.text:sub (col, col) == " " then
split_col = col
break
end -- if space
end -- if will now fit
col = col - 1
end -- while
-- if we found a place to split, use old style, and make it shorter
-- also make a copy and put the rest in that
if split_col then
table.insert (line_styles, style)
local style_copy = copytable.shallow (style)
style.text = style.text:sub (1, split_col)
style.length = split_col
style_copy.text = style_copy.text:sub (split_col + 1)
style_copy.length = #style_copy.text
table.insert (styles, 1, style_copy)
else
if next (line_styles) == nil then
table.insert (line_styles, style)
else
table.insert (styles, 1, style)
end -- if
end -- if
avail = 0 -- now we need to wrap
end -- if could not fit whole thing in
end -- while we still have styles over
-- display all lines
local first_visible = #lines - visible_lines
if first_visible < 1 then
first_visible = 1
end -- if
local count = 0
for i = first_visible, #lines do
count = count + 1
Display_Line (count, lines [i])
end -- for
-- force window redisplay
WindowShow (win, true) -- show it
end -- end chat_handler
-- startup stuff
win = GetUniqueID () -- get a unique name
-- make the window
WindowCreate (win, 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, WINDOW_POSITION, 0,
WINDOW_BACKGROUND_COLOUR) -- create window
-- grab a font
WindowFont (win, "f", FONT_NAME, FONT_SIZE) -- define font
-- work out how high it is
font_height = WindowFontInfo (win, "f", 1) -- height of the font
-- work out how many lines will fit
visible_lines = math.floor (WINDOW_HEIGHT / font_height) - 1
]]>
</script>
</muclient>
Basically when a line arrives, we have to gradually add the styles from that input line, into the saved line for the miniwindow, stopping when it won't fit. However if it won't fit, we need to examine the last style (the one that won't fit totally) and look backwards for a space, that happens to be inside the "fitting" area.
It looks messy, maybe someone can do a better job. |
- Nick Gammon
www.gammon.com.au, www.mushclient.com | Top |
|