Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

htdialog.cc

Go to the documentation of this file.
00001 /*
00002  *      HT Editor
00003  *      htdialog.cc
00004  *
00005  *      Copyright (C) 1999-2002 Stefan Weyergraf (stefan@weyergraf.de)
00006  *
00007  *      This program is free software; you can redistribute it and/or modify
00008  *      it under the terms of the GNU General Public License version 2 as
00009  *      published by the Free Software Foundation.
00010  *
00011  *      This program is distributed in the hope that it will be useful,
00012  *      but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  *      GNU General Public License for more details.
00015  *
00016  *      You should have received a copy of the GNU General Public License
00017  *      along with this program; if not, write to the Free Software
00018  *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00019  */
00020 
00021 #include <ctype.h>
00022 #include <stdlib.h>
00023 #include <string.h>
00024 
00025 #include "htclipboard.h"
00026 #include "htctrl.h"
00027 #include "htdialog.h"
00028 #include "hthist.h"
00029 #include "htidle.h"
00030 #include "htkeyb.h"
00031 #include "htpal.h"
00032 #include "htstring.h"
00033 #include "tools.h"
00034 
00035 /*
00036  *      CLASS ht_dialog
00037  */
00038 
00039 void ht_dialog::init(bounds *b, const char *desc, UINT framestyle)
00040 {
00041         ht_window::init(b, desc, framestyle);
00042         VIEW_DEBUG_NAME("ht_dialog");
00043         options&=~VO_SELBOUND;
00044         msgqueue=new ht_queue();
00045         msgqueue->init();
00046 }
00047 
00048 void ht_dialog::done()
00049 {
00050         msgqueue->done();
00051         delete msgqueue;
00052         ht_window::done();
00053 }
00054 
00055 int ht_dialog::alone()
00056 {
00057         return 1;
00058 }
00059 
00060 char *ht_dialog::defaultpalette()
00061 {
00062         return palkey_generic_dialog_default;
00063 }
00064 
00065 ht_queued_msg *ht_dialog::dequeuemsg()
00066 {
00067         return (ht_queued_msg*)msgqueue->dequeue();
00068 }
00069 
00070 void ht_dialog::draw()
00071 {
00072         clear(getcolor(palidx_generic_body));
00073         ht_group::draw();
00074 }
00075 
00076 int ht_dialog::getstate(int *_return_val)
00077 {
00078         if (_return_val) *_return_val=return_val;
00079         return state;
00080 }
00081 
00082 void ht_dialog::handlemsg(htmsg *msg)
00083 {
00084         if (msg->msg==msg_button_pressed) {
00085                 switch (msg->data1.integer) {
00086                         case button_cancel:
00087                                 setstate(ds_term_cancel, msg->data1.integer);
00088                                 clearmsg(msg);
00089                                 return;
00090                         default:
00091                                 setstate(ds_term_ok, msg->data1.integer);
00092                                 clearmsg(msg);
00093                                 return;
00094                 }
00095         }
00096         ht_window::handlemsg(msg);
00097         if (msg->msg==msg_keypressed) {
00098                 switch (msg->data1.integer) {
00099                         case K_Escape:
00100                                 setstate(ds_term_cancel, msg->data1.integer);
00101                                 clearmsg(msg);
00102                                 return;
00103                         case K_Return:
00104                                 sendmsg(msg_button_pressed, button_ok);
00105                                 clearmsg(msg);
00106                                 return;
00107                         case K_Control_O: {
00108 
00109                         }
00110                 }
00111         }
00112 }
00113 
00114 int ht_dialog::run(bool modal)
00115 {
00116         ht_view *orig_focused=app->getselected(), *orig_baseview=baseview;
00117         int oldx, oldy;
00118         ht_view *drawer=modal ? this : app;
00119         screen->getcursor(&oldx, &oldy);
00120         setstate(ds_normal, 0);
00121         ((ht_group*)app)->insert(this);
00122         ((ht_group*)app)->focus(this);
00123         baseview=this;
00124         drawer->sendmsg(msg_draw, 0);
00125         screen->show();
00126         while (getstate(0)==ds_normal) {
00127                 if (ht_keypressed()) {
00128                         ht_key k=ht_getkey();
00129                         sendmsg(msg_keypressed, k);
00130                         drawer->sendmsg(msg_draw, 0);
00131                         screen->show();
00132                 }
00133                 ht_queued_msg *q;
00134                 while ((q=dequeuemsg())) {
00135                         htmsg m=q->msg;
00136                         q->target->sendmsg(&m);
00137                         sendmsg(msg_draw);
00138                         delete q;
00139                 }
00140                 if (!modal) do_idle();
00141         }
00142         int return_val;
00143         int state=getstate(&return_val);
00144         screen->setcursor(oldx, oldy);
00145         ((ht_group*)app)->remove(this);
00146         app->focus(orig_focused);
00147         baseview=orig_baseview;
00148         if (state!=ds_term_cancel) {
00149                 return return_val;
00150         } else {
00151                 return 0;
00152         }
00153 }
00154 
00155 void ht_dialog::queuemsg(ht_view *target, htmsg *msg)
00156 {
00157         ht_queued_msg *q=new ht_queued_msg();
00158         q->target=target;
00159         q->msg=*msg;
00160         msgqueue->enqueue(q);
00161 }
00162 
00163 void ht_dialog::setstate(int st, int retval)
00164 {
00165         state = st;
00166         return_val = retval;
00167 }
00168 
00169 /*
00170  *      CLASS ht_cluster
00171  */
00172 
00173 void ht_cluster::init(bounds *b, ht_string_list *_strings)
00174 {
00175         ht_view::init(b, VO_SELECTABLE | VO_OWNBUFFER | VO_POSTPROCESS, 0);
00176         VIEW_DEBUG_NAME("ht_cluster");
00177         strings=_strings;
00178         scount=strings->count();
00179         if (scount>32) scount=32;                       /* cant use more than 32... */
00180         sel=0;
00181         for (int i=0; i<scount; i++) {
00182                 char *s=strings->get_string(i);
00183                 s=strchr(s, '~');
00184                 if (s) {
00185                         shortcuts[i]=ht_metakey((ht_key)*(s+1));
00186                 } else shortcuts[i]=K_INVALID;
00187         }
00188 }
00189 
00190 void ht_cluster::done()
00191 {
00192         strings->destroy();
00193         delete strings;
00194         ht_view::done();
00195 }
00196 
00197 char *ht_cluster::defaultpalette()
00198 {
00199         return palkey_generic_dialog_default;
00200 }
00201 
00202 /*
00203  *      CLASS ht_checkboxes
00204  */
00205 
00206 void ht_checkboxes::init(bounds *b, ht_string_list *strings)
00207 {
00208         ht_cluster::init(b, strings);
00209         VIEW_DEBUG_NAME("ht_checkboxes");
00210         state=0;
00211 }
00212 
00213 void ht_checkboxes::done()
00214 {
00215         ht_cluster::done();
00216 }
00217 
00218 int ht_checkboxes::datasize()
00219 {
00220         return sizeof (ht_checkboxes_data);
00221 }
00222 
00223 void ht_checkboxes::draw()
00224 {
00225         clear(getcolor(focused ? palidx_generic_cluster_focused
00226                 : palidx_generic_cluster_unfocused));
00227         int i=0;
00228         int vx=0, vy=0;
00229         int maxcolstrlen=0;
00230         while (i<scount) {
00231                 int c=getcolor(palidx_generic_cluster_unfocused);
00232                 if ((focused) && (sel==i)) c=getcolor(palidx_generic_cluster_focused);
00233                 char *s=strings->get_string(i);
00234                 int slen=strlen(s);
00235                 if (slen>maxcolstrlen) maxcolstrlen=slen;
00236                 if ((1<<i) & state) {
00237                         buf_print(vx, vy, c, "[X]");
00238                 } else {
00239                         buf_print(vx, vy, c, "[ ]");
00240                 }
00241                 int k=0, oc=c;
00242                 for (int q=0; q<size.w-4; q++) {
00243                         if (!*(s+q)) break;
00244                         if (*(s+q)=='~') {
00245                                 c=getcolor(palidx_generic_cluster_shortcut);
00246                                 continue;
00247                         } else {
00248                                 buf_printchar(vx+k+4, vy, c, *(s+q));
00249                                 k++;
00250                         }
00251                         c=oc;
00252                 }
00253                 i++;
00254                 vy++;
00255                 if (vy>=size.h) {
00256                         vx+=maxcolstrlen+5;
00257                         vy=0;
00258                         maxcolstrlen=0;
00259                 }
00260         }
00261 }
00262 
00263 void ht_checkboxes::getdata(ht_object_stream *s)
00264 {
00265         s->putIntDec(state, 4, NULL);
00266 }
00267 
00268 void ht_checkboxes::handlemsg(htmsg *msg)
00269 {
00270         if (msg->type==mt_postprocess) {
00271                 if (msg->msg==msg_keypressed) {
00272                         for (int i=0; i<scount; i++) {
00273                                 if ((shortcuts[i]!=-1) && (msg->data1.integer==shortcuts[i])) {
00274                                         sel=i;
00275                                         state=state^(1<<sel);
00276                                         app->focus(this);
00277                                         dirtyview();
00278                                         clearmsg(msg);
00279                                         return;
00280                                 }
00281                         }
00282                 }
00283         } else {
00284                 if (msg->msg==msg_keypressed) {
00285                         switch (msg->data1.integer) {
00286                                 case K_Left:
00287                                         sel-=size.h;
00288                                         if (sel<0) sel=0;
00289                                         dirtyview();
00290                                         clearmsg(msg);
00291                                         return;
00292                                 case K_Right:
00293                                         sel+=size.h;
00294                                         if (sel>=scount) sel=scount-1;
00295                                         dirtyview();
00296                                         clearmsg(msg);
00297                                         return;
00298                                 case K_Up:
00299                                         sel--;
00300                                         if (sel<0) sel=0;
00301                                         dirtyview();
00302                                         clearmsg(msg);
00303                                         return;
00304                                 case K_Down:
00305                                         sel++;
00306                                         if (sel>=scount) sel=scount-1;
00307                                         dirtyview();
00308                                         clearmsg(msg);
00309                                         return;
00310                                 case K_Space:
00311                                         state=state^(1<<sel);
00312                                         dirtyview();
00313                                         clearmsg(msg);
00314                                         return;
00315                         }
00316                 }
00317         }
00318         ht_cluster::handlemsg(msg);
00319 }
00320 
00321 void ht_checkboxes::setdata(ht_object_stream *s)
00322 {
00323         state=s->getIntDec(4, NULL);
00324         dirtyview();
00325 }
00326 
00327 /*
00328  *      CLASS ht_radioboxes
00329  */
00330 
00331 void ht_radioboxes::init(bounds *b, ht_string_list *strings)
00332 {
00333         ht_cluster::init(b, strings);
00334         VIEW_DEBUG_NAME("ht_radioboxes");
00335 }
00336 
00337 void ht_radioboxes::done()
00338 {
00339         ht_cluster::done();
00340 }
00341 
00342 int ht_radioboxes::datasize()
00343 {
00344         return sizeof (ht_radioboxes_data);
00345 }
00346 
00347 void ht_radioboxes::draw()
00348 {
00349         clear(getcolor(focused ? palidx_generic_cluster_focused
00350                 : palidx_generic_cluster_unfocused));
00351         int i=0;
00352         int vx=0, vy=0;
00353         int maxcolstrlen=0;
00354         while (i<scount) {
00355                 int c=getcolor(palidx_generic_cluster_unfocused);
00356                 if ((focused) && (sel==i)) c=getcolor(palidx_generic_cluster_focused);
00357                 char *s=strings->get_string(i);
00358                 int slen=strlen(s);
00359                 if (slen>maxcolstrlen) maxcolstrlen=slen;
00360                 buf_print(vx, vy, c, "( )");
00361                 if (i==sel) {
00362                         buf_printchar(vx+1, vy, c, CHAR_RADIO);
00363                 }
00364                 buf_print(vx+4, vy, c, s);
00365                 i++;
00366                 vy++;
00367                 if (vy>=size.h) {
00368                         vx+=maxcolstrlen+5;
00369                         vy=0;
00370                         maxcolstrlen=0;
00371                 }
00372         }
00373 }
00374 
00375 void ht_radioboxes::getdata(ht_object_stream *s)
00376 {
00377         s->putIntDec(sel, 4, NULL);
00378 }
00379 
00380 void ht_radioboxes::handlemsg(htmsg *msg)
00381 {
00382         if (msg->msg==msg_keypressed) {
00383                 switch (msg->data1.integer) {
00384                         case K_Left:
00385                                 sel-=size.h;
00386                                 if (sel<0) sel=0;
00387                                 dirtyview();
00388                                 clearmsg(msg);
00389                                 return;
00390                         case K_Right:
00391                                 sel+=size.h;
00392                                 if (sel>=scount) sel=scount-1;
00393                                 dirtyview();
00394                                 clearmsg(msg);
00395                                 return;
00396                         case K_Up:
00397                                 sel--;
00398                                 if (sel<0) sel=0;
00399                                 dirtyview();
00400                                 clearmsg(msg);
00401                                 return;
00402                         case K_Down:
00403                                 sel++;
00404                                 if (sel>=scount) sel=scount-1;
00405                                 dirtyview();
00406                                 clearmsg(msg);
00407                                 return;
00408 /*                      case K_Space:
00409                                 state=state^(1<<sel);
00410                                 dirtyview();
00411                                 clearmsg(msg);
00412                                 break;*/
00413                 }
00414         }
00415         ht_cluster::handlemsg(msg);
00416 }
00417 
00418 void ht_radioboxes::setdata(ht_object_stream *s)
00419 {
00420         sel=s->getIntDec(4, NULL);
00421 }
00422 
00423 
00424 /*
00425  *      CLASS ht_history_listbox
00426  */
00427 void ht_history_listbox::init(bounds *b, ht_list *hist)
00428 {
00429         history = hist;
00430         ht_listbox::init(b);
00431 }
00432 
00433 int  ht_history_listbox::calcCount()
00434 {
00435         return history->count();
00436 }
00437 
00438 void *ht_history_listbox::getFirst()
00439 {
00440         if (history->count()) {
00441                 return (void*)1;
00442         } else {
00443                 return NULL;
00444         }
00445 }
00446 
00447 void *ht_history_listbox::getLast()
00448 {
00449         if (history->count()) {
00450                 return (void*)(history->count());
00451         } else {
00452                 return NULL;
00453         }
00454 }
00455 
00456 void *ht_history_listbox::getNext(void *entry)
00457 {
00458         UINT e=(UINT)entry;
00459         if (!e) return NULL;
00460         if (e < history->count()) {
00461                 return (void*)(e+1);
00462         } else {
00463                 return NULL;
00464         }
00465 }
00466 
00467 void *ht_history_listbox::getPrev(void *entry)
00468 {
00469         UINT e=(UINT)entry;
00470         if (e > 1) {
00471                 return (void*)(e-1);
00472         } else {
00473                 return NULL;
00474         }
00475 }
00476 
00477 char *ht_history_listbox::getStr(int col, void *entry)
00478 {
00479         return ((ht_history_entry*)history->get((int)entry-1))->desc;
00480 }
00481 
00482 void ht_history_listbox::handlemsg(htmsg *msg)
00483 {
00484         switch (msg->msg) {
00485                 case msg_keypressed:
00486                         switch (msg->data1.integer) {
00487                                 case K_Delete: {
00488                                         int p = pos;
00489                                         cursorUp(1);
00490                                         history->del(p);
00491                                         update();
00492                                         if (p) cursorDown(1);
00493                                         dirtyview();
00494                                         clearmsg(msg);
00495                                         break;
00496                                 }
00497                         }
00498                 break;
00499         }
00500         ht_listbox::handlemsg(msg);
00501 }
00502 
00503 void *ht_history_listbox::quickfind(char *s)
00504 {
00505         void *item = getFirst();
00506         int slen = strlen(s);
00507         while (item && (ht_strncmp(getStr(0, item), s, slen)!=0)) {
00508                 item = getNext(item);
00509         }
00510         return item;
00511 }
00512 
00513 char    *ht_history_listbox::quickfindCompletition(char *s)
00514 {
00515         void *item = getFirst();
00516         char *res = NULL;
00517         int slen = strlen(s);
00518         while (item) {
00519                 if (ht_strncmp(getStr(0, item), s, slen)==0) {
00520                         if (!res) {
00521                                 res = ht_strdup(getStr(0, item));
00522                         } else {
00523                                 int a = strccomm(res, getStr(0, item));
00524                                 res[a] = 0;
00525                         }
00526                 }
00527                 item = getNext(item);
00528         }
00529         return res;
00530 }
00531 
00532 
00533 /*
00534  *      CLASS ht_history_popup_dialog
00535  */
00536 
00537 void ht_history_popup_dialog::init(bounds *b, ht_list *hist)
00538 {
00539         history = hist;
00540         ht_listpopup_dialog::init(b, "history");
00541 }
00542 
00543 void ht_history_popup_dialog::getdata(ht_object_stream *s)
00544 {
00545         // FIXME: public member needed:
00546         s->putIntDec(listbox->pos, 4, NULL);
00547         if (history->count()) {
00548                 s->putString(((ht_history_entry*)history->get(listbox->pos))->desc, NULL);
00549         } else {
00550                 s->putString(NULL, NULL);
00551         }
00552 }
00553 
00554 void ht_history_popup_dialog::init_text_listbox(bounds *b)
00555 {
00556         listbox=new ht_history_listbox();
00557         ((ht_history_listbox *)listbox)->init(b, history);
00558         insert(listbox);
00559 }
00560 
00561 void ht_history_popup_dialog::setdata(ht_object_stream *s)
00562 {
00563 }
00564 
00565 /*
00566  *      CLASS ht_inputfield
00567  */
00568 
00569 void ht_inputfield::init(bounds *b, int Maxtextlen, ht_list *hist)
00570 {
00571         ht_view::init(b, VO_SELECTABLE, "some inputfield");
00572         VIEW_DEBUG_NAME("ht_inputfield");
00573         
00574         history=hist;
00575         maxtextlenv=Maxtextlen;
00576         
00577         textv=(byte*)malloc(maxtextlenv+1);
00578         curcharv=textv;
00579         textlenv=0;
00580         selstartv=0;
00581         selendv=0;
00582 
00583         text=&textv;
00584         curchar=&curcharv;
00585         textlen=&textlenv;
00586         maxtextlen=&maxtextlenv;
00587         selstart=&selstartv;
00588         selend=&selendv;
00589 
00590         insert=1;
00591         ofs=0;
00592         attachedto=0;
00593 }
00594 
00595 void ht_inputfield::done()
00596 {
00597         freebuf();
00598         ht_view::done();
00599 }
00600 
00601 void ht_inputfield::attach(ht_inputfield *inputfield)
00602 {
00603         freebuf();
00604         inputfield->query(&curchar, &text, &selstart, &selend, &textlen, &maxtextlen);
00605         attachedto=inputfield;
00606         ofs=0;
00607         insert=1;
00608 }
00609 
00610 int ht_inputfield::datasize()
00611 {
00612         return sizeof (ht_inputfield_data);
00613 }
00614 
00615 char *ht_inputfield::defaultpalette()
00616 {
00617         return palkey_generic_dialog_default;
00618 }
00619 
00620 void ht_inputfield::freebuf()
00621 {
00622         if (!attachedto && (text) && (*text)) free(*text);
00623 }
00624 
00625 void ht_inputfield::getdata(ht_object_stream *s)
00626 {
00627         UINT h=s->recordStart(datasize());
00628         if (!attachedto) {
00629                 s->putIntDec(*textlen, 4, NULL);
00630                 s->putBinary(*text, *textlen, NULL);
00631         }
00632         s->recordEnd(h);
00633 }
00634 
00635 int ht_inputfield::insertbyte(byte *pos, byte b)
00636 {
00637         if (*textlen<*maxtextlen) {
00638                 if (*selstart) {
00639                         if (pos<*selstart) {
00640                                 (*selstart)++;
00641                                 (*selend)++;
00642                         } else if (pos<*selend) {
00643                                 (*selend)++;
00644                         }
00645                 }
00646                 memmove(pos+1, pos, *textlen-(pos-*text));
00647                 *pos=b;
00648                 (*textlen)++;
00649                 dirtyview();
00650                 return 1;
00651         }
00652         return 0;
00653 }
00654 
00655 void ht_inputfield::isetcursor(UINT pos)
00656 {
00657         if (pos<(UINT)*textlen) *curchar=*text+pos;
00658 }
00659 
00660 void ht_inputfield::query(byte ***c, byte ***t, byte ***ss, byte ***se, int **tl, int **mtl)
00661 {
00662         *c=curchar;
00663         *t=text;
00664         *ss=selstart;
00665         *se=selend;
00666         *tl=textlen;
00667         *mtl=maxtextlen;
00668 }
00669 
00670 void ht_inputfield::select_add(byte *start, byte *end)
00671 {
00672         if (end<start) {
00673                 byte *temp=start;
00674                 start=end;
00675                 end=temp;
00676         }
00677         if (end==*selstart) {
00678                 *selstart=start;
00679         } else if (start==*selend) {
00680                 *selend=end;
00681         } else if (start==*selstart) {
00682                 *selstart=end;
00683         } else if (end==*selend) {
00684                 *selend=start;
00685         } else {
00686                 *selstart=start;
00687                 *selend=end;
00688         }
00689         if (*selstart>*selend) {
00690                 byte *temp=*selstart;
00691                 *selstart=*selend;
00692                 *selend=temp;
00693         }
00694 }
00695 
00696 void ht_inputfield::setdata(ht_object_stream *s)
00697 {
00698         UINT h=s->recordStart(datasize());
00699         if (!attachedto) {
00700                 textlen=&textlenv;
00701                 *textlen=s->getIntDec(4, NULL);
00702                 
00703                 if (*textlen>*maxtextlen) *textlen=*maxtextlen;
00704                 
00705                 s->getBinary(*text, *textlen, NULL);
00706                 
00707                 curchar=&curcharv;
00708                 *curchar=*text+*textlen;
00709                 
00710                 if (*textlen) {
00711                         *selstart=*text;
00712                         *selend=*text+*textlen;
00713                 } else {
00714                         *selstart=0;
00715                         *selend=0;
00716                 }
00717 
00718                 ofs=0;
00719         }
00720         
00721         s->recordEnd(h);
00722         dirtyview();
00723 }
00724 
00725 /*
00726  *      CLASS ht_strinputfield
00727  */
00728 
00729 void ht_strinputfield::init(bounds *b, int maxstrlen, ht_list *history)
00730 {
00731         ht_inputfield::init(b, maxstrlen, history);
00732         VIEW_DEBUG_NAME("ht_strinputfield");
00733         is_virgin = true;
00734         selectmode = false;
00735 }
00736 
00737 void ht_strinputfield::done()
00738 {
00739         ht_inputfield::done();
00740 }
00741 
00742 void ht_strinputfield::correct_viewpoint()
00743 {
00744         if (*curchar-*text<ofs) ofs=*curchar-*text; else
00745         if (*curchar-*text-(size.w-2)*size.h+1>ofs) ofs=*curchar-*text-(size.w-2)*size.h+1;
00746 }
00747 
00748 void ht_strinputfield::draw()
00749 {
00750         int c=focused ? getcolor(palidx_generic_input_focused) :
00751                 getcolor(palidx_generic_input_unfocused);
00752         byte *t=*text+ofs;
00753         int l=*textlen-ofs;
00754         if (l>size.w) l=size.w;
00755         int y=0;
00756         fill(0, 0, size.w, size.h, c, ' ');
00757         if (ofs) buf_printchar(0, y, getcolor(palidx_generic_input_clip), '<');
00758         for (int k=0; k<*textlen-ofs; k++) {
00759                 if (1+k-y*(size.w-2)>size.w-2) {
00760                         if (y+1<size.h) y++; else break;
00761                 }
00762                 if ((t<*selstart) || (t>=*selend)) {
00763                         buf_printchar(1+k-y*(size.w-2), y, c, *(t++));
00764                 } else {
00765                         buf_printchar(1+k-y*(size.w-2), y, getcolor(palidx_generic_input_selected), *(t++));
00766                 }
00767         }
00768         if (*textlen-ofs > (size.w-2)*size.h) {
00769                 buf_printchar(size.w-1, y, getcolor(palidx_generic_input_clip), '>');
00770         }
00771         if (history && history->count()) {
00772                 buf_printchar(size.w-1, y+size.h-1, getcolor(palidx_generic_input_clip), CHAR_ARROW_DOWN);
00773         }
00774         if (focused) {
00775                 int cx, cy;
00776                 if (*curchar-*text-ofs>=(size.w-2)*size.h) {
00777                         cx = size.w-1;
00778                         cy = size.h-1;
00779                 } else {
00780                         cx = (*curchar-*text-ofs)%(size.w-2)+1;
00781                         cy = (*curchar-*text-ofs)/(size.w-2);
00782                 }
00783                 setcursor(cx, cy, insert ? cm_normal : cm_overwrite);
00784         }
00785 }
00786 
00787 void ht_strinputfield::handlemsg(htmsg *msg)
00788 {
00789         if ((msg->type==mt_empty) && (msg->msg==msg_keypressed)) {
00790                 int k = msg->data1.integer;
00791                 switch (k) {
00792                         case K_Alt_S:
00793                                 selectmode=!selectmode;
00794                                 clearmsg(msg);
00795                                 break;
00796                         case K_Up:
00797                                 is_virgin=0;
00798                                 if (*curchar-*text-ofs<size.w-2) {
00799                                         ofs-=size.w-2;
00800                                         if (ofs<0) ofs=0;
00801                                 }
00802                                 *curchar-=size.w-2;
00803                                 if (*curchar<*text) *curchar=*text;
00804                                 correct_viewpoint();
00805                                 dirtyview();
00806                                 clearmsg(msg);
00807                                 return;
00808                         case K_Down:
00809                                 is_virgin=0;
00810                                 if (*curchar+size.w-2-*text>*textlen) {
00811                                         history_dialog();
00812                                         clearmsg(msg);
00813                                         return;
00814                                 } else {
00815                                         *curchar+=size.w-2;
00816                                         if (*curchar-*text>*textlen) *curchar=*text+*textlen;
00817                                         correct_viewpoint();
00818                                         dirtyview();
00819                                 }
00820                                 clearmsg(msg);
00821                                 return;
00822                         case K_Shift_Left:
00823                         case K_Left:
00824                                 is_virgin=0;
00825                                 if (*curchar>*text) {
00826                                         (*curchar)--;
00827                                         if ((k==K_Shift_Left) != selectmode) {
00828                                                 select_add(*curchar, *curchar+1);
00829                                         }
00830                                 }                                   
00831                                 correct_viewpoint();
00832                                 dirtyview();
00833                                 clearmsg(msg);
00834                                 return;
00835                         case K_Shift_Right:                             
00836                         case K_Right:
00837                                 is_virgin=0;
00838                                 if (*curchar-*text<*textlen) {
00839                                         (*curchar)++;
00840                                         if ((k==K_Shift_Right) != selectmode) {
00841                                                 select_add(*curchar-1, *curchar);
00842                                         }
00843                                 }                                       
00844                                 correct_viewpoint();
00845                                 dirtyview();
00846                                 clearmsg(msg);
00847                                 return;
00848                         case K_Backspace:
00849                                 if (is_virgin) {
00850                                         is_virgin=0;
00851                                         *selstart=0;
00852                                         *selend=0;
00853                                         *textlen=0;
00854                                         *curchar=*text;
00855                                         dirtyview();
00856                                         clearmsg(msg);
00857                                 } else if (*curchar>*text) {
00858                                         *selstart=0;
00859                                         *selend=0;
00860                                         memmove(*curchar-1, *curchar, *textlen-(*curchar-*text));
00861                                         (*textlen)--;
00862                                         (*curchar)--;
00863                                         is_virgin=0;
00864                                         correct_viewpoint();
00865                                         dirtyview();
00866                                         clearmsg(msg);
00867                                         return;
00868                                 }
00869                                 break;
00870                         case K_Delete:
00871                                 if (is_virgin) {
00872                                         is_virgin=0;
00873                                         *selstart=0;
00874                                         *selend=0;
00875                                         *textlen=0;
00876                                         *curchar=*text;
00877                                         dirtyview();
00878                                         clearmsg(msg);
00879                                 } else if ((*curchar-*text<*textlen) && (*textlen)) {
00880                                         if (*selstart) {
00881                                                 if (*curchar>=*selstart) {
00882                                                         if (*curchar<*selend) (*selend)--;
00883                                                         if (*selstart==*selend) {
00884                                                                 *selstart=0;
00885                                                                 *selend=0;
00886                                                         }
00887                                                 } else {
00888                                                         (*selstart)--;
00889                                                         (*selend)--;
00890                                                 }
00891                                         }
00892                                         memmove(*curchar, *curchar+1, *textlen-(*curchar-*text)-1);
00893                                         (*textlen)--;
00894                                         dirtyview();
00895                                         clearmsg(msg);
00896                                         return;
00897                                 }
00898                                 break;
00899                         case K_Shift_Home:
00900                         case K_Home:
00901                                 is_virgin=0;
00902                                 if ((k==K_Shift_Home) != selectmode) {
00903                                         select_add(*curchar, *text);
00904                                 }                                       
00905                                 *curchar=*text;
00906                                 correct_viewpoint();
00907                                 dirtyview();
00908                                 clearmsg(msg);
00909                                 return;
00910                         case K_Shift_End:
00911                         case K_End:
00912                                 is_virgin=0;
00913                                 if ((k==K_Shift_End) != selectmode) {
00914                                         select_add(*curchar, *text+*textlen);
00915                                 }                                               
00916                                 *curchar=*text+*textlen;
00917                                 correct_viewpoint();
00918                                 dirtyview();
00919                                 clearmsg(msg);
00920                                 return;
00921                         case K_Insert:
00922                                 insert=!insert;
00923                                 dirtyview();
00924                                 clearmsg(msg);
00925                                 return;
00926                         case K_Alt_X:
00927                         case K_Shift_Delete:
00928                                 if (*selend>*selstart) clipboard_copy("inputfield", *selstart, *selend-*selstart);
00929                         case K_Alt_D:
00930                         case K_Control_Delete:
00931                                 if (*selend>*selstart) {
00932                                         memmove(*selstart, *selend, *textlen-(*selend-*text));
00933                                         *textlen-=*selend-*selstart;
00934                                         *curchar=*selstart;
00935                                         *selstart=0;
00936                                         *selend=0;
00937                                         is_virgin=0;
00938                                         correct_viewpoint();
00939                                 }
00940                                 dirtyview();
00941                                 clearmsg(msg);
00942                                 return;
00943                         case K_Alt_C:
00944                         case K_Control_Insert:
00945                                 if (*selend>*selstart) clipboard_copy("inputfield", *selstart, *selend-*selstart);
00946                                 is_virgin=0;
00947                                 dirtyview();
00948                                 clearmsg(msg);
00949                                 return;
00950                         case K_Alt_V:
00951                         case K_Shift_Insert: {
00952                                 int maxsize=MIN(*maxtextlen-*textlen, (int)clipboard_getsize());
00953                                 byte *buf=(byte*)malloc(maxsize);
00954                                 int r=clipboard_paste(buf, maxsize);
00955                                 if (r) {
00956                                         for (int i=0; i<r; i++) {
00957                                                 setbyte(buf[r-i-1]);
00958                                         }
00959                                         *selstart=*curchar;
00960                                         *selend=*curchar+r;
00961                                 }
00962                                 delete buf;
00963                                 is_virgin=0;
00964                                 dirtyview();
00965                                 clearmsg(msg);
00966                                 return;
00967                         }
00968                         default:
00969                                 if ((msg->data1.integer>=' ') && (msg->data1.integer<256)) {
00970                                         if (is_virgin) {
00971                                                 is_virgin=0;
00972                                                 *selstart=0;
00973                                                 *selend=0;
00974                                                 *textlen=0;
00975                                                 *curchar=*text;
00976                                                 ofs=0;
00977                                         }
00978                                         inputbyte(msg->data1.integer);
00979                                         dirtyview();
00980                                         clearmsg(msg);
00981                                         return;
00982                                 }
00983                 }
00984         }
00985         ht_inputfield::handlemsg(msg);
00986 }
00987 
00988 void ht_strinputfield::history_dialog()
00989 {
00990         if (history && history->count()) {
00991                 bounds b;
00992                 getbounds(&b);
00993                 b.y--;
00994                 b.h=8;
00995                 ht_history_popup_dialog *l=new ht_history_popup_dialog();
00996                 l->init(&b, history);
00997                 if (l->run(false)) {
00998                         ht_listpopup_dialog_data d;
00999                         l->databuf_get(&d, sizeof d);
01000 
01001                         if (d.cursor_string) {
01002                                 ht_history_entry *v=(ht_history_entry*)history->get(d.cursor_pos);
01003                                 if ((v->data) && (group)) {
01004                                         v->datafile->seek(0);
01005                                         group->setdata(v->data);
01006                                 } else {
01007                                         ht_inputfield_data e;
01008                                         e.textlen=strlen(d.cursor_string);
01009                                         e.text=(byte*)d.cursor_string;
01010                                         databuf_set(&e, sizeof e);
01011                                 }
01012                         }
01013                         is_virgin=0;
01014                 }
01015                 l->done();
01016                 delete l;
01017         }
01018 }
01019 
01020 void ht_strinputfield::receivefocus()
01021 {
01022         correct_viewpoint();
01023         ht_inputfield::receivefocus();
01024 }
01025 
01026 bool ht_strinputfield::inputbyte(byte a)
01027 {
01028         if (setbyte(a)) {
01029                 (*curchar)++;
01030                 correct_viewpoint();
01031                 is_virgin=0;
01032                 return true;
01033         }
01034         return false;
01035 }
01036 
01037 bool ht_strinputfield::setbyte(byte a)
01038 {
01039         if ((insert) || (*curchar-*text>=*textlen)) {
01040                 if ((insertbyte(*curchar, a)) && (*curchar-*text<*textlen)) return true;
01041         } else {
01042                 **curchar=a;
01043                 return true;
01044         }
01045         return false;
01046 }
01047 
01048 /*
01049  *      CLASS ht_hexinputfield
01050  */
01051 
01052 void ht_hexinputfield::init(bounds *b, int maxstrlen)
01053 {
01054         ht_inputfield::init(b, maxstrlen);
01055         VIEW_DEBUG_NAME("ht_strinputfield");
01056         nib=0;
01057         insert=1;
01058 }
01059 
01060 void ht_hexinputfield::done()
01061 {
01062         ht_inputfield::done();
01063 }
01064 
01065 void ht_hexinputfield::correct_viewpoint()
01066 {
01067         if (*curchar-*text<ofs) ofs=*curchar-*text; else
01068         if ((*curchar-*text)*3-(size.w-2)*size.h+5>ofs*3) ofs=((*curchar-*text)*3-(size.w-2)*size.h+5)/3;
01069 }
01070 
01071 void ht_hexinputfield::draw()
01072 {
01073         int c=focused ? getcolor(palidx_generic_input_focused) :
01074                 getcolor(palidx_generic_input_unfocused);
01075         char hbuf[256], *h=hbuf;
01076         int y=0;
01077         fill(0, 0, size.w, size.h, c, ' ');
01078         if (ofs) buf_print(0, y, getcolor(palidx_generic_input_clip), "<");
01079         int vv=*textlen-ofs;
01080         if (vv<0) vv=0; else if (vv>(size.w-2)*size.h/3) vv=(size.w-2)*size.h/3+1;
01081         for (int k=0; k<vv; k++) {
01082                 h+=sprintf(h, "%02x ", *(*text+k+ofs));
01083         }
01084         if (vv) {
01085                 h=hbuf;
01086                 while ((*h) && (y<size.h)) {
01087                         h+=buf_lprint(1, y, c, size.w-2, h);
01088                         y++;
01089                 }
01090                 y--;
01091         }
01092         if ((*textlen-ofs)*3 > (size.w-2)*size.h) {
01093                 buf_print(size.w-1, y, getcolor(palidx_generic_input_clip), ">");
01094         }
01095         if (focused) {
01096                 int cx, cy;
01097                 if ((*curchar-*text-ofs)*3+nib+1>=(size.w-2)*size.h) {
01098                         cx = size.w-1;
01099                         cy = size.h-1;
01100                 } else {
01101                         cx = ((*curchar-*text-ofs)*3+nib+1)%(size.w-2);
01102                         cy = ((*curchar-*text-ofs)*3+nib+1)/(size.w-2);
01103                 }
01104                 setcursor(cx, cy, insert ? cm_normal : cm_overwrite);
01105         }
01106 }
01107 
01108 void ht_hexinputfield::handlemsg(htmsg *msg)
01109 {
01110         if (msg->msg==msg_keypressed) {
01111                 switch (msg->data1.integer) {
01112                         case K_Up:
01113                                 if (*curchar-*text-ofs<(size.w-2)/3) {
01114                                         ofs-=(size.w-2)/3;
01115                                         if (ofs<0) ofs=0;
01116                                 }
01117                                 *curchar-=(size.w-2)/3;
01118                                 if (*curchar<*text) *curchar=*text;
01119                                 correct_viewpoint();
01120                                 dirtyview();
01121                                 clearmsg(msg);
01122                                 return;
01123                         case K_Down:
01124 /*                              if (*curchar-*text-ofs>=(size.w-2)*(size.h-1)/3) {
01125                                         ofs+=(size.w-2)/3;
01126                                 }*/
01127                                 *curchar+=(size.w-2)/3;
01128                                 if (*curchar-*text>*textlen) *curchar=*text+*textlen;
01129                                 if (*curchar-*text>=*textlen) nib=0;
01130                                 correct_viewpoint();
01131                                 dirtyview();
01132                                 clearmsg(msg);
01133                                 return;
01134                         case K_Left:
01135                                 if (nib) {
01136                                         nib=0;
01137                                 } else if (*curchar>*text) {
01138                                         (*curchar)--;
01139                                         nib=1;
01140                                 }
01141                                 correct_viewpoint();
01142                                 dirtyview();
01143                                 clearmsg(msg);
01144                                 return;
01145                         case K_Right:
01146                                 if (!nib) {
01147                                         if (*curchar-*text<*textlen) nib=1;
01148                                 } else if (*curchar-*text<*textlen) {
01149                                         (*curchar)++;
01150                                         nib=0;
01151                                 }
01152                                 correct_viewpoint();
01153                                 dirtyview();
01154                                 clearmsg(msg);
01155                                 return;
01156                         case K_Backspace:
01157                                 if (*textlen) {
01158                                         if (*curchar+nib>*text) {
01159 /*                                              if (*curchar-*text<*textlen) {
01160                                                         memmove(*curchar, *curchar+1, *textlen-(*curchar-*text)-1);
01161                                                 }
01162                                         } else {*/
01163                                                 memmove(*curchar-1+nib, *curchar+nib, *textlen-(*curchar-*text));
01164                                                 (*textlen)--;
01165                                                 if (*curchar-*text && !nib) (*curchar)--;
01166                                                 nib=0;
01167                                                 correct_viewpoint();
01168                                                 dirtyview();
01169                                         }
01170                                         clearmsg(msg);
01171                                         return;
01172                                 }
01173                                 break;
01174                         case K_Delete:
01175                                 if ((*curchar-*text<*textlen) && (*textlen)) {
01176                                         memmove(*curchar, *curchar+1, *textlen-(*curchar-*text)-1);
01177                                         (*textlen)--;
01178                                         nib=0;
01179                                         dirtyview();
01180                                         clearmsg(msg);
01181                                         return;
01182                                 }
01183                                 break;
01184                         case K_Home:
01185                                 *curchar=*text;
01186                                 nib=0;
01187                                 correct_viewpoint();
01188                                 dirtyview();
01189                                 clearmsg(msg);
01190                                 return;
01191                         case K_End:
01192                                 *curchar=*text+*textlen;
01193                                 nib=0;
01194                                 correct_viewpoint();
01195                                 dirtyview();
01196                                 clearmsg(msg);
01197                                 return;
01198                         case K_Insert:
01199                                 insert=!insert;
01200                                 dirtyview();
01201                                 clearmsg(msg);
01202                                 return;
01203                         default:
01204                                 if ((msg->data1.integer>='0') && (msg->data1.integer<='9')) {
01205                                         setnibble(msg->data1.integer-'0');
01206                                         dirtyview();
01207                                         clearmsg(msg);
01208                                 } else if ((msg->data1.integer>='a') && (msg->data1.integer<='f')) {
01209                                         setnibble(msg->data1.integer-'a'+10);
01210                                         dirtyview();
01211                                         clearmsg(msg);
01212                                 }
01213                                 return;
01214                 }
01215         }
01216         ht_inputfield::handlemsg(msg);
01217 }
01218 
01219 void ht_hexinputfield::receivefocus()
01220 {
01221         correct_viewpoint();
01222         if ((nib) && (*curchar-*text==*textlen)) {
01223                 nib=0;
01224         }
01225         ht_inputfield::receivefocus();
01226 }
01227 
01228 void ht_hexinputfield::setnibble(byte a)
01229 {
01230         if (((insert) || (*curchar-*text>=*textlen)) && (nib==0)) {
01231                 if ((insertbyte(*curchar, a<<4)) && (*curchar-*text<*textlen)) nib=1;
01232         } else {
01233                 if (nib) {
01234                         **curchar=(**curchar & 0xf0) | a;
01235                         (*curchar)++;
01236                         nib=0;
01237                 } else {
01238                         **curchar=(**curchar & 0xf) | (a<<4);
01239                         nib=1;
01240                 }
01241         }
01242         correct_viewpoint();
01243 }
01244 
01245 /*
01246  *      CLASS ht_button
01247  */
01248 
01249 void ht_button::init(bounds *b, const char *Text, int Value)
01250 {
01251         ht_view::init(b, VO_SELECTABLE | VO_OWNBUFFER | VO_POSTPROCESS, "some button");
01252         VIEW_DEBUG_NAME("ht_button");
01253         value=Value;
01254         text=ht_strdup(Text);
01255         pressed=0;
01256         magicchar=strchr(text, '~');
01257         if (magicchar) {
01258                 int l=strlen(text);
01259                 memmove(magicchar, magicchar+1, l-(magicchar-text));
01260                 shortcut1=ht_metakey((ht_key)tolower(*magicchar));
01261                 shortcut2=(ht_key)tolower(*magicchar);
01262         } else {
01263                 shortcut1=K_INVALID;
01264                 shortcut2=K_INVALID;
01265         }
01266 }
01267 
01268 void ht_button::done()
01269 {
01270         if (text) free(text);
01271         ht_view::done();
01272 }
01273 
01274 char *ht_button::defaultpalette()
01275 {
01276         return palkey_generic_dialog_default;
01277 }
01278 
01279 void ht_button::draw()
01280 {
01281         int c=focused ? getcolor(palidx_generic_button_focused) :
01282                 getcolor(palidx_generic_button_unfocused);
01283         fill(0, 0, size.w-1, size.h-1, c, ' ');
01284         int xp=(size.w-strlen(text))/2, yp=(size.h-1)/2;
01285         buf_print(xp, yp, c, text);
01286         if (magicchar) buf_printchar(xp+(magicchar-text), yp, getcolor(palidx_generic_button_shortcut), *magicchar);
01287 /* shadow */
01288         buf_printchar(0, 1, getcolor(palidx_generic_button_shadow), ' ');
01289         for (int i=1; i<size.w-1; i++) {
01290                 buf_printchar(i, 1, getcolor(palidx_generic_button_shadow), CHAR_FILLED_HU);
01291         }
01292         buf_printchar(size.w-1, 0, getcolor(palidx_generic_button_shadow), CHAR_FILLED_HL);
01293         buf_printchar(size.w-1, 1, getcolor(palidx_generic_button_shadow), CHAR_FILLED_HU);
01294 }
01295 
01296 void ht_button::handlemsg(htmsg *msg)
01297 {
01298         if (msg->type==mt_postprocess) {
01299                 if (msg->msg==msg_keypressed) {
01300                         if (((shortcut1!=K_INVALID) && (msg->data1.integer==shortcut1)) ||
01301                         ((shortcut2!=K_INVALID) && (msg->data1.integer==shortcut2))) {
01302                                 push();
01303                                 dirtyview();
01304                                 clearmsg(msg);
01305                                 return;
01306                         }
01307                 }
01308         } else if (msg->type==mt_empty) {
01309                 if (msg->msg==msg_keypressed) {
01310                         switch (msg->data1.integer) {
01311                                 case K_Return:
01312                                 case K_Space:
01313                                         push();
01314                                         dirtyview();
01315                                         clearmsg(msg);
01316                                         return;
01317                         }
01318                 }
01319         }
01320         ht_view::handlemsg(msg);
01321 }
01322 
01323 void ht_button::push()
01324 {
01325 /* FIXME: wont work for encapsulated buttons... */
01326 /* FIXME: (thats why I hacked this now...) */
01327         app->sendmsg(msg_button_pressed, value);
01328 //      baseview->sendmsg(msg_button_pressed, value);   // why not like this ?
01329         pressed=1;
01330 }
01331 
01332 /*
01333  *      CLASS ht_listbox_title
01334  */
01335 void    ht_listbox_title::init(bounds *b)
01336 {
01337         ht_view::init(b, VO_RESIZE, "ht_listbox_title");
01338         growmode = MK_GM(GMH_FIT, GMV_FIT);
01339         texts = NULL;
01340         listbox = NULL;
01341         cols = 0;
01342 }
01343 
01344 void    ht_listbox_title::done()
01345 {
01346         if (texts) {
01347                 for (int i=0; i<cols; i++) {
01348                         free(texts[i]);
01349                 }
01350                 free(texts);
01351         }
01352         ht_view::done();
01353 }
01354 
01355 char *ht_listbox_title::defaultpalette()
01356 {
01357         return palkey_generic_dialog_default;
01358 }
01359 
01360 void ht_listbox_title::draw()
01361 {
01362         vcp color = getTextColor();
01363         clear(color);
01364         if (!texts || !listbox) return;
01365         int x = listbox->x;
01366         x = 0;
01367         for (int i=0; i<cols; i++) {     
01368                 buf_lprint(x, 0, color, size.w, texts[i]);
01369                 x += listbox->widths[i];
01370                 if (i+1<cols) {
01371                         buf_printchar(x++, 0, color, ' ');
01372                         buf_printchar(x++, 0, color, CHAR_LINEV);
01373                         buf_printchar(x++, 0, color, ' ');
01374                 }
01375         }
01376 }
01377 
01378 vcp ht_listbox_title::getTextColor()
01379 {
01380         return getcolor(palidx_generic_body);
01381 }
01382 
01383 void ht_listbox_title::setText(int cols, ...)
01384 {
01385         va_list vargs;
01386         va_start(vargs, cols);
01387         setTextv(cols, vargs);
01388         va_end(vargs);
01389         va_end(vargs);
01390 }
01391 
01392 void ht_listbox_title::setTextv(int c, va_list vargs)
01393 {
01394         if (texts) {
01395                 for (int i=0; i<cols; i++) {
01396                         free(texts[i]);
01397                 }
01398                 free(texts);
01399         }
01400         texts = NULL;
01401         cols = c;
01402         if (!c) return;
01403         texts = (char**)malloc(c * sizeof(char*));
01404         for (int i=0; i<cols; i++) {
01405                 texts[i] = ht_strdup(va_arg(vargs, char* ));
01406         }
01407         update();
01408 }
01409 
01410 void ht_listbox_title::update()
01411 {
01412         if (texts && listbox && listbox->widths) {
01413                 for (int i=0; i<cols; i++) {
01414                         int s = strlen(texts[i]);
01415                         if (s > listbox->widths[i]) listbox->widths[i] = s;
01416                 }
01417         }
01418 }
01419 
01420 
01421 /*
01422  *      CLASS ht_listbox
01423  */
01424 
01425 class ht_listbox_vstate: public Object {
01426 public:
01427         void *e_top;
01428         void *e_cursor;
01429 
01430         ht_listbox_vstate(void *top, void *cursor)
01431         {
01432                 e_top = top;
01433                 e_cursor = cursor;
01434         }
01435 };
01436 
01437 void ht_listbox::init(bounds *b, UINT Listboxcaps)
01438 {
01439         ht_view::init(b, VO_SELECTABLE | VO_OWNBUFFER | VO_RESIZE, 0);
01440         cached_count = 0;
01441 
01442         growmode = MK_GM(GMH_FIT, GMV_FIT);
01443 
01444         bounds c=*b;
01445         c.x=c.w-1;
01446         c.y=0;
01447         c.w=1;
01448         scrollbar=new ht_scrollbar();
01449         scrollbar->init(&c, &pal, true);
01450 
01451         pos = 0;
01452         cursor = 0;
01453         e_top = getFirst();
01454         e_cursor = e_top;
01455         title = NULL;
01456         visible_height = 0;
01457         x = 0;
01458         widths = NULL;
01459         clearQuickfind();
01460         update();
01461         listboxcaps = Listboxcaps;
01462         cols = 0;
01463 }
01464 
01465 void    ht_listbox::done()
01466 {
01467         scrollbar->done();
01468         delete scrollbar;
01469         if (widths) free(widths);
01470         ht_view::done();
01471 }
01472 
01473 void ht_listbox::adjustPosHack()
01474 {
01475         if (e_cursor!=e_top) return;
01476         int i=0;
01477         void *tmp = e_cursor;
01478         if (!tmp) return;
01479         while ((tmp) && (i<=visible_height)) {
01480                 tmp = getNext(tmp);
01481                 i++;
01482         }
01483         if (i<visible_height) {
01484                 cursorDown(cursorUp(visible_height-pos-i));
01485         }
01486 }
01487 
01488 void ht_listbox::adjustScrollbar()
01489 {
01490         int pstart, psize;
01491         if (scrollbar_pos(pos-cursor, size.h, cached_count, &pstart, &psize)) {
01492                 mScrollbarEnabled = true;
01493                 scrollbar->enable();
01494                 bounds c = size;
01495                 c.x = c.w-1;
01496                 c.y = 0;
01497                 c.w = 1;
01498                 scrollbar->setbounds(&c);
01499                 scrollbar->setpos(pstart, psize);
01500         } else {
01501                 mScrollbarEnabled = false;
01502                 scrollbar->disable();
01503         }
01504 }
01505 
01506 void ht_listbox::attachTitle(ht_listbox_title *aTitle)
01507 {
01508         if (numColumns() > cols) rearrangeColumns();
01509         title = aTitle;
01510         title->listbox = this;
01511         title->update();
01512         title->dirtyview();
01513 }
01514 
01515 void ht_listbox::clearQuickfind()
01516 {
01517         quickfinder[0] = 0;
01518         qpos = quickfinder;
01519         updateCursor();
01520 }
01521 
01522 int  ht_listbox::cursorAdjust()
01523 {
01524         return 0;
01525 }
01526 
01527 int  ht_listbox::cursorUp(int n)
01528 {
01529         void *tmp;
01530         int  i = 0;
01531 
01532         while (n--) {
01533                 tmp = getPrev(e_cursor);
01534                 if (!tmp) break;
01535                 if (e_cursor==e_top) {
01536                         e_top = tmp;
01537                 } else {
01538                         cursor--;
01539                 }
01540                 e_cursor = tmp;
01541                 pos--;
01542                 if (pos<0) pos = 0; // if cursor was out of sync
01543                 i++;
01544         }
01545         return i;
01546 }
01547 
01548 int  ht_listbox::cursorDown(int n)
01549 {
01550         void *tmp;
01551         int  i = 0;
01552 
01553         while (n--) {
01554                 tmp = getNext(e_cursor);
01555                 if (!tmp) break;
01556                 if (cursor+1 >= visible_height) {
01557                         e_top = getNext(e_top);
01558                 } else {
01559                         cursor++;
01560                 }
01561                 pos++;
01562                 e_cursor = tmp;
01563                 i++;
01564         }
01565         return i;
01566 }
01567 
01568 int  ht_listbox::datasize()
01569 {
01570         return sizeof(ht_listbox_data);
01571 }
01572 
01573 char *ht_listbox::defaultpalette()
01574 {
01575         return palkey_generic_dialog_default;
01576 }
01577 
01578 void ht_listbox::draw()
01579 {
01580         int fc = focused ? getcolor(palidx_generic_list_focused_unselected) :
01581                 getcolor(palidx_generic_list_unfocused_unselected);
01582 
01583         int Cols = numColumns();
01584         if (Cols > cols) rearrangeColumns();
01585 
01586         bool resizing_cols = true;
01587         bool title_redraw = false;
01588         while (resizing_cols) {
01589                 resizing_cols = false;
01590                 clear(fc);
01591                 void *entry = e_top;
01592                 int i=0;
01593                 while ((entry) && (i < visible_height)) {
01594                         int c=(i==cursor) ? (focused ? getcolor(palidx_generic_list_focused_selected) :
01595                                 getcolor(palidx_generic_list_unfocused_selected)) : fc;
01596                         if (i==cursor) {
01597                                 fill(0, i, size.w, 1, c, ' ');
01598                         }
01599                         int X = -x;
01600                         for (int j=0; j<cols; j++) {
01601                                 char *s = getStr(j, entry);
01602                                 int slen = strlen(s);
01603                                 if (slen > widths[j]) {
01604                                         widths[j] = slen;
01605                                         /*
01606                                          *      a column has been resized,
01607                                          *      therefore we have to redraw a second time.
01608                                          */
01609                                         resizing_cols = true;
01610                                         title_redraw = true;
01611                                 }
01612                                 if (s) {
01613                                         if (X >= 0) {
01614                                                 buf_lprint(X, i, c, size.w, s);
01615                                         } else {
01616                                                 if (slen > -X) buf_lprint(0, i, c, size.w, &s[-X]);
01617                                         }
01618                                 }
01619                                 if (j==cols-1) {
01620                                         X += slen;
01621                                 } else {
01622                                         X += widths[j];
01623                                 }
01624                                 if (j+1<cols) {
01625                                         buf_printchar(X++, i, c, ' ');
01626                                         buf_printchar(X++, i, c, CHAR_LINEV);
01627                                         buf_printchar(X++, i, c, ' ');
01628                                 }
01629                         }
01630                         if (x > 0) {
01631                                 // more text left
01632                                 buf_printchar(0, i, c, '<');
01633                         }
01634                         // position of '>' char is scrollbar dependent
01635                         int a = mScrollbarEnabled ? 0 : 1;
01636                         if (X >= size.w+a) {
01637                                 // more text right
01638                                 buf_printchar(size.w-2+a, i, c, '>');
01639                         }
01640                         entry = getNext(entry);
01641                         i++;
01642                 }
01643         }
01644         updateCursor();
01645         if (title_redraw && title) {
01646                 title->update();
01647                 title->dirtyview();
01648         }
01649 /*     char dbg[100];
01650         sprintf(dbg, "cursor=%d pos=%d vh=%d qc:%s", cursor, pos, visible_height, quickfinder);
01651         lprint(0, 0, 1, size.w, dbg);
01652         sprintf(dbg, "e_top=%s", getstr(0, e_top));
01653         lprint(0, 1, 1, size.w, dbg);
01654         sprintf(dbg, "e_cursor=%s", getstr(0, e_cursor));
01655         lprint(0, 2, 1, size.w, dbg);*/
01656 }
01657 
01658 int  ht_listbox::estimateEntryPos(void *entry)
01659 {
01660         // this is slow!
01661         void *tmp = getFirst();
01662         int res = 0;
01663         while (tmp) {
01664                 if (tmp==entry) break;
01665                 tmp = getNext(tmp);
01666                 res++;
01667         }
01668         return (tmp==entry) ? res : -1;
01669 }
01670 
01671 void ht_listbox::getdata(ht_object_stream *s)
01672 {
01673         ht_listbox_data d;
01674         d.top_ptr = e_top;
01675         d.cursor_ptr = e_cursor;
01676         s->write(&d, sizeof d);
01677 }
01678 
01679 void ht_listbox::gotoItemByEntry(void *entry, bool clear_quickfind)
01680 {
01681         if (clear_quickfind) clearQuickfind();
01682         if (!entry) return;
01683         void *tmp = e_top;
01684         int i=0;
01685         bool ok=false;
01686         pos -= cursor;
01687         if (pos<0) pos = 0; // if cursor was out of sync
01688         cursor = 0;
01689 
01690         while ((tmp) && (i < visible_height)) {
01691                 if (tmp == entry) {
01692                         ok = true;
01693                         break;
01694                 }
01695                 pos++;
01696                 cursor++;
01697                 i++;
01698                 tmp = getNext(tmp);
01699         }
01700         e_cursor = entry;
01701         if (!ok) {
01702                 e_top = entry;
01703                 cursor = 0;
01704                 pos = estimateEntryPos(entry);
01705                 assert(pos != -1);
01706         }
01707         adjustPosHack();
01708         stateChanged();
01709 }
01710 
01711 void ht_listbox::gotoItemByPosition(UINT pos)
01712 {
01713         void *entry = getFirst();
01714         while (pos--) entry = getNext(entry);
01715         gotoItemByEntry(entry, true);
01716 }
01717 
01718 void ht_listbox::handlemsg(htmsg *msg)
01719 {
01720         switch (msg->msg) {
01721                 case msg_vstate_restore: {
01722                         ht_listbox_vstate *vs = (ht_listbox_vstate*)msg->data1.ptr;
01723                         e_top = vs->e_top;
01724                         e_cursor = vs->e_cursor;
01725                         update();
01726                         // FIXME: what about deleting entries !!!
01727                         clearmsg(msg);
01728                         return;
01729                 }
01730                 case msg_keypressed: switch (msg->data1.integer) {
01731                         case K_Control_PageUp:
01732                         case K_Home:
01733                                 clearQuickfind();
01734                                 pos = cursor = 0;
01735                                 e_top = e_cursor = getFirst();
01736                                 dirtyview();
01737                                 clearmsg(msg);
01738                                 stateChanged();
01739                                 return;
01740                         case K_Control_PageDown:
01741                         case K_End: {
01742                                 clearQuickfind();
01743                                 cursor = 0;
01744                                 pos = cached_count ? cached_count-1 : 0;
01745                                 e_cursor = e_top = getLast();
01746                                 cursorUp(visible_height-1);
01747                                 cursorDown(visible_height-1);
01748                                 dirtyview();
01749                                 clearmsg(msg);
01750                                 stateChanged();
01751                                 return;
01752                         }
01753                         case K_PageUp:
01754                                 clearQuickfind();
01755                                 cursorUp(visible_height-1);
01756                                 dirtyview();
01757                                 clearmsg(msg);
01758                                 stateChanged();
01759                                 return;
01760                         case K_PageDown: {
01761                                 clearQuickfind();
01762                                 cursorDown(visible_height-1);
01763                                 dirtyview();
01764                                 clearmsg(msg);
01765                                 stateChanged();
01766                                 return;
01767                         }
01768                         case K_Up:
01769                                 clearQuickfind();
01770                                 cursorUp(1);
01771                                 dirtyview();
01772                                 clearmsg(msg);
01773                                 stateChanged();
01774                                 return;
01775                         case K_Down:
01776                                 clearQuickfind();
01777                                 cursorDown(1);
01778                                 dirtyview();
01779                                 clearmsg(msg);
01780                                 stateChanged();
01781                                 return;
01782                         case K_Left:
01783                         case K_Control_Left:
01784                                 if (x > 0) x--;
01785                                 updateCursor();
01786                                 dirtyview();
01787                                 clearmsg(msg);
01788                                 stateChanged();
01789                                 return;
01790                         case K_Right:
01791                         case K_Control_Right:
01792                                 x++;
01793                                 updateCursor();
01794                                 dirtyview();
01795                                 clearmsg(msg);
01796                                 stateChanged();
01797                                 return;
01798                         case K_Tab:
01799                                 if (listboxcaps & LISTBOX_QUICKFIND) {
01800                                         if (*quickfinder) {
01801                                                 char *qc = quickfindCompletition(quickfinder);
01802                                                 if (qc) {
01803                                                         strcpy(quickfinder, qc);
01804                                                         qpos = strend(quickfinder);
01805                                                         free(qc);
01806                                                         goto qf;
01807                                                 }
01808                                         }
01809                                 }
01810                                 break;
01811                         case K_Backspace: {
01812                                 if (listboxcaps & LISTBOX_QUICKFIND) {
01813                                         if (qpos > quickfinder) {
01814                                                 *(--qpos) = 0;
01815                                                 qf:
01816                                                 void *a = quickfind(quickfinder);
01817                                                 if (a) {
01818                                                         gotoItemByEntry(a, false);
01819                                                         updateCursor();
01820                                                         dirtyview();
01821                                                 }
01822                                                 clearmsg(msg);
01823                                                 stateChanged();
01824                                         }
01825                                 }
01826                                 return;
01827                         }
01828                         default: {
01829                                 if ((listboxcaps & LISTBOX_QUICKFIND) && (msg->data1.integer > 31) && (msg->data1.integer < 0xff)) {
01830                                         *(qpos++) = msg->data1.integer;
01831                                         *qpos = 0;
01832                                         void *a = quickfind(quickfinder);
01833                                         if (a) {
01834                                                 gotoItemByEntry(a, false);
01835                                                 updateCursor();
01836                                                 dirtyview();
01837                                                 clearmsg(msg);
01838                                                 stateChanged();
01839                                         } else {
01840                                                 *(--qpos) = 0;
01841                                         }
01842                                 }
01843                         }
01844                 }
01845                 break;
01846         }
01847         ht_view::handlemsg(msg);
01848 }
01849 
01850 int     ht_listbox::numColumns()
01851 {
01852         return 1;
01853 }
01854 
01855 char    *ht_listbox::quickfindCompletition(char *s)
01856 {
01857         return ht_strdup(s);
01858 }
01859 
01860 void ht_listbox::rearrangeColumns()
01861 {
01862         if (widths) free(widths);
01863         cols = numColumns();
01864         widths = (int*)calloc(cols*sizeof(int), 1);
01865 }
01866 
01867 void ht_listbox::redraw()
01868 {
01869         ht_view::redraw();
01870         scrollbar->relocate_to(this);
01871 //      fprintf(stderr, "scrollbar: x=%d, y=%d, w=%d, h=%d\n", scrollbar->vsize.x, scrollbar->vsize.y, scrollbar->vsize.w, scrollbar->vsize.h);
01872         scrollbar->redraw();
01873         if (title) {
01874                 title->redraw();
01875         }
01876         scrollbar->unrelocate_to(this);
01877 }
01878 
01879 void ht_listbox::resize(int rw, int rh)
01880 {
01881         ht_view::resize(rw, rh);
01882         update();
01883 }
01884 
01885 void ht_listbox::stateChanged()
01886 {
01887         adjustScrollbar();
01888 }
01889 
01890 bool ht_listbox::selectEntry(void *entry)
01891 {
01892         return true;
01893 }
01894 
01895 void ht_listbox::setdata(ht_object_stream *s)
01896 {
01897         ht_listbox_data d;
01898         s->read(&d, sizeof d);
01899         e_top = d.top_ptr;
01900         e_cursor = d.cursor_ptr;
01901         update();
01902 }
01903 
01904 Object *ht_listbox::vstate_create()
01905 {
01906         return new ht_listbox_vstate(e_top, e_cursor);
01907 }
01908 
01909 void ht_listbox::vstate_save()
01910 {
01911         Object *vs = vstate_create();
01912         if (vs) {
01913                 htmsg m;
01914                 m.msg = msg_vstate_save;
01915                 m.type = mt_empty;
01916                 m.data1.ptr = vs;
01917                 m.data2.ptr = this;
01918                 app->sendmsg(&m);
01919         }
01920 }
01921 
01922 /*
01923  *      must be called if data has changed
01924  */
01925 void ht_listbox::update()
01926 {
01927         void *entry = getFirst();
01928         cached_count = calcCount();
01929         visible_height = MIN(size.h, cached_count);
01930         if (cached_count <= size.h) {
01931                 if (!e_cursor) e_cursor = getFirst();
01932                 cursor = 0;
01933                 while (entry && (cursor < visible_height)) {
01934                         if (entry == e_cursor) {
01935                                 e_top = getFirst();
01936                                 goto ok;
01937                         }
01938                         entry = getNext(entry);
01939                         cursor++;
01940                 }
01941         }
01942         if (!e_top) {
01943                 e_top = getFirst();
01944         }     
01945         if (!e_cursor) e_cursor = e_top;
01946         entry = e_top;
01947         cursor = 0;
01948         while (entry && (cursor < visible_height)) {
01949                 if (entry == e_cursor) goto ok;
01950                 entry = getNext(entry);
01951                 cursor++;
01952         }
01953         cursor = 0;
01954         e_top = e_cursor;
01955 ok:
01956         adjustPosHack();
01957         stateChanged();
01958         if (title) {
01959                 title->update();
01960                 title->dirtyview();
01961         }
01962         dirtyview();
01963 }
01964 
01965 void ht_listbox::updateCursor()
01966 {
01967         if (focused) {
01968                 if (*quickfinder) {
01969                         setcursor((qpos-quickfinder)+cursorAdjust()-x, cursor);
01970                 } else {
01971                         hidecursor();
01972                 }
01973         }               
01974 }
01975 
01976 /*
01977  *      ht_text_listbox
01978  */
01979 
01980 void    ht_text_listbox::init(bounds *b, int aCols, int aKeycol, UINT aListboxcaps)
01981 {
01982         first = last = NULL;
01983         count = 0;
01984         ht_listbox::init(b, aListboxcaps);
01985         cols = aCols;
01986         keycol = aKeycol;
01987         Cursor_adjust = 0;
01988         rearrangeColumns();
01989 }
01990 
01991 void ht_text_listbox::done()
01992 {
01993         clearAll();
01994         ht_listbox::done();
01995 }
01996 
01997 void ht_text_listbox::clearAll()
01998 {
01999         ht_text_listbox_item *temp = first;
02000         while (temp) {
02001                 ht_text_listbox_item *temp2 = temp->next;
02002                 freeExtraData(temp->extra_data);
02003                 for (int i=0; i<cols; i++) {
02004                         free(temp->data[i]);
02005                 }
02006                 free(temp);
02007                 temp = temp2;
02008         }
02009         first = last = NULL;
02010         
02011         pos = 0;
02012         cursor = 0;
02013         e_top = getFirst();
02014         e_cursor = e_top;
02015         x = 0;
02016         clearQuickfind();
02017 
02018         count = 0;
02019         Cursor_adjust = 0;
02020 }
02021 
02022 int     ht_text_listbox::calcCount()
02023 {
02024         return count;
02025 }
02026 
02027 int     ht_text_listbox::compare_strn(char *s1, char *s2, int l)
02028 {
02029         return ht_strncmp(s1, s2, l);
02030 }
02031 
02032 int     ht_text_listbox::compare_ccomm(char *s1, char *s2)
02033 {
02034         return strccomm(s1, s2);
02035 }
02036 
02037 int  ht_text_listbox::cursorAdjust()
02038 {
02039         return Cursor_adjust;
02040 }
02041 
02042 void ht_text_listbox::freeExtraData(void *extra_data)
02043 {
02044 }
02045 
02046 void *ht_text_listbox::getFirst()
02047 {
02048         return first;
02049 }
02050 
02051 UINT ht_text_listbox::getID(void *entry)
02052 {
02053         if (entry) {
02054                 return ((ht_text_listbox_item *)entry)->id;
02055         } else {
02056                 return 0;
02057         }           
02058 }
02059 
02060 void *ht_text_listbox::getLast()
02061 {
02062         return last;
02063 }
02064 
02065 void *ht_text_listbox::getNext(void *entry)
02066 {
02067         if (!entry) return NULL;
02068         return ((ht_text_listbox_item *)entry)->next;
02069 }
02070 
02071 void *ht_text_listbox::getPrev(void *entry)
02072 {
02073         if (!entry) return NULL;
02074         return ((ht_text_listbox_item *)entry)->prev;
02075 }
02076 
02077 char *ht_text_listbox::getStr(int col, void *entry)
02078 {
02079         if (entry && (col < cols)) {
02080                 return ((ht_text_listbox_item *)entry)->data[col];
02081         } else {
02082                 return "";
02083         }
02084 }
02085 
02086 void    ht_text_listbox::insert_str_extra(int id, void *extra_data, char **strs)
02087 {
02088 // FIXME: code duplication...
02089         ht_text_listbox_item *item = (ht_text_listbox_item *)malloc(sizeof(ht_text_listbox_item)+sizeof(char *)*cols);
02090         item->next = NULL;
02091         item->prev = last;
02092         item->id = id;
02093         item->extra_data = extra_data;
02094         for (int i=0; i<cols; i++) {
02095                 int slen = strlen(strs[i]);
02096                 if (slen > widths[i]) {
02097                         widths[i] = slen;
02098                 }
02099 
02100                 item->data[i] = ht_strdup(strs[i]);
02101         }
02102         if (first) {
02103                 last->next = item;
02104         } else {
02105                 first = item;
02106         }
02107         last = item;
02108         count++;
02109 }
02110 
02111 void    ht_text_listbox::insert_str_extra(int id, void *extra_data, char *str, ...)
02112 {
02113         ht_text_listbox_item *item = (ht_text_listbox_item *)malloc(sizeof(ht_text_listbox_item)+sizeof(char *)*cols);
02114         item->next = NULL;
02115         item->prev = last;
02116         item->id = id;
02117         item->extra_data = extra_data;
02118         va_list str2;
02119         va_start(str2, str);
02120         char *str3 = str;
02121         for (int i=0; i<cols; i++) {
02122                 int slen = strlen(str3);
02123                 if (slen > widths[i]) {
02124                         widths[i] = slen;
02125                 }
02126 
02127                 item->data[i] = ht_strdup(str3);
02128                 str3 = va_arg(str2, char *);
02129         }
02130         va_end(str2);
02131         if (first) {
02132                 last->next = item;
02133         } else {
02134                 first = item;
02135         }
02136         last = item;
02137         count++;
02138 }
02139 
02140 void    ht_text_listbox::insert_str(int id, char **strs)
02141 {
02142         insert_str_extra(id, NULL, strs);
02143 }
02144 
02145 void ht_text_listbox::insert_str(int id, char *str, ...)
02146 {
02147 // FIXME: same as insert_str(id, NULL, str, ...)
02148         ht_text_listbox_item *item = (ht_text_listbox_item *)malloc(sizeof(ht_text_listbox_item)+sizeof(char *)*cols);
02149         item->next = NULL;
02150         item->prev = last;
02151         item->id = id;
02152         item->extra_data = NULL;
02153         va_list str2;
02154         va_start(str2, str);
02155         char *str3 = str;
02156         for (int i=0; i<cols; i++) {
02157                 int slen = strlen(str3);
02158                 if (slen > widths[i]) {
02159                         widths[i] = slen;
02160                 }
02161 
02162                 item->data[i] = ht_strdup(str3);
02163                 str3 = va_arg(str2, char *);
02164         }
02165         va_end(str2);
02166         if (first) {
02167                 last->next = item;
02168         } else {
02169                 first = item;
02170         }
02171         last = item;
02172         count++;
02173 }
02174 
02175 int     ht_text_listbox::numColumns()
02176 {
02177         return cols;
02178 }
02179 
02180 void *ht_text_listbox::quickfind(char *s)
02181 {
02182         ht_text_listbox_item *item = first;
02183         int slen = strlen(s);
02184         while (item && (compare_strn(item->data[keycol], s, slen)!=0)) {
02185                 item = item->next;
02186         }
02187         return item;
02188 }
02189 
02190 char    *ht_text_listbox::quickfindCompletition(char *s)
02191 {
02192         ht_text_listbox_item *item = first;
02193         char *res = NULL;
02194         int slen = strlen(s);
02195         while (item) {
02196                 if (compare_strn(item->data[keycol], s, slen)==0) {
02197                         if (!res) {
02198                                 res = ht_strdup(item->data[keycol]);
02199                         } else {
02200                                 int a = compare_ccomm(item->data[keycol], res);
02201                                 res[a] = 0;
02202                         }
02203                 }
02204                 item = item->next;
02205         }
02206         return res;
02207 }
02208 
02209 static int ht_text_listboxcomparatio(ht_text_listbox_item *a, ht_text_listbox_item *b, int count, ht_text_listbox_sort_order *so)
02210 {
02211         for (int i=0;i<count;i++) {
02212                 int r = so[i].compare_func(a->data[so[i].col], b->data[so[i].col]);
02213                 if (r!=0) return r;
02214         }
02215         return 0;
02216 }
02217 
02218 static void ht_text_listboxqsort(int l, int r, int count, ht_text_listbox_sort_order *so, ht_text_listbox_item **list)
02219 {
02220         int m=(l+r)/2;
02221         int L=l;
02222         int R=r;
02223         ht_text_listbox_item *c=list[m];
02224         do {
02225                 while ((l<=r) && (ht_text_listboxcomparatio(list[l], c, count, so)<0)) l++;
02226                 while ((l<=r) && (ht_text_listboxcomparatio(list[r], c, count, so)>0)) r--;
02227                 if (l<=r) {
02228                         ht_text_listbox_item *t=list[l];
02229                         list[l]=list[r];
02230                         list[r]=t;
02231                         l++;
02232                         r--;
02233                 }
02234         } while(l<r);
02235         if (L<r) ht_text_listboxqsort(L, r, count, so, list);
02236         if (l<R) ht_text_listboxqsort(l, R, count, so, list);
02237 }
02238 
02239 void ht_text_listbox::sort(int count, ht_text_listbox_sort_order *so)
02240 {
02241         ht_text_listbox_item **list;
02242         ht_text_listbox_item *tmp;
02243         int i=0;
02244         int cnt = calcCount();
02245 
02246         if (cnt<2) return;
02247         
02248         list = (ht_text_listbox_item **)malloc(cnt*sizeof(void *));
02249         tmp = first;
02250         while (tmp) {
02251                 list[i++] = tmp;
02252                 tmp = (ht_text_listbox_item *)getNext(tmp);
02253         }
02254 
02255         int c_id = ((ht_text_listbox_item*)e_cursor)->id;
02256 
02257         ht_text_listboxqsort(0, cnt-1, count, so, list);
02258 
02259         for (i=0; i<cnt; i++) {
02260                 if (list[i]->id == c_id) {
02261                         pos = i;
02262                         e_cursor = list[i];
02263                 }
02264         }
02265 
02266         first = list[0];
02267         last = list[cnt-1];
02268         first->prev = NULL;
02269         last->next = NULL;
02270         last->prev = list[cnt-2];
02271         tmp = first->next = list[1];
02272         for (i=1; i<cnt-1; i++) {
02273                 tmp->prev = list[i-1];
02274                 tmp->next = list[i+1];
02275                 tmp = list[i+1];
02276         }
02277         free(list);
02278 
02279         update();
02280         stateChanged();
02281 }
02282 
02283 void ht_text_listbox::update()
02284 {
02285         ht_listbox::update();
02286         Cursor_adjust = 0;
02287         if (widths) {
02288                 for (int i=0; i<keycol; i++) {
02289                         Cursor_adjust+=widths[i]+3;
02290                 }
02291         }
02292 }
02293 
02294 /*
02295  *      CLASS ht_itext_listbox
02296  */
02297 
02298 void    ht_itext_listbox::init(bounds *b, int Cols, int Keycol)
02299 {
02300         ht_text_listbox::init(b, Cols, Keycol);
02301 }
02302 
02303 void    ht_itext_listbox::done()
02304 {
02305         ht_text_listbox::done();
02306 }
02307 
02308 int     ht_itext_listbox::compare_strn(char *s1, char *s2, int l)
02309 {
02310         return ht_strnicmp(s1, s2, l);
02311 }
02312 
02313 int     ht_itext_listbox::compare_ccomm(char *s1, char *s2)
02314 {
02315         return strcicomm(s1, s2);
02316 }
02317 
02318 /*
02319  *      CLASS ht_statictext
02320  */
02321 
02322 #define STATICTEXT_MIN_LINE_FILL 70     /* percent */
02323 
02324 void ht_statictext_align(ht_statictext_linedesc *d, statictext_align align, int w)
02325 {
02326         switch (align) {
02327                 case align_center:
02328                         d->ofs=(w-d->len)/2;
02329                         break;
02330                 case align_right:
02331                         d->ofs=w-d->len;
02332                         break;
02333                 default:
02334                         d->ofs=0;
02335                         break;
02336         }
02337 }
02338 
02339 void ht_statictext::init(bounds *b, const char *t, statictext_align al, bool breakl, bool trans)
02340 {
02341         ht_view::init(b, VO_OWNBUFFER | VO_RESIZE, "some statictext");
02342         VIEW_DEBUG_NAME("ht_statictext");
02343 
02344         align=al;
02345         breaklines=breakl;
02346         transparent=trans;
02347         text=ht_strdup(t);
02348 }
02349 
02350 void ht_statictext::done()
02351 {
02352         if (text) free(text);
02353         ht_view::done();
02354 }
02355 
02356 char *ht_statictext::defaultpalette()
02357 {
02358         return palkey_generic_dialog_default;
02359 }
02360 
02361 #define ssst_word               0
02362 #define ssst_separator  1
02363 #define ssst_whitespace 2
02364 
02365 int get_ssst(char s)
02366 {
02367         if (strchr(".,:;+-*/=()[]", s)) {
02368                 return ssst_separator;
02369         } else if (s==' ') {
02370                 return ssst_whitespace;
02371         }
02372         return ssst_word;
02373 }
02374 
02375 void ht_statictext::draw()
02376 {
02377         if (!transparent) clear(gettextcolor());
02378         char *t=gettext();
02379         if (!t) return;
02380         if (breaklines) {
02381 /* format string... */  
02382                 ht_statictext_linedesc *orig_d=(ht_statictext_linedesc *)malloc(sizeof (ht_statictext_linedesc)*size.h);
02383                 ht_statictext_linedesc *d=orig_d;
02384                 statictext_align lalign=align;
02385                 int c=0;
02386                 while ((*t) && (c<size.h)) {
02387 /* custom alignment */
02388                         if ((*t==ALIGN_CHAR_ESCAPE) && (align==align_custom)) {
02389                                 switch (t[1]) {
02390                                         case ALIGN_CHAR_LEFT:
02391                                                 lalign=align_left;
02392                                                 break;
02393                                         case ALIGN_CHAR_CENTER:
02394                                                 lalign=align_center;
02395                                                 break;
02396                                         case ALIGN_CHAR_RIGHT:
02397                                                 lalign=align_right;
02398                                                 break;
02399                                 }
02400                                 t+=2;
02401                         }
02402 /* determine line length */
02403                         int i=0, len=1;
02404                         char *bp=t+1, *n=t+1;
02405                         int ssst=get_ssst(t[i]);
02406                         while (t[i]) {
02407                                 if ((i+1>size.w) || (t[i]=='\n') || !(t[i+1])) {
02408                                         bool kill_ws=(t[i]!='\n');
02409                                         if (i+1<=size.w) {
02410                                                 /* line shorter than size.w */
02411                                                 bp=t+i+1;
02412                                         } else if (t[i]=='\n') {
02413                                                 /* line end */
02414                                                 bp=t+i+1;
02415                                         } else if (size.w && ((bp-t)*100/size.w < STATICTEXT_MIN_LINE_FILL)) {
02416                                                 /* force break to make line long enough */
02417                                                 bp=t+i;
02418                                         }
02419                                         len=bp-t;
02420                                         if (t[len-1]=='\n') len--;
02421                                         n=bp;
02422                                         if (kill_ws) {
02423                                                 while (*n==' ') n++;
02424                                                 while (t[len-1]==' ') len--;
02425                                         }
02426                                         break;
02427                                 }
02428                                 int s=get_ssst(t[i+1]);
02429                                 if ((ssst!=s) || (ssst==ssst_separator)) {
02430                                         bp=t+i+1;
02431                                 }
02432                                 ssst=s;
02433                                 i++;
02434                         }
02435                         d->text=t;
02436                         d->len=len;
02437                         ht_statictext_align(d, lalign, size.w);
02438                         d++;
02439                         c++;
02440                         t=n;
02441                 }
02442 
02443 
02444                 d=orig_d;
02445                 for (int i=0; i<c; i++) {
02446                         buf_lprint(d->ofs, i, gettextcolor(), d->len, d->text);
02447                         d++;
02448                 }
02449                 free(orig_d);
02450         } else {
02451                 int o=0;
02452                 buf_print(o, 0, gettextcolor(), t);
02453         }
02454 }
02455 
02456 vcp ht_statictext::gettextcolor()
02457 {
02458         return getcolor(palidx_generic_body);
02459 //      return VCP(VC_RED, VC_BLACK);
02460 }
02461 
02462 char *ht_statictext::gettext()
02463 {
02464         return text;
02465 }
02466 
02467 void ht_statictext::settext(const char *_text)
02468 {
02469         if (text) free(text);
02470         text = ht_strdup(_text);
02471         dirtyview();
02472 }
02473 
02474 /*
02475  *      CLASS ht_listpopup_dialog
02476  */
02477 
02478 void ht_listpopup_dialog::init(bounds *b, char *desc)
02479 {
02480         ht_dialog::init(b, desc, FS_TITLE | FS_MOVE);
02481         VIEW_DEBUG_NAME("ht_listpopup_dialog");
02482 
02483         bounds c;
02484         getclientarea(&c);
02485         c.x=0;
02486         c.y=0;
02487         init_text_listbox(&c);
02488 }
02489 
02490 void ht_listpopup_dialog::done()
02491 {
02492         ht_dialog::done();
02493 }
02494 
02495 int     ht_listpopup_dialog::datasize()
02496 {
02497         return sizeof (ht_listpopup_dialog_data);
02498 }
02499 
02500 char *ht_listpopup_dialog::defaultpalette()
02501 {
02502         return palkey_generic_blue;
02503 }
02504 
02505 void ht_listpopup_dialog::getdata(ht_object_stream *s)
02506 {
02507         ht_listbox_data d;
02508         listbox->databuf_get(&d, sizeof d);
02509 
02510         s->putIntDec(((ht_text_listbox*)listbox)->getID(d.cursor_ptr), 4, NULL);
02511 
02512         ht_text_listbox_item *cursor = (ht_text_listbox_item*)d.cursor_ptr;
02513         if (cursor) {
02514                 s->putString(cursor->data[0], NULL);
02515         } else {
02516                 s->putString(NULL, NULL);
02517         }
02518 }
02519 
02520 void ht_listpopup_dialog::init_text_listbox(bounds *b)
02521 {
02522         listbox=new ht_text_listbox();
02523         ((ht_text_listbox *)listbox)->init(b);
02524         insert(listbox);
02525 }
02526 
02527 void ht_listpopup_dialog::insertstring(char *string)
02528 {
02529         ((ht_text_listbox *)listbox)->insert_str(listbox->calcCount(), string);
02530         listbox->update();
02531 }
02532 
02533 void ht_listpopup_dialog::select_next()
02534 {
02535         listbox->cursorDown(1);
02536 }
02537 
02538 void ht_listpopup_dialog::select_prev()
02539 {
02540         listbox->cursorUp(1);
02541 }
02542 
02543 void ht_listpopup_dialog::setdata(ht_object_stream *s)
02544 {
02545         int cursor_id=s->getIntDec(4, NULL);
02546         s->getString(NULL);     /* ignored */
02547         
02548         listbox->gotoItemByPosition(cursor_id);
02549 }
02550 
02551 /*
02552  *      CLASS ht_listpopup
02553  */
02554 
02555 void    ht_listpopup::init(bounds *b)
02556 {
02557         ht_statictext::init(b, 0, align_left, 0);
02558         setoptions(options|VO_SELECTABLE);
02559         VIEW_DEBUG_NAME("ht_listpopup");
02560 
02561         bounds c=*b;
02562         c.x=0;
02563         c.y=0;
02564         c.h=8;
02565         
02566         listpopup=new ht_listpopup_dialog();
02567         listpopup->init(&c, 0);
02568 }
02569 
02570 void    ht_listpopup::done()
02571 {
02572         listpopup->done();
02573         delete listpopup;
02574         
02575         ht_view::done();
02576 }
02577 
02578 int ht_listpopup::datasize()
02579 {
02580         return listpopup->datasize();
02581 }
02582 
02583 void ht_listpopup::draw()
02584 {
02585         ht_statictext::draw();
02586         buf_printchar(size.w-1, 0, gettextcolor(), CHAR_ARROW_DOWN);
02587 }
02588 
02589 vcp ht_listpopup::gettextcolor()
02590 {
02591         return focused ? getcolor(palidx_generic_input_selected) :
02592                 getcolor(palidx_generic_input_focused);
02593 }
02594 
02595 void ht_listpopup::getdata(ht_object_stream *s)
02596 {
02597         listpopup->getdata(s);
02598 }
02599 
02600 char *ht_listpopup::gettext()
02601 {
02602         ht_listpopup_dialog_data d;
02603         listpopup->databuf_get(&d, sizeof d);
02604         return d.cursor_string;
02605 }
02606 
02607 void ht_listpopup::handlemsg(htmsg *msg)
02608 {
02609         if (msg->msg==msg_keypressed) {
02610                 switch (msg->data1.integer) {
02611                         case K_Up: {
02612                                 int r;
02613                                 ht_listpopup_dialog_data d;
02614                                 listpopup->databuf_get(&d, sizeof d);
02615                                 listpopup->select_prev();
02616                                 r=run_listpopup();
02617                                 clearmsg(msg);
02618                                 if (!r) listpopup->databuf_set(&d, sizeof d);
02619                                 return;
02620                         }
02621                         case K_Down: {
02622                                 int r;
02623                                 ht_listpopup_dialog_data d;
02624                                 listpopup->databuf_get(&d, sizeof d);
02625                                 listpopup->select_next();
02626                                 r=run_listpopup();
02627                                 clearmsg(msg);
02628                                 if (!r) listpopup->databuf_set(&d, sizeof d);
02629                                 return;
02630                         }                               
02631                 }
02632         }
02633         ht_statictext::handlemsg(msg);
02634 }
02635 
02636 int ht_listpopup::run_listpopup()
02637 {
02638         int r;
02639         listpopup->relocate_to(this);
02640         r=listpopup->run(false);
02641         listpopup->unrelocate_to(this);
02642         return r;
02643 }
02644 
02645 void ht_listpopup::insertstring(char *string)
02646 {
02647         listpopup->insertstring(string);
02648 }
02649 
02650 void ht_listpopup::setdata(ht_object_stream *s)
02651 {
02652         listpopup->setdata(s);
02653 }
02654 
02655 /*
02656  *      CLASS ht_listbox_ptr
02657  */
02658 
02659 ht_listbox_ptr::ht_listbox_ptr(ht_listbox *_listbox)
02660 {
02661         listbox=_listbox;
02662 }
02663 
02664 ht_listbox_ptr::~ht_listbox_ptr()
02665 {
02666 }
02667 
02668 /*
02669  *      CLASS ht_label
02670  */
02671 
02672 void ht_label::init(bounds *b, const char *_text, ht_view *_connected)
02673 {
02674         ht_view::init(b, VO_POSTPROCESS, 0);
02675         text = ht_strdup(_text);
02676         magicchar = strchr(text, '~');
02677         if (magicchar) {
02678                 int l = strlen(text);
02679                 memmove(magicchar, magicchar+1, l-(magicchar-text));
02680         }
02681         connected=_connected;
02682         if (magicchar) {
02683                 shortcut = ht_metakey((ht_key)*magicchar);
02684         } else shortcut = K_INVALID;
02685 }
02686 
02687 void ht_label::done()
02688 {
02689         if (text) free(text);
02690         ht_view::done();
02691 }
02692 
02693 char *ht_label::defaultpalette()
02694 {
02695         return palkey_generic_dialog_default;
02696 }
02697 
02698 void ht_label::draw()
02699 {
02700         vcp c;
02701         vcp sc = getcolor(palidx_generic_text_shortcut);
02702         if (connected->focused) {
02703                 c = getcolor(palidx_generic_text_focused);
02704         } else {
02705                 c = getcolor(palidx_generic_text_unfocused);
02706         }
02707         buf_lprint(0, 0, c, size.w, text);
02708         if (magicchar) buf_printchar(magicchar-text, 0, sc, *magicchar);
02709 }
02710 
02711 void ht_label::handlemsg(htmsg *msg)
02712 {
02713         if (msg->type==mt_postprocess) {
02714                 if (msg->msg==msg_keypressed) {
02715                         if ((shortcut!=-1) && (msg->data1.integer==shortcut)) {
02716                                 app->focus(connected);
02717                                 dirtyview();
02718                                 clearmsg(msg);
02719                                 return;
02720                         }
02721                 }
02722         } else ht_view::handlemsg(msg);
02723 }
02724 
02725 /*
02726  *      CLASS ht_progress_indicator
02727  */
02728 
02729 void    ht_progress_indicator::init(bounds *b, char *hint)
02730 {
02731         ht_window::init(b, NULL, 0);
02732 
02733         bounds c=*b;
02734 
02735         c.x=1;
02736         c.y=1;
02737         c.w-=c.x+2;
02738         c.h-=c.y+3;
02739         text=new ht_statictext();
02740         text->init(&c, NULL, align_center, true);
02741         insert(text);
02742 
02743         c.y+=2;
02744         c.h=1;
02745         ht_statictext *t=new ht_statictext();
02746         t->init(&c, hint, align_center);
02747         insert(t);
02748 }
02749 
02750 char *ht_progress_indicator::defaultpalette()
02751 {
02752         return palkey_generic_dialog_default;
02753 }
02754 
02755 void ht_progress_indicator::settext(const char *t)
02756 {
02757         text->settext(t);
02758 }
02759 
02760 /*
02761  *      CLASS ht_color_block
02762  */
02763 
02764 int vcs[16]={VC_BLACK, VC_BLUE, VC_GREEN, VC_CYAN, VC_RED, VC_MAGENTA, VC_YELLOW, VC_WHITE,   VC_LIGHT(VC_BLACK), VC_LIGHT(VC_BLUE), VC_LIGHT(VC_GREEN), VC_LIGHT(VC_CYAN), VC_LIGHT(VC_RED), VC_LIGHT(VC_MAGENTA), VC_LIGHT(VC_YELLOW), VC_LIGHT(VC_WHITE)};
02765 
02766 void ht_color_block::init(bounds *b, int selected, int Flags)
02767 {
02768         ht_view::init(b, VO_OWNBUFFER | VO_SELECTABLE, 0);
02769         VIEW_DEBUG_NAME("ht_color_block");
02770         flags=Flags;
02771         
02772         ht_color_block_data d;
02773         d.color = selected;
02774         databuf_set(&d, sizeof d);
02775         if (flags & cf_light) colors=16; else colors=8;
02776 }
02777 
02778 void ht_color_block::done()
02779 {
02780         ht_view::done();
02781 }
02782 
02783 int ht_color_block::datasize()
02784 {
02785         return sizeof (ht_color_block_data);
02786 }
02787 
02788 char *ht_color_block::defaultpalette()
02789 {
02790         return palkey_generic_dialog_default;
02791 }
02792 
02793 void ht_color_block::draw()
02794 {
02795         clear(getcolor(palidx_generic_body));
02796         dword cursor=VCP(focused ? VC_LIGHT(VC_WHITE) : VC_BLACK, VC_TRANSPARENT);
02797         for (int i=0; i<colors; i++) {
02798                 buf_printchar((i%4)*3+1, i/4, VCP(vcs[i], VC_TRANSPARENT), CHAR_FILLED_F);
02799                 buf_printchar((i%4)*3+2, i/4, VCP(vcs[i], VC_BLACK), CHAR_FILLED_M);
02800                 if (i==color) {
02801                         buf_printchar((i%4)*3, i/4, cursor, '>');
02802                         buf_printchar((i%4)*3+3, i/4, cursor, '<');
02803                 }
02804         }
02805         if (flags & cf_transparent) {
02806                 buf_print(1, (colors==8) ? 2 : 4, VCP(VC_BLACK, VC_TRANSPARENT), "transparent");
02807                 if (color==-1) {
02808                         buf_printchar(0, (colors==8) ? 2 : 4, cursor, '>');
02809                         buf_printchar(12, (colors==8) ? 2 : 4, cursor, '<');
02810                 }
02811         }
02812 }
02813 
02814 void ht_color_block::getdata(ht_object_stream *s)
02815 {
02816         s->putIntDec((color==-1) ? VC_TRANSPARENT : vcs[color], 4, NULL);
02817 }
02818 
02819 void ht_color_block::handlemsg(htmsg *msg)
02820 {
02821         if (msg->msg==msg_keypressed) {
02822                 switch (msg->data1.integer) {
02823                         case K_Left:
02824                                 if (color==-1) color=(flags & cf_light) ? 15 : 7; else
02825                                         if (color%4-1>=0) color--;
02826                                 dirtyview();
02827                                 clearmsg(msg);
02828                                 return;
02829                         case K_Right:
02830                                 if (color==-1) color=(flags & cf_light) ? 15 : 7; else
02831                                         if (color%4+1<=3) color++;
02832                                 dirtyview();
02833                                 clearmsg(msg);
02834                                 return;
02835                         case K_Up:
02836                                 if (color==-1) color=(flags & cf_light) ? 15 : 7; else
02837                                         if (color-4>=0) color-=4;
02838                                 dirtyview();
02839                                 clearmsg(msg);
02840                                 return;
02841                         case K_Down:
02842                                 if (color!=-1)
02843                                         if (color+4<colors) color+=4; else color=-1;
02844                                 dirtyview();
02845                                 clearmsg(msg);
02846                                 return;
02847                 }
02848         }
02849         ht_view::handlemsg(msg);
02850 }
02851 
02852 void ht_color_block::setdata(ht_object_stream *s)
02853 {
02854         int c=s->getIntDec(4, NULL);
02855         if (c==VC_TRANSPARENT) color=-1; else {
02856                 for (int i=0; i<16; i++) if (vcs[i]==c) {
02857                         color=i;
02858                         break;
02859                 }
02860         }
02861         dirtyview();
02862 }
02863 
02864 void center_bounds(bounds *b)
02865 {
02866         bounds c;
02867         app->getbounds(&c);
02868         b->x=(c.w-b->w)/2;
02869         b->y=(c.h-b->h)/2;     
02870 }
02871 

Generated on Fri May 7 21:15:32 2004 by doxygen 1.3.5