четверг, ноября 06, 2014
Пространства имен. Неработающая фича Delphi.
воскресенье, апреля 13, 2014
Эмуляция перегружаемых дефолтных свойств во FreePascal 2.7.1
В настоящий момент FreePascal не поддерживает перегружаемые дефолтные свойства (на что есть соответствующий запрос), поддержка которых появилась в Delphi после седьмой версии. Нельзя сказать, что это киллер-фича, но иногда она бывает очень полезной. Однако, с появлением поддержки улучшенных записей (advanced records) и перегрузки операторов появилась возможность немного сгладить этот досадный недостаток. От слов к коду:
program project1;
{$IFNDEF FPC}
{$APPTYPE CONSOLE}
{$DEFINE HAS_OVERLOADABLE_DEFAULT_PROPERTIES}
{$ELSE}
{$MODE DELPHI}
{$ENDIF}
Type
//
TContainer = Record
{$IFNDEF HAS_OVERLOADABLE_DEFAULT_PROPERTIES}
Strict Private
Type
//
StringNameOrIntegerId = Record
FKind : (ikName, ikId);
FName : String;
FId : Integer;
Class Operator Implicit(Const AName : String) : StringNameOrIntegerId;
Class Operator Implicit(Const AId : Integer) : StringNameOrIntegerId;
End;
//
{$ENDIF}
Private
Function GetItemByName(Const AName : String) : TObject;
Function GetItemById(Const AId : Integer) : TObject;
{$IFNDEF HAS_OVERLOADABLE_DEFAULT_PROPERTIES}
Function GetItem(Const ANameOrId : StringNameOrIntegerId) : TObject;
{$ENDIF}
Public
{$IFDEF HAS_OVERLOADABLE_DEFAULT_PROPERTIES}
Property Items[Const AName : String] : TObject Read GetItemByName; Default;
Property Items[Const AId : Integer] : TObject Read GetItemById; Default;
{$ELSE}
Property Items[Const ANameOrId : StringNameOrIntegerId] : TObject Read GetItem; Default;
{$ENDIF}
End;
{$IFNDEF HAS_OVERLOADABLE_DEFAULT_PROPERTIES}
{ TContainer.StringNameOrIntegerId }
//
Class Operator TContainer.StringNameOrIntegerId.Implicit(Const AName : String) : StringNameOrIntegerId;
Begin
Result.FKind := ikName;
Result.FName := AName;
End;
//
//
Class Operator TContainer.StringNameOrIntegerId.Implicit(Const AId : Integer) : StringNameOrIntegerId;
Begin
Result.FKind := ikId;
Result.FId := AId;
End;
//
{$ENDIF}
{ TContainer }
//
Function TContainer.GetItemByName(Const AName : String) : TObject;
Begin
Result := TObject(1); // stub
End;
//
//
Function TContainer.GetItemById(Const AId : Integer) : TObject;
Begin
Result := TObject(2); // stub
End;
//
{$IFNDEF HAS_OVERLOADABLE_DEFAULT_PROPERTIES}
//
Function TContainer.GetItem(Const ANameOrId : StringNameOrIntegerId) : TObject;
Begin
Case ANameOrId.FKind Of
ikName : Result := GetItemByName(ANameOrId.FName);
ikId : Result := GetItemById(ANameOrId.FId);
End;
End;
//
{$ENDIF}
Var
cnt : TContainer;
begin
Assert(cnt['name'] = TObject(1));
Assert(cnt[1024] = TObject(2));
WriteLn('Overloadable default properties works fine!');
ReadLn;
end.
Это готовый пример который можно собрать в Delphi и FreePascal 2.7.1. Из кода видно, что проблему решает новый тип – улучшеная запись выступающий в качестве типа индекса дефолтного свойства и инкапсулирующий реальный тип индекса. Прикладной код, при этом, остается полностью совместимым с Delphi и возможной поддержкой перегружаемых дефолтных свойств во FreePascal в будущем.
Данный метод также может пригодится в случае, когда некое свойство (не обязательно перегружаемое и дефолтное) должно принимать значения ограниченного числа типов, т.е. это может быть полезно не только для FreePascal, но и для Delphi.
четверг, марта 20, 2014
QPS в действии?
18 марта, баг-репорт QC#121566, которому были посвящены четыре поста “с ассемблером”, получил статус Resolved. Это, конечно, еще не Closed, но... Будем надеяться :) Хотя сам по себе факт решения проблемы довольно будничный, но не упомянуть о нем после широкой огласки было-бы несправедливо. Хочу поблагодарить всех, кто проголосовал, а также тех, кто способствовал распространению информации о данной проблеме. Спасибо.
Напомню, что в обновленной дорожной карте RAD Studio, Delphi and C++Builder на 2014 год, одним из пунктов декларируется QPS (Quality, Performance, Stability). Давно пора!
вторник, марта 11, 2014
Delphi. Ненависть. Продолжение истории.
В попытках найти решение проблемы с говнокодогенератором Delphi, я понял, что все хуже, чем я предполагал.
среда, февраля 05, 2014
Delphi. Ненависть 2. 64-битная версия
Пост-продолжение Delphi. Ненависть 2.
------------------------------ Delphi XE2 Update 4 Hotfix 1 x64:
Project1.dpr.68: Utils.Namespace.CompareString(S1, S2);
0000000000426680 488D4D58 lea rcx,[rbp+$58]
0000000000426684 488B15BDEB0000 mov rdx,[rel $0000ebbd]
000000000042668B E86020FEFF call @UStrLAsg
0000000000426690 488D4D50 lea rcx,[rbp+$50]
0000000000426694 488B15B5EB0000 mov rdx,[rel $0000ebb5]
000000000042669B E85020FEFF call @UStrLAsg
00000000004266A0 488B4D58 mov rcx,[rbp+$58]
00000000004266A4 488B5550 mov rdx,[rbp+$50]
00000000004266A8 E82349FFFF call CompareStr
Project1.dpr.69: Utils.Namespace.SameString(S1, S2);
00000000004266AD 488D4D48 lea rcx,[rbp+$48]
00000000004266B1 488B1590EB0000 mov rdx,[rel $0000eb90]
00000000004266B8 E83320FEFF call @UStrLAsg
00000000004266BD 488D4D40 lea rcx,[rbp+$40]
00000000004266C1 488B1588EB0000 mov rdx,[rel $0000eb88]
00000000004266C8 E82320FEFF call @UStrLAsg
00000000004266CD 488D4D38 lea rcx,[rbp+$38]
00000000004266D1 488B5548 mov rdx,[rbp+$48]
00000000004266D5 E81620FEFF call @UStrLAsg
00000000004266DA 488D4D30 lea rcx,[rbp+$30]
00000000004266DE 488B5540 mov rdx,[rbp+$40]
00000000004266E2 E80920FEFF call @UStrLAsg
00000000004266E7 488B4D38 mov rcx,[rbp+$38]
00000000004266EB 488B5530 mov rdx,[rbp+$30]
00000000004266EF E8DC48FFFF call CompareStr
------------------------------ Delphi XE5 Update 2 x64:
Project1.dpr.68: Utils.Namespace.CompareString(S1, S2);
0000000000426F94 488D4D78 lea rcx,[rbp+$78]
0000000000426F98 488B1581F20000 mov rdx,[rel $0000f281]
0000000000426F9F E88C23FEFF call @UStrLAsg
0000000000426FA4 488D4D70 lea rcx,[rbp+$70]
0000000000426FA8 488B1579F20000 mov rdx,[rel $0000f279]
0000000000426FAF E87C23FEFF call @UStrLAsg
0000000000426FB4 90 nop
0000000000426FB5 488B4D78 mov rcx,[rbp+$78]
0000000000426FB9 488B5570 mov rdx,[rbp+$70]
0000000000426FBD E86E34FFFF call CompareStr
0000000000426FC2 89453C mov [rbp+$3c],eax
0000000000426FC5 90 nop
0000000000426FC6 488D4D78 lea rcx,[rbp+$78]
0000000000426FCA E8411EFEFF call @UStrClr
0000000000426FCF 488D4D70 lea rcx,[rbp+$70]
0000000000426FD3 E8381EFEFF call @UStrClr
Project1.dpr.69: Utils.Namespace.SameString(S1, S2);
0000000000426FD8 488D4D58 lea rcx,[rbp+$58]
0000000000426FDC 488B153DF20000 mov rdx,[rel $0000f23d]
0000000000426FE3 E84823FEFF call @UStrLAsg
0000000000426FE8 488D4D50 lea rcx,[rbp+$50]
0000000000426FEC 488B1535F20000 mov rdx,[rel $0000f235]
0000000000426FF3 E83823FEFF call @UStrLAsg
0000000000426FF8 488D4D68 lea rcx,[rbp+$68]
0000000000426FFC E80F1EFEFF call @UStrClr
0000000000427001 488D4D60 lea rcx,[rbp+$60]
0000000000427005 E8061EFEFF call @UStrClr
000000000042700A 488D4D48 lea rcx,[rbp+$48]
000000000042700E E8FD1DFEFF call @UStrClr
0000000000427013 488D4D40 lea rcx,[rbp+$40]
0000000000427017 E8F41DFEFF call @UStrClr
000000000042701C 90 nop
000000000042701D 488D4D68 lea rcx,[rbp+$68]
0000000000427021 488B5558 mov rdx,[rbp+$58]
0000000000427025 E80623FEFF call @UStrLAsg
000000000042702A 488D4D60 lea rcx,[rbp+$60]
000000000042702E 488B5550 mov rdx,[rbp+$50]
0000000000427032 E8F922FEFF call @UStrLAsg
0000000000427037 90 nop
0000000000427038 488B4D68 mov rcx,[rbp+$68]
000000000042703C 488B5560 mov rdx,[rbp+$60]
0000000000427040 E8EB33FFFF call CompareStr
0000000000427045 894534 mov [rbp+$34],eax
0000000000427048 90 nop
0000000000427049 488D4D68 lea rcx,[rbp+$68]
000000000042704D E8BE1DFEFF call @UStrClr
0000000000427052 488D4D60 lea rcx,[rbp+$60]
0000000000427056 E8B51DFEFF call @UStrClr
000000000042705B 837D3400 cmp dword ptr [rbp+$34],$00
000000000042705F 0F94C0 setz al
0000000000427062 88453B mov [rbp+$3b],al
0000000000427065 90 nop
0000000000427066 488D4D58 lea rcx,[rbp+$58]
000000000042706A E8A11DFEFF call @UStrClr
000000000042706F 488D4D50 lea rcx,[rbp+$50]
0000000000427073 E8981DFEFF call @UStrClr
0000000000427078 488D4D68 lea rcx,[rbp+$68]
000000000042707C E88F1DFEFF call @UStrClr
0000000000427081 488D4D60 lea rcx,[rbp+$60]
0000000000427085 E8861DFEFF call @UStrClr
000000000042708A 488D4D48 lea rcx,[rbp+$48]
000000000042708E E87D1DFEFF call @UStrClr
0000000000427093 488D4D40 lea rcx,[rbp+$40]
0000000000427097 E8741DFEFF call @UStrClr
------------------------------ FreePascal 2.7.1. x64:
project1.lpr:68 Utils.Namespace.CompareString(S1, S2);
000000010000158A 488b157fda0100 mov 0x1da7f(%rip),%rdx # 0x10001f010
0000000100001591 488b0d68da0100 mov 0x1da68(%rip),%rcx # 0x10001f000
0000000100001598 e843e40000 callq 0x10000f9e0 <SYSUTILS_$$_COMPARESTR$ANSISTRING$ANSISTRING$$LONGINT>
project1.lpr:69 Utils.Namespace.SameString(S1, S2);
000000010000159D 488b156cda0100 mov 0x1da6c(%rip),%rdx # 0x10001f010
00000001000015A4 488b0d55da0100 mov 0x1da55(%rip),%rcx # 0x10001f000
00000001000015AB e830e40000 callq 0x10000f9e0 <SYSUTILS_$$_COMPARESTR$ANSISTRING$ANSISTRING$$LONGINT>
00000001000015B0 85c0 test %eax,%eax
00000001000015B2 0f94c0 sete %al
пятница, января 31, 2014
Firemonkey, которая гуляет сама по себе.
В одном из прошлых постов я упоминал о фантомных срабатываниях сенсорного экрана в Firemonkey-приложениях. Ввиду того, что воспроизвести это не так просто, а на слово верить в такое не хочется, пару дней назад я заснял этот эффект на видео. Прошу прощения за качество, делалось впопыхах.
Воспроизведено на устройстве Huawei Ascend Mate, Android 4.1.2, ланчер EmotionUI 1.5.
Проект на котором очень хорошо воспроизводятся эти эффекты можно взять тут (прямая ссылка).
На видео видно, что несмотря на фантомные срабатывания, когда к устройству даже не прикосаешься, само приложение никак не реагирует на прикосновения пальца (это бывает не всегда, и иногда оно таки реагирует). Более того, перестают реагировать даже системные навигационные кнопки. Все это безобразие можно прекратить только нажатием аппаратной кнопки выключения.
Нужно заметить, что ни в одном другом приложении, ни основанных на SDK, ни на NDK таких эффектов не наблюдается. К телефону вообще нет ни малейших претензий. Воспроизводится это только в Firemonkey-приложениях.
понедельник, января 20, 2014
Если хочешь быть здоров…
…закаляйся!
Уже пятый год, на Крещение, ходим с друзьями купаться. Вчера было здорово. Погода прекрасная: легкий морозец (-22 градуса) и едва заметный снежок.
понедельник, января 06, 2014
Delphi. Ненависть 2.
В посте Delphi. Ненависть. я показал как деградировал кодогенератор дельфей. Сегодня покажу еще раз, только уже с кодом на котором проблема воспроизводится.
воскресенье, декабря 29, 2013
Delphi XE5 Update 2. S.S.D.D.
Вот, наконец-то, и я добрался (несколько припозднился, но на то были причины) до ощупывания Delphi с поддержкой Android. С самого начала было ясно, что качественной эта поддержка не будет, а потому нет смысла сразу кидаться покупать какое-либо Android-устройство. Но в планах уже значиналось приобретение нового смартфона на замену дышавшей на ладан старенькой Nokia. С моделью я определился через несколько дней после выхода Delphi XE5 (стимул всё-таки), и как выяснилось практически сразу, с выбранной моделью у Delphi проблемы (точнее с графическим процессором используемом в данном аппарате). Но, телефон должен нравится мне, а не Delphi, поэтому выбора своего я решил не менять (хотя посматривал и на Lenovo K-900, но с тем у Delphi вообще фатальная несовместимость) и надеяться на скорый фикс этого бага. В Update 2 баг таки пофиксили. Ура. Тестируем новую обезьяну, ой, простите, теперь это уже FM Platform (не хухры-мухры, но попробуйте кроссплатформенно послать SMS’ку или погудеть виброй, так сразу поймете ценность этого “Platform” :))
суббота, октября 12, 2013
Кушайте, не обляпайтесь.
Сегодня в ридере появилась статья “Delphi штурмует Android. Беседуем с Всеволодом Леоновым о Delphi XE5” рассказывающая о победах и завоеваниях. Такое всегда интересно почитать. Я позволю себе процитировать оттуда небольшой фрагмент:
- Технологии FireMonkey уже несколько лет. Вроде все более менее становится стабильным и уже не так страшно применять новинку для продакшн приложений. По прошествии этого временного промежутка вы можете сказать, что технология удалась? Нашла ли она свою аудиторию и какие нововведения следует ожидать в обозримом будущем?
Что технология удалась, стало заметно, к сожалению, лишь сейчас, если мы смотрим на неё глазами разработчиков. Только сейчас программисты стали реально интересоваться Платформой приложений FM (бывшая FireMonkey), когда увидели всю её мощь для мобильной разработки под Android. И это несмотря на то, что архитектурно она была заложена и технологически реализована в релизе XE2. Например, российский проект www.sphere-online.ru – многоцелевая платформа онлайн-коммуникаций. Команда выбрала Платформу FM, т.к. изначально хотела сделать мульти-платформенное решение для Windows и Mac OS, причем с интерфейсом высшего качества. На следующем после XE2 релизе XE3 данная компания сделала мульти-платформенную систему, а что может быть лучшим доказательством успешности технологии, как ни реализация на её основе реального проекта!? Теперь данная команда благодарит сама себя за правильный выбор средства разработки в своё время и готовит мобильную поддержку.
В общем, я сходил по данной ссылке… Никакой многоцелевой платформы онлайн-коммуникаций там нет, есть редирект на онлайн-игру “Сфера-перерождение”. Думаю, ну мало-ли, может их сейчас принято называть многоцелевыми коммуникационными платформами. В общем, скачал клиент дабы посмотреть чего там на FMX наваяли. Оказалось, что FMX’ом там и не пахнет. Исполняемые модули, коих две штуки, собраны компилятором MS VC++, и россыпь dll’ей тоже ни коим боком к FMX не относится. Так то. А народ в комментариях радуется, дескать жива курилка. Хотел прямо там вопрос задать – что мол за дела - да у них для этого регистрироваться нужно. В общем вот. В меню сегодня лапша.
Обновление от 16.10.2013.
Так, похоже имела место быть чья-то невнимательность, из-за которой в статье была указана неправильная ссылка. А я уже успел о Всеволоде плохо подумать :) Спасибо Роману Янковскому за изыскания. Правильная ссылка вот http://www.sphere-live.com/ и там действительно коммуникационный софт с FMX-интерфейсом.
Но я же не зря ходил по тем ссылкам, я хотел посмотреть на интерфейс высшего качества о котором говорится в статье. Итак, кратко - под интерфейсом высшего качества имеется ввиду FMX-стиль “Jet” из Premium Style Pack (это тот, где все черное-черное). Кому-то сливающаяся чернота нравится, кому-то нет.
Теперь по порядку. Первый запуск на хостовой машине c Windows 7 x64 закончился ничем:
Следующие попытки я делал уже под виртуальной Windows 7 x86. Запуск прошел успешно. Но в окне регистрации, после выбора русского языка, снова сюрприз:
Дальше открывается основное окно с кучей элементов управления. Походив по меню (кстати, в этом стиле совершенно не понятно, какой пункт меню активен, а какой пассивен, т.е. какой может быть выбран, а какой нет) поймал еще один глюк (два одновременно открытых выпадающих меню):
Потребление памяти на этом этапе составляло примерно 140MB, что довольно много для такого софта, особенно если учесть, что пользоваться я им даже не начал. Реакция интерфейса на действия пользователя по FMX-овски неспешная, если не сказать тормозная. Это уж точно не высший класс. В конце-концов приложение пришлось прибить т.к. при выходе случилось страшное (я долго ждал завершения, но так и не дождался):
пятница, мая 10, 2013
Delphi. Ненависть.
Код (вызов представляющий собой каскад двух inlined методов):
xv.Initialize(bin.Instance);
Turbo Delphi 2006 Explorer генерирует:
XmlRpcDeserializerTest.pas.2634: xv.Initialize(bin.instance);
00526489 8D9524FFFEFF lea edx,[ebp-$000100dc]
0052648F 8D45E8 lea eax,[ebp-$18]
00526492 E88DA8FAFF call XmlRpcBinary.GetInstance
00526497 8B8524FFFEFF mov eax,[ebp-$000100dc]
0052649D 8945B0 mov [ebp-$50],eax
005264A0 A154784C00 mov eax,[$004c7854]
005264A5 50 push eax
005264A6 8D8558FFFFFF lea eax,[ebp-$000000a8]
005264AC B107 mov cl,$07
005264AE 8B55B0 mov edx,[ebp-$50]
005264B1 E89E37FAFF call XmlRpcValue.SetValueIntf
Delphi XE2 - XE4 генерирует:
XmlRpcDeserializerTest.pas.2634: xv.Initialize(bin.instance);
006C9E77 8D955CFFFEFF lea edx,[ebp-$000100a4]
006C9E7D 8D85C4FFFEFF lea eax,[ebp-$0001003c]
006C9E83 E8683DF6FF call XmlRpcBinary.GetInstance
006C9E88 8B9D5CFFFEFF mov ebx,[ebp-$000100a4]
006C9E8E 8D85E4FFFEFF lea eax,[ebp-$0001001c]
006C9E94 E8973FD4FF call @IntfClear
006C9E99 33C0 xor eax,eax
006C9E9B 55 push ebp
006C9E9C 684D9F6C00 push $006c9f4d
006C9EA1 64FF30 push dword ptr fs:[eax]
006C9EA4 648920 mov fs:[eax],esp
006C9EA7 8D85E4FFFEFF lea eax,[ebp-$0001001c]
006C9EAD E87E3FD4FF call @IntfClear
006C9EB2 33C0 xor eax,eax
006C9EB4 55 push ebp
006C9EB5 682D9F6C00 push $006c9f2d
006C9EBA 64FF30 push dword ptr fs:[eax]
006C9EBD 648920 mov fs:[eax],esp
006C9EC0 8D85E4FFFEFF lea eax,[ebp-$0001001c]
006C9EC6 8BD3 mov edx,ebx
006C9EC8 E87B3FD4FF call @IntfCopy
006C9ECD 33C0 xor eax,eax
006C9ECF 55 push ebp
006C9ED0 680D9F6C00 push $006c9f0d
006C9ED5 64FF30 push dword ptr fs:[eax]
006C9ED8 648920 mov fs:[eax],esp
006C9EDB A10C3B6200 mov eax,[$00623b0c]
006C9EE0 50 push eax
006C9EE1 8D85A0FFFEFF lea eax,[ebp-$00010060]
006C9EE7 B107 mov cl,$07
006C9EE9 8B95E4FFFEFF mov edx,[ebp-$0001001c]
006C9EEF E898C7F5FF call XmlRpcValue.SetValueIntf
Это п#$%&ц. Зарепортить не могу т.к. воспроизвести на другом коде не получается. Но подобное есть еще в паре мест, и тоже с разворачиванием inlined методов.
четверг, мая 02, 2013
Delphi XE4. Чем дальше, тем страшнее.
Кажется, у Embarcadero уже вошло в привычку выпускать сырые бета-версии и называть их релизами. Чтож, они испекли еще один. Судя по всему, делался он в дикой спешке – иначе объяснить настолько отвратительное качество просто нечем.
Firemonkey. Одно лечим, другое калечим.
В обезьяне произошли некоторые приятные изменения – анимация стала работать заметно лучше – и дело тут не в увеличенном вдвое фреймрейте - спасибо разделяемому RTTI-кэшу. Однако, для отсчетов временных интервалов по прежнему используется тип с малой точностью, поэтому на системах с большим аптаймом снова будут рывки.
Padding и Margins поменяли поведение на противиположное. Некоторые контролы переехали в другое пространство имен. В общем, переделки пользователям FMX, если такие отчаянные есть, обеспечены.
Формы FMX разучились сворачиваться в панель задач – клик по кнопке в панели ни к чему не приводит. Сворачивать можно только кнопкой в заголовке окна, но при этом форма сворачивается не в панель задачь, а в левый нижний угол над панелью.
В дизайнере не меняется шрифт у TText и TLabel. То есть изменение размера действует, а вот изменение названия нет.
Поправили TPath, теперь он справляется с довольно сложными контурами. Однако, TPath.WrapMode = pwFit работает некорректно. Сглаживание контуров под XP так и не сделали (она хоть и старушка, но все же третья по популярности ОС). Кстати, со сглаживанием вообще странность. В редакторе свойства TPath.Data контур оказывается сглаженным:
но стоит изменить размер окна, как сглаживание исчезает:
Поломали TreeView. Если у дерева вызвать метод TreeView.ExpandAll список узлов превращается в кашу (слева пример собранный в XE3, справа в XE4):
Плюс еще множество мелких косяков, вроде визуальных артефактов, которые просто лень документировать. По общим ощущениям FMX становится все более неюзабельной. Небольшие улучшения ни коим образом не влияют на картину вцелом.
пятница, декабря 07, 2012
Блеск и нищета Firemonkey²
Блеск
В Delphi XE3 у Firemonkey появилась возможность стилизовать неклиентскую область окон приложения. Для этого используются новые имена стилей: для Windows это windowborderstyle и toolwindowstyle, для Mac OS используется единственный стиль macborderstyle. Информации, как создать такие стили нет, во всяком случае я не нашел, поэтому всё что будет написано дальше является результатом исследования кода класса TWindowBorder и его потомков под каждую платформу. В общем, можно сказать, что создать собственный стиль неклиентской области дело довольно простое. Стиль подразумевает наличие некоторых предопределенных элементов (например ‘client’ отвечает за клиентскую область окна, а ‘title’ за его текстовый заголовок) из которых формируется внешний вид окна. Так же имя элемента стиля отвечает за обозначение действия какой-либо области окна. Например элементы c именем стиля ‘left’ и ‘right’ отвечают за изменение горизонтального размера окна, а ‘caption’ за его перемещение (элементов с одинаковым именем стиля может быть несколько, что в результате даст несколько зон отвечающих за одно и то же действие) То есть при клике на этих элементах будет выполняться соответствующее им действие. В общем, кто имел опыт работы с WinAPI, в части обработки оконных сообщений, наверняка провели параллель с такой вещью, как HITTEST, и оказались правы – механизм работает один-в-один. Это был блеск. Теперь о нищете.
Нищета
Воодушевившись открывшимися новыми возможностями я решил сделать стиль имитирующий окна Mac OS X Leon. За основу был взят незамысловатый скриншот:
и еще несколько изображений окон, где присутствовали кнопки в заголовке окна. Я не ставил себе целью сделать сразу полнофункциональный стиль, для начала хотелось добиться схожести с оригиналом. Вооружившись дизайнером стилей и в очередной раз убедившись, что пользоваться оным невозможно, было решено дизайнить стиль прямо на форме (ведь любой стиль это просто набор компонентов). Затем с формы стиль был скопирован в файл macosx.style и загружен в компонент класса TStyleBook, который был назначен форме. В редакторе стилей созданный стиль выглядел вот так:
Сглаживания на кнопке нет т.к. делал я все под Windows XP, а у Firemonkey на этой ОC сглаживание не работает (работало до Delphi XE2 Update 4 hotfix 1, но хотфиксом его сломали да так и не починили). Для создания эффекта тени пришлось генерировать картинку в GIMP т.к. стандартный эффект TShadowEffect такую тень отрисовать не способен (при значении свойства Softness равном единице тень уже имеет видимую глазу структуру, а при значениях больше единицы и вовсе превращается в клетчатое пятно). Но с картинкой возникает проблема. При изменении размера окна тень должна растягиваться без артефактов поэтому просто масштабировать картинку нельзя, её нужно делить на области: четыре имеющих постоянный размер (расположены в углах), две растягивающиеся горизонтально и две растягивающие вертикально. Итого получается восемь частей. Каждую такую часть можно было представить компонентом TImage в который был бы загружен файл соответствующей части изображения. Однако, в Delphi XE3, для поддержки растровых стилей Firemonkey, появился класс TSubImage способный отрисовывать указанную область изображения на которое он ссылается. Это удобнее, чем делать множество файлов. Но, этот класс не доступен в дизайнере, поэтому мне пришлось установить в IDE пакет регистрирующий его. В общем, после некоторого непредвиденного траха с пакетом, тень была готова. Заголовок с кнопкой и клиенсткую область сделать труда не составило. Хотя нет, подобрать градиент для кнопки было сложно т.к. элементы выделения (белые кружочки для изменения размеров) полностью перекрывали маленькую кнопку и изменяющийся градиент было не видно :) В результате схожесть не попиксельная, но довольно близка к оригиналу. Итак, стиль готов, первый запуск:
Легкое недоумение. Пробую максимизировать окно, оно максимизируется так, как будто тень является клиентской областью т.е. я вижу не распахнутую на весь экран клиентскую область, а клиентскую область в окружении черной рамки. Хорошо, с максимизацией разберемся как нибудь позже, но почему тень не прозрачная… Я же помню, что у меню были прозрачные тени. Ищу в файле стилей стиль для меню (menuviewstyle). Вижу, что тень сделана с помощью эффекта TShadowEffect, но место под неё зарезервировано с помощью свойств Margin и Padding у элементов стиля. Попробовал и я у своей тени выставить отрицательный Padding, вот что из этого вышло:
Тень совсем пропала, а кроме этого на каждое изменение размеров окна генерируется четыре исключительных ситуации EZeroDivide. В общем трюк не сработал. Начал смотреть, что же там происходит под капотом модуля FMX.Platform.Win отвечающем за взаимодействие с платформой Windows. А там все печально. Оказалось, что по изображению полученному отрисовкой стиля формируется регион (регион в терминологии Win32) и назначается окну. Всё, прощай прозрачная тень, прощайте сглаженные уголки окна и да здравствуют зазубрины :( Но, как же, тогда отрисовывается тень у меню? А для меню используются композитные окна (см. TFrom.Transparency). В общем, тоска зеленая :(
понедельник, декабря 03, 2012
iPhone “slide to unlock” animation средствами Firemonkey. DelphiXE2.
Как бы кто ни относился к Apple, одно признают все – эти парни умеют делать красиво. Их “красота” заключается в не пергруженных деталями интерфейсах и изысканных мелочах. Одной из таких мелочей является анимация элемента разблокировки экрана (кто не видел, погуглите slide to unlock animation). Как только вышла Delphi XE2 я сразу попробовал сделать подобный эффект средствами Firemonkey. Тогда, получив удовлетворительный результат, я не стал описывать его т.к. думал, что следующая версия Firemonkey позволит реализовать этот эффект не написав ни строчки кода. Этого, увы, не случилось. Более того, в Delphi XE3, классы TText и TLabel лишились свойства Fill, что сделало невозможным применение каких-либо вариантов раскраски текста. Поэтому публикую вариант для Delphi XE2.
Вот что у меня вышло:
Реализация очень простая. В качестве “раскраски” текста применяется битмап в который отрисовывается прямоугольник серого цвета с анимированным градиентом имитирующим пятно света. Все это делается в дизайнере, за исключением отрисовки контрола в битмап т.к. TBushGrab, являющаяся одним из вариантов использования кисти, корректно не работает.
Исходник и скомпилированный пример можно скачать тут.
пятница, сентября 28, 2012
Delphi XE3.FireMonkey: Фиксим рваную анимацию
О проблемах с анимацией в FireMonkey я уже неоднократно писал. Причина кроется в недостаточной точности используемого типа - Single. С переработкой FireMonkey на архитектуру сервисов, произошедшую в Delphi XE3, появилась возможность очень просто этот косяк пофиксить. В общем, фикс можно скачать отсюда.
p.s. Достаточно подключить модуль к проекту. Работает начиная с Delphi XE3. Будем надеяться, что с первым апдейтом этот фикс станет ненужен.
вторник, сентября 25, 2012
Delphi XE3.FireMonkey: куда ни кинь – всюду клин.
Это просто ужас какой-то – за что-бы ни взялся, ну просто все глючит :( После предыдущего подхода закончившегося серией QC-отчетов и серьезно охладившего пыл, сегодня решил еще поиграться с новым редактором стилей (о нем писать не буду – он ужасен. Даже элементарных действий по изменению Z-order для объектов нет, а Copy/Past умудряются глючить. Впрочем не удивительно, Крюков же говорил, что ему удобнее с текстовым представлением работать, видимо и нам нефиг расслабляться) и сделать небольшое т.н. gloat-logo наподобие такого:
Для этого я векторизовал в Inkscape изображение шлема с картинки для TLiveTile. Получилось довольно не плохо:
А вот так это отображается посредством TPath:
Для сравнения скриншот Delphi XE2 Update 4:
В общем, пользоваться этим нельзя.
Update: 26.09.2012 11:07
Пришлось залить на QC два готовых проекта демонстрирующих баги компонента. Кстати, имеет значение каким образом будет заполняться путь: через инспектор объектов или через редактор компонента. Глючат оба варианта. Кому интересно скачайте приложенные проекты.
воскресенье, сентября 09, 2012
Delphi XE3. Очередной сырой релиз Firemonkey.
Багу с анимацией не поправили, она как была рваная так таковой и осталась. Причины они, похоже, поняли. Типу Single, используемому для счетчика тиков таймера (и кому в голову такая идея пришла, для счетчика использовать нецелочисленный тип) не хватает точности если у системы большой аптайм. В IFMXTimerService.GetTick они заменили его на Extended, а вот в реализации класса TAnithread забыли.
TreeView стало сильно нагружать CPU. Для дерева с одной тысячей элементов загрузка доходит до 100% в состоянии покоя. Мне не понятно, они там вообще ничего не тестируют что-ли?
Еще вылез косяк с пропадаением/мерцанием шейдерной тени в 3D. Но тут без репорта, ибо надоело.
Регрессию с отсутствием сглаживания на XP тоже не пофиксили, а ведь она висит с выхода XE2 Update 4 Hotfix 1.
Update: 20:17 09.09.2012
Налетел еще на один косяк с тенью. Тень привязанная к объекту, который в свою очередь привязан якорями к своему контейнеру, не обновляется при изменении его размеров, а, похоже, просто подгоняется под размер.
Update: 23:46 12.09.2012
Удалось воспроизвести еще один косяк с эффектом тени. На TForm3D размещен прозрачный TLayer3D с объектом внутри. Объекту назначен эффект тени. Тень пропадает, когда активизируется другой шейдерный эффект (это, кстати, регрессия, на XE2 такого небыло):
четверг, августа 30, 2012
Lazarus 1.0. Релиз.
Свершилось. Lazarus 1.0 релизнулся. Поздравляем команду работавшую над этой замечательной средой со столь важной вехой. Буду постепенно адаптировать свои наработки под FreePascal, чтоб в перспективе полностью слезть с Delphi. Абракадабра, похоже, совсем берега потеряла.
среда, июля 18, 2012
Евангелисты врут. FireMonkey - отстой.
Вы, наверное, в курсе, что Embarcadero активно продвигает свое новое видение создания кроссплатформенного гуя – FireMonkey (они это называют фреймвоком, но для её нынешнего состояния это слишком круто звучит). В рунете анонсируется один конкурс за другим, проводятся вебинары, и пусть качество последних оставляет желать лучшего, но активность радует. Теперь, собственно, к теме. В рамках последнего конкурса было предложено разработать какое-нибудь приложение для обучения. И вот вчера появилась очередная работа за авторством Евгения Чмеля (не знаю, склоняется эта фамилия или нет). В отличии от виденных ранее, простеньких “одноформочек”, тут была сделана попытка подергать обезьяну за все конечности: стилизация, 3D, шейдерные эффекты (о GPU accelerated graphics очень любят говорить евангелисты Embarcadero :)) ). Давайте посмотрим, что из этого вышло. Для тех, кто не смотрел вебинары сделаю маленькое отступление. На одном из вебинаров, евангелист Embarcadero, Всеволод Леонов рассказал душещипательную историю о том, как ему пришлось “компьютер перегрузить, конкретно, жестко” (это цитата), из-за того, что Silverlight SDK и эмулятор Windows Phone 7 “не cработали” (это цитата) на его компьютере т.к. им не понравился видеоадаптер или настройки графического процессора. А вот приложения разработанные с использованием FireMokey, продолжает Всеволод, совершенно не требовательны к аппаратному обеспечению. Давайте посмотрим, как он нам врал. Беспристрастным свидетелем нам будет Process Explorer v15.05 от Марка Русиновича. Итак, качаем приложение Евгения и запускаем (скриншотов приложения Евгения не привожу, они есть по ссылке на его работу. Обратите внимание на размытость шрифтов).
Запустили приложение. Смотрим на потребление:
Нескромно, но можно простить “передовой технологии”. Переходим к разделу “Уроки” и выбираем “Урок 5”. Начинается подготовка сцены. Процесс этот длительный (у меня заняло чуть больше минуты, на четырехядерном Phenom II с частотой 3.3GHz), запаситесь терпением. Сцена построена. Смотрим на потребление:
Обезьяна хорошо подкрепилась. Даже очень хорошо. Теперь попробуйте подвигать мышку над кнопками вариантов ответов. Ощущение, что GUI реагирует ну о-о-очень вяло, не так-ли? Смотрите на график использования CPU (я имею ввиду, что вы должны сами это попробовать, на своем компьютере) – в эти моменты его загрузка приближается к 100% (у меня было ~21.5% для четырехядерного процессора, что эквивалетно 86% для одноядерного). А ведь нам кто-то рассказывал про GPU accelerated graphics. Ладно, идем дальше. Отвечаем на все вопросы урока. Смотрим потребление:
Глаза не округлились? Теперь посмотрите, для сравнения, сколько потребляет 3D-стрелялка FarCry с активным игровым процессом (уровень называется Фабрика, если кому, вдруг, интересно) запущенная в полноэкранном режиме 1440x900:
Выводы делайте сами.
четверг, июля 05, 2012
Delphi XE2 Update 4 HotFix 1. А с дженериками до сих пор проблемы :(
Хотите получить Access Violation на абсолютно ровном месте, без намека на ухабы? Велком, как говорится:
program array_of_generic_record;
{$APPTYPE CONSOLE}
Uses
TypInfo;
Type
TRec<T>
FField : T;
End;
Var
a : Array Of TRec<TObject>
i : Integer;
r : TRec<TObject>
begin
WriteLn(SizeOf(TRec<TObject>
WriteLn(GetTypeData(TypeInfo(TRec<TObject>
SetLength(A, 1000000); // but system.DynArraySetLength.elSize = 1; line 28288
// (DelphiXE2 update 4 hotfix 1); look at attached screenshot: bug.png
// absolutely normal code lead to access violation error
For i := Low(a) To High(a) Do
a[i] := r;
end.
В общем, из описания понятно, что в системном модуле неверно получается размер элемента динамического массива. Из-за чего, понятное дело, памяти выделяется меньше и попытки работать с таким массивом приводят к краху. На дворе 2012 год. Блин, когда они уже нормальный компилятор осилят написать. Лучи ненависти вам, абракадабры :E
p.s. QC #106917