02 Jan, 2010, Twisol wrote in the 21st comment:
Votes: 0
I've put in a lot of new changes to MiniWidget in the past couple weeks, mainly the addition of hotspot support (at last). I'm finding it difficult to progress without any feedback at all, so if anyone feels like messing around with the framework I would really appreciate hearing your thoughts.

I'm currently working on a proof-of-concept scrollbar widget, to exercise the hotspot abstraction layer. Mouse-drag events haven't quite been added yet because I'm still thinking about how I want the abstraction layer to behave, but it should otherwise be perfectly workable. A minor point to note, however, is that with raw MUSHclient miniwindows/hotspots, you always receive a cancelmouseover prior to a mousedown, and a mouseover after a mouseup (or cancelmousedown); under my framework, that doesn't happen, and it hides the intermediate events from you. If you mouse over a hotspot region under the framework and click on it, you will only receive mouseover, mousedown, mouseup (or cancelmousedown), in that order.

EDIT: I've updated the project's wiki page on GitHub to include installation directions. I'd be glad to upload my TicTacToe plugin as well if there's interest, though it's a bit messy.
02 Jan, 2010, tphegley wrote in the 22nd comment:
Votes: 0
Is there a link on how to set this up? I've never really dealt with mushclient's more advanced things. I'll mess around with it though.

edit
To clarify, how to set up a widget/code, not how to install your zip folder, i've already done that.
02 Jan, 2010, Twisol wrote in the 23rd comment:
Votes: 0
Well, at the moment there are only two standard widgets supplied with the framework: CharacterGrid and Gauge. You can either mess around with them, or try your hand at writing your own widget, but I'll assume you'd rather try using one of mine for now. You'll need to put this code into a plugin if you plan on using hotspots (though v4.46 of MUSHclient should be removing this restriction). If not, the script file will do just as well. (Also, please note that you'll need MUSHclient v4.45 in order for the hotspot support to work at all.)


First, you need to require() the library itself, then load any widgets you want to use. The library creates a global MWidget table, and it relies on its existence, so don't remove it.

Next, you'll want to set up your widgets. I like to do this in OnPluginInstall, and destroy them in OnPluginClose, so that you never have any unowned miniwindows hanging around.

Every widget can be 'viewed'; no widget is actually seen onscreen until a view is created for it or one of its owners. The view is the visual area you see, which you can move around the screen using v:Move(x, y); it defaults to (0,0). You use v:Refresh() in order to redraw the viewed area, but if you changed some property of a widget, and it doesn't invalidate itself automatically, you'll also need to use widget:Invalidate() to mark it as needing redrawing. (CharacterGrid doesn't do any automatic invalidation yet, because you can change the properties of its cells directly. Gauge does, on the other hand, because you only change it using :Value() and the like)

Below is a simple plugin I wrote early in the MiniWidget development in order to test things as I changed them, called TicTacToe. You can save it as a .xml file in your plugins directory and install it, and a white box should appear in the middle. You can mouse over it, click it to move, and it gives the most recent move of either player a colored background so you can keep track. (The ttt= alias is for debugging, but feel free to use it to look at the internals.)

<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE muclient>

<muclient>
<plugin
name="TicTacToe"
author="Soludra"
id="03829336f30e9f2dcace86e9"
language="Lua"
purpose="Play a game of Tic Tac Toe!"
date_written="2009-11-22 07:46:00"
requires="4.45"
version="1.2"
/>

<!– Triggers –>

<triggers>
</triggers>

<!– Aliases –>

<aliases>
<alias
match="^ttt=(.*)$"
enabled="y"
regexp="y"
send_to="12"
ignore_case="y"
sequence="100"
>
<send>print(%1)</send>
</alias>
</aliases>

<!– Script –>

<script>
<![CDATA[

require('tprint')

local MWidget = require("MWidget")
local CharacterGrid = MWidget.Load("CharacterGrid")

– Defines the default grid font.
local TICTACTOE_FONT = "Lucida Console"

local players = {
[1] = {
piece = 'X',
color = 0x00FF00,
lastmove = nil,
},
[2] = {
piece = 'O',
color = 0x0000FF,
lastmove = nil,
},
}
local current_player = 1
local cells_played = {}

local CheckRow = function(cell1, cell2, cell3)
if cell1.char ~= ' ' and
cell1.char == cell2.char and
cell2.char == cell3.char then
cell1.forecolor, cell2.forecolor, cell3.forecolor = 0xFF0000, 0xFF0000, 0xFF0000
return true
else
return false
end
end

local CheckWin = function()
local done = CheckRow(grid:Cell(1, 1), grid:Cell(1, 2), grid:Cell(1, 3)) or
CheckRow(grid:Cell(2, 1), grid:Cell(2, 2), grid:Cell(2, 3)) or
CheckRow(grid:Cell(3, 1), grid:Cell(3, 2), grid:Cell(3, 3)) or
CheckRow(grid:Cell(1, 1), grid:Cell(2, 1), grid:Cell(3, 1)) or
CheckRow(grid:Cell(1, 2), grid:Cell(2, 2), grid:Cell(3, 2)) or
CheckRow(grid:Cell(1, 3), grid:Cell(2, 3), grid:Cell(3, 3)) or
CheckRow(grid:Cell(1, 1), grid:Cell(2, 2), grid:Cell(3, 3)) or
CheckRow(grid:Cell(3, 1), grid:Cell(2, 2), grid:Cell(1, 3))

if done then
for y = 1,3 do
for x = 1,3 do
local hotspot = grid:Cell(x, y).hotspot

hotspot:SetHandler("mouseup", nil)
hotspot:SetHandler("mouseover", nil)
hotspot:SetHandler("cancelmouseover", nil)
end
end
end

return done
end

local CellClick = function(hotspot, event)
local grid = hotspot:GetOwner()
local cell = grid:HotspotToCell(hotspot)

if cells_played[cell] then
return
end
cells_played[cell] = true

local player = players[current_player]
if player.lastmove then
player.lastmove.backcolor = 0xFFFFFF
end

cell.char = player.piece
cell.backcolor = player.color
cell.forecolor = 0x000000

CheckWin()

player.lastmove = cell
current_player = (current_player%2) + 1

grid:Invalidate()
event.view:Refresh()
end

local CellFocus = function(hotspot, event)
local grid = hotspot:GetOwner()
local cell = grid:HotspotToCell(hotspot)

if cells_played[cell] then
return
end

cell.forecolor = players[current_player].color
cell.char = players[current_player].piece

grid:Invalidate()
event.view:Refresh()
end

local CellBlur = function(hotspot, event)
local grid = hotspot:GetOwner()
local cell = grid:HotspotToCell(hotspot)

if cells_played[cell] then
return
end

cell.forecolor = 0x000000
cell.char = ' '

grid:Invalidate()
event.view:Refresh()
end

local ResetTTT = function()
current_player = 1

grid:ResetGrid()

for y = 1, 3 do
for x = 1, 3 do
local cell = grid:Cell(x, y)

cell.forecolor = 0x000000
cell.hotspot:SetHandler("mouseover", CellFocus)
cell.hotspot:SetHandler("cancelmouseover", CellBlur)
cell.hotspot:SetHandler("mouseup", CellClick)
cell.hotspot:SetHandler("cancelmousedown", CellBlur)
end
end

v:Refresh()
end

OnPluginInstall = function()
grid = CharacterGrid.new(3, 3)
grid:Font(TICTACTOE_FONT, 15)
grid.canvas.backcolor = 0xFFFFFF

v = grid:GetView()
v:Anchor(12)

ResetTTT()
end

OnPluginClose = function()
v:Destroy()
grid:Destroy()
end

OnPluginEnable = OnPluginInstall
OnPluginDisable = OnPluginClose

]]>
</script>
</muclient>


I'm sure there are many ways I could have written the TicTacToe gameplay itself better, but the whole point was only to use it as a testing plugin for the framework. ;)
20.0/23