пятница, декабря 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. За основу был взят незамысловатый скриншот:

pic14

и еще несколько изображений окон, где присутствовали кнопки в заголовке окна. Я не ставил себе целью сделать сразу полнофункциональный стиль, для начала хотелось добиться схожести с оригиналом. Вооружившись дизайнером стилей и в очередной раз убедившись, что пользоваться оным невозможно, было решено дизайнить стиль прямо на форме (ведь любой стиль это просто набор компонентов). Затем с формы стиль был скопирован в файл macosx.style и загружен в компонент класса TStyleBook, который был назначен форме. В редакторе стилей созданный стиль выглядел вот так:

styledesigner

Сглаживания на кнопке нет т.к. делал я все под Windows XP, а у Firemonkey на этой ОC сглаживание не работает (работало до Delphi XE2 Update 4 hotfix 1, но хотфиксом его сломали да так и не починили). Для создания эффекта тени пришлось генерировать картинку в GIMP т.к. стандартный эффект TShadowEffect такую тень отрисовать не способен (при значении свойства Softness равном единице тень уже имеет видимую глазу структуру, а при значениях больше единицы и вовсе превращается в клетчатое пятно). Но с картинкой возникает проблема. При изменении размера окна тень должна растягиваться без артефактов поэтому просто масштабировать картинку нельзя, её нужно делить на области: четыре имеющих постоянный размер (расположены в углах), две растягивающиеся горизонтально и две растягивающие вертикально. Итого получается восемь частей. Каждую такую часть можно было представить компонентом TImage в который был бы загружен файл соответствующей части изображения. Однако, в Delphi XE3, для поддержки растровых стилей Firemonkey, появился класс TSubImage способный отрисовывать указанную область изображения на которое он ссылается. Это удобнее, чем делать множество файлов. Но, этот класс не доступен в дизайнере, поэтому мне пришлось установить в IDE пакет регистрирующий его. В общем, после некоторого непредвиденного траха с пакетом, тень была готова. Заголовок с кнопкой и клиенсткую область сделать труда не составило. Хотя нет, подобрать градиент для кнопки было сложно т.к. элементы выделения (белые кружочки для изменения размеров) полностью перекрывали маленькую кнопку и изменяющийся градиент было не видно :) В результате схожесть не попиксельная, но довольно близка к оригиналу. Итак, стиль готов, первый запуск:

styledwindowblackshadow

Легкое недоумение. Пробую максимизировать окно, оно максимизируется так, как будто тень является клиентской областью т.е. я вижу не распахнутую на весь экран клиентскую область, а клиентскую область в окружении черной рамки. Хорошо, с максимизацией разберемся как нибудь позже, но почему тень не прозрачная… Я же помню, что у меню были прозрачные тени. Ищу в файле стилей стиль для меню (menuviewstyle). Вижу, что тень сделана с помощью эффекта TShadowEffect, но место под неё зарезервировано с помощью свойств Margin и Padding у элементов стиля. Попробовал и я у своей тени выставить отрицательный Padding, вот что из этого вышло:

styledwindow

Тень совсем пропала, а кроме этого на каждое изменение размеров окна генерируется четыре исключительных ситуации 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.

Вот что у меня вышло:

spotlight_effect

Реализация очень простая. В качестве “раскраски” текста применяется битмап в который отрисовывается прямоугольник серого цвета с анимированным градиентом имитирующим пятно света. Все это делается в дизайнере, за исключением отрисовки контрола в битмап т.к. 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 наподобие такого:

firebird

Для этого я векторизовал в Inkscape изображение шлема с картинки для TLiveTile. Получилось довольно не плохо:

delphi_logo

А вот так это отображается посредством TPath:

dxe3

Для сравнения скриншот Delphi XE2 Update 4:

dxe2

В общем, пользоваться этим нельзя.

 

QC#109005

Update: 26.09.2012 11:07

Пришлось залить на QC два готовых проекта демонстрирующих баги компонента. Кстати, имеет значение каким образом будет заполняться путь: через инспектор объектов или через редактор компонента. Глючат оба варианта. Кому интересно скачайте приложенные проекты.

воскресенье, сентября 09, 2012

Delphi XE3. Очередной сырой релиз Firemonkey.

Багу с анимацией не поправили, она как была рваная так таковой и осталась. Причины они, похоже, поняли. Типу Single, используемому для счетчика тиков таймера (и кому в голову такая идея пришла, для счетчика использовать нецелочисленный тип) не хватает точности если у системы большой аптайм. В IFMXTimerService.GetTick они заменили его на Extended, а вот в реализации класса TAnithread забыли.

ani_bug

QC#108614

 

TreeView стало сильно нагружать CPU. Для дерева с одной тысячей элементов загрузка доходит до 100% в состоянии покоя. Мне не понятно, они там вообще ничего не тестируют что-ли?

treeview_bug

QC#108615

 

Еще вылез косяк с пропадаением/мерцанием шейдерной тени в 3D. Но тут без репорта, ибо надоело.

 

Регрессию с отсутствием сглаживания на XP тоже не пофиксили, а ведь она висит с выхода XE2 Update 4 Hotfix 1.

 

Update: 20:17 09.09.2012

Налетел еще на один косяк с тенью. Тень привязанная к объекту, который в свою очередь привязан якорями к своему контейнеру, не обновляется при изменении его размеров, а, похоже, просто подгоняется под размер.

shadow_bug

QC#108620

 

Update: 23:46 12.09.2012

Удалось воспроизвести еще один косяк с эффектом тени. На TForm3D размещен прозрачный TLayer3D с объектом внутри. Объекту назначен эффект тени. Тень пропадает, когда активизируется другой шейдерный эффект (это, кстати, регрессия, на XE2 такого небыло):

shadow_bug2

QC#108719

четверг, августа 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 от Марка Русиновича. Итак, качаем приложение Евгения и запускаем (скриншотов приложения Евгения не привожу, они есть по ссылке на его работу. Обратите внимание на размытость шрифтов).

Запустили приложение. Смотрим на потребление:

afterstart_memory 

Нескромно, но можно простить “передовой технологии”. Переходим к разделу “Уроки” и выбираем “Урок 5”. Начинается подготовка сцены. Процесс этот длительный (у меня заняло чуть больше минуты, на четырехядерном Phenom II с частотой 3.3GHz), запаситесь терпением. Сцена построена. Смотрим на потребление:

opened_lesson

Обезьяна хорошо подкрепилась. Даже очень хорошо. Теперь попробуйте подвигать мышку над кнопками вариантов ответов. Ощущение, что GUI реагирует ну о-о-очень вяло, не так-ли? Смотрите на график использования CPU (я имею ввиду, что вы должны сами это попробовать, на своем компьютере) – в эти моменты его загрузка приближается к 100% (у меня было ~21.5% для четырехядерного процессора, что эквивалетно 86% для одноядерного). А ведь нам кто-то рассказывал про GPU accelerated graphics. Ладно, идем дальше. Отвечаем на все вопросы урока. Смотрим потребление:

after_lesson

Глаза не округлились? Теперь посмотрите, для сравнения, сколько потребляет 3D-стрелялка FarCry с активным игровым процессом (уровень называется Фабрика, если кому, вдруг, интересно) запущенная в полноэкранном режиме 1440x900:

farcry 

Выводы делайте сами.

четверг, июля 05, 2012

Delphi XE2 Update 4 HotFix 1. А с дженериками до сих пор проблемы :(

Хотите получить Access Violation на абсолютно ровном месте, без намека на ухабы? Велком, как говорится:

program array_of_generic_record;

{$APPTYPE CONSOLE}

Uses

TypInfo;

Type

TRec<T> = Record
  FField : T;
End;

Var

a : Array Of TRec<TObject>;
i : Integer;
r : TRec<TObject>;

begin

WriteLn(SizeOf(TRec<TObject>)); // 4
WriteLn(GetTypeData(TypeInfo(TRec<TObject>))^.elSize); // 4

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

среда, апреля 18, 2012

Firemonkey. Анимммммация.

Полюбуйтесь:

fmx_animmmmmation

Параметры анимации:

  • Продолжительность 0.5 сек
  • Стартовое значение 6
  • Конечное значение 64

В уголочке приложение работающее под виртуальной машиной с Windows XP и приложение работающее на хост-машине с Windows 7. Приложение пишет в Memo-лог изменения свойства Step на которое настроена анимация.

Обнаруженных косяков два:

  1. Дважды приходит стартовое значение
  2. Разное количество “шагов” анимации при идентичных параметрах

А я думаю чего это у меня анимашка так дергается на семерке, и отчего кажется более плавной на виртуализированной XP. Ужас, блин.