return function(R)
    -- ** WIDGET **

    local widget = {}
    widget.__index=widget
    
    function widget.getProto(id,x,y)
        return {id=id,x=x,y=y,isActive=true,parent=nil}
    end
    
    function widget.new(id,x,y)
        return setmetatable(widget.getProto(id,x,y), widget)
    end
    
    function widget:setParent(p)
        self.parent=p
    end
    
    function widget:setActive(s)
        self.isActive=s
    end
    
    function widget:draw(ofsX,ofsY,ex)
        if not self.isActive then
            return
        end
        self:_draw(ofsX+self.x,ofsY+self.y,ex)
    end
    
    function widget:_draw(x,y,ex)
    end
    
    function widget:getHits(mx,my,ofsX,ofsY)
        if not self.isActive then
            return {}
        end
        return self:_getHits(mx,my,ofsX+self.x,ofsY+self.y)
    end
    
    function widget:_getHits(mx,my,ofsX,ofsY)
        return {}
    end
    
    -- ** BUTTON **

    local button = {}
    button.__index=button

    function button.getProto(id,x,y,w,h,label)
        local p=widget.getProto(id,x,y)
        p.w,p.h,p.label=w,h,label
        return p
    end

    -- label can be nil
    function button.new(id,x,y,w,h,label)
        return setmetatable(button.getProto(id,x,y,w,h,label), button)
    end
    setmetatable(button, {__index=widget})

    function button:_draw(x,y,ex)
        local bgCol=(ex and ex.isSelected) and 3 or 15
        rect(x,y,self.w,self.h,bgCol)
        if self.label then
            local w=print(self.label,240,0,12,false,1,true)
            print(self.label,x+(self.w-w)/2,y+(self.h-5)/2,12,false,1,true)
        end
    end

    -- returns {{id,self,inX,inY}} or {}
    function button:_getHits(mx,my,x,y)
        local inX,inY=mx-x,my-y
        if inX>=0 and inX<self.w and inY>=0 and inY<self.h then
            return {{id=self.id,widget=self,x=inX,y=inY}}
        end
        return {}
    end

    function button:setLabel(l)
        self.label=l
    end

    -- ** GUITEXT **

    local guiText = {}
    guiText.__index=guiText

    function guiText.getProto(id,x,y,w,h,label)
        local p=widget.getProto(id,x,y)
        p.w,p.h,p.label=w,h,label
        return p
    end

    function guiText.new(id,x,y,w,h,label)
        return setmetatable(guiText.getProto(id,x,y,w,h,label), guiText)
    end
    setmetatable(guiText, {__index=widget})

    function guiText:_draw(x,y)
        local w=print(self.label,240,0,12)
        print(self.label,x+(self.w-w)/2,y+(self.h-6)/2,12)
    end
    
    function guiText:setLabel(l)
        self.label=l
    end

    -- ** PANEL **

    local panel = {}
    panel.__index=panel
    
    function panel.getProto(id,x,y)
        local p=widget.getProto(id,x,y)
        p.widgets={}
        return p
    end
    
    function panel.new(id,x,y)
        return setmetatable(panel.getProto(id,x,y), panel)
    end
    setmetatable(panel, {__index=widget})
    
    function panel:addWidget(w)
        self.widgets[#self.widgets+1]=w
        w.setParent(self)
    end
    
    function panel:_draw(x,y)
        for i=1,#self.widgets do
            w=self.widgets[i]
            w:draw(x,y)
       end
    end
    
    function panel:_getHits(mx,my,ofsX,ofsY)
        local hitsOut={}
        for i=1,#self.widgets do
            w=self.widgets[i]
            local hits=w:getHits(mx,my,ofsX,ofsY)
            for i=1,#hits do
                hitsOut[#hitsOut+1]=hits[i]
            end
        end
        return hitsOut
    end

    -- ** BUTTON GROUP **

    local buttonGroup = {}
    buttonGroup.__index=buttonGroup
    
    function buttonGroup.getProto(id,x,y)
        local p=widget.getProto(id,x,y)
        p.buttons={}
        p.selected=nil
        return p
    end
    
    function buttonGroup.new(id,x,y)
        return setmetatable(buttonGroup.getProto(id,x,y), buttonGroup)
    end
    setmetatable(buttonGroup, {__index=widget})
    
    function buttonGroup:addButton(b)
        self.buttons[#self.buttons+1]=b
        b.setParent(self)
    end
    
    function buttonGroup:select(id)
        self.selected=id
    end
    
    function buttonGroup:getSelected()
        return self.selected
    end
    
    function buttonGroup:_draw(x,y)
        for i=1,#self.buttons do
            b=self.buttons[i]
            b:draw(x,y,{isSelected=(b.id==self.selected)})
       end
    end
    
    function buttonGroup:_getHits(mx,my,x,y)
        local hitsOut={}
        for i=1,#self.buttons do
            b=self.buttons[i]
            local hits=b:getHits(mx,my,x,y)
            for i=1,#hits do
                hitsOut[#hitsOut+1]=hits[i]
            end
       end
       return hitsOut
    end

    -- ** GUI **

    local gui = {}
    gui.__index=gui

    function gui.getProto(id,x,y)
        local p=panel.getProto(id,x,y)
        p.eventCb=nil
        p.hits={}
        return p
    end

    function gui.new(id,x,y)
        return setmetatable(gui.getProto(id,x,y), gui)
    end
    setmetatable(gui, {__index=panel})

    function gui:setEventCb(cb)
        self.eventCb=cb
    end

    function gui:draw()
        self:_draw(0,0)
    end

    function gui:getHits(mx,my)
        return self:_getHits(mx,my,0,0)
    end

    function gui:update()
        self.hits={}
        if not self.isActive then
            return
        end

        local m=R.getMouse()
        self.hits=self:getHits(m.x,m.y)

        if (m.lb or m.mb or m.rb) and self.eventCb then
            self.eventCb(m,self.hits)
        end
    end

    R.Gui=gui
    R.Panel=panel
    R.Button=button
    R.ButtonGroup=buttonGroup
    R.GuiText=guiText
end