Я накладываю различные графические элементы(виджеты) поверх видео. При изменении разрешения видео необходимо менять размер и расположение виджетов. Раньше мне приходилось программировать графический интерфейс на Qt. Там реализована математика перерисовки дочерних виджетов при растягивании главного окна. В Qt гибкие настройки поведения виджетов. Существуют ли библиотеки в которых реализована математика без графических элементов или мне нужно ковырять код Qt. Проект разрабатывается на C++ под Linux.
Здравствуйте, ShubinEV, Вы писали:
SEV>Я накладываю различные графические элементы(виджеты) поверх видео. При изменении разрешения видео необходимо менять размер и расположение виджетов. Раньше мне приходилось программировать графический интерфейс на Qt. Там реализована математика перерисовки дочерних виджетов при растягивании главного окна. В Qt гибкие настройки поведения виджетов. Существуют ли библиотеки в которых реализована математика без графических элементов или мне нужно ковырять код Qt. Проект разрабатывается на C++ под Linux.
Сочувствую.
Что можно посмотреть:
http://en.wikipedia.org/wiki/Layout_engine
http://en.wikipedia.org/wiki/List_of_layout_engines
http://en.wikipedia.org/wiki/Comparison_of_layout_engines
На рсдн есть форум посвященный HTMLayout
http://www.rsdn.ru/forum/htmlayout/, автора библиотеки зовут c-smile
http://www.rsdn.ru/Users/13953.aspx, возможно он сумеет что-то подсказать.
Здравствуйте, ShubinEV, Вы писали:
SEV>Я накладываю различные графические элементы(виджеты) поверх видео. При изменении разрешения видео необходимо менять размер и расположение виджетов. Раньше мне приходилось программировать графический интерфейс на Qt. Там реализована математика перерисовки дочерних виджетов при растягивании главного окна. В Qt гибкие настройки поведения виджетов. Существуют ли библиотеки в которых реализована математика без графических элементов или мне нужно ковырять код Qt. Проект разрабатывается на C++ под Linux.
Если не найдете что-нибудь готового и подходящего, то я бы рекомендовал бы посмотреть на то, как это сделано у Apple в Cocoa. Оно, правда, на Objective-C, но зато там довольно простой механизм, и его просто будет повторить. Смысл в том, что у каждого виджета (там оно NSView назвается) есть свойство autoresizingMask (типа int), являющееся комбинацией флагов:
enum {
NSViewNotSizable = 0,
NSViewMinXMargin = 1,
NSViewWidthSizable = 2,
NSViewMaxXMargin = 4,
NSViewMinYMargin = 8,
NSViewHeightSizable = 16,
NSViewMaxYMargin = 32
};
Флаги означают, что надо масштабировать пропорционально ширину (NSViewWidthSizable), высоту (NSViewHeightSizable), расстояние от левого края родителя до виджета (NSViewMinXMargin) и так далее (подробнее можно доку у apple почитать или посмотреть на код ниже внимательно).
Далее, при изменении размера виджета-контейнера (не всегда, правда, а только если это разрешено, но это не так важно), контейнер вызывает у каждого виджета, который он содержит, метод
- ( void ) resizeWithOldSuperviewSize: ( NSSize ) oldSize
. Вот код этого метода, выдранный из исходников GNUStep:
- (void) resizeWithOldSuperviewSize:(NSSize)oldSize
{ // does not call setFrame: or setFrameSize:!
float change, changePerOption;
NSSize old_size = _frame.size;
NSSize superViewFrameSize; // super_view should not be nil!
BOOL changedOrigin = NO;
BOOL changedSize = NO;
int options = 0;
if(!super_view)
return; // how can this happen? We are called as [[sub_views objectAtIndex:i] resizeWithOldSuperviewSize: oldSize]
superViewFrameSize = [super_view frame].size; // super_view should not be nil!
if(NSEqualSizes(oldSize, superViewFrameSize))
return; // ignore unchanged superview size
#if 0
NSLog(@"resizeWithOldSuperviewSize %x: %@ -> %@ %@", _v.autoresizingMask, NSStringFromSize(oldSize), NSStringFromSize(superViewFrameSize), self);
#endif
// do nothing if view is not resizable
if(_v.autoresizingMask == NSViewNotSizable)
return;
// determine if and how
if(_v.autoresizingMask & NSViewWidthSizable) // the X axis can be
options++; // resized
if(_v.autoresizingMask & NSViewMinXMargin)
options++;
if(_v.autoresizingMask & NSViewMaxXMargin)
options++;
// adjust the X axis if
if(options > 0) // any X options are
{ // set in the mask
change = superViewFrameSize.width - oldSize.width;
if(change != 0.0)
{
changePerOption = change / options;
if(_v.autoresizingMask & NSViewWidthSizable)
{
float oldFrameWidth = _frame.size.width;
_frame.size.width += changePerOption;
// NSWidth(frame) = MAX(0, NSWidth(frame) + changePerOption);
if (NSWidth(_frame) <= 0)
{
NSAssert((NSWidth(_frame) <= 0), @"View frame width <= 0!");
NSLog(@"resizeWithOldSuperviewSize: View frame width <= 0!");
_frame.size.width = 0;
}
if(_v.isRotatedFromBase)
{
_bounds.size.width *= _frame.size.width / oldFrameWidth; // keep proportion
// _bounds.size.width = floor(_bounds.size.width);
}
else
_bounds.size.width += changePerOption;
changedSize = YES;
}
if(_v.autoresizingMask & NSViewMinXMargin)
{
_frame.origin.x += changePerOption;
changedOrigin = YES;
}
}
}
// determine if and how
options = 0; // the Y axis can be
if(_v.autoresizingMask & NSViewHeightSizable) // resized
options++;
if(_v.autoresizingMask & NSViewMinYMargin)
options++;
if(_v.autoresizingMask & NSViewMaxYMargin)
options++;
// adjust the Y axis if
if(options > 0) // any Y options are
{ // set in the mask
change = superViewFrameSize.height - oldSize.height;
if(change != 0.0)
{
changePerOption = change/options;
if(_v.autoresizingMask & NSViewHeightSizable)
{
float oldFrameHeight = _frame.size.height;
_frame.size.height += changePerOption;
if(NSHeight(_frame) <= 0)
{
NSLog(@"resizeWithOldSuperviewSize: View frame height <= 0!");
_frame.size.height = 0;
}
if(_v.isRotatedFromBase)
{ // rotated
_bounds.size.height *= _frame.size.height/oldFrameHeight;
// _bounds.size.height = floor(_bounds.size.height);
}
else
{ // normal
// if([super_view isFlipped])
// _bounds.size.height -= changePerOption;
// else
_bounds.size.height += changePerOption;
}
changedSize = YES;
}
if([super_view isFlipped])
{
if((_v.autoresizingMask & NSViewMaxYMargin))
{
_frame.origin.y += changePerOption;
changedOrigin = YES;
}
}
else
{
if((_v.autoresizingMask & NSViewMinYMargin))
{
_frame.origin.y += changePerOption;
changedOrigin = YES;
}
}
}
}
if(changedSize || changedOrigin)
{ // we could call [self setFrameSize:] but that isn't done on AppKit
[self _invalidateCTM]; // update when needed
if(_v.isRotatedFromBase)
{
float sx = _frame.size.width / _bounds.size.width;
float sy = _frame.size.height / _bounds.size.height;
// FIXME: should we scale old_size?
NSLog(@"and now? %@", self);
}
[self resizeSubviewsWithOldSize: old_size]; // recursively go down
if(_v.postFrameChange)
[[NSNotificationCenter defaultCenter] postNotificationName:NOTICE(FrameDidChange) object: self];
}
}
Прошу прощения, я ничего форматировать и переписывать не стал, лень
![](/Forum/Images/smile.gif)
Смысл этого кода в том, что дочерний виджет пересчитает свое положение и размер исходя из набора флагов в свойстве autoresizingMask, нового и старого размера виджета-контейнера. Кроме того, он (в случае, если он тоже контейнер) вызовет этот метод у виджетов, которые он сожержит ( [ self resizeSubviewsWithOldSize: old_size ]; ). Небольшая такая рекурсия
Формулы не сложные, тормозить ничего толком не должно. Правда, непривычно сначала (очень сильно от Qt, Gtk и прочего отличается), но, если привыкнуть — то вполне удобно.
PS: еще раз прошу прощения, теперь за Objective-C, на C++ совсем лень это переписывать
А, да. Если будете брать этот код за основу, то вам надо знать, что в Cocoa за начало координат взят левый-нижний угол и y-координата изменяется снизу-вверх (ось y направлена снизу-вверх). А метод — ( BOOL ) isFlipped; у NSView переворачивает эту ось. Хотя, по-большей части на формулы это и не должно влиять, вроде бы.