(***********************************************************************
   This file is part of GTKpas, an OOP wrapper for GTK+ written
   for Pascal.

   Copyright (C) 2000 by Johann Glaser <Johann.Glaser@gmx.at>

   This program is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public License
   as published by the Free Software Foundation; either version 2
   of the License, or (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program in the file COPYING; if not, write to the 
   Free Software Foundation, Inc., 
   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
***********************************************************************)
Program RangeWidgets;
{$MODE OBJFPC}
Uses GLib,GDK,GTK,GTKpas;

Type TMenuCallback = Function(Sender:CMenuItem;Data:GPointer):GBoolean of object;

Type CRangeWidgets = Class(CWindow)
                HScale : CHScale;
                VScale : CVScale;
                Constructor Create;
                Function DeleteEventImpl(aEvent:PGdkEventAny):Gint; virtual; override;
                Procedure Destroy_; virtual; override;
                Function  cb_pos_menu_select(Sender:CMenuItem;Data:GPointer):GBoolean;
                Function  cb_update_menu_select(Sender:CMenuItem;Data:GPointer):GBoolean;
                Function  cb_digits_Scale(Sender:CAdjustment;Data:GPointer):GBoolean;
                Function  cb_page_size(Sender:CAdjustment;Data:GPointer):GBoolean;
                Function  cb_draw_value(Sender:CToggleButton;Data:GPointer):GBoolean;
                Function  OnQuitButtonClicked(Sender:CButton;Data:GPointer):GBoolean;
              End;

Var Kit    : CMain;

(* Convenience functions *)

Function MakeMenuItem(Name:PGChar;Callback:TMenuCallback;Data:GPointer):CMenuItem;
Var Item : CMenuItem;
Begin
  Item := CMenuItem.Create(Name);
  Item.OnActivate := Callback;
  Item.OnActivateData := Data;
  Item.Show;
  MakeMenuItem := Item;
End;

Procedure ScaleSetDefaultValues(Scale:CScale);
Begin
  Scale.UpdatePolicy := GTK_UPDATE_CONTINUOUS;
  Scale.Digits := 1;
  Scale.ValuePos := GTK_POS_TOP;
  Scale.DrawValueVar := True;
End;


(* makes the sample window *)
Constructor CRangeWidgets.Create;
Var Box1,Box2,Box3   : CBox;
    Button           : CButton;
    TButton          : CToggleButton;
    MyScrollbar      : CRange{Scrollbar};
    Separator        : CSeparator;
    Opt              : COptionMenu;
    Menu             : CMenu;
    Item             : CMenuItem;
    TheLabel         : CLabel;
    Scale            : CScale;
    Adj1,Adj2        : CAdjustment;
Begin
  (* Standard window-creating stuff *)
  inherited Create(GTK_WINDOW_TOPLEVEL);
  Title := 'range controls';

  Box1 := CVBox.Create(FALSE, 0);
  Add(Box1);
  Box1.Show;

  Box2 := CHBox.Create(FALSE, 10);
  Box2.BorderWidth := 10;
  Box1.PackStart(Box2, TRUE, TRUE, 0);
  Box2.Show;

  (* value, lower, upper, step_increment, page_increment, page_size *)
  (* Note that the page_size value only makes a difference for
   * Scrollbar widgets, and the highest value you'll get is actually
   * (upper - page_size). *)
  Adj1 := CAdjustment.Create(0.0, 0.0, 101.0, 0.1, 1.0, 1.0);

  vScale := CVScale.Create(Adj1);
  ScaleSetDefaultValues(vScale);
  Box2.PackStart(vScale, TRUE, TRUE, 0);
  vScale.Show;

  Box3 := CVBox.Create(FALSE, 10);
  Box2.PackStart(Box3, TRUE, TRUE, 0);
  Box3.Show;

  (* Reuse the same adjustment *)
  hScale := CHScale.Create(Adj1);
  hScale.SetUsize(200, 30);
  ScaleSetDefaultValues(hScale);
  Box3.PackStart(hScale, TRUE, TRUE, 0);
  hScale.Show;


  (* Reuse the same adjustment again *)
  WriteLn(StdErr,'Adjustment = ',LongInt(Adj1.GtkObject));
  MyScrollbar := CHScrollbar.Create(Adj1);
  WriteLn(StdErr,'Constructed = ',MyScrollbar.GtkObject^.Flags);
(*  MyScrollbar := CHScrollbar.Create(PGtkObject(GTK_SCROLLBAR(gtk_hscrollbar_new (Nil{GTK_ADJUSTMENT (adj1.GtkObject)}))));*)
  (* Notice how this causes the Scales to always be updated
   * continuously when the Scrollbar is moved *)
{  MyScrollbar.SetAdjustment(Adj1);}
{  gtk_range_set_adjustment(PGtkRange(MyScrollbar.GtkObject),PGtkAdjustment(Adj1.GtkObject));}
  WriteLn(StdErr,'Adjustment = ',LongInt(PGtkRange(MyScrollbar.GtkObject)^.Adjustment));
  WriteLn(StdErr,'Through = ',LongInt(PGtkRange(MyScrollbar.GtkObject)^.Trough));
  WriteLn(StdErr,'Slider = ',LongInt(PGtkRange(MyScrollbar.GtkObject)^.Slider));
  WriteLn(StdErr,'StepForw = ',LongInt(PGtkRange(MyScrollbar.GtkObject)^.step_forw));
  WriteLn(StdErr,'StepBack = ',LongInt(PGtkRange(MyScrollbar.GtkObject)^.step_back));
  WriteLn(StdErr,'x_click_point = ',LongInt(PGtkRange(MyScrollbar.GtkObject)^.x_click_point));
  WriteLn(StdErr,'y_click_point = ',LongInt(PGtkRange(MyScrollbar.GtkObject)^.y_click_point));
  WriteLn(StdErr,'button = ',LongInt(PGtkRange(MyScrollbar.GtkObject)^.button));
  WriteLn(StdErr,'digits = ',LongInt(PGtkRange(MyScrollbar.GtkObject)^.digits));
  WriteLn(StdErr,'policy = ',LongInt(PGtkRange(MyScrollbar.GtkObject)^.flag0));
  WriteLn(StdErr,'timer = ',LongInt(PGtkRange(MyScrollbar.GtkObject)^.timer));
  WriteLn(StdErr,'old_value = ',LongInt(PGtkRange(MyScrollbar.GtkObject)^.old_value));
  WriteLn(StdErr,'old_lower = ',LongInt(PGtkRange(MyScrollbar.GtkObject)^.old_lower));
  WriteLn(StdErr,'old_upper = ',LongInt(PGtkRange(MyScrollbar.GtkObject)^.old_upper));
  WriteLn(StdErr,'old_page_size = ',LongInt(PGtkRange(MyScrollbar.GtkObject)^.old_page_size));
  MyScrollbar.UpdatePolicy := GTK_UPDATE_CONTINUOUS;
  Box3.PackStart(MyScrollbar, True, True, 10);
  MyScrollbar.Show;

  Box2 := CHBox.Create(FALSE, 10);
  Box2.BorderWidth := 10;
  Box1.PackStart(Box2, TRUE, TRUE, 0);
  Box2.Show;

  (* A checkButton to control whether the value is displayed or not *)
  TButton := CCheckButton.Create('Display value on Scale widgets');
  TButton.Active := True;
  TButton.OnToggled := @cb_draw_value;
  Box2.PackStart(TButton, TRUE, TRUE, 0);
  TButton.Show;

  Box2 := CHBox.Create(FALSE, 10);
  Box2.BorderWidth := 10;

  (* An Option menu to change the position of the value *)
  TheLabel := CLabel.Create('Scale Value Position:');
  Box2.PackStart(TheLabel, FALSE, FALSE, 0);
  TheLabel.Show;

  Opt := COptionMenu.Create;
  Menu := CMenu.Create;
  Menu.Append(MakeMenuItem ('Top',    @cb_pos_Menu_select,GTK_POS_TOP));
  Menu.Append(MakeMenuItem ('Bottom', @cb_pos_Menu_select,GTK_POS_BOTTOM));
  Menu.Append(MakeMenuItem ('Left',   @cb_pos_Menu_select,GTK_POS_LEFT));
  Menu.Append(MakeMenuItem ('Right',  @cb_pos_Menu_select,GTK_POS_RIGHT));
  Opt.Menu := PGtkWidget(Menu.GtkObject);
  Box2.PackStart(Opt, TRUE, TRUE, 0);
  Opt.Show;

  Box1.PackStart(Box2, TRUE, TRUE, 0);
  Box2.Show;

  Box2 := CHBox.Create(FALSE, 10);
  Box2.BorderWidth := 10;

  (* Yet another Option Menu, this time for the update policy of the
   * Scale widgets *)
  TheLabel := CLabel.Create('Scale Update Policy:');
  Box2.PackStart(TheLabel, FALSE, FALSE, 0);
  TheLabel.Show;

  Opt := COptionMenu.Create;
  Menu := CMenu.Create;

  Item := MakeMenuItem('Continuous',@cb_update_Menu_select,GTK_UPDATE_CONTINUOUS);
  Menu.Append(Item);

  Item := MakeMenuItem('Discontinuous',@cb_update_Menu_select,GTK_UPDATE_DISCONTINUOUS);
  Menu.Append(Item);

  Item := MakeMenuItem('Delayed',@cb_update_Menu_select,GTK_UPDATE_DELAYED);
  Menu.Append(Item);

  Opt.Menu := PGtkWidget(Menu.GtkObject);
  Box2.PackStart(Opt, TRUE, TRUE, 0);
  Opt.Show;

  Box1.PackStart(Box2, TRUE, TRUE, 0);
  Box2.Show;

  Box2 := CHBox.Create(FALSE, 10);
  Box2.BorderWidth := 10;

  (* An HScale widget for adjusting the number of digits on the
   * sample Scales. *)
  TheLabel := CLabel.Create('Scale Digits:');
  Box2.PackStart(TheLabel, FALSE, FALSE, 0);
  TheLabel.Show;

  Adj2 := CAdjustment.Create(1.0, 0.0, 5.0, 1.0, 1.0, 0.0);
  Adj2.OnValueChanged := @cb_digits_scale;
  Scale := CHScale.Create(Adj2);
  Scale.Digits := 0;
  Box2.PackStart(Scale, TRUE, TRUE, 0);
  Scale.Show;

  Box1.PackStart(Box2, TRUE, TRUE, 0);
  Box2.Show;

  Box2 := CHBox.Create(FALSE, 10);
  Box2.BorderWidth := 10;

  (* And, one last HScale widget for adjusting the page size of the
   * Scrollbar. *)
  TheLabel := CLabel.Create('Scrollbar Page Size:');
  Box2.PackStart(TheLabel, FALSE, FALSE, 0);
  TheLabel.Show;

  Adj2 := CAdjustment.Create(1.0, 1.0, 101.0, 1.0, 1.0, 0.0);
  Adj2.OnValueChanged := @cb_page_size;
  Adj2.OnValueChangedData := Adj1;
  Scale := CHScale.Create(Adj2);
  Scale.Digits := 0;
  Box2.PackStart(Scale, TRUE, TRUE, 0);
  Scale.Show;

  Box1.PackStart(Box2, TRUE, TRUE, 0);
  Box2.Show;

  Separator := CHSeparator.Create;
  Box1.PackStart(Separator, FALSE, TRUE, 0);
  Separator.Show;

  Box2 := CVBox.Create(FALSE, 10);
  Box2.BorderWidth := 10;
  Box1.PackStart(Box2, FALSE, TRUE, 0);
  Box2.Show;

  Button := CButton.Create('Quit');
  Button.OnClicked := @OnQuitButtonClicked;
  Box2.PackStart(Button, TRUE, TRUE, 0);
  { make a property for that! }
  GTK_WIDGET_SET_FLAGS (PGtkWidget(Button.GtkObject), GTK_CAN_DEFAULT);
  Button.GrabDefault;
  Button.Show;

  Show;
End;
Function CRangeWidgets.DeleteEventImpl(aEvent:PGdkEventAny):Gint;
Begin
  inherited DeleteEventImpl(aEvent);
  WriteLn('delete event occoured');
  DeleteEventImpl := 1;
End;
Procedure CRangeWidgets.Destroy_;
Begin
  inherited Destroy_;
  WriteLn('Destroy_');
  Kit.Quit;
End;

Function  CRangeWidgets.cb_pos_menu_select(Sender:CMenuItem;Data:GPointer):GBoolean;
Begin
  WriteLn('=============== cb_pos_menu_select');
  (* Set the value position on both Scale widgets *)
  HScale.ValuePos := TGtkPositionType(Data);
  VScale.ValuePos := TGtkPositionType(Data);
  cb_pos_menu_select := True;
End;
Function  CRangeWidgets.cb_update_menu_select(Sender:CMenuItem;Data:GPointer):GBoolean;
Begin
  WriteLn('=============== cb_update_menu_select');
  (* Set the update policy for both Scale widgets *)
  HScale.UpdatePolicy := TGtkUpdateType(Data);
  VScale.UpdatePolicy := TGtkUpdateType(Data);
  cb_update_menu_select := True;
End;

Function  CRangeWidgets.cb_digits_scale(Sender:CAdjustment;Data:GPointer):GBoolean;
Begin
  WriteLn('=============== cb_digits_scale');
  (* Set the number of decimal places to which adj->value is rounded *)
  HScale.Digits := Round(PGtkAdjustment(Sender.GtkObject)^.Value);
  VScale.Digits := Round(PGtkAdjustment(Sender.GtkObject)^.Value);
  cb_digits_scale := True;
End;

Function  CRangeWidgets.cb_page_size(Sender:CAdjustment;Data:GPointer):GBoolean;
Begin
  WriteLn('=============== cb_page_size');
  (* Set the page size and page increment size of the sample
   * adjustment to the value specified by the 'Page Size' Scale *)
  PGtkAdjustment(CAdjustment(Data).GtkObject)^.page_size      := Round(PGtkAdjustment(Sender.GtkObject)^.Value);
  PGtkAdjustment(CAdjustment(Data).GtkObject)^.page_increment := Round(PGtkAdjustment(Sender.GtkObject)^.Value);
  (* Now emit the 'changed' signal to reconfigure all the widgets that
   * are attached to this adjustment *)
  { !!! }
  gtk_signal_emit_by_name (GTK_OBJECT (CAdjustment(Data).GtkObject), 'changed');
  cb_page_size := True;
End;

Function  CRangeWidgets.cb_draw_value(Sender:CToggleButton;Data:GPointer):GBoolean;
Begin
  WriteLn('=============== cb_draw_value');
  (* Turn the value display on the Scale widgets off or on depending
   *  on the state of the checkButton *)
  HScale.DrawValueVar := GBoolean(active(PGtkToggleButton(Sender.GtkObject)^));
  VScale.DrawValueVar := GBoolean(active(PGtkToggleButton(Sender.GtkObject)^));
  cb_draw_value := True;
End;

Function  CRangeWidgets.OnQuitButtonClicked(Sender:CButton;Data:GPointer):GBoolean;
Begin
  Destroy_;
  OnQuitButtonClicked := True;
End;

Var Window : CWindow;

Begin
  Kit := CMain.Create(@ArgC,@ArgV,False);

  Window := CRangeWidgets.Create;

  Kit.Run;
End.

