Skip to content

Instantly share code, notes, and snippets.

@warmist
Last active August 29, 2015 14:14
Show Gist options
  • Save warmist/df5b5b8f0e702d082ac7 to your computer and use it in GitHub Desktop.
Save warmist/df5b5b8f0e702d082ac7 to your computer and use it in GitHub Desktop.
Tutorial about dfhack gui system
local gui=require 'gui'
local widgets=require 'gui.widgets'
tutorial_screen=defclass(tutorial_screen,gui.FramedScreen)
function tutorial_screen:init(args)
self:addviews{
widgets.Label{text="Info:",frame={t=1,l=1}},
widgets.Label{text="Other text: Text Text text",frame={t=2,l=2}},
widgets.List{choices={'a','b','c'},frame={t=3,l=1}},
widgets.Label{
text={{text="Exit",key="LEAVESCREEN",frame={b=1,l=1},key_sep="()",on_activate=self:callback('dismiss')}}
}
}
end
tutorial_screen{}:show() --construct and show our screen

Gui programming on dfhack

Intro

So there is some strange notion that gui programming with dfhack is very hard. Everyone is inventing all these insanely hard raw tricks and trying to workaround df all the time but IMHO simplest system that is easy and fun to use is never used. Let's try to fix that.

Setup

Basics

Screen using scripts are not magical in any way and use same '.lua' scripts so let's create one. I called mine "tutorial.lua" and saved in df/hack/scripts folder. As you probably know we can invoke it from dfhack console by simply typing tutorial . Currently it does nothing, so let's fix that by adding first line into "tutorial.lua".

print('tutorial file running okay!')

After typing tutorial into dfhack console the 'tutorial file running okay!' should appear.

Tools of trade(destruction)

Now because we will be working on gui we need a toolkit for that. Fortunately for us Angavrilov made huge toolkit just for that. It includes many different useful things. So let's pull that in.

local gui=require 'gui'

Now because we will be making a screen it's best to thing about that in objective manner. Let's create a new class. Syntax for it might be strange but it has a reason.

tutorial_screen=defclass(tutorial_screen,gui.FramedScreen)

Tutorial_screen is the name of our class and we indicate that we want to inherit all the functionality from a snazy "FramedScreen". This allows to skip a LOT of boring setup and just do fun stuff.

Now there are a few ways to draw stuff. Simpler way makes you write more code, but is more flexible. That way is needed if you want to do something fancy. The idea is to add your own render method. The other way to draw is by using pre-made widgets. That way you define layout and functionality like in higher level languages by using buttons and labels and so on. To use this we need another 'require' so put this after 'local gui...' line

local widgets=require 'gui.widgets'

Now the layout and structure of said widgets must (you can do it later, but it's rare that it's needed) happen when constructing our object. For that let's use "init" method.

function tutorial_screen:init(args)
        self:addviews{
                widgets.Label{text="Info:",frame={t=1,l=1}},
                widgets.Label{text="Other text: Text Text text",frame={t=2,l=2}},
                widgets.List{choices={'a','b','c'},frame={t=3,l=1}},
        }
end

Now finally let's show this screen.

tutorial_screen{}:show() --construct and show our screen

One problem though. We can't exit this screen. If you are ever stuff in such screen just type "devel/pop-screen". Be careful, pop'ing df native screens can crash or exit from df.

Finally let's add a way to exit the screen in a normal way. Again there are more ways to do this but this seems like easiest to me :). In the "self:addviews{..." before closing "}" add these lines.

widgets.Label{
                        text={{text="Exit",key="LEAVESCREEN",frame={b=1,l=1},key_sep="()",on_activate=self:callback('dismiss')}}
                }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment