📄 htdialog.cc
字号:
/* * CLASS ht_listbox */class ht_listbox_vstate: public Object {public: void *e_top; void *e_cursor; ht_listbox_vstate(void *top, void *cursor) { e_top = top; e_cursor = cursor; }};void ht_listbox::init(Bounds *b, uint Listboxcaps){ ht_view::init(b, VO_SELECTABLE | VO_OWNBUFFER | VO_RESIZE, 0); cached_count = 0; growmode = MK_GM(GMH_FIT, GMV_FIT); Bounds c = *b; c.x = c.w-1; c.y = 0; c.w = 1; scrollbar = new ht_scrollbar(); scrollbar->init(&c, &pal, true); pos = 0; cursor = 0; e_top = getFirst(); e_cursor = e_top; title = NULL; visible_height = 0; x = 0; widths = NULL; clearQuickfind(); update(); listboxcaps = Listboxcaps; cols = 0;}void ht_listbox::done(){ scrollbar->done(); delete scrollbar; free(widths); ht_view::done();}void ht_listbox::adjustPosHack(){ if (e_cursor != e_top) return; int i=0; void *tmp = e_cursor; if (!tmp) return; while (tmp && i <= visible_height) { tmp = getNext(tmp); i++; } if (i < visible_height) { cursorDown(cursorUp(visible_height - pos - i)); }}void ht_listbox::adjustScrollbar(){ int pstart, psize; if (scrollbar_pos(pos-cursor, size.h, cached_count, &pstart, &psize)) { mScrollbarEnabled = true; scrollbar->enable(); Bounds c = size; c.x = c.w-1; c.y = 0; c.w = 1; scrollbar->setbounds(&c); scrollbar->setpos(pstart, psize); } else { mScrollbarEnabled = false; scrollbar->disable(); }}void ht_listbox::attachTitle(ht_listbox_title *aTitle){ if (numColumns() > cols) rearrangeColumns(); title = aTitle; title->listbox = this; title->update(); title->dirtyview();}void ht_listbox::clearQuickfind(){ quickfinder[0] = 0; qpos = quickfinder; updateCursor();}int ht_listbox::cursorAdjust(){ return 0;}int ht_listbox::cursorUp(int n){ void *tmp; int i = 0; while (n--) { tmp = getPrev(e_cursor); if (!tmp) break; if (e_cursor == e_top) { e_top = tmp; } else { cursor--; } e_cursor = tmp; pos--; if (pos < 0) pos = 0; // if cursor was out of sync i++; } return i;}int ht_listbox::cursorDown(int n){ void *tmp; int i = 0; while (n--) { tmp = getNext(e_cursor); if (!tmp) break; if (cursor+1 >= visible_height) { e_top = getNext(e_top); } else { cursor++; } pos++; e_cursor = tmp; i++; } return i;}int ht_listbox::datasize(){ return sizeof (ht_listbox_data);}const char *ht_listbox::defaultpalette(){ return palkey_generic_dialog_default;}void ht_listbox::draw(){ int fc = focused ? getcolor(palidx_generic_list_focused_unselected) : getcolor(palidx_generic_list_unfocused_unselected); int Cols = numColumns(); if (Cols > cols) rearrangeColumns(); bool title_redraw = false; bool resizing_cols; do { resizing_cols = false; clear(fc); void *entry = e_top; int i = 0; while (entry && i < visible_height) { int c = (i==cursor) ? (focused ? getcolor(palidx_generic_list_focused_selected) : getcolor(palidx_generic_list_unfocused_selected)) : fc; if (i == cursor) { fill(0, i, size.w, 1, c, ' '); } int X = -x; for (int j=0; j < cols; j++) { const char *s = getStr(j, entry); int slen = strlen(s); if (slen > widths[j]) { widths[j] = slen; /* * a column has been resized, * therefore we have to redraw a second time. */ resizing_cols = true; title_redraw = true; } if (s) { if (X >= 0) { buf->nprint(X, i, c, s, size.w); } else { if (slen > -X) buf->nprint(0, i, c, &s[-X], size.w); } } if (j==cols-1) { X += slen; } else { X += widths[j]; } if (j+1 < cols) { buf->printChar(X++, i, c, ' '); buf->printChar(X++, i, c, GC_1VLINE, CP_GRAPHICAL); buf->printChar(X++, i, c, ' '); } } if (x > 0) { // more text on the left buf->printChar(0, i, c, '<'); } // position of '>' char is scrollbar dependent int a = mScrollbarEnabled ? 0 : 1; if (X >= size.w+a) { // more text right buf->printChar(size.w-2+a, i, c, '>'); } entry = getNext(entry); i++; } } while (resizing_cols); updateCursor(); if (title_redraw && title) { title->update(); title->dirtyview(); }/* char dbg[100]; sprintf(dbg, "cursor=%d pos=%d vh=%d qc:%s", cursor, pos, visible_height, quickfinder); lprint(0, 0, 1, size.w, dbg); sprintf(dbg, "e_top=%s", getstr(0, e_top)); lprint(0, 1, 1, size.w, dbg); sprintf(dbg, "e_cursor=%s", getstr(0, e_cursor)); lprint(0, 2, 1, size.w, dbg);*/}int ht_listbox::estimateEntryPos(void *entry){ // this is slow! void *tmp = getFirst(); int res = 0; while (tmp) { if (tmp == entry) break; tmp = getNext(tmp); res++; } return (tmp==entry) ? res : -1;}void ht_listbox::getdata(ObjectStream &s){ ht_listbox_data_internal d; d.top_ptr = e_top; d.cursor_ptr = e_cursor; PUTX_BINARY(s, &d, sizeof d, NULL);}void ht_listbox::gotoItemByEntry(void *entry, bool clear_quickfind){ if (clear_quickfind) clearQuickfind(); if (!entry) return; void *tmp = e_top; int i=0; bool ok=false; pos -= cursor; if (pos<0) pos = 0; // if cursor was out of sync cursor = 0; while (tmp && i < visible_height) { if (tmp == entry) { ok = true; break; } pos++; cursor++; i++; tmp = getNext(tmp); } e_cursor = entry; if (!ok) { e_top = entry; cursor = 0; pos = estimateEntryPos(entry); assert(pos != -1); } adjustPosHack(); stateChanged();}void ht_listbox::gotoItemByPosition(uint pos){ void *entry = getFirst(); while (pos--) entry = getNext(entry); gotoItemByEntry(entry, true);}void ht_listbox::handlemsg(htmsg *msg){ switch (msg->msg) { case msg_vstate_restore: { ht_listbox_vstate *vs = (ht_listbox_vstate*)msg->data1.ptr; e_top = vs->e_top; e_cursor = vs->e_cursor; update(); // FIXME: what about deleting entries? clearmsg(msg); return; } case msg_keypressed: switch (msg->data1.integer) { case K_Control_PageUp: case K_Home: clearQuickfind(); pos = cursor = 0; e_top = e_cursor = getFirst(); dirtyview(); clearmsg(msg); stateChanged(); return; case K_Control_PageDown: case K_End: { clearQuickfind(); cursor = 0; pos = cached_count ? cached_count-1 : 0; e_cursor = e_top = getLast(); cursorUp(visible_height-1); cursorDown(visible_height-1); dirtyview(); clearmsg(msg); stateChanged(); return; } case K_PageUp: clearQuickfind(); cursorUp(visible_height-1); dirtyview(); clearmsg(msg); stateChanged(); return; case K_PageDown: { clearQuickfind(); cursorDown(visible_height-1); dirtyview(); clearmsg(msg); stateChanged(); return; } case K_Up: clearQuickfind(); cursorUp(1); dirtyview(); clearmsg(msg); stateChanged(); return; case K_Down: clearQuickfind(); cursorDown(1); dirtyview(); clearmsg(msg); stateChanged(); return; case K_Left: case K_Control_Left: if (x > 0) x--; updateCursor(); dirtyview(); clearmsg(msg); stateChanged(); return; case K_Right: case K_Control_Right: x++; updateCursor(); dirtyview(); clearmsg(msg); stateChanged(); return; case K_Tab: if (listboxcaps & LISTBOX_QUICKFIND) { if (*quickfinder) { char *qc = quickfindCompletition(quickfinder); if (qc) { strcpy(quickfinder, qc); qpos = ht_strend(quickfinder); free(qc); goto qf; } } } break; case K_Backspace: { if (listboxcaps & LISTBOX_QUICKFIND) { if (qpos > quickfinder) { *(--qpos) = 0; qf: void *a = quickfind(quickfinder); if (a) { gotoItemByEntry(a, false); updateCursor(); dirtyview(); } clearmsg(msg); stateChanged(); } } return; } default: { if ((listboxcaps & LISTBOX_QUICKFIND) && msg->data1.integer > 31 && msg->data1.integer < 0xff) { *qpos++ = msg->data1.integer; *qpos = 0; void *a = quickfind(quickfinder); if (a) { gotoItemByEntry(a, false); updateCursor(); dirtyview(); clearmsg(msg); stateChanged(); } else { *(--qpos) = 0; } } } } break; } ht_view::handlemsg(msg);}int ht_listbox::numColumns(){ return 1;}char *ht_listbox::quickfindCompletition(const char *s){ return ht_strdup(s);}void ht_listbox::rearrangeColumns(){ free(widths); cols = numColumns(); widths = (int*)calloc(cols*sizeof(int), 1);}void ht_listbox::redraw(){ ht_view::redraw(); scrollbar->relocate_to(this);// fprintf(stderr, "scrollbar: x=%d, y=%d, w=%d, h=%d\n", scrollbar->vsize.x, scrollbar->vsize.y, scrollbar->vsize.w, scrollbar->vsize.h); scrollbar->redraw(); if (title) { title->redraw(); } scrollbar->unrelocate_to(this);}void ht_listbox::resize(int rw, int rh){ ht_view::resize(rw, rh); update();}void ht_listbox::stateChanged(){ adjustScrollbar();}bool ht_listbox::selectEntry(void *entry){ return true;}void ht_listbox::setdata(ObjectStream &s){ ht_listbox_data_internal d; GET_BINARY(s, &d, sizeof d); e_top = d.top_ptr; e_cursor = d.cursor_ptr; update();}Object *ht_listbox::vstate_create(){ return new ht_listbox_vstate(e_top, e_cursor);}void ht_listbox::vstate_save(){ Object *vs = vstate_create(); if (vs) { htmsg m; m.msg = msg_vstate_save; m.type = mt_empty; m.data1.ptr = vs; m.data2.ptr = this; app->sendmsg(&m); }}/* * must be called if data has changed */void ht_listbox::update(){ void *entry = getFirst(); cached_count = calcCount(); visible_height = MIN(size.h, cached_count); if (cached_count <= size.h) { if (!e_cursor) e_cursor = getFirst(); cursor = 0; while (entry && cursor < visible_height) { if (entry == e_cursor) { e_top = getFirst(); goto ok; } entry = getNext(entry); cursor++; } } if (!e_top) { e_top = getFirst(); } if (!e_cursor) e_cursor = e_top; entry = e_top; cursor = 0; while (entry && cursor < visible_height) { if (entry == e_cursor) goto ok; entry = getNext(entry); cursor++; } cursor = 0; e_top = e_cursor;ok: adjustPosHack(); stateChanged(); if (title) { title->update(); title->dirtyview(); } dirtyview();}void ht_listbox::updateCursor(){ if (focused) { if (*quickfinder) { setcursor((qpos-quickfinder)+cursorAdjust()-x, cursor); } else { hidecursor(); } } }/* * ht_text_listbox */void ht_text_listbox::init(Bounds *b, int aCols, int aKeycol, uint aListboxcaps){ first = last = NULL; count = 0; ht_listbox::init(b, aListboxcaps); cols = aCols; keycol = aKeycol; Cursor_adjust = 0; rearrangeColumns();}void ht_text_listbox::done(){ clearAll(); ht_listbox::done();}void ht_text_listbox::clearAll(){ ht_text_listbox_item *temp = first; while (temp) { ht_text_listbox_item *temp2 = temp->next; freeExtraData(temp->extra_data); for (int i=0; i < cols; i++) { free(temp->data[i]); } free(temp); temp = temp2; } first = last = NULL; pos = 0; cursor = 0; e_top = getFirst(); e_cursor = e_top; x = 0; clearQuickfind(); count = 0; Cursor_adjust = 0;}int ht_text_listbox::calcCount(){ return count;}int ht_text_listbox::compare_strn(const char *s1, const char *s2, int l){ return ht_strncmp(s1, s2, l);}int ht_text_listbox::compare_ccomm(const char *s1, const char *s2){ return ht_strccomm(s1, s2);}int ht_text_listbox::cursorAdjust(){ return Cursor_adjust;}void ht_text_listbox::freeExtraData(void *extra_data){}void *ht_text_listbox::getFirst(){ return first;}uint ht_text_listbox::getID(void *entry){ if (entry) { return ((ht_text_listbox_item *)entry)->id; } else { return 0; } }void *ht_text_listbox::getExtra(void *entry){ if (entry) { return ((ht_text_listbox_item *)entry)->extra_data; } else { return NULL; } }void *ht_text_listbox::getLast(){ return last;}void *ht_text_listbox::getNext(void *entry){ if (!entry) return NULL; return ((ht_text_listbox_item *)entry)->next;}void *ht_text_listbox::getPrev(void *entry){ if (!entry) return NULL; return ((ht_text_listbox_item *)entry)->prev;}const char *ht_text_listbox::getStr(int col, void *entry){ if (entry && col < cols) { return ((ht_text_listbox_item *)entry)->data[col]; } else { return ""; }}void ht_text_listbox::insert_str_extra(int id, void *extra_data, const char **strs){ // FIXME: code duplication... ht_text_listbox_item *item = ht_malloc(sizeof(ht_text_listbox_item)+sizeof(char *)*cols); item->next = NULL; item->prev = last; item->id = id; item->extra_data = extra_data; for (int i=0; i<cols; i++) { int slen = strlen(strs[i]); if (slen > widths[i]) { widths[i] = slen; } item->data[i] = ht_strdup(strs[i]); } if (first) { last->next = item; } else { first = item; } last = item; count++;}void ht_text_listbox::insert_str_extra(int id, void *extra_data, const char *str, ...){ ht_text_listbox_item *item = ht_malloc(sizeof(ht_text_listbox_item)+sizeof(char *)*cols); item->next = NULL; item->prev = last; item->id = id; item->extra_data = extra_data; va_list str2; va_start(str2, str); const char *str3 = str; for (int i=0; i<cols; i++) { int slen = strlen(str3); if (slen > widths[i]) { widths[i] = slen; } item->data[i] = ht_strdup(str3); str3 = va_arg(str2, char *); } va_end(str2); if (first) { last->next = item; } else { first = item; } last = item; count++;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -