summaryrefslogtreecommitdiff
path: root/gui/listbox.inc
diff options
context:
space:
mode:
Diffstat (limited to 'gui/listbox.inc')
-rw-r--r--gui/listbox.inc329
1 files changed, 329 insertions, 0 deletions
diff --git a/gui/listbox.inc b/gui/listbox.inc
new file mode 100644
index 00000000..07a29c97
--- /dev/null
+++ b/gui/listbox.inc
@@ -0,0 +1,329 @@
+{%mainunit fpgui.pp}
+
+{ Listbox widget implementation }
+
+{$IFDEF read_interface}
+
+ TCustomListBox = class(TWidget)
+ private
+ FHotTrack: Boolean;
+ FItems: TStrings;
+ FItemIndex: Integer;
+ function EvMousePressed(Event: TMousePressedEventObj): Boolean;
+ function EvMouseReleased(Event: TMouseReleasedEventObj): Boolean;
+ function EvMouseMoved(Event: TMouseMoveEventObj): Boolean;
+ function ProcessMouseEvent(Event: TMouseEventObj): Boolean;
+ protected
+ ScrollingSupport: TScrollingSupport;
+ FMaxItemWidth: Integer;
+ ItemHeight: Integer;
+ procedure Paint(Canvas: TFCanvas); override;
+ function ProcessEvent(Event: TEventObj): Boolean; override;
+ function DistributeEvent(Event: TEventObj): Boolean; override;
+// procedure EvKeyPressed(Key: Word; Shift: TShiftState); override;
+ procedure CalcSizes; override;
+ procedure Resized; override;
+ procedure RecalcWidth;
+ procedure UpdateScrollBars;
+ procedure RedrawItem(AIndex: Integer);
+ property CanExpandWidth default True;
+ property CanExpandHeight default True;
+ property HotTrack: Boolean read FHotTrack write FHotTrack default False;
+ property ItemIndex: Integer read FItemIndex write FItemIndex default -1;
+ public
+ constructor Create(AOwner: TComponent); override;
+ destructor Destroy; override;
+ property Items: TStrings read FItems write FItems;
+ end;
+
+
+ TListBox = class(TCustomListBox)
+ published
+ // TWidget properties
+ property OnClick;
+ property Enabled;
+ // TCustomListBox properties
+ property HotTrack;
+ property Items;
+ property ItemIndex;
+ end;
+
+{$ENDIF read_interface}
+
+
+
+{$IFDEF read_implementation}
+
+// ===================================================================
+// TListBoxStrings
+// ===================================================================
+
+type
+
+ TListBoxStrings = class(TStringList)
+ protected
+ ListBox: TCustomListBox;
+ procedure SetUpdateState(Updating: Boolean); override;
+ public
+ constructor Create(AListBox: TCustomListBox);
+ function Add(const s: String): Integer; override;
+ end;
+
+
+constructor TListBoxStrings.Create(AListBox: TCustomListBox);
+begin
+ inherited Create;
+ ListBox := AListBox;
+end;
+
+function TListBoxStrings.Add(const s: String): Integer;
+var
+ ItemWidth: Integer;
+begin
+ Result := inherited Add(s);
+ if Assigned(ListBox.FindForm) and Assigned(ListBox.FindForm.Wnd) then
+ begin
+ ItemWidth := ListBox.FindForm.Wnd.Canvas.TextWidth(s) + 4;
+ if ItemWidth > ListBox.FMaxItemWidth then
+ ListBox.FMaxItemWidth := ItemWidth;
+ ListBox.UpdateScrollBars;
+ end;
+end;
+
+procedure TListBoxStrings.SetUpdateState(Updating: Boolean);
+begin
+ if not Updating then
+ ListBox.RecalcWidth;
+end;
+
+
+// ===================================================================
+// TCustomListBox
+// ===================================================================
+
+constructor TCustomListBox.Create(AOwner: TComponent);
+begin
+ inherited Create(AOwner);
+ WidgetStyle := WidgetStyle + [wsCaptureMouse, wsClickable, wsOpaque];
+ FCanExpandWidth := True;
+ FCanExpandHeight := True;
+
+ ScrollingSupport := TScrollingSupport.Create(Self);
+ ScrollingSupport.HorzScrollBar.OnScroll :=
+ @ScrollingSupport.DefHorzScrollHandler;
+ ScrollingSupport.VertScrollBar.OnScroll :=
+ @ScrollingSupport.DefVertScrollHandler;
+ Items := TListBoxStrings.Create(Self);
+ FItemIndex := -1;
+ UpdateScrollBars;
+end;
+
+destructor TCustomListBox.Destroy;
+begin
+ Items.Free;
+ ScrollingSupport.Free;
+ inherited Destroy;
+end;
+
+
+// protected methods
+
+procedure TCustomListBox.Paint(Canvas: TFCanvas);
+var
+ i, StartIndex, EndIndex: Integer;
+ ItemRect: TRect;
+ ItemFlags: TItemFlags;
+begin
+ inherited Paint(Canvas);
+
+ if not Canvas.IntersectClipRect(ScrollingSupport.ClientRect) then
+ exit;
+
+ Style.SetUIColor(Canvas, clWindow);
+// Style.DrawWindowBackground(Canvas, ScrollingSupport.ClientRect);
+ Canvas.FillRect(ScrollingSupport.ClientRect);
+ Style.SetUIColor(Canvas, clWindowText);
+
+ with ScrollingSupport.VertScrollBar do
+ begin
+ StartIndex := Position div ItemHeight;
+ EndIndex := (Position + PageSize) div ItemHeight;
+ end;
+
+ Canvas.AppendTranslation(ScrollingSupport.ClientRect.TopLeft -
+ ScrollingSupport.ScrollPos);
+
+ if StartIndex < 0 then
+ StartIndex := 0;
+ if EndIndex >= Items.Count then
+ EndIndex := Items.Count - 1;
+
+ for i := StartIndex to EndIndex do
+ begin
+ Canvas.SaveState;
+
+ ItemRect.Left := ScrollingSupport.HorzScrollBar.Position;
+ ItemRect.Top := i * ItemHeight;
+ ItemRect.Right := ScrollingSupport.ClientRect.Right -
+ ScrollingSupport.ClientRect.Left +
+ ScrollingSupport.HorzScrollBar.Position;
+ ItemRect.Bottom := (i + 1) * ItemHeight;
+
+ Canvas.IntersectClipRect(ItemRect);
+
+ ItemFlags := [];
+ if (wsHasFocus in WidgetState) and ((i = ItemIndex) or
+ ((ItemIndex = -1) and (i = 0))) then
+ Include(ItemFlags, ifFocused);
+ if i = ItemIndex then
+ Include(ItemFlags, ifSelected);
+
+ Style.DrawItemBefore(Canvas, ItemRect, ItemFlags);
+// Canvas.TextOut(Point(2, i * ItemHeight), Items[i]);
+ Style.DrawText(Canvas, Point(2, i * ItemHeight), Items[i], WidgetState);
+ Style.DrawItemAfter(Canvas, ItemRect, ItemFlags);
+
+ Canvas.RestoreState;
+ end;
+end;
+
+function TCustomListBox.ProcessEvent(Event: TEventObj): Boolean;
+begin
+ if Event.InheritsFrom(TMousePressedEventObj) then
+ Result := ScrollingSupport.ProcessEvent(Event) or
+ EvMousePressed(TMousePressedEventObj(Event)) or
+ inherited ProcessEvent(Event)
+ else if Event.InheritsFrom(TMouseReleasedEventObj) then
+ Result := ScrollingSupport.ProcessEvent(Event) or
+ EvMouseReleased(TMouseReleasedEventObj(Event)) or
+ inherited ProcessEvent(Event)
+ else if Event.InheritsFrom(TMouseMoveEventObj) then
+ Result := ScrollingSupport.ProcessEvent(Event) or
+ EvMouseMoved(TMouseMoveEventObj(Event)) or
+ inherited ProcessEvent(Event)
+ else
+ Result := ScrollingSupport.ProcessEvent(Event) or
+ inherited ProcessEvent(Event);
+end;
+
+function TCustomListBox.DistributeEvent(Event: TEventObj): Boolean;
+begin
+ Result := ScrollingSupport.DistributeEvent(Event) or
+ inherited DistributeEvent(Event);
+end;
+
+procedure TCustomListBox.CalcSizes;
+begin
+ ScrollingSupport.CalcSizes;
+ ItemHeight := FindForm.Wnd.Canvas.FontCellHeight;
+ ScrollingSupport.VertScrollBar.SmallChange := ItemHeight;
+ RecalcWidth;
+end;
+
+procedure TCustomListBox.Resized;
+begin
+ ScrollingSupport.Resized;
+ UpdateScrollBars;
+end;
+
+procedure TCustomListBox.RecalcWidth;
+var
+ i, ItemWidth: Integer;
+begin
+ if (not Assigned(FindForm)) or (not Assigned(FindForm.Wnd)) then
+ exit;
+
+ FMaxItemWidth := 0;
+ for i := 0 to Items.Count - 1 do
+ begin
+ ItemWidth := FindForm.Wnd.Canvas.TextWidth(Items[i]) + 4;
+ if ItemWidth > FMaxItemWidth then
+ FMaxItemWidth := ItemWidth;
+ end;
+ UpdateScrollBars;
+end;
+
+procedure TCustomListBox.UpdateScrollBars;
+begin
+ ScrollingSupport.SetVirtualSize(
+ gfxBase.Size(FMaxItemWidth, Items.Count * ItemHeight - 1));
+end;
+
+procedure TCustomListBox.RedrawItem(AIndex: Integer);
+var
+ ItemRect: TRect;
+begin
+ if AIndex < 0 then
+ exit;
+ ItemRect := ScrollingSupport.ClientRect;
+ Inc(ItemRect.Top, AIndex * ItemHeight -
+ ScrollingSupport.VertScrollBar.Position);
+ if (ItemRect.Top > ScrollingSupport.ClientRect.Bottom) or
+ (ItemRect.Top + ItemHeight <= ScrollingSupport.ClientRect.Top) then
+ exit;
+ ItemRect.Bottom := Min(ItemRect.Top + ItemHeight,
+ ScrollingSupport.ClientRect.Bottom);
+ Redraw(ItemRect);
+end;
+
+
+// private methods
+
+function TCustomListBox.EvMousePressed(Event: TMousePressedEventObj): Boolean;
+begin
+ if HotTrack then
+ Result := False
+ else if Event.Button = mbLeft then
+ Result := ProcessMouseEvent(Event)
+ else
+ Result := False;
+end;
+
+function TCustomListBox.EvMouseReleased(Event: TMouseReleasedEventObj): Boolean;
+begin
+ if HotTrack and (Event.Button = mbLeft) then
+ Result := ProcessMouseEvent(Event)
+ else
+ Result := False;
+end;
+
+function TCustomListBox.EvMouseMoved(Event: TMouseMoveEventObj): Boolean;
+begin
+ if HotTrack then
+ Result := ProcessMouseEvent(Event)
+ else
+ Result := False;
+end;
+
+function TCustomListBox.ProcessMouseEvent(Event: TMouseEventObj): Boolean;
+var
+ Index: Integer;
+begin
+ if not PtInRect(ScrollingSupport.ClientRect, Event.Position) then
+ begin
+ Result := False;
+ exit;
+ end;
+
+ Index := (Event.Position.y - ScrollingSupport.ClientRect.Top +
+ ScrollingSupport.VertScrollBar.Position) div ItemHeight;
+ if (Index >= 0) and (Index < Items.Count) and ((Index <> ItemIndex) or
+ (HotTrack and Event.InheritsFrom(TMouseReleasedEventObj))) then
+ begin
+ RedrawItem(ItemIndex);
+ FItemIndex := Index;
+ RedrawItem(ItemIndex);
+ if (not Event.InheritsFrom(TMouseMoveEventObj)) and Assigned(OnClick) then
+ OnClick(Self);
+ end;
+
+{ !!!: Re-include this for correct focus handling. But at the moment a focus
+ change results in a complete widget redraw, which is not very brilliant. }
+// inherited ProcessEvent(Event);
+
+ Result := True;
+end;
+
+
+{$ENDIF read_implementation}
+