GTK обнаружение окна изменяют размер от пользователя

Код уже несколько раз оказывался удобным, и я чувствую, что затраты на настройку очень низки, поскольку использование довольно низкое. Таким образом, я решил выпустить его под лицензией MIT и предоставить репозиторий GitHub, куда можно загрузить заголовок и небольшой файл примера.

http://djmuw.github.io/prettycc

0. Предисловие и формулировка

«украшение» в терминах этого ответа представляет собой набор строки префикса, строки-разделителя и строки-постфикса. Где строка префикса вставляется в поток до, а строка постфикса после значений контейнера (см. 2. Целевые контейнеры). Строка разделителя вставляется между значениями соответствующего контейнера.

Примечание. На самом деле этот ответ не рассматривает вопрос до 100%, поскольку декорация не является строго скомпилированной постоянной времени, поскольку для проверки того, было ли применено нестандартное декорирование к текущему потоку, требуются проверки во время выполнения. Тем не менее, я думаю, что он имеет некоторые приличные особенности.

Примечание 2: могут иметь незначительные ошибки, так как он еще не был хорошо протестирован.

[Тысяча сто шестьдесят один] 1. Общая идея / использование

Нулевой дополнительный код, необходимый для использования

Это должно быть так же просто, как

#include 
#include "pretty.h"

int main()
{
  std::cout << std::vector{1,2,3,4,5}; // prints 1, 2, 3, 4, 5
  return 0;
}

Легкая настройка ...

... относительно конкретного объекта потока

#include 
#include "pretty.h"

int main()
{
  // set decoration for std::vector for cout object
  std::cout << pretty::decoration>("(", ",", ")");
  std::cout << std::vector{1,2,3,4,5}; // prints (1,2,3,4,5)
  return 0;
}

или относительно всех потоков:

#include 
#include "pretty.h"

// set decoration for std::vector for all ostream objects
PRETTY_DEFAULT_DECORATION(std::vector, "{", ", ", "}")

int main()
{
  std::cout << std::vector{1,2,3,4,5}; // prints {1, 2, 3, 4, 5}
  std::cout << pretty::decoration>("(", ",", ")");
  std::cout << std::vector{1,2,3,4,5}; // prints (1,2,3,4,5)
  return 0;
}

Грубое описание

  • Код включает в себя шаблон класса, обеспечивающий оформление по умолчанию для любого типа
  • , который может быть специализирован для изменения оформления по умолчанию для (a) определенного типа (типов), и это
  • с использованием предоставленного частного хранилища. с помощью ios_base с использованием xalloc / pword для сохранения указателя на объект pretty::decor, конкретно украшающий определенный тип в определенном потоке.

Если объект pretty::decor для этого потока не был установлен явно, вызывается pretty::defaulted::decoration() для получения декорации по умолчанию для данного типа. Класс pretty::defaulted должен быть специализирован для настройки декораций по умолчанию.

2. Целевые объекты / контейнеры

Целевые объекты obj для «красивого украшения» этого кода - это объекты с перегрузками

  • std::begin и std::end. ] определено (включает массивы в стиле C),
  • , имеющие begin(obj) и end(obj), доступные через ADL,
  • имеют тип std::tuple
  • или типа std::pair.

Код включает в себя признак для идентификации классов с особенностями диапазона (begin / end). (Хотя проверка не включена, является ли begin(obj) == end(obj) допустимым выражением.)

Код предоставляет operator<< в глобальном пространстве имен, которые применяются только к классам, не имеющим более специализированной версии operator<< имеется в наличии. Поэтому, например, std::string не печатается с использованием оператора в этом коде, хотя имеет действительную пару begin / end.

3. Использование и настройка

Декорации могут быть наложены отдельно для каждого типа (кроме разных tuple) и потока (не тип потока!). (Т.е. std::vector может иметь разные декорации для разных потоковых объектов.)

A) Декорация по умолчанию

Префикс по умолчанию - "" (ничего), как и постфикс по умолчанию, в то время как разделитель по умолчанию - ", " (запятая + пробел).

B) Настраиваемое оформление по умолчанию для типа путем специализации шаблона класса pretty::defaulted

У struct defaulted есть статическая функция-член decoration(), возвращающая объект decor, который включает значения по умолчанию для данный тип.

Пример использования массива:

Настройка печати массива по умолчанию:

namespace pretty
{
  template
  struct defaulted
  {
    static decor decoration()
    {
      return{ { "(" }, { ":" }, { ")" } };
    }
  };
}

Печать массива массивов:

float e[5] = { 3.4f, 4.3f, 5.2f, 1.1f, 22.2f };
std::cout << e << '\n'; // prints (3.4:4.3:5.2:1.1:22.2)

Использование макроса PRETTY_DEFAULT_DECORATION(TYPE, PREFIX, DELIM, POSTFIX, ...) для char streams

Макрос расширяется до

namespace pretty { 
  template< __VA_ARGS__ >
  struct defaulted< TYPE > {
    static decor< TYPE > decoration() {
      return { PREFIX, DELIM, POSTFIX };
    } 
  }; 
} 

, что позволяет переписать вышеуказанную частичную специализацию в

PRETTY_DEFAULT_DECORATION(T[N], "", ";", "", class T, std::size_t N)

или вставить полную специализацию, например

PRETTY_DEFAULT_DECORATION(std::vector, "(", ", ", ")")

Включен еще один макрос для wchar_t потоков: PRETTY_DEFAULT_WDECORATION.

[1 171] С) Наложение декораций на потоки

Функция pretty::decoration используется для наложения декораций на определенный поток. Существуют перегрузки, принимающие либо один строковый аргумент, являющийся разделителем (принимающий префикс и постфикс из класса по умолчанию), либо три строковых аргумента, собирающих полное оформление

Полное оформление для данного типа и потока

float e[3] = { 3.4f, 4.3f, 5.2f };
std::stringstream u;
// add { ; } decoration to u
u << pretty::decoration("{", "; ", "}");

// use { ; } decoration
u << e << '\n'; // prints {3.4; 4.3; 5.2}

// uses decoration returned by defaulted::decoration()
std::cout << e; // prints 3.4, 4.3, 5.2

Настройка разделителя для данного потока

PRETTY_DEFAULT_DECORATION(float[3], "{{{", ",", "}}}")

std::stringstream v;
v << e; // prints {{{3.4,4.3,5.2}}}

v << pretty::decoration(":");
v << e; // prints {{{3.4:4.3:5.2}}}

v << pretty::decoration("((", "=", "))");
v << e; // prints ((3.4=4.3=5.2))

4. Специальная обработка std::tuple

Вместо того, чтобы разрешать специализацию для каждого возможного типа кортежа, этот код применяет любое украшение, доступное для std::tuple, ко всем видам std::tuple<...> с.

[1 165] 5. Удалить пользовательское оформление из потока

Чтобы вернуться к стандартному оформлению для данного типа, используйте шаблон функции pretty::clear в потоке s.

s << pretty::clear>();

5. Дополнительные примеры

Печать "в виде матрицы" с разделителем новой строки

std::vector> m{ {1,2,3}, {4,5,6}, {7,8,9} };
std::cout << pretty::decoration>>("\n");
std::cout << m;

Печать

1, 2, 3
4, 5, 6
7, 8, 9

См. Его на ideone / KKUebZ

6. Код

#ifndef pretty_print_0x57547_sa4884X_0_1_h_guard_
#define pretty_print_0x57547_sa4884X_0_1_h_guard_

#include 
#include 
#include 
#include 
#include 

#define PRETTY_DEFAULT_DECORATION(TYPE, PREFIX, DELIM, POSTFIX, ...) \
    namespace pretty { template< __VA_ARGS__ >\
    struct defaulted< TYPE > {\
    static decor< TYPE > decoration(){\
      return { PREFIX, DELIM, POSTFIX };\
    } /*decoration*/ }; /*defaulted*/} /*pretty*/

#define PRETTY_DEFAULT_WDECORATION(TYPE, PREFIX, DELIM, POSTFIX, ...) \
    namespace pretty { template< __VA_ARGS__ >\
    struct defaulted< TYPE, wchar_t, std::char_traits > {\
    static decor< TYPE, wchar_t, std::char_traits > decoration(){\
      return { PREFIX, DELIM, POSTFIX };\
    } /*decoration*/ }; /*defaulted*/} /*pretty*/

namespace pretty
{

  namespace detail
  {
    // drag in begin and end overloads
    using std::begin;
    using std::end;
    // helper template
    template  using _ol = std::integral_constant*;
    // SFINAE check whether T is a range with begin/end
    template
    class is_range
    {
      // helper function declarations using expression sfinae
      template  = nullptr>
      static std::false_type b(...);
      template  = nullptr>
      static auto b(U &v) -> decltype(begin(v), std::true_type());
      template  = nullptr>
      static std::false_type e(...);
      template  = nullptr>
      static auto e(U &v) -> decltype(end(v), std::true_type());
      // return types
      using b_return = decltype(b(std::declval()));
      using e_return = decltype(e(std::declval()));
    public:
      static const bool value = b_return::value && e_return::value;
    };
  }

  // holder class for data
  template>
  struct decor
  {
    static const int xindex;
    std::basic_string prefix, delimiter, postfix;
    decor(std::basic_string const & pre = "",
      std::basic_string const & delim = "",
      std::basic_string const & post = "")
      : prefix(pre), delimiter(delim), postfix(post) {}
  };

  template
  int const decor::xindex = std::ios_base::xalloc();

  namespace detail
  {

    template
    void manage_decor(std::ios_base::event evt, std::ios_base &s, int const idx)
    {
      using deco_type = decor;
      if (evt == std::ios_base::erase_event)
      { // erase deco
        void const * const p = s.pword(idx);
        if (p)
        {
          delete static_cast(p);
          s.pword(idx) = nullptr;
        }
      }
      else if (evt == std::ios_base::copyfmt_event)
      { // copy deco
        void const * const p = s.pword(idx);
        if (p)
        {
          auto np = new deco_type{ *static_cast(p) };
          s.pword(idx) = static_cast(np);
        }
      }
    }

    template struct clearer {};

    template
    std::basic_ostream& operator<< (
      std::basic_ostream &s, clearer const &)
    {
      using deco_type = decor;
      void const * const p = s.pword(deco_type::xindex);
      if (p)
      { // delete if set
        delete static_cast(p);
        s.pword(deco_type::xindex) = nullptr;
      }
      return s;
    }

    template  
    struct default_data { static const CharT * decor[3]; };
    template <> 
    const char * default_data::decor[3] = { "", ", ", "" };
    template <> 
    const wchar_t * default_data::decor[3] = { L"", L", ", L"" };

  }

  // Clear decoration for T
  template
  detail::clearer clear() { return{}; }
  template
  void clear(std::basic_ostream &s) { s << detail::clearer{}; }

  // impose decoration on ostream
  template
  std::basic_ostream& operator<<(
    std::basic_ostream &s, decor && h)
  {
    using deco_type = decor;
    void const * const p = s.pword(deco_type::xindex);
    // delete if already set
    if (p) delete static_cast(p);
    s.pword(deco_type::xindex) = static_cast(new deco_type{ std::move(h) });
    // check whether we alread have a callback registered
    if (s.iword(deco_type::xindex) == 0)
    { // if this is not the case register callback and set iword
      s.register_callback(detail::manage_decor, deco_type::xindex);
      s.iword(deco_type::xindex) = 1;
    }
    return s;
  }

  template>
  struct defaulted
  {
    static inline decor decoration()
    {
      return{ detail::default_data::decor[0],
        detail::default_data::decor[1],
        detail::default_data::decor[2] };
    }
  };

  template>
  decor decoration(
    std::basic_string const & prefix,
    std::basic_string const & delimiter,
    std::basic_string const & postfix)
  {
    return{ prefix, delimiter, postfix };
  }

  template>
    decor decoration(
      std::basic_string const & delimiter)
  {
    using str_type = std::basic_string;
    return{ defaulted::decoration().prefix,
      delimiter, defaulted::decoration().postfix };
  }

  template>
    decor decoration(CharT const * const prefix,
      CharT const * const delimiter, CharT const * const postfix)
  {
    using str_type = std::basic_string;
    return{ str_type{ prefix }, str_type{ delimiter }, str_type{ postfix } };
  }

  template>
    decor decoration(CharT const * const delimiter)
  {
    using str_type = std::basic_string;
    return{ defaulted::decoration().prefix,
      str_type{ delimiter }, defaulted::decoration().postfix };
  }

  template
  struct tuple
  {
    template
    static void print(std::basic_ostream& s, T const & value,
      std::basic_string const &delimiter)
    {
      s << std::get(value) << delimiter;
      tuple::print(s, value, delimiter);
    }
  };

  template
  struct tuple
  {
    template
    static void print(std::basic_ostream& s, T const & value,
      std::basic_string const &) {
      s << std::get(value);
    }
  };

}

template
std::basic_ostream & operator<< (
  std::basic_ostream &s, std::tuple<> const & v)
{
  using deco_type = pretty::decor, CharT, TraitT>;
  using defaulted_type = pretty::defaulted, CharT, TraitT>;
  void const * const p = s.pword(deco_type::xindex);
  auto const d = static_cast(p);
  s << (d ? d->prefix : defaulted_type::decoration().prefix);
  s << (d ? d->postfix : defaulted_type::decoration().postfix);
  return s;
}

template
std::basic_ostream & operator<< (
  std::basic_ostream &s, std::tuple const & v)
{
  using deco_type = pretty::decor, CharT, TraitT>;
  using defaulted_type = pretty::defaulted, CharT, TraitT>;
  using pretty_tuple = pretty::tuple, 0U, sizeof...(T)-1U>;
  void const * const p = s.pword(deco_type::xindex);
  auto const d = static_cast(p);
  s << (d ? d->prefix : defaulted_type::decoration().prefix);
  pretty_tuple::print(s, v, d ? d->delimiter : 
    defaulted_type::decoration().delimiter);
  s << (d ? d->postfix : defaulted_type::decoration().postfix);
  return s;
}

template
std::basic_ostream & operator<< (
  std::basic_ostream &s, std::pair const & v)
{
  using deco_type = pretty::decor, CharT, TraitT>;
  using defaulted_type = pretty::defaulted, CharT, TraitT>;
  void const * const p = s.pword(deco_type::xindex);
  auto const d = static_cast(p);
  s << (d ? d->prefix : defaulted_type::decoration().prefix);
  s << v.first;
  s << (d ? d->delimiter : defaulted_type::decoration().delimiter);
  s << v.second;
  s << (d ? d->postfix : defaulted_type::decoration().postfix);
  return s;
}


template>
  typename std::enable_if < pretty::detail::is_range::value,
  std::basic_ostream < CharT, TraitT >> ::type & operator<< (
    std::basic_ostream &s, T const & v)
{
  bool first(true);
  using deco_type = pretty::decor;
  using default_type = pretty::defaulted;
  void const * const p = s.pword(deco_type::xindex);
  auto d = static_cast const * const>(p);
  s << (d ? d->prefix : default_type::decoration().prefix);
  for (auto const & e : v)
  { // v is range thus range based for works
    if (!first) s << (d ? d->delimiter : default_type::decoration().delimiter);
    s << e;
    first = false;
  }
  s << (d ? d->postfix : default_type::decoration().postfix);
  return s;
}

#endif // pretty_print_0x57547_sa4884X_0_1_h_guard_

17
задан Drew Dormann 29 June 2009 в 19:48
поделиться

4 ответа

Вы пытались подключиться к событию GDK_CONFIGURE?

Посмотрите этот пример под Раздел «Подвижное окно». В этом примере показан обратный вызов, который что-то делает при перемещении окна, но событие configure является универсальным для событий перемещения, изменения размера и порядка стека.

8
ответ дан 30 November 2019 в 13:40
поделиться

В PyGTK я всегда наблюдал за expose_event для изменения размера окна, затем используйте метод get_allocation , чтобы получить новый размер.

3
ответ дан 30 November 2019 в 13:40
поделиться

Вы можете собрать что-то вместе, используя gdk_window_get_root_origin , чтобы получить верхний левый угол окна, и gdk_window_get_geometry , чтобы получить ширину и высоту . Затем вы можете подключить обратный вызов к GDK_BUTTON_PRESS_MASK и проверить, происходит ли нажатие кнопки около / на одном из краев окна.

Конечно, это кажется довольно хакерским, и меня действительно беспокоит, что я не смог найти какой-то простой способ сделать это из документации GdkWindow. Существует функция gdk_window_begin_resize_drag , которая на самом деле заставляет меня думать, что есть более чистый способ сделать это, но я не видел ничего более очевидного, чем мой ответ.

0
ответ дан 30 November 2019 в 13:40
поделиться

Мне удалось это осуществить, наблюдая за сигналами size_allocate и size_request в GtkWindow . Если size_request когда-либо становилось меньше, я вызвал resize (1,1) . Если size_allocate когда-либо было больше, чем ожидалось, я отключил систему.

Я обязательно обработал size_request , возвращающий сначала большой, затем маленький и имеющий size_allocate быть большим, а затем маленьким. Я не знаю, возможно ли это, но я исправил это, убедившись, что уменьшил ожидаемые значения для size_allocate только тогда, когда у меня был меньший size_allocate , а не когда у меня был меньший size_request .

Убедитесь, что ваш обработчик size_request идет после обработчика базового класса, чтобы вы получили правильные значения. Я сделал это, переопределив метод, а затем сначала вызвав метод базового класса.

Я пробовал это как в 1, так и в 2 измерениях, и, похоже, это работает в любом случае.

7
ответ дан 30 November 2019 в 13:40
поделиться
Другие вопросы по тегам:

Похожие вопросы: