3 classvar <w, <>docTitle = "History repeats", <>docHeight=120;
5 var <history, <w, <textV;
6 var <startBut, <filtBut, <filTextV, <filtBut, <keyPop, <topBut;
7 var <doc, <oldDocs, <docFlag = \sameDoc, <>stickMode=0;
9 var <filters, <filteredIndices, <filteredShorts, <filtering = false;
10 var lastLineSelected = 0, lastLinesShown;
12 *new { |history, where, numTextLines=12|
13 ^super.new.init(history, where ? (0@0), numTextLines);
16 init { |inHist, where, numTextLines=12|
18 var closebut, listV, font, flow;
19 bounds = where @ (where + (300@400));
21 font = Font.monospace(9); ////
22 w = Window("History", bounds).front; ////
23 flow = w.addFlowLayout(2@2, 1@1);
28 textV = TextView(w, Rect(0,0, 300 - 4, numTextLines * 12)).string_("")
29 .enterInterpretsSelection_(false)
30 .keyDownAction_({ |txvw, char, mod, uni, keycode|
32 if ([3, 13].includes(char.ascii)) {
33 this.rip(textV.string);
38 // to do: disable if history is not current!
39 startBut = Button(w, Rect(0, 0, 50, 20)) ////
40 .states_([ ["start"], ["end"]])
44 0, { if (history == History.current) { History.end } },
45 1, { if (history == History.current) { History.start } }
49 filtBut = Button(w, Rect(0, 0, 32, 20)) ////
51 .states_([["all"], ["filt"]]).action_({ |btn|
52 this.filtering_(btn.value > 0);
53 if (filtering) { this.filterLines };
54 history.hasMovedOn = true;
57 keyPop = PopUpMenu(w, Rect(0, 0, 40, 20))
58 .items_([\all] ++ history.keys).value_(0)
59 .action_({ |pop| this.setKeyFilter(pop.items[pop.value]) });
61 filTextV = TextView(w, Rect(0,0, 88, 20)).string_("")
62 .enterInterpretsSelection_(false)
64 .keyDownAction_({ |txvw, char, mod, uni, keycode|
65 this.setStrFilter(txvw.string);
66 if (this.filtering) { this.filterLines; }
68 topBut = Button(w, Rect(0, 0, 32, 20))
69 .states_([["top"], ["keep"]]).value_(0)
72 .action_({ |but| this.stickMode_(but.value) });
74 Button(w, Rect(0, 0, 32, 20)) ////
78 .action_({ |btn| this.rip(textV.string) });
80 Button(w, Rect(0,0, 16, 20))
81 .states_([["v"], ["^"]])
84 var views = w.view.children;
86 [2, 1, 1, 1, 2, 3, 3, 3, 5],
87 [5, 7, 7, 7, 8, 9, 9, 9, 8]
88 ][btn.value.asInteger];
90 views.do { |v, i| v.resize_(resizes[i]) };
94 listV = ListView(w, bounds.copy.insetBy(2).height_(230))
98 .background_(Color.grey(0.62))
100 var index = lview.value;
101 if (lview.items.isEmpty) {
102 "no entries yet.".postln;
104 lastLineSelected = listV.items[index];
106 this.postInlined(index)
108 this.postInlined(filteredIndices[index])
112 .enterKeyAction_({ |lview|
113 var index = lview.value;
114 if (filtering) { index = filteredIndices[index] };
116 history.lines[index][2].postln.interpret.postln;
117 // "did execute.".postln;
119 "execute line from history failed.".postln;
122 history.hasMovedOn = true;
125 var newIndex, selectedLine, linesToShow, keys;
126 var newStr = filTextV.string;
127 if (filTextV.hasFocus and: (newStr != filters[1])) {
128 this.setStrFilter(newStr);
129 }; // clumsy, but filTextV has no usable action...
131 if (history.hasMovedOn) {
132 startBut.enabled_(history.isCurrent);
133 startBut.value_(History.started.binaryValue).refresh;
135 filtBut.value_(filtering.binaryValue).refresh;
136 if (filTextV.hasFocus.not) { filTextV.string_(filters[1]) };
137 keys = [\all] ++ history.keys.asArray.sort;
139 keyPop.value_(keys.indexOf(filters[0]) ? 0);
140 if (stickMode == 1) {
141 // remember old selection
142 selectedLine = (lastLinesShown ? [])[listV.value];
145 linesToShow = if (filtering.not) {
146 history.lineShorts.array.copy
152 if (linesToShow != lastLinesShown) {
153 // "or updating listview here?".postln;
154 listV.items_(linesToShow);
155 lastLinesShown = linesToShow;
157 newIndex = if (selectedLine.isNil) { 0 }
158 { linesToShow.indexOf(selectedLine) };
159 listV.value_(newIndex ? 0);
160 if(stickMode == 0) { listV.action.value(listV) };
161 history.hasMovedOn = false;
163 }, 1, { w.isClosed }, "histwin");
165 setKeyFilter { |key| filters.put(0, key); this.filterLines; }
166 setStrFilter { |str| filters.put(1, str); this.filterLines; }
168 filtering_ { |flag=true|
170 history.hasMovedOn_(true);
172 filterOn { this.filtering_(true) }
173 filterOff { this.filtering_(false) }
176 filteredIndices = history.indicesFor(*filters);
177 filteredShorts = history.lineShorts[filteredIndices];
179 keyPop.value_(keyPop.items.indexOf(filters[0] ? 0));
180 filTextV.string_(filters[1]);
182 if (filtering) { history.hasMovedOn = true; };
184 postInlined { |index|
186 if (history.lines.isNil) { "no history lines yet.".postln; ^this };
187 line = history.lines[index];
188 if (line.isNil) { "history: no line found!".inform; ^this };
189 textV.string_(line[2]);
193 if (history.lines.isNil) { "no history lines yet.".postln; ^this };
194 line = history.lines[index];
195 if (line.isNil) { "history: no line found!".inform; ^this };
197 doc.string_(line[2]).front;
198 try { this.alignDoc };
202 var docbounds, winbounds;
203 docbounds = doc.bounds;
204 winbounds = w.bounds;
208 winbounds.top + winbounds.height + 24,
216 this.findDoc; doc.view.children.first.string_(textV.string); doc.front;
220 if (docFlag == \newDoc) { oldDocs = oldDocs.add(doc) };
221 if (docFlag == \newDoc or: doc.isNil or: { Window.allWindows.includes(doc).not }) {
222 doc = Window(docTitle, Rect(300, 500, 300, 100));
224 TextView(doc, doc.bounds.resizeBy(-8, -8)).resize_(5);
226 oldDocs = oldDocs.select {|d| d.notNil and: { d.dataptr.notNil } };