//
// Unit tests for the Fast Light Tool Kit (FLTK).
//
// Copyright 1998-2024 by Bill Spitzak and others.
//
// This library is free software. Distribution and use rights are outlined in
// the file "COPYING" which should have been included with this file.  If this
// file is missing or damaged, see the license at:
//
//     https://www.fltk.org/COPYING.php
//
// Please see the following page on how to report bugs and issues:
//
//     https://www.fltk.org/bugs.php
//

#include "unittests.h"

#include <FL/Fl_Group.H>
#include <FL/Fl_Box.H>
#include <FL/Fl_Browser.H>
#include <FL/Fl_Tree.H>
#include <FL/Fl_Table.H>
#include <FL/Fl_Text_Display.H>
#include <FL/Fl_Value_Slider.H>
#include <FL/Fl_Terminal.H>

//
// Test new 1.3.x global vs. local scrollbar sizing
//
class Ut_Table : public Fl_Table {
  // Handle drawing table's cells
  //     Fl_Table calls this function to draw each visible cell in the table.
  //     It's up to us to use FLTK's drawing functions to draw the cells the way we want.
  //
  void draw_cell(TableContext context, int ROW=0, int COL=0, int X=0, int Y=0, int W=0, int H=0) FL_OVERRIDE {
    static char s[10];
    switch ( context ) {
      case CONTEXT_STARTPAGE:                   // before page is drawn..
        fl_font(FL_HELVETICA, 8);               // set font for drawing operations
        return;
      case CONTEXT_CELL:                        // Draw data in cells
        snprintf(s, 10, "%c", 'A'+ROW+COL);
        fl_push_clip(X,Y,W,H);
          // Draw cell bg
          fl_color(FL_WHITE); fl_rectf(X,Y,W,H);
          // Draw cell data
          fl_color(FL_GRAY0); fl_draw(s, X,Y,W,H, FL_ALIGN_CENTER);
          // Draw box border
          fl_color(color()); fl_rect(X,Y,W,H);
        fl_pop_clip();
        return;
      default:
        return;
    }
  }
  public:
  // Constructor
  //     Make our data array, and initialize the table options.
  //
  Ut_Table(int X, int Y, int W, int H, const char *L=0)
    : Fl_Table(X,Y,W,H,L) {
    // Rows
    rows(13);                   // how many rows
    row_height_all(10);         // default height of rows
    // Cols
    cols(13);                   // how many columns
    col_width_all(10);          // default width of columns
    end();                      // end the Fl_Table group
  }
  ~Ut_Table() { }
};

static const char *phonetics[] = {
  "Alpha", "Bravo", "Charlie", "Delta", "Echo", "Foxtrot",
  "Golf", "Hotel", "India", "Juliet", "Kilo", "Lima", "Mike",
  "November", "Oscar", "Papa", "Quebec", "Romeo", "Sierra", "Tango",
  "Uniform", "Victor", "Whiskey", "X-ray", "Yankee", "Zulu", NULL
};

class Ut_Scrollbar_Size_Test : public Fl_Group {
    Fl_Browser      *brow_a, *brow_b, *brow_c;
    Fl_Tree         *tree_a, *tree_b, *tree_c;
    Ut_Table        *table_a,*table_b,*table_c;
    Fl_Text_Display *text_a, *text_b, *text_c;
    Fl_Terminal     *term_a, *term_b, *term_c;

    Fl_Browser *makebrowser(int X,int Y,int W,int H,const char*L=0) {
        Fl_Browser *b = new Fl_Browser(X,Y,W,H,L);
        b->type(FL_MULTI_BROWSER);
        b->labelsize(10);
        b->textsize(10);
        b->align(FL_ALIGN_TOP);
        for (int t=0; phonetics[t]; t++ ) {
          b->add(phonetics[t]);
          if ( phonetics[t][0] == 'C' ) b->add("Long entry will show h-bar");
        }
        return(b);
    }
    Fl_Tree *maketree(int X,int Y,int W,int H,const char*L=0) {
        Fl_Tree *b = new Fl_Tree(X,Y,W,H,L);
        b->labelsize(10);
        b->item_labelsize(10);
        b->type(FL_TREE_SELECT_MULTI);
        b->align(FL_ALIGN_TOP);
        for (int t=0; phonetics[t]; t++ ) {
          b->add(phonetics[t]);
          if ( phonetics[t][0] == 'C' ) b->add("Long entry will show h-bar");
        }
        return(b);
    }
    Ut_Table *maketable(int X,int Y,int W,int H,const char*L=0) {
        Ut_Table *mta = new Ut_Table(X,Y,W,H,L);
        mta->labelsize(10);
        mta->align(FL_ALIGN_TOP);
        mta->end();
        return(mta);
    }
    Fl_Text_Display *maketextdisplay(int X,int Y,int W,int H,const char*L=0) {
        Fl_Text_Display *dpy = new Fl_Text_Display(X,Y,W,H,L);
        Fl_Text_Buffer  *buf = new Fl_Text_Buffer();
        dpy->labelsize(10);
        dpy->textsize(10);
        dpy->buffer(buf);
        for (int t=0; phonetics[t]; t++ ) {
          buf->printf("%s\n", phonetics[t]);
          if ( phonetics[t][0] == 'C' ) buf->printf("Long entry will show h-bar\n");
        }
        return(dpy);
    }
    Fl_Terminal *maketerm(int X,int Y,int W,int H,const char*L=0) {
        Fl_Terminal *term = new Fl_Terminal(X,Y,W,H,L);
        term->labelsize(8);
        term->textsize(8);
        term->end();
        term->display_columns(40); // force wider than normal to show hscroll
        term->printf("Long entry will show h-bar\n");
        return(term);
    }
    void slide_cb2(Fl_Value_Slider *in) {
        const char *label = in->label();
        int val = int(in->value());
        //fprintf(stderr, "VAL='%d'\n",val);
        if ( strcmp(label,"A: Scroll Size") == 0 ) {
            brow_a->scrollbar_size(val);
            tree_a->scrollbar_size(val);
            table_a->scrollbar_size(val);
            text_a->scrollbar_size(val);
            term_a->scrollbar_size(val);
        } else {
            Fl::scrollbar_size(val);
        }
        in->window()->redraw();
    }
    static void slide_cb(Fl_Widget *w, void *data) {
        Ut_Scrollbar_Size_Test *o = (Ut_Scrollbar_Size_Test*)data;
        o->slide_cb2((Fl_Value_Slider*)w);
    }
public:
    static Fl_Widget *create() {
      return(new Ut_Scrollbar_Size_Test(UT_TESTAREA_X, UT_TESTAREA_Y, UT_TESTAREA_W, UT_TESTAREA_H));
    }

    // CTOR
    Ut_Scrollbar_Size_Test(int X, int Y, int W, int H)
      : Fl_Group(X,Y,W,H) {
      begin();
        //      _____________    _______________
        //     |_____________|  |_______________|
        //                                                ---     -----  <-- tgrpy
        //       brow_a      brow_b      brow_c            ↕ 14     ↑
        //     ----------  ----------  ----------         ---       |    <-- browy
        //     |        |  |        |  |        |          ↑ browh  |
        //     |        |  |        |  |        |          ↓        |
        //     ----------  ----------  ----------         ---     tgrph
        //                                                 ↑        |
        //       tree_a      tree_b      tree_c            ↓ 20     |
        //     ----------  ----------  ----------         ---       |    <-- treey
        //     |        |  |        |  |        |          ↑ treeh  |
        //     |        |  |        |  |        |          ↓        |
        //     ----------  ----------  ----------         ---       |
        //                                                 ↑        |
        //      table_a     table_b     table_c            ↓ 20     |
        //     ----------  ----------  ----------         ---       |    <-- tabley
        //     |        |  |        |  |        |          ↑ tableh |
        //     |        |  |        |  |        |          ↓        |
        //     ----------  ----------  ----------         ---       |
        //                                                 ↑        |
        //      term_a      term_b      term_c             ↓ 20     |
        //     ----------  ----------  ----------         ---       |    <-- termy
        //     |        |  |        |  |        |          ↑ termh  |
        //     |        |  |        |  |        |          ↓        ↓
        //     ----------  ----------  ----------         ---     ------
        //  etc..
        int tgrpy = Y+30;
        int tgrph = H-30;
        int ysep  = 20;                 // y separation between widgets
        int browy = tgrpy+14;
        int browh = tgrph/5 - 20;       // 5: number of widgets vertically
        int treey = browy + browh + ysep;
        int treeh = browh;
        int tabley = treey + treeh + ysep;
        int tableh = browh;
        int texty = tabley + tableh + ysep;
        int texth = browh;
        int termy = texty + texth + ysep;
        // int termh = texth; // unused but left because it's documented above
        brow_a = makebrowser(X+ 10,browy,100,browh,"Browser A");
        brow_b = makebrowser(X+120,browy,100,browh,"Browser B");
        brow_c = makebrowser(X+230,browy,100,browh,"Browser C");
        tree_a = maketree(X+ 10,treey,100,treeh,"Tree A");
        tree_b = maketree(X+120,treey,100,treeh,"Tree B");
        tree_c = maketree(X+230,treey,100,treeh,"Tree C");
        table_a = maketable(X+ 10,tabley,100,tableh,"Table A");
        table_b = maketable(X+120,tabley,100,tableh,"Table B");
        table_c = maketable(X+230,tabley,100,tableh,"Table C");
        text_a = maketextdisplay(X+ 10,texty,100,texth,"Text Display A");
        text_b = maketextdisplay(X+120,texty,100,texth,"Text Display B");
        text_c = maketextdisplay(X+230,texty,100,texth,"Text Display C");
        term_a = maketerm(X+ 10,termy,100,texth,"Term A");
        term_b = maketerm(X+120,termy,100,texth,"Term B");
        term_c = maketerm(X+230,termy,100,texth,"Term C");
        Fl_Value_Slider *slide_glob = new Fl_Value_Slider(X+100,Y,100,18,"Global Scroll Size");
        slide_glob->value(16);
        slide_glob->type(FL_HORIZONTAL);
        slide_glob->align(FL_ALIGN_LEFT);
        slide_glob->range(0.0, 30.0);
        slide_glob->step(1.0);
        slide_glob->callback(slide_cb, (void*)this);
        slide_glob->labelsize(12);
        Fl_Value_Slider *slide_browa = new Fl_Value_Slider(X+350,Y,100,18,"A: Scroll Size");
        slide_browa->value(0);
        slide_browa->type(FL_HORIZONTAL);
        slide_browa->align(FL_ALIGN_LEFT);
        slide_browa->range(0.0, 30.0);
        slide_browa->step(1.0);
        slide_browa->callback(slide_cb, (void*)this);
        slide_browa->labelsize(12);
        int msgbox_x = brow_c->x() + brow_c->w() + 20;
        int msgbox_y = tgrpy;
        int msgbox_w = W-(msgbox_x-X);
        int msgbox_h = tgrph;
        Fl_Box *msgbox = new Fl_Box(msgbox_x,msgbox_y,msgbox_w,msgbox_h);
        msgbox->label("\nVerify global scrollbar sizing and per-widget scrollbar sizing. "
                      "Scrollbar's size should change interactively as size sliders are changed. "
                      "Changing 'Global Scroll Size' should affect all scrollbars AS LONG AS the "
                      "'A: Scroll Size' slider is 0. Otherwise its value takes precedence "
                      "for all the 'A' group widgets.");
        msgbox->labelsize(12);
        msgbox->align(FL_ALIGN_INSIDE|FL_ALIGN_CENTER|FL_ALIGN_LEFT|FL_ALIGN_WRAP);
        msgbox->box(FL_FLAT_BOX);
        msgbox->color(53); // 90% gray
      end();
    }
};

UnitTest scrollbarsize(UT_TEST_SCROLLBARSIZE, "Scrollbar Size", Ut_Scrollbar_Size_Test::create);
