diff --git a/efiler/EDE_FileView.h b/efiler/EDE_FileView.h index 3837933..b20282c 100644 --- a/efiler/EDE_FileView.h +++ b/efiler/EDE_FileView.h @@ -14,19 +14,32 @@ #ifndef EDE_FileView_H #define EDE_FileView_H -#include -#include + + +#define USE_FLU_WRAP_GROUP + + +#include // for FL_PATH_MAX +#include +#include +#include +#include +#include +#include #include #include +#include #include "EDE_Browser.h" -// This class provides the generic FileView class and two -// derived classes called FileIconView and FileDetailsView. -// These classes are interchangeable, so that application -// can just declare FileView* and use. -// FileView is populated with FileItem's. +#ifdef USE_FLU_WRAP_GROUP +# include "Flu_Wrap_Group.h" +#else +# include +#endif + + struct FileItem { edelib::String name; // just the name @@ -45,6 +58,625 @@ typedef void (rename_callback_type)(const char*); typedef void (paste_callback_type)(const char*); +#define ICONW 70 +#define ICONH 80 +// Spacing to use between icons +#define ICON_SPACING 5 + +// How many pixels from selection edge will be ignored +// (e.g. if selection laso only touches a widget with <5px, it will not be selected) +#define SELECTION_EDGE 5 + +#ifdef USE_FLU_WRAP_GROUP +class FileIconView_ : public Flu_Wrap_Group { +#else +class FileIconView_ : public edelib::ExpandableGroup { +#endif +private: + // private vars for handling selection and focus + // because group doesn't do it + int focused; + int* m_selected; + + rename_callback_type* rename_callback_; + paste_callback_type* paste_callback_; + Fl_Callback* context_callback_; + + int select_x1,select_y1,select_x2,select_y2; + + Fl_Button* find_button(edelib::String realpath) { + for (int i=0; iuser_data(); + if (realpath==tmp) return b; + } + return 0; + } +public: +#ifdef USE_FLU_WRAP_GROUP + FileIconView_(int X, int Y, int W, int H, char*label=0) : Flu_Wrap_Group(X,Y,W,H,label) +#else + FileIconView_(int X, int Y, int W, int H, char*label=0) : edelib::ExpandableGroup(X,Y,W,H,label) +#endif + { + end(); + box(FL_DOWN_BOX); + color(FL_BACKGROUND2_COLOR); +#ifdef USE_FLU_WRAP_GROUP + spacing(ICON_SPACING,ICON_SPACING); +#endif + + select_x1=select_y1=select_x2=select_y2=0; + focused=0; + m_selected = 0; + + rename_callback_ = 0; + paste_callback_ = 0; + context_callback_ = 0; + } + void insert(int row, FileItem *item) { + // update list of selected[] items + if (!m_selected) + m_selected = (int*)malloc(sizeof(int)*(children()+1)); + else + m_selected = (int*)realloc(m_selected,sizeof(int)*(children()+1)); + m_selected[children()]=0; + + Fl_Button* b = new Fl_Button(0,0,ICONW,ICONH); + b->box(FL_FLAT_BOX); + b->color(FL_BACKGROUND2_COLOR); + b->align(FL_ALIGN_INSIDE|FL_ALIGN_CENTER|FL_ALIGN_WRAP|FL_ALIGN_CLIP); + + // Set the label + char buffer[FL_PATH_MAX]; + uint j=0; + for (uint i=0; iname.length(); i++,j++) { + buffer[j] = item->name[i]; + buffer[j+1] = '\0'; + if (buffer[j] == '@') { // escape @ + buffer[++j] = '@'; + buffer[j+1] = '\0'; + } + b->copy_label(buffer); + int lw =0, lh = 0; + fl_measure(b->label(), lw, lh); + if (lw>ICONW) { + if (j==i+2) { // already added 2 newlines + buffer[j-2]='.'; + buffer[j-1]='.'; + buffer[j]='.'; + buffer[j+1]='\0'; + j+=2; + break; // for + } else { // add newline + buffer[j+1]=buffer[j]; + buffer[j]='\n'; + buffer[j+2]='\0'; + j++; + } + } + } + while (j<=item->name.length()+2){ + buffer[j++]='\n'; + //buffer[j++]='L'; + } + buffer[j]='\0'; + b->copy_label(buffer); + + // Tooltip text + edelib::String tooltip = _("Name: ")+item->name; + if (item->size != "") tooltip += _("\nSize: ")+item->size; + tooltip += _("\nType: ")+item->description+_("\nDate: ")+item->date+_("\nPermissions: ")+item->permissions; + b->tooltip(strdup(tooltip.c_str())); + b->user_data(strdup(item->realpath.c_str())); + + // Set icon + edelib::String icon = edelib::IconTheme::get(item->icon.c_str(),edelib::ICON_SIZE_MEDIUM); + if (icon=="") icon = edelib::IconTheme::get("misc",edelib::ICON_SIZE_MEDIUM,edelib::ICON_CONTEXT_MIMETYPE); + b->image(Fl_Shared_Image::get(icon.c_str())); + +#ifdef USE_FLU_WRAP_GROUP + Flu_Wrap_Group::insert(*b,row); +#else + edelib::ExpandableGroup::insert(*b,row); +#endif + //insert(*b,row); -- why doesn't this work? + redraw(); + } + void add(FileItem *item) { insert(children()+1, item); } + + void remove(FileItem *item) { + Fl_Button* b = find_button(item->realpath); + if (b) { +#ifdef USE_FLU_WRAP_GROUP + Flu_Wrap_Group::remove(*b); // note that FWG requires to dereference the pointer +#else + edelib::ExpandableGroup::remove(b); +#endif + //remove(b); + delete b; + } + } + + void remove(int row) { + if (row<1 || row>children()) return; + Fl_Button* b = (Fl_Button*)child(row-1); +#ifdef USE_FLU_WRAP_GROUP + Flu_Wrap_Group::remove(*b); // note that FWG requires to dereference the pointer +#else + edelib::ExpandableGroup::remove(b); +#endif + //remove(b); + delete b; + } + + + void update(FileItem *item) { + Fl_Button* b = find_button(item->realpath); + if (!b) return; + + // Tooltip text + edelib::String tooltip = _("Name: ")+item->name+_("\nSize: ")+item->size+_("\nType: ")+item->description+_("\nDate: ")+item->date+_("\nPermissions: ")+item->permissions; + b->tooltip(strdup(tooltip.c_str())); + + // Set icon + edelib::String icon = edelib::IconTheme::get(item->icon.c_str(),edelib::ICON_SIZE_MEDIUM); + if (icon=="") icon = edelib::IconTheme::get("misc",edelib::ICON_SIZE_MEDIUM,edelib::ICON_CONTEXT_MIMETYPE); + b->image(Fl_Shared_Image::get(icon.c_str())); + + b->redraw(); + } + + // This is needed because update() uses path to find item in list + void update_path(const char* oldpath,const char* newpath) { + Fl_Button* b = find_button(oldpath); + if (!b) return; + b->user_data(strdup(newpath)); + } + + // Set item to "disabled" + void gray(int row) { + if (row<1 || row>children()) return; + Fl_Button* b = (Fl_Button*)child(row-1); + // FIXME this also means that item can't be selected + b->deactivate(); + } + // Set item to "enabled" + void ungray(int row) { + if (row<1 || row>children()) return; + Fl_Button* b = (Fl_Button*)child(row-1); + b->activate(); + } + + // Setup callback that will be used when renaming and dnd + void rename_callback(rename_callback_type* cb) { rename_callback_ = cb; } + void paste_callback(paste_callback_type* cb) { paste_callback_ = cb; } + void context_callback(Fl_Callback* cb) { context_callback_ = cb; } + + // Item real path (data value) + const char* path(int row) { + if (row<1 || row>children()) return 0; + Fl_Button* b = (Fl_Button*)child(row-1); + return (const char*)b->user_data(); + } + + // Is item selected? + int selected(int row) { + if (row<1 || row>children()) return 0; + int i=0; + while(m_selected[i]!=0) + if (m_selected[i++]==row) return 1; + return 0; + } + + // Select item (if value=1) or unselect (if value=0) + void select(int row, int value) { + if (row<1 || row>children()) return; + if (!m_selected) return; // shouldn't happen + set_focus(row); + int i=0; + Fl_Button* b = (Fl_Button*)child(row-1); + if (value) { + while (m_selected[i++]!=0); + m_selected[i]=row; + + b->color(FL_SELECTION_COLOR); + b->labelcolor(fl_contrast(FL_FOREGROUND_COLOR,FL_SELECTION_COLOR)); + b->redraw(); + } else { + while (m_selected[i]!=0) { + if (m_selected[i]==row) { + int j=i; + while (m_selected[j]!=0) { + m_selected[j]=m_selected[j+1]; + j++; + } + break; + } + i++; + } + + b->color(FL_BACKGROUND2_COLOR); + b->labelcolor(FL_FOREGROUND_COLOR); + b->redraw(); + } + } + + // Return nr. of widget that has keyboard focus + int get_focus() { +/*#ifdef USE_FLU_WRAP_GROUP +fprintf( stderr, "---- get_focus()=%d\n", focused); + return focused; +#else*/ + Fl_Widget* focus = Fl::focus(); + int i = find(focus); // Fl_Group method + if (ichildren()) return; + Fl_Button* b = (Fl_Button*)child(row-1); + +#ifdef USE_FLU_WRAP_GROUP + // scroll_to() will scroll widget to the top of view + // I prefer that view is scrolled just enough so icon is visible + // FIXME: sometimes b->y() is so large that it wraps around and becomes positive + if (b->y()+b->h() > y()+h()) { + int scrollto = scrollbar.value() + (b->y()+b->h()-y()-h())+1; +fprintf (stderr, "by: %d bh: %d y: %d h: %d sv: %d\n", b->y(), b->h(), y(), h(), scrollbar.value()); + ((Fl_Valuator*)&scrollbar)->value(scrollto); + redraw(); + draw(); // we need to relayout the group so that b->y() value is updated for next call + } + if (b->y() < y()) + scroll_to(b); +#else + // Not tested and probably broken: + Fl_Scrollbar* s = get_scroll(); + if (b->y() > s->value()+h()) { + // Widget is below current view + scrolly(b->y()+b->h()-h()); + } else if (b->y() < s->value()) { + // Widget is above current view + scrolly(b->y()); + } + // else { widget is visible, do nothing } +#endif + } + + // Set keyboard focus to given item + void set_focus(int row) { +fprintf( stderr, "---- set_focus(%d)\n", row); + if (row<1 || row>children()) return; + Fl_Button* b = (Fl_Button*)child(row-1); + b->take_focus(); + show_item(row); + focused=row; + } + + + // Overloaded handle() method, see inline comments for details + int handle(int e) { +//fprintf (stderr, " -- FileIconView - Event %d\n",e); + + // Fixes for focus management + // fltk provides focus management for members of Fl_Group, but it has minor problems: + // - when pressing Alt+Tab, focused widget is forgotten + // - if no widget is focused, arrow keys will navigate outside group + // - Tab has same effect as right arrow + + + if (Fl::focus()->inside(this)) { // is focus inside? + int k = Fl::event_key(); +//fprintf(stderr, "event: %d key: %d\n",e,k); + if (k==FL_Up || k==FL_Down || k==FL_Left || k==FL_Right) { + // Wrap around + // FL_KEYDOWN happens only if key is otherwise unhandled + if (e==FL_KEYDOWN) { + int x = get_focus()-1; + Fl_Widget* b = child(x); + Fl_Widget* b2; + if (k==FL_Up) b2=above(b); + if (k==FL_Down) b2=below(b); + // Bug in Flu_Wrap_Group - inconsistent behavior of below() + if (k==FL_Down && b2==b) b2=child(children()-1); + if (k==FL_Left) b2=left(b); + if (k==FL_Right) b2=next(b); + if (((k==FL_Up) || (k==FL_Left)) && x==0) + b2=child(children()-1); + if (((k==FL_Down) || (k==FL_Right)) && x==children()-1) + b2=child(0); + for (int i=0; ilabel()); + // Because widgets can be *very* nested, we go straight + // to window() + Fl_Group* master=window(); + Fl_Widget* jumpto=0; + int i=0; + while (jumpto==0 && master!=this) { + jumpto=master->child(i); +fprintf (stderr, " -- (%s)\n", jumpto->label()); + if (this->inside(jumpto) || !jumpto->visible()) + jumpto=0; + i++; + if (i==master->children()) { + int j; + for (j=0; jchildren(); j++) + if (master->child(j)->visible()) break; + if (j==master->children()) {// nothing is visible!? + master=(Fl_Group*)this; +fprintf (stderr, "WTF\n"); + }else{ + master=(Fl_Group*)master->child(j); +fprintf (stderr, " -> [%s]\n", master->label()); +} + i=0; + } + if (jumpto!=0 && !jumpto->take_focus()) + jumpto=0; // widget refused focus, keep searching + } +fprintf (stderr, "[X]\n"); + // if this is the only widget, do nothing + return 1; + } + } + if (e==FL_FOCUS) { + // Restore focused widget after losing focus + if (focused) set_focus(focused); + return 1; + } + +/*#ifdef USE_FLU_WRAP_GROUP + int k = Fl::event_key(); +// if (e==FL_KEYBOARD) fprintf (stderr, "Key: %d", k); + if ((e==FL_KEYUP || e==FL_KEYBOARD) && (k==FL_Up || k==FL_Down || k==FL_Left || k==FL_Right)) { + Fl_Widget* nextw=0; + if (focused) { + Fl_Widget* currentw = child(focused-1); + switch(k) { // Flu_Wrap_Group methods: + case FL_Up: + nextw = above(currentw); break; + case FL_Down: + nextw = below(currentw); break; + case FL_Left: + nextw = left(currentw); break; + case FL_Right: + nextw = next(currentw); break; + } + // Flu_Wrap_Group bug: all methods will wrap around EXCEPT + // Flu_Wrap_Group::below() ?! + if (k==FL_Down && nextw==currentw) + nextw = child(0); + } +fprintf (stderr, "Event k: %d focused: %d\n", k, focused); + + if (focused && nextw) + for (int i=0; ix() && Fl::event_x() < x()+w()-Fl::scrollbar_size()) { + return 1; + } + // We accept focus (defaults to 0 with FL_GROUP) + if (e==FL_FOCUS) return 1; + + // Do callback on enter key + // (because icons don't have callbacks) + if (e==FL_KEYBOARD && Fl::event_key()==FL_Enter) { + do_callback(); + return 1; + } + + // Drag to select (a.k.a. "laso") operation + // Draw a dashed line around icons + static bool laso=false; + if (e==FL_DRAG) { +fprintf (stderr, "FL_DRAG! "); + if (!laso) { +fprintf (stderr, "- begin.\n"); + laso=true; + // Set coordinates for selection box (drawn in draw()) + select_x1=select_x2=Fl::event_x(); + select_y1=select_y2=Fl::event_y(); + } else { +fprintf (stderr, "- box (%d,%d,%d,%d).\n",select_x1,select_y1,select_x2,select_y2); + select_x2=Fl::event_x(); + select_y2=Fl::event_y(); + redraw(); + } + return 1; + } + + // Mouse button released + if (e==FL_RELEASE) { +fprintf (stderr, "FL_RELEASE! "); + // Unselect everything unless Shift or Ctrl is held + if (!Fl::event_state(FL_SHIFT) && !Fl::event_state(FL_CTRL)) { + for (int i=0;icolor(FL_BACKGROUND2_COLOR); + b->labelcolor(FL_FOREGROUND_COLOR); + } + redraw(); + int i=0; + while (m_selected[i]!=0) m_selected[i++]=0; + } + + // Stop laso operation + if (laso) { +fprintf (stderr, "- stop drag.\n"); + laso=false; + + // Order coordinates + int tmp; + if (select_x1>select_x2) { tmp=select_x1; select_x1=select_x2; select_x2=tmp; } + if (select_y1>select_y2) { tmp=select_y1; select_y1=select_y2; select_y2=tmp; } + + // Don't include the edges + select_x1 += SELECTION_EDGE; + select_y1 += SELECTION_EDGE; + select_x2 -= SELECTION_EDGE; + select_y2 -= SELECTION_EDGE; +fprintf(stderr, "After fixing the box coords: (%d,%d,%d,%d)\n", select_x1, select_y1, select_x2, select_y2); + + // Calculate which buttons were lasoed + int i; + for (i=0; ix()+w->w(); + int wy2 = w->y()+w->h(); + if (select_x2>w->x() && select_x1w->y() && select_y1label(), w->x(), w->y(), wx2, wy2); + } + } + // TODO: add code for Shift key + + select_x1=select_x2=select_y1=select_y2=0; + redraw(); + + // Single click + } else { + // Find child that was clicked + int i; + for (i=0; itake_focus(); // Remove focus from all buttons + focused=0; + } + } + + // Right button - call context menu + if (Fl::event_button() == 3) { + Fl::event_is_click(0); // prevent doubleclicking with right button + if (context_callback_) context_callback_(this, (void*)path(get_focus())); + } + + // Double-click operation + if (Fl::event_clicks()) { + do_callback(); + } + } +/* + // Check if it is drag + static bool clicked=false; + if (e==FL_PUSH) { +fprintf (stderr, "FL_PUSH %d %d...\n",Fl::event_is_click(),Fl::event_clicks()); + clicked=true; + return 1; + } else if (e != FL_DRAG && e != FL_NO_EVENT && clicked) { +fprintf (stderr, "-- triggered click %d\n",e); + clicked=false; + // Unselect everything unless Shift or Alt is held + if (!Fl::event_key(FL_Shift_L) && !Fl::event_key(FL_Shift_R) && !Fl::event_key(FL_Shift_L)) + for (int i=0; i0 && select_y1>0) { + fl_color(33); + fl_line_style(FL_DASH); + fl_line(select_x1,select_y1,select_x1,select_y2); + fl_line(select_x1,select_y2,select_x2,select_y2); + fl_line(select_x2,select_y2,select_x2,select_y1); + fl_line(select_x2,select_y1,select_x1,select_y1); + fl_line_style(0); + } + } + + // Override clear so that we can empty selected & focused values + void clear() { + focused=0; + if (m_selected) free(m_selected); + m_selected = 0; +#ifdef USE_FLU_WRAP_GROUP + Flu_Wrap_Group::clear(); +#else + edelib::ExpandableGroup::clear(); +#endif + } +}; class FileDetailsView_ : public EDE_Browser { @@ -306,10 +938,14 @@ fprintf (stderr, "value: %s\n", value.c_str()); bucket.add(ntext); // doesn't work - //Fl_Image* im = get_icon(row); + Fl_Image* im = get_icon(row)->copy(); + //im->refresh(); //im->uncache(); // doesn't work + //im->color_average(FL_BACKGROUND_COLOR, 1.0); + //im->data(im->data(),im->count()); + set_icon(row,im); - //redraw(); // OPTIMIZE + redraw(); // OPTIMIZE } @@ -484,12 +1120,14 @@ fprintf(stderr, "Call FileView::clear()\n"); bucket.empty(); EDE_Browser::clear(); } + + int visible() { return Fl_Widget::visible(); } }; -class FileView : public Fl_Group { +/*class FileView : public Fl_Group { public: FileView(int X, int Y, int W, int H, char*label=0) : Fl_Group(X,Y,W,H,label) {} @@ -548,9 +1186,87 @@ public: const char* text(int i) { return browser->text(i); } void text(int i, const char* c) { return browser->text(i,c); } uchar column_char() { return browser->column_char(); } +};*/ + +enum FileViewType { + FILE_DETAILS_VIEW, + FILE_ICON_VIEW }; +class FileDetailsView : public Fl_Group { +private: + FileDetailsView_* browser; + FileIconView_* icons; + FileViewType m_type; +public: + FileDetailsView(int X, int Y, int W, int H, char*label=0) : Fl_Group(X,Y,W,H,label) { + browser = new FileDetailsView_(X,Y,W,H,label); + browser->end(); +// browser->hide(); + icons = new FileIconView_(X,Y,W,H,label); + icons->end(); + end(); + + // Set default to FILE_DETAILS_VIEW + icons->hide(); + m_type=FILE_DETAILS_VIEW; + } + + void setType(FileViewType t) { + m_type=t; + if (t==FILE_DETAILS_VIEW) { + icons->hide(); + //browser->show(); + } + if (t==FILE_ICON_VIEW) { + //browser->hide(); + icons->show(); + //redraw(); + } + } + FileViewType getType() { + return m_type; + } + + // View methods + void insert(int row, FileItem *item) { browser->insert(row,item); icons->insert(row,item); } + void add(FileItem *item) { browser->add(item); icons->add(item); } + void remove(FileItem *item) { browser->remove(item); icons->remove(item); } + void update(FileItem *item) { browser->update(item); icons->update(item); } + + void update_path(const char* oldpath,const char* newpath) { browser->update_path(oldpath,newpath); icons->update_path(oldpath,newpath); } + + void gray(int row) { browser->gray(row); icons->gray(row); } + void ungray(int row) { browser->ungray(row); icons->ungray(row); } + + void rename_callback(rename_callback_type* cb) { browser->rename_callback(cb); icons->rename_callback(cb); } + void paste_callback(paste_callback_type* cb) { browser->paste_callback(cb); icons->paste_callback(cb); } + void context_callback(Fl_Callback* cb) { browser->context_callback(cb); icons->context_callback(cb); } + + // Browser methods + const char* path(int i) { if (m_type==FILE_DETAILS_VIEW) return (const char*)browser->data(i); else return icons->path(i); } + int size() { if (m_type==FILE_DETAILS_VIEW) return browser->size(); else return icons->children();} + int selected(int i) { if (m_type==FILE_DETAILS_VIEW) return browser->selected(i); else return icons->selected(i); } + void select(int i, int k) { browser->select(i,k); browser->middleline(i); icons->select(i,k); icons->show_item(i); } + int get_focus() { if (m_type==FILE_DETAILS_VIEW) return browser->get_focus(); else return icons->get_focus(); } + void set_focus(int i) { browser->set_focus(i); icons->set_focus(i);} + void remove(int i) { browser->remove(i); icons->remove(i);} + void clear() { browser->clear(); icons->clear();} + void callback(Fl_Callback*cb) { browser->callback(cb); icons->callback(cb);} + int take_focus() { if (m_type==FILE_DETAILS_VIEW) return browser->take_focus(); else return icons->take_focus(); } + + // These methods are used by do_rename() + const char* text(int i) { return browser->text(i); } + void text(int i, const char* c) { return browser->text(i,c); } + uchar column_char() { return browser->column_char(); } + + // Overloaded... + //int handle(int e) { if +}; + + + #endif /* $Id */ diff --git a/efiler/efiler.cpp b/efiler/efiler.cpp index 5b889cf..dcfcd34 100644 --- a/efiler/efiler.cpp +++ b/efiler/efiler.cpp @@ -28,7 +28,6 @@ #include #include // for fl_dir_chooser, used in "Open location" #include -#include #include // location bar #include @@ -41,6 +40,7 @@ #include "EDE_DirTree.h" // directory tree #include "Util.h" // ex-edelib #include "ede_ask.h" // replacement for fl_ask +//#include "Ask.h" #include "fileops.h" // file operations #include "filesystem.h" // filesystem support @@ -77,6 +77,62 @@ const int statusbar_width = 400; int default_tree_width=150; +/*----------------------------------------------------------------- + Some improvements to Fl_File_Input, that should be added + upstream: + * enable to set shortcut in label (STR 1770 for Fl_Input_) + * navigate using Ctrl+arrow (here we jump to dir. sep.) +-------------------------------------------------------------------*/ + +class My_File_Input : public Fl_File_Input { + int shortcut_; +public: + My_File_Input(int X,int Y,int W,int H,const char *label=0) : Fl_File_Input(X,Y,W,H,label) { + set_flag(SHORTCUT_LABEL); + shortcut_ = 0; + } + + int shortcut() const {return shortcut_;} + void shortcut(int s) {shortcut_ = s;} + + int handle(int e) { + if (e==FL_SHORTCUT) { + if (!(shortcut() ? Fl::test_shortcut(shortcut()) : test_shortcut())) return 0; + if (Fl::visible_focus() && handle(FL_FOCUS)) Fl::focus(this); + return 1; + } + if (e==FL_KEYDOWN) { + if (Fl::event_state(FL_CTRL)) { + const char* v = value(); + if (Fl::event_key()==FL_Left) { + for (uint i=position()-2; i>=0; i--) + if (v[i]=='/') { + if (Fl::event_state(FL_SHIFT)) + position(i+1,mark()); + else + position(i+1,i+1); + break; + } + return 1; // don't go out + } + if (Fl::event_key()==FL_Right) { + for (uint i=position()+1; iname = n; item->realpath = fullpath; item->date = nice_time(stat_buffer.st_mtime); - item->permissions = ""; // todo + item->permissions = permission_text(stat_buffer.st_mode,stat_buffer.st_uid,stat_buffer.st_gid); if (strcmp(n,"..")==0) { item->icon = "undo"; item->description = "Go up"; @@ -320,10 +452,12 @@ fprintf (stderr, "ICON: %s !!!!!\n", icon.c_str()); Main menu and other callbacks -------------------------------------------------------------------*/ -// This callback is called by doubleclicking on file list, by main and context menu +// This callback is called by doubleclicking on file list, by main menu and context menu void open_cb(Fl_Widget*w, void*data) { fprintf (stderr,"cb\n"); + if (Fl::event_clicks() || Fl::event_key() == FL_Enter || w==main_menu || w==context_menu) { + fprintf (stderr,"enter\n"); //if (Fl::event_clicks()) fprintf(stderr, "clicks\n"); //if (Fl::event_key()==FL_Enter) fprintf(stderr, "ekey\n"); @@ -343,7 +477,7 @@ fprintf (stderr,"enter\n"); return; } - // Call opener + // Find opener mime_resolver.set(path); char* opener = simpleopener(mime_resolver.type().c_str()); @@ -360,7 +494,7 @@ fprintf (stderr,"enter\n"); if (opener) { int k=edelib::run_program(o2,false); fprintf(stderr, "retval: %d\n", k); } else - statusbar->copy_label(tsprintf(_("No program to open %s!"), fl_filename_name(view->path(view->get_focus())))); + statusbar->copy_label(tsprintf(_("No program to open %s!"), fl_filename_name(path))); rlim->rlim_cur = old_rlimit; setrlimit (RLIMIT_CORE, rlim); @@ -372,14 +506,12 @@ fprintf (stderr,"enter\n"); // Main menu callbacks -void location_cb(Fl_Widget*, void*) { - const char *dir = fl_dir_chooser(_("Choose location"),current_dir); - if (dir) loaddir(dir); +void new_cb(Fl_Widget*, void*) { + // FIXME: use program path + edelib::run_program(tsprintf("efiler %s",current_dir),false); } -void new_cb(Fl_Widget*, void*) { edelib::run_program(tsprintf("efiler %s",current_dir),false); } - -void quit_cb(Fl_Widget*, void*) {exit(0);} +void quit_cb(Fl_Widget*, void*) { win->hide(); } void cut_cb(Fl_Widget*, void*) { do_cut_copy(false); } void copy_cb(Fl_Widget*, void*) { do_cut_copy(true); } @@ -391,14 +523,12 @@ void showtree_cb(Fl_Widget*, void*) { showtree = !showtree; if (!showtree) { tree_width = dirtree->w(); - tile->position(default_tree_width, 1, 1, 1); // NOTE! + tile->position(default_tree_width, 1, 1, 1); // NOTE this doesn't always work! fprintf(stderr, "Hide tree: %d\n", tree_width); -// showtree->clear(); } else { int currentw = dirtree->w(); tile->position(currentw, 1, tree_width, 1); fprintf(stderr, "Show tree: %d %d\n", currentw, tree_width); -// showtree->set(); } } @@ -412,12 +542,15 @@ void locationbar_cb(Fl_Widget*, void*) { location_bar->show(); location_bar->resize(0, menubar_height, win->w(), location_bar_height); tile->resize(0, menubar_height+location_bar_height, win->w(), win->h()-menubar_height-location_bar_height-statusbar_height); +// win->resizable(tile); // win keeps old tile size... win->redraw(); } else { location_bar->hide(); // location_bar->resize(0, menubar_height, win->w(), 0); tile->resize(0, menubar_height, win->w(), win->h()-menubar_height-statusbar_height); win->redraw(); + win->resizable(tile); + win->redraw(); } } @@ -435,14 +568,25 @@ void case_cb(Fl_Widget*, void*) { loaddir(current_dir); } -void dirsfirst_cb(Fl_Widget*, void*) { dirsfirst=!dirsfirst; loaddir(current_dir); } +void dirsfirst_cb(Fl_Widget*, void*) { + dirsfirst=!dirsfirst; + loaddir(current_dir); +} // dummy callbacks - TODO void ow_cb(Fl_Widget*, void*) { fprintf(stderr, "callback\n"); } // make a list of openers void pref_cb(Fl_Widget*, void*) { fprintf(stderr, "callback\n"); } -void iconsview_cb(Fl_Widget*, void*) { fprintf(stderr, "callback\n"); } -void listview_cb(Fl_Widget*, void*) { fprintf(stderr, "callback\n"); } +void iconsview_cb(Fl_Widget*, void*) { +//fprintf(stderr, "callback\n"); +view->setType(FILE_ICON_VIEW); +loaddir(current_dir); +} +void listview_cb(Fl_Widget*, void*) { +//fprintf(stderr, "callback\n"); +view->setType(FILE_DETAILS_VIEW); +loaddir(current_dir); +} void about_cb(Fl_Widget*, void*) { fprintf(stderr, "callback\n"); } void aboutede_cb(Fl_Widget*, void*) { fprintf(stderr, "callback\n"); } @@ -461,12 +605,12 @@ void tree_cb(Fl_Widget*, void*) { // and callbacks for shortcut buttons // location_input is set to FL_WHEN_CHANGED void location_input_cb(Fl_Widget*, void*) { -fprintf (stderr, "location_input_cb %d\n",Fl::event()); - if (Fl::event_key() == FL_Enter || Fl::event()==FL_RELEASE) + if (Fl::event_key() == FL_Enter || Fl::event()==FL_RELEASE) + // second event is click on button loaddir(location_input->value()); - if (Fl::event()==FL_KEYDOWN && Fl::event_key()!=FL_BackSpace) { - // Pressing a key in Fl_Input will automatically replace selection with that key + if (Fl::event()==FL_KEYDOWN && Fl::event_key()!=FL_BackSpace && Fl::event_key()!=FL_Delete) { + // Pressing a key in Fl_Input will automatically replace selection with that char // So there are really two possibilities: // 1. Cursor is at the end, we add autocomplete stuff at cursor pos // 2. Cursor is in the middle, we do nothing @@ -478,7 +622,6 @@ fprintf (stderr, "location_input_cb %d\n",Fl::event()); int mark = location_input->mark(); // To avoid scandir, we will use view contents - // smart, eh? :) if ((strlen(loc)>strlen(current_dir)) && (!strchr(loc+strlen(current_dir),'/'))) { int i; for (i=1; i<=view->size(); i++) { @@ -532,6 +675,8 @@ fprintf (stderr, "location_input_cb %d\n",Fl::event()); +// TODO: move this to view +// every item should have own context menu defined Fl_Menu_Item context_menu_definition[] = { {_("&Open"), 0, open_cb}, @@ -546,7 +691,6 @@ Fl_Menu_Item context_menu_definition[] = { // Right click - show context menu void context_cb(Fl_Widget*, void*) { -// context_menu->position(Fl::event_x_root(),Fl::event_y_root()); context_menu->popup(); context_menu->value(-1); } @@ -580,9 +724,9 @@ Fl_Menu_Item main_menu_definition[] = { {_("&Detailed list"), FL_F+8, listview_cb, 0, FL_MENU_RADIO|FL_MENU_VALUE|FL_MENU_DIVIDER}, {_("Directory &tree"), FL_F+9, showtree_cb, 0, FL_MENU_TOGGLE|FL_MENU_VALUE}, {_("&Location bar"), FL_F+10, locationbar_cb, 0, FL_MENU_TOGGLE|FL_MENU_VALUE}, - {_("&Show hidden"), 0, showhidden_cb, 0, FL_MENU_TOGGLE|FL_MENU_DIVIDER}, + {_("&Hidden files"), 0, showhidden_cb, 0, FL_MENU_TOGGLE|FL_MENU_DIVIDER}, {_("&Refresh"), FL_F+5, refresh_cb}, - {_("S&ort"), 0, 0, 0, FL_SUBMENU}, + {_("&Sort"), 0, 0, 0, FL_SUBMENU}, {_("&Case sensitive"), 0, case_cb, 0, FL_MENU_TOGGLE}, {_("D&irectories first"), 0, dirsfirst_cb, 0, FL_MENU_TOGGLE|FL_MENU_VALUE}, {0}, @@ -598,7 +742,7 @@ Fl_Menu_Item main_menu_definition[] = { // Main program - +extern int FL_NORMAL_SIZE; int main (int argc, char **argv) { // Parse command line - this must come first @@ -608,8 +752,8 @@ int main (int argc, char **argv) { current_dir[0]='\0'; else { if (strcmp(argv[unknown],"--help")==0) { - printf("EFiler - EDE File Manager\nPart of Equinox Desktop Environment (EDE).\nCopyright (c) 2000-2007 EDE Authors.\n\nThis program is licenced under terms of the\nGNU General Public Licence version 2 or newer.\nSee COPYING for details.\n\n"); - printf("Usage:\n\tefiler [OPTIONS] [PATH]\n\n"); + printf(_("EFiler - EDE File Manager\nPart of Equinox Desktop Environment (EDE).\nCopyright (c) 2000-2007 EDE Authors.\n\nThis program is licenced under terms of the\nGNU General Public Licence version 2 or newer.\nSee COPYING for details.\n\n")); + printf(_("Usage:\n\tefiler [OPTIONS] [PATH]\n\n")); printf("%s\n",Fl::help); return 1; } @@ -624,6 +768,8 @@ FL_NORMAL_SIZE=12; fl_message_font(FL_HELVETICA, 12); + // Main GUI design + win = new Fl_Double_Window(default_window_width, default_window_height); // win->color(FL_WHITE); win->begin(); @@ -632,12 +778,12 @@ fl_message_font(FL_HELVETICA, 12); location_bar = new Fl_Group(0, menubar_height, default_window_width, location_bar_height); location_bar->begin(); - location_input = new Fl_File_Input(70, menubar_height+2, default_window_width-200, location_bar_height-5, _("Location:")); + location_input = new My_File_Input(70, menubar_height+2, default_window_width-200, location_bar_height-5, _("L&ocation:")); location_input->align(FL_ALIGN_LEFT); location_input->callback(location_input_cb); location_input->when(FL_WHEN_ENTER_KEY_CHANGED); location_bar->end(); - location_bar->box(FL_UP_BOX); // hack for label size + location_bar->box(FL_UP_BOX); location_bar->resizable(location_input); tile = new Fl_Tile(0, menubar_height+location_bar_height, default_window_width, default_window_height-menubar_height-location_bar_height-statusbar_height); @@ -647,7 +793,7 @@ fl_message_font(FL_HELVETICA, 12); view = new FileDetailsView(150, menubar_height+location_bar_height, default_window_width-default_tree_width, default_window_height-menubar_height-location_bar_height-statusbar_height); view->callback(open_cb); - // callback for renaming + // callbacks for file ops view->rename_callback(do_rename); view->paste_callback(do_paste); view->context_callback(context_cb); @@ -657,7 +803,7 @@ fl_message_font(FL_HELVETICA, 12); statusbar = new Fl_Box(2, default_window_height-statusbar_height+2, statusbar_width, statusbar_height-4); statusbar->box(FL_DOWN_BOX); statusbar->align(FL_ALIGN_LEFT|FL_ALIGN_INSIDE|FL_ALIGN_CLIP); - statusbar->label(_("Ready.")); + statusbar->label(_("EFiler is starting...")); Fl_Box* filler = new Fl_Box(statusbar_width+2, default_window_height-statusbar_height+2, default_window_width-statusbar_width, statusbar_height-4); sbgroup->end(); @@ -672,22 +818,22 @@ fl_message_font(FL_HELVETICA, 12); win->resizable(tile); // win->resizable(view); + // Set application (window manager) icon + // FIXME: due to fltk bug this icon doesn't have transparency fl_open_display(); Pixmap p, mask; - XpmCreatePixmapFromData(fl_display, DefaultRootWindow(fl_display), efiler_xpm, &p, &mask, NULL); win->icon((char*)p); - win->show(argc,argv); - view->take_focus(); - - // Yet another hack for label size.... // TODO remember previous configuration showhidden=false; dirsfirst=true; ignorecase=true; semaphore=false; showtree=true; showlocation=true; tree_width = default_tree_width; + win->show(argc,argv); + view->take_focus(); dirtree->init(); loaddir(current_dir); + return Fl::run(); }