From 58239e97ed2372c5110db5684a4c228bcb5ebf95 Mon Sep 17 00:00:00 2001 From: Alexander Gavrilov Date: Sat, 1 Dec 2012 16:50:03 +0400 Subject: [PATCH] Implement the history graph in the workflow status screen. --- Lua API.html | 14 +- Lua API.rst | 2 + Readme.html | 27 +++- Readme.rst | 33 ++++- dfhack.init-example | 1 + images/workflow-new1.png | Bin 6674 -> 6775 bytes images/workflow-new2.png | Bin 6862 -> 7793 bytes images/workflow-status.png | Bin 0 -> 5118 bytes images/workflow.png | Bin 4931 -> 5779 bytes library/lua/gui/widgets.lua | 19 ++- scripts/gui/workflow.lua | 248 ++++++++++++++++++++++++------------ 11 files changed, 248 insertions(+), 96 deletions(-) create mode 100644 images/workflow-status.png diff --git a/Lua API.html b/Lua API.html index f42905d01..f14239a10 100644 --- a/Lua API.html +++ b/Lua API.html @@ -2787,6 +2787,14 @@ before rendering the token.

  • token.tile = pen

    Specifies a pen to paint as one tile before the main part of the token.

  • +
  • token.width = ...

    +

    If specified either as a value or a callback, the text field is padded +or truncated to the specified number.

    +
  • +
  • token.pad_char = '?'

    +

    If specified together with width, the padding area is filled with +this character instead of just being skipped over.

    +
  • token.key = '...'

    Specifies the keycode associated with the token. The string description of the key binding is added to the text content of the token.

    @@ -2848,7 +2856,9 @@ this may be extended with mouse click support.

    icon_pen:Default pen for icons. -on_select:Selection change callback; called as on_select(index,choice). +on_select:Selection change callback; called as on_select(index,choice). +This is also called with nil arguments if setChoices is called +with an empty list. on_submit:Enter key callback; if specified, the list reacts to the key and calls it as on_submit(index,choice). @@ -2928,6 +2938,8 @@ supports:

    edit_pen:If specified, used instead of cursor_pen for the edit field. +edit_below:If true, the edit field is placed below the list instead of above. + not_found_label:  Specifies the text of the label shown when no items match the filter. diff --git a/Lua API.rst b/Lua API.rst index 714a41bfb..cedc36441 100644 --- a/Lua API.rst +++ b/Lua API.rst @@ -2785,6 +2785,8 @@ It has the following attributes: :inactive_pen: If specified, used for the cursor when the widget is not active. :icon_pen: Default pen for icons. :on_select: Selection change callback; called as ``on_select(index,choice)``. + This is also called with *nil* arguments if ``setChoices`` is called + with an empty list. :on_submit: Enter key callback; if specified, the list reacts to the key and calls it as ``on_submit(index,choice)``. :on_submit2: Shift-Enter key callback; if specified, the list reacts to the key diff --git a/Readme.html b/Readme.html index deea72bef..d75be99f4 100644 --- a/Readme.html +++ b/Readme.html @@ -3034,11 +3034,11 @@ current job, and their current status.

    current count is below the lower bound of the range, the job is resumed; if it is above or equal to the top bound, it will be suspended. Within the range, the specific constraint has no effect on the job; others may still affect it.

    -

    Pressing 'c' switches the current constraint between counting stacks or items. -Pressing 'm' lets you input the range directly; 'e', 'r', 'd', 'f' adjust the -bounds by 1, 5, or 25 depending on the direction and the 'c' setting (counting -items and expanding the range each gives a 5x bonus).

    -

    Pressing 'n' produces a list of possible outputs of this job as guessed by +

    Pressing 'I' switches the current constraint between counting stacks or items. +Pressing 'R' lets you input the range directly; 'e', 'r', 'd', 'f' adjust the +bounds by 5, 10, or 20 depending on the direction and the 'I' setting (counting +items and expanding the range each gives a 2x bonus).

    +

    Pressing 'A' produces a list of possible outputs of this job as guessed by workflow, and lets you create a new constraint by choosing one as template. If you don't see the choice you want in the list, it likely means you have to adjust the job material first using job item-material or gui/workshop-job, @@ -3050,6 +3050,23 @@ added to the list. If you use Shift-Enter, the interface proceeds to the next dialog, which allows you to edit the suggested constraint parameters to suit your need, and set the item count range.

    images/workflow-new2.png +

    Pressing 'S' (or, with the example config, Alt-W in the 'z' stocks screen) +opens the overall status screen, which was copied from the C++ implementation +by falconne for better integration with the rest of the lua script:

    +images/workflow-status.png +

    This screen shows all currently existing workflow constraints, and allows +monitoring and/or changing them from one screen. The constraint list can +be filtered by typing text in the field below.

    +

    The color of the stock level number indicates how "healthy" the stock level +is, based on current count and trend. Bright green is very good, green is good, +red is bad, bright red is very bad.

    +

    The limit number is also color-coded. Red means that there are currently no +workshops producing that item (i.e. no jobs). If it's yellow, that means the +production has been delayed, possibly due to lack of input materials.

    +

    The chart on the right is a plot of the last 14 days (28 half day plots) worth +of stock history for the selected item, with the rightmost point representing +the current stock value. The bright green dashed line is the target +limit (maximum) and the dark green line is that minus the gap (minimum).

    gui/assign-rack

    diff --git a/Readme.rst b/Readme.rst index a214a6ecb..a84691b05 100644 --- a/Readme.rst +++ b/Readme.rst @@ -2295,12 +2295,12 @@ current count is below the lower bound of the range, the job is resumed; if it is above or equal to the top bound, it will be suspended. Within the range, the specific constraint has no effect on the job; others may still affect it. -Pressing 'c' switches the current constraint between counting stacks or items. -Pressing 'm' lets you input the range directly; 'e', 'r', 'd', 'f' adjust the -bounds by 1, 5, or 25 depending on the direction and the 'c' setting (counting -items and expanding the range each gives a 5x bonus). +Pressing 'I' switches the current constraint between counting stacks or items. +Pressing 'R' lets you input the range directly; 'e', 'r', 'd', 'f' adjust the +bounds by 5, 10, or 20 depending on the direction and the 'I' setting (counting +items and expanding the range each gives a 2x bonus). -Pressing 'n' produces a list of possible outputs of this job as guessed by +Pressing 'A' produces a list of possible outputs of this job as guessed by workflow, and lets you create a new constraint by choosing one as template. If you don't see the choice you want in the list, it likely means you have to adjust the job material first using ``job item-material`` or ``gui/workshop-job``, @@ -2316,6 +2316,29 @@ suit your need, and set the item count range. .. image:: images/workflow-new2.png +Pressing 'S' (or, with the example config, Alt-W in the 'z' stocks screen) +opens the overall status screen, which was copied from the C++ implementation +by falconne for better integration with the rest of the lua script: + +.. image:: images/workflow-status.png + +This screen shows all currently existing workflow constraints, and allows +monitoring and/or changing them from one screen. The constraint list can +be filtered by typing text in the field below. + +The color of the stock level number indicates how "healthy" the stock level +is, based on current count and trend. Bright green is very good, green is good, +red is bad, bright red is very bad. + +The limit number is also color-coded. Red means that there are currently no +workshops producing that item (i.e. no jobs). If it's yellow, that means the +production has been delayed, possibly due to lack of input materials. + +The chart on the right is a plot of the last 14 days (28 half day plots) worth +of stock history for the selected item, with the rightmost point representing +the current stock value. The bright green dashed line is the target +limit (maximum) and the dark green line is that minus the gap (minimum). + gui/assign-rack =============== diff --git a/dfhack.init-example b/dfhack.init-example index 8fafa4cf4..7617b9f6e 100644 --- a/dfhack.init-example +++ b/dfhack.init-example @@ -91,6 +91,7 @@ keybinding add Alt-A@dwarfmode/QueryBuilding/Some/Workshop/Job gui/workshop-job # workflow front-end keybinding add Alt-W@dwarfmode/QueryBuilding/Some/Workshop/Job gui/workflow +keybinding add Alt-W@overallstatus "gui/workflow status" # assign weapon racks to squads so that they can be used keybinding add P@dwarfmode/QueryBuilding/Some/Weaponrack gui/assign-rack diff --git a/images/workflow-new1.png b/images/workflow-new1.png index 50d0e1f421ac9de1abf87545c8d7ade31bd4cd4a..498fc4e80b4eb9736a00429195a9eee6dbd17d14 100644 GIT binary patch delta 6724 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 delta 6601 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 literal 6862 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 literal 0 HcmV?d00001 diff --git a/images/workflow.png b/images/workflow.png index a0a0d4216b51bcecc99c82e4ab6e527225410501..7506c730f520d74f42f35b01034e4b083db83940 100644 GIT binary patch literal 5779 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 literal 4931 zcmeAS@N?(olHy`uVBq!ia0y~yU{+vYVANq@W?*1A$$W~Ffq_9Qz$e6&fq|i+q2a)R z0}Txf|NsAI08{Fg%Wez*UeYsH}{-xw8fWyNC8H+i2@eBPKGt4-XnEkQ$+N)mcrVZIXfjI zt$8NQS;@c4OCy@el3n0fL%Re=OVeCwmUS-#jyt~;@{evbt@jH&q}h4YXZ=fo?AZ}# zzVY~bX89{jKklvV5O83U=7eRU0-F|exH33u{ARi|)xk=fUwy(kO~y{ii=Rs!KAdT2 znQgS;G1JZ`QUccd8}78dmN_Bco!+F%G>N4}rskI7yD6T{B}`3Mq7*VXnh&ox{lPgw zO-La7#SZaLjtZ8+FWtCqwEPz5h;9)JW^(zUJ)2p(!((I1(W6ru0$C5YA z4xPv?Vdq4JGNvSm%6@mUV|7_R_oZ5*v>Cqy`cMBaLS-LLDQ@b*v7 z!!%CQ;5FZ0PO$i0k(wDfQ;~;pWld^m!i4_&*bf0Ty!m0@AM*Ed1gA6@6!5BKk94Nzse>F&nC)cnq?@rK`3JJ-uwyZAXz zvL0&me)I0>JJqO7c`w#UbIdlmRLsyLt#$0q-j0;e(A!Qi3TzxpR&_A0{TCU!@#~HA zPmN!H&|y6Bd&-*Qt4b3-ZfuHr_?<<7XNSXw9=_xm-GyH)8?HsBz5Dj8)?2L6Mk!2( zi;2-#U*J`={dLBoeR-WJE4%FT@AERQ(?2_6ymU`Gsbbp08q67U&64VdX2+D?M%WI8QB6eo|w~NxxdolR^p~er!D47knt* zk6oJ+%(i-RyEtwAZ z-Y8{UlqY}ccKhXc$>S^?os-sV;$F2$hdEyIB#TE+3P{#F*p5X-`(g_3%f=%fVK+Gi>2{nG<)t_w#p7(0SuL;hUdoBvT5%f|}Op zM}D=ICojEURwASvImc*nif5tWqYI%w)1Da5h-P2XUKTY+nKZxf z6@O;_wB*XR%qaeBDT|Ve{0s+lCF(YBFE7;-Gg6=L(cp+ z%inK(yX`hlV~+pp)1Co$kNAKL{b0T!k?+%A&N3Z0XVzTj}@Xbjk7#B!${f?$^~k?G)Idemh;ErBP*_V(UBAZpEM% z4%3d-dR&{tD$11-$vdx7#e1frKx&k`LW!qC)lE%~7BPmP7c#1+BbVQNx{W2yZJj<&<4GhY3f zQq5W-DaTob;+zvMdxUMAEqG#Eq~L`8`~H8Gby)Mp!hvgTIhP&}OYvsbMb|i4W?o7a zG)kMM>d<3&X49Ab-~Vrwxbf-jm5<+BCM~_X#vx+Utwmd3NPViEq51M}-TK6gz)dz= zb)w!yPP;q5`RKIY`&%1k9FsW3XRzROn1z#td9i|-Pr#0*CbgGJ~7qQ?|){dLf6botPY>1>#(0F%TzeC zNsr0Mb(*S!hV{EhVT*THc+V*%_La^mE@r#Lb4RNopsXu)VN9|vx4wO`p8mP`O&et2 z_@7?uv+090yYdm%N&8biPGD|WDKj^#T~=G0>Z#j(`@@HM zbMu%^3MovO%iZXs5*bvtf2Y8S6Oq#xF8b-7w%T8K-fw$His!VaVOw9gY>V^KEJ;*eY(!cO>Jhb(^RFMuYc&_J2vfQ z&v~_q(+e3IyBQwEOg(BP5##5uPjls?AS^ zn^)`ad}eBKIH1GWAr+2MjMrIzC8Pu*QkSfm0w6V@d!Bu2}Q@VEKIjggJ+f^e@Ukp-c4a-j{4B(q! z_)YP-RQan)uWLHncqXh=@op%ve7>1M&%ZYNNz}9}n;zIYSX2pd)NGryb!9l0%i+C@ z7jMZf-FQ0lr&rkCS6S=jIbwF~GmV?3>R{sB@cmpyub8{##ob%ao1d1Nvc@b!m#-z8 zF+Yt-;C2`1ggvUO?@zie{qFxXwnZfj9xg2@x{;;wYC4g+d@YU-yuv~{QgkC%^>^R; zcAe2B^ZlZ8f!pg2>1|%~r*VzzCJ7dnM?F=I1t$I{nHuBPn&l>|c3bIg3BIm)DCqPo zS&th_rkVa)#8-aO_qh6f&zW2f4HteY{@gEAA)9UIkfkS|eQHyQjKI?N*kUc0BIZS5 z%q?P!N8*ot+POw0d#{6uJ`>mVO4D68y~BLBu6k?NvUIH}!^5SKijUViMtX~tH#sX5 zXymTtJfSD#@oo~Uh@QZ-ZJU@UZB3cjA+4ygm0^NYd*g?wkL3!HtKO|#!@?2%MnRxX zwf-bi+quJx{8C@Hw>G?(B7R>-Ke9-#+iZ8r$=b+wb{9?0J=K`6I`hsG0p6C_Ynv|2 zdOTxVjNRg!pO{`g&nkItvrKjR`5%o1>wfFpb=maD_i*95=aI8IQNh#&iLJAXRbTY(;l>HzepaF3B@t?MR#Ul<|^c^I`5=1yfD0ayi`D+3KgYpL@bJ z4eRB~Eb9%9q`u$w|IZ(rDLPUwR6V9KEIjh!1&5-*Dd9#H&uI*aVIgl8T^9)7bmhk+ z)k#aIq!m6f5t!yDbMg^GcJk?{g`cPCgbHwcSBz8O5k4i%{=uhViIWq?wK7H>s_C^dG?nw z-e2|#^S?LuCT{<=+^xey>|Jux!lxc$@i8kBVjBcHf~|Jy`p%S6REpfA(7pBs$3ZD0 zd4Y**eweDnZh9hd;b^4TGo{mqq?+=6Ez)z)JG;r|`SxSp)vlZLZmxXIS^jELYHFy} z#NtR6p?&(@(>NSdv}+nAuM6Cl)Y)~hp(Di-R3*hJ#8_EO=X?EAqI*{kPqK0g^BnK? zp7K3g!u|Gt@0WO1aColO+n+b5>dg7SRZp!RnA?%^ zaoYS79E<|to7|X{Cb=q1%;sqDQHu;Ztt4Q>of4_A{O=^wTZ{Cz>abou{3%3&L##A> zQ<_)xQ#JPOC5zPWOL$EaHrf{#Wg(pZkz4XrfN-A%+&osg`p6#U9fk1 z{_b8}GdFIN%cesPZ(eNt%d7yF69Q_SKQ~VXETSa_X6)GOzYQS``W<$dBQyhu#T3QR*rHkiX4tEPQeOiuGn^{ zcBeOOm?mm)pj3{dyyI+vrFe_sk>(o{zgF0sV^Hj<5RkT)+aJX$dFXfJ7I9||rL#>e ziXN>8B{msmH4CJ0~!HS$15Umime>g(LXBg5fg-wFUKQ@t-fI{i^MG zC}#ZC;kv|oz9Ru2T9WL=-b@gf7gNP}@VvxLhK|SwO0(Yc9gP;-I+JDJaQ;|H{oBuPQwm~O`J?SRPU~D?%BoNGJjJ+3ZqL2 zZ%Pb9()NERZt*wq-#p_S6L4HYuynf1pt!ZYu$A78DFQMLLFlc zr=fr@3+Kb!tVjtDLFFWeY2C|vSQI{-6yI@7qmFTU+^tjWZztqAUa~KUZ~dgOqbl%o zf#pI;FEy_TXJwThIUT4I*xzve`(%bzpOljX?#}DP4lQcLs#a0XH=37gKetcu!;BkXx zroKMI#0zE}3`;gxa(gO#IVP*1T6rRMnxw+rZ>cZ2JZ^edE^E|Ob8n7GJ2D~9VV&VK zh0|VdJ+DV^`t&|Ww&T^U&8`ZrTXlAJo>7_}eZ4kv)hlE3v)lpul=>G{-_vSbBJ?)K z{jI>xGaRq}HtDR&*rmn3)2&b;Q#i3$<^5xaJdRg?w=v$lE+RIuy!l6(Qb^flm9u5d zYxuhrYny-Ex@jZRW2#tyjdsR! zE3PBzZ8~#Typfk}*iaI*afgM^e_jqp4yA=w9V|_MoOQVsmY1vgIZZg7Q|H^jBilUX z`X;HYA`Y8PYo=ZGT71VqkVSe4;{=6RkVMWFL1zvn-bN0`8*DBDO#(|AKYl*1!M^j( zGx0{A%aOi(7jIQvyxz@s=gl^;juUzlB7ZSW)VThB-`5{crf<$_tf{N1d!oR{wsj4c zg4xVfO&yI3rY^S>2)B3Cech_SXyhC#uvuXDn(tvN4=uOr;8$Cbx|id~?JF#v|0kYx z*fcSz<2UOpF2f}$?K50eCnQeVWqo9woQugy70#hW1Qk7`nP*mAR$$?r{dlSZiy(VZnbBE^OClV}9dB$lt;#JwHbGHD-kn8}Bl(19 z^USJh1(u(8>tyE!2rwCnoGmff{y$A#IbUpB6UXctmW%fMi;6-g@i%WN@hU0ZE5?-6 zxywPPqc)hSY1uEm2@O}|U6M|F2nmSVvi`l`^V6}&DUC%T(c9rcLr&w*mM2rUDn#G2 oR{1|6Nz$v}Sstq=)1*HPJFR!H{g`tg3^dT?>FVdQ&MBb@0B&`AZU6uP diff --git a/library/lua/gui/widgets.lua b/library/lua/gui/widgets.lua index ebbffbbbd..cb9e1c9be 100644 --- a/library/lua/gui/widgets.lua +++ b/library/lua/gui/widgets.lua @@ -418,7 +418,13 @@ List.ATTRS{ function List:init(info) self.page_top = 1 self.page_size = 1 - self:setChoices(info.choices, info.selected) + + if info.choices then + self:setChoices(info.choices, info.selected) + else + self.choices = {} + self.selected = 1 + end end function List:setChoices(choices, selected) @@ -481,6 +487,9 @@ function List:moveCursor(delta, force_cb) if cnt < 1 then self.page_top = 1 self.selected = 1 + if force_cb and self.on_select then + self.on_select(nil,nil) + end return end @@ -657,13 +666,17 @@ function FilteredList:init(info) end end self.not_found = Label{ - visible = false, + visible = true, text = info.not_found_label or 'No matches', text_pen = COLOR_LIGHTRED, frame = { l = info.icon_width, t = self.list.frame.t }, } self:addviews{ self.edit, self.list, self.not_found } - self:setChoices(info.choices, info.selected) + if info.choices then + self:setChoices(info.choices, info.selected) + else + self.choices = {} + end end function FilteredList:getChoices() diff --git a/scripts/gui/workflow.lua b/scripts/gui/workflow.lua index 9a45f6554..77a87c9ce 100644 --- a/scripts/gui/workflow.lua +++ b/scripts/gui/workflow.lua @@ -130,12 +130,20 @@ RangeEditor = defclass(RangeEditor, widgets.Label) RangeEditor.ATTRS { get_cb = DEFAULT_NIL, - save_cb = DEFAULT_NIL + save_cb = DEFAULT_NIL, + keys = { + count = 'CUSTOM_SHIFT_I', + modify = 'CUSTOM_SHIFT_R', + min_dec = 'BUILDING_TRIGGER_MIN_SIZE_DOWN', + min_inc = 'BUILDING_TRIGGER_MIN_SIZE_UP', + max_dec = 'BUILDING_TRIGGER_MAX_SIZE_DOWN', + max_inc = 'BUILDING_TRIGGER_MAX_SIZE_UP', + } } function RangeEditor:init(args) self:setText{ - { key = 'BUILDING_TRIGGER_ENABLE_CREATURE', + { key = self.keys.count, text = function() local cons = self.get_cb() or null_cons if cons.goal_by_count then @@ -145,21 +153,21 @@ function RangeEditor:init(args) end end, on_activate = self:callback('onChangeUnit') }, - { key = 'BUILDING_TRIGGER_ENABLE_MAGMA', text = ': Modify', + { key = self.keys.modify, text = ': Range', on_activate = self:callback('onEditRange') }, NEWLINE, ' ', - { key = 'BUILDING_TRIGGER_MIN_SIZE_DOWN', - on_activate = self:callback('onIncRange', 'goal_gap', 5) }, - { key = 'BUILDING_TRIGGER_MIN_SIZE_UP', + { key = self.keys.min_dec, + on_activate = self:callback('onIncRange', 'goal_gap', 2) }, + { key = self.keys.min_inc, on_activate = self:callback('onIncRange', 'goal_gap', -1) }, { text = function() local cons = self.get_cb() or null_cons return string.format(': Min %-4d ', cons.goal_value - cons.goal_gap) end }, - { key = 'BUILDING_TRIGGER_MAX_SIZE_DOWN', + { key = self.keys.max_dec, on_activate = self:callback('onIncRange', 'goal_value', -1) }, - { key = 'BUILDING_TRIGGER_MAX_SIZE_UP', - on_activate = self:callback('onIncRange', 'goal_value', 5) }, + { key = self.keys.max_inc, + on_activate = self:callback('onIncRange', 'goal_value', 2) }, { text = function() local cons = self.get_cb() or null_cons return string.format(': Max %-4d', cons.goal_value) @@ -200,9 +208,9 @@ end function RangeEditor:onIncRange(field, delta) local cons = self.get_cb() if not cons.goal_by_count then - delta = delta * 5 + delta = delta * 2 end - cons[field] = math.max(1, cons[field] + delta) + cons[field] = math.max(1, cons[field] + delta*5) self.save_cb(cons) end @@ -295,7 +303,7 @@ function NewConstraint:init(args) } }, widgets.Label{ - frame = { l = 0, t = 13 }, + frame = { l = 0, t = 14 }, text = { 'Desired range: ', { pen = COLOR_LIGHTCYAN, @@ -311,7 +319,7 @@ function NewConstraint:init(args) } }, RangeEditor{ - frame = { l = 1, t = 15 }, + frame = { l = 1, t = 16 }, get_cb = self:cb_getfield('constraint'), save_cb = self:callback('onRangeChange'), }, @@ -353,7 +361,7 @@ function NewConstraint:postinit() end function NewConstraint:isValid() - return self.constraint.item_type >= 0 + return self.constraint.item_type >= 0 or self.constraint.is_craft end function NewConstraint:onChange() @@ -455,6 +463,59 @@ function NewConstraint:onRangeChange() cons.goal_gap = math.max(1, math.min(cons.goal_gap, cons.goal_value-1)) end +------------------------------ +-- CONSTRAINT HISTORY GRAPH -- +------------------------------ + +HistoryGraph = defclass(HistoryGraph, widgets.Widget) + +HistoryGraph.ATTRS { + frame_inset = 1, + history_pen = COLOR_CYAN, +} + +function HistoryGraph:init(info) +end + +function HistoryGraph:setData(history, bars) + self.history = history or {} + self.bars = bars or {} + + local maxval = 1 + for i,v in ipairs(self.history) do + maxval = math.max(maxval, v) + end + for i,v in ipairs(self.bars) do + maxval = math.max(maxval, v.value) + end + self.max_value = maxval +end + +function HistoryGraph:onRenderFrame(dc,rect) + dc:fill(rect.x1,rect.y1,rect.x1,rect.y2,{ch='\xb3', fg=COLOR_BROWN}) + dc:fill(rect.x1,rect.y2,rect.x2,rect.y2,{ch='\xc4', fg=COLOR_BROWN}) + dc:seek(rect.x1,rect.y1):char('\x1e', COLOR_BROWN) + dc:seek(rect.x1,rect.y2):char('\xc5', COLOR_BROWN) + dc:seek(rect.x2,rect.y2):char('\x10', COLOR_BROWN) + dc:seek(rect.x1,rect.y2-1):char('0', COLOR_BROWN) +end + +function HistoryGraph:onRenderBody(dc) + local coeff = (dc.height-1)/self.max_value + + for i,v in ipairs(self.bars) do + local y = dc.height-1-math.floor(0.5 + coeff*v.value) + dc:fill(0,y,dc.width-1,y,v.pen or {ch='-', fg=COLOR_GREEN}) + end + + local xbase = dc.width-1-#self.history + for i,v in ipairs(self.history) do + local x = xbase + i + local y = dc.height-1-math.floor(0.5 + coeff*v) + dc:seek(x,y):char('*', self.history_pen) + end +end + ------------------------------ -- GLOBAL CONSTRAINT SCREEN -- ------------------------------ @@ -478,47 +539,7 @@ function ConstraintList:init(args) self:addviews{ widgets.Panel{ - frame = { w = 31, r = 0, h = 6, t = 0 }, - frame_inset = 1, - subviews = { - widgets.Label{ - frame = { l = 0, t = 0 }, - enabled = self:callback('isAnySelected'), - text = { - { text = function() - local cur = self:getCurConstraint() - if cur then - return string.format( - 'Currently %d (%d in use)', - current_stock(cur), - if_by_count(cur, cur.cur_in_use_count, cur.cur_in_use_amount) - ) - else - return 'No constraint selected' - end - end } - } - }, - RangeEditor{ - frame = { l = 0, t = 2 }, - enabled = self:callback('isAnySelected'), - get_cb = self:callback('getCurConstraint'), - save_cb = self:callback('saveConstraint'), - }, - } - }, - widgets.Widget{ - active = false, - frame = { w = 1, r = 31 }, - frame_background = gui.BOUNDARY_FRAME.frame_pen, - }, - widgets.Widget{ - active = false, - frame = { w = 31, r = 0, h = 1, t = 6 }, - frame_background = gui.BOUNDARY_FRAME.frame_pen, - }, - widgets.Panel{ - frame = { l = 0, r = 32 }, + frame = { l = 0, r = 31 }, frame_inset = 1, on_layout = function(body) self.fwidth = body.width - (12+1+1+7+1+1+1+7) @@ -541,6 +562,7 @@ function ConstraintList:init(args) edit_pen = COLOR_LIGHTCYAN, text_pen = { fg = COLOR_GREY, bg = COLOR_BLACK }, cursor_pen = { fg = COLOR_WHITE, bg = COLOR_GREEN }, + on_select = self:callback('onSelectConstraint'), }, widgets.Label{ frame = { b = 0, h = 1 }, @@ -557,27 +579,66 @@ function ConstraintList:init(args) else return COLOR_WHITE end - end }, ', ', - { key = 'CUSTOM_SHIFT_S', text = ': Search', - on_activate = function() - self.subviews.list.edit.active = not self.subviews.list.edit.active - end, - pen = function() - if self.subviews.list.edit.active then - return COLOR_LIGHTCYAN + end }, + } + } + } + }, + widgets.Panel{ + frame = { w = 30, r = 0, h = 6, t = 0 }, + frame_inset = 1, + subviews = { + widgets.Label{ + frame = { l = 0, t = 0 }, + enabled = self:callback('isAnySelected'), + text = { + { text = function() + local cur = self:getCurConstraint() + if cur then + return string.format( + 'Currently %d (%d in use)', + current_stock(cur), + if_by_count(cur, cur.cur_in_use_count, cur.cur_in_use_amount) + ) else - return COLOR_WHITE + return 'No constraint selected' end end } } - } + }, + RangeEditor{ + frame = { l = 0, t = 2 }, + enabled = self:callback('isAnySelected'), + get_cb = self:callback('getCurConstraint'), + save_cb = self:callback('saveConstraint'), + keys = { + count = 'CUSTOM_SHIFT_I', + modify = 'CUSTOM_SHIFT_R', + min_dec = 'SECONDSCROLL_PAGEUP', + min_inc = 'SECONDSCROLL_PAGEDOWN', + max_dec = 'SECONDSCROLL_UP', + max_inc = 'SECONDSCROLL_DOWN', + } + }, } }, + widgets.Widget{ + active = false, + frame = { w = 1, r = 30 }, + frame_background = gui.BOUNDARY_FRAME.frame_pen, + }, + widgets.Widget{ + active = false, + frame = { w = 30, r = 0, h = 1, t = 6 }, + frame_background = gui.BOUNDARY_FRAME.frame_pen, + }, + HistoryGraph{ + view_id = 'graph', + frame = { w = 30, r = 0, t = 7, b = 0 }, + } } - self.subviews.list.edit.active = false - - self:initListChoices() + self:initListChoices(nil, args.select_token) end function stock_trend_color(cons) @@ -733,6 +794,29 @@ function ConstraintList:onDeleteConstraint() ) end +function ConstraintList:onSelectConstraint(idx,item) + local history, bars + + if item then + local cons = item.obj + local vfield = if_by_count(cons, 'cur_count', 'cur_amount') + + bars = { + { value = cons.goal_value - cons.goal_gap, pen = {ch='-', fg=COLOR_GREEN} }, + { value = cons.goal_value, pen = {ch='-', fg=COLOR_LIGHTGREEN} }, + } + + history = {} + for i,v in ipairs(cons.history or {}) do + table.insert(history, v[vfield]) + end + + table.insert(history, cons[vfield]) + end + + self.subviews.graph:setData(history, bars) +end + ------------------------------- -- WORKSHOP JOB INFO OVERLAY -- ------------------------------- @@ -772,14 +856,20 @@ function JobConstraints:init(args) widgets.Label{ frame = { l = 0, b = 0 }, text = { - { key = 'CUSTOM_N', text = ': New limit, ', + { key = 'CUSTOM_SHIFT_A', text = ': Add limit, ', on_activate = self:callback('onNewConstraint') }, - { key = 'CUSTOM_X', text = ': Delete', + { key = 'CUSTOM_SHIFT_X', text = ': Delete', enabled = self:callback('isAnySelected'), on_activate = self:callback('onDeleteConstraint') }, NEWLINE, NEWLINE, { key = 'LEAVESCREEN', text = ': Back', - on_activate = self:callback('dismiss') } + on_activate = self:callback('dismiss') }, + ' ', + { key = 'CUSTOM_SHIFT_S', text = ': Status', + on_activate = function() + local sel = self:getCurConstraint() + ConstraintList{ select_token = (sel or {}).token }:show() + end } } }, } @@ -873,22 +963,16 @@ function JobConstraints:onNewConstraint() local choices = {} for i,cons in ipairs(variants) do local itemstr = describe_item_type(cons) - local matstr = describe_material(cons) - local matflags = utils.list_bitfield_flags(cons.mat_mask) - if #matflags > 0 then - local fstr = table.concat(matflags, '/') - if matstr == 'any material' then - matstr = 'any '..fstr - else - matstr = 'any '..fstr..' '..matstr - end + local matstr,matflags = describe_material(cons) + if matflags then + matstr = matflags..' '..matstr end table.insert(choices, { text = itemstr..' of '..matstr, obj = cons }) end dlg.ListBox{ - frame_title = 'New limit', + frame_title = 'Add limit', text = 'Select one of the possible outputs:', text_pen = COLOR_WHITE, choices = choices, @@ -930,7 +1014,7 @@ end local args = {...} -if args[1] == 'list' then +if args[1] == 'status' then check_enabled(function() ConstraintList{}:show() end) else if not string.match(dfhack.gui.getCurFocus(), '^dwarfmode/QueryBuilding/Some/Workshop/Job') then