ui.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469
  1. #define Uses_TKeys
  2. #define Uses_TApplication
  3. #define Uses_TEvent
  4. #define Uses_TRect
  5. #define Uses_TDialog
  6. #define Uses_TStaticText
  7. #define Uses_TButton
  8. #define Uses_TMenuBar
  9. #define Uses_TSubMenu
  10. #define Uses_TMenuItem
  11. #define Uses_TStatusLine
  12. #define Uses_TStatusItem
  13. #define Uses_TStatusDef
  14. #define Uses_TScroller
  15. #define Uses_TDeskTop
  16. #define Uses_TCollection
  17. #define Uses_TScroller
  18. #define Uses_TWindow
  19. #define Uses_ipstream
  20. #define Uses_opstream
  21. #define Uses_TStreamableClass
  22. #define Uses_TFrame
  23. #include <memory>
  24. #include <tvision/tv.h>
  25. // Single Line Frame Characters
  26. const char BOX_SINGLE_HORIZONTAL = '\xC4'; // ─
  27. const char BOX_SINGLE_VERTICAL = '\xB3'; // │
  28. // Double Line Frame Characters
  29. const char BOX_DOUBLE_HORIZONTAL = '\xCD'; // ═
  30. const char BOX_DOUBLE_VERTICAL = '\xBA'; // ║
  31. // Junctions: Single Horizontal to Double Vertical
  32. const char BOX_SINGLE_HORIZONTAL_TO_DOUBLE_VERTICAL_TOP =
  33. '\xD1'; // ╤ (Approximation)
  34. const char BOX_SINGLE_HORIZONTAL_TO_DOUBLE_VERTICAL_BOTTOM =
  35. '\xCF'; // ╧ (Approximation)
  36. // Junctions: Double Horizontal to Single Vertical
  37. const char BOX_DOUBLE_HORIZONTAL_TO_SINGLE_VERTICAL_LEFT =
  38. '\xC3'; // ╟ (Approximation)
  39. const char BOX_DOUBLE_HORIZONTAL_TO_SINGLE_VERTICAL_RIGHT =
  40. '\xB4'; // ╢ (Approximation)
  41. // Cross junctions
  42. const char BOX_CROSS_SINGLE = '\xC5'; // ┼
  43. const char BOX_CROSS_DOUBLE =
  44. '\xCE'; // ╬ (No direct equivalent, used closest match)
  45. const char BOX_CROSS_SINGLE_TO_DOUBLE = '\xD8'; // ╪ (Approximation)
  46. const char BOX_CROSS_DOUBLE_TO_SINGLE = '\xD7'; // ╫ (Approximation)
  47. // Corners
  48. const char BOX_CORNER_TOP_LEFT_SINGLE = '\xDA'; // ┌
  49. const char BOX_CORNER_TOP_RIGHT_SINGLE = '\xBF'; // ┐
  50. const char BOX_CORNER_BOTTOM_LEFT_SINGLE = '\xC0'; // └
  51. const char BOX_CORNER_BOTTOM_RIGHT_SINGLE = '\xD9'; // ┘
  52. const char BOX_CORNER_TOP_LEFT_DOUBLE = '\xC9'; // ╔
  53. const char BOX_CORNER_TOP_RIGHT_DOUBLE = '\xBB'; // ╗
  54. const char BOX_CORNER_BOTTOM_LEFT_DOUBLE = '\xC8'; // ╚
  55. const char BOX_CORNER_BOTTOM_RIGHT_DOUBLE = '\xBC'; // ╝
  56. static char text[100] = "iniytial";
  57. class TItemCollection : public TCollection {
  58. public:
  59. TItemCollection(short lim, short delta) : TCollection(lim, delta) {}
  60. virtual void freeItem(void *p) { delete[] (char *)p; }
  61. private:
  62. virtual void *readItem(ipstream &) { return 0; }
  63. virtual void writeItem(void *, opstream &) {}
  64. };
  65. class TItemViewer : public TScroller {
  66. int selectedLine = 0;
  67. public:
  68. enum class ViewedColumn { Items, Categories, Weights };
  69. char *fileName;
  70. TCollection *fileLines;
  71. Boolean isValid;
  72. TItemViewer(const TRect &bounds, TScrollBar *aHScrollBar,
  73. TScrollBar *aVScrollBar, const ViewedColumn &col);
  74. ~TItemViewer();
  75. TItemViewer(StreamableInit) : TScroller(streamableInit){};
  76. void draw();
  77. void setState(ushort aState, Boolean enable);
  78. void scrollDraw();
  79. Boolean valid(ushort command) const;
  80. virtual void handleEvent(TEvent &event) override;
  81. int findSel(TPoint p);
  82. virtual TPalette &getPalette() const override;
  83. private:
  84. virtual const char *streamableName() const { return name; }
  85. protected:
  86. virtual void write(opstream &);
  87. virtual void *read(ipstream &);
  88. public:
  89. static const char *const name;
  90. static TStreamable *build();
  91. };
  92. #define cpTestView "\x6\x7\x2\x9"
  93. TPalette &TItemViewer::getPalette() const {
  94. static TPalette palette(cpTestView, sizeof(cpTestView) - 1);
  95. return palette;
  96. }
  97. class TItemWindow : public TWindow {
  98. TItemViewer *itemViewer, *catViewer, *weightViewer;
  99. const TRect itemViewerBounds() const {
  100. auto bounds = getExtent();
  101. TRect r(bounds.a.x, bounds.a.y, bounds.b.x / 3, bounds.b.y);
  102. r.grow(-1, -1);
  103. return r;
  104. }
  105. const TRect catViewerBounds() const {
  106. auto bounds = getExtent();
  107. TRect r(bounds.b.x / 3 - 2, bounds.a.y, 2 * bounds.b.x / 3 - 1, bounds.b.y);
  108. r.grow(-1, -1);
  109. return r;
  110. }
  111. const TRect weightViewerBounds() const {
  112. auto bounds = getExtent();
  113. TRect r(2 * bounds.b.x / 3 - 3, bounds.a.y, bounds.b.x, bounds.b.y);
  114. r.grow(-1, -1);
  115. return r;
  116. }
  117. public:
  118. TItemWindow(const char *fileName);
  119. static TFrame *initFrame(TRect r);
  120. void draw() override;
  121. virtual void handleEvent(TEvent &event) override;
  122. virtual TPalette &getPalette() const override;
  123. protected:
  124. virtual void sizeLimits(TPoint &min, TPoint &max) override {
  125. TWindow::sizeLimits(min, max);
  126. min.x = size.x / 2 + 10;
  127. };
  128. };
  129. #define cpItemWindow "\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x06"
  130. TPalette &TItemWindow::getPalette() const {
  131. static TPalette palette(cpItemWindow, sizeof(cpItemWindow) - 1);
  132. return palette;
  133. }
  134. const int maxLineLength = 256;
  135. const char *const TItemViewer::name = "TItemViewer";
  136. void TItemViewer::handleEvent(TEvent &event) {
  137. TScroller::handleEvent(event);
  138. switch (event.what) {
  139. case evKeyDown:
  140. switch (event.keyDown.keyCode) {
  141. case kbDown:
  142. if (selectedLine < fileLines->getCount() - 1) // -2 is header for now
  143. selectedLine++;
  144. clearEvent(event);
  145. break;
  146. case kbUp:
  147. if (selectedLine > 0)
  148. selectedLine--;
  149. clearEvent(event);
  150. break;
  151. }
  152. break;
  153. case evMouseDown:
  154. TPoint mouse = makeLocal(event.mouse.where);
  155. int i = findSel(mouse);
  156. if (i != -1)
  157. selectedLine = i;
  158. clearEvent(event);
  159. break;
  160. }
  161. sprintf(text, "%s: %d", fileName, selectedLine);
  162. TProgram::application->statusLine->update();
  163. draw();
  164. TProgram::application->statusLine->draw();
  165. }
  166. int TItemViewer::findSel(TPoint p) {
  167. TRect r = getExtent();
  168. if (!r.contains(p))
  169. return -1;
  170. else {
  171. int s = p.y - 2;
  172. if (s >= fileLines->getCount())
  173. return -1;
  174. else
  175. return s;
  176. }
  177. }
  178. TItemViewer::TItemViewer(const TRect &bounds, TScrollBar *aHScrollBar,
  179. TScrollBar *aVScrollBar, const ViewedColumn &col)
  180. : TScroller(bounds, aHScrollBar, aVScrollBar) {
  181. if (col == ViewedColumn::Categories)
  182. growMode = gfGrowHiX | gfGrowHiY;
  183. else
  184. growMode = gfGrowHiY;
  185. isValid = True;
  186. fileLines = new TItemCollection(5, 5);
  187. switch (col) {
  188. case ViewedColumn::Items:
  189. fileName = newStr("Items");
  190. break;
  191. case ViewedColumn::Categories:
  192. fileName = newStr("Categories");
  193. break;
  194. case ViewedColumn::Weights:
  195. fileName = newStr("Weights");
  196. break;
  197. }
  198. fileLines->insert(newStr("1"));
  199. fileLines->insert(newStr("2"));
  200. fileLines->insert(newStr("3"));
  201. fileLines->insert(newStr("4"));
  202. fileLines->insert(newStr("5"));
  203. fileLines->insert(newStr("6"));
  204. fileLines->insert(newStr("7"));
  205. }
  206. TItemViewer::~TItemViewer() { destroy(fileLines); }
  207. void TItemViewer::draw() {
  208. TDrawBuffer b;
  209. char *p;
  210. TAttrPair c = getColor(1);
  211. TAttrPair cFrame = getColor(3);
  212. TAttrPair cSelected = getColor(2);
  213. TAttrPair cHeader = getColor(4);
  214. // Header
  215. b.moveChar(0, ' ', c, size.x);
  216. b.moveChar(size.x - 1, BOX_SINGLE_VERTICAL, cFrame, 1);
  217. b.moveStr(0, fileName, getState(sfFocused) ? cHeader : c);
  218. writeBuf(0, 0, (short)size.x, 1, b);
  219. // Line
  220. b.moveChar(0, ' ', cFrame, size.x);
  221. char line[size.x] = {0};
  222. memset(line, BOX_SINGLE_HORIZONTAL, size.x - 1);
  223. b.moveStr(0, line, cFrame);
  224. b.moveChar(size.x - 1, BOX_CROSS_SINGLE, cFrame, 1);
  225. writeBuf(0, 1, (short)size.x, 1, b);
  226. for (short i = 0; i < size.y; i++) {
  227. b.moveChar(0, ' ', c, size.x);
  228. b.moveChar(size.x - 1, BOX_SINGLE_VERTICAL, c, 1);
  229. if (delta.y + i < fileLines->getCount()) {
  230. p = (char *)(fileLines->at(delta.y + i));
  231. if (p)
  232. b.moveStr(0, p, i == selectedLine ? cSelected : c);
  233. }
  234. writeBuf(0, i + 2, (short)size.x, 1, b);
  235. }
  236. }
  237. void TItemViewer::scrollDraw() {
  238. TScroller::scrollDraw();
  239. draw();
  240. }
  241. void TItemViewer::setState(ushort aState, Boolean enable) {
  242. TScroller::setState(aState, enable);
  243. if (enable && (aState & sfExposed))
  244. setLimit(limit.x, limit.y);
  245. }
  246. Boolean TItemViewer::valid(ushort) const { return isValid; }
  247. void *TItemViewer::read(ipstream &is) {
  248. char *fName = NULL;
  249. TScroller::read(is);
  250. delete fName;
  251. return this;
  252. }
  253. void TItemViewer::write(opstream &os) {
  254. TScroller::write(os);
  255. os.writeString(fileName);
  256. }
  257. TStreamable *TItemViewer::build() { return new TItemViewer(streamableInit); }
  258. TStreamableClass RItemView(TItemViewer::name, TItemViewer::build,
  259. __DELTA(TItemViewer));
  260. static short winNumber = 0;
  261. class TCustomFrame : public TFrame {
  262. public:
  263. using TFrame::TFrame; // Inherit constructor
  264. virtual void draw() override {
  265. TFrame::draw(); // Call base class draw
  266. TDrawBuffer b;
  267. TAttrPair cNormal = getColor(4);
  268. int fstSep = size.x / 3 - 2;
  269. int sndSep = 2 * size.x / 3 - 3;
  270. b.moveChar(0, ' ', cNormal, 1);
  271. b.putChar(0, BOX_SINGLE_HORIZONTAL_TO_DOUBLE_VERTICAL_TOP);
  272. writeLine(fstSep, 0, 1, 1, b);
  273. writeLine(sndSep, 0, 1, 1, b);
  274. }
  275. };
  276. TFrame *TItemWindow::initFrame(TRect r) { return new TCustomFrame(r); }
  277. TItemWindow::TItemWindow(const char *fileName)
  278. : TWindow(TProgram::deskTop->getExtent(), fileName, winNumber++),
  279. TWindowInit(&TItemWindow::initFrame) {
  280. options |= ofTileable;
  281. auto bounds = getExtent();
  282. itemViewer = new TItemViewer(
  283. itemViewerBounds(), standardScrollBar(sbHorizontal | sbHandleKeyboard),
  284. standardScrollBar(sbVertical | sbHandleKeyboard),
  285. TItemViewer::ViewedColumn::Items);
  286. insert(itemViewer);
  287. catViewer = new TItemViewer(
  288. catViewerBounds(), standardScrollBar(sbHorizontal | sbHandleKeyboard),
  289. standardScrollBar(sbVertical | sbHandleKeyboard),
  290. TItemViewer::ViewedColumn::Categories);
  291. insert(catViewer);
  292. weightViewer = new TItemViewer(
  293. weightViewerBounds(), standardScrollBar(sbHorizontal | sbHandleKeyboard),
  294. standardScrollBar(sbVertical | sbHandleKeyboard),
  295. TItemViewer::ViewedColumn::Weights);
  296. insert(weightViewer);
  297. }
  298. void TItemWindow::draw() {
  299. itemViewer->changeBounds(itemViewerBounds());
  300. catViewer->changeBounds(catViewerBounds());
  301. weightViewer->changeBounds(weightViewerBounds());
  302. TWindow::draw();
  303. }
  304. void TItemWindow::handleEvent(TEvent &event) { TWindow::handleEvent(event); }
  305. const int GreetThemCmd = 100;
  306. const int CallListCmd = 101;
  307. class THelloApp : public TApplication {
  308. public:
  309. THelloApp();
  310. virtual void handleEvent(TEvent &event);
  311. static TMenuBar *initMenuBar(TRect);
  312. static TStatusLine *initStatusLine(TRect);
  313. void set_hello(const std::string &new_line) { hello_line = new_line; }
  314. virtual void idle() override;
  315. private:
  316. std::string hello_line;
  317. void greetingBox();
  318. };
  319. THelloApp::THelloApp()
  320. : TProgInit(&THelloApp::initStatusLine, &THelloApp::initMenuBar,
  321. &THelloApp::initDeskTop) {}
  322. void THelloApp::greetingBox() {
  323. TDialog *d = new TDialog(TRect(25, 5, 55, 16), "Hello, World!");
  324. d->insert(new TStaticText(TRect(3, 5, 15, 6), hello_line.c_str()));
  325. d->insert(new TButton(TRect(16, 2, 28, 4), "Terrific", cmCancel, bfNormal));
  326. d->insert(new TButton(TRect(16, 4, 28, 6), "Ok", cmCancel, bfNormal));
  327. d->insert(new TButton(TRect(16, 6, 28, 8), "Lousy", cmCancel, bfNormal));
  328. d->insert(new TButton(TRect(16, 8, 28, 10), "Cancel", cmCancel, bfNormal));
  329. deskTop->execView(d);
  330. destroy(d);
  331. }
  332. void THelloApp::handleEvent(TEvent &event) {
  333. TApplication::handleEvent(event);
  334. if (event.what == evCommand) {
  335. switch (event.message.command) {
  336. case GreetThemCmd:
  337. greetingBox();
  338. clearEvent(event);
  339. break;
  340. case CallListCmd:
  341. if (TView *w = validView(new TItemWindow("test")))
  342. deskTop->insert(w);
  343. clearEvent(event);
  344. break;
  345. default:
  346. break;
  347. }
  348. }
  349. }
  350. TMenuBar *THelloApp::initMenuBar(TRect r) {
  351. r.b.y = r.a.y + 1;
  352. return new TMenuBar(
  353. r, *new TSubMenu("~F~ile", kbAltH) +
  354. *new TMenuItem("~G~reeting...", GreetThemCmd, kbAltG) +
  355. *new TMenuItem("~L~ist...", CallListCmd, kbAltL) + newLine() +
  356. *new TMenuItem("E~x~it", cmQuit, cmQuit, hcNoContext, "Alt-X"));
  357. }
  358. class HintStatusLine : public TStatusLine {
  359. public:
  360. HintStatusLine(TRect r, TStatusDef &def) : TStatusLine(r, def) {}
  361. virtual const char *hint(ushort) override;
  362. };
  363. const char *HintStatusLine::hint(ushort aHelpCtx) { return text; }
  364. TStatusLine *THelloApp::initStatusLine(TRect r) {
  365. r.a.y = r.b.y - 1;
  366. return new HintStatusLine(
  367. r, *new TStatusDef(0, 50) +
  368. *new TStatusItem("~F10~ Menu", kbF10, cmMenu) +
  369. *new TStatusItem("~Alt-X~ Exit", kbAltX, cmQuit) +
  370. *new TStatusDef(50, 0xFFFF) + *new TStatusItem(0, kbF10, cmMenu) +
  371. *new TStatusItem("~F1~ Help", kbF1, cmHelp));
  372. }
  373. void THelloApp::idle() {
  374. if (statusLine != 0)
  375. statusLine->update();
  376. if (commandSetChanged == True) {
  377. message(this, evBroadcast, cmCommandSetChanged, 0);
  378. commandSetChanged = False;
  379. }
  380. }
  381. #ifndef BINARY
  382. extern "C" int ui_main(char *hello_line) {
  383. #else
  384. int main() {
  385. const char *hello_line = "test line";
  386. #endif
  387. THelloApp helloWorld;
  388. helloWorld.set_hello(hello_line);
  389. helloWorld.run();
  390. return 0;
  391. }