piecescontainer.rb
require 'Qt'
class PiecesContainer < Qt::Widget
attr_accessor :mode, :dropbox
def initialize title, parent=nil
super parent
@title = Qt::Label.new title
@pieces = []
@top_border = 5
@row = @top_border
@left_border = 5
@col = @left_border
@piece_size = 80
@col_width = @piece_size + 10
@row_height = @piece_size + 10
@num_cols = 2
@view_y = 0
setMinimumSize 220,100
setMaximumWidth 220
layout = Qt::GridLayout.new self
layout.addWidget @title, 0, 0, 1,2, Qt::AlignLeft
@dropbox = Qt::Frame.new{
setFrameStyle Qt::Frame::Panel
setSizePolicy Qt::SizePolicy::MinimumExpanding, Qt::SizePolicy::MinimumExpanding
setMouseTracking true
}
@dropbox.installEventFilter self
layout.addWidget @dropbox, 1, 0, 1, 1
@vertical_scrollbar = Qt::ScrollBar.new Qt::Vertical, self
@vertical_scrollbar.connect(SIGNAL('valueChanged(int)')) do |val|
@dropbox.scroll 0, @view_y - val
@view_y = val
end
layout.addWidget @vertical_scrollbar, 1,1
setLayout layout
@mode = :none
end
def get_pieces
pieces = @pieces.map{ |elem| elem.grid}
end
def load_pieces pieces
pieces.each do |raw_piece|
add_piece Piece.new(raw_piece, @piece_size, @dropbox)
end
update
end
def add_piece piece
@pieces << piece
add_piece_to_grid piece
end
def add_piece_to_grid piece
piece.move @col, @row-@view_y
@col += @col_width
if @col > @num_cols*@col_width
@col = @left_border
@row += @row_height
end
end
def delete_piece piece
piece.hide
@pieces.delete piece
# tidy up grid, basically reset it
@col = @left_border
@row = @top_border
@pieces.each do |piece|
add_piece_to_grid piece
end
end
def enterEvent event
setFocus(Qt::MouseFocusReason)
end
def keyPressEvent event
if event.key == Qt::Key_Escape
@floater.hide unless @floater.nil?
@floater = nil
@mode = :none
end
end
def eventFilter obj, event
if obj == @dropbox
case event.type
when Qt::Event::Enter
if $clipboard.has_item?
@mode = :new_piece_hover
@floater = Piece.new $clipboard.item, @piece_size, @dropbox
@floater.update
$clipboard.item = nil
end
when Qt::Event::Leave
if @mode == :new_piece_hover or @mode == :piece_hover
$clipboard.item = @floater.grid
@floater.hide
@floater = nil
@mode = :none
update
end
when Qt::Event::MouseMove
if @mode == :new_piece_hover or @mode == :piece_hover
@floater.move event.pos.x, event.pos.y
@floater.update
update
end
when Qt::Event::MouseButtonPress
if event.button == Qt::LeftButton
if @mode == :new_piece_hover
add_piece @floater
@floater.floating = false
@floater = nil
@mode = :none
$clipboard.item = nil
update
else
# see if clicked existing piece
piece = @pieces.select{ |piece| piece.underMouse } #return array
unless piece.empty?
@floater = Piece.new piece[0].grid, @piece_size, @dropbox
@floater.move event.pos.x, event.pos.y
@floater.show
@mode = :piece_hover
end
end
elsif event.button == Qt::RightButton
unless @mode != :none
show_context_menu event.pos
end
end
when Qt::Event::Wheel
delta = event.delta/120
@view_y -= delta
if @view_y < 0
@view_y = 0
return
end
@dropbox.scroll 0, delta
@vertical_scrollbar.setValue @view_y
end
end
end
def show_context_menu pos
point = mapToGlobal(pos)
menu = Qt::Menu.new self
piece = @pieces.select{ |piece| piece.underMouse } #return array
unless piece.empty?
piece = piece[0]
delete_action = Qt::Action.new "Delete", self
menu.addAction delete_action
end
return if menu.isEmpty
selected_item = menu.exec point
if selected_item == delete_action
delete_piece piece
end
end
end
class Piece < Qt::Widget
attr_accessor :grid, :floating
def initialize grid, size, parent=nil #parent will be @dropbox
super parent
@grid = grid
xs = @grid.map{|elem| elem[0]}
ys = @grid.map{|elem| elem[1]}
@grid_w = xs.max - xs.min
@grid_h = ys.max - ys.min
@cell_size = (size*1.0 / ([@grid_w,@grid_h].max+1))
setFixedSize size, size
setMouseTracking true
@floating = true
show
end
def paintEvent event
painter = Qt::Painter.new self
painter.setPen Qt::SolidLine
if [@grid_w,@grid_h].max < 25
#vertical lines
for x in (0..(width/@cell_size)-1)
painter.drawLine x*@cell_size,0,x*@cell_size,height
end
#horizontal lines
for y in (0..(height/@cell_size)-1)
painter.drawLine 0, y*@cell_size,width,y*@cell_size
end
color = Qt::green
else
color = Qt::Color.new 0,150,0
end
painter.drawRect 0, 0, width-1, height-1
painter.setPen Qt::NoPen
@grid.each do |cell|
painter.fillRect cell[0]*@cell_size+1, cell[1]*@cell_size+1, @cell_size-1, @cell_size-1, color
end
painter.end
end
end