#include #include "diawxgtk.h" int layout_indent = 1; void layout_debug (const char *id, const char *ctl, ...) { if (1 || strncmp(id,"fram",4)==0){ for (int i=0; ic; if (c != NULL){ int px,py; c->GetPosition(&px,&py); py -= diffy; c->SetSize (px,py,-1,-1,wxSIZE_ALLOW_MINUS_ONE); }else if (item->homemade){ somelabels = true; item->y -= diffy; } } voffset = newpos; if (somelabels){ wxClientDC dc(this); dc.SetBackground (*background.brush); dc.Clear(); } OnPaint(); } if (vscroll->GetValue() != newpos) vscroll->SetValue (newpos); } } PUBLIC VIRTUAL void MFORM::hmoveitems (int newpos) { //int viewstart,viewlength,objlength,pagelength; //hscroll->GetValues(&viewstart, &viewlength, &objlength, &pagelength); if (newpos < 0) newpos = 0; //int limit = objlength - viewlength; //if (newpos > limit) newpos = limit; int curpos = hscroll->GetValue(); int diffx = newpos - hoffset; if (diffx != 0){ bool somelabels = false; for (int i=0; ic; if (c != NULL){ int px,py; c->GetPosition(&px,&py); px -= diffx; c->SetSize (px,py,-1,-1,wxSIZE_ALLOW_MINUS_ONE); }else if (item->homemade){ somelabels = true; item->x -= diffx; } } hoffset = newpos; if (somelabels){ wxClientDC dc(this); dc.SetBackground (*background.brush); dc.Clear(); } OnPaint(); } if (curpos != newpos) hscroll->SetValue (newpos); } PUBLIC void MFORM::vscroll_func (wxScrollEvent &ev) { if (ev.GetOrientation() == wxHORIZONTAL){ hscroll_func (ev); }else{ vmoveitems (ev.GetPosition()); } } /* Make sure the vertical scroll bar is created */ PUBLIC void wxFORMBASE::setvscroll() { if (vscroll == NULL){ vscroll = new wxScrollBar (this,-1,wxDefaultPosition,wxDefaultSize ,wxSB_VERTICAL); voffset = 0; } } PUBLIC void MFORM::hscroll_func (wxScrollEvent &ev) { hmoveitems (ev.GetPosition()); } /* Make sure the horizontal scroll bar is created */ PUBLIC void wxFORMBASE::sethscroll() { if (hscroll == NULL){ hscroll = new wxScrollBar (this,-1,wxDefaultPosition,wxDefaultSize ,wxSB_HORIZONTAL); hoffset = 0; } } PROTECTED void MFORM::FitStrategie_marge( int gauche, int droit, // Right margin int haut, // Top margin int bas, // Bottom margin bool use_cur_size, int maxw, // Maximum width allowed int maxh, // Maximum height allowed bool force, // Extend the dimension to use the maxw and maxh wxSize &give) // Result will be written there { if (!use_cur_size){ maxw -= (droit+4+marge_droite); maxh -= (bas+4+marge_bas); // SetClientSize reserves 2 pixels (I think) around } int nb = nbc; gauche += marge_gauche; droit += marge_droite; haut += marge_haut; bas += marge_bas; wxClientDC dc(this); dc.SetFont (*font_normal); // int has_fill = 0; // Map all the fields in the proper tbcell entry int i; int noline = 0; for (i=0; itype == T_NEWLINE) noline++; } CELLDISPS *tbcell = new CELLDISPS[noline+1]; /* PASS 1: We map all the item in the tbcell array. Items are organised into lines and T_NEWLINE items mark the end of a line. Some items are spanning over multiple lines and columns. We reserv the corresponding cells in tbcell. */ int nocol = 0; noline = 0; for (i=0; itype == T_NEWLINE){ noline++; nocol = 0; }else if (item->type == T_SKIP){ int used = USED_LEFT | USED_TOP; tbcell[noline][nocol].item = item; for (int sk=0; skh_cells; sk++,nocol++){ tbcell[noline][nocol].used = used; used &= ~USED_LEFT; } }else if (item->type == T_FILL){ if (stretch_mode == STRETCH_NONE){ stretch_mode = STRETCH_LOOK; } tbcell[noline][nocol].item = item; tbcell[noline][nocol].used = USED_LEFT | USED_TOP; nocol++; }else{ if (item->type == T_TEXT && stretch_mode == STRETCH_NONE){ stretch_mode = STRETCH_LOOK; } tbcell[noline][nocol].item = item; int used = USED_LEFT | USED_TOP; if (item->is_hcontrib){ int nbcol = item->h_cells; if (nbcol > 1) used |= USED_MULTICOL; if (item->v_cells > 1) used |= USED_MULTILINE; for (; nbcol>0; nbcol--,nocol++){ int nol = noline; used |= USED_TOP; for (int l=0; lv_cells; l++,nol++){ tbcell[nol][nocol].item = item; tbcell[nol][nocol].used = used; used &= ~USED_TOP; } used &= ~USED_LEFT; } }else{ tbcell[noline][nocol].used = used; nocol++; } } } int lineheight[noline+1]; memset (colwidth,0,sizeof(colwidth)); memset (lineheight,0,sizeof(lineheight)); /* PASS 2: Dans un premier temps, on calcule la largeur de chaque colonne et la hauteur de chaque ligne en ne tenant compte que des items simple (non multi-ligne ou non-multicolonne) Pour chaque colonne, on trouve l'item le plus large. Pour chaque ligne, on trouve l'item le plus haut. */ int charheight = (int)dc.GetCharHeight(); for (i=0; i<=noline; i++){ for (int c=0; citem; if (item != NULL && item->is_hcontrib){ int nbcol = item->h_cells; int nbline = item->v_cells; if (item->c != NULL){ if (use_cur_size){ int w,h; item->c->GetSize(&w,&h); ptcell->width = w; ptcell->height = h; }else{ if (item->pref_width == -1){ item->c->GetSize(&item->pref_width ,&item->pref_height); } ptcell->width = item->pref_width; ptcell->height = item->pref_height; } }else if (item->type == T_LABEL || item->type == T_BUTTONFILL){ wxCoord w,h; defs_setdc (item->dcn,dc); dc.GetTextExtent (item->s,&w,&h); if (item->pref_width > w) w = item->pref_width; if (item->pref_height > h) h = item->pref_height; ptcell->width = (int)w+6; ptcell->height = (int)h; if (item->type == T_BUTTONFILL){ if (item->options & MFORM_OPTFLAT){ ptcell->height += charheight/2; }else{ ptcell->height += charheight; } }else{ ptcell->height += 6; } item->height = ptcell->height; }else if (item->type == T_ICON){ int w = item->bitmap->GetWidth(); int h = item->bitmap->GetHeight(); item->width = ptcell->width = w; item->height = ptcell->height = h; }else if (item->type == T_RICHTEXT){ int w,h; richtext_extent (item->s,w,h); ptcell->width = w; ptcell->height = h; }else if (item->type == T_RADIO){ wxCoord w,h; dc.GetTextExtent (item->s,&w,&h); item->width = ptcell->width = (int)w + 14; item->height = ptcell->height = charheight + 6; }else if (item->type == T_FILL){ if (use_cur_size) ptcell->width = item->width; } if (nbcol == 1){ if (colwidth[c] < ptcell->width) colwidth[c] = ptcell->width; } if (nbline == 1){ if (lineheight[i] < ptcell->height) lineheight[i] = ptcell->height; } } } } /* PASS 3: On recommence le processus, mais ce coup ci, en ne tenant compte que des items multi-colonnes et multi-ligne. Ce qui nous interesse, c'est la largeur totale des X colonnes occupé par l'item vs sa propre largeur. Si sa largeur excede alors, on augmentera artificiellement la largeur de la dernière colonne. On pourrait aussi repartir l'excédant entre les colonnes On fait la même chose pour les multi-lignes */ for (i=0; i<=noline; i++){ for (int c=0; citem; if (item != NULL && item->is_hcontrib){ int used = ptcell->used; int nbcol = item->h_cells; int nbline = item->v_cells; if (ptcell->width != -1){ if (nbcol > 1 && (used & USED_LEFT) != 0){ int total = 0; for (int x=0; xwidth){ colwidth[c+nbcol-1] += ptcell->width-total; } } if (nbline > 1 && (used & USED_TOP) != 0){ int total = 0; for (int x=0; xheight) lineheight[i+nbline-1] += ptcell->height-total; } } } } } // We ajust the width according to parent specification for (i=0; i colwidth[i]) colwidth[i] = minw; } /* PASS 4: On connait maintenant les spécifications de chaque colonnes et chaque lignes, donc la taille maximum de chaque cellule. On va repasser au travers du design une fois de plus et demander à tous les items extensibles de bien vouloirs s'étirer pour occuper leur cellule complètement. */ for (i=0; i<=noline; i++){ for (int c=0; cused & (USED_TOP | USED_LEFT)) == (USED_TOP | USED_LEFT)){ MFORM_C *item = ptcell->item; if (item != NULL){ if (item->type == T_FORM || item->type == T_BOOK || item->type == T_CLIST){ wxWindow *w = item->c; if (item->getformbase()->may_stretch()){ int nbcol = item->h_cells; int nbline = item->v_cells; int cwidth = 0; int cheight = 0; for (int ci=0; ci item->pref_width || cheight > item->pref_height){ w->SetSize (cwidth,cheight); } if (stretch_mode == STRETCH_NONE){ stretch_mode = STRETCH_LOOK; } } }else if (item->type == T_TEXT){ int nbcol = item->h_cells; int nbline = item->v_cells; int cwidth = 0; int cheight = 0; for (int ci=0; ciitem; if (item != NULL){ int used = ptcell->used; if((used & USED_LEFT) != 0 && (used & USED_TOP) != 0 && ptcell->width != -1){ int nbcol = item->h_cells; int nbline = item->v_cells; char dhori = item->h_align; char dverti = item->v_align; int total_width = 0; for (int x=0; xwidth; }else if (dhori == 'c'){ xpos += (total_width - ptcell->width)/2; } if (dverti == 'b'){ ypos += total_height - ptcell->height; }else if (dverti == 'c'){ ypos += (total_height - ptcell->height)/2; } int ypos_scrolled = ypos - voffset; if (item->homemade){ item->x = xpos; item->y = ypos_scrolled; item->width = total_width; }else if (item->type == T_HLINE){ item->c->SetSize(xpos,ypos_scrolled,total_width,ptcell->height); }else if (item->type != T_FILL){ int curx,cury; item->c->GetPosition(&curx,&cury); if (curx != xpos || cury != ypos_scrolled){ item->c->SetSize (xpos,ypos_scrolled,-1,-1,0); } } //if (item->is_vline()) item->setspec(-1,-1,-1,total_height); } } h_pos += colwidth[c]; } v_pos += lineheight[i]; } /* Final adjustments. Some scrollbars are installed if needed */ // stretch_last(h_pos); // fprintf (stderr,"id=:%s: h_pos %d maxw %d v_pos %d maxh %d\n",id,h_pos,maxw,v_pos,maxh); // fprintf (stderr,"layout vpos %d doc_height %d h_pos %d doc_width %d\n",v_pos,doc_height,h_pos,doc_width); if (doc_height > v_pos) v_pos = doc_height; if (doc_width > h_pos) h_pos = doc_width; bool need_vscroll = vscroll != NULL || ((nbc > 5 || doc_height != -1) && v_pos > maxh); if (force && maxh > v_pos) v_pos = maxh; int document_height = v_pos; int document_width = h_pos; int new_height = v_pos > maxh ? maxh : v_pos; if (strncmp(id,"fram",4)==0) need_vscroll = false; if (need_vscroll){ setvscroll(); maxw -= 20; v_pos = new_height; } bool need_hscroll = !istop() && (h_pos > maxw || hscroll != NULL); if (force && maxw > h_pos) h_pos = maxw; int new_width = h_pos > maxw ? maxw : h_pos; layout_debug (id,"need_hscroll %d %p force %d h_pos %d maxw %d max_width %d\n",need_hscroll,hscroll,force,h_pos,maxw,max_width); //if (strncmp(id,"fram",4)==0) need_hscroll = false; if (need_hscroll){ sethscroll(); hscroll->SetScrollbar(0,new_width,document_width,200); h_pos = new_width; if (vscroll == NULL){ int sw,sh; hscroll->GetSize (&sw,&sh); v_pos += sh; } hscroll->SetSize (0,v_pos-20,new_width,20); new_height -= 20; } if (vscroll != NULL){ // fprintf (stderr,"v set %d %d %d %d\n",h_pos,haut,20,new_height); int v_height = new_height; if (v_height == 0) v_height = 10; vscroll->SetSize (h_pos,haut,20,v_height); h_pos += (int)20; vscroll->SetScrollbar(0,v_height,document_height,v_height); } if (fixed.x != -1){ SetSize (fixed.x,fixed.y,-1,-1,0); } if (fixed.w != -1){ give.Set(fixed.w,fixed.h); }else{ give.Set (h_pos+droit,v_pos+bas); } modified = false; layout_once = true; delete [] tbcell; } PUBLIC VIRTUAL void MFORM::dolayout(int maxw, int maxh, bool force, wxSize &give) { layout_debug (id,"dolayout1\n"); layout_indent++; FitStrategie_marge(sidetitle != NULL ? 20 : 0,0,0,0,true,maxw,maxh, force,give); layout_indent--; layout_debug (id,"dolayout2\n"); } class MFORM_SIZER: public wxSizer{ int revlayout; MFORM *mf; int std_width,std_height; int last_width,last_height; /*~PROTOBEG~ MFORM_SIZER */ protected: wxSize CalcMin (void); public: MFORM_SIZER (MFORM *_mf); protected: void RecalcSizes (void); public: void layout_if (void); /*~PROTOEND~ MFORM_SIZER */ }; PUBLIC MFORM_SIZER::MFORM_SIZER(MFORM *_mf) { revlayout = -1; mf = _mf; std_width = std_height = -1; last_width = last_height = -1; } /* Compute the layout of the form to find its standard dimensions */ PUBLIC void MFORM_SIZER::layout_if() { int new_revlayout = mf->getrevlayout(); if (new_revlayout != revlayout){ revlayout = new_revlayout; wxSize give; mf->dolayout (mf->max_width,mf->max_height,false,give); last_width = std_width = give.GetWidth(); last_height = std_height = give.GetHeight(); layout_debug (mf->id,"MinSize %d %d\n",std_width,std_height); SetMinSize (std_width,std_height); mf->SetSizeHints (std_width,std_height); mf->pref_width = std_width; mf->pref_height = std_height; } } PROTECTED wxSize MFORM_SIZER::CalcMin() { layout_debug (mf->id,"Calcmin1 last(%d,%d) std(%d,%d)\n",last_width,last_height,std_width,std_height); layout_if(); layout_debug (mf->id,"Calcmin2 last(%d,%d) std(%d,%d)\n",last_width,last_height,std_width,std_height); return wxSize (std_width,std_height); } PROTECTED void MFORM_SIZER::RecalcSizes() { layout_if(); int width,height; mf->GetClientSize (&width,&height); if (strcmp(mf->id,"main-0-1")==0){ static int c=0; c++; if (c==2 && 0){ char *pt = NULL; *pt='a'; } } layout_debug (mf->id,"RecalcSizes1 now[%d %d] last[ %d %d] std[%d %d]\n",width,height,last_width,last_height,std_width,std_height); if (last_width != width || last_height != height){ layout_debug (mf->id,"RecalcSizes2 now[%d %d] last[ %d %d] std[%d %d]\n",width,height,last_width,last_height,std_width,std_height); layout_indent++; mf->resizeitems (width-last_width,height-last_height); last_width = width; last_height = height; layout_indent--; } layout_debug (mf->id,"RecalcSizes3\n"); } /* Register the general purpose layout engine as a sizer */ PRIVATE void MFORM::initsizer() { MFORM_SIZER *s = new MFORM_SIZER (this); SetSizer (s); } PRIVATE void MFORM::DoSetSize (int x, int y, int w, int h, int flags) { //layout_debug (id,"DoSetSize1 %d %d %d %d %d\n",x,y,w,h,flags); wxFORMBASE::DoSetSize (x,y,w,h,flags); //layout_debug (id,"DoSetSize2 %d %d %d %d %d\n",x,y,w,h,flags); } PRIVATE void MFORM::DoMoveWindow (int x, int y, int w, int h) { //layout_debug (id,"DoMoveWindow1 %d %d %d %d\n",x,y,w,h); wxFORMBASE::DoMoveWindow (x,y,w,h); //layout_debug (id,"DoMoveWindow2 %d %d %d %d\n",x,y,w,h); } PRIVATE void MFORM::DoSetClientSize (int w, int h) { //layout_debug (id,"DoSetClientSize1 %d %d\n",w,h); wxFORMBASE::DoSetClientSize (w,h); //layout_debug (id,"DoSetClientSize2 %d %d\n",w,h); } PRIVATE wxSize MFORM::DoGetVirtualSize () const { int w,h; GetSize (&w,&h); //layout_debug (id,"DoGetVirtualSize %d %d\n",w,h); return wxSize (w,h); } class MyDialog: public wxDialog{ public: MyDialog(wxFrame *, wxWindowID, const wxString &); }; MyDialog::MyDialog(wxFrame *parent, wxWindowID id, const wxString &title ) : wxDialog(parent, id, title, wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER) { wxBoxSizer *topsizer = new wxBoxSizer( wxVERTICAL ); MFORM *m = new MFORM (NULL,this,"MFORM"); MFORM *intro = new MFORM (m,"intro"); m->New_form(intro); //intro->New_string ("i1",10,"intro"); intro->New_label ("Ceci est le titre"); for (int i=0; i<4; i++){ intro->Newline(); intro->New_label ("Ceci est la deuxieme ligne"); intro->New_label ("Ceci est la deuxieme ligne"); intro->New_label ("Ceci est la deuxieme ligne"); intro->New_label ("Ceci est la deuxieme ligne"); intro->New_label ("Ceci est la deuxieme ligne"); } //intro->Newline(); //intro->New_string ("i1",10,"intro"); intro->Fit(); m->Dispolast('c',3,'t',1); m->Newline(); m->New_string ("t1",10,"allo1"); m->New_string ("t1",20,"allo2"); m->New_string ("t1",25,"allo3"); m->Newline(); GROUP *gr = new GROUP_FIT(m,"g1","Titre"); m->New_form(gr); gr->New_text ("t1",80,5); gr->Fit(); m->Dispolast('l',3,'t',1); m->Newline(); #if 1 static const char *tbcols[]={"col1","col2","col3"}; CLIST *cl = m->New_clist ("clist",3,tbcols); m->Dispolast('l',3,'t',1); for (int i=0; i<5; i++){ char tmp[10]; sprintf (tmp,"l%d",i); const char *tbvals[]={tmp,tmp,tmp}; cl->Set_item (tmp,tbvals); } cl->Fit(); m->Newline(); #endif #if 0 BOOK *b = new BOOK(m,"book"); m->New_book(b); m->Dispolast('l',3,'t',1); for (int i=0; i<2; i++){ MFORM *page = new MFORM(b,"page"); b->New_page(page,"title page"); for (int j=0; j<4; j++){ page->New_label ("Ceci est la deuxieme ligne"); page->Newline(); } page->Fit(); } b->Fit(); m->Newline(); #else wxBOOK *b = new wxBOOK(m,"book"); m->New_book(b); m->Dispolast('l',3,'t',1); for (int i=0; i<2; i++){ MFORM *page = new MFORM(b,b,"page"); b->New_page(page,"title page"); for (int j=0; j<4; j++){ page->New_label ("Ceci est la deuxieme ligne"); page->Newline(); } page->Fit(); } b->Fit(); m->Newline(); #endif FORMBUTTON *mf = m->New_formbutton("BUTTON"); mf->New_button ("b1",true,"Bouton1"); mf->New_button ("b2",true,"Bouton2"); mf->Fit(); m->Dispolast('l',3,'t',1); m->Fit(); topsizer->Add (m,1,wxEXPAND); // create text ctrl with minimal size 100x60 topsizer->Add( new wxTextCtrl( this, -1, "My text.", wxDefaultPosition, wxSize(100,60), wxTE_MULTILINE), 1, // make vertically stretchable wxEXPAND | // make horizontally stretchable wxALL, // and make border all around 10 ); // set border width to 10 wxBoxSizer *button_sizer = new wxBoxSizer( wxHORIZONTAL ); button_sizer->Add( new wxButton( this, wxID_OK, "OK" ), 0, // make horizontally unstretchable wxALL, // make border all around (implicit top alignment) 10 ); // set border width to 10 button_sizer->Add( new wxButton( this, wxID_CANCEL, "Cancel" ), 0, // make horizontally unstretchable wxALL, // make border all around (implicit top alignment) 10 ); // set border width to 10 topsizer->Add( button_sizer, 0, // make vertically unstretchable wxALIGN_CENTER ); // no border and centre horizontally //SetAutoLayout(TRUE); SetSizer( topsizer ); // use the sizer for layout topsizer->SetSizeHints( this ); // set size hints to honour minimum size //topsizer->Fit(this); } wxFrame *test_dialog() { wxFrame *fram = new wxFrame(NULL,-1,"test",wxPoint(100,100),wxSize(400,400)); wxDialog *dia = new MyDialog (fram,-1,"test"); dia->Show(); //fram->SetAutoLayout(TRUE); //fram->Fit(); //fram->Show(true); return fram; }