diff --git a/game/engines/default/data/gfx/border_1_sel.png b/game/engines/default/data/gfx/border_1_sel.png
deleted file mode 100644
index 99ced49ab8ad309a82057719a9135b4fd7e8df7e..0000000000000000000000000000000000000000
Binary files a/game/engines/default/data/gfx/border_1_sel.png and /dev/null differ
diff --git a/game/engines/default/data/gfx/border_3_sel.png b/game/engines/default/data/gfx/border_3_sel.png
deleted file mode 100644
index 6872c673de9d862059813e92ad48447483d8dde9..0000000000000000000000000000000000000000
Binary files a/game/engines/default/data/gfx/border_3_sel.png and /dev/null differ
diff --git a/game/engines/default/data/gfx/border_7_sel.png b/game/engines/default/data/gfx/border_7_sel.png
deleted file mode 100644
index be00ddc55dc416018cea6f9cbd5bb2667d9976e5..0000000000000000000000000000000000000000
Binary files a/game/engines/default/data/gfx/border_7_sel.png and /dev/null differ
diff --git a/game/engines/default/data/gfx/border_9_sel.png b/game/engines/default/data/gfx/border_9_sel.png
deleted file mode 100644
index e5c46af2864ab728971d972dcfb315d2e898e16f..0000000000000000000000000000000000000000
Binary files a/game/engines/default/data/gfx/border_9_sel.png and /dev/null differ
diff --git a/game/engines/default/data/gfx/ui/border_hor_left.png b/game/engines/default/data/gfx/ui/border_hor_left.png
new file mode 100644
index 0000000000000000000000000000000000000000..2b3130eef84224d32ae885ca5c161255460c1808
Binary files /dev/null and b/game/engines/default/data/gfx/ui/border_hor_left.png differ
diff --git a/game/engines/default/data/gfx/ui/border_hor_middle.png b/game/engines/default/data/gfx/ui/border_hor_middle.png
new file mode 100644
index 0000000000000000000000000000000000000000..33f47205854ce4e15fa5c890e4c7d68792b732a4
Binary files /dev/null and b/game/engines/default/data/gfx/ui/border_hor_middle.png differ
diff --git a/game/engines/default/data/gfx/ui/border_hor_right.png b/game/engines/default/data/gfx/ui/border_hor_right.png
new file mode 100644
index 0000000000000000000000000000000000000000..61f0794af30d93ee94a9b90d0ca90f6df142a9bb
Binary files /dev/null and b/game/engines/default/data/gfx/ui/border_hor_right.png differ
diff --git a/game/engines/default/data/gfx/ui/border_vert_bottom.png b/game/engines/default/data/gfx/ui/border_vert_bottom.png
new file mode 100644
index 0000000000000000000000000000000000000000..5a78bacf717e2c2214bd1313151c7bea3da516aa
Binary files /dev/null and b/game/engines/default/data/gfx/ui/border_vert_bottom.png differ
diff --git a/game/engines/default/data/gfx/ui/border_vert_middle.png b/game/engines/default/data/gfx/ui/border_vert_middle.png
new file mode 100644
index 0000000000000000000000000000000000000000..8c6ece2a46ef2f2262bad44abc958a515b314705
Binary files /dev/null and b/game/engines/default/data/gfx/ui/border_vert_middle.png differ
diff --git a/game/engines/default/data/gfx/ui/border_vert_top.png b/game/engines/default/data/gfx/ui/border_vert_top.png
new file mode 100644
index 0000000000000000000000000000000000000000..938dd5a32cb9d0f856cbdb0297e1b2b53cfc4084
Binary files /dev/null and b/game/engines/default/data/gfx/ui/border_vert_top.png differ
diff --git a/game/engines/default/data/gfx/ui/button1.png b/game/engines/default/data/gfx/ui/button1.png
new file mode 100644
index 0000000000000000000000000000000000000000..00976452efe42bbe87f28e0607393b312c0a5479
Binary files /dev/null and b/game/engines/default/data/gfx/ui/button1.png differ
diff --git a/game/engines/default/data/gfx/ui/button2.png b/game/engines/default/data/gfx/ui/button2.png
new file mode 100644
index 0000000000000000000000000000000000000000..9cc7816a8b88d7ac1706b2f0286d8566ad75e135
Binary files /dev/null and b/game/engines/default/data/gfx/ui/button2.png differ
diff --git a/game/engines/default/data/gfx/ui/button3.png b/game/engines/default/data/gfx/ui/button3.png
new file mode 100644
index 0000000000000000000000000000000000000000..58c2f02f1337da0466a99fe396bf563dd8a590ec
Binary files /dev/null and b/game/engines/default/data/gfx/ui/button3.png differ
diff --git a/game/engines/default/data/gfx/ui/button4.png b/game/engines/default/data/gfx/ui/button4.png
new file mode 100644
index 0000000000000000000000000000000000000000..877a852cb1854e0ba60cdaa97fc3e53102a16de2
Binary files /dev/null and b/game/engines/default/data/gfx/ui/button4.png differ
diff --git a/game/engines/default/data/gfx/ui/button5.png b/game/engines/default/data/gfx/ui/button5.png
new file mode 100644
index 0000000000000000000000000000000000000000..1f9caf1b4c781dfad789deff090344bae8b29076
Binary files /dev/null and b/game/engines/default/data/gfx/ui/button5.png differ
diff --git a/game/engines/default/data/gfx/ui/button6.png b/game/engines/default/data/gfx/ui/button6.png
new file mode 100644
index 0000000000000000000000000000000000000000..55e30a5b40567f8cfbf3873aaeefc996d5f9c33e
Binary files /dev/null and b/game/engines/default/data/gfx/ui/button6.png differ
diff --git a/game/engines/default/data/gfx/ui/button7.png b/game/engines/default/data/gfx/ui/button7.png
new file mode 100644
index 0000000000000000000000000000000000000000..99f9414b1a423a7d37be1348335a25b11e6b104c
Binary files /dev/null and b/game/engines/default/data/gfx/ui/button7.png differ
diff --git a/game/engines/default/data/gfx/ui/button8.png b/game/engines/default/data/gfx/ui/button8.png
new file mode 100644
index 0000000000000000000000000000000000000000..98eae90eee50109e3185550e75ba2ed62d7de4b6
Binary files /dev/null and b/game/engines/default/data/gfx/ui/button8.png differ
diff --git a/game/engines/default/data/gfx/ui/button9.png b/game/engines/default/data/gfx/ui/button9.png
new file mode 100644
index 0000000000000000000000000000000000000000..9a94b8dd11d27a043f83884da189adc940fb441d
Binary files /dev/null and b/game/engines/default/data/gfx/ui/button9.png differ
diff --git a/game/engines/default/data/gfx/ui/button_sel1.png b/game/engines/default/data/gfx/ui/button_sel1.png
new file mode 100644
index 0000000000000000000000000000000000000000..84024fd45c6d2d7dd45741ce848acb69caa14d27
Binary files /dev/null and b/game/engines/default/data/gfx/ui/button_sel1.png differ
diff --git a/game/engines/default/data/gfx/ui/button_sel2.png b/game/engines/default/data/gfx/ui/button_sel2.png
new file mode 100644
index 0000000000000000000000000000000000000000..80490c979142f9be9b4c33d64db8c859edff00e5
Binary files /dev/null and b/game/engines/default/data/gfx/ui/button_sel2.png differ
diff --git a/game/engines/default/data/gfx/ui/button_sel3.png b/game/engines/default/data/gfx/ui/button_sel3.png
new file mode 100644
index 0000000000000000000000000000000000000000..2b36e22ca5c0db56a4aa8044451d30337177f2e6
Binary files /dev/null and b/game/engines/default/data/gfx/ui/button_sel3.png differ
diff --git a/game/engines/default/data/gfx/ui/button_sel4.png b/game/engines/default/data/gfx/ui/button_sel4.png
new file mode 100644
index 0000000000000000000000000000000000000000..3748d5f7458f207b3b7200d1fe853907f9691d65
Binary files /dev/null and b/game/engines/default/data/gfx/ui/button_sel4.png differ
diff --git a/game/engines/default/data/gfx/ui/button_sel5.png b/game/engines/default/data/gfx/ui/button_sel5.png
new file mode 100644
index 0000000000000000000000000000000000000000..2a03675556a4645a9c1733a02fb967556e09bb4b
Binary files /dev/null and b/game/engines/default/data/gfx/ui/button_sel5.png differ
diff --git a/game/engines/default/data/gfx/ui/button_sel6.png b/game/engines/default/data/gfx/ui/button_sel6.png
new file mode 100644
index 0000000000000000000000000000000000000000..1fc0d7f740b4bca7e915d05f77d7e8892b4cf3a7
Binary files /dev/null and b/game/engines/default/data/gfx/ui/button_sel6.png differ
diff --git a/game/engines/default/data/gfx/ui/button_sel7.png b/game/engines/default/data/gfx/ui/button_sel7.png
new file mode 100644
index 0000000000000000000000000000000000000000..3cb79bd2878b4babe1ac41fc66d0ed68744be32a
Binary files /dev/null and b/game/engines/default/data/gfx/ui/button_sel7.png differ
diff --git a/game/engines/default/data/gfx/ui/button_sel8.png b/game/engines/default/data/gfx/ui/button_sel8.png
new file mode 100644
index 0000000000000000000000000000000000000000..8f127091610d7de9fb7d5beedc3c660456cc0e8b
Binary files /dev/null and b/game/engines/default/data/gfx/ui/button_sel8.png differ
diff --git a/game/engines/default/data/gfx/ui/button_sel9.png b/game/engines/default/data/gfx/ui/button_sel9.png
new file mode 100644
index 0000000000000000000000000000000000000000..3a37a9c601008a1050b148cbc71cf16c19c3ea56
Binary files /dev/null and b/game/engines/default/data/gfx/ui/button_sel9.png differ
diff --git a/game/engines/default/data/gfx/ui/checkbox-ok.png b/game/engines/default/data/gfx/ui/checkbox-ok.png
index ea6255e2c2162c871542fd003bc928c6c992f0e2..cbde8abc763eb2af5b90ac7a2921257359cba6b4 100644
Binary files a/game/engines/default/data/gfx/ui/checkbox-ok.png and b/game/engines/default/data/gfx/ui/checkbox-ok.png differ
diff --git a/game/engines/default/data/gfx/ui/checkbox.png b/game/engines/default/data/gfx/ui/checkbox.png
new file mode 100644
index 0000000000000000000000000000000000000000..fb2c7e9ac0241190ab313510aa48cc90e8abc7eb
Binary files /dev/null and b/game/engines/default/data/gfx/ui/checkbox.png differ
diff --git a/game/engines/default/data/gfx/ui/dialogueV3_1.png b/game/engines/default/data/gfx/ui/dialogueV3_1.png
new file mode 100644
index 0000000000000000000000000000000000000000..cc1304bdf94ef1611a34e595bc445edcb348e63f
Binary files /dev/null and b/game/engines/default/data/gfx/ui/dialogueV3_1.png differ
diff --git a/game/engines/default/data/gfx/ui/dialogueV3_2.png b/game/engines/default/data/gfx/ui/dialogueV3_2.png
new file mode 100644
index 0000000000000000000000000000000000000000..a9304fd19f9cd9e7addb555238ab01f865e20917
Binary files /dev/null and b/game/engines/default/data/gfx/ui/dialogueV3_2.png differ
diff --git a/game/engines/default/data/gfx/ui/dialogueV3_3.png b/game/engines/default/data/gfx/ui/dialogueV3_3.png
new file mode 100644
index 0000000000000000000000000000000000000000..59a35dd49c4c4c19ed7488842de7208c747d3240
Binary files /dev/null and b/game/engines/default/data/gfx/ui/dialogueV3_3.png differ
diff --git a/game/engines/default/data/gfx/ui/dialogueV3_4.png b/game/engines/default/data/gfx/ui/dialogueV3_4.png
new file mode 100644
index 0000000000000000000000000000000000000000..bd251293fde8f59873fba81b97e5e6721536afd8
Binary files /dev/null and b/game/engines/default/data/gfx/ui/dialogueV3_4.png differ
diff --git a/game/engines/default/data/gfx/ui/dialogueV3_5.png b/game/engines/default/data/gfx/ui/dialogueV3_5.png
new file mode 100644
index 0000000000000000000000000000000000000000..20ffaf2e23686b80a8a7da2759b7858e83f0f9d9
Binary files /dev/null and b/game/engines/default/data/gfx/ui/dialogueV3_5.png differ
diff --git a/game/engines/default/data/gfx/ui/dialogueV3_6.png b/game/engines/default/data/gfx/ui/dialogueV3_6.png
new file mode 100644
index 0000000000000000000000000000000000000000..f1c5f5eb73fc598cb5f29215fcf0759335ef69b3
Binary files /dev/null and b/game/engines/default/data/gfx/ui/dialogueV3_6.png differ
diff --git a/game/engines/default/data/gfx/ui/dialogueV3_7.png b/game/engines/default/data/gfx/ui/dialogueV3_7.png
new file mode 100644
index 0000000000000000000000000000000000000000..b05f385bee8b43a2b4c6015e72298a20b9d4c444
Binary files /dev/null and b/game/engines/default/data/gfx/ui/dialogueV3_7.png differ
diff --git a/game/engines/default/data/gfx/ui/dialogueV3_8.png b/game/engines/default/data/gfx/ui/dialogueV3_8.png
new file mode 100644
index 0000000000000000000000000000000000000000..7db710a7158edc54385476e9ac31d784d4715d53
Binary files /dev/null and b/game/engines/default/data/gfx/ui/dialogueV3_8.png differ
diff --git a/game/engines/default/data/gfx/ui/dialogueV3_9.png b/game/engines/default/data/gfx/ui/dialogueV3_9.png
new file mode 100644
index 0000000000000000000000000000000000000000..0edb8bda24dae50cde401536b02bf30da4df21d4
Binary files /dev/null and b/game/engines/default/data/gfx/ui/dialogueV3_9.png differ
diff --git a/game/engines/default/data/gfx/ui/minus.png b/game/engines/default/data/gfx/ui/minus.png
index 4f6d721d5467bf90eccfa8096af6b25b83a003ec..f7f8bacf5a1b98a6c28f44494eb92e72b7f30a1c 100644
Binary files a/game/engines/default/data/gfx/ui/minus.png and b/game/engines/default/data/gfx/ui/minus.png differ
diff --git a/game/engines/default/data/gfx/ui/plus.png b/game/engines/default/data/gfx/ui/plus.png
index 8e700c6fa51c5a9fc175a4504223ed343260524e..96659f95d199c1f9b09ec2ef3a5019a2b216e745 100644
Binary files a/game/engines/default/data/gfx/ui/plus.png and b/game/engines/default/data/gfx/ui/plus.png differ
diff --git a/game/engines/default/data/gfx/ui/scrollbar-sel.png b/game/engines/default/data/gfx/ui/scrollbar-sel.png
index 21ebe87149a225adf15a59dd4d1edbd3b6020ae1..65abf84a55ae61d337ca206ad96f9375e8b5838b 100644
Binary files a/game/engines/default/data/gfx/ui/scrollbar-sel.png and b/game/engines/default/data/gfx/ui/scrollbar-sel.png differ
diff --git a/game/engines/default/data/gfx/ui/scrollbar.png b/game/engines/default/data/gfx/ui/scrollbar.png
index c20574112f672353bab2e0f58fb4d66fbea4e908..ebb91fdb2b17413c482611dabbadb0ec346c65c0 100644
Binary files a/game/engines/default/data/gfx/ui/scrollbar.png and b/game/engines/default/data/gfx/ui/scrollbar.png differ
diff --git a/game/engines/default/data/gfx/ui/scrollbar_bottom.png b/game/engines/default/data/gfx/ui/scrollbar_bottom.png
new file mode 100644
index 0000000000000000000000000000000000000000..70772188ba2cb979e9159f70724bfe184b27d286
Binary files /dev/null and b/game/engines/default/data/gfx/ui/scrollbar_bottom.png differ
diff --git a/game/engines/default/data/gfx/ui/scrollbar_top.png b/game/engines/default/data/gfx/ui/scrollbar_top.png
new file mode 100644
index 0000000000000000000000000000000000000000..eb72163c5bd6ad14a8f29104cf604145aacd2fac
Binary files /dev/null and b/game/engines/default/data/gfx/ui/scrollbar_top.png differ
diff --git a/game/engines/default/data/gfx/ui/selector-sel1.png b/game/engines/default/data/gfx/ui/selector-sel1.png
new file mode 100644
index 0000000000000000000000000000000000000000..b0ddd760d866b7ebd5804f3bdeb22bda476ff6e5
Binary files /dev/null and b/game/engines/default/data/gfx/ui/selector-sel1.png differ
diff --git a/game/engines/default/data/gfx/ui/selector-sel2.png b/game/engines/default/data/gfx/ui/selector-sel2.png
new file mode 100644
index 0000000000000000000000000000000000000000..8c1f15423cdb0b46346114be54bfebdd8a8ba1d2
Binary files /dev/null and b/game/engines/default/data/gfx/ui/selector-sel2.png differ
diff --git a/game/engines/default/data/gfx/ui/selector-sel3.png b/game/engines/default/data/gfx/ui/selector-sel3.png
new file mode 100644
index 0000000000000000000000000000000000000000..a18adda6ba5476883fe44f56357d440dd6ab279c
Binary files /dev/null and b/game/engines/default/data/gfx/ui/selector-sel3.png differ
diff --git a/game/engines/default/data/gfx/ui/selector-sel4.png b/game/engines/default/data/gfx/ui/selector-sel4.png
new file mode 100644
index 0000000000000000000000000000000000000000..164fd1ef9bcd9824a77bce82e476856dd0cc7e13
Binary files /dev/null and b/game/engines/default/data/gfx/ui/selector-sel4.png differ
diff --git a/game/engines/default/data/gfx/ui/selector-sel5.png b/game/engines/default/data/gfx/ui/selector-sel5.png
new file mode 100644
index 0000000000000000000000000000000000000000..7d804e9fa0edcee3aa360c99d033cc4270b75746
Binary files /dev/null and b/game/engines/default/data/gfx/ui/selector-sel5.png differ
diff --git a/game/engines/default/data/gfx/ui/selector-sel6.png b/game/engines/default/data/gfx/ui/selector-sel6.png
new file mode 100644
index 0000000000000000000000000000000000000000..4d20de19463dd780848e002029e49ed78b4caec9
Binary files /dev/null and b/game/engines/default/data/gfx/ui/selector-sel6.png differ
diff --git a/game/engines/default/data/gfx/ui/selector-sel7.png b/game/engines/default/data/gfx/ui/selector-sel7.png
new file mode 100644
index 0000000000000000000000000000000000000000..3dbb01ff4dd216cc0e90e6513c2c8dfb6dee8e34
Binary files /dev/null and b/game/engines/default/data/gfx/ui/selector-sel7.png differ
diff --git a/game/engines/default/data/gfx/ui/selector-sel8.png b/game/engines/default/data/gfx/ui/selector-sel8.png
new file mode 100644
index 0000000000000000000000000000000000000000..48ad10102b61e0e4cc2d1cb21ac626d4e58d541f
Binary files /dev/null and b/game/engines/default/data/gfx/ui/selector-sel8.png differ
diff --git a/game/engines/default/data/gfx/ui/selector-sel9.png b/game/engines/default/data/gfx/ui/selector-sel9.png
new file mode 100644
index 0000000000000000000000000000000000000000..36ed869166a5d341cc23b90b8be6353a618e3e8a
Binary files /dev/null and b/game/engines/default/data/gfx/ui/selector-sel9.png differ
diff --git a/game/engines/default/data/gfx/ui/selector1.png b/game/engines/default/data/gfx/ui/selector1.png
new file mode 100644
index 0000000000000000000000000000000000000000..b0ddd760d866b7ebd5804f3bdeb22bda476ff6e5
Binary files /dev/null and b/game/engines/default/data/gfx/ui/selector1.png differ
diff --git a/game/engines/default/data/gfx/ui/selector2.png b/game/engines/default/data/gfx/ui/selector2.png
new file mode 100644
index 0000000000000000000000000000000000000000..8c1f15423cdb0b46346114be54bfebdd8a8ba1d2
Binary files /dev/null and b/game/engines/default/data/gfx/ui/selector2.png differ
diff --git a/game/engines/default/data/gfx/ui/selector3.png b/game/engines/default/data/gfx/ui/selector3.png
new file mode 100644
index 0000000000000000000000000000000000000000..a18adda6ba5476883fe44f56357d440dd6ab279c
Binary files /dev/null and b/game/engines/default/data/gfx/ui/selector3.png differ
diff --git a/game/engines/default/data/gfx/ui/selector4.png b/game/engines/default/data/gfx/ui/selector4.png
new file mode 100644
index 0000000000000000000000000000000000000000..164fd1ef9bcd9824a77bce82e476856dd0cc7e13
Binary files /dev/null and b/game/engines/default/data/gfx/ui/selector4.png differ
diff --git a/game/engines/default/data/gfx/ui/selector5.png b/game/engines/default/data/gfx/ui/selector5.png
new file mode 100644
index 0000000000000000000000000000000000000000..7d804e9fa0edcee3aa360c99d033cc4270b75746
Binary files /dev/null and b/game/engines/default/data/gfx/ui/selector5.png differ
diff --git a/game/engines/default/data/gfx/ui/selector6.png b/game/engines/default/data/gfx/ui/selector6.png
new file mode 100644
index 0000000000000000000000000000000000000000..4d20de19463dd780848e002029e49ed78b4caec9
Binary files /dev/null and b/game/engines/default/data/gfx/ui/selector6.png differ
diff --git a/game/engines/default/data/gfx/ui/selector7.png b/game/engines/default/data/gfx/ui/selector7.png
new file mode 100644
index 0000000000000000000000000000000000000000..3dbb01ff4dd216cc0e90e6513c2c8dfb6dee8e34
Binary files /dev/null and b/game/engines/default/data/gfx/ui/selector7.png differ
diff --git a/game/engines/default/data/gfx/ui/selector8.png b/game/engines/default/data/gfx/ui/selector8.png
new file mode 100644
index 0000000000000000000000000000000000000000..48ad10102b61e0e4cc2d1cb21ac626d4e58d541f
Binary files /dev/null and b/game/engines/default/data/gfx/ui/selector8.png differ
diff --git a/game/engines/default/data/gfx/ui/selector9.png b/game/engines/default/data/gfx/ui/selector9.png
new file mode 100644
index 0000000000000000000000000000000000000000..36ed869166a5d341cc23b90b8be6353a618e3e8a
Binary files /dev/null and b/game/engines/default/data/gfx/ui/selector9.png differ
diff --git a/game/engines/default/engine/ui/Base.lua b/game/engines/default/engine/ui/Base.lua
index 555d0081153133b05ef6835698160f495344dde6..62f0291714805cf4eaed17f44bf08b8982fe74ae 100644
--- a/game/engines/default/engine/ui/Base.lua
+++ b/game/engines/default/engine/ui/Base.lua
@@ -26,6 +26,7 @@ module(..., package.seeall, class.make)
 
 local gfx_prefix = "/data/gfx/"
 local cache = {}
+local tcache = {}
 
 -- Default font
 _M.font = core.display.newFont("/data/font/Vera.ttf", 12)
@@ -61,3 +62,50 @@ function _M:getImage(file)
 	cache[file] = {s, s:getSize()}
 	return unpack(cache[file])
 end
+
+function _M:getTexture(file)
+	if tcache[file] then return tcache[file] end
+	local i, w, h = self:getImage(file)
+	if not i then return end
+	local t, tw, th = i:glTexture()
+	local r = {t=t, w=w, h=h, tw=tw, th=th}
+	tcache[file] = r
+	return r
+end
+
+function _M:makeFrame(base, w, h)
+	local f = {}
+	if base then
+		f.b7 = self:getTexture(base.."7.png")
+		f.b9 = self:getTexture(base.."9.png")
+		f.b1 = self:getTexture(base.."1.png")
+		f.b3 = self:getTexture(base.."3.png")
+		f.b8 = self:getTexture(base.."8.png")
+		f.b4 = self:getTexture(base.."4.png")
+		f.b2 = self:getTexture(base.."2.png")
+		f.b6 = self:getTexture(base.."6.png")
+		f.b5 = self:getTexture(base.."5.png")
+	end
+	f.w = w
+	f.h = h
+	return f
+end
+
+function _M:drawFrame(f, x, y, r, g, b, a)
+	if not f.b7 then return end
+
+	-- Sides
+	f.b8.t:toScreenFull(x + f.b7.w, y, f.w - f.b7.w - f.b9.w + 1, f.b8.h, f.b8.tw, f.b8.th, r, g, b, a)
+	f.b2.t:toScreenFull(x + f.b7.w, y + f.h - f.b3.h, f.w - f.b7.w - f.b9.w + 1, f.b2.h, f.b2.tw, f.b2.th, r, g, b, a)
+	f.b4.t:toScreenFull(x, y + f.b7.h, f.b4.w, f.h - f.b7.h - f.b1.h + 1, f.b4.tw, f.b4.th, r, g, b, a)
+	f.b6.t:toScreenFull(x + f.w - f.b9.w, y + f.b7.h, f.b6.w, f.h - f.b7.h - f.b1.h + 1, f.b6.tw, f.b6.th, r, g, b, a)
+
+	-- Body
+	f.b5.t:toScreenFull(x + f.b7.w, y + f.b7.h, f.w - f.b7.w - f.b3.w + 1, f.h - f.b7.h - f.b3.h + 1, f.b6.tw, f.b6.th, r, g, b, a)
+
+	-- Corners
+	f.b7.t:toScreenFull(x, y, f.b7.w, f.b7.h, f.b7.tw, f.b7.th, r, g, b, a)
+	f.b1.t:toScreenFull(x, y + f.h - f.b1.h, f.b1.w, f.b1.h, f.b1.tw, f.b1.th, r, g, b, a)
+	f.b9.t:toScreenFull(x + f.w - f.b9.w, y, f.b9.w, f.b9.h, f.b9.tw, f.b9.th, r, g, b, a)
+	f.b3.t:toScreenFull(x + f.w - f.b3.w, y + f.h - f.b3.h, f.b3.w, f.b3.h, f.b3.tw, f.b3.th, r, g, b, a)
+end
diff --git a/game/engines/default/engine/ui/Button.lua b/game/engines/default/engine/ui/Button.lua
index a105864189c7b0971f53b86b37b571cf95a28927..9297469b690146f04a07aad0db5cd16329becbc4 100644
--- a/game/engines/default/engine/ui/Button.lua
+++ b/game/engines/default/engine/ui/Button.lua
@@ -24,6 +24,11 @@ local Focusable = require "engine.ui.Focusable"
 --- A generic UI button
 module(..., package.seeall, class.inherit(Base, Focusable))
 
+frame_ox1 = -5
+frame_ox2 = 5
+frame_oy1 = -5
+frame_oy2 = 5
+
 function _M:init(t)
 	self.text = assert(t.text, "no button text")
 	self.fct = assert(t.fct, "no button fct")
@@ -36,51 +41,37 @@ function _M:generate()
 	self.mouse:reset()
 	self.key:reset()
 
-	local ls, ls_w, ls_h = self:getImage("ui/button-left-sel.png")
-	local ms, ms_w, ms_h = self:getImage("ui/button-middle-sel.png")
-	local rs, rs_w, rs_h = self:getImage("ui/button-right-sel.png")
-	local l, l_w, l_h = self:getImage("ui/button-left.png")
-	local m, m_w, m_h = self:getImage("ui/button-middle.png")
-	local r, r_w, r_h = self:getImage("ui/button-right.png")
-
 	-- Draw UI
 	self.font:setStyle("bold")
 	local w, h = self.font:size(self.text)
 	if self.force_w then w = self.force_w end
-	local fw, fh = w + ls_w + rs_w, ls_h
-	local ss = core.display.newSurface(fw, fh)
-	local s = core.display.newSurface(fw, fh)
-
-	ss:merge(ls, 0, 0)
-	for i = ls_w, fw - rs_w do ss:merge(ms, i, 0) end
-	ss:merge(rs, fw - rs_w, 0)
-	ss:drawColorStringBlended(self.font, self.text, ls_w, (fh - h) / 2, 255, 255, 255)
+	self.w, self.h = w - frame_ox1 + frame_ox2, h - frame_oy1 + frame_oy2
 
-	s:merge(l, 0, 0)
-	for i = l_w, fw - r_w do s:merge(m, i, 0) end
-	s:merge(r, fw - r_w, 0)
-	s:drawColorStringBlended(self.font, self.text, ls_w, (fh - h) / 2, 255, 255, 255)
+	local s = core.display.newSurface(w, h)
+	s:drawColorStringBlended(self.font, self.text, 0, 0, 255, 255, 255, true)
+	self.tex = {s:glTexture()}
 	self.font:setStyle("normal")
 
 	-- Add UI controls
-	self.mouse:registerZone(0, 0, fw, fh, function(button, x, y, xrel, yrel, bx, by, event) if button == "left" and event == "button" then self.fct() end end)
+	self.mouse:registerZone(0, 0, self.w, self.h, function(button, x, y, xrel, yrel, bx, by, event) if button == "left" and event == "button" then self.fct() end end)
 	self.key:addBind("ACCEPT", function() self.fct() end)
 
-	self.tex, self.tex_w, self.tex_h = s:glTexture()
-	self.stex = ss:glTexture()
-	self.rw, self.rh = fw, fh
-	self.w, self.h = fw+10, fh+10
+	self.rw, self.rh = w, h
+	self.frame = self:makeFrame("ui/button", self.w, self.h)
+	self.frame_sel = self:makeFrame("ui/button_sel", self.w, self.h)
 end
 
 function _M:display(x, y, nb_keyframes)
 	if self.focused then
-		self.stex:toScreenFull(x+5, y+5, self.rw, self.rh, self.tex_w, self.tex_h)
+		self:drawFrame(self.frame_sel, x, y)
+		self.tex[1]:toScreenFull(x-frame_ox1, y-frame_oy1, self.rw, self.rh, self.tex[2], self.tex[3])
 	else
-		self.tex:toScreenFull(x+5, y+5, self.rw, self.rh, self.tex_w, self.tex_h)
+		self:drawFrame(self.frame, x, y)
 		if self.focus_decay then
-			self.stex:toScreenFull(x+5, y+5, self.rw, self.rh, self.tex_w, self.tex_h, 1, 1, 1, self.focus_decay / self.focus_decay_max_d)
+			self:drawFrame(self.frame_sel, x, y, 1, 1, 1, self.focus_decay / self.focus_decay_max_d)
 			self.focus_decay = self.focus_decay - nb_keyframes
 			if self.focus_decay <= 0 then self.focus_decay = nil end
 		end
+		self.tex[1]:toScreenFull(x-frame_ox1, y-frame_oy1, self.rw, self.rh, self.tex[2], self.tex[3])
 	end
 end
diff --git a/game/engines/default/engine/ui/Checkbox.lua b/game/engines/default/engine/ui/Checkbox.lua
index 17095f7be3ef9a5f64408210265e7d06b5083097..39bb919c73351b44a88a24a43845d8706806d290 100644
--- a/game/engines/default/engine/ui/Checkbox.lua
+++ b/game/engines/default/engine/ui/Checkbox.lua
@@ -37,44 +37,21 @@ function _M:generate()
 	self.mouse:reset()
 	self.key:reset()
 
-	local ls, ls_w, ls_h = self:getImage("ui/textbox-left-sel.png")
-	local ms, ms_w, ms_h = self:getImage("ui/textbox-middle-sel.png")
-	local rs, rs_w, rs_h = self:getImage("ui/textbox-right-sel.png")
-	local l, l_w, l_h = self:getImage("ui/textbox-left.png")
-	local m, m_w, m_h = self:getImage("ui/textbox-middle.png")
-	local r, r_w, r_h = self:getImage("ui/textbox-right.png")
-	local c, c_w, c_h = self:getImage("ui/textbox-cursor.png")
-	local chk, chk_w, chk_h = self:getImage("ui/checkbox-ok.png")
+	self.check = self:getTexture("ui/checkbox.png")
+	self.tick = self:getTexture("ui/checkbox-ok.png")
 
 	self.h = r_h
 
 	-- Draw UI
-	local title_w = self.font:size(self.title)
-	self.w = title_w + chk_w
-	local w, h = self.w, r_h
-	local fw, fh = w - title_w - ls_w - rs_w, self.font_h
-	self.fw, self.fh = fw, fh
-	self.text_x = ls_w + title_w
-	self.text_y = (h - fh) / 2
-	self.max_display = math.floor(fw / self.font_mono_w)
-	local ss = core.display.newSurface(w, h)
-	local s = core.display.newSurface(w, h)
+	self.title_w, self.title_h = self.font:size(self.title)
+	self.w, self.h = self.title_w + self.check.w, math.max(self.font_h, self.check.h)
 
-	ss:merge(ls, title_w, 0)
-	for i = title_w + ls_w, w - rs_w do ss:merge(ms, i, 0) end
-	ss:merge(rs, w - rs_w, 0)
-	ss:drawColorStringBlended(self.font, self.title, 0, (h - fh) / 2, 255, 255, 255, true)
-
-	s:merge(l, title_w, 0)
-	for i = title_w + l_w, w - r_w do s:merge(m, i, 0) end
-	s:merge(r, w - r_w, 0)
-	s:drawColorStringBlended(self.font, self.title, 0, (h - fh) / 2, 255, 255, 255, true)
-
-	self.chk_tex, self.chk_tex_w, self.chk_tex_h = chk:glTexture()
-	self.chk_w, self.chk_h = chk_w, chk_h
+	local s = core.display.newSurface(self.title_w, self.title_h)
+	s:drawColorStringBlended(self.font, self.title, 0, 0, 255, 255, 255, true)
+	self.tex = {s:glTexture()}
 
 	-- Add UI controls
-	self.mouse:registerZone(title_w + ls_w, 0, fw, h, function(button, x, y, xrel, yrel, bx, by, event)
+	self.mouse:registerZone(0, 0, self.w, self.h, function(button, x, y, xrel, yrel, bx, by, event)
 		if event == "button" then
 			self:select()
 		end
@@ -83,9 +60,6 @@ function _M:generate()
 	self.key:addCommands{
 		_SPACE = function() self:select() end,
 	}
-
-	self.tex, self.tex_w, self.tex_h = s:glTexture()
-	self.stex = ss:glTexture()
 end
 
 function _M:select()
@@ -93,17 +67,18 @@ function _M:select()
 end
 
 function _M:display(x, y, nb_keyframes)
+	self.tex[1]:toScreenFull(x, y + (self.h - self.title_h) / 2, self.title_w, self.title_h, self.tex[2], self.tex[3])
 	if self.focused then
-		self.stex:toScreenFull(x, y, self.w, self.h, self.tex_w, self.tex_h)
+		self.check.t:toScreenFull(x + self.title_w, y, self.check.w, self.check.h, self.check.tw, self.check.th)
 	else
-		self.tex:toScreenFull(x, y, self.w, self.h, self.tex_w, self.tex_h)
+		self.check.t:toScreenFull(x + self.title_w, y, self.check.w, self.check.h, self.check.tw, self.check.th)
 		if self.focus_decay then
-			self.stex:toScreenFull(x, y, self.w, self.h, self.tex_w, self.tex_h, 1, 1, 1, self.focus_decay / self.focus_decay_max_d)
+--			self.check.t:toScreenFull(x + self.title_w, y, self.check.w, self.check.h, self.check.tw, self.check.th)
 			self.focus_decay = self.focus_decay - nb_keyframes
 			if self.focus_decay <= 0 then self.focus_decay = nil end
 		end
 	end
 	if self.checked then
-		self.chk_tex:toScreenFull(x + self.w - self.chk_w, y, self.chk_w, self.chk_h, self.chk_tex_w, self.chk_tex_h)
+		self.tick.t:toScreenFull(x + self.title_w, y, self.tick.w, self.tick.h, self.tick.tw, self.tick.th)
 	end
 end
diff --git a/game/engines/default/engine/ui/Dialog.lua b/game/engines/default/engine/ui/Dialog.lua
index a2dbc4420f4f2d855b2157ab1833dd9a1c3f539a..9fd7bb980c6a6c1b436277f7c38b7b864451fe23 100644
--- a/game/engines/default/engine/ui/Dialog.lua
+++ b/game/engines/default/engine/ui/Dialog.lua
@@ -128,6 +128,25 @@ function _M:init(title, w, h, x, y, alpha, font, showup)
 		self.__showup = 2
 	end
 
+	self.frame = self.frame or {
+		b7 = "ui/dialogueV3_7.png",
+		b9 = "ui/dialogueV3_9.png",
+		b1 = "ui/dialogueV3_1.png",
+		b3 = "ui/dialogueV3_3.png",
+		b4 = "ui/dialogueV3_4.png",
+		b6 = "ui/dialogueV3_6.png",
+		b8 = "ui/dialogueV3_8.png",
+		b2 = "ui/dialogueV3_2.png",
+		b5 = "ui/dialogueV3_5.png",
+		shadow = {x=15, y=15, a=0.5},
+		a = 1,
+	}
+	self.frame.ox1 = self.frame.ox1 or -42
+	self.frame.ox2 = self.frame.ox2 or 42
+	self.frame.oy1 = self.frame.oy1 or -42
+	self.frame.oy2 = self.frame.oy2 or 42
+	self.frame.a = self.frame.a or 1
+
 	self.uis = {}
 	self.focus_ui = nil
 	self.focus_ui_id = 0
@@ -153,35 +172,37 @@ end
 
 function _M:generate()
 	local gamew, gameh = core.display.size()
-	local s = core.display.newSurface(self.w, self.h)
-	s:alpha(true)
-	s:erase(0, 0, 0, self.alpha)
-
-	local b7, b7_w, b7_h = self:getImage("border_7.png")
-	local b9, b9_w, b9_h = self:getImage("border_9.png")
-	local b1, b1_w, b1_h = self:getImage("border_1.png")
-	local b3, b3_w, b3_h = self:getImage("border_3.png")
-	local b8, b8_w, b8_h = self:getImage("border_8.png")
-	local b4, b4_w, b4_h = self:getImage("border_4.png")
-
-	s:merge(b7, 0, 0)
-	s:merge(b9, self.w - b9_w, 0)
-	s:merge(b1, 0, self.h - b1_h)
-	s:merge(b3, self.w - b9_w, self.h - b3_h)
-
-	for i = b7_w, self.w - b9_w do
-		s:merge(b8, i, 0)
-		s:merge(b8, i, 20)
-		s:merge(b8, i, self.h - 3)
-	end
-	for i = b7_h, self.h - b1_h do
-		s:merge(b4, 0, i)
-		s:merge(b4, self.w - 3, i)
+
+	self.frame.w = self.w - self.frame.ox1 + self.frame.ox2
+	self.frame.h = self.h - self.frame.oy1 + self.frame.oy2
+
+	self.b7 = self:getTexture(self.frame.b7)
+	self.b9 = self:getTexture(self.frame.b9)
+	self.b1 = self:getTexture(self.frame.b1)
+	self.b3 = self:getTexture(self.frame.b3)
+	self.b8 = self:getTexture(self.frame.b8)
+	self.b4 = self:getTexture(self.frame.b4)
+	self.b2 = self:getTexture(self.frame.b2)
+	self.b6 = self:getTexture(self.frame.b6)
+	self.b5 = self:getTexture(self.frame.b5)
+
+	self.overs = {}
+	for i, o in ipairs(self.frame.overlays or {}) do
+		local ov = self:getTexture(o.image)
+		if o.gen then
+			o.gen(ov, self)
+		else
+			ov.x = o.x
+			ov.y = o.y
+			ov.a = o.a
+		end
+		self.overs[#self.overs+1] = ov
 	end
 
+--[[
 	local tw, th = self.font_bold:size(self.title)
 	s:drawColorStringBlended(self.font_bold, self.title, (self.w - tw) / 2, 4, 255,255,255)
-
+]]
 	if self.absolute then
 		self.mouse:registerZone(0, 0, gamew, gameh, function(button, x, y, xrel, yrel, bx, by, event) self:mouseEvent(button, x, y, xrel, yrel, bx - self.display_x, by - self.display_y, event) end)
 	else
@@ -196,8 +217,6 @@ function _M:generate()
 		MOVE_LEFT = "MOVE_UP",
 		MOVE_RIGHT = "MOVE_DOWN",
 	}
-
-	self.tex, self.tex_w, self.tex_h = s:glTexture()
 end
 
 function _M:loadUI(t)
@@ -362,32 +381,67 @@ function _M:makeKeyChar(i)
 	end
 end
 
+function _M:drawFrame(x, y, r, g, b, a)
+	x = x + self.frame.ox1
+	y = y + self.frame.oy1
+
+	-- Corners
+	self.b7.t:toScreenFull(x, y, self.b7.w, self.b7.h, self.b7.tw, self.b7.th, r, g, b, a)
+	self.b1.t:toScreenFull(x, y + self.frame.h - self.b1.h, self.b1.w, self.b1.h, self.b1.tw, self.b1.th, r, g, b, a)
+	self.b9.t:toScreenFull(x + self.frame.w - self.b9.w, y, self.b9.w, self.b9.h, self.b9.tw, self.b9.th, r, g, b, a)
+	self.b3.t:toScreenFull(x + self.frame.w - self.b3.w, y + self.frame.h - self.b3.h, self.b3.w, self.b3.h, self.b3.tw, self.b3.th, r, g, b, a)
+
+	-- Sides
+	self.b8.t:toScreenFull(x + self.b7.w, y, self.frame.w - self.b7.w - self.b9.w, self.b8.h, self.b8.tw, self.b8.th, r, g, b, a)
+	self.b2.t:toScreenFull(x + self.b7.w, y + self.frame.h - self.b3.h, self.frame.w - self.b7.w - self.b9.w, self.b2.h, self.b2.tw, self.b2.th, r, g, b, a)
+	self.b4.t:toScreenFull(x, y + self.b7.h, self.b4.w, self.frame.h - self.b7.h - self.b1.h, self.b4.tw, self.b4.th, r, g, b, a)
+	self.b6.t:toScreenFull(x + self.frame.w - self.b9.w, y + self.b7.h, self.b6.w, self.frame.h - self.b7.h - self.b1.h, self.b6.tw, self.b6.th, r, g, b, a)
+
+	-- Body
+	self.b5.t:toScreenFull(x + self.b7.w, y + self.b7.h, self.frame.w - self.b7.w - self.b3.w , self.frame.h - self.b7.h - self.b3.h, self.b6.tw, self.b6.th, r, g, b, a)
+
+	-- Overlays
+	for i = 1, #self.overs do
+		local ov = self.overs[i]
+		ov.t:toScreenFull(x + ov.x, y + ov.y, ov.w , ov.h, ov.tw, ov.th, r, g, b, a * ov.a)
+	end
+end
+
 function _M:toScreen(x, y, nb_keyframes)
 	if self.__hidden then return end
 
-	-- Draw with only the texture
+	local zoom = 1
 	if self.__showup then
 		local eff = self.__showup_effect or "pop"
 		if eff == "overpop" then
-			local zoom = self.__showup / 7
+			zoom = self.__showup / 7
 			if self.__showup >= 9 then
 				zoom = (9 - (self.__showup - 9)) / 7 - 1
 				zoom = 1 + zoom * 0.5
 			end
-			self.tex:toScreenFull(x + (self.w - self.w * zoom) / 2, y + (self.h - self.h * zoom) / 2, self.w * zoom, self.h * zoom, self.tex_w * zoom, self.tex_h * zoom)
 			self.__showup = self.__showup + nb_keyframes
 			if self.__showup >= 11 then self.__showup = nil end
 		else
-			local zoom = self.__showup / 7
-			self.tex:toScreenFull(x + (self.w - self.w * zoom) / 2, y + (self.h - self.h * zoom) / 2, self.w * zoom, self.h * zoom, self.tex_w * zoom, self.tex_h * zoom)
+			zoom = self.__showup / 7
 			self.__showup = self.__showup + nb_keyframes
 			if self.__showup >= 7 then self.__showup = nil end
 		end
-	else
-		self.tex:toScreenFull(x, y, self.w, self.h, self.tex_w, self.tex_h)
-		for i = 1, #self.uis do
-			local ui = self.uis[i]
-			ui.ui:display(x + ui.x, y + ui.y, nb_keyframes)
-		end
 	end
+
+	local ox, oy = x, y
+	local hw, hh = math.floor(self.w / 2), math.floor(self.h / 2)
+	local tx, ty = x + hw, y + hh
+	x, y = -hw, -hh
+	core.display.glTranslate(tx, ty, 0)
+	if zoom < 1 then core.display.glScale(zoom, zoom, zoom) end
+
+	if self.frame.shadow then self:drawFrame(x + self.frame.shadow.x, y + self.frame.shadow.y, 0, 0, 0, self.frame.shadow.a) end
+	self:drawFrame(x, y, 1, 1, 1, self.frame.a)
+	for i = 1, #self.uis do
+		local ui = self.uis[i]
+		ui.ui:display(x + ui.x, y + ui.y, nb_keyframes, ox + ui.x, oy + ui.y)
+	end
+
+	if zoom < 1 then core.display.glScale() end
+	core.display.glTranslate(-tx, -ty, 0)
 end
diff --git a/game/engines/default/engine/ui/List.lua b/game/engines/default/engine/ui/List.lua
index 0094d55ecfdca5202153c21c723bf7b2f5c8c8d2..9577fd556a3dcb1c39750fe8d1cf1e94302dab21 100644
--- a/game/engines/default/engine/ui/List.lua
+++ b/game/engines/default/engine/ui/List.lua
@@ -20,17 +20,12 @@
 require "engine.class"
 local Base = require "engine.ui.Base"
 local Focusable = require "engine.ui.Focusable"
+local Slider = require "engine.ui.Slider"
+local Slider = require "engine.ui.Slider"
 
 --- A generic UI list
 module(..., package.seeall, class.inherit(Base, Focusable))
 
-local ls, ls_w, ls_h = _M:getImage("ui/selection-left-sel.png")
-local ms, ms_w, ms_h = _M:getImage("ui/selection-middle-sel.png")
-local rs, rs_w, rs_h = _M:getImage("ui/selection-right-sel.png")
-local l, l_w, l_h = _M:getImage("ui/selection-left.png")
-local m, m_w, m_h = _M:getImage("ui/selection-middle.png")
-local r, r_w, r_h = _M:getImage("ui/selection-right.png")
-
 function _M:init(t)
 	self.list = assert(t.list, "no list list")
 	self.w = assert(t.width, "no list width")
@@ -42,23 +37,6 @@ function _M:init(t)
 	self.scrollbar = t.scrollbar
 	self.all_clicks = t.all_clicks
 
-	self.fh = ls_h
-	self.default = {}
-	self.default.surface = core.display.newSurface(self.w, self.fh)
-	self.default.s = core.display.newSurface(self.w, self.fh)
-	self.default.ss = core.display.newSurface(self.w, self.fh)
-	self.default.sus = core.display.newSurface(self.w, self.fh)
-
-	self.default.ss:merge(ls, 0, 0)
-	for i = ls_w, self.w - rs_w, ms_w do self.default.ss:merge(ms, i, 0) end
-	self.default.ss:merge(rs, self.w - rs_w, 0)
-
-	self.default.s:erase(0, 0, 0)
-
-	self.default.sus:merge(l, 0, 0)
-	for i = l_w, self.w - r_w, m_w do self.default.sus:merge(m, i, 0) end
-	self.default.sus:merge(r, self.w - r_w, 0)
-
 	Base.init(self, t)
 end
 
@@ -70,8 +48,14 @@ function _M:generate()
 	self.scroll = 1
 	self.max = #self.list
 
-	local fw, fh = self.w, ls_h
+	local fw, fh = self.w, self.font_h + 6
 	self.fw, self.fh = fw, fh
+	if not self.surf then self.surf = core.display.newSurface(fw, fh) end
+	local s = self.surf
+
+	self.frame = self:makeFrame(nil, fw, fh)
+	self.frame_sel = self:makeFrame("ui/selector-sel", fw, fh)
+	self.frame_usel = self:makeFrame("ui/selector", fw, fh)
 
 	if not self.h then self.h = self.nb_items * fh end
 
@@ -79,39 +63,17 @@ function _M:generate()
 
 	-- Draw the scrollbar
 	if self.scrollbar then
-		local sb, sb_w, sb_h = self:getImage("ui/scrollbar.png")
-		local ssb, ssb_w, ssb_h = self:getImage("ui/scrollbar-sel.png")
-
-		self.scrollbar = { bar = {}, sel = {} }
-		self.scrollbar.sel.w, self.scrollbar.sel.h, self.scrollbar.sel.tex, self.scrollbar.sel.texw, self.scrollbar.sel.texh = ssb_w, ssb_h, ssb:glTexture()
-		local s = core.display.newSurface(sb_w, self.h - fh)
-		for i = 0, self.h - fh do s:merge(sb, 0, i) end
-		self.scrollbar.bar.w, self.scrollbar.bar.h, self.scrollbar.bar.tex, self.scrollbar.bar.texw, self.scrollbar.bar.texh = ssb_w, self.h - fh, s:glTexture()
+		self.scrollbar = Slider.new{size=self.h - fh, max=self.max}
 	end
 
 	-- Draw the list items
 	for i, item in ipairs(self.list) do
 		local color = item.color or {255,255,255}
 		local text = item[self.display_prop]
-		local src_ss = self.default.ss
-		local src_sus = self.default.sus
-		local src_s = self.default.s
-		local ss = self.default.surface
-		local sus = self.default.surface
-		local s = self.default.surface
-
-		ss:erase(0, 0, 0)
-		ss:merge(src_ss, 0, 0)
-		ss:drawColorStringBlended(self.font, text, ls_w, (fh - self.font_h) / 2, color[1], color[2], color[3], nil, fw - ls_w - rs_w)
-		item._stex = ss:glTexture()
-
-		s:merge(src_s, 0, 0)
-		s:drawColorStringBlended(self.font, text, ls_w, (fh - self.font_h) / 2, color[1], color[2], color[3], nil, fw - ls_w - rs_w)
-		item._tex, item._tex_w, item._tex_h = s:glTexture()
-
-		sus:merge(src_sus, 0, 0)
-		sus:drawColorStringBlended(self.font, text, ls_w, (fh - self.font_h) / 2, color[1], color[2], color[3], nil, fw - ls_w - rs_w)
-		item._sustex = sus:glTexture()
+
+		s:erase(0, 0, 0, 0)
+		s:drawColorStringBlended(self.font, text, 0, (self.fh - self.font_h) / 2, color[1], color[2], color[3], true, fw)
+		item._tex = {s:glTexture()}
 	end
 
 	-- Add UI controls
@@ -179,24 +141,23 @@ function _M:display(x, y, nb_keyframes)
 		local item = self.list[i]
 		if not item then break end
 		if self.sel == i then
-			if self.focused then item._stex:toScreenFull(x, y, self.fw, self.fh, item._tex_w, item._tex_h)
-			else item._sustex:toScreenFull(x, y, self.fw, self.fh, item._tex_w, item._tex_h) end
+			if self.focused then self:drawFrame(self.frame_sel, x, y)
+			else self:drawFrame(self.frame_usel, x, y) end
 		else
-			item._tex:toScreenFull(x, y, self.fw, self.fh, item._tex_w, item._tex_h)
+			self:drawFrame(self.frame, x, y)
 			if item.focus_decay then
-				if self.focused then item._stex:toScreenFull(x, y, self.fw, self.fh, item._tex_w, item._tex_h, 1, 1, 1, item.focus_decay / self.focus_decay_max_d)
-				else item._sustex:toScreenFull(x, y, self.fw, self.fh, item._tex_w, item._tex_h, 1, 1, 1, item.focus_decay / self.focus_decay_max_d) end
+				if self.focused then self:drawFrame(self.frame_sel, x, y, 1, 1, 1, item.focus_decay / self.focus_decay_max_d)
+				else self:drawFrame(self.frame_usel, x, y, 1, 1, 1, item.focus_decay / self.focus_decay_max_d) end
 				item.focus_decay = item.focus_decay - nb_keyframes
 				if item.focus_decay <= 0 then item.focus_decay = nil end
 			end
 		end
+		item._tex[1]:toScreenFull(x + self.frame_sel.b4.w, y, self.fw, self.fh, item._tex[2], item._tex[3])
 		y = y + self.fh
 	end
 
 	if self.focused and self.scrollbar then
-		local pos = self.sel * (self.h - self.fh) / self.max
-
-		self.scrollbar.bar.tex:toScreenFull(bx + self.w - self.scrollbar.bar.w, by + self.fh, self.scrollbar.bar.w, self.scrollbar.bar.h, self.scrollbar.bar.texw, self.scrollbar.bar.texh)
-		self.scrollbar.sel.tex:toScreenFull(bx + self.w - self.scrollbar.sel.w, by + self.fh + pos, self.scrollbar.sel.w, self.scrollbar.sel.h, self.scrollbar.sel.texw, self.scrollbar.sel.texh)
+		self.scrollbar.pos = self.sel
+		self.scrollbar:display(bx + self.w - self.scrollbar.w, by)
 	end
 end
diff --git a/game/engines/default/engine/ui/ListColumns.lua b/game/engines/default/engine/ui/ListColumns.lua
index 6335070d1e09d7db909fff925a9d25457eba8b9e..60df37ca1589b1d764f7ef9a2d73211a3990c736 100644
--- a/game/engines/default/engine/ui/ListColumns.lua
+++ b/game/engines/default/engine/ui/ListColumns.lua
@@ -20,24 +20,11 @@
 require "engine.class"
 local Base = require "engine.ui.Base"
 local Focusable = require "engine.ui.Focusable"
+local Slider = require "engine.ui.Slider"
 
 --- A generic UI multi columns list
 module(..., package.seeall, class.inherit(Base, Focusable))
 
-local ls, ls_w, ls_h = _M:getImage("ui/selection-left-sel.png")
-local ms, ms_w, ms_h = _M:getImage("ui/selection-middle-sel.png")
-local rs, rs_w, rs_h = _M:getImage("ui/selection-right-sel.png")
-local l, l_w, l_h = _M:getImage("ui/selection-left.png")
-local m, m_w, m_h = _M:getImage("ui/selection-middle.png")
-local r, r_w, r_h = _M:getImage("ui/selection-right.png")
-
-local cls, cls_w, cls_h = _M:getImage("ui/selection-left-column-sel.png")
-local cms, cms_w, cms_h = _M:getImage("ui/selection-middle-column-sel.png")
-local crs, crs_w, crs_h = _M:getImage("ui/selection-right-column-sel.png")
-local cl, cl_w, cl_h = _M:getImage("ui/selection-left-column.png")
-local cm, cm_w, cm_h = _M:getImage("ui/selection-middle-column.png")
-local cr, cr_w, cr_h = _M:getImage("ui/selection-right-column.png")
-
 function _M:init(t)
 	self.list = assert(t.list, "no list list")
 	self.columns = assert(t.columns, "no list columns")
@@ -54,6 +41,8 @@ function _M:init(t)
 
 	self.fh = t.item_height or ls_h
 
+	self.fh = t.item_height or (self.font_h + 6)
+
 	local w = self.w
 	if self.scrollbar then w = w - 10 end
 	for j, col in ipairs(self.columns) do
@@ -73,23 +62,11 @@ function _M:init(t)
 		end
 
 		col.surface = core.display.newSurface(col.width, self.fh)
-		col.s = core.display.newSurface(col.width, self.fh)
-		col.ss = core.display.newSurface(col.width, self.fh)
-		col.sus = core.display.newSurface(col.width, self.fh)
-
-		col.ss:merge(ls, 0, 0)
-		for i = ls_w, col.width - rs_w, ms_w do col.ss:merge(ms, i, 0) end
-		col.ss:merge(rs, col.width - rs_w, 0)
-
-		col.s:erase(0, 0, 0)
-
-		col.sus:merge(l, 0, 0)
-		for i = l_w, col.width - r_w, m_w do col.sus:merge(m, i, 0) end
-		col.sus:merge(r, col.width - r_w, 0)
-
-		col._istex = {col.ss:glTexture()}
-		col._itex = {col.s:glTexture()}
-		col._isustex = {col.sus:glTexture()}
+		col.frame = self:makeFrame(nil, col.width, self.fh)
+		col.frame_sel = self:makeFrame("ui/selector-sel", col.width, self.fh)
+		col.frame_usel = self:makeFrame("ui/selector", col.width, self.fh)
+		col.frame_col = self:makeFrame("ui/selector", col.width, self.fh)
+		col.frame_col_sel = self:makeFrame("ui/selector-sel", col.width, self.fh)
 	end
 
 	Base.init(self, t)
@@ -115,7 +92,7 @@ function _M:drawItem(item)
 
 			s:erase(0, 0, 0, 0)
 			-- We use 1000 and do not cut lines to make sure it draws as much as possible
-			text:drawOnSurface(s, 10000, nil, self.font, ls_w, (fh - self.font_h) / 2, color[1], color[2], color[3])
+			text:drawOnSurface(s, 10000, nil, self.font, col.frame_sel.b4.w, (fh - self.font_h) / 2, color[1], color[2], color[3])
 			item._tex = item._tex or {}
 			item._tex[j] = {s:glTexture()}
 		end
@@ -131,8 +108,7 @@ function _M:generate()
 	self.max = #self.list
 	self:selectColumn(1, true)
 
-	local fh = ls_h
-	self.fh = fh
+	local fh = self.fh
 
 	if not self.h then self.h = self.nb_items * fh end
 
@@ -140,14 +116,7 @@ function _M:generate()
 
 	-- Draw the scrollbar
 	if self.scrollbar then
-		local sb, sb_w, sb_h = self:getImage("ui/scrollbar.png")
-		local ssb, ssb_w, ssb_h = self:getImage("ui/scrollbar-sel.png")
-
-		self.scrollbar = { bar = {}, sel = {} }
-		self.scrollbar.sel.w, self.scrollbar.sel.h, self.scrollbar.sel.tex, self.scrollbar.sel.texw, self.scrollbar.sel.texh = ssb_w, ssb_h, ssb:glTexture()
-		local s = core.display.newSurface(sb_w, self.h - fh)
-		for i = 0, self.h - fh do s:merge(sb, 0, i) end
-		self.scrollbar.bar.w, self.scrollbar.bar.h, self.scrollbar.bar.tex, self.scrollbar.bar.texw, self.scrollbar.bar.texh = ssb_w, self.h - fh, s:glTexture()
+		self.scrollbar = Slider.new{size=self.h - fh, max=self.max}
 	end
 
 	-- Draw the list columns
@@ -156,23 +125,14 @@ function _M:generate()
 		local fw = col.width
 		col.fw = fw
 		local text = col.name
-		local ss = core.display.newSurface(fw, fh)
-		local s = core.display.newSurface(fw, fh)
+		local s = col.surface
 
 		self.font:setStyle("bold")
-		ss:merge(cls, 0, 0)
-		for i = cls_w, fw - crs_w do ss:merge(cms, i, 0) end
-		ss:merge(crs, fw - crs_w, 0)
-		ss:drawColorStringBlended(self.font, text, cls_w, (fh - self.font_h) / 2, 255, 255, 255, nil, fw - cls_w - crs_w)
-
-		s:merge(cl, 0, 0)
-		for i = cl_w, fw - cr_w do s:merge(cm, i, 0) end
-		s:merge(cr, fw - cr_w, 0)
-		s:drawColorStringBlended(self.font, text, cl_w, (fh - self.font_h) / 2, 255, 255, 255, nil, fw - cl_w - cr_w)
+		s:erase(0, 0, 0, 0)
+		s:drawColorStringBlended(self.font, text, col.frame_sel.b4.w, (fh - self.font_h) / 2, 255, 255, 255, true, fw - col.frame_sel.b4.w - col.frame_sel.b6.w)
 		self.font:setStyle("normal")
 
 		col._tex, col._tex_w, col._tex_h = s:glTexture()
-		col._stex = ss:glTexture()
 
 		self.mouse:registerZone(colx, 0, col.width, self.fh, function(button, x, y, xrel, yrel, bx, by, event)
 			if button == "left" and event == "button" then self:selectColumn(j) end
@@ -279,17 +239,15 @@ function _M:selectColumn(i, force)
 	end
 end
 
-function _M:display(x, y, nb_keyframes)
+function _M:display(x, y, nb_keyframes, screen_x, screen_y)
 	local bx, by = x, y
 	for j = 1, #self.columns do
 		local col = self.columns[j]
 		local y = y
 		if not self.hide_columns then
-			if self.cur_col == j then
-				col._stex:toScreenFull(x, y, col.fw, self.fh, col._tex_w, col._tex_h)
-			else
-				col._tex:toScreenFull(x, y, col.fw, self.fh, col._tex_w, col._tex_h)
-			end
+			if self.cur_col == j then self:drawFrame(col.frame_col_sel, x, y)
+			else self:drawFrame(col.frame_col_sel, x, y) end
+			col._tex:toScreenFull(x, y, col.fw, self.fh, col._tex_w, col._tex_h)
 			y = y + self.fh
 		end
 
@@ -298,13 +256,13 @@ function _M:display(x, y, nb_keyframes)
 			local item = self.list[i]
 			if not item then break end
 			if self.sel == i then
-				if self.focused then col._istex[1]:toScreenFull(x, y, col.fw, self.fh, col._istex[2], col._istex[3])
-				else col._isustex[1]:toScreenFull(x, y, col.fw, self.fh, col._isustex[2], col._isustex[3]) end
+				if self.focused then self:drawFrame(col.frame_sel, x, y)
+				else self:drawFrame(col.frame_usel, x, y) end
 			else
-				col._itex[1]:toScreenFull(x, y, col.fw, self.fh, col._itex[2], col._itex[3])
+				self:drawFrame(col.frame, x, y)
 				if item.focus_decay then
-					if self.focused then col._istex[1]:toScreenFull(x, y, col.fw, self.fh, col._istex[2], col._istex[3], 1, 1, 1, item.focus_decay / self.focus_decay_max_d)
-					else col._isustex[1]:toScreenFull(x, y, col.fw, self.fh, col._isustex[2], col._isustex[3], 1, 1, 1, item.focus_decay / self.focus_decay_max_d) end
+					if self.focused then self:drawFrame(col.frame_sel, x, y, 1, 1, 1, item.focus_decay / self.focus_decay_max_d)
+					else self:drawFrame(col.frame_usel, x, y, 1, 1, 1, item.focus_decay / self.focus_decay_max_d) end
 					item.focus_decay = item.focus_decay - nb_keyframes
 					if item.focus_decay <= 0 then item.focus_decay = nil end
 				end
@@ -314,8 +272,8 @@ function _M:display(x, y, nb_keyframes)
 			else
 				item._tex[j][1]:toScreenFull(x, y, col.fw, self.fh, item._tex[j][2], item._tex[j][3])
 			end
-			item.last_display_x = x
-			item.last_display_y = y
+			item.last_display_x = screen_x + (x - bx)
+			item.last_display_y = screen_y + (y - by)
 			y = y + self.fh
 		end
 
@@ -323,9 +281,7 @@ function _M:display(x, y, nb_keyframes)
 	end
 
 	if self.focused and self.scrollbar then
-		local pos = self.sel * (self.h - self.fh) / self.max
-
-		self.scrollbar.bar.tex:toScreenFull(bx + self.w - self.scrollbar.bar.w, by + self.fh, self.scrollbar.bar.w, self.scrollbar.bar.h, self.scrollbar.bar.texw, self.scrollbar.bar.texh)
-		self.scrollbar.sel.tex:toScreenFull(bx + self.w - self.scrollbar.sel.w, by + self.fh + pos, self.scrollbar.sel.w, self.scrollbar.sel.h, self.scrollbar.sel.texw, self.scrollbar.sel.texh)
+		self.scrollbar.pos = self.sel
+		self.scrollbar:display(bx + self.w - self.scrollbar.w, by)
 	end
 end
diff --git a/game/engines/default/engine/ui/Separator.lua b/game/engines/default/engine/ui/Separator.lua
index 1bb87ee15fe8328252578b84ca98fa63342951cd..f930557484409c5d2bb67552d3bc481d003fc318 100644
--- a/game/engines/default/engine/ui/Separator.lua
+++ b/game/engines/default/engine/ui/Separator.lua
@@ -32,28 +32,30 @@ end
 
 function _M:generate()
 	if self.dir == "horizontal" then
-		local b4, b4_w, b4_h = self:getImage("border_4.png")
-
-		-- Draw UI
-		self.w, self.h = b4_w, self.size
-		local s = core.display.newSurface(self.w, self.h)
-
-		for i = 0, self.size do s:merge(b4, 0, i) end
-
-		self.tex, self.tex_w, self.tex_h = s:glTexture()
+		self.top = self:getTexture("ui/border_vert_top.png")
+		self.middle = self:getTexture("ui/border_vert_middle.png")
+		self.bottom = self:getTexture("ui/border_vert_bottom.png")
+		self.w, self.h = self.middle.w, self.size
 	else
-		local b8, b8_w, b8_h = self:getImage("border_8.png")
-
-		-- Draw UI
-		self.w, self.h = self.size, b8_h
-		local s = core.display.newSurface(self.w, self.h)
-
-		for i = 0, self.size do s:merge(b8, i, 0) end
-
-		self.tex, self.tex_w, self.tex_h = s:glTexture()
+		self.left = self:getTexture("ui/border_hor_left.png")
+		self.middle = self:getTexture("ui/border_hor_middle.png")
+		self.right = self:getTexture("ui/border_hor_right.png")
+		self.w, self.h = self.size, self.middle.h
 	end
 end
 
 function _M:display(x, y)
-	self.tex:toScreenFull(x, y, self.w, self.h, self.tex_w, self.tex_h)
+	if self.dir == "horizontal" then
+--		x = x - math.floor(self.top.w / 2)
+--		y = y - math.floor(self.top.h / 2)
+		self.top.t:toScreenFull(x, y, self.top.w, self.top.h, self.top.tw, self.top.th)
+		self.bottom.t:toScreenFull(x, y + self.h - self.bottom.h, self.bottom.w, self.bottom.h, self.bottom.tw, self.bottom.th)
+		self.middle.t:toScreenFull(x, y + self.top.h, self.middle.w, self.h - self.top.h - self.bottom.h, self.middle.tw, self.middle.th)
+	else
+--		x = x - math.floor(self.left.w / 2)
+--		y = y - math.floor(self.left.h / 2)
+		self.left.t:toScreenFull(x, y, self.left.w, self.left.h, self.left.tw, self.left.th)
+		self.right.t:toScreenFull(x + self.w - self.right.w, y, self.right.w, self.right.h, self.right.tw, self.right.th)
+		self.middle.t:toScreenFull(x + self.left.w, y, self.w - self.left.w - self.right.w, self.middle.h, self.middle.tw, self.middle.th)
+	end
 end
diff --git a/game/engines/default/engine/ui/Slider.lua b/game/engines/default/engine/ui/Slider.lua
new file mode 100644
index 0000000000000000000000000000000000000000..b4147e988d7b9105d6a50892e2f92b829467d097
--- /dev/null
+++ b/game/engines/default/engine/ui/Slider.lua
@@ -0,0 +1,47 @@
+-- TE4 - T-Engine 4
+-- Copyright (C) 2009, 2010 Nicolas Casalini
+--
+-- This program is free software: you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation, either version 3 of the License, or
+-- (at your option) any later version.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with this program.  If not, see <http://www.gnu.org/licenses/>.
+--
+-- Nicolas Casalini "DarkGod"
+-- darkgod@te4.org
+
+require "engine.class"
+local Base = require "engine.ui.Base"
+
+--- A generic UI slider, usualy used by other UI elements
+module(..., package.seeall, class.inherit(Base))
+
+function _M:init(t)
+	self.size = assert(t.size, "no slider size")
+	self.max = assert(t.max, "no slider max")
+	self.pos = t.pos or 0
+
+	Base.init(self, t)
+end
+
+function _M:generate()
+	self.top = self:getTexture("ui/scrollbar_top.png")
+	self.middle = self:getTexture("ui/scrollbar.png")
+	self.bottom = self:getTexture("ui/scrollbar_bottom.png")
+	self.sel = self:getTexture("ui/scrollbar-sel.png")
+	self.w, self.h = self.middle.w, self.size
+end
+
+function _M:display(x, y)
+	self.top.t:toScreenFull(x, y, self.top.w, self.top.h, self.top.tw, self.top.th)
+	self.bottom.t:toScreenFull(x, y + self.h - self.bottom.h, self.bottom.w, self.bottom.h, self.bottom.tw, self.bottom.th)
+	self.middle.t:toScreenFull(x, y + self.top.h, self.middle.w, self.h - self.top.h - self.bottom.h, self.middle.tw, self.middle.th)
+	self.sel.t:toScreenFull(x - (self.sel.w - self.top.w) / 2, y + (self.pos * self.size / self.max) + self.sel.h / 2, self.sel.w, self.sel.h, self.sel.tw, self.sel.th)
+end
diff --git a/game/engines/default/engine/ui/Textzone.lua b/game/engines/default/engine/ui/Textzone.lua
index 45fdc5bb932bb7cab155754aa8a2e3eff3a56251..8a111e924b586394173d45a42805bc80da5c9f3c 100644
--- a/game/engines/default/engine/ui/Textzone.lua
+++ b/game/engines/default/engine/ui/Textzone.lua
@@ -20,6 +20,7 @@
 require "engine.class"
 local Base = require "engine.ui.Base"
 local Focusable = require "engine.ui.Focusable"
+local Slider = require "engine.ui.Slider"
 
 --- A generic UI list
 module(..., package.seeall, class.inherit(Base, Focusable))
@@ -34,6 +35,7 @@ function _M:init(t)
 	self.no_color_bleed = t.no_color_bleed
 	self.auto_height = t.auto_height
 	self.auto_width = t.auto_width
+	self.color = t.color or {r=255, g=255, b=255}
 
 	if self.auto_width then self.w = 10000 end
 
@@ -64,19 +66,11 @@ function _M:generate()
 	end
 
 	-- Draw the list items
-	self.list = tstring.makeLineTextures(text, self.fw, self.font, true)
+	self.list = tstring.makeLineTextures(text, self.fw, self.font, true, self.color.r, self.color.g, self.color.b)
 
 	-- Draw the scrollbar
 	if self.scrollbar then
-		local sb, sb_w, sb_h = self:getImage("ui/scrollbar.png")
-		local ssb, ssb_w, ssb_h = self:getImage("ui/scrollbar-sel.png")
-
-		self.scrollbar = { bar = {}, sel = {} }
-		self.scrollbar.sel.w, self.scrollbar.sel.h, self.scrollbar.sel.tex, self.scrollbar.sel.texw, self.scrollbar.sel.texh = ssb_w, ssb_h, ssb:glTexture()
-		local s = core.display.newSurface(sb_w, self.h - fh)
-		s:erase(200,0,0)
-		for i = 0, self.h - fh do s:merge(sb, 0, i) end
-		self.scrollbar.bar.w, self.scrollbar.bar.h, self.scrollbar.bar.tex, self.scrollbar.bar.texw, self.scrollbar.bar.texh = ssb_w, self.h - fh, s:glTexture()
+		self.scrollbar = Slider.new{size=self.h - fh, max=self.max - self.max_display + 1}
 	end
 
 	-- Add UI controls
@@ -109,9 +103,7 @@ function _M:display(x, y)
 	end
 
 	if self.focused and self.scrollbar then
-		local pos = self.scroll * (self.h - self.fh) / (self.max - self.max_display + 1)
-
-		self.scrollbar.bar.tex:toScreenFull(bx + self.w - self.scrollbar.bar.w, by + self.fh, self.scrollbar.bar.w, self.scrollbar.bar.h, self.scrollbar.bar.texw, self.scrollbar.bar.texh)
-		self.scrollbar.sel.tex:toScreenFull(bx + self.w - self.scrollbar.sel.w, by + self.fh + pos, self.scrollbar.sel.w, self.scrollbar.sel.h, self.scrollbar.sel.texw, self.scrollbar.sel.texh)
+		self.scrollbar.pos = self.scroll
+		self.scrollbar:display(bx + self.w - self.scrollbar.w, by)
 	end
 end
diff --git a/game/engines/default/engine/ui/TreeList.lua b/game/engines/default/engine/ui/TreeList.lua
index 41a6fdc7a26d40ae1499ecd02210e145ad268bc8..c33ed2a24b8d657f88a0ea59bff0f10beca82896 100644
--- a/game/engines/default/engine/ui/TreeList.lua
+++ b/game/engines/default/engine/ui/TreeList.lua
@@ -20,18 +20,13 @@
 require "engine.class"
 local Base = require "engine.ui.Base"
 local Focusable = require "engine.ui.Focusable"
+local Slider = require "engine.ui.Slider"
 
 --- A generic UI list
 module(..., package.seeall, class.inherit(Base, Focusable))
 
-local ls, ls_w, ls_h = _M:getImage("ui/selection-left-sel.png")
-local ms, ms_w, ms_h = _M:getImage("ui/selection-middle-sel.png")
-local rs, rs_w, rs_h = _M:getImage("ui/selection-right-sel.png")
-local l, l_w, l_h = _M:getImage("ui/selection-left.png")
-local m, m_w, m_h = _M:getImage("ui/selection-middle.png")
-local r, r_w, r_h = _M:getImage("ui/selection-right.png")
-local plus, plus_w, plus_h = _M:getImage("ui/plus.png")
-local minus, minus_w, minus_h = _M:getImage("ui/minus.png")
+local plus = _M:getTexture("ui/plus.png")
+local minus = _M:getTexture("ui/minus.png")
 
 function _M:init(t)
 	self.tree = assert(t.tree, "no tree tree")
@@ -50,8 +45,7 @@ function _M:init(t)
 	self.key_prop = t.key_prop or "__id"
 	self.sel_by_col = t.sel_by_col and {} or nil
 
-
-	self.fh = ls_h
+	self.fh = t.item_height or (self.font_h + 6)
 
 	local w = self.w
 	if self.scrollbar then w = w - 10 end
@@ -78,6 +72,11 @@ function _M:init(t)
 		end
 
 		col.surface = core.display.newSurface(col.width, self.fh)
+		col.frame = self:makeFrame(nil, col.width, self.fh)
+		col.frame_sel = self:makeFrame("ui/selector-sel", col.width, self.fh)
+		col.frame_usel = self:makeFrame("ui/selector", col.width, self.fh)
+		col.frame_col = self:makeFrame("ui/selector", col.width, self.fh)
+		col.frame_col_sel = self:makeFrame("ui/selector-sel", col.width, self.fh)
 
 		col._backs = {}
 	end
@@ -87,46 +86,6 @@ function _M:init(t)
 	Base.init(self, t)
 end
 
-function _M:getColumnBackground(col, level, sign, shown)
-	if sign then sign = true else sign = false end
-	if shown then shown = true else shown = false end
-	level = (col.id == 1) and level or 0
-	if col._backs[level] and col._backs[level][sign] and col._backs[level][sign][shown] then return col._backs[level][sign][shown] end
-	local backs = {}
-	col._backs[level] = col._backs[level] or {}
-	col._backs[level][sign] = col._backs[level][sign] or {}
-	col._backs[level][sign][shown] = backs
-
-	local s = col.surface
-
-	local offset = 0
-	if col.id == 1 then
-		offset = level * self.level_offset
-		if sign then offset = offset + plus_w end
-	end
-	local startx = ls_w + offset
-
-	s:erase(0, 0, 0)
-	s:merge(ls, offset, 0)
-	for i = offset + ls_w, col.width - rs_w, ms_w do s:merge(ms, i, 0) end
-	s:merge(rs, col.width - rs_w, 0)
-	if col.id == 1 and sign then s:merge(shown and minus or plus, offset - plus_w, 0) end
-	backs._stex, backs._stex_w, backs._stex_h = s:glTexture()
-
-	s:erase(0, 0, 0)
-	if col.id == 1 and sign then s:merge(shown and minus or plus, offset - plus_w, 0) end
-	backs._tex, backs._tex_w, backs._tex_h = s:glTexture()
-
-	s:erase(0, 0, 0)
-	s:merge(l, offset, 0)
-	for i = offset + l_w, col.width - r_w, m_w do s:merge(m, i, 0) end
-	s:merge(r, col.width - r_w, 0)
-	if col.id == 1 and sign then s:merge(shown and minus or plus, offset - plus_w, 0) end
-	backs._sustex, backs._sustex_w, backs._sustex_h = s:glTexture()
-
-	return backs
-end
-
 function _M:drawItem(item)
 	item.cols = {}
 	for i, col in ipairs(self.columns) do
@@ -147,14 +106,14 @@ function _M:drawItem(item)
 		local offset = 0
 		if i == 1 then
 			offset = level * self.level_offset
-			if item.nodes then offset = offset + plus_w end
+			if item.nodes then offset = offset + plus.w end
 		end
-		local startx = ls_w + offset
+		local startx = col.frame_sel.b4.w + offset
 
 		item.cols[i] = {}
 
 		s:erase(0, 0, 0, 0)
-		text:drawOnSurface(s, col.width - startx - rs_w, 1, self.font, startx, (self.fh - self.font_h) / 2, color[1], color[2], color[3])
+		text:drawOnSurface(s, col.width - startx - col.frame_sel.b6.w, 1, self.font, startx, (self.fh - self.font_h) / 2, color[1], color[2], color[3])
 		item.cols[i]._tex, item.cols[i]._tex_w, item.cols[i]._tex_h = s:glTexture()
 	end
 	if self.on_drawitem then self.on_drawitem(item) end
@@ -176,7 +135,7 @@ function _M:generate()
 	self.mouse:reset()
 	self.key:reset()
 
-	local fw, fh = self.w, ls_h
+	local fw, fh = self.w, self.fh
 	self.fw, self.fh = fw, fh
 
 	if not self.h then self.h = self.nb_items * fh end
@@ -185,14 +144,7 @@ function _M:generate()
 
 	-- Draw the scrollbar
 	if self.scrollbar then
-		local sb, sb_w, sb_h = self:getImage("ui/scrollbar.png")
-		local ssb, ssb_w, ssb_h = self:getImage("ui/scrollbar-sel.png")
-
-		self.scrollbar = { bar = {}, sel = {} }
-		self.scrollbar.sel.w, self.scrollbar.sel.h, self.scrollbar.sel.tex, self.scrollbar.sel.texw, self.scrollbar.sel.texh = ssb_w, ssb_h, ssb:glTexture()
-		local s = core.display.newSurface(sb_w, self.h - fh)
-		for i = 0, self.h - fh do s:merge(sb, 0, i) end
-		self.scrollbar.bar.w, self.scrollbar.bar.h, self.scrollbar.bar.tex, self.scrollbar.bar.texw, self.scrollbar.bar.texh = ssb_w, self.h - fh, s:glTexture()
+		self.scrollbar = Slider.new{size=self.h - fh, max=1}
 	end
 
 	-- Draw the tree items
@@ -212,7 +164,7 @@ function _M:generate()
 			end end
 		end
 		self:onSelect()
-		if self.list[self.sel] and self.list[self.sel].nodes and bx <= plus_w and button ~= "wheelup" and button ~= "wheeldown" and event == "button" then
+		if self.list[self.sel] and self.list[self.sel].nodes and bx <= plus.w and button ~= "wheelup" and button ~= "wheeldown" and event == "button" then
 			self:treeExpand(nil)
 		else
 			if (self.all_clicks or button == "left") and button ~= "wheelup" and button ~= "wheeldown" and event == "button" then self:onUse(button) end
@@ -324,21 +276,24 @@ function _M:display(x, y, nb_keyframes)
 			local col = self.columns[j]
 			local item = self.list[i]
 			if not item then break end
-			local backs = self:getColumnBackground(col, item.level, item.nodes, item.shown)
 			if self.sel == i and (not self.sel_by_col or self.cur_col == j) then
-				if self.focused then backs._stex:toScreenFull(x, y, col.width, self.fh, backs._stex_w, backs._stex_h)
-				else backs._sustex:toScreenFull(x, y, col.width, self.fh, backs._sustex_w, backs._sustex_h) end
+				if self.focused then self:drawFrame(col.frame_sel, x, y)
+				else self:drawFrame(col.frame_usel, x, y) end
 			elseif (not self.sel_by_col or self.cur_col == j) then
-				backs._tex:toScreenFull(x, y, col.width, self.fh, backs._tex_w, backs._tex_h)
+				self:drawFrame(col.frame, x, y)
 				if item.focus_decay then
-					if self.focused then backs._stex:toScreenFull(x, y, col.width, self.fh, backs._stex_w, backs._stex_h, 1, 1, 1, item.focus_decay / self.focus_decay_max_d)
-					else backs._sustex:toScreenFull(x, y, col.width, self.fh, backs._sustex_w, backs._sustex_h, 1, 1, 1, item.focus_decay / self.focus_decay_max_d) end
+					if self.focused then self:drawFrame(col.frame_sel, x, y, 1, 1, 1, item.focus_decay / self.focus_decay_max_d)
+					else self:drawFrame(col.frame_usel, x, y, 1, 1, 1, item.focus_decay / self.focus_decay_max_d) end
 					item.focus_decay = item.focus_decay - nb_keyframes
 					if item.focus_decay <= 0 then item.focus_decay = nil end
 				end
-			else
-				backs._tex:toScreenFull(x, y, col.width, self.fh, backs._tex_w, backs._tex_h)
 			end
+
+			if item.nodes and j == 1 then
+				local s = item.shown and minus or plus
+				s.t:toScreenFull(x, y + (self.fh - s.h) / 2, s.w, s.h, s.th, s.th)
+			end
+
 			item.cols[j]._tex:toScreenFull(x, y, col.width, self.fh, item.cols[j]._tex_w, item.cols[j]._tex_h)
 			x = x + col.width
 		end
@@ -346,9 +301,8 @@ function _M:display(x, y, nb_keyframes)
 	end
 
 	if self.focused and self.scrollbar then
-		local pos = self.sel * (self.h - self.fh) / self.max
-
-		self.scrollbar.bar.tex:toScreenFull(bx + self.w - self.scrollbar.bar.w, by + self.fh, self.scrollbar.bar.w, self.scrollbar.bar.h, self.scrollbar.bar.texw, self.scrollbar.bar.texh)
-		self.scrollbar.sel.tex:toScreenFull(bx + self.w - self.scrollbar.sel.w, by + self.fh + pos, self.scrollbar.sel.w, self.scrollbar.sel.h, self.scrollbar.sel.texw, self.scrollbar.sel.texh)
+		self.scrollbar.pos = self.sel
+		self.scrollbar.max = self.max
+		self.scrollbar:display(bx + self.w - self.scrollbar.w, by)
 	end
 end
diff --git a/game/engines/default/engine/utils.lua b/game/engines/default/engine/utils.lua
index 99f5bd91bf37444305d20983bf6cdc3bae7cc0bd..fdc6c51b10f84f7d4a250ae49f119f680b33a5e2 100644
--- a/game/engines/default/engine/utils.lua
+++ b/game/engines/default/engine/utils.lua
@@ -647,15 +647,15 @@ function tstring:splitLines(max_width, font)
 	return ret, max_w
 end
 
-function tstring:makeLineTextures(max_width, font, no_split)
+function tstring:makeLineTextures(max_width, font, no_split, r, g, b)
 	local list = no_split and self or self:splitLines(max_width, font)
 	local fh = font:lineSkip()
 	local s = core.display.newSurface(max_width, fh)
 	s:erase(0, 0, 0, 0)
 	local texs = {}
 	local w = 0
-	local r, g, b = 255, 255, 255
-	local oldr, oldg, oldb = 255, 255, 255
+	local r, g, b = r or 255, g or 255, b or 255
+	local oldr, oldg, oldb = r, g, b
 	local v, tv
 	for i = 1, #list do
 		v = list[i]
diff --git a/game/modules/tome/class/Game.lua b/game/modules/tome/class/Game.lua
index 716087f7292f5714791573e973d9f0493e9697ec..118179bf0c45d4a232f3191ad275149af7fef081 100644
--- a/game/modules/tome/class/Game.lua
+++ b/game/modules/tome/class/Game.lua
@@ -853,8 +853,7 @@ function _M:setupCommands()
 		end end,
 		[{"_g","ctrl"}] = function() if config.settings.cheat then
 --			self.nicer_tiles:postProcessLevelTiles(self.level)
-			local m = game.zone:makeEntity(game.level, "object", {properties={"lore"}}, nil, true)
-			game.zone:addEntity(game.level, m, "object", game.player.x, game.player.y)
+			game:registerDialog(require("mod.dialogs.Donation").new())
 		end end,
 	}
 
diff --git a/game/modules/tome/class/interface/PlayerLore.lua b/game/modules/tome/class/interface/PlayerLore.lua
index abfd377ed01434a25912d13931c3d28e6e13056c..4a7579d4abe3c61a04a57188159e3bc6268a32f2 100644
--- a/game/modules/tome/class/interface/PlayerLore.lua
+++ b/game/modules/tome/class/interface/PlayerLore.lua
@@ -19,6 +19,7 @@
 
 require "engine.class"
 local Dialog = require "engine.ui.Dialog"
+local LorePopup = require "mod.dialogs.LorePopup"
 
 module(..., package.seeall, class.make)
 
@@ -75,7 +76,7 @@ end
 function _M:learnLore(lore)
 	if not self:knownLore(lore) then
 		local l = self:getLore(lore)
-		Dialog:simpleLongPopup("Lore found: #0080FF#"..l.name, "#ANTIQUE_WHITE#"..util.getval(l.lore), game.w * 0.6, nil, nil, 0.8)
+		LorePopup.new(l, game.w * 0.6, 0.8)
 		game.logPlayer(self, "Lore found: #0080FF#%s", l.name)
 		game.logPlayer(self, "#ANTIQUE_WHITE#%s", util.getval(l.lore))
 		game.logPlayer(self, "You can read all your collected lore in the game menu, by pressing Escape.")
diff --git a/game/modules/tome/data/general/objects/boss-artifacts.lua b/game/modules/tome/data/general/objects/boss-artifacts.lua
index 89202fa73512c5e550221d69c603b8737d6c1a0f..12651ce7ff7bdc2c96df27130a57c1f15d5f3831 100644
--- a/game/modules/tome/data/general/objects/boss-artifacts.lua
+++ b/game/modules/tome/data/general/objects/boss-artifacts.lua
@@ -801,7 +801,7 @@ newEntity{ base = "BASE_GEM", define_as = "CRYSTAL_FOCUS",
 			o.unique = o.name
 			o.no_unique_lore = true
 			if o.combat and o.combat.dam then
-				o.combat.dam = o.combat.dam * 1.5
+				o.combat.dam = o.combat.dam * 1.25
 				o.combat.damtype = engine.DamageType.ARCANE
 			end
 			o.wielder = o.wielder or {}
diff --git a/game/modules/tome/data/gfx/ui/parchment1.png b/game/modules/tome/data/gfx/ui/parchment1.png
new file mode 100644
index 0000000000000000000000000000000000000000..1204872001b2f74f6ee48d436b08a6f204b5e0fb
Binary files /dev/null and b/game/modules/tome/data/gfx/ui/parchment1.png differ
diff --git a/game/modules/tome/data/gfx/ui/parchment2.png b/game/modules/tome/data/gfx/ui/parchment2.png
new file mode 100644
index 0000000000000000000000000000000000000000..b5c5c23245189ab4f08e099c4e70536acb409728
Binary files /dev/null and b/game/modules/tome/data/gfx/ui/parchment2.png differ
diff --git a/game/modules/tome/data/gfx/ui/parchment3.png b/game/modules/tome/data/gfx/ui/parchment3.png
new file mode 100644
index 0000000000000000000000000000000000000000..053d56494a64c4b8a957400665b0de14797f8702
Binary files /dev/null and b/game/modules/tome/data/gfx/ui/parchment3.png differ
diff --git a/game/modules/tome/data/gfx/ui/parchment4.png b/game/modules/tome/data/gfx/ui/parchment4.png
new file mode 100644
index 0000000000000000000000000000000000000000..af534d4a3253cb842a33aa75a5372f9687b17f38
Binary files /dev/null and b/game/modules/tome/data/gfx/ui/parchment4.png differ
diff --git a/game/modules/tome/data/gfx/ui/parchment5.png b/game/modules/tome/data/gfx/ui/parchment5.png
new file mode 100644
index 0000000000000000000000000000000000000000..c3aee676a26ba0895abc6a564515eb2e6dc52c28
Binary files /dev/null and b/game/modules/tome/data/gfx/ui/parchment5.png differ
diff --git a/game/modules/tome/data/gfx/ui/parchment6.png b/game/modules/tome/data/gfx/ui/parchment6.png
new file mode 100644
index 0000000000000000000000000000000000000000..10f0fa0a6af3808498dcf02df56389464e25c2e5
Binary files /dev/null and b/game/modules/tome/data/gfx/ui/parchment6.png differ
diff --git a/game/modules/tome/data/gfx/ui/parchment7.png b/game/modules/tome/data/gfx/ui/parchment7.png
new file mode 100644
index 0000000000000000000000000000000000000000..93e2b95813484e9a26a5e3fa4d6489609b39ddad
Binary files /dev/null and b/game/modules/tome/data/gfx/ui/parchment7.png differ
diff --git a/game/modules/tome/data/gfx/ui/parchment8.png b/game/modules/tome/data/gfx/ui/parchment8.png
new file mode 100644
index 0000000000000000000000000000000000000000..9f12823702b6f66592357f7cf3771c8b1063f2a4
Binary files /dev/null and b/game/modules/tome/data/gfx/ui/parchment8.png differ
diff --git a/game/modules/tome/data/gfx/ui/parchment9.png b/game/modules/tome/data/gfx/ui/parchment9.png
new file mode 100644
index 0000000000000000000000000000000000000000..25b3ec0a34b91d8e715c11d69223eeac231a6df0
Binary files /dev/null and b/game/modules/tome/data/gfx/ui/parchment9.png differ
diff --git a/game/modules/tome/data/gfx/ui/parchmentblood1.png b/game/modules/tome/data/gfx/ui/parchmentblood1.png
new file mode 100644
index 0000000000000000000000000000000000000000..ddda2adc90189b35119fb376f4a7b1f9a16e0406
Binary files /dev/null and b/game/modules/tome/data/gfx/ui/parchmentblood1.png differ
diff --git a/game/modules/tome/data/gfx/ui/parchmentblood2.png b/game/modules/tome/data/gfx/ui/parchmentblood2.png
new file mode 100644
index 0000000000000000000000000000000000000000..fc14764296191cff425f9e6e5d16e46361f66b35
Binary files /dev/null and b/game/modules/tome/data/gfx/ui/parchmentblood2.png differ
diff --git a/game/modules/tome/data/gfx/ui/parchmentblood3.png b/game/modules/tome/data/gfx/ui/parchmentblood3.png
new file mode 100644
index 0000000000000000000000000000000000000000..d069932e34e33b9ce8a54b83ae86978ae78f81eb
Binary files /dev/null and b/game/modules/tome/data/gfx/ui/parchmentblood3.png differ
diff --git a/game/modules/tome/data/gfx/ui/parchmentblood4.png b/game/modules/tome/data/gfx/ui/parchmentblood4.png
new file mode 100644
index 0000000000000000000000000000000000000000..959a9c87c680a6022d53e6353ca450b16665e28d
Binary files /dev/null and b/game/modules/tome/data/gfx/ui/parchmentblood4.png differ
diff --git a/game/modules/tome/data/gfx/ui/parchmentblood5.png b/game/modules/tome/data/gfx/ui/parchmentblood5.png
new file mode 100644
index 0000000000000000000000000000000000000000..0e6c047bb24fdee9113618af865d9ea126b9ad17
Binary files /dev/null and b/game/modules/tome/data/gfx/ui/parchmentblood5.png differ
diff --git a/game/modules/tome/data/lore/age-allure.lua b/game/modules/tome/data/lore/age-allure.lua
index e38b646b7c59461b15ac88742516faf6b8974ad3..caf075978e72a31dec896a3cdedb096c934a41d3 100644
--- a/game/modules/tome/data/lore/age-allure.lua
+++ b/game/modules/tome/data/lore/age-allure.lua
@@ -116,6 +116,7 @@ newLore{
 	id = "halfling-research-note-4",
 	category = "age of allure",
 	name = "research log of halfling mage Hompalan",
+	bloodstains = 7,
 	lore = [[
 #{bold}#Hompalan's Log Entry 9#{normal}#
 #{italic}#Age of Allure 4549#{normal}#
diff --git a/game/modules/tome/data/lore/maze.lua b/game/modules/tome/data/lore/maze.lua
index 7cdf247f65561a25fcf9b26daa73bf8cfe652cdd..b97d01fb8d6c4256b20008a2450799995339101c 100644
--- a/game/modules/tome/data/lore/maze.lua
+++ b/game/modules/tome/data/lore/maze.lua
@@ -84,6 +84,7 @@ newLore{
 	id = "maze-note-7",
 	category = "maze",
 	name = "diary (the maze)",
+	bloodstains = 2,
 	lore = [[Dear diary,
 
 #{italic}#This text is unreadable as it is thoroughly caked in blood.#{normal}#]],
diff --git a/game/modules/tome/data/lore/old-forest.lua b/game/modules/tome/data/lore/old-forest.lua
index 0fd0b4852dec613ed5b9cb7ff3fc042860a2c00e..f360b35dee0e5d83ddb62a2ab9c78801bd52ae96 100644
--- a/game/modules/tome/data/lore/old-forest.lua
+++ b/game/modules/tome/data/lore/old-forest.lua
@@ -75,6 +75,7 @@ newLore{
 	id = "old-forest-note-6",
 	category = "old forest",
 	name = "journal entry (old forest)",
+	bloodstains = 4,
 	lore = [[#{italic}#From the notes of Darwood Oakton, explorer:
 #{bold}#CHAPTER SIX: HORR...
 
diff --git a/game/modules/tome/data/lore/trollmire.lua b/game/modules/tome/data/lore/trollmire.lua
index 910f22705d309fda0a66e1f9a8c2e950dff439a3..07d1260f3c7f4fbeb008321cf637c7c575f558c8 100644
--- a/game/modules/tome/data/lore/trollmire.lua
+++ b/game/modules/tome/data/lore/trollmire.lua
@@ -58,6 +58,7 @@ newLore{
 	id = "trollmire-note-5",
 	category = "trollmire",
 	name = "tattered paper scrap (trollmire)",
+	bloodstains = 3,
 	lore = [[You find a tattered page scrap. Perhaps this is part of a diary entry.
 "...writing this in a tree and he's at the bottom of it. Waiting. His club is the size of a tall dwarf. Don't think I'm going to make it."]],
 }
diff --git a/game/modules/tome/dialogs/LorePopup.lua b/game/modules/tome/dialogs/LorePopup.lua
new file mode 100644
index 0000000000000000000000000000000000000000..ae39ea07e79f8b73454fc6300d823d2d4f89ac6c
--- /dev/null
+++ b/game/modules/tome/dialogs/LorePopup.lua
@@ -0,0 +1,72 @@
+-- ToME - Tales of Maj'Eyal
+-- Copyright (C) 2009, 2010 Nicolas Casalini
+--
+-- This program is free software: you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation, either version 3 of the License, or
+-- (at your option) any later version.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with this program.  If not, see <http://www.gnu.org/licenses/>.
+--
+-- Nicolas Casalini "DarkGod"
+-- darkgod@te4.org
+
+require "engine.class"
+local Dialog = require "engine.ui.Dialog"
+local ListColumns = require "engine.ui.ListColumns"
+local TextzoneList = require "engine.ui.TextzoneList"
+local Separator = require "engine.ui.Separator"
+
+module(..., package.seeall, class.inherit(Dialog))
+
+function _M:init(l, w, force_height)
+	local text = util.getval(l.lore).."\n"
+	local list = text:splitLines(w - 10, self.font)
+
+	self.frame = {
+		shadow = {x = 10, y = 10, a = 0.5},
+		ox1 = -16, ox2 = 16,
+		oy1 = -16, oy2 = 16,
+		b7 = "ui/parchment7.png",
+		b9 = "ui/parchment9.png",
+		b1 = "ui/parchment1.png",
+		b3 = "ui/parchment3.png",
+		b4 = "ui/parchment4.png",
+		b6 = "ui/parchment6.png",
+		b8 = "ui/parchment8.png",
+		b2 = "ui/parchment2.png",
+		b5 = "ui/parchment5.png",
+	}
+	if l.bloodstains then
+		local ovs = {}
+		for i = 1, l.bloodstains do
+			ovs[#ovs+1] = {image="ui/parchmentblood"..rng.range(1, 5)..".png", gen=function(self, dialog)
+				self.x = rng.range(30, dialog.w - 60)
+				self.y = rng.range(30, dialog.h - 60)
+				self.a = rng.float(0.5, 0.8)
+			end}
+		end
+		self.frame.overlays = ovs
+	end
+
+	Dialog.init(self, "Lore found: #0080FF#"..l.name, 1, 1)
+
+	local h = math.min(force_height and (force_height * game.h) or 999999999, self.font_h * #list)
+	self:loadUI{
+		{left = 3, top = 3, ui=require("engine.ui.Textzone").new{
+				width=w+10, height=h, scrollbar=(h < self.font_h * #list) and true or false, text=text, color={r=0x3a, g=0x35, b=0x33},
+			}
+		}
+	}
+	if not no_leave then
+		self.key:addBind("EXIT", function() game:unregisterDialog(self) if fct then fct() end end)
+	end
+	self:setupUI(true, true)
+	game:registerDialog(self)
+end
diff --git a/game/modules/tome/dialogs/debug/ChangeZone.lua b/game/modules/tome/dialogs/debug/ChangeZone.lua
index e19b23fa0a51f4df67e4e531eed2427021f93f5d..0168539ab569a960bd0f055343423301c2156b95 100644
--- a/game/modules/tome/dialogs/debug/ChangeZone.lua
+++ b/game/modules/tome/dialogs/debug/ChangeZone.lua
@@ -28,7 +28,7 @@ function _M:init()
 	self:generateList()
 	engine.ui.Dialog.init(self, "Debug/Cheat! It's BADDDD!", 1, 1)
 
-	local list = List.new{width=400, height=500, list=self.list, fct=function(item) self:use(item) end}
+	local list = List.new{width=400, height=500, scrollbar=true, list=self.list, fct=function(item) self:use(item) end}
 
 	self:loadUI{
 		{left=0, top=0, ui=list},
diff --git a/src/core_lua.c b/src/core_lua.c
index ebbf4563457b4ac7ba7d1d988ff2ed19de5e6a0a..8ad2ed6197db73d00ccb6b23394f807b6238ab79 100644
--- a/src/core_lua.c
+++ b/src/core_lua.c
@@ -1018,6 +1018,24 @@ static int sdl_texture_toscreen_full(lua_State *L)
 	return 0;
 }
 
+static int gl_scale(lua_State *L)
+{
+	if (lua_isnumber(L, 1))
+	{
+		glPushMatrix();
+		glScalef(lua_tonumber(L, 1), lua_tonumber(L, 2), lua_tonumber(L, 3));
+	}
+	else
+		glPopMatrix();
+	return 0;
+}
+
+static int gl_translate(lua_State *L)
+{
+	glTranslatef(lua_tonumber(L, 1), lua_tonumber(L, 2), lua_tonumber(L, 3));
+	return 0;
+}
+
 static int sdl_texture_bind(lua_State *L)
 {
 	GLuint *t = (GLuint*)auxiliar_checkclass(L, "gl{texture}", 1);
@@ -1520,6 +1538,8 @@ static const struct luaL_reg displaylib[] =
 	{"getModesList", sdl_get_modes_list},
 	{"setMouseCursor", sdl_set_mouse_cursor},
 	{"setGamma", sdl_set_gamma},
+	{"glTranslate", gl_translate},
+	{"glScale", gl_scale},
 	{NULL, NULL},
 };