1{%MainUnit winceint.pp}
2
3{******************************************************************************
4                                 wincelistsl.inc
5  TWinCEListStringList, TWinCEComboBoxStringList and TWinCECheckListBoxStrings
6
7 ******************************************************************************
8
9 *****************************************************************************
10  This file is part of the Lazarus Component Library (LCL)
11
12  See the file COPYING.modifiedLGPL.txt, included in this distribution,
13  for details about the license.
14 *****************************************************************************
15}
16
17{$IFOPT H+}
18  {$DEFINE H_PLUS}
19{$ELSE}
20  {$H+}
21  {$UNDEF H_PLUS}
22{$ENDIF}
23
24{*************************************************************}
25{                      Default compare function               }
26{*************************************************************}
27
28function DefaultCompareFunc(A, B: HWND): Integer; CDecl;
29Var
30  AStr, BStr: PWideChar;
31Begin
32  AStr:=nil;
33  BStr:=nil;
34  GetWindowTextW(A, AStr, GetWindowTextLength(A) + 1);
35  GetWindowTextW(B, BStr, GetWindowTextLength(B) + 1);
36  Result := WideCompareStr(widestring(AStr), widestring(BStr));//roozbeh:does this work?!
37end;
38
39{*************************************************************}
40{                      TWinCEListStringList methods           }
41{*************************************************************}
42
43{------------------------------------------------------------------------------
44  Method: TWinCEListStringList.Create
45  Params:
46  Returns:
47
48 ------------------------------------------------------------------------------}
49constructor TWinCEListStringList.Create(List : HWND; TheOwner: TWinControl);
50begin
51  inherited Create;
52  if List = HWND(nil) then
53    Raise Exception.Create('Unspecified list window');
54    //DebugLn('Trace:Unspecified list window');
55  FWinCEList := List;
56  FSender := TheOwner;
57
58  //Set proper wince flags for ComboBox/ListBox and get/set Combo Height
59  InitFlags;
60  // Determine if the list is sorted
61  FSorted := (UINT(GetWindowLong(FWinCEList, GWL_STYLE)) and FFlagSort <> 0);
62end;
63
64procedure TWinCEListStringList.InitFlags;
65begin
66  FFlagSort         := UINT(LBS_SORT);
67  FFlagGetText      := UINT(LB_GETTEXT);
68  FFlagGetTextLen   := UINT(LB_GETTEXTLEN);
69  FFlagGetCount     := UINT(LB_GETCOUNT);
70  FFlagResetContent := UINT(LB_RESETCONTENT);
71  FFlagDeleteString := UINT(LB_DELETESTRING);
72  FFlagInsertString := UINT(LB_INSERTSTRING);
73  FFlagAddString    := UINT(LB_ADDSTRING);
74  FFlagGetItemData  := UINT(LB_GETITEMDATA);
75  FFlagSetItemData  := UINT(LB_SETITEMDATA);
76  FFlagGetItemIndex := UINT(LB_GETCURSEL);
77  FFlagSetItemIndex := UINT(LB_SETCURSEL);
78  FFlagGetSelected  := UINT(LB_GETSEL);
79  FFlagSetSelected  := UINT(LB_SETSEL);
80end;
81
82{------------------------------------------------------------------------------
83  Method: TWinCEListStringList.SetSorted
84  Params:
85  Returns:
86
87 ------------------------------------------------------------------------------}
88procedure TWinCEListStringList.SetSorted(Val: Boolean);
89Begin
90  If Val <> FSorted Then
91  Begin
92    FSorted:= Val;
93    Sort;
94  End;
95End;
96
97{------------------------------------------------------------------------------
98  Method: TWinCEListStringList.Sort
99  Params:
100  Returns:
101
102 ------------------------------------------------------------------------------}
103procedure TWinCEListStringList.Sort;
104Begin
105  // The win api doesn't allow to change the sort on the fly,
106  // so is needed to recreate the window
107  RecreateWnd(FSender);
108End;
109
110{------------------------------------------------------------------------------
111  Method: TWinCEListStringList.Assign
112  Params:
113  Returns:
114
115 ------------------------------------------------------------------------------}
116procedure TWinCEListStringList.Assign(Source: TPersistent);
117Var
118  S: TStrings;
119  Counter: Integer;
120  AnIndex: Integer;
121  tmpStr : widestring;
122Begin
123  { Do not call inherited Assign as it does things we do not want to happen }
124  If Source Is TStrings Then
125  Begin
126    S:= TStrings(Source);
127    QuoteChar:=S.QuoteChar;
128    Delimiter:=S.Delimiter;
129    NameValueSeparator:=S.NameValueSeparator;
130    Windows.SendMessage(FWinCEList, FFlagResetContent, 0, 0);
131    For Counter := 0 To (TStrings(Source).Count - 1) Do
132    Begin
133      tmpStr := UTF8Decode(s[Counter]);
134      AnIndex := Windows.SendMessageW(FWinCEList, FFlagAddString, 0,
135       LPARAM(PWideChar(tmpStr))); //Insert
136      PutObject(AnIndex, S.Objects[Counter]);
137    end;
138  End
139  Else
140    inherited Assign(Source);
141End;
142
143
144{------------------------------------------------------------------------------
145  Method: TWinCEListStringList.Add
146  Params:
147  Returns:
148
149 ------------------------------------------------------------------------------}
150function TWinCEListStringList.Add(const S: string): Integer;
151begin
152  Result := Count;
153  Insert(Count, S);
154  if FSorted then
155    Result := FLastInsertedIndex;
156end;
157
158{------------------------------------------------------------------------------
159  Method: TWinCEListStringList.Get
160  Params:
161  Returns:
162
163 ------------------------------------------------------------------------------}
164function TWinCEListStringList.Get(Index: Integer): String;
165Var
166  w: widestring;
167Begin
168  If (Index < 0) Or (Index >= Count) Then
169    Raise Exception.Create('Out of bounds.')
170  Else
171  Begin
172    SetLength(w, Windows.SendMessageW(FWinCEList, FFlagGetTextLen, Index, 0));
173    Windows.SendMessageW(FWinCEList, FFlagGetText, Index, LPARAM(PWideChar(w)));
174    Result := UTF8Encode(w);
175  End;
176End;
177
178{------------------------------------------------------------------------------
179  Method: TWinCEListStringList.GetCount
180  Params:
181  Returns:
182
183 ------------------------------------------------------------------------------}
184function TWinCEListStringList.GetCount: Integer;
185Begin
186  Result := Windows.SendMessage(FWinCEList, FFlagGetCount, 0, 0);
187End;
188
189{------------------------------------------------------------------------------
190  Method: TWinCEListStringList.Clear
191  Params:
192  Returns:
193
194 ------------------------------------------------------------------------------}
195procedure TWinCEListStringList.Clear;
196Begin
197  Windows.SendMessage(FWinCEList, FFlagResetContent, 0, 0);
198End;
199
200{------------------------------------------------------------------------------
201  Method: TWinCEListStringList.Delete
202  Params:
203  Returns:
204
205 ------------------------------------------------------------------------------}
206procedure TWinCEListStringList.Delete(Index: Integer);
207Begin
208  Windows.SendMessage(FWinCEList, FFlagDeleteString, Index, 0);
209End;
210
211{------------------------------------------------------------------------------
212  Method: TWinCEListStringList.GetObject
213  Params:
214  Returns:
215
216 ------------------------------------------------------------------------------}
217function TWinCEListStringList.GetObject(Index: Integer): TObject;
218Begin
219  HWND(Result) := Windows.SendMessageW(FWinCEList, FFlagGetItemData, Index, 0);
220End;
221
222{------------------------------------------------------------------------------
223  Method: TWinCEListStringList.Insert
224  Params:
225  Returns:
226
227 ------------------------------------------------------------------------------}
228procedure TWinCEListStringList.Insert(Index: Integer; Const S: String);
229Begin
230  FLastInsertedIndex := Index;
231  if FSorted then
232    FLastInsertedIndex := Windows.SendMessageW(FWinCEList, FFlagAddString, 0, LPARAM(PWideChar(Utf8Decode(S))))
233  else
234    Windows.SendMessageW(FWinCEList, FFlagInsertString, Index, LPARAM(PWideChar(Utf8Decode(S))));
235End;
236
237procedure TWinCEListStringList.Put(Index: integer; const S: string);
238var
239  lItemIndex: integer;
240  lSelected: boolean;
241begin
242  // remember selection
243  lItemIndex := -1;
244  if FFlagGetSelected <> 0 then
245  begin
246    lItemIndex := SendMessageW(FWinCEList, FFlagGetSelected, Index, 0);
247    lSelected := lItemIndex > 0;
248    if lItemIndex <> LB_ERR then
249      lItemIndex := Index;
250  end;
251  if lItemIndex = -1 then
252  begin
253    lItemIndex := SendMessageW(FWinCEList, FFlagGetItemIndex, 0, 0);
254    lSelected := true;
255  end;
256
257  inherited;
258
259  if lSelected then
260  begin
261    if (FFlagSetSelected = 0)
262      or (SendMessageW(FWinCEList, FFlagSetSelected, Windows.WParam(true), lItemIndex) = -1) then
263    begin
264      SendMessageW(FWinCEList, FFlagSetItemIndex, lItemIndex, 0);
265    end;
266  end;
267end;
268
269{------------------------------------------------------------------------------
270  Method: TWinCEListStringList.PutObject
271  Params:
272  Returns:
273
274 ------------------------------------------------------------------------------}
275procedure TWinCEListStringList.PutObject(Index: Integer; AObject: TObject);
276Begin
277  Windows.SendMessage(FWinCEList, FFlagSetItemData, Index, LPARAM(AObject));
278End;
279
280{ TWinCEComboBoxStringList }
281
282procedure TWinCEComboBoxStringList.InitFlags;
283var
284  R: TRect;
285begin
286  FFlagSort         := UINT(CBS_SORT);
287  FFlagGetText      := UINT(CB_GETLBTEXT);
288  FFlagGetTextLen   := UINT(CB_GETLBTEXTLEN);
289  FFlagGetCount     := UINT(CB_GETCOUNT);
290  FFlagResetContent := UINT(CB_RESETCONTENT);
291  FFlagDeleteString := UINT(CB_DELETESTRING);
292  FFlagInsertString := UINT(CB_INSERTSTRING);
293  FFlagAddString    := UINT(CB_ADDSTRING);
294  FFlagGetItemData  := UINT(CB_GETITEMDATA);
295  FFlagSetItemData  := UINT(CB_SETITEMDATA);
296  FFlagGetItemIndex := UINT(CB_GETCURSEL);
297  FFlagSetItemIndex := UINT(CB_SETCURSEL);
298  FFlagGetSelected  := UINT(0);
299  FFlagSetSelected  := UINT(0);
300  //Get edit and item sizes
301  Windows.GetClientRect(FWinCEList,@R);
302  FEditHeight := R.Bottom;
303  FItemHeight := Windows.SendMessage(FWinCEList, CB_GETITEMHEIGHT, 0, 0);
304  FDropDownCount := TComboBox(FSender).DropDownCount;
305  If FDropDownCount = 0 then
306    FDropDownCount := 8;
307end;
308
309procedure TWinCEComboBoxStringList.UpdateComboHeight;
310var
311  Left, Top, Width, Height: integer;
312begin
313  Left := FSender.Left;
314  Top := FSender.Top;
315  Width := FSender.Width;
316  Height := ComboHeight;
317  LCLBoundsToWin32Bounds(FSender, Left, Top, Width, Height);
318  MoveWindow(FSender.Handle, Left, Top, Width, Height, true);
319  LCLControlSizeNeedsUpdate(FSender, true);
320end;
321
322procedure TWinCEComboBoxStringList.Assign(Source: TPersistent);
323var
324  EditText: string;
325  lItemIndex: integer;
326begin
327  if Source is TStrings then
328  begin
329    // save text in edit box, assigning strings clears the text
330    TWinCEWSCustomComboBox.GetText(FSender, EditText);
331
332    inherited Assign(Source);
333
334    // restore text in edit box
335    UpdateComboHeight;
336    TWinCEWSCustomComboBox.SetText(FSender, EditText);
337    lItemIndex := IndexOf(EditText);
338    if lItemIndex <> -1 then
339      TWinCEWSCustomComboBox.SetItemIndex(TCustomComboBox(FSender), lItemIndex);
340  end else
341    inherited Assign(Source);
342end;
343
344function TWinCEComboBoxStringList.GetComboHeight: integer;
345begin
346  if (FSender is TCustomComboBox) and (TCustomComboBox(FSender).Style = csSimple) then
347  begin
348    // combobox workaround:
349    // if style = csSimple follow the LCL height.
350    Result := FSender.Height;
351  end else
352  begin
353    if Count = 0 then
354    begin
355      Result := FEditHeight + FItemHeight + 2;
356    end else
357    begin
358      Result := FEditHeight + FDropDownCount * FItemHeight + 2;
359    end;
360  end;
361end;
362
363procedure TWinCEComboBoxStringList.Clear;
364var
365  SaveText: String;
366begin
367  if not TCustomComboBox(FSender).ReadOnly then
368    SaveText := TCustomComboBox(FSender).Text;
369  inherited;
370  UpdateComboHeight;
371  if not TCustomComboBox(FSender).ReadOnly then
372    TCustomComboBox(FSender).Text := SaveText;
373end;
374
375procedure TWinCEComboBoxStringList.Delete(Index: integer);
376begin
377  inherited Delete(Index);
378  if Count <= 1 then
379    UpdateComboHeight;
380end;
381
382procedure TWinCEComboBoxStringList.Insert(Index: integer; const S: string);
383begin
384  inherited Insert(Index, S);
385  if GetCount = 1 then
386    UpdateComboHeight;
387end;
388
389
390{ TWinCECheckListBoxStrings }
391
392constructor TWinCECheckListBoxStrings.Create(List : HWND; TheOwner: TWinControl);
393begin
394  inherited Create(List, TheOwner);
395  with FDefaultItem do
396  begin
397    State := cbUnchecked;
398    TheObject := nil;
399  end;
400end;
401
402function TWinCECheckListBoxStrings.GetState(AIndex: Integer): TCheckBoxState;
403var
404  Data: PWinCECheckListBoxItemRecord;
405begin
406  Data := GetItemRecord(AIndex, False);
407  Result := Data^.State
408end;
409
410function TWinCECheckListBoxStrings.GetItemRecord(const Index: Integer;
411  const CreateNew: boolean): PWinCECheckListBoxItemRecord;
412begin
413  Result := PWinCECheckListBoxItemRecord(Windows.SendMessage(FWinCEList, LB_GETITEMDATA, Index, 0));
414  if (not Assigned(Result)) then begin
415    if CreateNew then begin
416      Result := new(PWinCECheckListBoxItemRecord);
417      Result^ := FDefaultItem;
418    end
419    else Result := @FDefaultItem;
420  end;
421end;
422
423procedure TWinCECheckListBoxStrings.SetItemRecord(const Index: Integer;
424  ItemRecord: PWinCECheckListBoxItemRecord);
425begin
426  Windows.SendMessage(FWinCEList, LB_SETITEMDATA, Index, LPARAM(ItemRecord));
427end;
428
429procedure TWinCECheckListBoxStrings.SetState(AIndex: Integer;
430  const AValue: TCheckBoxState);
431var
432  ItemRecord: PWinCECheckListBoxItemRecord;
433begin
434  ItemRecord := GetItemRecord(AIndex, True);
435  ItemRecord^.State := AValue;
436  SetItemRecord(AIndex, ItemRecord);
437end;
438
439procedure TWinCECheckListBoxStrings.Clear;
440begin
441  DeleteItemRecords(FWinCEList);
442  inherited Clear;
443end;
444
445procedure TWinCECheckListBoxStrings.Delete(Index: Integer);
446begin
447  DeleteItemRecord(FWinCEList, Index);
448  inherited Delete(Index);
449end;
450
451procedure TWinCECheckListBoxStrings.Move(CurIndex, NewIndex: Integer);
452var
453  AState: TCheckBoxState;
454begin
455  AState := State[CurIndex];
456  inherited Move(CurIndex, NewIndex);
457  State[NewIndex] := AState;
458end;
459
460function TWinCECheckListBoxStrings.GetObject(Index: Integer): TObject;
461begin
462  Result:= GetItemRecord(Index, false)^.TheObject;
463end;
464
465procedure TWinCECheckListBoxStrings.PutObject(Index: Integer; AObject: TObject);
466var
467  ItemRecord: PWinCECheckListBoxItemRecord;
468begin
469  ItemRecord := GetItemRecord(Index, true);
470  ItemRecord^.TheObject := AObject;
471  SetItemRecord(Index, ItemRecord);
472end;
473
474class procedure TWinCECheckListBoxStrings.DeleteItemRecords(const List: HWND);
475var
476  Index: Integer;
477  ItemCount: Integer;
478begin
479  ItemCount := Windows.SendMessage(List, LB_GETCOUNT, 0, 0);
480  for Index := 0 to ItemCount-1 do
481    DeleteItemRecord(List, Index);
482end;
483
484class procedure TWinCECheckListBoxStrings.DeleteItemRecord(const List: HWND;const Index: integer);
485var
486  ItemRecord: PWinCECheckListBoxItemRecord;
487begin
488  ItemRecord := PWinCECheckListBoxItemRecord(Windows.SendMessage(List, LB_GETITEMDATA, Index, 0));
489  if Assigned(ItemRecord)
490    then Dispose(ItemRecord);
491end;
492
493{$IFDEF H_PLUS}
494  {$UNDEF H_PLUS}
495{$ELSE}
496  {$H-}
497{$ENDIF}
498
499
500
501
502